From 65c6e79fb2df827b4ed1c3263ee22ac1b60c712c Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 9 Sep 2024 19:24:55 +0200 Subject: [PATCH 001/186] [MOD/META] Change README/CHANGELOG --- CHANGELOG.md | 18 ++++++++++++++++++ README.MD | 1 + 2 files changed, 19 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5762504 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Parsee changelogs + +This document holds changes logged between versions, ever +since `tomboyish-bridges-adventure`'s release. +Dates are to be written as DD/MM/YYYY. Please update the +changelog as you go, no one wants to keep track of every +commit done between releases. + +## Alpha +### v0.1.0[tomboyish-bridges-adventure] <9/9/2024> +Nothing much to say, but this is the first alpha release +of Parsee. May occasionally deadlock. +#### New things +*NONE* +#### Bugfixes +*NONE* +#### Deprecated features +*NONE* diff --git a/README.MD b/README.MD index 51fcf7f..a84c386 100644 --- a/README.MD +++ b/README.MD @@ -1,6 +1,7 @@ # Parsee - the jealous XMPP<=>Matrix bridge Parsee is a Matrix<=>XMPP bridge written in C99, with Cytoplasm, similar to Bifrost, but it is NOT a drop-in replacment. +**NOTE**: Use [this Cytoplasm branch for LMDB](https://git.telodendria.io/lda/Cytoplasm) ## Why? ### Naming From 7593225e18789fbded0823c40850bc46148ef39a Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 08:00:06 +0200 Subject: [PATCH 002/186] [MOD/META] Correct README, make sure edit is NULL --- README.MD | 2 +- src/StanzaBuilder.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index a84c386..1d3f334 100644 --- a/README.MD +++ b/README.MD @@ -1,7 +1,7 @@ # Parsee - the jealous XMPP<=>Matrix bridge Parsee is a Matrix<=>XMPP bridge written in C99, with Cytoplasm, similar to Bifrost, but it is NOT a drop-in replacment. -**NOTE**: Use [this Cytoplasm branch for LMDB](https://git.telodendria.io/lda/Cytoplasm) +**NOTE**: Use [this Cytoplasm branch for LMDB](https://git.telodendria.io/lda/Cytoplasm/src/branch/fix-deadlock) ## Why? ### Naming diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 5426f80..1817997 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -40,6 +40,7 @@ CreateStanzaBuilder(char *from, char *to, char *id) builder->replying_to_stanza = NULL; builder->replying_to_sender = NULL; + builder->editing = NULL; builder->type = NULL; builder->body = NULL; builder->oob = NULL; From 488ab92a90f81a1ef11f597bfaa6c33626b4871f Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 10:52:40 +0200 Subject: [PATCH 003/186] [MOD] Modify retention periods --- src/Parsee/Data.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index f5c20fe..d4bf6cb 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -177,9 +177,10 @@ ParseeCleanup(void *datp) } \ while (0) - CleanupField(stanza, 30 MINUTES, 50); - CleanupField(event, 30 MINUTES, 50); - CleanupField(id, 30 MINUTES, 50); + /* TODO: Custom retention period for any 1.0 */ + CleanupField(stanza, 30 MINUTES, 500); + CleanupField(event, 30 MINUTES, 500); + CleanupField(id, 30 MINUTES, 500); #undef CleanupField } DbListFree(chats); @@ -231,9 +232,9 @@ ParseeCleanup(void *datp) } \ while (0) - CleanupField(stanza, 3 HOURS, 50); - CleanupField(event, 3 HOURS, 50); - CleanupField(id, 3 HOURS, 50); + CleanupField(stanza, 3 HOURS, 500); + CleanupField(event, 3 HOURS, 500); + CleanupField(id, 3 HOURS, 500); DbUnlock(data->db, ref); } From 2a6a3300e6e3f4fe13db642b0ee9a61335bc8b32 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 19:07:12 +0200 Subject: [PATCH 004/186] [CI] Start entering CI hell --- .forgejo/workflows/demo.yaml | 6 ++++++ .gitignore | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 .forgejo/workflows/demo.yaml diff --git a/.forgejo/workflows/demo.yaml b/.forgejo/workflows/demo.yaml new file mode 100644 index 0000000..433cfc5 --- /dev/null +++ b/.forgejo/workflows/demo.yaml @@ -0,0 +1,6 @@ +on: [push] +jobs: + test: + runs-on: amd64-debian + steps: + - run: echo Welcome to CI Hell :D diff --git a/.gitignore b/.gitignore index f2c57e6..6104661 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ tags # Whitelists !etc/* !etc/** +!.forgejo +!.forgejo/* +!.forgejo/** From 971f8ba3aac7dec53c69c34b94875e45213ae0fe Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 19:22:01 +0200 Subject: [PATCH 005/186] [CI] Mess with waters --- .forgejo/workflows/check-gcc.yaml | 15 +++++++++++++++ .forgejo/workflows/demo.yaml | 6 ------ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 .forgejo/workflows/check-gcc.yaml delete mode 100644 .forgejo/workflows/demo.yaml diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml new file mode 100644 index 0000000..684aa9d --- /dev/null +++ b/.forgejo/workflows/check-gcc.yaml @@ -0,0 +1,15 @@ +name: Checks Parsee's correctness on GCC +on: [push] +jobs: + compile: + runs-on: amd64-debian + steps: + - name: Install LMDB+OpenSSL tools + run: echo $(uname -a) $(env | grep container) + - name: Clone Cytoplasm + uses: actions/checkout@v3 + with: + repository: "https://git.telodendria.io/Telodendria/Cytoplasm" + - name: Configure Cytoplasm + run: ./configure --with-lmdb + diff --git a/.forgejo/workflows/demo.yaml b/.forgejo/workflows/demo.yaml deleted file mode 100644 index 433cfc5..0000000 --- a/.forgejo/workflows/demo.yaml +++ /dev/null @@ -1,6 +0,0 @@ -on: [push] -jobs: - test: - runs-on: amd64-debian - steps: - - run: echo Welcome to CI Hell :D From fdc0dfbcb6da41f145aff57e646281824c7e5fbe Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 19:56:08 +0200 Subject: [PATCH 006/186] [CI] Try running in a container --- .forgejo/workflows/check-gcc.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 684aa9d..113704b 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -3,9 +3,14 @@ on: [push] jobs: compile: runs-on: amd64-debian + container: + image: debian:12 steps: - name: Install LMDB+OpenSSL tools - run: echo $(uname -a) $(env | grep container) + run: | + echo $(uname -a) $(env | grep container) + apt update + apt install build-essential liblmdb-dev nodejs libssl-dev - name: Clone Cytoplasm uses: actions/checkout@v3 with: From f1d864c975e37fc621fbfd38ee36c67de8476df4 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:00:51 +0200 Subject: [PATCH 007/186] [CI] User input moment --- .forgejo/workflows/check-gcc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 113704b..4cfa7ad 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -2,15 +2,15 @@ name: Checks Parsee's correctness on GCC on: [push] jobs: compile: - runs-on: amd64-debian + runs-on: debian:12 container: image: debian:12 steps: - name: Install LMDB+OpenSSL tools run: | echo $(uname -a) $(env | grep container) - apt update - apt install build-essential liblmdb-dev nodejs libssl-dev + apt update -y + apt install -y build-essential liblmdb-dev nodejs libssl-dev - name: Clone Cytoplasm uses: actions/checkout@v3 with: From 1f31ce2c35dcdad345b168267200b5589789859f Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:15:41 +0200 Subject: [PATCH 008/186] [CI] Use proper tag --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 4cfa7ad..ac442df 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -2,7 +2,7 @@ name: Checks Parsee's correctness on GCC on: [push] jobs: compile: - runs-on: debian:12 + runs-on: amd64-debian container: image: debian:12 steps: From c8925dbe0034cdc1f8b64a23bd4a714671542a43 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:19:20 +0200 Subject: [PATCH 009/186] [CI] checkout is stupid --- .forgejo/workflows/check-gcc.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index ac442df..86f41e1 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -14,7 +14,8 @@ jobs: - name: Clone Cytoplasm uses: actions/checkout@v3 with: - repository: "https://git.telodendria.io/Telodendria/Cytoplasm" + repository: "Telodendria/Cytoplasm" + github-server-url: 'https://git.telodendria.io' - name: Configure Cytoplasm run: ./configure --with-lmdb From 4e22fb6f0459352c7225a2b75725b25ad26ba9b9 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:21:39 +0200 Subject: [PATCH 010/186] [CI] Install git too --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 86f41e1..b168ba2 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -10,7 +10,7 @@ jobs: run: | echo $(uname -a) $(env | grep container) apt update -y - apt install -y build-essential liblmdb-dev nodejs libssl-dev + apt install -y build-essential liblmdb-dev nodejs libssl-dev git - name: Clone Cytoplasm uses: actions/checkout@v3 with: From 60f3dc12c17711c871387b35b29b1f3d25d9f923 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:28:14 +0200 Subject: [PATCH 011/186] [CI] Hopefully this works --- .forgejo/workflows/check-gcc.yaml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index b168ba2..edcf7fc 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -11,11 +11,19 @@ jobs: echo $(uname -a) $(env | grep container) apt update -y apt install -y build-essential liblmdb-dev nodejs libssl-dev git - - name: Clone Cytoplasm + - name: Clone/Configure Cytoplasm + run: | + git clone https:/git.telodendria.io/Telodendria/Cytoplasm + cd Cytoplasm + ./configure --with-lmdb + - name: Build Cytoplasm + run: make -j$(nproc) + - name: Install Cytoplasm + run: make install + - name: Clone Parsee uses: actions/checkout@v3 - with: - repository: "Telodendria/Cytoplasm" - github-server-url: 'https://git.telodendria.io' - - name: Configure Cytoplasm - run: ./configure --with-lmdb + - name: Build Parsee + run: 'make && make ayadoc' + - name: Install Parsee + run: 'make install' From 7314be5aeb8b49bee182c7200e07757382b3a4aa Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:29:38 +0200 Subject: [PATCH 012/186] [CI] Silly me! --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index edcf7fc..2dd4c46 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -13,7 +13,7 @@ jobs: apt install -y build-essential liblmdb-dev nodejs libssl-dev git - name: Clone/Configure Cytoplasm run: | - git clone https:/git.telodendria.io/Telodendria/Cytoplasm + git clone https://git.telodendria.io/Telodendria/Cytoplasm cd Cytoplasm ./configure --with-lmdb - name: Build Cytoplasm From aa8faec48659c803f4dcb8b8cf7f4dd20733397d Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:33:04 +0200 Subject: [PATCH 013/186] [CI] Try getting in the right directory --- .forgejo/workflows/check-gcc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 2dd4c46..28af308 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -17,9 +17,9 @@ jobs: cd Cytoplasm ./configure --with-lmdb - name: Build Cytoplasm - run: make -j$(nproc) + run: 'cd Cytoplasm && make -j$(nproc)' - name: Install Cytoplasm - run: make install + run: 'cd Cytoplasm && make install' - name: Clone Parsee uses: actions/checkout@v3 - name: Build Parsee From 9cba44f69b28ec3a0a24f1020fda676693010db3 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 20:39:45 +0200 Subject: [PATCH 014/186] [CI] Set a depth of 1 --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 28af308..dbca697 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -13,7 +13,7 @@ jobs: apt install -y build-essential liblmdb-dev nodejs libssl-dev git - name: Clone/Configure Cytoplasm run: | - git clone https://git.telodendria.io/Telodendria/Cytoplasm + git clone https://git.telodendria.io/Telodendria/Cytoplasm --depth=1 cd Cytoplasm ./configure --with-lmdb - name: Build Cytoplasm From 5149a37d2e00eb234424df58ae6f70ec539e33ff Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:10:23 +0200 Subject: [PATCH 015/186] [CI] Use local mirror of Cytoplasm --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index dbca697..e8dc9a3 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -13,7 +13,7 @@ jobs: apt install -y build-essential liblmdb-dev nodejs libssl-dev git - name: Clone/Configure Cytoplasm run: | - git clone https://git.telodendria.io/Telodendria/Cytoplasm --depth=1 + git clone https://git.kappach.at/KappaChat/Cytoplasm --depth=1 cd Cytoplasm ./configure --with-lmdb - name: Build Cytoplasm From e1b044b26861d8a6d3d287e7563372ac14be99ef Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:13:05 +0200 Subject: [PATCH 016/186] [CI] Set prefix to /usr --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index e8dc9a3..b28fa13 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -15,7 +15,7 @@ jobs: run: | git clone https://git.kappach.at/KappaChat/Cytoplasm --depth=1 cd Cytoplasm - ./configure --with-lmdb + ./configure --with-lmdb --prefix=/usr - name: Build Cytoplasm run: 'cd Cytoplasm && make -j$(nproc)' - name: Install Cytoplasm From a7c06bdb5cd6baca22ccd0e562467d107fa74160 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:29:08 +0200 Subject: [PATCH 017/186] [CI] Exit CI hell... for now. --- .forgejo/workflows/build-release.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .forgejo/workflows/build-release.yaml diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml new file mode 100644 index 0000000..6878f4a --- /dev/null +++ b/.forgejo/workflows/build-release.yaml @@ -0,0 +1,10 @@ +name: Builds static Parsee for a release. +on: [release] +jobs: + compile: + runs-on: amd64-debian + container: + image: debian:12 + steps: + - name: TODO + run: TODO From 3ae262c452c55dffa6a39f3cbc7ab5954604fd4a Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:39:08 +0200 Subject: [PATCH 018/186] [CI] Be stringent on flags --- .forgejo/workflows/check-gcc.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index b28fa13..cd6d98b 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -1,4 +1,4 @@ -name: Checks Parsee's correctness on GCC +name: Checks Parsee's correctness on GCC+Debian on: [push] jobs: compile: @@ -23,7 +23,10 @@ jobs: - name: Clone Parsee uses: actions/checkout@v3 - name: Build Parsee - run: 'make && make ayadoc' + run: > + echo 'CFLAGS=-Werror -Wall -Wextra -pedantic' >> build.conf + cat build.conf + make && make ayadoc - name: Install Parsee run: 'make install' From a3dc90f93ec371d11626443d4da542d1fcc6a791 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:41:21 +0200 Subject: [PATCH 019/186] [CI] What? --- .forgejo/workflows/check-gcc.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index cd6d98b..20bbcf9 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -23,8 +23,8 @@ jobs: - name: Clone Parsee uses: actions/checkout@v3 - name: Build Parsee - run: > - echo 'CFLAGS=-Werror -Wall -Wextra -pedantic' >> build.conf + run: | + echo '"CFLAGS=-Werror -Wall -Wextra -pedantic"' >> build.conf cat build.conf make && make ayadoc - name: Install Parsee From 42f02010d4fedc6981a88a72b4e5ad8b1be71dca Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:43:25 +0200 Subject: [PATCH 020/186] [CI] Don't doublequote --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 20bbcf9..38d32ca 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v3 - name: Build Parsee run: | - echo '"CFLAGS=-Werror -Wall -Wextra -pedantic"' >> build.conf + echo 'CFLAGS=-Werror -Wall -Wextra -pedantic' >> build.conf cat build.conf make && make ayadoc - name: Install Parsee From 696def187c7e223bb81a5391194ebc094ca3855c Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:47:08 +0200 Subject: [PATCH 021/186] [MOD/FIX] Set history limit, change logo, CI --- src/AS/Media.c | 2 +- src/Parsee/Logo.c | 3 +-- src/Routes/Root.c | 23 ++++++++++++++++++----- src/XMPP/MUC.c | 5 ++++- src/include/Parsee.h | 2 +- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/AS/Media.c b/src/AS/Media.c index 4e642e9..fceefa9 100644 --- a/src/AS/Media.c +++ b/src/AS/Media.c @@ -14,7 +14,7 @@ char * ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) { char *size_str, *path, *ret, *user; - int i; + unsigned int i; HttpClientContext *ctx; HashMap *reply; if (!c || !from) diff --git a/src/Parsee/Logo.c b/src/Parsee/Logo.c index 245a91c..30885d9 100644 --- a/src/Parsee/Logo.c +++ b/src/Parsee/Logo.c @@ -4,11 +4,10 @@ const char *parsee_ascii[PARSEE_ASCII_LINES] = { - "----------------------------", " =+======", " || | _ _/__----", " / || \\ ==+= _/_____\\_", - " | || | -|- L___J", + " | || | -|- L___J ", "_/ || \\_ ||| .______\\", " || | | | |.____.|", " || / | \\ |L____||", diff --git a/src/Routes/Root.c b/src/Routes/Root.c index af89909..d96e5f6 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -84,11 +84,14 @@ RouteHead(RouteRoot, arr, argp) P("color: #eee;"); P("font-family: sans-serif;"); P("}"); - P("#cols {"); - P("column-count: 3;"); - P("min-width: 100%;"); - P("max-width: 100%;"); - P("width: 100%;"); + P("#ascii {"); + P("text-align: center;"); + P("color: #be1337;"); + P("font-size: 4vw;"); + P("}"); + P("#ascii pre {"); + P("display: inline-block;"); + P("text-align: left;"); P("}"); P("img {"); P("image-rendering: pixelated;"); @@ -115,6 +118,7 @@ RouteHead(RouteRoot, arr, argp) P(""); { + size_t i; P("
"); P("

Your %s is running, all with that %s!

", NAME, CODE); P("
"); @@ -124,6 +128,15 @@ RouteHead(RouteRoot, arr, argp) P("%s", GetRandomQuote()); } P(""); + P("
");
+            for (i = 0; i < PARSEE_ASCII_LINES; i++)
+            {
+                XMLElement *e = XMLCreateText(parsee_ascii[i]);
+                XMLEncode(args->stream, e);
+                XMLFreeElement(e);
+                P("
"); + } + P("
"); P("

"); { diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 832fdfe..3a81764 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -170,7 +170,7 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) { - XMLElement *presence, *x, *reply; + XMLElement *presence, *x, *reply, *history; char *from, *id; if (!comp || !fr || !muc) { @@ -185,6 +185,9 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) XMLAddAttr(presence, "to", muc); XMLAddAttr(presence, "id", (id = StrRandom(8))); XMLAddAttr(x, "xmlns", "http://jabber.org/protocol/muc"); + history = XMLCreateTag("history"); + XMLAddAttr(history, "seconds", "3600"); /* TODO: Custom timeout */ + XMLAddChild(x, history); XMLAddChild(presence, x); XMPPAnnotatePresence(presence); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index e19fd42..f64df82 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -101,7 +101,7 @@ typedef struct Argument { extern const char media_parsee_logo[]; /* An ASCII-art rendition of "小橋" */ -#define PARSEE_ASCII_LINES 9 +#define PARSEE_ASCII_LINES 8 extern const char *parsee_ascii[PARSEE_ASCII_LINES]; /** From 1d188069dbe69883d52c1653b7fce0f3669ae9e0 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 21:51:09 +0200 Subject: [PATCH 022/186] [FIX] Fix other little CI thing --- src/AS/Relations.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/AS/Relations.c b/src/AS/Relations.c index 4809413..e9baa5a 100644 --- a/src/AS/Relations.c +++ b/src/AS/Relations.c @@ -25,19 +25,20 @@ ASGetRelations(const ParseeConfig *c, size_t n, char *room, char *event, char *t } user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); - if (event) + if (type) { - path = StrConcat(6, + path = StrConcat(8, "/_matrix/client/v1/rooms/", room, - "/relations/", event, + "/relations/", event, "/", type, "?user_id=", user ); } else { - path = StrConcat(4, + path = StrConcat(6, "/_matrix/client/v1/rooms/", room, - "/relations?user_id=", user + "/relations/", event, + "?user_id=", user ); } Free(user); From 907ac13da929fa90864424248eed50631b0b51ee Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 22:20:13 +0200 Subject: [PATCH 023/186] [FIX] Make Parsee build on GCC without warns --- src/Command/Router.c | 20 ++++++++++++++++---- src/Commands/Help.c | 2 ++ src/Commands/ListBans.c | 2 ++ src/Commands/Stats.c | 2 ++ src/Main.c | 2 ++ src/Parsee/Config.c | 2 +- src/Parsee/User.c | 2 -- src/Routes/Root.c | 3 ++- src/Routes/Transactions.c | 1 + src/StrSplit.c | 8 ++++---- src/Streams/Reader.c | 4 ++-- src/Streams/Writer.c | 9 ++++++++- src/XML/SAX.c | 2 ++ src/XMPPCommands/Admins.c | 2 ++ src/XMPPCommands/Cleanup.c | 2 ++ src/XMPPCommands/Nofly.c | 2 ++ src/XMPPCommands/Status.c | 2 ++ src/XMPPThread/PEP.c | 19 ++++++++++++++----- src/XMPPThread/PEPs/VCard.c | 1 + src/XMPPThread/Stanzas/IQ.c | 5 +++++ 20 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/Command/Router.c b/src/Command/Router.c index d188640..0a09d28 100644 --- a/src/Command/Router.c +++ b/src/Command/Router.c @@ -15,35 +15,47 @@ CommandCreateRouter(void) void CommandAddCommand(CommandRouter *rter, char *c, CommandRoute rte) { + CommandRoute *indirect; if (!rter || !c || !rte) { return; } - HashMapSet(rter->routes, c, rte); + + /* Little dirty trick to force C99 into submission, and since + * some architectures may separate data/code. Still don't like it... */ + indirect = Malloc(sizeof(rte)); + *indirect = rte; + HashMapSet(rter->routes, c, (void *) indirect); } void RouteCommand(CommandRouter *rter, Command *cmd, void *d) { - CommandRoute route; + CommandRoute *route; if (!rter || !cmd) { return; } route = HashMapGet(rter->routes, cmd->command); - if (route) + if (route && *route) { - route(cmd, d); + (*route)(cmd, d); } } void CommandFreeRouter(CommandRouter *rter) { + char *key; + CommandRoute *val; if (!rter) { return; } + while (HashMapIterate(rter->routes, &key, (void **) &val)) + { + Free(val); + } HashMapFree(rter->routes); Free(rter); } diff --git a/src/Commands/Help.c b/src/Commands/Help.c index f60980c..0e25009 100644 --- a/src/Commands/Help.c +++ b/src/Commands/Help.c @@ -25,4 +25,6 @@ CommandHead(CmdHelp, cmd, argp) ); ReplyBasic("*Written with a shoelace and UHU glue by LDA <3 !*"); BotDestroy(); + + (void) cmd; } diff --git a/src/Commands/ListBans.c b/src/Commands/ListBans.c index 109c5d4..50d9d31 100644 --- a/src/Commands/ListBans.c +++ b/src/Commands/ListBans.c @@ -32,4 +32,6 @@ CommandHead(CmdListBans, cmd, argp) DbUnlock(data->db, listed); BotDestroy(); + + (void) cmd; } diff --git a/src/Commands/Stats.c b/src/Commands/Stats.c index 219204a..0df0b44 100644 --- a/src/Commands/Stats.c +++ b/src/Commands/Stats.c @@ -40,4 +40,6 @@ CommandHead(CmdStats, cmd, argp) ReplyBasic("*Written with a shoelace and UHU glue by LDA <3 !*"); BotDestroy(); + + (void) cmd; } diff --git a/src/Main.c b/src/Main.c index 652512c..aa47822 100644 --- a/src/Main.c +++ b/src/Main.c @@ -276,5 +276,7 @@ end: ParseeDestroyOIDTable(); ParseeDestroyHeadTable(); ParseeDestroyJIDTable(); + + (void) env; return 0; } diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 72eff53..0e1ee04 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -30,7 +30,7 @@ ParseeConfigLoad(char *conf) { return; } - stream = StreamOpen("parsee.json", "r"); + stream = StreamOpen(conf ? conf : "parsee.json", "r"); if (!stream) { return; diff --git a/src/Parsee/User.c b/src/Parsee/User.c index c751731..90c7ca5 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -356,8 +356,6 @@ ParseePushDMRoom(ParseeData *d, char *mxid, char *jid, char *r) void ParseeDeleteDM(ParseeData *d, char *mxid, char *jid) { - DbRef *ref; - HashMap *j; char *dmid; if (!d || !mxid || !jid) { diff --git a/src/Routes/Root.c b/src/Routes/Root.c index d96e5f6..410652a 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -131,7 +131,7 @@ RouteHead(RouteRoot, arr, argp) P("

");
             for (i = 0; i < PARSEE_ASCII_LINES; i++)
             {
-                XMLElement *e = XMLCreateText(parsee_ascii[i]);
+                XMLElement *e = XMLCreateText((char *) parsee_ascii[i]);
                 XMLEncode(args->stream, e);
                 XMLFreeElement(e);
                 P("
"); @@ -249,5 +249,6 @@ RouteHead(RouteRoot, arr, argp) P(""); #undef P + (void) arr; return NULL; } diff --git a/src/Routes/Transactions.c b/src/Routes/Transactions.c index 27e7393..580e43c 100644 --- a/src/Routes/Transactions.c +++ b/src/Routes/Transactions.c @@ -42,6 +42,7 @@ RouteHead(RouteTxns, arr, argp) response = HashMapCreate(); end: + (void) arr; JsonFree(request); return response; } diff --git a/src/StrSplit.c b/src/StrSplit.c index 91ecec7..aef23f5 100644 --- a/src/StrSplit.c +++ b/src/StrSplit.c @@ -117,7 +117,7 @@ StrFullRect(char **split) char StrGet(StringRect *rect, int line, int col) { - int actual_line, actual_col; + size_t actual_line, actual_col; char *linep; if (!rect || !rect->source_lines) { @@ -150,7 +150,7 @@ StrGet(StringRect *rect, int line, int col) size_t StrViewChars(StringRect rect, int line) { - int actual_line; + size_t actual_line; char *linep; if (!rect.source_lines) { @@ -174,7 +174,7 @@ StrViewChars(StringRect rect, int line) StringRect StrGetl(StringRect *rect, int line, bool extend) { - int actual_line; + size_t actual_line; StringRect ret; if (!rect->source_lines) { @@ -204,7 +204,7 @@ StrGetl(StringRect *rect, int line, bool extend) StringRect StrShift(StringRect rect, int n) { - int new = rect.start_char + n; + size_t new = rect.start_char + n; if (new > rect.end_char) { new = rect.end_char; diff --git a/src/Streams/Reader.c b/src/Streams/Reader.c index 2c0613a..bca261a 100644 --- a/src/Streams/Reader.c +++ b/src/Streams/Reader.c @@ -10,10 +10,10 @@ Stream * StrStreamReaderN(char *buffer, int n) { - if (!buffer) + if (!buffer || n < 0) { return NULL; } - return StreamFile(fmemopen(buffer, n ? n : strlen(buffer), "rb")); + return StreamFile(fmemopen(buffer, n ? (size_t) n : strlen(buffer), "rb")); } diff --git a/src/Streams/Writer.c b/src/Streams/Writer.c index 88bc7ee..c29b026 100644 --- a/src/Streams/Writer.c +++ b/src/Streams/Writer.c @@ -11,6 +11,9 @@ static ssize_t ReadStreamWriter(void *coop, void *to, size_t n) { /* Reading from a stream writer is silly. */ + (void) coop; + (void) to; + (void) n; return 0; } static ssize_t @@ -33,6 +36,9 @@ static off_t SeekStreamWriter(void *coop, off_t mag, int sgn) { /* TODO: Seeking would be useful, though not supported yet. */ + (void) coop; + (void) mag; + (void) sgn; return 0; } @@ -40,10 +46,11 @@ static int CloseStreamWriter(void *coop) { /* Nothing to free as of now. */ + (void) coop; return 0; } -const static IoFunctions Functions = { +static const IoFunctions Functions = { .read = ReadStreamWriter, .seek = SeekStreamWriter, .write = WriteStreamWriter, diff --git a/src/XML/SAX.c b/src/XML/SAX.c index 07c920a..f2eb814 100644 --- a/src/XML/SAX.c +++ b/src/XML/SAX.c @@ -582,6 +582,8 @@ XMLCreateEnd(XMLexer *lexer, char *end) event->col = 0; event->offset = 0; + (void) lexer; + return event; } static XMLEvent * diff --git a/src/XMPPCommands/Admins.c b/src/XMPPCommands/Admins.c index 7f0b172..1baf789 100644 --- a/src/XMPPCommands/Admins.c +++ b/src/XMPPCommands/Admins.c @@ -58,4 +58,6 @@ AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * DbUnlock(data->db, ref); } XMLAddChild(out, x); + + (void) form; } diff --git a/src/XMPPCommands/Cleanup.c b/src/XMPPCommands/Cleanup.c index 4554f53..22780ff 100644 --- a/src/XMPPCommands/Cleanup.c +++ b/src/XMPPCommands/Cleanup.c @@ -29,4 +29,6 @@ CleanCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o ParseeCleanup(data); /* TODO: Cleanup old sessions? */ SetNote("info", "Parsee data was sucessfully cleant up."); + + (void) form; } diff --git a/src/XMPPCommands/Nofly.c b/src/XMPPCommands/Nofly.c index 86a7bb1..dcbef67 100644 --- a/src/XMPPCommands/Nofly.c +++ b/src/XMPPCommands/Nofly.c @@ -87,4 +87,6 @@ NoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o } DbUnlock(data->db, ref); } + + (void) form; } diff --git a/src/XMPPCommands/Status.c b/src/XMPPCommands/Status.c index 41a923a..f1a0b73 100644 --- a/src/XMPPCommands/Status.c +++ b/src/XMPPCommands/Status.c @@ -75,4 +75,6 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * EndItem(); } XMLAddChild(out, x); + + (void) form; } diff --git a/src/XMPPThread/PEP.c b/src/XMPPThread/PEP.c index be60096..856d6de 100644 --- a/src/XMPPThread/PEP.c +++ b/src/XMPPThread/PEP.c @@ -68,20 +68,23 @@ PEPManagerCookie(PEPManager *manager) void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event) { + PEPEvent *indirect; if (!manager || !node || !event) { return; } + indirect = Malloc(sizeof(event)); + *indirect = event; pthread_mutex_lock(&manager->lock); - HashMapSet(manager->node_table, node, event); + HashMapSet(manager->node_table, node, indirect); pthread_mutex_unlock(&manager->lock); } static bool PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) { - PEPEvent call = NULL; + PEPEvent *call = NULL; XMLElement *event, *ps, *ev; size_t i; if (!manager || !stanza) @@ -101,7 +104,7 @@ PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) XMLElement *items = ArrayGet(event->children, i); char *node = HashMapGet(items->attrs, "node"); - if ((call = HashMapGet(manager->node_table, node))) + if ((call = HashMapGet(manager->node_table, node)) && *call) { size_t j; /* Use the callback over all items */ @@ -109,13 +112,13 @@ PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) { for (j = 0; j < ArraySize(items->children); j++) { - call(manager, stanza, ArrayGet(items->children, j)); + (*call)(manager, stanza, ArrayGet(items->children, j)); } return true; } /* ... or over "items" specifically. */ - call(manager, stanza, items); + (*call)(manager, stanza, items); return true; } } @@ -142,12 +145,18 @@ PEPManagerHandle(PEPManager *manager, XMLElement *stanza) void DestroyPEPManager(PEPManager *manager) { + char *key; + PEPEvent *val; if (!manager) { return; } pthread_mutex_destroy(&manager->lock); + while (HashMapIterate(manager->node_table, &key, (void **) &val)) + { + Free(val); + } HashMapFree(manager->node_table); Free(manager); } diff --git a/src/XMPPThread/PEPs/VCard.c b/src/XMPPThread/PEPs/VCard.c index a57c948..1859e97 100644 --- a/src/XMPPThread/PEPs/VCard.c +++ b/src/XMPPThread/PEPs/VCard.c @@ -118,4 +118,5 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(reply); + (void) item; } diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index ebfd84e..125c5e1 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -113,6 +113,8 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq_reply); + + (void) args; } void @@ -440,6 +442,9 @@ void IQError(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { /* TODO */ + (void) args; + (void) stanza; + (void) thr; } void IQSet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) From eefd5f0389f0b15cd70715e6ba5e0af54ec876c1 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 10 Sep 2024 22:28:55 +0200 Subject: [PATCH 024/186] [MOD] Don't make the text so large --- src/Routes/Root.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Routes/Root.c b/src/Routes/Root.c index 410652a..e0e3e87 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -87,7 +87,6 @@ RouteHead(RouteRoot, arr, argp) P("#ascii {"); P("text-align: center;"); P("color: #be1337;"); - P("font-size: 4vw;"); P("}"); P("#ascii pre {"); P("display: inline-block;"); From e8fb9b9641ad2f3ddc27d2fdfbd7e4e82131d8a3 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 09:15:20 +0200 Subject: [PATCH 025/186] [CI] Try to create a static CI job --- .forgejo/workflows/build-release.yaml | 52 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 6878f4a..c9617d7 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -1,10 +1,56 @@ name: Builds static Parsee for a release. -on: [release] +on: [release, workflow_dispatch] jobs: compile: runs-on: amd64-debian container: image: debian:12 steps: - - name: TODO - run: TODO + - name: Install LMDB+OpenSSL tools + run: | + echo $(uname -a) $(env | grep container) + apt update -y + apt install -y build-essential liblmdb-dev nodejs libssl-dev git + - name: Clone everything + run: | + mkdir -p repos + git clone --depth=1 https://git.musl-libc.org/git/musl repos/musl + git clone --depth=1 https://github.com/openssl/openssl repos/openssl + git clone --depth=1 https://github.com/LMDB/lmdb repos/lmdb + git clone --depth=1 https://git.kappach.at/KappaChat/Cytoplasm repos/cyto + echo "PREFIX=$GITHUB_WORKSPACE/usr" >> $GITHUB_ENV + echo "PATH=$GITHUB_WORKSPACE/usr/bin:$PATH" >> $GITHUB_ENV + echo "INCLUDE_PATH=$GITHUB_WORKSPACE/usr/include" >> $GITHUB_ENV + echo "LIBRARY_PATH=$GITHUB_WORKSPACE/usr/lib" >> $GITHUB_ENV + - name: Build musl + run: | + cd repos/musl + ./configure --prefix=${PREFIX} + make -j$(nproc) + make install -j$(nproc) + alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" + - name: Build OpenSSL + run: | + alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" + cd repos/openssl + CC=musl-gcc ./Configure -static --static --prefix=${PREFIX} no-async no-engine -DOPENSSL_NO_SECURE_MEMORY + make -j$(nproc) + make install -j$(nproc) + cp libcrypto.a ${PREFIX}/lib + cp libssl.a ${PREFIX}/lib + - name: Build LMDB + run: | + alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" + cd repos/lmdb/libraries/liblmdb + make CC=musl-gcc + make install prefix=${PREFIX} + - name: Build Cytoplasm + run: | + alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" + cd repos/cyto + rm configure + wget https://kappach.at/configure + chmod +x configure + ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb + make -j$(nproc) + make install From d9bea609dd8f626002c07f62b067b9814cfceaf5 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 09:33:02 +0200 Subject: [PATCH 026/186] [CI] This should(n't) do the trick --- .forgejo/workflows/build-release.yaml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index c9617d7..35ff447 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -10,7 +10,7 @@ jobs: run: | echo $(uname -a) $(env | grep container) apt update -y - apt install -y build-essential liblmdb-dev nodejs libssl-dev git + apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget - name: Clone everything run: | mkdir -p repos @@ -54,3 +54,15 @@ jobs: ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb make -j$(nproc) make install + - name: Clone Parsee + uses: actions/checkout@v3 + - name: Build Parsee + run: | + alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" + echo "all: adminify aya b64 config noavatars" > tools/Makefile + echo "%: %.c" >> tools/Makefile + echo "$(printf '\\t')musl-gcc -I $(PREFIX)/usr/include -static -o $(PREFIX)/$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true + musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm + ls $PREFIX + From 89ab1b57f03eff8c4d31b2bc268705c2eeaeef05 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 09:40:05 +0200 Subject: [PATCH 027/186] [CI] Please? --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 35ff447..cdb8b22 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -61,7 +61,7 @@ jobs: alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" echo "all: adminify aya b64 config noavatars" > tools/Makefile echo "%: %.c" >> tools/Makefile - echo "$(printf '\\t')musl-gcc -I $(PREFIX)/usr/include -static -o $(PREFIX)/$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + echo "$(printf '\\t')musl-gcc -I ${PREFIX}/usr/include -static -o $(PREFIX)/$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm ls $PREFIX From eb9512cde50aa9ea28f5221a31d5d0e677e44865 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 09:58:50 +0200 Subject: [PATCH 028/186] [CI] Do not use checkout --- .forgejo/workflows/build-release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index cdb8b22..6620efe 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -54,10 +54,10 @@ jobs: ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb make -j$(nproc) make install - - name: Clone Parsee - uses: actions/checkout@v3 - - name: Build Parsee + - name: Clone/Build Parsee run: | + git clone https://git.kappach.at/${{ github.repository}} parsee + cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" echo "all: adminify aya b64 config noavatars" > tools/Makefile echo "%: %.c" >> tools/Makefile From 4dcd989c8bdfff94298fa103b38614e1b2f9f0b9 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 10:05:07 +0200 Subject: [PATCH 029/186] [CI] Use the PREFIX less --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 6620efe..51087bf 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -61,7 +61,7 @@ jobs: alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" echo "all: adminify aya b64 config noavatars" > tools/Makefile echo "%: %.c" >> tools/Makefile - echo "$(printf '\\t')musl-gcc -I ${PREFIX}/usr/include -static -o $(PREFIX)/$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + echo "$(printf '\\t')musl-gcc -I ../usr/include -static -o $(PREFIX)/$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm ls $PREFIX From 4496f377fd2b01a6e7d32fbfc2811d587a3100c7 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 11:10:33 +0200 Subject: [PATCH 030/186] [CI] Even less prefix --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 51087bf..1788b88 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -61,7 +61,7 @@ jobs: alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" echo "all: adminify aya b64 config noavatars" > tools/Makefile echo "%: %.c" >> tools/Makefile - echo "$(printf '\\t')musl-gcc -I ../usr/include -static -o $(PREFIX)/$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + echo "$(printf '\\t')musl-gcc -I ../usr/include -static -o ../$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm ls $PREFIX From 2955787aa240bbb90c9d0ca228c52e08050555c3 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 11:17:31 +0200 Subject: [PATCH 031/186] [CI] Please? --- .forgejo/workflows/build-release.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 1788b88..9c0c34b 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -59,9 +59,13 @@ jobs: git clone https://git.kappach.at/${{ github.repository}} parsee cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" + export TAB=$(printf '\t') echo "all: adminify aya b64 config noavatars" > tools/Makefile echo "%: %.c" >> tools/Makefile - echo "$(printf '\\t')musl-gcc -I ../usr/include -static -o ../$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + echo "${TAB}musl-gcc -I ../usr/include -static -o ../$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + cd tools + make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib + cd .. make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm ls $PREFIX From 7ab99982f568e27fdaeab036d1ee19deeffb1506 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 11:28:15 +0200 Subject: [PATCH 032/186] [CI] Escape $s --- .forgejo/workflows/build-release.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 9c0c34b..68fb3a7 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -62,9 +62,10 @@ jobs: export TAB=$(printf '\t') echo "all: adminify aya b64 config noavatars" > tools/Makefile echo "%: %.c" >> tools/Makefile - echo "${TAB}musl-gcc -I ../usr/include -static -o ../$@.$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + echo "${TAB}musl-gcc -I ../usr/include -static -o ../\$@.\$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile + cat tools/Makefile cd tools - make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib + make cd .. make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm From e9b36730b596f263b1ff25b342c45c232b8dc0eb Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 11:49:26 +0200 Subject: [PATCH 033/186] [CI] C'est le commit final --- .forgejo/workflows/build-release.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 68fb3a7..ab2d224 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -70,4 +70,17 @@ jobs: make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm ls $PREFIX - + - name: Create a final archive + run: | + cd parsee + mkdir bin + cp "${PREFIX}/parsee.$(uname -m)" bin + cp ../*.$(uname -m) bin + tar -czvf "$(uname)-$(uname -m).tgz" bin + cp "$(uname)-$(uname -m).tgz" .. + echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV + - name: Upload it all + uses: actions/upload-artifact@v4 + with: + name: ${{ env.PGZ }} + path: ${{ env.PGZ }} From 0c402d80322860c82f8174f50fe32f58e8b4650e Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 11:56:49 +0200 Subject: [PATCH 034/186] [CI] it was, infact, not the last commit --- .forgejo/workflows/build-release.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index ab2d224..f5cd15a 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -74,8 +74,9 @@ jobs: run: | cd parsee mkdir bin + cd .. cp "${PREFIX}/parsee.$(uname -m)" bin - cp ../*.$(uname -m) bin + cp $(find .. -name "*.$(uname -m)") bin tar -czvf "$(uname)-$(uname -m).tgz" bin cp "$(uname)-$(uname -m).tgz" .. echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV From aef19d5eaf74fde98a259bb7a33ea35fd7f61cbe Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:03:15 +0200 Subject: [PATCH 035/186] [CI] Should do it, I think --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index f5cd15a..8cd5191 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -74,7 +74,7 @@ jobs: run: | cd parsee mkdir bin - cd .. + ls "${PREFIX}" cp "${PREFIX}/parsee.$(uname -m)" bin cp $(find .. -name "*.$(uname -m)") bin tar -czvf "$(uname)-$(uname -m).tgz" bin From 0e746465c666272b79c28dbce743a8922452a143 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:13:14 +0200 Subject: [PATCH 036/186] [CI] Help. --- .forgejo/workflows/build-release.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 8cd5191..18325ca 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -73,11 +73,11 @@ jobs: - name: Create a final archive run: | cd parsee - mkdir bin + mkdir bins ls "${PREFIX}" - cp "${PREFIX}/parsee.$(uname -m)" bin - cp $(find .. -name "*.$(uname -m)") bin - tar -czvf "$(uname)-$(uname -m).tgz" bin + cp "${PREFIX}/parsee.$(uname -m)" bins + cp $(find . -name "*.$(uname -m)") bins + tar -czvf "$(uname)-$(uname -m).tgz" bins cp "$(uname)-$(uname -m).tgz" .. echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV - name: Upload it all From 9e4348c6e31de0dc6f075fe47d4aff50858be9ce Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:20:21 +0200 Subject: [PATCH 037/186] [CI] AAA --- .forgejo/workflows/build-release.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 18325ca..7a6c168 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -68,14 +68,15 @@ jobs: make cd .. make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true - musl-gcc -static -o "${PREFIX}/parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm + musl-gcc -static -o "parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm ls $PREFIX - name: Create a final archive run: | cd parsee mkdir bins ls "${PREFIX}" - cp "${PREFIX}/parsee.$(uname -m)" bins + ls . + cp "parsee.$(uname -m)" bins cp $(find . -name "*.$(uname -m)") bins tar -czvf "$(uname)-$(uname -m).tgz" bins cp "$(uname)-$(uname -m).tgz" .. From 5c5540ffa6d8f1ea21c5cb83d4fbba1740f7ce8a Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:25:46 +0200 Subject: [PATCH 038/186] [CI] By Jove, I think I got it! --- .forgejo/workflows/build-release.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 7a6c168..12e95b1 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -76,8 +76,7 @@ jobs: mkdir bins ls "${PREFIX}" ls . - cp "parsee.$(uname -m)" bins - cp $(find . -name "*.$(uname -m)") bins + cp $(find . -maxdepth 1 -name "*.$(uname -m)") bins tar -czvf "$(uname)-$(uname -m).tgz" bins cp "$(uname)-$(uname -m).tgz" .. echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV From 79c94759daf8f4cccc93f891d115b28aa96fbe50 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:33:26 +0200 Subject: [PATCH 039/186] [CI] TFW it's broken --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 12e95b1..b1d51aa 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -81,7 +81,7 @@ jobs: cp "$(uname)-$(uname -m).tgz" .. echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV - name: Upload it all - uses: actions/upload-artifact@v4 + uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: name: ${{ env.PGZ }} path: ${{ env.PGZ }} From 79e65f0822e1371ff2b584be48064f09443a39ce Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:42:31 +0200 Subject: [PATCH 040/186] [CI] Label artifact as tar.gz.zip --- .forgejo/workflows/build-release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index b1d51aa..eef3708 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -80,8 +80,8 @@ jobs: tar -czvf "$(uname)-$(uname -m).tgz" bins cp "$(uname)-$(uname -m).tgz" .. echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV - - name: Upload it all + - name: Upload it all(as a ZIP of a .TGZ) uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: - name: ${{ env.PGZ }} + name: ${{ env.PGZ }}.zip path: ${{ env.PGZ }} From b55457d5fe0e4ef7ad86cb93be4cc45bf92df7cd Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:43:11 +0200 Subject: [PATCH 041/186] [CI] Actual tgz.zip --- .forgejo/workflows/build-release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index eef3708..4ffebd0 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -77,9 +77,9 @@ jobs: ls "${PREFIX}" ls . cp $(find . -maxdepth 1 -name "*.$(uname -m)") bins - tar -czvf "$(uname)-$(uname -m).tgz" bins + tar -czvf "$(uname)-$(uname -m).tar.gz" bins cp "$(uname)-$(uname -m).tgz" .. - echo "PGZ=$(uname)-$(uname -m).tgz" >> $GITHUB_ENV + echo "PGZ=$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: From 5c7189f51822add1f3a76a54d7b8c7c02ff2a947 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:53:27 +0200 Subject: [PATCH 042/186] [CI] Is he stupid? --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 4ffebd0..4aa3715 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -78,7 +78,7 @@ jobs: ls . cp $(find . -maxdepth 1 -name "*.$(uname -m)") bins tar -czvf "$(uname)-$(uname -m).tar.gz" bins - cp "$(uname)-$(uname -m).tgz" .. + cp "$(uname)-$(uname -m).tar.gz" .. echo "PGZ=$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) uses: https://github.com/christopherhx/gitea-upload-artifact@v4 From 619f49f8c8d98ac74420b27cad33ff421460d70c Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 12:59:20 +0200 Subject: [PATCH 043/186] [CI] Don't actually suffix ZIP, I think --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 4aa3715..f20b6bf 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -83,5 +83,5 @@ jobs: - name: Upload it all(as a ZIP of a .TGZ) uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: - name: ${{ env.PGZ }}.zip + name: ${{ env.PGZ }} path: ${{ env.PGZ }} From 0586e863e7efc8dce2698749a5fc2c5de5fd9fd7 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 15:10:03 +0200 Subject: [PATCH 044/186] [CI] Try using directory --- .forgejo/workflows/build-release.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index f20b6bf..2ec42e5 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -79,9 +79,10 @@ jobs: cp $(find . -maxdepth 1 -name "*.$(uname -m)") bins tar -czvf "$(uname)-$(uname -m).tar.gz" bins cp "$(uname)-$(uname -m).tar.gz" .. - echo "PGZ=$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV + echo "NAM=parsee-$(uname)-$(uname -m)" >> $GITHUB_ENV + echo "DIR=$PWD/bins" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: name: ${{ env.PGZ }} - path: ${{ env.PGZ }} + path: ${{ env.DIR }} From 355a9d9b99258fa948ac5a2da39feb616eb2f2f6 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 11 Sep 2024 15:15:46 +0200 Subject: [PATCH 045/186] [CI] Oops --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 2ec42e5..e2e1312 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -84,5 +84,5 @@ jobs: - name: Upload it all(as a ZIP of a .TGZ) uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: - name: ${{ env.PGZ }} + name: ${{ env.NAM }} path: ${{ env.DIR }} From 9352bf9bba4191bab55075f3ec2c99cfe29a49f1 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 20:02:40 +0200 Subject: [PATCH 046/186] [META] Death to GNUMakefile and build.c Soon bound to add a -s flag for static build. --- .forgejo/workflows/check-gcc.yaml | 1 + .gitignore | 2 + Makefile | 90 ---- build.c | 863 ------------------------------ configure.c | 622 +++++++++++++++++++++ 5 files changed, 625 insertions(+), 953 deletions(-) delete mode 100644 Makefile delete mode 100644 build.c create mode 100644 configure.c diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 38d32ca..8f6f4a2 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -24,6 +24,7 @@ jobs: uses: actions/checkout@v3 - name: Build Parsee run: | + cc configure.c -o configure && ./configure echo 'CFLAGS=-Werror -Wall -Wextra -pedantic' >> build.conf cat build.conf make && make ayadoc diff --git a/.gitignore b/.gitignore index 6104661..05919ab 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ parsee .* data data/* +Makefile +configure tools/out tools/out/* diff --git a/Makefile b/Makefile deleted file mode 100644 index c1125b3..0000000 --- a/Makefile +++ /dev/null @@ -1,90 +0,0 @@ -# (GNU)Makefile for building Parsee -# ================================ -# TODO: Consider making something akin to a configure script that checks -# for dependencies, or maybe even use *autoconf* (the devil!) - - -# =========================== Parsee Flags ============================= - -include build.conf - -REPOSITORY=$(shell git remote get-url origin) - -# =========================== Compilation Flags ============================ -CYTO_INC ?=/usr/local/include/ # Where Cytoplasm's include path is - # located. -CYTO_LIB ?=/usr/local/lib # Where's Cytoplasm's library is - # located. -PREFIX ?=/usr/local - -AYAS=ayaya -ETC=etc -FCFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -DCODE=\"$(CODE)\" $(CFLAGS) -FLDFLAGS=-L $(CYTO_LIB) -lCytoplasm $(LDFLAGS) -AFLAGS=-C "$(ETC)/ayadoc/style.css" -p "$(NAME)" -# ============================ Compilation ================================= -SRC_FILES:=$(shell find $(SOURCE) -name '*.c') $(shell find $(ETC)/media -name '*.png') -OBJ_FILES:=${subst $(ETC)/media/,$(OBJECT)/,${subst $(SOURCE)/,$(OBJECT)/,$(patsubst %.png, %.o, $(patsubst %.c, %.o, $(SRC_FILES)))}} - -CPP_FILES:=$(shell find $(INCLUDES) -name '*.h') -AYA_FILES:=${subst $(INCLUDES)/,$(AYAS)/,$(patsubst %.h, %.html, $(CPP_FILES))} - -all: utils binary - -binary: $(OBJ_FILES) - $(CC) $(FLDFLAGS) $(OBJ_FILES) -o $(BINARY) -tags: $(SRC_FILES) - @ctags --recurse $(SOURCE)/ - -clean: - rm -rf $(OBJECT) $(BINARY) $(AYAS) - -$(OBJECT)/%.o: $(ETC)/media/%.png - @mkdir -p $(shell dirname "$@") - @echo "const char media_$(shell basename $< .png)[] =" > $@.c - @base64 $< | \ - sed -e 's/^\(.*\)$$/ "\1"/' | \ - sed -e '$$ s/^\(.*\)$$/\1;/' >> $@.c - $(CC) -c $(FCFLAGS) $@.c -o $@ -$(OBJECT)/%.o: $(SOURCE)/%.c - @mkdir -p $(shell dirname "$@") - $(CC) -c $(FCFLAGS) $< -o $@ - -utils: - (cd tools && make) - -ayadoc: utils $(AYA_FILES) - -$(AYAS)/%.html: $(INCLUDES)/%.h - @mkdir -p $(shell dirname "$@") - tools/out/aya $(AFLAGS) -i $< -o $@ - - -# Installs everything. -install: binary utils ayadoc install_setup install_parsee install_tools install_aya install_man - @echo Installed $(NAME) to $(PREFIX)! - -install_setup: - install -dm755 "$(PREFIX)/bin" - install -dm755 "$(PREFIX)/share/doc" - install -dm755 "$(PREFIX)/man" - -install_parsee: - install -Dm755 "$(BINARY)" "$(PREFIX)/bin/$(BINARY)" - -TOOLS:=$(shell find 'tools/out' -name '*') -ITOOL:=${subst tools/out/,$(PREFIX)/bin/,$(patsubst tools/out/%, tools/out/$(BINARY)-%, $(TOOLS))} -install_tools: $(ITOOL) -$(PREFIX)/bin/$(BINARY)-%: tools/out/% - install -Dm755 "$<" "$@" - -IHTML:=${subst $(AYAS)/,$(PREFIX)/share/doc/$(BINARY)/,$(AYA_FILES)} -install_aya: $(IHTML) -$(PREFIX)/share/doc/$(BINARY)/%: $(AYAS)/% - install -Dm644 "$<" "$@" - -MPAGE:=$(shell find 'etc/man' -name '*.*') -PPAGE:=${subst etc/man/,$(PREFIX)/man/,$(MPAGE)} -install_man: $(PPAGE) -$(PREFIX)/man/%: etc/man/% - install -Dm644 "$<" "$@" diff --git a/build.c b/build.c deleted file mode 100644 index b80a7d9..0000000 --- a/build.c +++ /dev/null @@ -1,863 +0,0 @@ -/* build.c - Simple, POSIX, non-Cytoplasm utility to build out - * the entirety of Parsee from scratch, without any Makefiles. - * - * The main reason why this tool exists is merely because the - * current Make-based building is not POSIX compliant, and I - * am simply not porting it to be. The Makefile shall stay - * supported however, but if possible, use build.c. - * To run it, just build it with: - * cc build.c -o /tmp/build && /tmp/build - * - * TODO: Parallel jobs, CFLAGS and LDFLAGS. - * Note that this bit is formatted differently. - * -------------------------------- - * LICENSE: CC0 - * Written-By: LDA [lda@freetards.xyz] [@fourier:ari.lt] */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_BUILD_PATH "build.conf" -#define DEFAULT_COMPILER "cc" -#define Compiler(info) (info.basic.cc ? info.basic.cc : DEFAULT_COMPILER) - -static char * -string_rep_ext(char *in, char *ext1, char *ext2) -{ - char *end; - size_t inLen; - if (!in || !ext1 || !ext2) - { - return NULL; - } - - inLen = strlen(in); - end = inLen + in; - - while (end >= in) - { - if (!strcmp(end, ext1)) - { - size_t cpyLen = end - in; - size_t extLen = strlen(ext2); - char *ret = malloc(cpyLen + extLen + 1); - - memcpy(ret, in, cpyLen); - memcpy(ret + cpyLen, ext2, extLen); - ret[cpyLen + extLen] = '\0'; - return ret; - } - end--; - } - return NULL; -} -static char * -string_dup(char *in) -{ - char *out; - size_t len; - if (!in) - { - return NULL; - } - len = strlen(in); - out = malloc(len + 1); - memcpy(out, in, len); - out[len] = '\0'; - - return out; -} -static char * -string_cat(char *in1, char *in2) -{ - char *out; - size_t len1, len2; - if (!in1) - { - return string_dup(in2); - } - if (!in2) - { - return string_dup(in1); - } - - len1 = strlen(in1); - len2 = strlen(in2); - out = malloc(len1 + len2 + 1); - memcpy(out, in1, len1); - memcpy(out + len1, in2, len2); - out[len1 + len2] = '\0'; - - return out; -} -static char * -trim_nl(char *in) -{ - char *tc; - if (!in) - { - return NULL; - } - - while ((tc = strrchr(in, '\n'))) - { - *tc = '\0'; - } - - return in; -} - -typedef struct str_array { - char **values; - size_t quantity; -} str_array_t; -static str_array_t * -str_array_create(void) -{ - str_array_t *ret = malloc(sizeof(*ret)); - - ret->values = NULL; - ret->quantity = 0; - return ret; -} -static void -str_array_free(str_array_t *arr) -{ - size_t i; - if (!arr) - { - return; - } - - for (i = 0; i < arr->quantity; i++) - { - if (arr->values[i]) free(arr->values[i]); - } - if (arr->values) free(arr->values); - free(arr); -} -static void -str_array_set(str_array_t *arr, size_t i, char *str) -{ - if (!arr) - { - return; - } - - if (i >= arr->quantity) - { - size_t size = (i+1) * sizeof(*arr->values); - size_t j; - arr->values = realloc(arr->values, size); - for (j = arr->quantity; j <= i; j++) - { - arr->values[j] = NULL; - } - arr->quantity = i + 1 ; - } - if (arr->values[i]) free(arr->values[i]); - arr->values[i] = string_dup(str); -} -static void -str_array_add(str_array_t *arr, char *str) -{ - if (!arr) - { - return; - } - str_array_set(arr, arr->quantity, str); -} -static char * -str_array_get(str_array_t *arr, size_t i) -{ - if (!arr) - { - return NULL; - } - return i < arr->quantity ? arr->values[i] : NULL; -} -static size_t -str_array_len(str_array_t *arr) -{ - return arr ? arr->quantity : 0; -} - -typedef struct buildinfo { - struct basic { - char *codename; - char *version; - - char *name; - - char *binary; - - char *src; - char *inc; - char *obj; - - char *cflags, *ldflags; - - char *cc; - } basic; - - char *repo; -} buildinfo_t; -static void -destroy_buildinfo(buildinfo_t *info) -{ - if (!info) - { - return; - } - -#define FreeIfExistent(v) do \ - { \ - if (v) \ - { \ - free(v); \ - v = NULL; \ - } \ - } while (0) - - FreeIfExistent(info->basic.codename); - FreeIfExistent(info->basic.version); - FreeIfExistent(info->basic.ldflags); - FreeIfExistent(info->basic.binary); - FreeIfExistent(info->basic.cflags); - FreeIfExistent(info->basic.name); - FreeIfExistent(info->basic.src); - FreeIfExistent(info->basic.inc); - FreeIfExistent(info->basic.obj); - FreeIfExistent(info->basic.cc); - FreeIfExistent(info->repo); -} - -static char * -cmd_stdout(char *cmd) -{ - FILE *f; - char *line = NULL; - size_t size; - if (!cmd) - { - return NULL; - } - if (!(f = popen(cmd, "r"))) - { - return NULL; - } - - getline(&line, &size, f); - pclose(f); - return line; -} -static int -exec_code(char *program, char *argv[]) -{ - pid_t forkRet; - if (!program || !argv) - { - return -1; - } - - forkRet = fork(); - if (forkRet == 0) - { - /* Child */ - execvp(program, argv); - exit(0); - } - else - { - /* Parent */ - int status; - if (waitpid(forkRet, &status, 0) == -1) - { - return -1; - } - return status; - } - - /* We're not meant to ever be there, but TCC is stupid. */ - return -1; -} - -static char * -strchrn(char *s, char c) -{ - s = strchr(s, c); - return s ? s+1 : NULL; -} -static char * -strchrl(char *s, char c) -{ - char *s1 = NULL; - while ((s = strchr(s, c))) - { - s1 = s; - s++; - } - return s1; -} -static void -mkdir_rec(char *dir) -{ - char tmp[PATH_MAX]; - char *start; - if (!dir || strlen(dir) >= PATH_MAX - 1) - { - return; - } - - memset(tmp, '\0', sizeof(tmp)); - for (start = dir; start && *start; start = strchrn(start, '/')) - { - char subtmp[PATH_MAX]; - char *next = strchr(start, '/'); - if (!next) - { - next = start + strlen(start); - } - memcpy(subtmp, start, next - start); - subtmp[next - start] = '\0'; - - { - memcpy(tmp, dir, start - dir); - tmp[strlen(tmp) - 1] = '\0'; - mkdir(tmp, 0770); - } - } -} -static str_array_t * -split(char *dir) -{ - str_array_t *ret; - char *start; - if (!dir || strlen(dir) >= PATH_MAX - 1) - { - return NULL; - } - - ret = str_array_create(); - for (start = dir; start; start = strchrn(start, ' ')) - { - char subtmp[PATH_MAX]; - char *next = strchr(start, ' '); - if (!next) - { - next = start + strlen(start); - } - memcpy(subtmp, start, next - start); - subtmp[next - start] = '\0'; - - str_array_add(ret, subtmp); - } - return ret; -} -static time_t -mod_date(char *file) -{ - struct stat s; - if (stat(file, &s)) - { - return (time_t) 0; - } - return s.st_mtime; -} -static bool -build_file(char *cSource, buildinfo_t info, bool isTool) -{ - str_array_t *args, *cflags; - char *oFileName, *objPath, *oFile; - int ret, i = 0; - int srclen; - - char *code, *name, *vers, *repo; - if (!cSource) - { - return false; - } - - if (!isTool) - { - srclen = strncmp(cSource, "src", 3) ? - strlen(info.basic.obj) + 1 : - strlen(info.basic.src) + 1 ; - objPath = string_cat(info.basic.obj, "/"); - oFile = string_rep_ext(cSource + srclen, ".c", ".o"); - oFileName = string_cat(objPath, oFile); - } - else - { - srclen = 6; - objPath = string_dup("tools/out/"); - oFile = string_rep_ext(cSource + srclen, ".c", ""); - oFileName = string_cat(objPath, oFile); - } - mkdir_rec(oFileName); - - if (!isTool && (mod_date(cSource) < mod_date(oFileName))) - { - free(objPath); - free(oFileName); - free(oFile); - return true; - } - - args = str_array_create(); - if (!isTool) - { - printf("\tCC %s...\n", cSource); - } - - str_array_add(args, Compiler(info)); - if (isTool) - { - str_array_add(args, "-lCytoplasm"); - str_array_add(args, "-I."); - } - else - { - str_array_add(args, "-c"); - } - str_array_add(args, cSource); - - cflags = split(info.basic.cflags); - for (i = 0; i < str_array_len(cflags); i++) - { - str_array_add(args, str_array_get(cflags, i)); - } - str_array_free(cflags); - - str_array_add(args, "-o"); - str_array_add(args, oFileName); - - str_array_add(args, "-I"); - str_array_add(args, info.basic.inc); - str_array_add(args, "-I"); - str_array_add(args, info.basic.src); - - { - char *pre = string_cat("\"", info.basic.version); - char *pos = string_cat(pre, "\""); - vers = string_cat("-DVERSION=", pos); - str_array_add(args, vers); - - free(pos); - free(pre); - } - { - char *pre = string_cat("\"", info.basic.name); - char *pos = string_cat(pre, "\""); - name = string_cat("-DNAME=", pos); - str_array_add(args, name); - - free(pos); - free(pre); - } - { - char *pre = string_cat("\"", info.basic.codename); - char *pos = string_cat(pre, "\""); - code = string_cat("-DCODE=", pos); - str_array_add(args, code); - - free(pos); - free(pre); - } - { - char *pre = string_cat("\"", info.repo); - char *pos = string_cat(pre, "\""); - repo = string_cat("-DREPOSITORY=", pos); - str_array_add(args, repo); - - free(pos); - free(pre); - } - - str_array_add(args, NULL); - - ret = exec_code(Compiler(info), args->values); - - str_array_free(args); - free(objPath); - free(oFileName); - free(oFile); - free(vers); - free(name); - free(code); - free(repo); - return ret == EXIT_SUCCESS; -} -static bool -finalise_file(str_array_t *arr, buildinfo_t info) -{ - str_array_t *flags, *ldflags; - size_t i; - bool ret = true; - if (!arr) - { - return false; - } - - flags = str_array_create(); - str_array_add(flags, Compiler(info)); - - ldflags = split(info.basic.cflags); - for (i = 0; i < str_array_len(ldflags); i++) - { - str_array_add(flags, str_array_get(ldflags, i)); - } - str_array_free(ldflags); - - str_array_add(flags, "-lCytoplasm"); - - for (i = 0; i < str_array_len(arr); i++) - { - char *file = str_array_get(arr, i); - if (file) - { - size_t srclen = strncmp(file, "src", 3) ? - strlen(info.basic.obj) + 1 : - strlen(info.basic.src) + 1 ; - char *objPath = string_cat(info.basic.obj, "/"); - char *oFile = string_rep_ext(file + srclen, ".c", ".o"); - char *oFileName = string_cat(objPath, oFile); - - str_array_add(flags, oFileName); - - free(oFileName); - free(oFile); - free(objPath); - } - } - - str_array_add(flags, "-o"); - str_array_add(flags, info.basic.binary); - str_array_add(flags, NULL); - ret = exec_code(Compiler(info), flags->values); - - str_array_free(flags); - return ret; -} - -static str_array_t * -collect_sources(char *dir, bool head, char *ext) -{ - DIR *handle; - str_array_t *ret; - struct dirent *ent; - if (!dir) - { - return NULL; - } - - ret = str_array_create(); - handle = opendir(dir); - if (!handle) - { - printf("error: cannot open directory '%s'\n", dir); - return ret; - } - while ((ent = readdir(handle))) - { - char *name = ent->d_name; - if (*name == '.') continue; - - if (strlen(name) > strlen(ext) && - !strcmp(name + strlen(name) - strlen(ext), ext)) - { - char *d1 = string_cat(dir, "/"); - char *na = string_cat(d1, name); - str_array_add(ret, na); - free(d1); - free(na); - continue; - } - if (!strchr(name, '.') && - strcmp(name, "out") && - strcmp(name, "Makefile")) - { - str_array_t *sub; - char *d1 = string_cat(dir, "/"); - char *d2 = string_cat(d1, name); - size_t i; - - sub = collect_sources(d2, false, ext); - for (i = 0; i < str_array_len(sub); i++) - { - char *file = str_array_get(sub, i); - str_array_add(ret, file); - } - str_array_free(sub); - free(d2); - free(d1); - } - } - closedir(handle); - return ret; -} - -static char * -process_png(char *png, buildinfo_t info) -{ - size_t i = 0; - char *symbol; - char *cFile, *oFile; - char *pcFile, *poFile; - char *pcFile1, *poFile1; - char *filename, *symbol1; - char *arguments[8] = { 0 }; - if (!png) - { - return NULL; - } - - if (!(filename = strchrl(png, '/'))) - { - return NULL; - } - filename++; - - pcFile1= string_cat(info.basic.obj, "/"); - pcFile = string_cat(pcFile1, filename); - cFile = string_rep_ext(pcFile, ".png", ".c"); - free(pcFile); - free(pcFile1); - - poFile1= string_cat(info.basic.obj, "/"); - poFile = string_cat(poFile1, filename); - oFile = string_rep_ext(poFile, ".png", ".o"); - free(poFile); - free(poFile1); - - symbol1 = string_rep_ext(filename, ".png", ""); - symbol = string_cat("media_", symbol1); - free(symbol1); - - mkdir_rec(oFile); - mkdir_rec(cFile); - - /* Build the image into Base64 */ - arguments[i++] = "tools/out/b64"; - arguments[i++] = png; - arguments[i++] = symbol; - arguments[i++] = cFile; - arguments[i++] = NULL; - - if (exec_code(arguments[0], arguments)) - { - free(symbol); - free(cFile); - free(oFile); - return NULL; - } - - /* Compile it out */ - i = 0; - arguments[i++] = Compiler(info); - arguments[i++] = "-c"; - arguments[i++] = cFile; - arguments[i++] = "-o"; - arguments[i++] = oFile; - arguments[i++] = NULL; - - if (exec_code(arguments[0], arguments)) - { - free(symbol); - free(cFile); - free(oFile); - return NULL; - } - - free(symbol); - free(oFile); - return cFile; -} -/* Builds the entirety of Parsee. */ -static int -main_build(int argc, char *argv[]) -{ - buildinfo_t info = { 0 }; - FILE *buildinfo = NULL; - char *line = NULL; - size_t size, i; - ssize_t nread; - str_array_t *sources, *images; - - /* Step 1: Get all basic information from build.conf */ - if (!(buildinfo = fopen(DEFAULT_BUILD_PATH, "r"))) - { - printf("error: cannot open '%s'\n", DEFAULT_BUILD_PATH); - goto fail; - } - while ((nread = getline(&line, &size, buildinfo)) != -1) - { - char *eq = strchr(line, '='); - char *end = strchr(line, '\n'); - - char *key, *val; - if (!eq) - { - free(line); - printf( - "error: line in '%s' does not contain '='\n", - DEFAULT_BUILD_PATH - ); - goto fail; - } - - /* Set delimiters */ - *eq = '\0'; - if (end) *end = '\0'; - - key = line; - val = eq + 1; - - /* Now, we have KV mappings. */ -#define If(k, v, d) do \ - { \ - if (!strcmp(key, k) && !info.v) \ - { \ - info.v = string_dup(val); \ - printf("%s: %s\n", d, val); \ - } \ - } while (0) - - If("CODE", basic.codename, "Codename"); - If("NAME", basic.name, "Name"); - If("VERSION", basic.version, "Version"); - If("BINARY", basic.binary, "Binary name"); - - If("CFLAGS", basic.cflags, "C compiler arguments"); - If("LDFLAGS", basic.ldflags, "Linker arguments"); - - If("INCLUDES", basic.inc, "Include path"); - If("SOURCE", basic.src, "Source path"); - If("OBJECT", basic.obj, "Object path"); - If("CC", basic.cc, "Compiler"); - } - if (line) - { - free(line); - line = NULL; - } - - fclose(buildinfo); - buildinfo = NULL; - - /* Step 2: Get all information from commands. */ - if (!(info.repo = cmd_stdout("git remote get-url origin"))) - { - printf("error: cannot find origins url\n"); - goto fail; - } - info.repo = trim_nl(info.repo); - - if (argc >= 2 && !strcmp(argv[1], "clean")) - { - char *args[8]; - size_t i; - unlink(info.basic.binary); - - args[i++] = "rm"; - args[i++] = "-r"; - args[i++] = info.basic.obj; - args[i++] = NULL; - exec_code(args[0], args); - goto end; - } - - - /* Step 3: Build all utilities. */ - sources = collect_sources("tools", true, ".c"); - for (i = 0; i < str_array_len(sources); i++) - { - char *file = str_array_get(sources, i); - printf("\tTOOL %s...\n", file); - if (!build_file(file, info, true)) - { - str_array_free(sources); - goto fail; - } - } - str_array_free(sources); - - /* Step 4: Build all media files. */ - sources = collect_sources(info.basic.src, true, ".c"); - images = collect_sources("etc/media", true, ".png"); - for (i = 0; i < str_array_len(images); i++) - { - char *file = str_array_get(images, i); - char *out; - - out = process_png(file, info); - if (!out) - { - str_array_free(images); - str_array_free(sources); - goto fail; - } - printf("\tPNG %s\n", file); - str_array_add(sources, out); - free(out); - } - str_array_free(images); - - /* Step 5: Build all of Parsee itself */ - for (i = 0; i < str_array_len(sources); i++) - { - char *file = str_array_get(sources, i); - if (!build_file(file, info, false)) - { - str_array_free(sources); - goto fail; - } - } - printf("\tLINK\n"); - if (!finalise_file(sources, info)) - { - str_array_free(sources); - goto fail; - } - str_array_free(sources); - /* TODO: Step 6: Build every Ayadoc */ -end: - destroy_buildinfo(&info); - return EXIT_SUCCESS; -fail: - if (buildinfo) - { - fclose(buildinfo); - buildinfo = NULL; - } - destroy_buildinfo(&info); - return EXIT_FAILURE; -} - -int -main(int argc, char *argv[]) -{ - /* TODO: Multiple flags(build/install/ayadoc/...) */ - if ((argc - 1) < 1) - { - /* No arguments, let's just build. */ - return main_build(argc, argv); - } - - if (!strcmp(argv[1], "build") || - !strcmp(argv[1], "clean")) - { - return main_build(argc, argv); - } - - printf("%s: unknown verb: %s\n", argv[0], argv[1]); - return EXIT_FAILURE; -} diff --git a/configure.c b/configure.c new file mode 100644 index 0000000..4d67d07 --- /dev/null +++ b/configure.c @@ -0,0 +1,622 @@ +/* configure.c - Simple, POSIX, non-Cytoplasm utility to build out + * a Parsee Makefile. + * To run it, just build it with: + * cc configure.c -o configure && configure + * -------------------------------- + * LICENSE: CC0 + * Written-By: LDA [lda@freetards.xyz] [@fourier:ari.lt] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char * +string_rep_ext(char *in, char *ext1, char *ext2) +{ + char *end; + size_t inLen; + if (!in || !ext1 || !ext2) + { + return NULL; + } + + inLen = strlen(in); + end = inLen + in; + + while (end >= in) + { + if (!strcmp(end, ext1)) + { + size_t cpyLen = end - in; + size_t extLen = strlen(ext2); + char *ret = malloc(cpyLen + extLen + 1); + + memcpy(ret, in, cpyLen); + memcpy(ret + cpyLen, ext2, extLen); + ret[cpyLen + extLen] = '\0'; + return ret; + } + end--; + } + return NULL; +} +static char * +string_dup(char *in) +{ + char *out; + size_t len; + if (!in) + { + return NULL; + } + len = strlen(in); + out = malloc(len + 1); + memcpy(out, in, len); + out[len] = '\0'; + + return out; +} +static char * +string_cat(char *in1, char *in2) +{ + char *out; + size_t len1, len2; + if (!in1) + { + return string_dup(in2); + } + if (!in2) + { + return string_dup(in1); + } + + len1 = strlen(in1); + len2 = strlen(in2); + out = malloc(len1 + len2 + 1); + memcpy(out, in1, len1); + memcpy(out + len1, in2, len2); + out[len1 + len2] = '\0'; + + return out; +} +static char * +trim_nl(char *in) +{ + char *tc; + if (!in) + { + return NULL; + } + + while ((tc = strrchr(in, '\n'))) + { + *tc = '\0'; + } + + return in; +} + +typedef struct str_array { + char **values; + size_t quantity; +} str_array_t; +static str_array_t * +str_array_create(void) +{ + str_array_t *ret = malloc(sizeof(*ret)); + + ret->values = NULL; + ret->quantity = 0; + return ret; +} +static void +str_array_free(str_array_t *arr) +{ + size_t i; + if (!arr) + { + return; + } + + for (i = 0; i < arr->quantity; i++) + { + if (arr->values[i]) free(arr->values[i]); + } + if (arr->values) free(arr->values); + free(arr); +} +static void +str_array_set(str_array_t *arr, size_t i, char *str) +{ + if (!arr) + { + return; + } + + if (i >= arr->quantity) + { + size_t size = (i+1) * sizeof(*arr->values); + size_t j; + arr->values = realloc(arr->values, size); + for (j = arr->quantity; j <= i; j++) + { + arr->values[j] = NULL; + } + arr->quantity = i + 1 ; + } + if (arr->values[i]) free(arr->values[i]); + arr->values[i] = string_dup(str); +} +static void +str_array_add(str_array_t *arr, char *str) +{ + if (!arr) + { + return; + } + str_array_set(arr, arr->quantity, str); +} +static char * +str_array_get(str_array_t *arr, size_t i) +{ + if (!arr) + { + return NULL; + } + return i < arr->quantity ? arr->values[i] : NULL; +} +static size_t +str_array_len(str_array_t *arr) +{ + return arr ? arr->quantity : 0; +} +static char * +cmd_stdout(char *cmd) +{ + FILE *f; + char *line = NULL; + size_t size; + if (!cmd) + { + return NULL; + } + if (!(f = popen(cmd, "r"))) + { + return NULL; + } + + getline(&line, &size, f); + pclose(f); + return line; +} +static int +exec_code(char *program, char *argv[]) +{ + pid_t forkRet; + if (!program || !argv) + { + return -1; + } + + forkRet = fork(); + if (forkRet == 0) + { + /* Child */ + execvp(program, argv); + exit(0); + } + else + { + /* Parent */ + int status; + if (waitpid(forkRet, &status, 0) == -1) + { + return -1; + } + return status; + } + + /* We're not meant to ever be there, but TCC is stupid. */ + return -1; +} + +static char * +strchrn(char *s, char c) +{ + s = strchr(s, c); + return s ? s+1 : NULL; +} +static char * +strchrl(char *s, char c) +{ + char *s1 = NULL; + while ((s = strchr(s, c))) + { + s1 = s; + s++; + } + return s1; +} +static str_array_t * +split(char *dir) +{ + str_array_t *ret; + char *start; + if (!dir || strlen(dir) >= PATH_MAX - 1) + { + return NULL; + } + + ret = str_array_create(); + for (start = dir; start; start = strchrn(start, '/')) + { + char subtmp[PATH_MAX]; + char *next = strchr(start, '/'); + if (!next) + { + next = start + strlen(start); + } + memcpy(subtmp, start, next - start); + subtmp[next - start] = '\0'; + + str_array_add(ret, subtmp); + } + return ret; +} +static str_array_t * +collect_sources(char *dir, bool head, char *ext) +{ + DIR *handle; + str_array_t *ret; + struct dirent *ent; + if (!dir) + { + return NULL; + } + + ret = str_array_create(); + handle = opendir(dir); + if (!handle) + { + printf("error: cannot open directory '%s'\n", dir); + return ret; + } + while ((ent = readdir(handle))) + { + char *name = ent->d_name; + if (*name == '.') continue; + + if (strlen(name) > strlen(ext) && + !strcmp(name + strlen(name) - strlen(ext), ext)) + { + char *d1 = string_cat(dir, "/"); + char *na = string_cat(d1, name); + str_array_add(ret, na); + free(d1); + free(na); + continue; + } + if (!strchr(name, '.') && + strcmp(name, "out") && + strcmp(name, "Makefile")) + { + str_array_t *sub; + char *d1 = string_cat(dir, "/"); + char *d2 = string_cat(d1, name); + size_t i; + + sub = collect_sources(d2, false, ext); + for (i = 0; i < str_array_len(sub); i++) + { + char *file = str_array_get(sub, i); + str_array_add(ret, file); + } + str_array_free(sub); + free(d2); + free(d1); + } + } + closedir(handle); + return ret; +} + +/* Builds the entirety of Parsee. */ +static void +write_objects(FILE *makefile, str_array_t *sources) +{ + size_t i; + if (!makefile || !sources) + { + return; + } + for (i = 0; i < str_array_len(sources); i++) + { + char *src = str_array_get(sources, i); + char *ofl = string_rep_ext(src, ".c", ".o"); + char *obj = string_cat("build", ofl + 3); + + fprintf(makefile, " %s", obj); + free(ofl); + free(obj); + } +} +static void +write_images(FILE *makefile, str_array_t *sources) +{ + size_t i; + if (!makefile || !sources) + { + return; + } + for (i = 0; i < str_array_len(sources); i++) + { + char *src = str_array_get(sources, i); + char *ofl = string_rep_ext(src, ".png", ".o"); + char *obj = string_cat("build", ofl + 3 + 1 + 5); + + fprintf(makefile, " %s", obj); + free(ofl); + free(obj); + } +} +static void +write_executable(FILE *makefile, str_array_t *sources) +{ + size_t i; + if (!makefile || !sources) + { + return; + } + for (i = 0; i < str_array_len(sources); i++) + { + char *src = str_array_get(sources, i); + char *ofl = string_rep_ext(src, ".c", ""); + char *obj = string_cat("tools/out", ofl + 5); + + fprintf(makefile, " %s", obj); + free(ofl); + free(obj); + } +} +static void +write_ayas(FILE *makefile, str_array_t *sources) +{ + size_t i; + if (!makefile || !sources) + { + return; + } + for (i = 0; i < str_array_len(sources); i++) + { + char *src = str_array_get(sources, i); + char *ofl = string_rep_ext(src, ".h", ".html"); + char *obj = string_cat("$(AYAYAS)", ofl + 3 + 1 + 7); + + fprintf(makefile, " %s", obj); + free(ofl); + free(obj); + } +} +static int +main_build(int argc, char *argv[]) +{ + FILE *makefile; + char *repo = cmd_stdout("git remote get-url origin"); + size_t size, i; + ssize_t nread; + str_array_t *sources, *images, *utils, *aya; + + if (strchr(repo, '\n')) + { + *(strchr(repo, '\n')) = '\0'; + } + + + makefile = fopen("Makefile", "w"); + fprintf(makefile, "# Autogenerated POSIX Makefile\n"); + fprintf(makefile, "# Ideally do not touch.\n\n"); + fprintf(makefile, ".POSIX: \n"); + fprintf(makefile, "include build.conf\n\n"); + fprintf(makefile, "AYAYAS=ayaya\n"); + fprintf(makefile, "CYTO_LIB=/usr/local/lib\n"); + fprintf(makefile, "CYTO_INC=/usr/local/include\n"); + fprintf(makefile, "ETC=etc\n\n"); + + fprintf(makefile, "all: utils binary ayadoc\n\n"); + + /* Create all objects */ + sources = collect_sources("src", true, ".c"); + images = collect_sources("etc/media", true, ".png"); + fprintf(makefile, "binary:"); + write_objects(makefile, sources); + write_images(makefile, images); + fprintf(makefile, "\n\t"); + { + fprintf(makefile, "$(CC) -L $(CYTO_LIB) -lCytoplasm $(LDFLAGS)"); + write_objects(makefile, sources); + write_images(makefile, images); + fprintf(makefile, " -o $(BINARY)\n"); + } + + /* Write rules for every source */ + for (i = 0; i < str_array_len(sources); i++) + { + char *src = str_array_get(sources, i); + char *ofl = string_rep_ext(src, ".c", ".o"); + char *obj = string_cat("build", ofl + 3); + + fprintf(makefile, "%s: %s\n", obj, src); + { + str_array_t *s = split(obj); + ssize_t j; + + fprintf(makefile, "\t@mkdir -p "); + for (j = 0; j < str_array_len(s) - 1; j++) + { + fprintf(makefile, "%s/", str_array_get(s, j)); + } + fprintf(makefile, "\n"); + str_array_free(s); + + fprintf(makefile, "\t$(CC) -c -Isrc -Isrc/include -I$(CYTO_INC) "); + fprintf(makefile, "-DVERSION=\"\\\"$(VERDION)\\\"\" "); + fprintf(makefile, "-DNAME=\"\\\"$(NAME)\\\"\" "); + fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" "); + fprintf(makefile, "-DREPOSITORY=\"\\\"%s\\\"\" ", repo); + fprintf(makefile, "$(CFLAGS) $< -o $@\n"); + } + free(ofl); + free(obj); + } + for (i = 0; i < str_array_len(images); i++) + { + char *src = str_array_get(images, i); + char *ofl = string_rep_ext(src, ".png", ".o"); + char *obj = string_cat("build", ofl + 3 + 1 + 5); + char *cfl = string_cat("build", src + 3 + 1 + 5); + + fprintf(makefile, "%s: %s\n", obj, src); + + { + str_array_t *s = split(obj); + char *sym; + ssize_t j; + + fprintf(makefile, "\t@mkdir -p "); + for (j = 0; j < str_array_len(s) - 1; j++) + { + fprintf(makefile, "%s/", str_array_get(s, j)); + } + fprintf(makefile, "\n"); + sym = j != -1 ? str_array_get(s, j): NULL; + sym = string_rep_ext(sym, ".o", ""); + str_array_free(s); + + fprintf(makefile, "\ttools/out/b64 $< 'media_%s' '%s.c'\n", sym, obj); + fprintf(makefile, "\t$(CC) -c %s.c -o $@\n", obj); + free(sym); + } + free(obj); + free(ofl); + free(cfl); + } + + /* Build utilities */ + utils = collect_sources("tools", true, ".c"); + fprintf(makefile, "utils:"); + write_executable(makefile, utils); + fprintf(makefile, "\n"); + for (i = 0; i < str_array_len(utils); i++) + { + char *src = str_array_get(utils, i); + char *ofl = string_rep_ext(src, ".c", ""); + char *obj = string_cat("tools/out", ofl + 5); + + fprintf(makefile, "%s: %s\n", obj, src); + { + fprintf(makefile, "\t@mkdir -p tools/out\n"); + fprintf(makefile, "\t$(CC) $(CFLAGS) -lCytoplasm $< -o $@\n"); + } + + free(ofl); + free(obj); + } + + /* Build Aya */ + aya = collect_sources("src/include", true, ".h"); + fprintf(makefile, "ayadoc:"); + write_ayas(makefile, aya); + fprintf(makefile, "\n"); + for (i = 0; i < str_array_len(aya); i++) + { + char *src = str_array_get(aya, i); + char *ofl = string_rep_ext(src, ".h", ".html"); + char *obj = string_cat("$(AYAYAS)", ofl + 3 + 1 + 7); + + fprintf(makefile, "%s: %s\n", obj, src); + { + str_array_t *s = split(obj); + ssize_t j; + + fprintf(makefile, "\t@mkdir -p "); + for (j = 0; j < str_array_len(s) - 1; j++) + { + fprintf(makefile, "%s/", str_array_get(s, j)); + } + fprintf(makefile, "\n"); + str_array_free(s); + + fprintf(makefile, + "\ttools/out/aya " + "-C etc/ayadoc/style.css " + "-p $(NAME) " + "-i $< -o $@\n" + ); + } + + free(ofl); + free(obj); + } + + fprintf(makefile, "install-parsee: binary\n"); + { + fprintf(makefile, "\tmkdir -m 755 -p $(PREFIX)/bin\n"); + fprintf(makefile, "\tcp $(BINARY) $(PREFIX)/bin\n"); + fprintf(makefile, "\tchmod 755 $(PREFIX)/bin/$(BINARY)\n"); + } + + fprintf(makefile, "install-tools: utils\n"); + fprintf(makefile, "\tmkdir -m 755 -p $(PREFIX)/bin\n"); + for (i = 0; i < str_array_len(utils); i++) + { + char *tool = str_array_get(utils, i); + char *ofl = string_rep_ext(tool, ".c", ""); + char *obj = string_cat("tools/out", ofl + 5); + char *bna = basename(obj); + + fprintf(makefile, "\tcp %s $(PREFIX)/bin/parsee-%s\n", obj, bna); + fprintf(makefile, "\tchmod 755 $(PREFIX)/bin/parsee-%s\n", bna); + + free(ofl); + free(obj); + } + fprintf(makefile, "install-aya: ayadoc\n"); + fprintf(makefile, "\tmkdir -m 755 -p $(PREFIX)/aya/$(BINARY)\n"); + fprintf(makefile, "\tcp -R $(AYAYAS)/* $(PREFIX)/aya/$(BINARY)\n"); + fprintf(makefile, "install-man:\n"); + fprintf(makefile, "\tmkdir -m 755 -p $(PREFIX)/share/man\n"); + fprintf(makefile, "\tcp -R etc/man/* $(PREFIX)/share/man\n"); + + fprintf(makefile, + "install: " + "install-parsee " + "install-tools " + "install-aya " + "install-man\n" + ); + + fprintf(makefile, "clean:\n\trm -rf ayaya build $(BINARY) tools/out\n"); + + str_array_free(sources); + str_array_free(images); + str_array_free(utils); + str_array_free(aya); + fflush(makefile); + fclose(makefile); + free(repo); + return EXIT_SUCCESS; +} + +int +main(int argc, char *argv[]) +{ + return main_build(argc, argv); +} From e0e398bfb5397b2c72f113c3cd5af345fc38f5d7 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 20:06:33 +0200 Subject: [PATCH 047/186] [META/CI] Thanks CI for catching this! --- tools/adminify.c | 1 + tools/aya.c | 1 + tools/config.c | 1 + tools/noavatars.c | 1 + 4 files changed, 4 insertions(+) diff --git a/tools/adminify.c b/tools/adminify.c index 26afb92..ee9e749 100644 --- a/tools/adminify.c +++ b/tools/adminify.c @@ -114,5 +114,6 @@ Main(Array *args, HashMap *env) } Log(LOG_ERR, "%s: couldn't open DB '%s'", exec, db_path); + (void) env; return EXIT_FAILURE; } diff --git a/tools/aya.c b/tools/aya.c index 04a80f5..6ce8771 100644 --- a/tools/aya.c +++ b/tools/aya.c @@ -492,5 +492,6 @@ Main(Array *args, HashMap *env) StreamClose(output); StreamClose(input); + (void) env; return EXIT_SUCCESS; } diff --git a/tools/config.c b/tools/config.c index c6ab515..3881eb1 100644 --- a/tools/config.c +++ b/tools/config.c @@ -131,5 +131,6 @@ Main(Array *args, HashMap *env) end: UriFree(api_base); Free(media); + (void) env; return code; } diff --git a/tools/noavatars.c b/tools/noavatars.c index 0c5526c..93fba1c 100644 --- a/tools/noavatars.c +++ b/tools/noavatars.c @@ -30,5 +30,6 @@ Main(Array *args, HashMap *env) } Log(LOG_ERR, "%s: couldn't open DB '%s'", exec, db_path); + (void) env; return EXIT_FAILURE; } From 90ddce47571842c0ca7082b46661590d4f26f20e Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 20:09:35 +0200 Subject: [PATCH 048/186] [CI/FIX] Aya... --- tools/aya.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/aya.c b/tools/aya.c index 6ce8771..69371d1 100644 --- a/tools/aya.c +++ b/tools/aya.c @@ -157,6 +157,9 @@ HandleReturnValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *fi *tag_del = '\0'; } + (void) aya; + (void) d; + /* Already write the field */ StreamPrintf(out, " %s", field); @@ -200,6 +203,8 @@ HandleSeeValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *field "%s", field, field ); + (void) aya; + (void) d; } #define SplitBy(sym, cb, del_str) \ char *start_of_arg = val, *separator = NULL; \ From a110b44ad66ef99165c45d58956544878d8defe2 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 20:11:54 +0200 Subject: [PATCH 049/186] [CI/FIX] --- tools/b64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/b64.c b/tools/b64.c index 53c08e8..ba125f2 100644 --- a/tools/b64.c +++ b/tools/b64.c @@ -50,5 +50,6 @@ Main(Array *args, HashMap *env) StreamFlush(outStream); StreamClose(outStream); + (void) env; return EXIT_SUCCESS; } From 92d33fa641f063bfb18b51138417f35f467a3b80 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 22:17:35 +0200 Subject: [PATCH 050/186] [MOD/CI/BUILD] Static builds, via the native tools --- .forgejo/workflows/build-release.yaml | 21 +++--------- README.MD | 9 +++--- configure.c | 46 ++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index e2e1312..bd65c3e 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -59,26 +59,13 @@ jobs: git clone https://git.kappach.at/${{ github.repository}} parsee cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" - export TAB=$(printf '\t') - echo "all: adminify aya b64 config noavatars" > tools/Makefile - echo "%: %.c" >> tools/Makefile - echo "${TAB}musl-gcc -I ../usr/include -static -o ../\$@.\$(shell uname -m) $< -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm" >> tools/Makefile - cat tools/Makefile - cd tools - make - cd .. - make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib 2> /dev/null || true - musl-gcc -static -o "parsee.$(uname -m)" $(find build/ -name '*.o') -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto -llmdb -flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections -lCytoplasm - ls $PREFIX + ./configure -s -i + make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib + make PREFIX=bins + ls bins - name: Create a final archive run: | cd parsee - mkdir bins - ls "${PREFIX}" - ls . - cp $(find . -maxdepth 1 -name "*.$(uname -m)") bins - tar -czvf "$(uname)-$(uname -m).tar.gz" bins - cp "$(uname)-$(uname -m).tar.gz" .. echo "NAM=parsee-$(uname)-$(uname -m)" >> $GITHUB_ENV echo "DIR=$PWD/bins" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) diff --git a/README.MD b/README.MD index 1d3f334..a2bff9d 100644 --- a/README.MD +++ b/README.MD @@ -26,11 +26,10 @@ a bridge may be a good way to start. ## BUILDING ```sh -$ make # This generates a 'parsee' executable. -$ cd tools # If you want to build more tools -$ make && cd .. -$ make ayadoc # If you want to build HTML documentation -$ make [PREFIX=(install path)] install # To install Parsee. +$ cc configure.c -o configure +$ ./configure # use -s if you want static Parsee+OpenSSL, use -s -l if LMDB is needed +$ make +$ make [PREFIX=...] install # run as root if on a protected dir like /usr ``` If there are any Cytoplasm-related build failures, you may want to check the Makefile to change a few variables (you can set `CYTO_INC` and `CYTO_LIB` for Cytoplasm's include and diff --git a/configure.c b/configure.c index 4d67d07..c122c63 100644 --- a/configure.c +++ b/configure.c @@ -412,6 +412,8 @@ main_build(int argc, char *argv[]) char *repo = cmd_stdout("git remote get-url origin"); size_t size, i; ssize_t nread; + bool with_static = false, with_lmdb = false; + int opt; str_array_t *sources, *images, *utils, *aya; if (strchr(repo, '\n')) @@ -419,6 +421,19 @@ main_build(int argc, char *argv[]) *(strchr(repo, '\n')) = '\0'; } + while ((opt = getopt(argc, argv, "sl")) != -1) + { + switch (opt) + { + case 's': + with_static = true; + break; + case 'l': + with_lmdb = with_static; + with_static = true; + break; + } + } makefile = fopen("Makefile", "w"); fprintf(makefile, "# Autogenerated POSIX Makefile\n"); @@ -440,10 +455,20 @@ main_build(int argc, char *argv[]) write_images(makefile, images); fprintf(makefile, "\n\t"); { - fprintf(makefile, "$(CC) -L $(CYTO_LIB) -lCytoplasm $(LDFLAGS)"); + fprintf(makefile, "$(CC) -o $(BINARY)"); + if (with_static) + { + fprintf(makefile, " -static"); + } + fprintf(makefile, " -L $(CYTO_LIB)"); write_objects(makefile, sources); write_images(makefile, images); - fprintf(makefile, " -o $(BINARY)\n"); + if (with_static) + { + fprintf(makefile, " -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto"); + if (with_lmdb) fprintf(makefile, " -llmdb"); + } + fprintf(makefile, " -lCytoplasm $(LDFLAGS)\n"); } /* Write rules for every source */ @@ -467,7 +492,7 @@ main_build(int argc, char *argv[]) str_array_free(s); fprintf(makefile, "\t$(CC) -c -Isrc -Isrc/include -I$(CYTO_INC) "); - fprintf(makefile, "-DVERSION=\"\\\"$(VERDION)\\\"\" "); + fprintf(makefile, "-DVERSION=\"\\\"$(VERSION)\\\"\" "); fprintf(makefile, "-DNAME=\"\\\"$(NAME)\\\"\" "); fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" "); fprintf(makefile, "-DREPOSITORY=\"\\\"%s\\\"\" ", repo); @@ -523,7 +548,20 @@ main_build(int argc, char *argv[]) fprintf(makefile, "%s: %s\n", obj, src); { fprintf(makefile, "\t@mkdir -p tools/out\n"); - fprintf(makefile, "\t$(CC) $(CFLAGS) -lCytoplasm $< -o $@\n"); + fprintf(makefile, "\t$(CC) -o $@"); + if (with_static) + { + fprintf(makefile, " -static"); + } + fprintf(makefile, " $<"); + fprintf(makefile, " -L $(CYTO_LIB)"); + if (with_static) + { + fprintf(makefile, " -lm -lpthread -lssl"); + fprintf(makefile, " -lCytoplasm -lssl -lcrypto"); + if (with_lmdb) fprintf(makefile, " -llmdb"); + } + fprintf(makefile, " -lCytoplasm $(CFLAGS)\n"); } free(ofl); From eb25ce3e2b4524e7a09db18f27daaa53879e244e Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 22:29:07 +0200 Subject: [PATCH 051/186] [CI] Silly me, I need to build configure --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index bd65c3e..5868b1f 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -59,7 +59,7 @@ jobs: git clone https://git.kappach.at/${{ github.repository}} parsee cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" - ./configure -s -i + cc configure.c -o configure && ./configure -s -i make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib make PREFIX=bins ls bins From b10f14d06796c84d89b1bd775a010d955664e1f4 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 22:35:41 +0200 Subject: [PATCH 052/186] [CI] What. --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 5868b1f..cfeadb0 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -59,7 +59,7 @@ jobs: git clone https://git.kappach.at/${{ github.repository}} parsee cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" - cc configure.c -o configure && ./configure -s -i + musl-gcc -static configure.c -o configure && ./configure -s -i make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib make PREFIX=bins ls bins From 75bbe696334a7883fff1c7a0eb3913ccac20cb4f Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 22:58:13 +0200 Subject: [PATCH 053/186] [CI/FIX] Use limits.h --- configure.c | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.c b/configure.c index c122c63..b5d6200 100644 --- a/configure.c +++ b/configure.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include From 0ba708e28fdd16244b9e7f09042f283c9a9377b8 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 23:05:14 +0200 Subject: [PATCH 054/186] [CI] Is he stupid??? --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index cfeadb0..15881bf 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -59,7 +59,7 @@ jobs: git clone https://git.kappach.at/${{ github.repository}} parsee cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" - musl-gcc -static configure.c -o configure && ./configure -s -i + musl-gcc -static configure.c -o configure && ./configure -s -l make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib make PREFIX=bins ls bins From fc75dc52aa65cd5eeb8a334dd9d9d5e33de80a6a Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 23:14:05 +0200 Subject: [PATCH 055/186] [CI] This ought to be it --- .forgejo/workflows/build-release.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 15881bf..6a996f9 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -61,8 +61,7 @@ jobs: alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" musl-gcc -static configure.c -o configure && ./configure -s -l make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib - make PREFIX=bins - ls bins + make PREFIX=bins install - name: Create a final archive run: | cd parsee From 19cf159f21f05f01f25a58337cb91c462d03e763 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 12 Sep 2024 23:41:01 +0200 Subject: [PATCH 056/186] [CI] Crank compression to 9 --- .forgejo/workflows/build-release.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 6a996f9..a6eaaa6 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -60,7 +60,7 @@ jobs: cd parsee alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" musl-gcc -static configure.c -o configure && ./configure -s -l - make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib + make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib LDFLAGS=-s make PREFIX=bins install - name: Create a final archive run: | @@ -71,4 +71,5 @@ jobs: uses: https://github.com/christopherhx/gitea-upload-artifact@v4 with: name: ${{ env.NAM }} + compression-level: 9 path: ${{ env.DIR }} From 92db543d782eceef60a1aacccb5ae91e39720c15 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 13 Sep 2024 00:02:35 +0200 Subject: [PATCH 057/186] [CI] Bloody hell... --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index a6eaaa6..088af5f 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -68,7 +68,7 @@ jobs: echo "NAM=parsee-$(uname)-$(uname -m)" >> $GITHUB_ENV echo "DIR=$PWD/bins" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) - uses: https://github.com/christopherhx/gitea-upload-artifact@v4 + uses: https://github.com/christopherhx/gitea-upload-artifact@fix-artifact-v4-upload-above-8MB with: name: ${{ env.NAM }} compression-level: 9 From 63772d50ab0451468b4240413c92a217f121f19d Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 13 Sep 2024 06:10:25 +0200 Subject: [PATCH 058/186] [CI] I hate Forgejo. --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 088af5f..e63b30d 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -68,7 +68,7 @@ jobs: echo "NAM=parsee-$(uname)-$(uname -m)" >> $GITHUB_ENV echo "DIR=$PWD/bins" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) - uses: https://github.com/christopherhx/gitea-upload-artifact@fix-artifact-v4-upload-above-8MB + uses: https://code.forgejo.org/forgejo/upload-artifact@v4 with: name: ${{ env.NAM }} compression-level: 9 From 4164eb5ed2c6f7103820e1316917b20e5ac54052 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 13 Sep 2024 12:00:46 +0200 Subject: [PATCH 059/186] [CI] Try compressing the compress --- .forgejo/workflows/build-release.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index e63b30d..b550e8f 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -65,8 +65,9 @@ jobs: - name: Create a final archive run: | cd parsee - echo "NAM=parsee-$(uname)-$(uname -m)" >> $GITHUB_ENV - echo "DIR=$PWD/bins" >> $GITHUB_ENV + echo "NAM=parsee-$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV + tar -czvf $PWD/bins.tar.hz $PWD/bins + echo "DIR=$PWD/bins.tar.gz" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) uses: https://code.forgejo.org/forgejo/upload-artifact@v4 with: From 9f1c2046fdd04ff9702943e50da56e11fc28d012 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 13 Sep 2024 14:29:51 +0200 Subject: [PATCH 060/186] [FIX] Fix out media from Matrix --- CHANGELOG.md | 9 +++++++++ src/Events.c | 1 + 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5762504..be12615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,3 +16,12 @@ of Parsee. May occasionally deadlock. *NONE* #### Deprecated features *NONE* + +### v0.1.1[star-of-hope] +Fixes some media metadata things. +#### New things +*NONE* +#### Bugfixes +- Adds more information to media events so that clients can behave. +#### Deprecated features +*NONE* diff --git a/src/Events.c b/src/Events.c index e625d07..85b1e37 100644 --- a/src/Events.c +++ b/src/Events.c @@ -119,6 +119,7 @@ MatrixCreateMedia(char *mxc, char *body, char *mime) } map = HashMapCreate(); + JsonSet(map, JsonValueString(mime), 2, "info", "mimetype"); HashMapSet(map, "msgtype", JsonValueString(matrix_type)); HashMapSet(map, "mimetype", JsonValueString(mime)); HashMapSet(map, "body", JsonValueString(body)); From 4a2160503bd1c8bcaa83c1e2856622395d3b1c67 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 12:07:30 +0200 Subject: [PATCH 061/186] [CI] Try to Mbed things out --- .forgejo/workflows/build-release.yaml | 25 +++++++++++-------------- configure.c | 6 +++--- src/Parsee/Data.c | 5 +++++ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index b550e8f..f83fcdd 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -10,14 +10,14 @@ jobs: run: | echo $(uname -a) $(env | grep container) apt update -y - apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget + apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget python3 - name: Clone everything run: | mkdir -p repos git clone --depth=1 https://git.musl-libc.org/git/musl repos/musl - git clone --depth=1 https://github.com/openssl/openssl repos/openssl + git clone --depth=1 https://github.com/Mbed-TLS/mbedtls repos/mbed git clone --depth=1 https://github.com/LMDB/lmdb repos/lmdb - git clone --depth=1 https://git.kappach.at/KappaChat/Cytoplasm repos/cyto + git clone --depth=1 https://git.kappach.at/lda/Cytoplasm repos/cyto echo "PREFIX=$GITHUB_WORKSPACE/usr" >> $GITHUB_ENV echo "PATH=$GITHUB_WORKSPACE/usr/bin:$PATH" >> $GITHUB_ENV echo "INCLUDE_PATH=$GITHUB_WORKSPACE/usr/include" >> $GITHUB_ENV @@ -29,15 +29,13 @@ jobs: make -j$(nproc) make install -j$(nproc) alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" - - name: Build OpenSSL + - name: Build MbedTLS run: | alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" - cd repos/openssl - CC=musl-gcc ./Configure -static --static --prefix=${PREFIX} no-async no-engine -DOPENSSL_NO_SECURE_MEMORY - make -j$(nproc) - make install -j$(nproc) - cp libcrypto.a ${PREFIX}/lib - cp libssl.a ${PREFIX}/lib + cd repos/mbed + python3 -m pip install -r scripts/basic.requirements.txt --break-system-packages + make CC=musl-gcc -j$(nproc) + make install DESTDIR=${PREFIX} -j$(nproc) - name: Build LMDB run: | alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" @@ -48,10 +46,9 @@ jobs: run: | alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" cd repos/cyto - rm configure - wget https://kappach.at/configure - chmod +x configure - ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb + git fetch + git checkout add-mbed + ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb --with-mbed make -j$(nproc) make install - name: Clone/Build Parsee diff --git a/configure.c b/configure.c index b5d6200..b01b351 100644 --- a/configure.c +++ b/configure.c @@ -466,7 +466,7 @@ main_build(int argc, char *argv[]) write_images(makefile, images); if (with_static) { - fprintf(makefile, " -lm -lpthread -lssl -lCytoplasm -lssl -lcrypto"); + fprintf(makefile, " -lm -lpthread -lmbedtls -lmbedx509 -lmbedcrypto -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto"); if (with_lmdb) fprintf(makefile, " -llmdb"); } fprintf(makefile, " -lCytoplasm $(LDFLAGS)\n"); @@ -558,8 +558,8 @@ main_build(int argc, char *argv[]) fprintf(makefile, " -L $(CYTO_LIB)"); if (with_static) { - fprintf(makefile, " -lm -lpthread -lssl"); - fprintf(makefile, " -lCytoplasm -lssl -lcrypto"); + fprintf(makefile, " -lm -lpthread -lmbedtls -lmbedx509 -lmbedcrypto"); + fprintf(makefile, " -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto"); if (with_lmdb) fprintf(makefile, " -llmdb"); } fprintf(makefile, " -lCytoplasm $(CFLAGS)\n"); diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index d4bf6cb..2dae26e 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -159,13 +159,16 @@ ParseeCleanup(void *datp) ArrayAdd(to_delete, StrDuplicate(f)); \ cleaned++; \ } \ + Log(LOG_INFO, "Free A, %s [%s][%p]", f, #field, ref); \ DbUnlock(data->db, ref); \ + Log(LOG_INFO, "Free'd!"); \ } \ DbListFree(field##_list); \ \ for (j = 0; j < ArraySize(to_delete); j++) \ { \ field = ArrayGet(to_delete, j); \ + Log(LOG_INFO, "%s (%ss)", field, #field"s"); \ if (cleaned > threshold) \ { \ DbDelete(data->db, 4, "chats", chat, #field"s", field); \ @@ -236,7 +239,9 @@ ParseeCleanup(void *datp) CleanupField(event, 3 HOURS, 500); CleanupField(id, 3 HOURS, 500); + Log(LOG_INFO, "Free B %p", ref); DbUnlock(data->db, ref); + Log(LOG_INFO, "Free'd!"); } DbListFree(chats); Log(LOG_DEBUG, "Cleant up %d entries...", entries); From 901a88c63845ed6e4f2004a29380ddbf029c26f5 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 12:12:25 +0200 Subject: [PATCH 062/186] [CI] Ow. --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index f83fcdd..7108b43 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -17,7 +17,7 @@ jobs: git clone --depth=1 https://git.musl-libc.org/git/musl repos/musl git clone --depth=1 https://github.com/Mbed-TLS/mbedtls repos/mbed git clone --depth=1 https://github.com/LMDB/lmdb repos/lmdb - git clone --depth=1 https://git.kappach.at/lda/Cytoplasm repos/cyto + git clone --depth=1 https://git.telodendria.io/lda/Cytoplasm repos/cyto echo "PREFIX=$GITHUB_WORKSPACE/usr" >> $GITHUB_ENV echo "PATH=$GITHUB_WORKSPACE/usr/bin:$PATH" >> $GITHUB_ENV echo "INCLUDE_PATH=$GITHUB_WORKSPACE/usr/include" >> $GITHUB_ENV From 7c4333f13739e790f6f4f6ee4732bfd553c9ac73 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 12:24:20 +0200 Subject: [PATCH 063/186] [CI] Python hjinks --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 7108b43..f827a78 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -10,7 +10,7 @@ jobs: run: | echo $(uname -a) $(env | grep container) apt update -y - apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget python3 + apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget python3 python3-pip - name: Clone everything run: | mkdir -p repos From 1f7a220a8f1e253c3b3487a853a7c30e47394d95 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 12:26:36 +0200 Subject: [PATCH 064/186] [CI] Build with submodules --- .forgejo/workflows/build-release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index f827a78..3d77022 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -33,6 +33,7 @@ jobs: run: | alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" cd repos/mbed + git submodule update --init python3 -m pip install -r scripts/basic.requirements.txt --break-system-packages make CC=musl-gcc -j$(nproc) make install DESTDIR=${PREFIX} -j$(nproc) From 2e4314be481dd82d904b2371aa8f58519c92f45d Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 12:33:29 +0200 Subject: [PATCH 065/186] [CI] Grab the right branch --- .forgejo/workflows/build-release.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 3d77022..6c93c33 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -17,7 +17,7 @@ jobs: git clone --depth=1 https://git.musl-libc.org/git/musl repos/musl git clone --depth=1 https://github.com/Mbed-TLS/mbedtls repos/mbed git clone --depth=1 https://github.com/LMDB/lmdb repos/lmdb - git clone --depth=1 https://git.telodendria.io/lda/Cytoplasm repos/cyto + git clone -b add-mbed --single-branch https://git.telodendria.io/lda/Cytoplasm repos/cyto echo "PREFIX=$GITHUB_WORKSPACE/usr" >> $GITHUB_ENV echo "PATH=$GITHUB_WORKSPACE/usr/bin:$PATH" >> $GITHUB_ENV echo "INCLUDE_PATH=$GITHUB_WORKSPACE/usr/include" >> $GITHUB_ENV @@ -48,7 +48,6 @@ jobs: alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" cd repos/cyto git fetch - git checkout add-mbed ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb --with-mbed make -j$(nproc) make install From 613822e40c4853261cf13c98d89045dae894700c Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 13:17:54 +0200 Subject: [PATCH 066/186] [CI] Base on a Mbed release --- .forgejo/workflows/build-release.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 6c93c33..c48afc4 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -10,12 +10,14 @@ jobs: run: | echo $(uname -a) $(env | grep container) apt update -y - apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget python3 python3-pip + apt install -y build-essential liblmdb-dev nodejs libssl-dev git wget python3 python3-pip bzip2 - name: Clone everything run: | mkdir -p repos git clone --depth=1 https://git.musl-libc.org/git/musl repos/musl - git clone --depth=1 https://github.com/Mbed-TLS/mbedtls repos/mbed + wget https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-3.6.1/mbedtls-3.6.1.tar.bz2 + tar -xvf mbedtls-3.6.1.tar.bz2 + mv mbedtls-3.6.1/ repos/mbed git clone --depth=1 https://github.com/LMDB/lmdb repos/lmdb git clone -b add-mbed --single-branch https://git.telodendria.io/lda/Cytoplasm repos/cyto echo "PREFIX=$GITHUB_WORKSPACE/usr" >> $GITHUB_ENV @@ -33,7 +35,6 @@ jobs: run: | alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" cd repos/mbed - git submodule update --init python3 -m pip install -r scripts/basic.requirements.txt --break-system-packages make CC=musl-gcc -j$(nproc) make install DESTDIR=${PREFIX} -j$(nproc) From bdb1f46c7769e1b4889f6e5d7b6b90635ebf9571 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 13:40:08 +0200 Subject: [PATCH 067/186] [CI] Use custom configure --- .forgejo/workflows/build-release.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index c48afc4..f8dfa02 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -49,6 +49,9 @@ jobs: alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${PREFIX}/lib" cd repos/cyto git fetch + rm configure + wget https://git.kappach.at/configure + chmod +x configure ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb --with-mbed make -j$(nproc) make install From dd6dede2e843da06dfab442e9e712208f12f26f0 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 13:43:56 +0200 Subject: [PATCH 068/186] [CI] Use the right URL --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index f8dfa02..d9e6e2a 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -50,7 +50,7 @@ jobs: cd repos/cyto git fetch rm configure - wget https://git.kappach.at/configure + wget https://kappach.at/configure chmod +x configure ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb --with-mbed make -j$(nproc) From d99b827d5ccca3a7bb089ec5338050ca38e45048 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 13:47:51 +0200 Subject: [PATCH 069/186] [CI] Fix typo in generation --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index d9e6e2a..4d7e903 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -67,7 +67,7 @@ jobs: run: | cd parsee echo "NAM=parsee-$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV - tar -czvf $PWD/bins.tar.hz $PWD/bins + tar -czvf $PWD/bins.tar.gz $PWD/bins echo "DIR=$PWD/bins.tar.gz" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) uses: https://code.forgejo.org/forgejo/upload-artifact@v4 From cb70d599bfd15d88a439a556238213d4ff71c7cc Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 14:15:10 +0200 Subject: [PATCH 070/186] [CI[ Try to get ARM64. --- .forgejo/workflows/build-release.yaml | 4 ++-- .forgejo/workflows/check-gcc.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 4d7e903..cde57b9 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -2,7 +2,7 @@ name: Builds static Parsee for a release. on: [release, workflow_dispatch] jobs: compile: - runs-on: amd64-debian + runs-on: [amd64-debian,arm64-debian,debian] container: image: debian:12 steps: @@ -67,7 +67,7 @@ jobs: run: | cd parsee echo "NAM=parsee-$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV - tar -czvf $PWD/bins.tar.gz $PWD/bins + tar -czvf bins.tar.gz bins echo "DIR=$PWD/bins.tar.gz" >> $GITHUB_ENV - name: Upload it all(as a ZIP of a .TGZ) uses: https://code.forgejo.org/forgejo/upload-artifact@v4 diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 8f6f4a2..bbbc7d5 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -2,7 +2,7 @@ name: Checks Parsee's correctness on GCC+Debian on: [push] jobs: compile: - runs-on: amd64-debian + runs-on: [amd64-debian,arm64-debian,debian] container: image: debian:12 steps: From 1ce2eea9d806e53d7f8f84ead21555dae2cfefcb Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 15:24:54 +0200 Subject: [PATCH 071/186] [CI] Use single runs-on --- .forgejo/workflows/build-release.yaml | 2 +- .forgejo/workflows/check-gcc.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index cde57b9..b41b04e 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -2,7 +2,7 @@ name: Builds static Parsee for a release. on: [release, workflow_dispatch] jobs: compile: - runs-on: [amd64-debian,arm64-debian,debian] + runs-on: debian container: image: debian:12 steps: diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index bbbc7d5..82e4ef6 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -2,7 +2,7 @@ name: Checks Parsee's correctness on GCC+Debian on: [push] jobs: compile: - runs-on: [amd64-debian,arm64-debian,debian] + runs-on: debian container: image: debian:12 steps: From f8b834c652df9c76ce7c42ebe23a2f0872cc33bc Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 15:40:50 +0200 Subject: [PATCH 072/186] [CI] Help --- .forgejo/workflows/check-gcc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 82e4ef6..27a7285 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -4,7 +4,7 @@ jobs: compile: runs-on: debian container: - image: debian:12 + image: docker://debian:12 steps: - name: Install LMDB+OpenSSL tools run: | From 0cccef7194448d10799dcc5a0be6e1cbc47fedd0 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 15 Sep 2024 16:22:03 +0200 Subject: [PATCH 073/186] [CI] I hate Docker, again --- .forgejo/workflows/build-release.yaml | 2 +- .forgejo/workflows/check-gcc.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index b41b04e..af52cae 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -4,7 +4,7 @@ jobs: compile: runs-on: debian container: - image: debian:12 + image: debian steps: - name: Install LMDB+OpenSSL tools run: | diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index 27a7285..fda4a05 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -4,7 +4,7 @@ jobs: compile: runs-on: debian container: - image: docker://debian:12 + image: debian steps: - name: Install LMDB+OpenSSL tools run: | From 05be7fe249b6636e7ff1e9dace0bf34532b29637 Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 16 Sep 2024 09:32:44 +0200 Subject: [PATCH 074/186] [MOD] Do some tricks to make formatting nicer It just didn't make sense on basic messages and Element Android. Fluffy behaved as excepted, though. --- src/Parsee/Data.c | 5 ----- src/XEP-0393.c | 22 +++++++++++++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 2dae26e..d4bf6cb 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -159,16 +159,13 @@ ParseeCleanup(void *datp) ArrayAdd(to_delete, StrDuplicate(f)); \ cleaned++; \ } \ - Log(LOG_INFO, "Free A, %s [%s][%p]", f, #field, ref); \ DbUnlock(data->db, ref); \ - Log(LOG_INFO, "Free'd!"); \ } \ DbListFree(field##_list); \ \ for (j = 0; j < ArraySize(to_delete); j++) \ { \ field = ArrayGet(to_delete, j); \ - Log(LOG_INFO, "%s (%ss)", field, #field"s"); \ if (cleaned > threshold) \ { \ DbDelete(data->db, 4, "chats", chat, #field"s", field); \ @@ -239,9 +236,7 @@ ParseeCleanup(void *datp) CleanupField(event, 3 HOURS, 500); CleanupField(id, 3 HOURS, 500); - Log(LOG_INFO, "Free B %p", ref); DbUnlock(data->db, ref); - Log(LOG_INFO, "Free'd!"); } DbListFree(chats); Log(LOG_DEBUG, "Cleant up %d entries...", entries); diff --git a/src/XEP-0393.c b/src/XEP-0393.c index a90b4a1..2976563 100644 --- a/src/XEP-0393.c +++ b/src/XEP-0393.c @@ -399,21 +399,37 @@ ShoveXML(XEP393Element *element, XMLElement *xmlparent) char * XEP393ToXMLString(XEP393Element *xepd) { - XMLElement *root; + XMLElement *root, *act_root; + XMLElement *child; Stream *writer; char *ret = NULL; + size_t i, children; if (!xepd) { return NULL; } root = XMLCreateTag("span"); + act_root = root; ShoveXML(xepd, root); writer = StrStreamWriter(&ret); - XMLEncode(writer, root); - XMLFreeElement(root); + children = ArraySize(root->children); + + child = ArrayGet(root->children, 0); + if (children == 1 && StrEquals(child->name, "p")) + { + children = ArraySize(child->children); + root = child; + } + for (i = 0; i < children; i++) + { + child = ArrayGet(root->children, i); + + XMLEncode(writer, child); + } + XMLFreeElement(act_root); StreamFlush(writer); StreamClose(writer); From 9ff70bc0ed683b8840141b265bad2f7cbff53985 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 17 Sep 2024 10:21:27 +0200 Subject: [PATCH 075/186] [CI] Push my luck with strategies --- .forgejo/workflows/build-release.yaml | 8 ++++++-- README.MD | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index af52cae..a30318d 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -2,9 +2,13 @@ name: Builds static Parsee for a release. on: [release, workflow_dispatch] jobs: compile: - runs-on: debian + strategy: + matrix: + distro: [ debian ] + arch: [ 'amd64', 'arm64' ] + runs-on: ${{ matrix.distro }}-${{ matrix.arch }} container: - image: debian + image: ${{ matrix.distro }} steps: - name: Install LMDB+OpenSSL tools run: | diff --git a/README.MD b/README.MD index a2bff9d..251f68d 100644 --- a/README.MD +++ b/README.MD @@ -1,7 +1,7 @@ # Parsee - the jealous XMPP<=>Matrix bridge Parsee is a Matrix<=>XMPP bridge written in C99, with Cytoplasm, similar to Bifrost, but it is NOT a drop-in replacment. -**NOTE**: Use [this Cytoplasm branch for LMDB](https://git.telodendria.io/lda/Cytoplasm/src/branch/fix-deadlock) +Currently, it is *alpha* stage, which means that I wouldn't recommend using this in production, as I can change anything, at any time. ## Why? ### Naming @@ -27,13 +27,14 @@ a bridge may be a good way to start. ## BUILDING ```sh $ cc configure.c -o configure -$ ./configure # use -s if you want static Parsee+OpenSSL, use -s -l if LMDB is needed +$ ./configure # use -s if you want static Parsee+MbedTLS, use -s -l if LMDB is needed $ make $ make [PREFIX=...] install # run as root if on a protected dir like /usr ``` If there are any Cytoplasm-related build failures, you may want to check the Makefile to change a few variables (you can set `CYTO_INC` and `CYTO_LIB` for Cytoplasm's include and library paths specifically.) +If you build with MbedTLS, please mind setting the `CYTO_TLS_CA` env to Parsee. ### DEPENDENCIES Parsee tries to avoid dependencies aside from [Cytoplasm](https://git.telodendria.io/Telodendria/Cytoplasm). From 9d67cb61650b6899cdfe74ef462dbe541523670a Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 17 Sep 2024 10:24:26 +0200 Subject: [PATCH 076/186] [CI] Silly me. --- .forgejo/workflows/build-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index a30318d..8ea7e73 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -6,7 +6,7 @@ jobs: matrix: distro: [ debian ] arch: [ 'amd64', 'arm64' ] - runs-on: ${{ matrix.distro }}-${{ matrix.arch }} + runs-on: [${{ matrix.distro }}, ${{ matrix.arch }}] container: image: ${{ matrix.distro }} steps: From 5ffd413e67c1df802ac4dc49780d3e976ce243ea Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 17 Sep 2024 10:33:46 +0200 Subject: [PATCH 077/186] [CI/FIX] Fix YAML issue --- .forgejo/workflows/build-release.yaml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 8ea7e73..8c2762e 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -4,9 +4,14 @@ jobs: compile: strategy: matrix: - distro: [ debian ] - arch: [ 'amd64', 'arm64' ] - runs-on: [${{ matrix.distro }}, ${{ matrix.arch }}] + distro: + - debian + arch: + - amd64 + - arm64 + runs-on: + - ${{ matrix.distro }} + - ${{ matrix.arch }} container: image: ${{ matrix.distro }} steps: From f96e0a95bd28740726fa66d9689a040dbf9deb0c Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 17 Sep 2024 21:45:26 +0200 Subject: [PATCH 078/186] [CI] Just generate ZIPs --- .forgejo/workflows/build-release.yaml | 13 ++++++------- .forgejo/workflows/check-gcc.yaml | 12 ++++++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml index 8c2762e..c649ab1 100644 --- a/.forgejo/workflows/build-release.yaml +++ b/.forgejo/workflows/build-release.yaml @@ -1,5 +1,5 @@ -name: Builds static Parsee for a release. -on: [release, workflow_dispatch] +name: Builds static Parsee +on: [push] jobs: compile: strategy: @@ -75,12 +75,11 @@ jobs: - name: Create a final archive run: | cd parsee - echo "NAM=parsee-$(uname)-$(uname -m).tar.gz" >> $GITHUB_ENV - tar -czvf bins.tar.gz bins - echo "DIR=$PWD/bins.tar.gz" >> $GITHUB_ENV - - name: Upload it all(as a ZIP of a .TGZ) + echo "NAM=parsee-$(uname)-$(uname -m)" >> $GITHUB_ENV + echo "DIR=$PWD/bins" >> $GITHUB_ENV + - name: Upload it all(as a ZIP) uses: https://code.forgejo.org/forgejo/upload-artifact@v4 with: name: ${{ env.NAM }} - compression-level: 9 path: ${{ env.DIR }} + compression-level: 9 diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index fda4a05..bcf2c00 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -2,9 +2,17 @@ name: Checks Parsee's correctness on GCC+Debian on: [push] jobs: compile: - runs-on: debian + strategy: + matrix: + distro: + - debian + arch: + - amd64 + runs-on: + - ${{ matrix.distro }} + - ${{ matrix.arch }} container: - image: debian + image: ${{ matrix.distro }} steps: - name: Install LMDB+OpenSSL tools run: | From 420c05690fcf9ae2aa43376422b094d55a479077 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 18 Sep 2024 05:55:47 +0200 Subject: [PATCH 079/186] [FIX] Catch SIGPIPEs --- src/Signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Signal.c b/src/Signal.c index 85e771c..f0f4ee7 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -38,7 +38,7 @@ ParseeInitialiseSignals(HttpServer *s, pthread_t xmpp, XMPPComponent *j) sa.sa_flags = SA_RESTART; #define Register(act) (sigaction(act, &sa, NULL) >= 0) - if (!Register(SIGTERM) || !Register(SIGINT)) + if (!Register(SIGTERM) || !Register(SIGINT) || !Register(SIGPIPE)) { Log(LOG_ERR, "Couldn't register signals..."); return false; From f666f39b7c4785040166a6703c360b59af8afa5e Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 18 Sep 2024 07:58:21 +0200 Subject: [PATCH 080/186] [MOD] Add CHANGELOG, start PEPing --- CHANGELOG.md | 10 +++++-- README.MD | 5 ++-- src/StanzaBuilder.c | 10 ------- src/XMPPThread/PEP.c | 47 ++++++++++++++++++++++++++++--- src/XMPPThread/ReListener.c | 2 +- src/XMPPThread/Stanzas/Presence.c | 7 ++++- src/XMPPThread/internal.h | 3 +- 7 files changed, 62 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be12615..bf82211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,10 +18,16 @@ of Parsee. May occasionally deadlock. *NONE* ### v0.1.1[star-of-hope] -Fixes some media metadata things. +Fixes some media metadata things, and replaces the build +system of Parsee. #### New things *NONE* #### Bugfixes - Adds more information to media events so that clients can behave. +- Fixes issues where SIGPIPE can actually just kill Parsee. +- Allows MbedTLS through a specific Cytoplasm patch. +- "Lone" XMPP messages no longer render weirdly on Element Android's +weird rendering. #### Deprecated features -*NONE* +- The old `build.c` and `Makefile`s used for building are removed, +and replaced by the `configure.c` C file(/script via TCC). diff --git a/README.MD b/README.MD index 251f68d..5205590 100644 --- a/README.MD +++ b/README.MD @@ -68,6 +68,8 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th (see `etc/man`) ## TODOS before 1.0 rolls around +- PROPER FUCKING AVATARS + XMPP->Matrix is decent, Matrix->XMPP is effectiveny not done - Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency. - It depends on more stuff anyways, and I don't want to weigh down the dependency list of Parsee for that. @@ -79,8 +81,6 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th extension packagers may integrate properly. - Get rid of the '?'-syntax and use another invalid Matrix char/valid XMPP char ('$'?) for escaped? -- PROPER FUCKING AVATARS - XMPP->Matrix is decent, Matrix->XMPP is effectiveny not done - Consider making room/MUC admins/owners be able to plumb instead of it being restricted to Parsee admins, with permission from MUC owners, too - Limiting to admins may be a way to "control" consent for both, but this is @@ -91,7 +91,6 @@ restricted to Parsee admins, with permission from MUC owners, too support XMPP->Matrix bridging. - Manage MUC DMs in a reasonable manner. Thanks `@freeoffers4u:matrix.org` for being a fucking annoyance and DMing an old Parsee semi-anon user for no clear reason. -- Deadlocks. It's always deadlocks. ## DONATING/CONTRIBUTING If you know things about XMPP or Matrix, yet aren't familiar with C99, or just diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 1817997..6ac3a5c 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -286,16 +286,6 @@ SetStanzaXParsee(StanzaBuilder *builder, HashMap *e) XMLAddChild(parsee_link, link_elem); XMLAddChild(parsee, parsee_link); - parsee_text = XMLCreateTag("zayds-note"); - text_elem = XMLCreateText("\"LDA HANG YOURSELF\" - Zayd"); - XMLAddChild(parsee_text, text_elem); - XMLAddChild(parsee, parsee_text); - - parsee_text = XMLCreateTag("mcnebs-note"); - text_elem = XMLCreateText("LDA will never beat the allegations"); - XMLAddChild(parsee_text, text_elem); - XMLAddChild(parsee, parsee_text); - if (event_id) { parsee_event = XMLCreateTag("event-id"); diff --git a/src/XMPPThread/PEP.c b/src/XMPPThread/PEP.c index 856d6de..c459292 100644 --- a/src/XMPPThread/PEP.c +++ b/src/XMPPThread/PEP.c @@ -10,6 +10,8 @@ #include #include +#define PUBSUB "http://jabber.org/protocol/pubsub" + XMLElement * CreatePubsubRequest(char *from, char *to, char *node) { @@ -22,7 +24,7 @@ CreatePubsubRequest(char *from, char *to, char *node) XMLAddAttr(iq_req, "type", "set"); pubsub = XMLCreateTag("pubsub"); - XMLAddAttr(pubsub, "xmlns", "http://jabber.org/protocol/pubsub"); + XMLAddAttr(pubsub, "xmlns", PUBSUB); XMLAddChild(iq_req, pubsub); sub = XMLCreateTag("subscribe"); @@ -34,12 +36,40 @@ CreatePubsubRequest(char *from, char *to, char *node) return iq_req; } +static bool +IsPubsubRequest(XMLElement *stanza) +{ + char *type = HashMapGet(stanza ? stanza->attrs : NULL, "type"); + XMLElement *pubsub, *subscribe; + if (!stanza) + { + return false; + } + + if (!StrEquals(stanza->name, "iq") || + !StrEquals(type, "set")) + { + return false; + } + + pubsub = XMLookForTKV(stanza, "pubsub", "xmlns", PUBSUB); + if (!pubsub) + { + return false; + } + + return XMLookForUnique(pubsub, "subscribe"); +} + + struct PEPManager { pthread_mutex_t lock; ParseeData *data; HashMap *node_table; + HashMap *followers; + void *cookie; }; @@ -56,6 +86,7 @@ CreatePEPManager(ParseeData *data, void *cookie) ret->cookie = cookie; ret->data = data; ret->node_table = HashMapCreate(); + ret->followers = HashMapCreate(); pthread_mutex_init(&ret->lock, NULL); return ret; @@ -91,9 +122,9 @@ PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) { return false; } -#define PEP_NS "http://jabber.org/protocol/pubsub" - if (!(ps = XMLookForTKV(stanza, "pubsub", "xmlns", PEP_NS)) && - !(ev = XMLookForTKV(stanza, "event", "xmlns", PEP_NS "#event"))) + + if (!(ps = XMLookForTKV(stanza, "pubsub", "xmlns", PUBSUB)) && + !(ev = XMLookForTKV(stanza, "event", "xmlns", PUBSUB "#event"))) { return false; } @@ -135,6 +166,11 @@ PEPManagerHandle(PEPManager *manager, XMLElement *stanza) } /* Check if it is a PEP stanza */ + if (IsPubsubRequest(stanza)) + { + Log(LOG_DEBUG, "UNIMPLEMENTED PUBSUB SUBSCRIPTION"); + /* TODO */ + } if (PEPManagerHandleEvent(manager, stanza)) { return true; @@ -158,5 +194,8 @@ DestroyPEPManager(PEPManager *manager) Free(val); } HashMapFree(manager->node_table); + + HashMapFree(manager->followers); + Free(manager); } diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 5d410f6..f518a67 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -68,7 +68,7 @@ XMPPDispatcher(void *argp) if (StrEquals(stanza->name, "presence")) { - PresenceStanza(args, stanza); + PresenceStanza(args, stanza, thread); XMLFreeElement(stanza); continue; } diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 225a361..ed52364 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -57,7 +57,7 @@ GuessStatus(XMLElement *stanza) return USER_STATUS_ONLINE; } void -PresenceStanza(ParseeData *args, XMLElement *stanza) +PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { #define MUC_USER_NS "http://jabber.org/protocol/muc#user" XMLElement *user_info; @@ -66,6 +66,11 @@ PresenceStanza(ParseeData *args, XMLElement *stanza) char *oid = HashMapGet(stanza->attrs, "from"); + if (PEPManagerHandle(thr->info->pep_manager, stanza)) + { + return; + } + if (ServerHasXEP421(args, oid)) { XMLElement *occupant = XMLookForTKV( diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index d937b8a..4c39b40 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -78,7 +78,7 @@ XMLElement * CreatePubsubRequest(char *from, char *to, char *node); bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); -void PresenceStanza(ParseeData *args, XMLElement *stanza); +void PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); bool ServerHasXEP421(ParseeData *data, char *from); @@ -89,6 +89,7 @@ PEPManager * CreatePEPManager(ParseeData *data, void *cookie); void * PEPManagerCookie(PEPManager *manager); void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event); bool PEPManagerHandle(PEPManager *manager, XMLElement *stanza); +void PEPManagerBroadcast(PEPManager *manager, char *as, XMLElement *item); void DestroyPEPManager(PEPManager *manager); /* PEP callbacks for the handler */ From 7ee5c055f4a8c57146cff6d00a808104ba9fb6c7 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 18 Sep 2024 15:39:52 +0200 Subject: [PATCH 081/186] [MOD] Actually start noting down presence requests --- build.conf | 1 + src/Signal.c | 4 ++ src/XMPPThread/PEP.c | 1 + src/XMPPThread/PresenceSub.c | 62 +++++++++++++++++++++++++++++++ src/XMPPThread/Stanzas/Presence.c | 10 ++++- src/XMPPThread/internal.h | 4 ++ 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/XMPPThread/PresenceSub.c diff --git a/build.conf b/build.conf index b3ce98b..ebc5276 100644 --- a/build.conf +++ b/build.conf @@ -6,3 +6,4 @@ SOURCE=src INCLUDES=src/include OBJECT=build CC=cc +CFLAGS=-O3 diff --git a/src/Signal.c b/src/Signal.c index f0f4ee7..89e48e2 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -22,6 +22,10 @@ SignalHandler(int signal) HttpServerStop(server); return; } + if (signal == SIGPIPE) + { + Log(LOG_DEBUG, "Caught a SIGPIPE..."); + } } bool diff --git a/src/XMPPThread/PEP.c b/src/XMPPThread/PEP.c index c459292..a8868ec 100644 --- a/src/XMPPThread/PEP.c +++ b/src/XMPPThread/PEP.c @@ -58,6 +58,7 @@ IsPubsubRequest(XMLElement *stanza) return false; } + Log(LOG_INFO, "WOAH"); return XMLookForUnique(pubsub, "subscribe"); } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c new file mode 100644 index 0000000..da070c4 --- /dev/null +++ b/src/XMPPThread/PresenceSub.c @@ -0,0 +1,62 @@ +#include "XMPPThread/internal.h" + +static char * +SubscriptionHash(ParseeData *data, char *from, char *to) +{ + uint8_t *sum; + char *hash; + size_t len; + + len = strlen(from) + 1 + strlen(to); + sum = Malloc(len); + memset(sum, 0x00, len); + memcpy(sum[0], from, strlen(from)): + memcpy(sum[strlen(from) + 1], to, strlen(to)); + + hash = ParseeHMAC(data->id, sum, len); + Free(sum); + + return hash; +} + +void +AddPresenceSubscriber(ParseeData *data, char *from, char *to) +{ + Db *database; + DbRef *ref; + char *hash; + if (!data || !from || !to) + { + return; + } + + database = data->db; + hash = SubscriptionHash(data, from, to); + ref = DbCreate(database, 2, "subscriptions", hash); + + HashMapSet(DbRef(ref), "from", JsonValueString(from)); + HashMapSet(DbRef(ref), "to", JsonValueString(to)); + /* I don't think we need more information right now */ + + DbClose(database, ref); + Free(hash); +} + +bool +IsSubscribed(ParseeData *data, char *user, char *to) +{ + Db *database; + char *hash; + bool ret; + if (!data || !from || !to) + { + return; + } + + database = data->db; + hash = SubscriptionHash(data, from, to); + ret = DbExists(database, 2, "subscriptions", hash); + Free(hash); + + return ret; +} diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index ed52364..8323f6a 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -65,6 +65,15 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLElement *status = XMLookForUnique(stanza, "status"); char *oid = HashMapGet(stanza->attrs, "from"); + char *dst = HashMapGet(stanza->attrs, "to"); + char *type = HashMapGet(stanza->attrs, "type"); + + if (StrEquals(type, "subscribe")) + { + Log(LOG_WARNING, "!PRESENCE SUBSCRIPTION REQUEST! (%s:%s)", oid, dst); + AddPresenceSubscriber(args, oid, dst); /* TODO: Send presence updates + * whenever possible. */ + } if (PEPManagerHandle(thr->info->pep_manager, stanza)) { @@ -97,7 +106,6 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *jid = item ? HashMapGet(item->attrs, "jid") : NULL; char *trim = ParseeTrimJID(jid); char *from = NULL; - char *type = HashMapGet(stanza->attrs, "type"); char *room = ParseeGetBridgedRoom(args, stanza); char *decode_from, *real_matrix; char *matrix_user_pl = ParseeEncodeJID(args->config, trim, false); diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index 4c39b40..3a158b5 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -97,3 +97,7 @@ void PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item); void PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item); char * ScrambleOID(ParseeData *data, char *opaque_oid); + +/* Presence management */ +void AddPresenceSubscriber(ParseeData *data, char *from, char *to); +bool IsSubscribed(ParseeData *data, char *user, char *to); From c607a990040fa8ab5799c91ce63046cb5e07263a Mon Sep 17 00:00:00 2001 From: lda Date: Thu, 19 Sep 2024 06:54:17 +0000 Subject: [PATCH 082/186] [FIX] Get rid of unused variable It's joever... --- src/StanzaBuilder.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 6ac3a5c..0a97102 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -259,7 +259,6 @@ SetStanzaXParsee(StanzaBuilder *builder, HashMap *e) { XMLElement *parsee_version, *ver_elem; XMLElement *parsee_link, *link_elem; - XMLElement *parsee_text, *text_elem; XMLElement *parsee_event, *event_elem; XMLElement *parsee_json, *json_elem; char *event_id = GrabString(e, 1, "event_id"); From e54332e3763a32d596e41abdcc1e74e0717a2636 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 19 Sep 2024 23:24:46 +0200 Subject: [PATCH 083/186] [MOD] Basic work to get XMPP avatars through PEP Attaboy! --- CHANGELOG.md | 2 +- README.MD | 2 +- src/AS/Media.c | 93 ++++++++++++++++++++++++++ src/AS/Profile.c | 69 ++++++++++++++++++++ src/Main.c | 2 + src/MatrixEventHandler.c | 72 ++++++++++++++++++--- src/XMPPThread/PEP.c | 3 +- src/XMPPThread/PresenceSub.c | 108 +++++++++++++++++++++++++++---- src/XMPPThread/Stanzas/IQ.c | 63 ++++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 11 ++++ src/include/AS.h | 20 ++++++ src/include/Parsee.h | 6 ++ tools/aya.c | 2 +- 13 files changed, 428 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf82211..3076eeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ of Parsee. May occasionally deadlock. Fixes some media metadata things, and replaces the build system of Parsee. #### New things -*NONE* +- Start dealing with some basic PEP-based avatars. #### Bugfixes - Adds more information to media events so that clients can behave. - Fixes issues where SIGPIPE can actually just kill Parsee. diff --git a/README.MD b/README.MD index 5205590..51cc590 100644 --- a/README.MD +++ b/README.MD @@ -69,7 +69,7 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th ## TODOS before 1.0 rolls around - PROPER FUCKING AVATARS - XMPP->Matrix is decent, Matrix->XMPP is effectiveny not done + XMPP->Matrix is decent, Matrix->XMPP is effectively a WIP - Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency. - It depends on more stuff anyways, and I don't want to weigh down the dependency list of Parsee for that. diff --git a/src/AS/Media.c b/src/AS/Media.c index fceefa9..1742189 100644 --- a/src/AS/Media.c +++ b/src/AS/Media.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -127,3 +128,95 @@ ASReupload(const ParseeConfig *c, char *from, char **mime) return ret; } +bool +ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha) +{ + HttpClientContext *cctx; + Stream *stream; + Stream *fake; + Uri *uri; + char *path, *buf = NULL; + unsigned char *sha1; + size_t len; + bool ret; + if (!c || !mxc || !mime || !sha) + { + return false; + } + *mime = NULL; + *sha = NULL; + + if (!(uri = UriParse(mxc)) || !StrEquals(uri->proto, "mxc")) + { + return false; + } + + path = StrConcat(3, "/_matrix/media/v3/download/", uri->host, uri->path); + cctx = ParseeCreateRequest(c, HTTP_GET, path); + ASAuthenticateRequest(c, cctx); + HttpRequestSendHeaders(cctx); + HttpRequestSend(cctx); + + *mime = StrDuplicate( + HashMapGet(HttpResponseHeaders(cctx), "content-type") + ); + stream = HttpClientStream(cctx); + fake = StreamFile(open_memstream(&buf, &len)); + StreamCopy(stream, fake); + StreamClose(fake); + + sha1 = Sha1Raw(buf, len); + free(buf); + *sha = ShaToHex(sha1, HASH_SHA1); + Free(sha1); + + HttpClientContextFree(cctx); + UriFree(uri); + Free(path); + return true; +} +bool +ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len) +{ + HttpClientContext *cctx; + Stream *stream; + Stream *fake; + Uri *uri; + char *path, *buf = NULL; + bool ret; + if (!c || !mxc || !mime || !out || !len) + { + return false; + } + *mime = NULL; + *out = NULL; + *len = 0; + + if (!(uri = UriParse(mxc)) || !StrEquals(uri->proto, "mxc")) + { + return false; + } + + path = StrConcat(3, "/_matrix/media/v3/download/", uri->host, uri->path); + cctx = ParseeCreateRequest(c, HTTP_GET, path); + ASAuthenticateRequest(c, cctx); + HttpRequestSendHeaders(cctx); + HttpRequestSend(cctx); + + *mime = StrDuplicate( + HashMapGet(HttpResponseHeaders(cctx), "content-type") + ); + stream = HttpClientStream(cctx); + fake = StreamFile(open_memstream(&buf, len)); + StreamCopy(stream, fake); + StreamClose(fake); + + *out = Malloc(*len); + memcpy(*out, buf, *len); + free(buf); + + HttpClientContextFree(cctx); + UriFree(uri); + Free(path); + return true; +} diff --git a/src/AS/Profile.c b/src/AS/Profile.c index 73e9b4b..f536300 100644 --- a/src/AS/Profile.c +++ b/src/AS/Profile.c @@ -136,3 +136,72 @@ ASGetName(const ParseeConfig *c, char *room, char *user) } return ret; } +char * +ASGetAvatar(const ParseeConfig *c, char *room, char *user) +{ + HttpClientContext *ctx; + HashMap *reply; + char *path = NULL, *ret = NULL; + char *u2 = user; + if (!c || !user) + { + return NULL; + } + + if (room) + { + 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, "avatar_url")) + ); + HttpClientContextFree(ctx); + JsonFree(reply); + Free(path); + + user = u2; + + Log(LOG_DEBUG, "ASGetAvatar: trying to grab avatar from room, got %s", ret); + } + + if (!ret) + { + user = HttpUrlEncode(user); + path = StrConcat(3, + "/_matrix/client/v3/profile/", user, "/avatar_url" + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(user); + user = u2; + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "avatar_url")) + ); + StreamFlush(StreamStderr()); + HttpClientContextFree(ctx); + JsonFree(reply); + Free(path); + + Log(LOG_DEBUG, "ASGetAvatar: trying to grab avatar from profile, got %s", ret); + } + + return ret; +} diff --git a/src/Main.c b/src/Main.c index aa47822..fe976bf 100644 --- a/src/Main.c +++ b/src/Main.c @@ -78,6 +78,8 @@ Main(Array *args, HashMap *env) ); ParseePrintASCII(); Log(LOG_INFO, "======================="); + Log(LOG_INFO, "(C)opyright 2023 LDA"); + Log(LOG_INFO, "(This program is free software, see LICENSE.)"); LogConfigIndent(LogConfigGlobal()); { diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 82d4cf8..3835fe8 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -16,7 +16,7 @@ static const char * GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to); -static void +static char * JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) { char *sender = GrabString(event, 1, "sender"); @@ -50,7 +50,7 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) ParseePushNickTable(muc, sender, nick); Free(nick); - Free(rev); + return (rev); } static void @@ -98,13 +98,71 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) { char *muc = ParseeGetMUCID(data, chat_id); char *name = ASGetName(data->config, room_id, state_key); + char *avatar = ASGetAvatar(data->config, room_id, state_key); + char *jabber = JoinMUC(data, event, jid, muc, name); - JoinMUC(data, event, jid, muc, name); + Log(LOG_DEBUG, "MATRIX: Joining as '%s' (avatar=%s)", jabber, avatar); + + Free(avatar); + Free(jabber); Free(name); Free(muc); /* TODO: XEP-0084 magic to advertise a new avatar if possible. */ } + else + { + char *avatar = ASGetAvatar(data->config, room_id, state_key); + char *sha = NULL, *mime = NULL, *url = NULL; + char *full_jid = StrConcat(3, + jid, "@", data->config->component_host + ); + XMLElement *elem, *pevent, *items, *item, *meta, *info; + + Log(LOG_DEBUG, "MATRIX: Got local user '%s'(mxid=%s avatar=%s)", jid, state_key, avatar); + + url = ParseeToUnauth(data, avatar); + elem = XMLCreateTag("message"); + ASGetMIMESHA(data->config, avatar, &mime, &sha); + { +#define PUBSUB "http://jabber.org/protocol/pubsub" +#define AVATAR "urn:xmpp:avatar:metadata" + pevent = XMLCreateTag("event"); + XMLAddAttr(pevent, "xmlns", PUBSUB "#event"); + { + items = XMLCreateTag("items"); + item = XMLCreateTag("item"); + XMLAddAttr(items, "node", AVATAR); + XMLAddAttr(item, "id", sha); + { + meta = XMLCreateTag("metadata"); + info = XMLCreateTag("info"); + XMLAddAttr(meta, "xmlns", AVATAR); + + XMLAddAttr(info, "id", sha); + XMLAddAttr(info, "url", url); + XMLAddAttr(info, "type", mime); + + XMLAddChild(meta, info); + XMLAddChild(item, meta); + } + XMLAddChild(items, item); + XMLAddChild(pevent, items); + } + XMLAddChild(elem, pevent); +#undef PUBSUB + } + + /* TODO: Broadcast PEP avatar change */ + ParseeBroadcastStanza(data, full_jid, elem); + XMLFreeElement(elem); + + Free(full_jid); + Free(avatar); + Free(mime); + Free(sha); + Free(url); + } Free(jid); Free(chat_id); } @@ -263,7 +321,7 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } matrix_name = ASGetName(data->config, room_id, matrix_sender); - JoinMUC(data, event, *from, muc_id, matrix_name); + Free(JoinMUC(data, event, *from, muc_id, matrix_name)); *to = muc_id; Free(matrix_name); @@ -350,12 +408,8 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) goto end; } - /* TODO: Check the name's validity. - * Is there a good way to check for that that isn't - * just "await on join and try again?" */ name = ASGetName(data->config, id, m_sender); - - JoinMUC(data, event, encoded_from, muc_id, name); + Free(JoinMUC(data, event, encoded_from, muc_id, name)); to = muc_id; diff --git a/src/XMPPThread/PEP.c b/src/XMPPThread/PEP.c index a8868ec..f49dcd0 100644 --- a/src/XMPPThread/PEP.c +++ b/src/XMPPThread/PEP.c @@ -40,7 +40,7 @@ static bool IsPubsubRequest(XMLElement *stanza) { char *type = HashMapGet(stanza ? stanza->attrs : NULL, "type"); - XMLElement *pubsub, *subscribe; + XMLElement *pubsub; if (!stanza) { return false; @@ -58,7 +58,6 @@ IsPubsubRequest(XMLElement *stanza) return false; } - Log(LOG_INFO, "WOAH"); return XMLookForUnique(pubsub, "subscribe"); } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c index da070c4..453df40 100644 --- a/src/XMPPThread/PresenceSub.c +++ b/src/XMPPThread/PresenceSub.c @@ -1,5 +1,14 @@ #include "XMPPThread/internal.h" +#include +#include +#include +#include +#include +#include + +#include + static char * SubscriptionHash(ParseeData *data, char *from, char *to) { @@ -10,14 +19,28 @@ SubscriptionHash(ParseeData *data, char *from, char *to) len = strlen(from) + 1 + strlen(to); sum = Malloc(len); memset(sum, 0x00, len); - memcpy(sum[0], from, strlen(from)): - memcpy(sum[strlen(from) + 1], to, strlen(to)); + memcpy(&sum[0], from, strlen(from)); + memcpy(&sum[strlen(from) + 1], to, strlen(to)); - hash = ParseeHMAC(data->id, sum, len); + hash = Base64Encode(sum, len); Free(sum); return hash; } +static void +DecodeSubscription(ParseeData *data, char *hash, char **from, char **to) +{ + char *sum; + if (!data || !hash || !from || !to) + { + return; + } + + sum = Base64Decode(hash, strlen(hash)); + *from = StrDuplicate(sum); + *to = StrDuplicate(sum + strlen(sum) + 1); + Free(sum); +} void AddPresenceSubscriber(ParseeData *data, char *from, char *to) @@ -32,13 +55,18 @@ AddPresenceSubscriber(ParseeData *data, char *from, char *to) database = data->db; hash = SubscriptionHash(data, from, to); - ref = DbCreate(database, 2, "subscriptions", hash); + ref = DbCreate(database, 2, "subs", hash); + if (!ref) + { + goto end; + } - HashMapSet(DbRef(ref), "from", JsonValueString(from)); - HashMapSet(DbRef(ref), "to", JsonValueString(to)); + HashMapSet(DbJson(ref), "from", JsonValueString(from)); + HashMapSet(DbJson(ref), "to", JsonValueString(to)); /* I don't think we need more information right now */ - DbClose(database, ref); +end: + DbUnlock(database, ref); Free(hash); } @@ -48,15 +76,73 @@ IsSubscribed(ParseeData *data, char *user, char *to) Db *database; char *hash; bool ret; - if (!data || !from || !to) + if (!data || !user || !to) { - return; + return false; } database = data->db; - hash = SubscriptionHash(data, from, to); - ret = DbExists(database, 2, "subscriptions", hash); + hash = SubscriptionHash(data, user, to); + ret = DbExists(database, 2, "subs", hash); Free(hash); return ret; } + +void +ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza) +{ + XMPPComponent *jabber = data ? data->jabber : NULL; + Array *entries; + size_t i; + if (!data || !from || !stanza) + { + return; + } + + /* Copy our stanza so that we can freely modify it */ + stanza = XMLCopy(stanza); + + /* Start doing a storm on Mt. Subs. */ + entries = DbList(data->db, 1, "subs"); + for (i = 0; i < ArraySize(entries); i++) + { + char *entry = ArrayGet(entries, i); + char *entry_from = NULL, *entry_to = NULL; + char *storm_id; /* ooe */ + XMLElement *sub; + + DecodeSubscription(data, entry, &entry_from, &entry_to); + + if (!StrEquals(entry_to, from)) + { + goto end; + } + + Log(LOG_DEBUG, + "PRESENCE SYSTEM: " + "We should be brotkasting straight to %s (from %s)", + entry_from, from + ); + sub = XMLCopy(stanza); + XMLAddAttr(sub, "from", from); + XMLAddAttr(sub, "to", entry_from); + + /* TODO: Should we store IDs somewhere? */ + XMLAddAttr(sub, "id", (storm_id = StrRandom(16))); + + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, sub); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + + XMLFreeElement(sub); + Free(storm_id); + end: + Free(entry_from); + Free(entry_to); + } + DbListFree(entries); + XMLFreeElement(stanza); + +} diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 125c5e1..6058ba4 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -327,6 +327,7 @@ void IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { XMPPComponent *jabber = args->jabber; + XMLElement *pubsub; char *from = HashMapGet(stanza->attrs, "from"); char *to = HashMapGet(stanza->attrs, "to"); char *id = HashMapGet(stanza->attrs, "id"); @@ -395,6 +396,68 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLFreeElement(iqVCard); } } +#define PS "http://jabber.org/protocol/pubsub" + else if ((pubsub = XMLookForTKV(stanza, "pubsub", "xmlns", PS))) + { + /* TODO: Pass this through the PEP manager */ + XMLElement *a_items = XMLookForTKV(pubsub, + "items", "node", "urn:xmpp:avatar:data" + ); + if (a_items) + { + /* Do, without regret, start shoving an avatar out the bus */ + char *to_matrix = ParseeDecodeMXID(to); + char *avatar = ASGetAvatar(args->config, NULL, to_matrix); + char *buf, *mime; + char *b64; + size_t len; + XMLElement *reply; + + ASGrab(args->config, avatar, &mime, &buf, &len); + b64 = Base64Encode(buf, len); + Free(buf); + + Log(LOG_INFO, "FM=%s", to_matrix); + Log(LOG_INFO, "B=%s (%dB)", b64, (int) len); + /* Strike back with a response */ + reply = XMLCreateTag("iq"); + XMLAddAttr(reply, "type", "result"); + XMLAddAttr(reply, "to", from); + XMLAddAttr(reply, "from", to); + XMLAddAttr(reply, "id", HashMapGet(stanza->attrs, "id")); + { + XMLElement *ps = XMLCreateTag("pubsub"); + XMLElement *items = XMLCreateTag("items"); + XMLAddAttr(ps, "xmlns", PS); + XMLAddAttr(items, "node", "urn:xmpp:avatar:data"); + { + XMLElement *item = XMLCreateTag("item"); + XMLElement *data = XMLCreateTag("data"); + XMLAddAttr(item, "id", "TODO"); + XMLAddAttr(data, "xmlns", "urn:xmpp:avatar:data"); + + XMLAddChild(data, XMLCreateText(b64)); + + XMLAddChild(item, data); + XMLAddChild(items, item); + } + XMLAddChild(ps, items); + XMLAddChild(reply, ps); + } + + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, reply); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + XMLFreeElement(reply); + + Free(to_matrix); + Free(avatar); + Free(mime); + Free(b64); + } + } +#undef PS else if (XMLookForTKV(stanza, "query", "xmlns", DISCO)) { IQDiscoGet(args, jabber, stanza); diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 75722e5..9237aec 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -97,6 +97,17 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); return false; } + /*{ + XMLElement *foo = XMLCreateTag("message"); + XMLElement *body = XMLCreateTag("body"); + XMLAddAttr(foo, "type", "chat"); + XMLAddChild(foo, body); + XMLAddChild(body, XMLCreateText("Storm on Mt. Ooe (sorry if you see this)")); + + BroadcastStanza(args, HashMapGet(stanza->attrs, "to"), foo); + XMLFreeElement(foo); + }*/ + if (ServerHasXEP421(args, from)) { diff --git a/src/include/AS.h b/src/include/AS.h index 1d993e1..ad91e60 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -141,6 +141,14 @@ extern void ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, ch * Modifies: NOTHING */ extern char * ASGetName(const ParseeConfig *c, char *room, char *user); +/** Returns the user's avatar in a room, or a the global user avatar, to be + * Free'd + * ------------- + * Returns: The user's name in the [HEAP] | NULL + * Thrasher: Free + * Modifies: NOTHING */ +extern char * ASGetAvatar(const ParseeConfig *c, char *room, char *user); + /** Uploads data to Matrix to be used later * ---------------- * Returns: A valid MXC URI[HEAP] | NULL @@ -170,4 +178,16 @@ extern Array * ASGetRelations(const ParseeConfig *c, size_t n, char *room, char * Thrashes: {relations} * See-Also: ASGetRelations */ extern void ASFreeRelations(Array *relations); + +/** Returns the MIME and SHA-1 hash of a media entry, in one fell swoop. + * ----------------- + * Returns: whenever the media exists + * Modifies: {mime}[HEAP], {sha}[HEAP] */ +extern bool ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha); + +/** Retrieves media off an MXC link. + * ------------ + * Returns: whenever the media exists + * Modifies {mime}[HEAP], {out}[HEAP], {len} */ +extern bool ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len); #endif diff --git a/src/include/Parsee.h b/src/include/Parsee.h index f64df82..34077cd 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -401,4 +401,10 @@ extern void ParseeSetThreads(int xmpp, int http); extern char * ParseeHMAC(char *key, uint8_t *msg, size_t msglen); #define ParseeHMACS(key, msg) ParseeHMAC(key, (uint8_t *) msg, strlen(msg)) +/** Broadcasts a stanza from a user to any that may be interested by it + * (PEP or subscription) + * ------------------------------------- + * Returns: NOTHING */ +extern void ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *s); + #endif diff --git a/tools/aya.c b/tools/aya.c index 69371d1..b49fd6b 100644 --- a/tools/aya.c +++ b/tools/aya.c @@ -109,7 +109,7 @@ ParseAyadoc(char *raw) if (parsing_notes) { char *del = strchr(line_content, ':'); - char *val = del + 1; + char *val = del ? del + 1 : NULL; if (del && strlen(del) >= 1) { while (*val && isspace(*val)) From 6e9ba8f0eed70f653d03fb92d88cec7dbe68f30a Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 19 Sep 2024 23:30:59 +0200 Subject: [PATCH 084/186] [FIX] Fix media C99 fuckups --- src/AS/Media.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/AS/Media.c b/src/AS/Media.c index 1742189..65f049c 100644 --- a/src/AS/Media.c +++ b/src/AS/Media.c @@ -138,7 +138,6 @@ ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha) char *path, *buf = NULL; unsigned char *sha1; size_t len; - bool ret; if (!c || !mxc || !mime || !sha) { return false; @@ -165,7 +164,7 @@ ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha) StreamCopy(stream, fake); StreamClose(fake); - sha1 = Sha1Raw(buf, len); + sha1 = Sha1Raw((unsigned char *) buf, len); free(buf); *sha = ShaToHex(sha1, HASH_SHA1); Free(sha1); @@ -183,7 +182,6 @@ ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len) Stream *fake; Uri *uri; char *path, *buf = NULL; - bool ret; if (!c || !mxc || !mime || !out || !len) { return false; From 9b4d97b0336d69f3fd47d759465477646e90a932 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 20 Sep 2024 07:01:35 +0200 Subject: [PATCH 085/186] [FIX] Fix subscription hash's warns --- src/XMPPThread/PresenceSub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c index 453df40..3f55bce 100644 --- a/src/XMPPThread/PresenceSub.c +++ b/src/XMPPThread/PresenceSub.c @@ -10,7 +10,7 @@ #include static char * -SubscriptionHash(ParseeData *data, char *from, char *to) +SubscriptionHash(char *from, char *to) { uint8_t *sum; char *hash; @@ -22,7 +22,7 @@ SubscriptionHash(ParseeData *data, char *from, char *to) memcpy(&sum[0], from, strlen(from)); memcpy(&sum[strlen(from) + 1], to, strlen(to)); - hash = Base64Encode(sum, len); + hash = Base64Encode((const char *) sum, len); Free(sum); return hash; @@ -54,7 +54,7 @@ AddPresenceSubscriber(ParseeData *data, char *from, char *to) } database = data->db; - hash = SubscriptionHash(data, from, to); + hash = SubscriptionHash(from, to); ref = DbCreate(database, 2, "subs", hash); if (!ref) { @@ -82,7 +82,7 @@ IsSubscribed(ParseeData *data, char *user, char *to) } database = data->db; - hash = SubscriptionHash(data, user, to); + hash = SubscriptionHash(user, to); ret = DbExists(database, 2, "subs", hash); Free(hash); From 6167732e83ef23ddadb4d4e554c984c59c872d74 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 21 Sep 2024 13:18:59 +0200 Subject: [PATCH 086/186] [FIX] BMP for MUC nicks, dip toes in vCard avatars Can, your, Bifrost, Do, That. -lh --- README.MD | 25 ++-- src/Main.c | 13 +++ src/MatrixEventHandler.c | 10 +- src/Unistr.c | 225 ++++++++++++++++++++++++++++++++++++ src/XMPPThread/Stanzas/IQ.c | 55 +++++++-- src/include/Unistring.h | 67 +++++++++++ 6 files changed, 378 insertions(+), 17 deletions(-) create mode 100644 src/Unistr.c create mode 100644 src/include/Unistring.h diff --git a/README.MD b/README.MD index 51cc590..0467280 100644 --- a/README.MD +++ b/README.MD @@ -1,22 +1,25 @@ # Parsee - the jealous XMPP<=>Matrix bridge Parsee is a Matrix<=>XMPP bridge written in C99, with Cytoplasm, similar to Bifrost, but it is NOT a drop-in replacment. -Currently, it is *alpha* stage, which means that I wouldn't recommend using this in production, as I can change anything, at any time. +Currently, it is *alpha* stage, which means that I wouldn't recommend using this in production, +as I can change anything, at any time, and it may behave strangely at times. ## Why? ### Naming The name 'Parsee' is actually a reference to [Parsee Mizuhashi](https://en.touhouwiki.net/wiki/Parsee_Mizuhashi), -a "*bridge* princess". +a "*bridge* princess". The other name you actually can sometimes see explains itself, so I won't +be talking about it. ### Reasoning (personal to LDA) I hate Bifrost. I also wanted to dip my toes in XMPP, XML, and bridges a bit. Also, as a sister project to KappaChat, this means that I can integrate Parsee with KappaChat however I wish it to be, which allows me to mess around with a codebase I'm already familiar with. -A more "up-to-date" reason may be to have a small, 'Just Werks' bridging solution *that is good*. +A more "up-to-date" reason may be to have a small, 'Just Werks' bridging solution *that is good*, +and maybe as a testing ground for Cytoplasm features I sometimes add. -Well, I'm *trying* to do that, at least. +(Well, I'm *trying* to do that, at least. Please scream at me if that fails(or just doesn't run on a overclocked Raspberry -Pi 4B, which, by the way, is literally where Parsee+XMPP is running for now.) +Pi 4B, which, by the way, is literally where Parsee+XMPP is running for now.)) ### "Why not just use Matrix lol" ### "Why not just use XMPP lol" @@ -26,7 +29,7 @@ a bridge may be a good way to start. ## BUILDING ```sh -$ cc configure.c -o configure +$ cc configure.c -o configure # that or use tcc -run to consolidate these two steps. $ ./configure # use -s if you want static Parsee+MbedTLS, use -s -l if LMDB is needed $ make $ make [PREFIX=...] install # run as root if on a protected dir like /usr @@ -65,17 +68,21 @@ returns with a landing page, then this side works. You can read it for some more ## DOCS Currently, the main sources of documentation are the Ayadocs(for headers) and the manpages -(see `etc/man`) +(see `etc/man`). ## TODOS before 1.0 rolls around -- PROPER FUCKING AVATARS +- Make Parsee go *vroooooooooommmmmmm*, by NOT asking the server constantly +about what is available and what is not, as that is a source of latency, and +thus slowdowns. +- PROPER FUCKING VCARD AVATARS XMPP->Matrix is decent, Matrix->XMPP is effectively a WIP - Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency. - It depends on more stuff anyways, and I don't want to weigh down the dependency list of Parsee for that. - Matrix's libolm is deprecated. They replaced it with a Rust version that pulls in *way too many* dependencies, and that lacks a C binding. We may - put in the work of either forking off libolm or making a binding to KappaChat. + ~~put in the work of either forking off libolm or~~ be making a binding with + KappaChat(when I get around to remaking UI :p). - Josh did infact tell me that maybe C bindings may happen. I'd be willing to help out, but IDK. In any case, this will at best be an extension packagers may integrate properly. diff --git a/src/Main.c b/src/Main.c index fe976bf..b0ed711 100644 --- a/src/Main.c +++ b/src/Main.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,18 @@ Main(Array *args, HashMap *env) start = UtilTsMillis(); + { + Unistr *s = UnistrCreate("Array 日本語🌋"); + size_t i; + for (i = 0; i < UnistrSize(s); i++) + { + uint32_t cp = UnistrGetch(s, i); + Log(LOG_INFO, "%X", cp); + } + + UnistrFree(s); + } + memset(&conf, 0, sizeof(conf)); Log(LOG_INFO, "%s - v%s[%s] (Cytoplasm %s)", diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 3835fe8..73feda5 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -21,10 +22,17 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) { char *sender = GrabString(event, 1, "sender"); - char *nick = StrDuplicate(name); + Unistr *uninick = UnistrCreate(name); + Unistr *filtered = UnistrFilter(uninick, UnistrIsBMP); + char *nick = UnistrC(filtered); char *rev = StrConcat(3, muc, "/", nick); int nonce = 0; + Log(LOG_DEBUG, "MUCJOINER: filtered '%s' to '%s'", name, nick); + + UnistrFree(uninick); + UnistrFree(filtered); + while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 32) { char *nonce_str = StrInt(nonce); diff --git a/src/Unistr.c b/src/Unistr.c new file mode 100644 index 0000000..b9439c8 --- /dev/null +++ b/src/Unistr.c @@ -0,0 +1,225 @@ +#include + +#include +#include +#include + +#include + +struct Unistr { + size_t length; + uint32_t *codepoints; +}; + +void +UnistrAddch(Unistr *unistr, uint32_t u) +{ + if (!unistr || !u) + { + return; + } + unistr->length++; + unistr->codepoints = Realloc( + unistr->codepoints, + unistr->length * sizeof(*unistr->codepoints) + ); + + unistr->codepoints[unistr->length - 1] = u; +} + +static bool +UTFIsN(char *off, size_t available, int n, uint8_t pc) +{ + int i; + uint8_t *offu = (uint8_t *) off; + if ((available < n) || ((*offu >> (8-n-1)) != pc)) + { + return false; + } + + for (i = 0; i < n - 1; i++) + { + if ((offu[i+1] >> 6) != 0b10) + { + return false; + } + } + return true; +} + +Unistr * +UnistrCreate(char *src) +{ + size_t len, i; + Unistr *str; + char *start; + if (!src) + { + return NULL; + } + + len = strlen(src); + str = Malloc(sizeof(*str)); + str->length = 0; + str->codepoints = NULL; + + /* We can't just set the length to {len}. */ + for (i = 0; i < len; i++) + { + char byte = src[i]; + size_t available = len - i; + if ((byte & 0x80) == 0) + { + /* This is a regular codepoint */ + UnistrAddch(str, byte & 0x7F); + continue; + } + else if (UTFIsN(&src[i], available, 2, 0b110)) + { + char a = src[i+0] & 0b00011111; + char b = src[i+1] & 0b00111111; + uint32_t u = (a << (6 * 1)) | b; + + /* Overlongs are errors. */ + if (u < 0x0080 || u > 0x07FF) + { + UnistrFree(str); + return NULL; + } + + UnistrAddch(str, u); + i += 2 - 1; + continue; + } + else if (UTFIsN(&src[i], available, 3, 0b1110)) + { + char a = src[i+0] & 0b00001111; + char b = src[i+1] & 0b00111111; + char c = src[i+2] & 0b00111111; + uint32_t u = + (a << (6 * 2)) | + (b << (6 * 1)) | + (c << (6 * 0)) ; + + /* Overlongs are errors. */ + if (u < 0x0800 || u > 0xFFFF) + { + UnistrFree(str); + return NULL; + } + + UnistrAddch(str, u); + i += 3 - 1; + continue; + } + else if (UTFIsN(&src[i], available, 4, 0b11110)) + { + char a = src[i+0] & 0b00000111; + char b = src[i+1] & 0b00111111; + char c = src[i+2] & 0b00111111; + char d = src[i+3] & 0b00111111; + uint32_t u = + (a << (6 * 3)) | + (b << (6 * 2)) | + (c << (6 * 1)) | + (d << (6 * 0)) ; + + /* Overlongs are errors. */ + if (u < 0x10000 || u > 0x10FFFF) + { + UnistrFree(str); + return NULL; + } + + UnistrAddch(str, u); + i += 4 - 1; + continue; + + } + } + + return str; +} +void +UnistrFree(Unistr *unistr) +{ + if (!unistr) + { + return; + } + + Free(unistr->codepoints); + Free(unistr); +} +char * +UnistrC(Unistr *unistr) +{ + char *ret, *tmp, *utf; + size_t i; + if (!unistr) + { + return NULL; + } + + ret = NULL; + for (i = 0; i < unistr->length; i++) + { + uint32_t code = unistr->codepoints[i]; + utf = StrUtf8Encode(code); + + tmp = ret; + ret = StrConcat(2, ret, utf); + Free(tmp); + Free(utf); + } + + return ret; +} +size_t +UnistrSize(Unistr *unistr) +{ + return unistr ? unistr->length : 0; +} +uint32_t +UnistrGetch(Unistr *unistr, size_t i) +{ + if (!unistr) + { + return 0; + } + + return i < unistr->length ? unistr->codepoints[i] : 0; +} +bool +UnistrIsBMP(uint32_t u) +{ + if (u == 0) + { + return NULL; + } + + return u <= 0xFFFF; +} +Unistr * +UnistrFilter(Unistr *str, UnistrFilterFunc filter) +{ + Unistr *unistr; + size_t i; + if (!str || !filter) + { + return NULL; + } + + unistr = UnistrCreate(""); + for (i = 0; i < UnistrSize(str); i++) + { + uint32_t code = UnistrGetch(str, i); + if (!filter(code)) + { + continue; + } + UnistrAddch(unistr, code); + } + + return unistr; +} diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 6058ba4..c6e929f 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -356,14 +356,14 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) { - Log(LOG_INFO, "vCard information GET for %s", to); + char *to_matrix = ParseeGetBridgedUser(args, stanza); + char *name = ASGetName(args->config, NULL, to_matrix); + XMLElement *iqVCard; + Log(LOG_DEBUG, "vCard information GET for %s", to); - /* TODO: "a compliant server MUST respond on behalf of the - * requestor and not forward the IQ to the requestee's - * connected resource". */ if (!strncmp(to, "parsee@", 7)) { - XMLElement *iqVCard = XMLCreateTag("iq"); + iqVCard = XMLCreateTag("iq"); XMLAddAttr(iqVCard, "from", to); XMLAddAttr(iqVCard, "to", from); XMLAddAttr(iqVCard, "id", id); @@ -394,7 +394,49 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iqVCard); + Free(to_matrix); + Free(name); + return; } + + iqVCard = XMLCreateTag("iq"); + XMLAddAttr(iqVCard, "from", to); + XMLAddAttr(iqVCard, "to", from); + XMLAddAttr(iqVCard, "id", id); + XMLAddAttr(iqVCard, "type", "result"); + { + XMLElement *vCard = XMLCreateTag("vCard"); + char *mto_link = ParseeGenerateMTO(to_matrix); + XMLAddAttr(vCard, "xmlns", "vcard-temp"); + { + XMLElement *fn = CreateTagWithText( + "FN", name ? name : to_matrix + ); + XMLElement *nick = CreateTagWithText( + "NICKNAME", to_matrix + ); + XMLElement *url = CreateTagWithText( + "URL", mto_link + ); + + /* TODO: Maybe abstract the vCard code. */ + /* TODO: Make a function to just get a user's avatar + * automatically. */ + XMLAddChild(vCard, nick); + XMLAddChild(vCard, url); + XMLAddChild(vCard, fn); + + Free(mto_link); + } + XMLAddChild(iqVCard, vCard); + } + + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iqVCard); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + Free(to_matrix); + Free(name); } #define PS "http://jabber.org/protocol/pubsub" else if ((pubsub = XMLookForTKV(stanza, "pubsub", "xmlns", PS))) @@ -417,8 +459,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) b64 = Base64Encode(buf, len); Free(buf); - Log(LOG_INFO, "FM=%s", to_matrix); - Log(LOG_INFO, "B=%s (%dB)", b64, (int) len); + Log(LOG_DEBUG, "IQ-GET: PUBSUB AVATAR OF=%s", to_matrix); /* Strike back with a response */ reply = XMLCreateTag("iq"); XMLAddAttr(reply, "type", "result"); diff --git a/src/include/Unistring.h b/src/include/Unistring.h new file mode 100644 index 0000000..f1c9aee --- /dev/null +++ b/src/include/Unistring.h @@ -0,0 +1,67 @@ +#ifndef PARSEE_UNISTRING_H +#define PARSEE_UNISTRING_H + +/*-*

A basic datastructure to handle Unicode strings easily.

+ *

Mainly used because dealing with UTF-8 directly may be an + * annoyance, and it may be used as a base for Cytoplasm's own + * string management

+ * -------- + * Written-By: LDA + * License: CC0 */ + +#include +#include +#include + +/* An opaque structure for a Unistring */ +typedef struct Unistr Unistr; + +/** Decodes an UTF-8 string into a separate Unistr. + * ------- + * Returns: a valid Unistr[HEAP] | NULL + * Thrasher: UnistrFree */ +extern Unistr * UnistrCreate(char *src); + +/** Returns the length of an unistring. + * ---------- + * Returns: the unistring's length | NULL */ +extern size_t UnistrSize(Unistr *unistr); + +/** Returns the character of an unistring at a location, + * or 0 if it is inaccessible. + * ---------- + * Returns: The Unicode codepoint of a specific 0-index | 0 */ +extern uint32_t UnistrGetch(Unistr *unistr, size_t i); + +/** Adds a singular codepoint to a unistring(IFF not 0 and valid). + * ------------- + * Returns: NOTHING + * Modifies: unistr */ +extern void UnistrAddch(Unistr *unistr, uint32_t u); + +/** Encodes a unistring into a C UTF-8 string + * -------------- + * Returns: a valid NULL-terminated string[HEAP] | NULL + * Thrasher: Free */ +extern char * UnistrC(Unistr *unistr); + +/** Destroys all memory associated with a unistring. + * ---------- + * Returns: NOTHING + * Thrashes: {unistr} */ +extern void UnistrFree(Unistr *unistr); + +/** Returns true IFF the character is within the unicode BMP and + * not 0x0000 + * ------------------------------------------------------------ + * Returns: whenever the character is within the BMP */ +extern bool UnistrIsBMP(uint32_t u); + +typedef bool (*UnistrFilterFunc)(uint32_t u); +/** "Filters" characters in a Unistring by codepoint, removing + * those with callbacks which return false into a new unistring. + * -------------------- + * Returns: a new unistring with filtered characters removed */ +extern Unistr * UnistrFilter(Unistr *str, UnistrFilterFunc filter); + +#endif From b9954c06ce5f82d7caca1df781686bc0ef5704d9 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 21 Sep 2024 13:48:09 +0200 Subject: [PATCH 087/186] [FIX] Apparently 0b isn't valid C99 --- src/Main.c | 12 ------------ src/Unistr.c | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/Main.c b/src/Main.c index b0ed711..988894f 100644 --- a/src/Main.c +++ b/src/Main.c @@ -72,18 +72,6 @@ Main(Array *args, HashMap *env) start = UtilTsMillis(); - { - Unistr *s = UnistrCreate("Array 日本語🌋"); - size_t i; - for (i = 0; i < UnistrSize(s); i++) - { - uint32_t cp = UnistrGetch(s, i); - Log(LOG_INFO, "%X", cp); - } - - UnistrFree(s); - } - memset(&conf, 0, sizeof(conf)); Log(LOG_INFO, "%s - v%s[%s] (Cytoplasm %s)", diff --git a/src/Unistr.c b/src/Unistr.c index b9439c8..cfb100a 100644 --- a/src/Unistr.c +++ b/src/Unistr.c @@ -39,7 +39,7 @@ UTFIsN(char *off, size_t available, int n, uint8_t pc) for (i = 0; i < n - 1; i++) { - if ((offu[i+1] >> 6) != 0b10) + if ((offu[i+1] >> 6) != 0x2) { return false; } @@ -74,10 +74,10 @@ UnistrCreate(char *src) UnistrAddch(str, byte & 0x7F); continue; } - else if (UTFIsN(&src[i], available, 2, 0b110)) + else if (UTFIsN(&src[i], available, 2, 0x06)) { - char a = src[i+0] & 0b00011111; - char b = src[i+1] & 0b00111111; + char a = src[i+0] & 0x1F; + char b = src[i+1] & 0x3F; uint32_t u = (a << (6 * 1)) | b; /* Overlongs are errors. */ @@ -91,11 +91,11 @@ UnistrCreate(char *src) i += 2 - 1; continue; } - else if (UTFIsN(&src[i], available, 3, 0b1110)) + else if (UTFIsN(&src[i], available, 3, 0x0E)) { - char a = src[i+0] & 0b00001111; - char b = src[i+1] & 0b00111111; - char c = src[i+2] & 0b00111111; + char a = src[i+0] & 0x0F; + char b = src[i+1] & 0x3F; + char c = src[i+2] & 0x3F; uint32_t u = (a << (6 * 2)) | (b << (6 * 1)) | @@ -112,12 +112,12 @@ UnistrCreate(char *src) i += 3 - 1; continue; } - else if (UTFIsN(&src[i], available, 4, 0b11110)) + else if (UTFIsN(&src[i], available, 4, 0x1E)) { - char a = src[i+0] & 0b00000111; - char b = src[i+1] & 0b00111111; - char c = src[i+2] & 0b00111111; - char d = src[i+3] & 0b00111111; + char a = src[i+0] & 0x07; + char b = src[i+1] & 0x3F; + char c = src[i+2] & 0x3F; + char d = src[i+3] & 0x3F; uint32_t u = (a << (6 * 3)) | (b << (6 * 2)) | From dba3dcc85f6d0b8b2d09361d31dfd5962e5fa006 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 21 Sep 2024 14:11:04 +0200 Subject: [PATCH 088/186] [FIX] Fix more unistr fuckups --- src/Unistr.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Unistr.c b/src/Unistr.c index cfb100a..3db7441 100644 --- a/src/Unistr.c +++ b/src/Unistr.c @@ -28,11 +28,11 @@ UnistrAddch(Unistr *unistr, uint32_t u) } static bool -UTFIsN(char *off, size_t available, int n, uint8_t pc) +UTFIsN(char *off, size_t available, size_t n, uint8_t pc) { - int i; + size_t i; uint8_t *offu = (uint8_t *) off; - if ((available < n) || ((*offu >> (8-n-1)) != pc)) + if (((available < n) || ((*offu >> (8-n-1)) != pc)) && (n >= 1)) { return false; } @@ -52,7 +52,6 @@ UnistrCreate(char *src) { size_t len, i; Unistr *str; - char *start; if (!src) { return NULL; From c2ea3807ec50b8392e293e1236f452364f93a9dd Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 21 Sep 2024 18:26:35 +0200 Subject: [PATCH 089/186] [MOD/FIX] Licensewerk, start counting by codepoint XEP-0426 came out of the blue, and it *hit* me! --- LICENSE | 2 +- src/Parsee/Utils/String.c | 18 +++++++++++++ src/StanzaBuilder.c | 2 +- src/Unistr.c | 45 ++++++++++++++++++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 25 +++++++++++++----- src/include/Parsee.h | 4 +++ src/include/Unistring.h | 12 +++++++++ 7 files changed, 100 insertions(+), 8 deletions(-) diff --git a/LICENSE b/LICENSE index 1e1282b..ce865e6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -For the files src/Parsee/HMAC.c, src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, +For the files src/include/Unistring.h, src/Unistr.h rc/Parsee/HMAC.c, src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, see COPYING.CC0. For any other file in src/, see COPYING.AGPL as the primary license. diff --git a/src/Parsee/Utils/String.c b/src/Parsee/Utils/String.c index 89d6f4a..c054d13 100644 --- a/src/Parsee/Utils/String.c +++ b/src/Parsee/Utils/String.c @@ -3,6 +3,8 @@ #include #include +#include + #include #include @@ -37,6 +39,22 @@ ParseeFindDatastart(char *data) return (int) (startline - data); } +int +ParseeFindDatastartU(char *data) +{ + Unistr *str; + size_t ret; + if (!data) + { + return 0; + } + + str = UnistrCreate(data); + ret = UnistrGetOffset(str, (uint32_t) '>'); + UnistrFree(str); + + return (int) ret; +} char * ParseeStringifyDate(uint64_t millis) diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 0a97102..811c6d3 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -185,7 +185,7 @@ ExportStanza(StanzaBuilder *builder) builder->replying_to_sender && builder->body) { - int off = ParseeFindDatastart(builder->body); + int off = ParseeFindDatastartU(builder->body); char *ostr = StrInt(off); XMLElement *reply = XMLCreateTag("reply"); XMLElement *fallback = XMLCreateTag("fallback"); diff --git a/src/Unistr.c b/src/Unistr.c index 3db7441..5eaae43 100644 --- a/src/Unistr.c +++ b/src/Unistr.c @@ -3,8 +3,10 @@ #include #include #include +#include #include +#include struct Unistr { size_t length; @@ -222,3 +224,46 @@ UnistrFilter(Unistr *str, UnistrFilterFunc filter) return unistr; } + +Unistr * +UnistrConcat(size_t n, ...) +{ + va_list list; + size_t i; + Unistr *ret = UnistrCreate(""); + + va_start(list, n); + for (i = 0; i < n; i++) + { + Unistr *to_concat = va_arg(list, Unistr *); + size_t j; + for (j = 0; j < UnistrSize(to_concat); j++) + { + UnistrAddch(ret, UnistrGetch(to_concat, j)); + } + } + + va_end(list); + return ret; +} +size_t +UnistrGetOffset(Unistr *str, uint32_t sep) +{ + size_t i; + uint32_t prev = 0x0A; + if (!str || !sep) + { + return 0; + } + + for (i = 0; i < str->length; i++) + { + uint32_t curr = str->codepoints[i]; + if (prev == 0x0A && curr != sep) + { + return i; + } + prev = curr; + } + return 0; +} diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 9237aec..1b79b77 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -9,6 +9,20 @@ #include +static void +LazyRegister(ParseeData *data, char *mxid, char *name) +{ + if (!DbExists(data->db, 2, "users", mxid)) + { + ASRegisterUser(data->config, mxid); + DbUnlock(data->db, DbCreate(data->db, 2, "users", mxid)); + } + if (name) + { + ASSetName(data->config, mxid, name); + } +} + static void ProcessChatstates(ParseeData *args, XMLElement *stanza) { @@ -211,7 +225,7 @@ end_error: HashMap *room_json; char *from = HashMapGet(stanza->attrs, "from"); - ASRegisterUser(args->config, from_matrix); + LazyRegister(args, from_matrix, NULL); room = ASCreateDM(args->config, from_matrix, to); mroom_id = StrDuplicate(room); Log(LOG_INFO, "Creating a DM to '%s'(%s)...", to, mroom_id); @@ -273,11 +287,10 @@ end_error: XMLElement *oob, *oob_data; pthread_mutex_unlock(&thr->info->chk_lock); - ASRegisterUser(args->config, encoded); - if (!chat) - { - ASSetName(args->config, encoded, res); - } + + LazyRegister(args, encoded, !chat ? res : NULL); + /* TODO: I don't think we can quite remove that. Maybe + * the user was kicked and the bridge is unaware? */ ASInvite(args->config, mroom_id, encoded); Free(ASJoin(args->config, mroom_id, encoded)); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 34077cd..efa59eb 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -286,6 +286,10 @@ extern void ParseeCleanup(void *data); /* Finds the offset of the first line without a '>' at its start. */ extern int ParseeFindDatastart(char *data); +/* Finds the offset of the first line without a '>' at its start(as + * Unicode codepoints). */ +extern int ParseeFindDatastartU(char *data); + /* XMPP-ifies a message event to XEP-0393 if possible. */ extern char * ParseeXMPPify(HashMap *event); diff --git a/src/include/Unistring.h b/src/include/Unistring.h index f1c9aee..6fbc296 100644 --- a/src/include/Unistring.h +++ b/src/include/Unistring.h @@ -39,6 +39,13 @@ extern uint32_t UnistrGetch(Unistr *unistr, size_t i); * Modifies: unistr */ extern void UnistrAddch(Unistr *unistr, uint32_t u); +/** Concats N unistrings into a new, separate unistring. + * --------------------- + * Returns: a new unistring[HEAP] + * Modifies: NOTHING + * Thrasher: UnistrFree */ +extern Unistr * UnistrConcat(size_t n, ...); + /** Encodes a unistring into a C UTF-8 string * -------------- * Returns: a valid NULL-terminated string[HEAP] | NULL @@ -64,4 +71,9 @@ typedef bool (*UnistrFilterFunc)(uint32_t u); * Returns: a new unistring with filtered characters removed */ extern Unistr * UnistrFilter(Unistr *str, UnistrFilterFunc filter); +/** Finds the offset of the first line not starting with a specific + * characters in terms of Unicode codepoints. + * -------- + * Returns: an offset of the first line to not start by {c} | 0 */ +extern size_t UnistrGetOffset(Unistr *str, uint32_t sep); #endif From dec0d1f3d95b1044ca1597281f961699d955a999 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 22 Sep 2024 11:18:41 +0200 Subject: [PATCH 090/186] [FIX/WIP] Start making Parsee go vroom --- CHANGELOG.md | 2 + src/Parsee/Data.c | 2 + src/XMPPThread/Bridged.c | 1 - src/XMPPThread/Stanzas/Message.c | 150 ++++++++++++++++++++++-------- src/XMPPThread/Stanzas/Presence.c | 4 - 5 files changed, 113 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3076eeb..0e038b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ system of Parsee. - Allows MbedTLS through a specific Cytoplasm patch. - "Lone" XMPP messages no longer render weirdly on Element Android's weird rendering. +- Start fixing bug where Parsee takes several seconds to send a +message coming from XMPP #### Deprecated features - The old `build.c` and `Makefile`s used for building are removed, and replaced by the `configure.c` C file(/script via TCC). diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index d4bf6cb..de53627 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -181,6 +181,8 @@ ParseeCleanup(void *datp) CleanupField(stanza, 30 MINUTES, 500); CleanupField(event, 30 MINUTES, 500); CleanupField(id, 30 MINUTES, 500); + + /* TODO: Also cleanup user cache information */ #undef CleanupField } DbListFree(chats); diff --git a/src/XMPPThread/Bridged.c b/src/XMPPThread/Bridged.c index 58fb571..7e047a4 100644 --- a/src/XMPPThread/Bridged.c +++ b/src/XMPPThread/Bridged.c @@ -226,7 +226,6 @@ ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force) { ParseePushOIDTable(xmpp_from, occ_id); } - Log(LOG_DEBUG, "Trying Occ ID for %s{%s}", xmpp_from, occ_id); } if (!occ_id) diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 1b79b77..32f9fa1 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -1,6 +1,7 @@ #include "XMPPThread/internal.h" #include +#include #include #include @@ -12,15 +13,58 @@ static void LazyRegister(ParseeData *data, char *mxid, char *name) { - if (!DbExists(data->db, 2, "users", mxid)) + DbRef *ref; + char *hash = ParseeHMACS(data->id, mxid); + char *dbname; + if (!(ref = DbLock(data->db, 2, "users", hash))) { ASRegisterUser(data->config, mxid); - DbUnlock(data->db, DbCreate(data->db, 2, "users", mxid)); + ref = DbCreate(data->db, 2, "users", hash); + HashMapSet(DbJson(ref), "mxid", JsonValueString(mxid)); + HashMapSet(DbJson(ref), "ts", JsonValueInteger(UtilTsMillis())); } - if (name) + dbname = GrabString(DbJson(ref), 1, "name"); + if (name && !StrEquals(dbname, name)) { ASSetName(data->config, mxid, name); + HashMapSet(DbJson(ref), "name", JsonValueString(name)); } + DbUnlock(data->db, ref); + Free(hash); +} +static char * +LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev) +{ + HashMap *duplicate; + char *event; + if (!args || !mxid || !mroom_id || !ev) + { + return NULL; + } + if (!mroom_id) + { + mroom_id = "m.room.message"; + } + + duplicate = JsonDuplicate(ev); + event = ASSend( + args->config, mroom_id, mxid, + "m.room.message", + ev + ); + if (event) + { + JsonFree(duplicate); + return event; + } + + ASInvite(args->config, mroom_id, mxid); + Free(ASJoin(args->config, mroom_id, mxid)); + + return ASSend( + args->config, mroom_id, mxid, + "m.room.message", duplicate + ); } static void @@ -79,6 +123,15 @@ ProcessChatstates(ParseeData *args, XMLElement *stanza) } #undef CHAT_STATES } +static float +TimeElapsed(uint64_t *rectime, uint64_t v) +{ + uint64_t time = UtilTsMillis(); + float t = ((time-v)/1000.f); + *rectime = time; + + return t; +} bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { @@ -97,30 +150,30 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *type = HashMapGet(stanza->attrs, "type"); bool chat = StrEquals(type, "chat"); size_t i; + uint64_t time, rectime; +#define Elapsed(v) (TimeElapsed(&rectime, v)) + to = NULL; from = NULL; decode_from = NULL; from_matrix = NULL; Log(LOG_DEBUG, " usage=%d", MemoryAllocated()); + time = UtilTsMillis(); + rectime = time; from = HashMapGet(stanza->attrs, "from"); if (ParseeManageBan(args, from, NULL)) { XMLFreeElement(stanza); - Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); + Log(LOG_DEBUG, + " time=%f " + "usage=%d (%s:%d)", + Elapsed(time), + MemoryAllocated(), __FILE__, __LINE__ + ); return false; } - /*{ - XMLElement *foo = XMLCreateTag("message"); - XMLElement *body = XMLCreateTag("body"); - XMLAddAttr(foo, "type", "chat"); - XMLAddChild(foo, body); - XMLAddChild(body, XMLCreateText("Storm on Mt. Ooe (sorry if you see this)")); - - BroadcastStanza(args, HashMapGet(stanza->attrs, "to"), foo); - XMLFreeElement(foo); - }*/ if (ServerHasXEP421(args, from)) @@ -132,13 +185,17 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *occ_id = occupant ? HashMapGet(occupant->attrs, "id") : NULL; if (occ_id) { - Log(LOG_DEBUG, - "'%s' has support for XEP-421, fetching OID=%s", - from, occ_id - ); + if (args->verbosity >= PARSEE_VERBOSE_COMICAL) + { + Log(LOG_DEBUG, + "'%s' has support for XEP-421, fetching OID=%s", + from, occ_id + ); + } ParseePushOIDTable(from, occ_id); } } + Log(LOG_DEBUG, "XEP-421: %fs", Elapsed(rectime)); if (StrEquals(type, "error")) { @@ -164,9 +221,8 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) message = StrConcat(3, type, ": ", text); room = ParseeGetBridgedRoom(args, stanza); - Free(ASSend( - args->config, room, parsee, - "m.room.message", + Free(LazySend( + args, parsee, room, NULL, MatrixCreateNotice(message) )); @@ -176,9 +232,15 @@ end_error: Free(parsee); Free(room); Free(user); - Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); + Log(LOG_DEBUG, + " time=%f " + "usage=%d (%s:%d)", + Elapsed(time), + MemoryAllocated(), __FILE__, __LINE__ + ); return false; } + Log(LOG_DEBUG, "Error management: %fs", Elapsed(rectime)); if (moderated) { @@ -206,18 +268,22 @@ end_error: body = XMLookForUnique(stanza, "body"); PEPManagerHandle(thr->info->pep_manager, stanza); + Log(LOG_DEBUG, "PEP management: %fs", Elapsed(rectime)); ProcessChatstates(args, stanza); + Log(LOG_DEBUG, "Chatstate management: %fs", Elapsed(rectime)); to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); decode_from = ParseeLookupJID(from); from_matrix = ParseeEncodeJID(args->config, decode_from, true); room = ParseeFindDMRoom(args, to, from); data = body ? ArrayGet(body->children, 0) : NULL; + Log(LOG_DEBUG, "Fetching user info: %fs", Elapsed(rectime)); /* TODO: CLEAN THAT UP INTO A CREATEDM FUNCTION */ mroom_id = ParseeGetBridgedRoom(args, stanza); Log(LOG_DEBUG, "Bridging event to '%s'...", mroom_id); + Log(LOG_DEBUG, "Fetching bridge: %fs", Elapsed(rectime)); if (!mroom_id && !room && !XMPPIsParseeStanza(stanza) && to && *to == '@') { @@ -228,7 +294,7 @@ end_error: LazyRegister(args, from_matrix, NULL); room = ASCreateDM(args->config, from_matrix, to); mroom_id = StrDuplicate(room); - Log(LOG_INFO, "Creating a DM to '%s'(%s)...", to, mroom_id); + Log(LOG_DEBUG, "Creating a DM to '%s'(%s)...", to, mroom_id); if (room) { room_ref = DbCreate(args->db, 3, "rooms", room, "data"); @@ -277,6 +343,7 @@ end_error: StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(ps); + Log(LOG_DEBUG, "Subscription to XEP-0084: %fs", Elapsed(rectime)); Free(parsee); Free(trim); @@ -289,10 +356,7 @@ end_error: pthread_mutex_unlock(&thr->info->chk_lock); LazyRegister(args, encoded, !chat ? res : NULL); - /* TODO: I don't think we can quite remove that. Maybe - * the user was kicked and the bridge is unaware? */ - ASInvite(args->config, mroom_id, encoded); - Free(ASJoin(args->config, mroom_id, encoded)); + Log(LOG_DEBUG, "Matrix registration: %fs", Elapsed(rectime)); reactions = XMLookForTKV(stanza, "reactions", "xmlns", "urn:xmpp:reactions:0" @@ -322,9 +386,9 @@ end_error: ); ShoveStanza(content, stanza); - event_id = ASSend( - args->config, mroom_id, encoded, - "m.room.message", content + event_id = LazySend( + args, encoded, mroom_id, NULL, + content ); Free(mxc); } @@ -364,14 +428,13 @@ end_error: reaction = ArrayGet(react_child, i); react_data = ArrayGet(reaction->children, 0); - Free(ASSend( - args->config, mroom_id, encoded, - "m.reaction", + event_id = LazySend( + args, encoded, mroom_id, "m.reaction", ShoveStanza( MatrixCreateReact(event_id, react_data->data), stanza ) - )); + ); } Free(event_id); event_id = NULL; @@ -401,9 +464,9 @@ end_error: Free(reply_id); } ShoveStanza(ev, stanza); - event_id = ASSend( - args->config, mroom_id, encoded, - "m.room.message", ev + event_id = LazySend( + args, encoded, mroom_id, NULL, + ev ); } pthread_mutex_lock(&thr->info->chk_lock); @@ -424,9 +487,9 @@ end_error: ); Log(LOG_DEBUG, "Replacing events in %s(%s)", mroom_id, event_id); - Free(ASSend( - args->config, mroom_id, encoded, - "m.room.message", ev + Free(LazySend( + args, encoded, mroom_id, NULL, + ev )); ParseePushAllStanza(args, stanza, event_id); pthread_mutex_unlock(&thr->info->chk_lock); @@ -459,7 +522,12 @@ end: Free(decode_from); Free(room); Free(to); - Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); + Log(LOG_DEBUG, + " time=%f " + "usage=%d (%s:%d)", + (UtilTsMillis()-time)/1000.f, + MemoryAllocated(), __FILE__, __LINE__ + ); return true; } diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 8323f6a..174a916 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -89,10 +89,6 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *occ_id = occupant ? HashMapGet(occupant->attrs, "id") : NULL; if (occ_id) { - Log(LOG_DEBUG, - "'%s' has support for XEP-421, fetching OID=%s", - oid, occ_id - ); ParseePushOIDTable(oid, occ_id); } } From 63285ac24a3985387ad44f873b9e26d662006090 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 22 Sep 2024 15:13:12 +0200 Subject: [PATCH 091/186] [FIX] Fix a very silly mistake --- src/XMPPThread/Stanzas/Message.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 32f9fa1..a442db8 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -41,15 +41,15 @@ LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev) { return NULL; } - if (!mroom_id) + if (!type) { - mroom_id = "m.room.message"; + type = "m.room.message"; } duplicate = JsonDuplicate(ev); event = ASSend( args->config, mroom_id, mxid, - "m.room.message", + type, ev ); if (event) @@ -63,7 +63,7 @@ LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev) return ASSend( args->config, mroom_id, mxid, - "m.room.message", duplicate + type, duplicate ); } From 2324f9afc0b82a032100d96de65832863b49d076 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 22 Sep 2024 18:36:53 +0200 Subject: [PATCH 092/186] [MOD/META] Clarify LICENSE more, fix chatstates --- CHANGELOG.md | 25 ++++++++++++++--------- LICENSE | 2 +- src/AS/Indicators.c | 5 +++-- src/XMPPThread/Stanzas/Message.c | 34 +++++++++++++++++++++++++++----- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e038b1..ea26c72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Dates are to be written as DD/MM/YYYY. Please update the changelog as you go, no one wants to keep track of every commit done between releases. +## Release +*There is currently no full releases of Parsee* + +## Beta +*There is currently no beta releases of Parsee* + ## Alpha ### v0.1.0[tomboyish-bridges-adventure] <9/9/2024> Nothing much to say, but this is the first alpha release @@ -18,18 +24,19 @@ of Parsee. May occasionally deadlock. *NONE* ### v0.1.1[star-of-hope] -Fixes some media metadata things, and replaces the build -system of Parsee. +Fixes some media metadata things, replaces the build system, +and speeds up Parsee a tad bit. #### New things - Start dealing with some basic PEP-based avatars. -#### Bugfixes -- Adds more information to media events so that clients can behave. -- Fixes issues where SIGPIPE can actually just kill Parsee. - Allows MbedTLS through a specific Cytoplasm patch. -- "Lone" XMPP messages no longer render weirdly on Element Android's -weird rendering. -- Start fixing bug where Parsee takes several seconds to send a -message coming from XMPP +#### Bugfixes +- Adds more information to media events so that clients can +behave. +- Fixes issues where SIGPIPE can actually just kill Parsee. +- "Lone" XMPP messages no longer render weirdly on Element +Android's weird rendering. +- Start fixing bug where Parsee takes several seconds to send +a message coming from XMPP #### Deprecated features - The old `build.c` and `Makefile`s used for building are removed, and replaced by the `configure.c` C file(/script via TCC). diff --git a/LICENSE b/LICENSE index ce865e6..cb9aa73 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ For the files src/include/Unistring.h, src/Unistr.h rc/Parsee/HMAC.c, src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, see COPYING.CC0. -For any other file in src/, see COPYING.AGPL as the primary license. +For any other file in src/, see COPYING.AGPL as the primary license(AGPL-3.0-or-later) As Parsee depends on Cytoplasm, its license is left here in COPYING.CYTO diff --git a/src/AS/Indicators.c b/src/AS/Indicators.c index afe860a..9797649 100644 --- a/src/AS/Indicators.c +++ b/src/AS/Indicators.c @@ -30,8 +30,9 @@ ASType(const ParseeConfig *c, char *user, char *room, bool status) 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)); + /* If someone types for 5 minutes straight, they got something + * weird man. */ + HashMapSet(json, "timeout", JsonValueInteger(5 MINUTES)); ctx = ParseeCreateRequest(c, HTTP_PUT, path); Free(path); ASAuthenticateRequest(c, ctx); diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index a442db8..d477d8e 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -20,14 +20,22 @@ LazyRegister(ParseeData *data, char *mxid, char *name) { ASRegisterUser(data->config, mxid); ref = DbCreate(data->db, 2, "users", hash); - HashMapSet(DbJson(ref), "mxid", JsonValueString(mxid)); - HashMapSet(DbJson(ref), "ts", JsonValueInteger(UtilTsMillis())); + if (ref) + { + HashMapSet(DbJson(ref), "mxid", JsonValueString(mxid)); + HashMapSet(DbJson(ref), + "ts", JsonValueInteger(UtilTsMillis()) + ); + } } dbname = GrabString(DbJson(ref), 1, "name"); if (name && !StrEquals(dbname, name)) { ASSetName(data->config, mxid, name); - HashMapSet(DbJson(ref), "name", JsonValueString(name)); + if (ref) + { + HashMapSet(DbJson(ref), "name", JsonValueString(name)); + } } DbUnlock(data->db, ref); Free(hash); @@ -101,8 +109,24 @@ ProcessChatstates(ParseeData *args, XMLElement *stanza) mroom_id = NULL; from_matrix = NULL; } - if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES) || - XMLookForTKV(stanza, "received", "xmlns", "urn:xmpp:receipts") || + if (XMLookForTKV(stanza, "paused", "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, "received", "xmlns", "urn:xmpp:receipts") || XMLookForTKV(stanza, "displayed", "xmlns", "urn:xmpp:chat-markers:0")) { /* TODO: Use stanza ID if possible */ From 0f3253a3856f070516eaf0e8cfe0a0eabe09c353 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 24 Sep 2024 07:08:25 +0200 Subject: [PATCH 093/186] [FIX] Fix unfreed value on renames --- src/Parsee/Utils/Formatting.c | 2 ++ src/XMPPThread/Stanzas/Message.c | 16 +++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 4e89aec..77a3d9b 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -151,6 +151,8 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) else if (StrEquals(elem->name, "a")) { char *href = HashMapGet(elem->attrs, "href"); + /* TODO: Check if the element here is a Matrix.TO + * pointing to a Parsee user. */ Concat("("); for (i = 0; i < ArraySize(elem->children); i++) { diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index d477d8e..cbec486 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -34,7 +34,9 @@ LazyRegister(ParseeData *data, char *mxid, char *name) ASSetName(data->config, mxid, name); if (ref) { - HashMapSet(DbJson(ref), "name", JsonValueString(name)); + JsonValueFree(HashMapSet( + DbJson(ref), "name", JsonValueString(name) + )); } } DbUnlock(data->db, ref); @@ -109,7 +111,8 @@ ProcessChatstates(ParseeData *args, XMLElement *stanza) mroom_id = NULL; from_matrix = NULL; } - if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES)) + if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES) || + XMLookForTKV(stanza, "inactive", "xmlns", CHAT_STATES)) { char *latest = NULL; from_matrix = ParseeGetBridgedUser(args, stanza); @@ -147,6 +150,7 @@ ProcessChatstates(ParseeData *args, XMLElement *stanza) } #undef CHAT_STATES } + static float TimeElapsed(uint64_t *rectime, uint64_t v) { @@ -294,9 +298,6 @@ end_error: PEPManagerHandle(thr->info->pep_manager, stanza); Log(LOG_DEBUG, "PEP management: %fs", Elapsed(rectime)); - ProcessChatstates(args, stanza); - Log(LOG_DEBUG, "Chatstate management: %fs", Elapsed(rectime)); - to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); decode_from = ParseeLookupJID(from); from_matrix = ParseeEncodeJID(args->config, decode_from, true); @@ -318,7 +319,6 @@ end_error: LazyRegister(args, from_matrix, NULL); room = ASCreateDM(args->config, from_matrix, to); mroom_id = StrDuplicate(room); - Log(LOG_DEBUG, "Creating a DM to '%s'(%s)...", to, mroom_id); if (room) { room_ref = DbCreate(args->db, 3, "rooms", room, "data"); @@ -403,7 +403,6 @@ end_error: { content = MatrixCreateMedia(mxc, data->data, mime); - /* Yeah, no, I'm not modifying the media creation code. */ HashMapSet(content, "at.kappach.at.parsee.external", JsonValueString(oob_data->data) @@ -539,6 +538,9 @@ end_error: } } + ProcessChatstates(args, stanza); + Log(LOG_DEBUG, "Chatstate management: %fs", Elapsed(rectime)); + end: Free(mroom_id); mroom_id = NULL; From 749df0feb1f0538ebe89f60d7d4979ff688efd05 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 25 Sep 2024 22:09:11 +0200 Subject: [PATCH 094/186] [ADD/WIP] Basic support for opting-out of bridging --- src/MatrixEventHandler.c | 1 + src/XMPPThread/Stanzas/Presence.c | 36 +++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 73feda5..fdb7b7b 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -416,6 +416,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) goto end; } + /* TODO: Avoid using the AS endpoints */ name = ASGetName(data->config, id, m_sender); Free(JoinMUC(data, event, encoded_from, muc_id, name)); diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 174a916..b2ae52a 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -109,6 +109,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *role = HashMapGet(item->attrs, "role"); int power_level = 0; char *parsee = ParseeMXID(args); + char *parsee_j = ParseeJID(args); Free(trim); @@ -144,8 +145,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (StrEquals(role, "visitor")) { - char *parsee = ParseeJID(args); - if (!StrEquals(HashMapGet(stanza->attrs, "to"), parsee) && + if (!StrEquals(HashMapGet(stanza->attrs, "to"), parsee_j) && IsStatus(110)) { char *muc = ParseeTrimJID(HashMapGet(stanza->attrs, "from")); @@ -158,8 +158,6 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) Free(muc); } - - Free(parsee); } /* Set the user's PL @@ -213,12 +211,42 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ASLeave(args->config, room, real_matrix); } } + if (StrEquals(type, "unavailable") && + StrEquals(dst, parsee_j) && + (IsStatus(301) || IsStatus(307))) + { + char *chat_id = ParseeGetFromRoomID(args, room); + char *muc = ParseeTrimJID(oid); + DbRef *ref; + + ref = DbLock(args->db, 1, "chats"); + JsonValueFree(HashMapDelete( + GrabObject(DbJson(ref), 1, "rooms"), + room + )); + JsonValueFree(HashMapDelete( + GrabObject(DbJson(ref), 1, "mucs"), + muc + )); + DbUnlock(args->db, ref); + DbDelete(args->db, 2, "chats", chat_id); + + Free(ASSend( + args->config, room, parsee, + "m.room.message", + MatrixCreateNotice("This room has been unlinked.") + )); + ASLeave(args->config, room, parsee); + Free(chat_id); + Free(muc); + } Free(from); Free(decode_from); Free(real_matrix); Free(matrix_user_pl); + Free(parsee_j); Free(parsee); Free(room); } From e7ba1fa48d87b92c970b32c1a8cec322e8911088 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 26 Sep 2024 11:11:39 +0200 Subject: [PATCH 095/186] [MOD] Separate the unlink in another function --- src/Parsee/Chats.c | 39 +++++++++++++++++++++++++++++++ src/XMPPThread/Stanzas/Presence.c | 15 +----------- src/include/Parsee.h | 9 ++++++- 3 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 src/Parsee/Chats.c diff --git a/src/Parsee/Chats.c b/src/Parsee/Chats.c new file mode 100644 index 0000000..6207b05 --- /dev/null +++ b/src/Parsee/Chats.c @@ -0,0 +1,39 @@ +#include + +#include +#include + +void +ParseeUnlinkRoom(ParseeData *data, char *chat_id) +{ + char *muc, *room; + DbRef *ref; + if (!data || !chat_id) + { + return; + } + + muc = ParseeGetMUCID(data, chat_id); + room = ParseeGetRoomID(data, chat_id); + if (!muc || !room) + { + Free(muc); + Free(room); + return; + } + + ref = DbLock(data->db, 1, "chats"); + JsonValueFree(HashMapDelete( + GrabObject(DbJson(ref), 1, "rooms"), + room + )); + JsonValueFree(HashMapDelete( + GrabObject(DbJson(ref), 1, "mucs"), + muc + )); + DbUnlock(data->db, ref); + DbDelete(data->db, 2, "chats", chat_id); + + Free(muc); + Free(room); +} diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index b2ae52a..89448b6 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -216,20 +216,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) (IsStatus(301) || IsStatus(307))) { char *chat_id = ParseeGetFromRoomID(args, room); - char *muc = ParseeTrimJID(oid); - DbRef *ref; - ref = DbLock(args->db, 1, "chats"); - JsonValueFree(HashMapDelete( - GrabObject(DbJson(ref), 1, "rooms"), - room - )); - JsonValueFree(HashMapDelete( - GrabObject(DbJson(ref), 1, "mucs"), - muc - )); - DbUnlock(args->db, ref); - DbDelete(args->db, 2, "chats", chat_id); + ParseeUnlinkRoom(args, chat_id); Free(ASSend( args->config, room, parsee, @@ -238,7 +226,6 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) )); ASLeave(args->config, room, parsee); Free(chat_id); - Free(muc); } diff --git a/src/include/Parsee.h b/src/include/Parsee.h index efa59eb..d0e3f1c 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -344,7 +344,8 @@ extern bool ParseeManageBan(ParseeData *, char *user, char *room); extern bool ParseeVerifyDMStanza(ParseeData *data, char *room_id, char *id); -/** Checks if a Matrix/XMPP user is considered as "administrator" by Parsee. +/** Checks if a Matrix/XMPP user is considered as "administrator" by + * Parsee. * ---------------------- * Returns: (whenever the user is an admin) * Modifies: NOTHING */ @@ -411,4 +412,10 @@ extern char * ParseeHMAC(char *key, uint8_t *msg, size_t msglen); * Returns: NOTHING */ extern void ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *s); +/** Destroys the mapping between a MUC and a room from a chat ID. + * ---------------- + * Modifies: the DB's room mappings + * Returns: NOTHING */ +extern void ParseeUnlinkRoom(ParseeData *data, char *chat_id); + #endif From 3ceae7b053bc31c97f778de5b336d1d0891aa3e7 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 26 Sep 2024 19:07:46 +0200 Subject: [PATCH 096/186] I honestly don't know what to call it. It's not a 0.2 release, btw. --- CHANGELOG.md | 4 ++- README.MD | 6 ++-- XEPS-TBD.TXT | 15 +++++---- build.conf | 1 + etc/man/man7/parsee-cmd-syntax.7 | 50 ++++++++++++++++++++++++++++++ src/Command/Parser.c | 2 +- src/Commands/BanUser.c | 6 ++-- src/Commands/UnlinkMUC.c | 53 +++++++++++++++++++++----------- src/Main.c | 7 ++++- src/Parsee/Chats.c | 39 ----------------------- src/Parsee/Data.c | 35 +++++++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 40 +++++++++++++++++++----- src/include/Parsee.h | 6 ++-- 13 files changed, 179 insertions(+), 85 deletions(-) create mode 100644 etc/man/man7/parsee-cmd-syntax.7 delete mode 100644 src/Parsee/Chats.c diff --git a/CHANGELOG.md b/CHANGELOG.md index ea26c72..2092d1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,12 +23,14 @@ of Parsee. May occasionally deadlock. #### Deprecated features *NONE* -### v0.1.1[star-of-hope] +### v0.2.0[star-of-hope] Fixes some media metadata things, replaces the build system, and speeds up Parsee a tad bit. #### New things - Start dealing with some basic PEP-based avatars. - Allows MbedTLS through a specific Cytoplasm patch. +- Kicking/Banning Parsee from XMPP effectively unlinks it. +- Start adding documentation to Parsee; #### Bugfixes - Adds more information to media events so that clients can behave. diff --git a/README.MD b/README.MD index 0467280..2955984 100644 --- a/README.MD +++ b/README.MD @@ -71,9 +71,7 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th (see `etc/man`). ## TODOS before 1.0 rolls around -- Make Parsee go *vroooooooooommmmmmm*, by NOT asking the server constantly -about what is available and what is not, as that is a source of latency, and -thus slowdowns. +- Make Parsee actually go *vroooooooooommmmmmm*. - PROPER FUCKING VCARD AVATARS XMPP->Matrix is decent, Matrix->XMPP is effectively a WIP - Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency. @@ -93,6 +91,8 @@ restricted to Parsee admins, with permission from MUC owners, too - Limiting to admins may be a way to "control" consent for both, but this is only if Parsee admins are good-willed, which we must assume such statment to be false by default. + - Currently, MUC owners may kick Parsee out, with the effect of unlinking the + MUC. - Look at XEPS-TBD.TXT for XEPs to be done - Add a MUC server to Parsee, such that it may be able to hook onto it and therefore support XMPP->Matrix bridging. diff --git a/XEPS-TBD.TXT b/XEPS-TBD.TXT index ae74f4f..9ed28cf 100644 --- a/XEPS-TBD.TXT +++ b/XEPS-TBD.TXT @@ -21,10 +21,14 @@ Somewhat implemented XEPs: This allows reactions, which Matrix also has support to. The two systems don't seem *too* restrictive on one-another (unlike some IM platforms I won't mention), so this doesn't sound too bad to do - HALF-IMPLEMENTED: Removing reacts won't work. + TODO: Add support from Matrix. ~ https://xmpp.org/extensions/xep-0184.html Only Matrix->XMPP as of now. Requesting data from Matrix ASes without /sync seems like a non-option as of now, which _sucks_. + ~ https://xmpp.org/extensions/xep-0084.html + Avatar support would be extremely useful, if just a QoL improvment. + Matrix and XMPP both have support for these. + XEP-0084 is a pain in the ass to implement and seems generally just For future XEPs: - https://xmpp.org/extensions/xep-0449.html @@ -34,12 +38,7 @@ For future XEPs: which is used along PEP, it seems, and meanwhile Matrix has ''support'' for packs too, tracking them is between "annoyance" and "yeah, no.". -ON STANDBY BECAUSE THESE HAVE BEEN TERRIBLE TO DEAL WITH AND WHO KEEPS WRITING -THESE I WANT TO SEND THEM A NICE, BRIGHT GIFT: - x https://xmpp.org/extensions/xep-0084.html - Avatar support would be extremely useful, if just a QoL improvment. - Matrix and XMPP both have support for these. - XEP-0084 is a pain in the ass to implement and seems generally just +On Standby: unreliable, however. x https://xmpp.org/extensions/xep-0080.html Can't think of a good analogy to these... @@ -48,7 +47,7 @@ THESE I WANT TO SEND THEM A NICE, BRIGHT GIFT: Not XEPs, but ideas that _needs_ to be added: ~ "GIVE THE PUPPETS APPROPRIATE PLS/ROLES" - Hydro/t4d Happens on Matrix. I'll need to handle that on XMPP as well. - - Standalone/Static Parsee, ideally as small as it can be(if not as APE). + ~ Standalone/Static Parsee, ideally as small as it can be(if not as APE). - Kappa-like extension system(maybe bridging more than just Matrix-XMPP.) - https://www.youtube.com/watch?v=InL414iDZmY diff --git a/build.conf b/build.conf index ebc5276..3e06176 100644 --- a/build.conf +++ b/build.conf @@ -7,3 +7,4 @@ INCLUDES=src/include OBJECT=build CC=cc CFLAGS=-O3 +PREFIX=/usr diff --git a/etc/man/man7/parsee-cmd-syntax.7 b/etc/man/man7/parsee-cmd-syntax.7 new file mode 100644 index 0000000..ba11e67 --- /dev/null +++ b/etc/man/man7/parsee-cmd-syntax.7 @@ -0,0 +1,50 @@ +." The last field is the codename, by the way. +." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN +.TH parsee-cmd-syntax 7 "Parsee Utility" "star-of-hope" + +.SH NAME +parsee-cmd-syntax - Basic syntax information with Parsee Matrix commands + +.SH DESCRIPTION +Parsee uses a specific syntax for commands, which is generally different +from regular bots, but closer to +.B dd(1) 's +syntax. +.PP +A command is formatted as so. +.sp +.if n \{\ +.RS 4 +.\} +.nf +.B ![NAME] arg1=val1 arg2='val2' arg3="val\(rs\(dq3" +.fi +.if n \{\ +.RE +.\} +.sp + +.PP +The +.B arg1=val1 +syntax is to be used for simple values, with values containing no spaces. + +.PP +The +.B NAME +attribute defines the command to be called, and the +.B arg1='val1' , +and +.B arg2="val2" +syntax is to be used for simple values, with values containing spaces. If +the value needs to contain quotes, they may be escaped with +.B \(rs' +and +.B \(rs" +respectively. + +.SH LICENSE +This document is under public domain, or CC0 if not allowed by local law. + +.SH SEE ALSO +.B parsee(1) diff --git a/src/Command/Parser.c b/src/Command/Parser.c index 2101254..fea5007 100644 --- a/src/Command/Parser.c +++ b/src/Command/Parser.c @@ -25,7 +25,7 @@ CommandParse(char *cmd) } end_data = strchr(cmd, ' '); - if (!end_data) + if (!end_data || (cmd > end_data)) { ret = Malloc(sizeof(*ret)); ret->command = StrDuplicate(cmd); diff --git a/src/Commands/BanUser.c b/src/Commands/BanUser.c index 6e42356..adc505e 100644 --- a/src/Commands/BanUser.c +++ b/src/Commands/BanUser.c @@ -22,11 +22,9 @@ CommandHead(CmdBanUser, cmd, argp) BotDestroy(); return; } - ASBan(data->config, room, user); - ReplySprintf("Banning %s from '%s'...", - user, room - ); + ASBan(data->config, room, user); + ReplySprintf("Banning %s from '%s'...", user, room); BotDestroy(); } diff --git a/src/Commands/UnlinkMUC.c b/src/Commands/UnlinkMUC.c index 3e2ae81..2a94b92 100644 --- a/src/Commands/UnlinkMUC.c +++ b/src/Commands/UnlinkMUC.c @@ -9,43 +9,60 @@ #include +static bool +Grab(ParseeData *data, Command *cmd, char **muc, char **chat_id, char **room) +{ + if (HashMapGet(cmd->arguments, "muc")) + { + *muc = HashMapGet(cmd->arguments, "muc"); + + *chat_id = ParseeGetFromMUCID(data, *muc); + *room = ParseeGetRoomID(data, *chat_id); + if (!chat_id || !room) + { + return false; + } + return true; + } + else if (HashMapGet(cmd->arguments, "room")) + { + *room = HashMapGet(cmd->arguments, "room"); + + *chat_id = ParseeGetFromRoomID(data, *room); + *muc = ParseeGetMUCID(data, *chat_id); + if (!chat_id || !muc) + { + return false; + } + return true; + } + return false; +} + CommandHead(CmdUnlinkMUC, cmd, argp) { ParseeCmdArg *args = argp; ParseeData *data = args->data; HashMap *json, *event = args->event, *mucs; - DbRef *ref; char *muc = NULL, *chat_id = NULL, *room = NULL; BotInitialise(); - muc = HashMapGet(cmd->arguments, "muc"); - if (!muc) + if (!Grab(data, cmd, &muc, &chat_id, &room)) { - ReplyBasic("`muc` field REQUIRED."); + ReplyBasic("`muc`|`room` REQUIRED"); goto end; } - ref = DbLock(data->db, 1, "chats"); - json = DbJson(ref); - chat_id = StrDuplicate(GrabString(json, 2, "mucs", muc)); + chat_id = ParseeGetFromMUCID(data, muc); + room = ParseeGetRoomID(data, chat_id); if (!chat_id) { ReplySprintf("No internal mapping to '%s'.", muc); goto end; } - mucs = GrabObject(json, 1, "mucs"); - JsonValueFree(HashMapDelete(mucs, muc)); - DbUnlock(data->db, ref); - room = ParseeGetRoomID(data, chat_id); - ref = DbLock(data->db, 1, "chats"); - json = DbJson(ref); - mucs = GrabObject(json, 1, "rooms"); - JsonValueFree(HashMapDelete(mucs, room)); - DbUnlock(data->db, ref); - - DbDelete(data->db, 2, "chats", chat_id); + ParseeUnlinkRoom(data, chat_id); /* TODO: Do it automatically, if *not plumbed* */ ReplySprintf("The MUC %s is now *unlinked*.", muc); diff --git a/src/Main.c b/src/Main.c index 988894f..7f01258 100644 --- a/src/Main.c +++ b/src/Main.c @@ -47,7 +47,7 @@ static const Argument arguments[] = "Generates a parsee.yaml AS file before exiting") Arg('v', false, NULL, "Forces Parsee to print in a more verbose fashion " - "(-vv prints stanzas to stderr)") + "(-vvv prints stanzas to stderr)") Arg('h', false, NULL, "Generates an help screen(this one!)") @@ -116,6 +116,9 @@ Main(Array *args, HashMap *env) case PARSEE_VERBOSE_LOG: LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG); break; + case PARSEE_VERBOSE_TIMINGS: + Log(LOG_DEBUG, "Logging bench information."); + break; case PARSEE_VERBOSE_STANZA: Log(LOG_DEBUG, "Enabling stanza printing."); break; @@ -226,6 +229,8 @@ Main(Array *args, HashMap *env) if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart)) { char *parsee = ParseeMXID(conf.handlerArgs); + + /* TODO: An hardcoded avatar like this sucks. */ ASSetAvatar(parsee_conf, parsee, "mxc://tedomum.net/" diff --git a/src/Parsee/Chats.c b/src/Parsee/Chats.c deleted file mode 100644 index 6207b05..0000000 --- a/src/Parsee/Chats.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include -#include - -void -ParseeUnlinkRoom(ParseeData *data, char *chat_id) -{ - char *muc, *room; - DbRef *ref; - if (!data || !chat_id) - { - return; - } - - muc = ParseeGetMUCID(data, chat_id); - room = ParseeGetRoomID(data, chat_id); - if (!muc || !room) - { - Free(muc); - Free(room); - return; - } - - ref = DbLock(data->db, 1, "chats"); - JsonValueFree(HashMapDelete( - GrabObject(DbJson(ref), 1, "rooms"), - room - )); - JsonValueFree(HashMapDelete( - GrabObject(DbJson(ref), 1, "mucs"), - muc - )); - DbUnlock(data->db, ref); - DbDelete(data->db, 2, "chats", chat_id); - - Free(muc); - Free(room); -} diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index de53627..0db1436 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -538,3 +538,38 @@ end: return ret; } + +void +ParseeUnlinkRoom(ParseeData *data, char *chat_id) +{ + char *muc, *room; + DbRef *ref; + if (!data || !chat_id) + { + return; + } + + muc = ParseeGetMUCID(data, chat_id); + room = ParseeGetRoomID(data, chat_id); + if (!muc || !room) + { + Free(muc); + Free(room); + return; + } + + ref = DbLock(data->db, 1, "chats"); + JsonValueFree(HashMapDelete( + GrabObject(DbJson(ref), 1, "rooms"), + room + )); + JsonValueFree(HashMapDelete( + GrabObject(DbJson(ref), 1, "mucs"), + muc + )); + DbUnlock(data->db, ref); + DbDelete(data->db, 2, "chats", chat_id); + + Free(muc); + Free(room); +} diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index cbec486..ae5f345 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -223,7 +223,10 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ParseePushOIDTable(from, occ_id); } } - Log(LOG_DEBUG, "XEP-421: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "XEP-421: %fs", Elapsed(rectime)); + } if (StrEquals(type, "error")) { @@ -268,7 +271,10 @@ end_error: ); return false; } - Log(LOG_DEBUG, "Error management: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "Error management: %fs", Elapsed(rectime)); + } if (moderated) { @@ -296,19 +302,28 @@ end_error: body = XMLookForUnique(stanza, "body"); PEPManagerHandle(thr->info->pep_manager, stanza); - Log(LOG_DEBUG, "PEP management: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "PEP management: %fs", Elapsed(rectime)); + } to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); decode_from = ParseeLookupJID(from); from_matrix = ParseeEncodeJID(args->config, decode_from, true); room = ParseeFindDMRoom(args, to, from); data = body ? ArrayGet(body->children, 0) : NULL; - Log(LOG_DEBUG, "Fetching user info: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "Fetching user info: %fs", Elapsed(rectime)); + } /* TODO: CLEAN THAT UP INTO A CREATEDM FUNCTION */ mroom_id = ParseeGetBridgedRoom(args, stanza); Log(LOG_DEBUG, "Bridging event to '%s'...", mroom_id); - Log(LOG_DEBUG, "Fetching bridge: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "Fetching bridge: %fs", Elapsed(rectime)); + } if (!mroom_id && !room && !XMPPIsParseeStanza(stanza) && to && *to == '@') { @@ -367,7 +382,10 @@ end_error: StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(ps); - Log(LOG_DEBUG, "Subscription to XEP-0084: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "Subscription to XEP-0084: %fs", Elapsed(rectime)); + } Free(parsee); Free(trim); @@ -380,7 +398,10 @@ end_error: pthread_mutex_unlock(&thr->info->chk_lock); LazyRegister(args, encoded, !chat ? res : NULL); - Log(LOG_DEBUG, "Matrix registration: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "Matrix registration: %fs", Elapsed(rectime)); + } reactions = XMLookForTKV(stanza, "reactions", "xmlns", "urn:xmpp:reactions:0" @@ -539,7 +560,10 @@ end_error: } ProcessChatstates(args, stanza); - Log(LOG_DEBUG, "Chatstate management: %fs", Elapsed(rectime)); + if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + { + Log(LOG_DEBUG, "Chatstate management: %fs", Elapsed(rectime)); + } end: Free(mroom_id); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index d0e3f1c..1873dae 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -20,7 +20,8 @@ typedef struct ParseeData ParseeData; #define PARSEE_VERBOSE_NONE 0 #define PARSEE_VERBOSE_LOG 1 -#define PARSEE_VERBOSE_STANZA 2 +#define PARSEE_VERBOSE_TIMINGS 2 +#define PARSEE_VERBOSE_STANZA 3 #define PARSEE_VERBOSE_COMICAL 53 /* MINUTES */ typedef struct ParseeConfig { @@ -100,7 +101,8 @@ typedef struct Argument { /* A base64-encoded Parsee logo */ extern const char media_parsee_logo[]; -/* An ASCII-art rendition of "小橋" */ +/* An ASCII-art rendition of "小橋". + * I'm sorry for its quality. If anyone wants to redraw it, feel free. */ #define PARSEE_ASCII_LINES 8 extern const char *parsee_ascii[PARSEE_ASCII_LINES]; From af2d08a4311ca1bd211b088cf825e811194b39e5 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 28 Sep 2024 13:24:38 +0200 Subject: [PATCH 097/186] [ADD/WIP] Start introducing whitelist command The whitelist system will also be managable from XMPP and Matrix, and will be for MUC/room management. --- tools/whitelist.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tools/whitelist.c diff --git a/tools/whitelist.c b/tools/whitelist.c new file mode 100644 index 0000000..e1348d5 --- /dev/null +++ b/tools/whitelist.c @@ -0,0 +1,114 @@ +/* whitelist.c - Manages a Parsee MUC/user whitelist manually + * ============================================================ + * Example of usage: + * parsee-whitelist [CONFIG] [add|del|remove|list] + * Under CC0, as its a rather useful example of a Parsee tool. + * See LICENSE for more information about Parsee's licensing. */ + +#include "common.h" + +#include + +int +Main(Array *args, HashMap *env) +{ + int ret = EXIT_SUCCESS; + char *verb; + Db *db; + if (ArraySize(args) <= 2) + { + Log(LOG_ERR, + "Usage: %s [CONFIG] [add|del|clear|list] ", + ArrayGet(args, 0) + ); + return EXIT_FAILURE; + } + + if (!(db = GetDB(ArrayGet(args, 1)))) + { + Log(LOG_ERR, "Couldn't load database"); + ret = EXIT_FAILURE; + goto end; + } + + verb = ArrayGet(args, 2); + if (StrEquals(verb, "add")) + { + char *user = ArrayGet(args, 3); + DbRef *ref = !user ? NULL : DbLock( + db, 1, "whitelist" + ); + if (!ref && user) + { + ref = DbCreate( + db, 1, "whitelist" + ); + } + + if (!user) + { + ret = EXIT_FAILURE; + goto end; + } + JsonValueFree(HashMapSet( + DbJson(ref), + user, JsonValueObject(HashMapCreate()) + )); + DbUnlock(db, ref); + } + else if (StrEquals(verb, "del")) + { + char *user = ArrayGet(args, 3); + DbRef *ref = !user ? NULL : DbLock( + db, 1, "whitelist" + ); + if (!ref && user) + { + ref = DbCreate( + db, 1, "whitelist" + ); + } + + if (!user) + { + ret = EXIT_FAILURE; + goto end; + } + JsonValueFree(HashMapDelete(DbJson(ref), user)); + DbUnlock(db, ref); + } + else if (StrEquals(verb, "clear")) + { + DbDelete(db, 1, "whitelist"); + } + else if (StrEquals(verb, "list")) + { + DbRef *ref = DbLockIntent( + db, DB_HINT_READONLY, + 1, "whitelist" + ); + Array *keys = HashMapKeys(DbJson(ref)); + size_t i; + + for (i = 0; i < ArraySize(keys); i++) + { + char *key = ArrayGet(keys, i); + + Log(LOG_INFO, "- %s", key); + } + + + ArrayFree(keys); + DbUnlock(db, ref); + } + else + { + ret = EXIT_FAILURE; + goto end; + } + +end: + (void) env; + DbClose(db); + return ret; +} From 0b00a665bfe20c6a27b06ab67b09e29a85faf341 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 28 Sep 2024 15:58:41 +0200 Subject: [PATCH 098/186] [ADD] MUC whitelists, part II --- CHANGELOG.md | 4 +++- src/Commands/Plumb.c | 3 ++- src/Parsee/Data.c | 35 +++++++++++++++++++++++++++++++++++ src/Routes/UserAck.c | 3 ++- src/include/Parsee.h | 6 ++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2092d1f..b95b8f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,9 @@ and speeds up Parsee a tad bit. - Start dealing with some basic PEP-based avatars. - Allows MbedTLS through a specific Cytoplasm patch. - Kicking/Banning Parsee from XMPP effectively unlinks it. -- Start adding documentation to Parsee; +- Start adding documentation to Parsee +- Add MUC whitelists for plumbing, alongside a `whitelist` tool + #### Bugfixes - Adds more information to media events so that clients can behave. diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index e3c4ff3..8d94dfc 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -24,7 +24,8 @@ CommandHead(CmdPlumb, cmd, argp) BotRequired(room); /* Check MUC viability */ - if (ParseeManageBan(args->data, muc, NULL)) + if (ParseeManageBan(args->data, muc, NULL) || + ParseeIsMUCWhitelisted(args->data, muc)) { ReplySprintf("MUC '%s' is not allowed on this bridge.", muc); goto end; diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 0db1436..87b2263 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -573,3 +574,37 @@ ParseeUnlinkRoom(ParseeData *data, char *chat_id) Free(muc); Free(room); } +bool +ParseeIsMUCWhitelisted(ParseeData *data, char *muc) +{ + char *server, *serv_start; + DbRef *ref; + bool ret; + if (!data || !muc) + { + return false; + } + + if (!DbExists(data->db, 1, "whitelist")) + { + return true; + } + + serv_start = strchr(muc, '@'); + serv_start = serv_start ? serv_start : muc; + server = StrDuplicate(serv_start + 1); + if (strchr(server, '/')) + { + *(strchr(server, '/')) = '\0'; + } + + ref = DbLockIntent(data->db, + DB_HINT_READONLY, + 1, "whitelist" + ); + ret = HashMapGet(DbJson(ref), server); + DbUnlock(data->db, ref); + Free(server); + + return ret; +} diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c index 9bb17e2..828be65 100644 --- a/src/Routes/UserAck.c +++ b/src/Routes/UserAck.c @@ -67,7 +67,8 @@ RouteHead(RouteRoomAck, arr, argp) } muc = ParseeDecodeLocalMUC(args->data->config, room); - if (ParseeManageBan(args->data, muc, NULL)) + if (ParseeManageBan(args->data, muc, NULL) || + ParseeIsMUCWhitelisted(args->data, muc)) { HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); response = MatrixCreateError( diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 1873dae..158f563 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -420,4 +420,10 @@ extern void ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *s); * Returns: NOTHING */ extern void ParseeUnlinkRoom(ParseeData *data, char *chat_id); +/** Verifies if there is no whitelists OR that a MUC's server is whitelisted. + * ---------------------- + * Returns: if a MUC is to be allowed + * Modifies: NOTHING */ +extern bool ParseeIsMUCWhitelisted(ParseeData *data, char *muc); + #endif From a38e14e029757c6b40038916e67983ae7a0f5f1e Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 28 Sep 2024 19:04:23 +0200 Subject: [PATCH 099/186] [FIX] Fix unused variables --- src/Commands/UnlinkMUC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/UnlinkMUC.c b/src/Commands/UnlinkMUC.c index 2a94b92..7f7cc50 100644 --- a/src/Commands/UnlinkMUC.c +++ b/src/Commands/UnlinkMUC.c @@ -43,7 +43,7 @@ CommandHead(CmdUnlinkMUC, cmd, argp) { ParseeCmdArg *args = argp; ParseeData *data = args->data; - HashMap *json, *event = args->event, *mucs; + HashMap *event = args->event; char *muc = NULL, *chat_id = NULL, *room = NULL; BotInitialise(); From 09d38993bb9da1caaf09218d8928f478e84e71da Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 29 Sep 2024 09:37:46 +0200 Subject: [PATCH 100/186] [ADD] Add XMPP commands for managing whitelists --- src/XMPPCommands/Whitelist.c | 142 +++++++++++++++++++++++++++++++++++ src/include/XMPPCommands.x.h | 10 +++ 2 files changed, 152 insertions(+) create mode 100644 src/XMPPCommands/Whitelist.c diff --git a/src/XMPPCommands/Whitelist.c b/src/XMPPCommands/Whitelist.c new file mode 100644 index 0000000..8e097a8 --- /dev/null +++ b/src/XMPPCommands/Whitelist.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +void +ClearWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); + + if (!ParseeIsAdmin(data, trimmed)) + { + SetNote("error", "User is not authorised to execute command."); + + Free(trimmed); + return; + } + Free(trimmed); + + if (!DbDelete(data->db, 1, "whitelist")) + { + SetNote("error", "Parsee whitelist was non-existent or could not be removed."); + return; + } + /* TODO: Cleanup old sessions? */ + SetNote("info", "Parsee whitelist was removed."); + + (void) form; +} +void +AddWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); + char *entity = NULL; + DbRef *ref; + + GetFieldValue(entity, "entity", form); + + if (!ParseeIsAdmin(data, trimmed)) + { + SetNote("error", "User is not authorised to execute command."); + + Free(trimmed); + return; + } + if (!entity) + { + SetNote("error", "No entity found."); + Free(trimmed); + return; + } + + Free(trimmed); + + ref = DbLock(data->db, 1, "whitelist"); + if (!ref) + { + ref = DbCreate(data->db, 1, "whitelist"); + } + if (!ref) + { + SetNote("error", "Couldn't get a database entry. You're cooked."); + return; + } + JsonValueFree(HashMapSet( + DbJson(ref), + entity, JsonValueObject(HashMapCreate()) + )); + DbUnlock(data->db, ref); + + SetNote("info", "Server successfully whitelisted."); +} +void +WhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); + XMLElement *x; + XMLElement *title; + XMLElement *reported, *item, *field, *value, *txt; + + if (!ParseeIsAdmin(data, trimmed)) + { + SetNote("error", "User is not authorised to execute command."); + + Free(trimmed); + return; + } + + x = XMLCreateTag("x"); + XMLAddAttr(x, "xmlns", "jabber:x:data"); + title = XMLCreateTag("title"); + XMLAddChild(x, title); + XMLAddChild(out, x); + + Free(trimmed); + + SetTitle(x, NAME " chat whitelist"); + + XMLAddAttr(x, "type", "result"); + { + DbRef *ref = DbLock(data->db, 1, "whitelist"); + HashMap *obj; + char *serv; + JsonValue *obj_val; + reported = XMLCreateTag("reported"); + XMLAddChild(x, reported); + + if (!ref) + { + ref = DbCreate(data->db, 1, "global_bans"); + } + + obj = DbJson(ref); + + /* Report */ + Report("server", "Allowed servers"); + + /* Set */ + while (HashMapIterate(obj, &serv, (void **) &obj_val)) + { + BeginItem(); + SetField("server", serv); + EndItem(); + + (void) obj_val; + } + DbUnlock(data->db, ref); + } + + (void) form; +} diff --git a/src/include/XMPPCommands.x.h b/src/include/XMPPCommands.x.h index d305340..eaeb5b9 100644 --- a/src/include/XMPPCommands.x.h +++ b/src/include/XMPPCommands.x.h @@ -28,5 +28,15 @@ XMPPSetFormTitle(cmd, "No-fly addition form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \ }) \ + XMPP_COMMAND(ClearWhitelistCallback, "clear-wl", "Removes the chat whitelist", {}) \ + XMPP_COMMAND(AddWhitelistCallback, "add-wl", "Adds server to chat whitelist", { \ + XMPPOption *serv = XMPPCreateText(true, "entity", ""); \ + XMPPSetDescription(serv, "Server to mark as admin"); \ + XMPPAddOption(cmd, serv); \ + \ + XMPPSetFormTitle(cmd, "Chatlist addition form"); \ + XMPPSetFormInstruction(cmd, "Add a server to whitelist"); \ + }) \ + XMPP_COMMAND(WhitelistCallback, "wl", "Get Parsee's chat whitelist", {}) \ XMPPCOMMANDS From d989331716297c7405238dca11dec81c718e3fcf Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 30 Sep 2024 06:11:31 +0200 Subject: [PATCH 101/186] [MOD] Add width/height information when possible --- src/Events.c | 7 +++- src/FileInfo.c | 66 ++++++++++++++++++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 6 ++- src/include/FileInfo.h | 23 +++++++++++ src/include/Matrix.h | 4 +- 5 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/FileInfo.c create mode 100644 src/include/FileInfo.h diff --git a/src/Events.c b/src/Events.c index 85b1e37..a78e756 100644 --- a/src/Events.c +++ b/src/Events.c @@ -79,7 +79,7 @@ MatrixCreateNickChange(char *nick) return map; } HashMap * -MatrixCreateMedia(char *mxc, char *body, char *mime) +MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info) { HashMap *map; char *mime_type = NULL, *matrix_type = NULL; @@ -120,6 +120,11 @@ MatrixCreateMedia(char *mxc, char *body, char *mime) map = HashMapCreate(); JsonSet(map, JsonValueString(mime), 2, "info", "mimetype"); + if (info && info->width && info->height) + { + JsonSet(map, JsonValueInteger(info->width), 2, "info", "w"); + JsonSet(map, JsonValueInteger(info->height), 2, "info", "h"); + } HashMapSet(map, "msgtype", JsonValueString(matrix_type)); HashMapSet(map, "mimetype", JsonValueString(mime)); HashMapSet(map, "body", JsonValueString(body)); diff --git a/src/FileInfo.c b/src/FileInfo.c new file mode 100644 index 0000000..e242e9d --- /dev/null +++ b/src/FileInfo.c @@ -0,0 +1,66 @@ +#include + +#include +#include + +#include +#include + +static int +GetField(XMLElement *elem) +{ + XMLElement *child; + if (!elem || ArraySize(elem->children) != 1) + { + return 0; + } + + child = ArrayGet(elem->children, 0); + + return strtol(child->data, NULL, 10); +} + +FileInfo * +FileInfoFromXMPP(XMLElement *stanza) +{ + FileInfo *info; + XMLElement *reference, *sims, *file; + + if (!stanza) + { + return NULL; + } + + reference = XMLookForTKV(stanza, + "reference", "xmlns", "urn:xmpp:reference:0" + ); + sims = XMLookForTKV(reference, + "media-sharing", "xmlns", "urn:xmpp:sims:1" + ); + file = XMLookForTKV(sims, + "file", "xmlns", "urn:xmpp:jingle:apps:file-transfer:5" + ); + if (!file) + { + return NULL; + } + + info = Malloc(sizeof(*info)); + + + info->width = GetField(XMLookForUnique(file, "width")); + info->height = GetField(XMLookForUnique(file, "height")); + info->size = GetField(XMLookForUnique(file, "size")); + return info; +} + +void +FileInfoFree(FileInfo *info) +{ + if (!info) + { + return; + } + + Free(info); +} diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index ae5f345..7cb82b3 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -419,10 +419,13 @@ end_error: if (oob_data) { + FileInfo *info = FileInfoFromXMPP(stanza); mxc = ASReupload(args->config, oob_data->data, &mime); if (mxc) { - content = MatrixCreateMedia(mxc, data->data, mime); + content = MatrixCreateMedia( + mxc, data->data, mime, info + ); HashMapSet(content, "at.kappach.at.parsee.external", @@ -436,6 +439,7 @@ end_error: ); Free(mxc); } + FileInfoFree(info); Free(mime); } } diff --git a/src/include/FileInfo.h b/src/include/FileInfo.h new file mode 100644 index 0000000..3d98c9b --- /dev/null +++ b/src/include/FileInfo.h @@ -0,0 +1,23 @@ +#ifndef PARSEE_FILEINFO_H +#define PARSEE_FILEINFO_H + +#include "XML.h" + +typedef struct FileInfo { + int width; + int height; + int size; +} FileInfo; + +/** Grab file metadata through SIMS. + * ---------------- + * Returns: File information(SIMS)[HEAP] + * Thrasher: FileInfoFree */ +extern FileInfo * FileInfoFromXMPP(XMLElement *stanza); + +/** Frees all information related with file metadata. + * -------------- + * Thrashes: info */ +extern void FileInfoFree(FileInfo *info); + +#endif diff --git a/src/include/Matrix.h b/src/include/Matrix.h index 0ffb7ec..a408389 100644 --- a/src/include/Matrix.h +++ b/src/include/Matrix.h @@ -3,6 +3,8 @@ #include +#include "FileInfo.h" + /* A simple representation of everything. It is not as complex as * Telodendria's CommonID parser, simply because Parsee does not * need such complexity. */ @@ -33,7 +35,7 @@ extern HashMap * MatrixCreateReact(char *event, char *body); extern HashMap * MatrixCreateReplace(char *event, char *body); /* Creates the content for a media file. */ -extern HashMap * MatrixCreateMedia(char *mxc, char *body, char *mime); +extern HashMap * MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info); /* Creates the content for a m.room.name state event */ extern HashMap * MatrixCreateNameState(char *name); From 9ea8f35c491efd0fc1f355e9accc2bfd88752d8e Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 1 Oct 2024 06:59:13 +0200 Subject: [PATCH 102/186] [ADD/WIP] Try dealing in VCards --- src/MatrixEventHandler.c | 14 ++++++++++++ src/XMPPThread/Stanzas/IQ.c | 38 ++++++++++++++++++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 4 +++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index fdb7b7b..163baca 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -165,6 +165,20 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) ParseeBroadcastStanza(data, full_jid, elem); XMLFreeElement(elem); + elem = XMLCreateTag("presence"); + { + XMLElement *x = XMLCreateTag("x"); + XMLElement *photo; + + XMLAddAttr(x, "xmlns", "vcard-temp:x:update"); + photo = XMLCreateTag("photo"); + XMLAddChild(photo, XMLCreateText(sha)); + XMLAddChild(x, photo); + XMLAddChild(elem, x); + } + ParseeBroadcastStanza(data, full_jid, elem); + XMLFreeElement(elem); + Free(full_jid); Free(avatar); Free(mime); diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index c6e929f..6ff097c 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -46,6 +46,42 @@ TrimBase64(char *b64) return ret; } +XMLElement * +GenerateAvatarData(ParseeData *data, char *mxid) +{ + char *mxc, *mime = NULL, *out = NULL, *b64 = NULL; + XMLElement *elem = NULL, *type, *binval; + size_t len = 0; + if (!data || !mxid) + { + return NULL; + } + + mxc = ASGetAvatar(data->config, NULL, mxid); + + if (!ASGrab(data->config, mxc, &mime, &out, &len)) + { + goto end; + } + b64 = Base64Encode(out, len); + + elem = XMLCreateTag("PHOTO"); + type = XMLCreateTag("TYPE"); + binval = XMLCreateTag("BINVAL"); + + XMLAddChild(type, XMLCreateText(mime)); + XMLAddChild(binval, XMLCreateText(b64)); + + XMLAddChild(elem, type); + XMLAddChild(elem, binval); + +end: + Free(mime); + Free(out); + Free(b64); + return elem; +} + #define DISCO "http://jabber.org/protocol/disco#info" static XMLElement * IQGenerateQuery(void) @@ -425,6 +461,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(vCard, nick); XMLAddChild(vCard, url); XMLAddChild(vCard, fn); + XMLAddChild(vCard, GenerateAvatarData(args, to_matrix)); Free(mto_link); } @@ -435,6 +472,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLEncode(jabber->stream, iqVCard); StreamFlush(jabber->stream); pthread_mutex_unlock(&jabber->write_lock); + XMLFreeElement(iqVCard); Free(to_matrix); Free(name); } diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 7cb82b3..6181616 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -349,7 +349,9 @@ end_error: * SENT TO NON-PARSEE PUPPETS, AS A "FIX" TO THE MULTITHREADED * ISSUE. * - * I HATE THIS. I NEED TO FIND A BETTER WAY. */ + * I HATE THIS. I NEED TO FIND A BETTER WAY. + * + * Actually, is it even _that_ bad? */ if (!chat && strncmp(HashMapGet(stanza->attrs, "to"), "parsee@", 7)) { goto end; From d585134ce1a9e26a54b791b6642b8b6de498031c Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 2 Oct 2024 21:13:28 +0200 Subject: [PATCH 103/186] [ADD/WIP] Temporary vCard avatard Gajim still reacts weirdly.... also it leaks memory related to avatars, so that sucks... --- CHANGELOG.md | 2 +- src/Commands/Plumb.c | 2 +- src/MatrixEventHandler.c | 38 +++++++++++++++++++------------------ src/Parsee/User.c | 2 +- src/Routes/UserAck.c | 2 +- src/XMPP/MUC.c | 16 +++++++++++++--- src/XMPPThread/Stanzas/IQ.c | 6 +++++- src/include/XMPP.h | 2 +- 8 files changed, 43 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b95b8f8..8a48645 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ of Parsee. May occasionally deadlock. Fixes some media metadata things, replaces the build system, and speeds up Parsee a tad bit. #### New things -- Start dealing with some basic PEP-based avatars. +- Start dealing with some basic PEP and vCard-based avatars. - Allows MbedTLS through a specific Cytoplasm patch. - Kicking/Banning Parsee from XMPP effectively unlinks it. - Start adding documentation to Parsee diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index 8d94dfc..b555b7a 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -63,7 +63,7 @@ CommandHead(CmdPlumb, cmd, argp) if (chat_id) { char *rev = StrConcat(2, muc, "/parsee"); - XMPPJoinMUC(args->data->jabber, "parsee", rev, false); + XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, false); Free(rev); } diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 163baca..9f601d5 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -18,7 +18,7 @@ static const char * GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to); static char * -JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) +JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char *hash) { char *sender = GrabString(event, 1, "sender"); @@ -33,7 +33,8 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) UnistrFree(uninick); UnistrFree(filtered); - while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 32) + /* TODO: vCards! */ + while (!XMPPJoinMUC(data->jabber, jid, rev, hash, true) && nonce < 32) { char *nonce_str = StrInt(nonce); char *input = StrConcat(3, sender, name, nonce_str); @@ -101,18 +102,24 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) else if (StrEquals(membership, "join") && !ParseeIsPuppet(conf, state_key)) { char *jid = ParseeEncodeMXID(state_key); + char *sha = NULL, *mime = NULL; + char *avatar = ASGetAvatar(data->config, room_id, state_key); + char *url = ParseeToUnauth(data, avatar); chat_id = ParseeGetFromRoomID(data, room_id); + + ASGetMIMESHA(data->config, avatar, &mime, &sha); + Free(avatar); + avatar = NULL; if (chat_id) { char *muc = ParseeGetMUCID(data, chat_id); char *name = ASGetName(data->config, room_id, state_key); - char *avatar = ASGetAvatar(data->config, room_id, state_key); - char *jabber = JoinMUC(data, event, jid, muc, name); - + char *jabber = JoinMUC(data, event, jid, muc, name, sha); + avatar = ASGetAvatar(data->config, room_id, state_key); Log(LOG_DEBUG, "MATRIX: Joining as '%s' (avatar=%s)", jabber, avatar); - Free(avatar); Free(jabber); + Free(avatar); Free(name); Free(muc); @@ -120,18 +127,14 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) } else { - char *avatar = ASGetAvatar(data->config, room_id, state_key); - char *sha = NULL, *mime = NULL, *url = NULL; char *full_jid = StrConcat(3, jid, "@", data->config->component_host ); XMLElement *elem, *pevent, *items, *item, *meta, *info; - Log(LOG_DEBUG, "MATRIX: Got local user '%s'(mxid=%s avatar=%s)", jid, state_key, avatar); + Log(LOG_DEBUG, "MATRIX: Got local user '%s'(mxid=%s)", jid, state_key); - url = ParseeToUnauth(data, avatar); elem = XMLCreateTag("message"); - ASGetMIMESHA(data->config, avatar, &mime, &sha); { #define PUBSUB "http://jabber.org/protocol/pubsub" #define AVATAR "urn:xmpp:avatar:metadata" @@ -180,13 +183,12 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) XMLFreeElement(elem); Free(full_jid); - Free(avatar); - Free(mime); - Free(sha); - Free(url); } - Free(jid); Free(chat_id); + Free(mime); + Free(sha); + Free(jid); + Free(url); } else if ((StrEquals(membership, "leave") || StrEquals(membership, "ban")) @@ -343,7 +345,7 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } matrix_name = ASGetName(data->config, room_id, matrix_sender); - Free(JoinMUC(data, event, *from, muc_id, matrix_name)); + Free(JoinMUC(data, event, *from, muc_id, matrix_name, NULL)); *to = muc_id; Free(matrix_name); @@ -432,7 +434,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) /* TODO: Avoid using the AS endpoints */ name = ASGetName(data->config, id, m_sender); - Free(JoinMUC(data, event, encoded_from, muc_id, name)); + Free(JoinMUC(data, event, encoded_from, muc_id, name, NULL)); to = muc_id; diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 90c7ca5..fe7d00b 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -554,7 +554,7 @@ ParseeSendPresence(ParseeData *data) char *rev = StrConcat(2, muc, "/parsee"); /* Make a fake user join the MUC */ Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(data->jabber, "parsee", rev, false); + XMPPJoinMUC(data->jabber, "parsee", rev, NULL, false); Free(rev); } diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c index 828be65..54ca96e 100644 --- a/src/Routes/UserAck.c +++ b/src/Routes/UserAck.c @@ -131,7 +131,7 @@ RouteHead(RouteRoomAck, arr, argp) { char *rev = StrConcat(2, muc, "/parsee"); Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(args->data->jabber, "parsee", rev, false); + XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, false); Free(rev); } diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 3a81764..498ddfa 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -168,9 +168,9 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) Free(identifier); } bool -XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) +XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, bool ret) { - XMLElement *presence, *x, *reply, *history; + XMLElement *presence, *x, *reply, *history, *photo; char *from, *id; if (!comp || !fr || !muc) { @@ -192,6 +192,16 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) XMLAddChild(presence, x); XMPPAnnotatePresence(presence); + if (hash) + { + x = XMLCreateTag("x"); + XMLAddAttr(x, "xmlns", "vcard-temp:x:update"); + photo = XMLCreateTag("photo"); + XMLAddChild(photo, XMLCreateText(hash)); + XMLAddChild(x, photo); + XMLAddChild(presence, x); + } + XMLEncode(comp->stream, presence); StreamFlush(comp->stream); @@ -200,7 +210,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) pthread_mutex_unlock(&comp->write_lock); - if (care && (reply = ParseeAwaitStanza(id, 500))) + if (ret && (reply = ParseeAwaitStanza(id, 500))) { bool exit_code = true; diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 6ff097c..c2dc3a9 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -78,6 +78,7 @@ GenerateAvatarData(ParseeData *data, char *mxid) end: Free(mime); Free(out); + Free(mxc); Free(b64); return elem; } @@ -395,7 +396,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *to_matrix = ParseeGetBridgedUser(args, stanza); char *name = ASGetName(args->config, NULL, to_matrix); XMLElement *iqVCard; - Log(LOG_DEBUG, "vCard information GET for %s", to); + Log(LOG_DEBUG, "vCard information GET for %s (%s)", to, to_matrix); if (!strncmp(to, "parsee@", 7)) { @@ -435,6 +436,9 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) return; } + Free(to_matrix); + to_matrix = ParseeDecodeMXID(to); + iqVCard = XMLCreateTag("iq"); XMLAddAttr(iqVCard, "from", to); XMLAddAttr(iqVCard, "to", from); diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 24a23d9..0a4cfe7 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -30,7 +30,7 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); /* Makes a user join/leave a MUC */ -extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care); +extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, bool ret); extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ From 17474bda0f3b0ecac0d0a9967a2ea79e3d35bad1 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 3 Oct 2024 07:53:39 +0200 Subject: [PATCH 104/186] [FIX] (Try to) fix the memory leak --- src/MatrixEventHandler.c | 12 ++++++++++-- src/XMPPThread/Stanzas/IQ.c | 21 +++------------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 9f601d5..cb86427 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -122,6 +122,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) Free(avatar); Free(name); Free(muc); + avatar = NULL; /* TODO: XEP-0084 magic to advertise a new avatar if possible. */ } @@ -185,6 +186,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) Free(full_jid); } Free(chat_id); + Free(avatar); Free(mime); Free(sha); Free(jid); @@ -424,7 +426,8 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) } else { - char *name; + char *name, *mime = NULL, *sha = NULL; + char *avatar; /* Try to find the chat ID */ muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -434,11 +437,16 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) /* TODO: Avoid using the AS endpoints */ name = ASGetName(data->config, id, m_sender); - Free(JoinMUC(data, event, encoded_from, muc_id, name, NULL)); + avatar = ASGetAvatar(data->config, id, sender); + ASGetMIMESHA(data->config, avatar, &mime, &sha); + Free(JoinMUC(data, event, encoded_from, muc_id, name, sha)); to = muc_id; + Free(sha); + Free(mime); Free(name); + Free(avatar); } if (reply_id) { diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index c2dc3a9..0f25c4c 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -49,7 +49,7 @@ TrimBase64(char *b64) XMLElement * GenerateAvatarData(ParseeData *data, char *mxid) { - char *mxc, *mime = NULL, *out = NULL, *b64 = NULL; + char *mxc = NULL, *mime = NULL, *out = NULL, *b64 = NULL; XMLElement *elem = NULL, *type, *binval; size_t len = 0; if (!data || !mxid) @@ -57,9 +57,10 @@ GenerateAvatarData(ParseeData *data, char *mxid) return NULL; } + /* TODO: Use the right room */ mxc = ASGetAvatar(data->config, NULL, mxid); - if (!ASGrab(data->config, mxc, &mime, &out, &len)) + if (!mxc || !ASGrab(data->config, mxc, &mime, &out, &len)) { goto end; } @@ -449,22 +450,6 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *mto_link = ParseeGenerateMTO(to_matrix); XMLAddAttr(vCard, "xmlns", "vcard-temp"); { - XMLElement *fn = CreateTagWithText( - "FN", name ? name : to_matrix - ); - XMLElement *nick = CreateTagWithText( - "NICKNAME", to_matrix - ); - XMLElement *url = CreateTagWithText( - "URL", mto_link - ); - - /* TODO: Maybe abstract the vCard code. */ - /* TODO: Make a function to just get a user's avatar - * automatically. */ - XMLAddChild(vCard, nick); - XMLAddChild(vCard, url); - XMLAddChild(vCard, fn); XMLAddChild(vCard, GenerateAvatarData(args, to_matrix)); Free(mto_link); From b7c360d5285fb714955094c21a5f1db6956203fd Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 4 Oct 2024 12:09:56 +0200 Subject: [PATCH 105/186] [FIX] Handle logic mistake in plumbing --- CHANGELOG.md | 31 +++++++++++++++++-------------- src/Commands/Plumb.c | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a48645..33a2d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,24 +13,16 @@ commit done between releases. *There is currently no beta releases of Parsee* ## Alpha -### v0.1.0[tomboyish-bridges-adventure] <9/9/2024> -Nothing much to say, but this is the first alpha release -of Parsee. May occasionally deadlock. -#### New things -*NONE* -#### Bugfixes -*NONE* -#### Deprecated features -*NONE* - ### v0.2.0[star-of-hope] Fixes some media metadata things, replaces the build system, -and speeds up Parsee a tad bit. +tries out avatar support some more and speeds up Parsee a tad +bit. #### New things - Start dealing with some basic PEP and vCard-based avatars. -- Allows MbedTLS through a specific Cytoplasm patch. +- Allows experimental MbedTLS through a specific Cytoplasm +patch. - Kicking/Banning Parsee from XMPP effectively unlinks it. -- Start adding documentation to Parsee +- Start adding basic documentation to Parsee - Add MUC whitelists for plumbing, alongside a `whitelist` tool #### Bugfixes @@ -40,7 +32,18 @@ behave. - "Lone" XMPP messages no longer render weirdly on Element Android's weird rendering. - Start fixing bug where Parsee takes several seconds to send -a message coming from XMPP +a message coming from XMPP with MbedTLS(it is still slow and +unstable) + #### Deprecated features - The old `build.c` and `Makefile`s used for building are removed, and replaced by the `configure.c` C file(/script via TCC). +### v0.1.0[tomboyish-bridges-adventure] <9/9/2024> +Nothing much to say, but this is the first alpha release +of Parsee. May occasionally deadlock. +#### New things +*NONE* +#### Bugfixes +*NONE* +#### Deprecated features +*NONE* diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index b555b7a..66f8283 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -25,7 +25,7 @@ CommandHead(CmdPlumb, cmd, argp) /* Check MUC viability */ if (ParseeManageBan(args->data, muc, NULL) || - ParseeIsMUCWhitelisted(args->data, muc)) + !ParseeIsMUCWhitelisted(args->data, muc)) { ReplySprintf("MUC '%s' is not allowed on this bridge.", muc); goto end; From 179fd405dbb3a874b7fb6d092dbddc647637f386 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 5 Oct 2024 09:20:49 +0200 Subject: [PATCH 106/186] [FIX] Do not listen for kick requests They may be sent for scenarios where an unlink is NOT wanted. --- CHANGELOG.md | 2 +- src/XMPPThread/Stanzas/Presence.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33a2d76..1d5c0f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ bit. - Start dealing with some basic PEP and vCard-based avatars. - Allows experimental MbedTLS through a specific Cytoplasm patch. -- Kicking/Banning Parsee from XMPP effectively unlinks it. +- Banning Parsee from a XMPP MUC effectively unlinks it. - Start adding basic documentation to Parsee - Add MUC whitelists for plumbing, alongside a `whitelist` tool diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 89448b6..b72f988 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -212,8 +212,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) } } if (StrEquals(type, "unavailable") && - StrEquals(dst, parsee_j) && - (IsStatus(301) || IsStatus(307))) + StrEquals(dst, parsee_j) && IsStatus(301)) { char *chat_id = ParseeGetFromRoomID(args, room); From 94090a8c972bf314d746abe4c83aa7e045c325fd Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 5 Oct 2024 09:43:12 +0200 Subject: [PATCH 107/186] [MOD] Rewrite the status code slightly Also handle error-based kicks --- src/XMPPThread/Stanzas/Presence.c | 62 +++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index b72f988..dc825f3 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -56,6 +56,60 @@ GuessStatus(XMLElement *stanza) } return USER_STATUS_ONLINE; } + +static Array * +GetStatuses(XMLElement *info) +{ + XMLElement *child; + Array *ret; + size_t i; + if (!info) + { + return NULL; + } + + ret = ArrayCreate(); + for (i = 0; i < ArraySize(info->children); i++) + { + child = ArrayGet(info->children, i); + if (StrEquals(child->name, "status")) + { + ArrayAdd(ret, HashMapGet(child->attrs, "code")); + } + } + + return ret; +} + +static void +FreeStatuses(Array *statuses) +{ + if (!statuses) + { + return; + } + + ArrayFree(statuses); +} +static bool +HasStatus(Array *statuses, const char *code) +{ + size_t i; + if (!statuses || !code) + { + return false; + } + + for (i = 0; i < ArraySize(statuses); i++) + { + if (StrEquals(ArrayGet(statuses, i), code)) + { + return true; + } + } + + return false; +} void PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { @@ -96,9 +150,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if ((user_info = XMLookForTKV(stanza, "x", "xmlns", MUC_USER_NS))) { XMLElement *item = XMLookForUnique(user_info, "item"); - XMLElement *status = XMLookForUnique(user_info, "status"); -#define IsStatus(code) (status && \ - StrEquals(HashMapGet(status->attrs, "code"), #code)) + Array *statuses = GetStatuses(user_info); +#define IsStatus(code) (HasStatus(statuses, #code)) char *jid = item ? HashMapGet(item->attrs, "jid") : NULL; char *trim = ParseeTrimJID(jid); char *from = NULL; @@ -197,7 +250,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { ASBan(args->config, room, real_matrix); } - else if (IsStatus(307)) + else if (IsStatus(307) && !IsStatus(333)) { ASKick(args->config, room, real_matrix); } @@ -235,6 +288,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) Free(parsee_j); Free(parsee); Free(room); + FreeStatuses(statuses); } if (status) { From a48c3ba1266499fff045c2cc52aa529e133a0ef9 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 8 Oct 2024 17:27:25 +0200 Subject: [PATCH 108/186] [ADD] Have avatars on first-message too --- src/AS/Profile.c | 1 - src/MatrixEventHandler.c | 18 +++++++++++++----- src/XML/Parser.c | 8 ++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/AS/Profile.c b/src/AS/Profile.c index f536300..1f1a0da 100644 --- a/src/AS/Profile.c +++ b/src/AS/Profile.c @@ -195,7 +195,6 @@ ASGetAvatar(const ParseeConfig *c, char *room, char *user) ret = StrDuplicate( JsonValueAsString(HashMapGet(reply, "avatar_url")) ); - StreamFlush(StreamStderr()); HttpClientContextFree(ctx); JsonFree(reply); Free(path); diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index cb86427..8fec7ca 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -103,7 +103,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) { char *jid = ParseeEncodeMXID(state_key); char *sha = NULL, *mime = NULL; - char *avatar = ASGetAvatar(data->config, room_id, state_key); + char *avatar = ASGetAvatar(data->config, NULL, state_key); char *url = ParseeToUnauth(data, avatar); chat_id = ParseeGetFromRoomID(data, room_id); @@ -115,7 +115,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) char *muc = ParseeGetMUCID(data, chat_id); char *name = ASGetName(data->config, room_id, state_key); char *jabber = JoinMUC(data, event, jid, muc, name, sha); - avatar = ASGetAvatar(data->config, room_id, state_key); + avatar = ASGetAvatar(data->config, NULL, state_key); Log(LOG_DEBUG, "MATRIX: Joining as '%s' (avatar=%s)", jabber, avatar); Free(jabber); @@ -333,7 +333,8 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } else { - char *matrix_name; + char *matrix_name, *matrix_avatar; + char *mime, *sha; muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -347,10 +348,16 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } matrix_name = ASGetName(data->config, room_id, matrix_sender); - Free(JoinMUC(data, event, *from, muc_id, matrix_name, NULL)); + matrix_avatar = ASGetAvatar(data->config, NULL, matrix_sender); + + ASGetMIMESHA(data->config, matrix_avatar, &mime, &sha); + Free(JoinMUC(data, event, *from, muc_id, matrix_name, sha)); *to = muc_id; + Free(matrix_avatar); Free(matrix_name); + Free(mime); + Free(sha); } Free(chat_id); @@ -437,8 +444,9 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) /* TODO: Avoid using the AS endpoints */ name = ASGetName(data->config, id, m_sender); - avatar = ASGetAvatar(data->config, id, sender); + avatar = ASGetAvatar(data->config, NULL, m_sender); ASGetMIMESHA(data->config, avatar, &mime, &sha); + Free(JoinMUC(data, event, encoded_from, muc_id, name, sha)); to = muc_id; diff --git a/src/XML/Parser.c b/src/XML/Parser.c index 1b8d30a..359e637 100644 --- a/src/XML/Parser.c +++ b/src/XML/Parser.c @@ -116,6 +116,11 @@ XMLEncodeString(Stream *stream, char *data) { size_t i; + if (!stream || !data) + { + return; + } + for (i = 0; i < strlen(data); i++) { char c = data[i]; @@ -145,6 +150,9 @@ XMLEncodeString(Stream *stream, char *data) continue; } StreamPrintf(stream, "%c", c); + /* TODO: Maybe consider Unistrings and encode arbitrary Unicode + * codepoints * with special XML. Oughta make it printable, you know? + */ } } void From 13a9d23fa0fcbd2df2aaee7da7d2dc5f9a23fd0b Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 11 Oct 2024 16:09:21 +0200 Subject: [PATCH 109/186] [FIX/ADD] Fix YAML generation, keep track of time --- README.MD | 3 +-- src/Commands/Plumb.c | 2 +- src/Main.c | 2 ++ src/MatrixEventHandler.c | 2 +- src/Parsee/Config.c | 3 +++ src/Parsee/Data.c | 9 +++++++++ src/Parsee/User.c | 10 ++++++++-- src/Routes/Root.c | 2 +- src/Routes/UserAck.c | 2 +- src/Signal.c | 1 + src/XMPPThread/ReListener.c | 5 ++++- src/include/XMPP.h | 2 +- 12 files changed, 33 insertions(+), 10 deletions(-) diff --git a/README.MD b/README.MD index 2955984..786e905 100644 --- a/README.MD +++ b/README.MD @@ -72,8 +72,7 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th ## TODOS before 1.0 rolls around - Make Parsee actually go *vroooooooooommmmmmm*. -- PROPER FUCKING VCARD AVATARS - XMPP->Matrix is decent, Matrix->XMPP is effectively a WIP +- Avoid making 'back-puppets' from Matrix as much as possible - Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency. - It depends on more stuff anyways, and I don't want to weigh down the dependency list of Parsee for that. diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index 66f8283..f51e4e6 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -63,7 +63,7 @@ CommandHead(CmdPlumb, cmd, argp) if (chat_id) { char *rev = StrConcat(2, muc, "/parsee"); - XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, false); + XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, -1, false); Free(rev); } diff --git a/src/Main.c b/src/Main.c index 7f01258..af2496d 100644 --- a/src/Main.c +++ b/src/Main.c @@ -106,6 +106,8 @@ Main(Array *args, HashMap *env) /* Write out the config file to a YAML document */ Log(LOG_INFO, "Generating YAML..."); yaml = StreamOpen("parsee.yaml", "w"); + ParseeConfigLoad(configuration); + ParseeConfigInit(); ParseeExportConfigYAML(yaml); StreamClose(yaml); Free(opts); diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 8fec7ca..0f84789 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -34,7 +34,7 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char UnistrFree(filtered); /* TODO: vCards! */ - while (!XMPPJoinMUC(data->jabber, jid, rev, hash, true) && nonce < 32) + while (!XMPPJoinMUC(data->jabber, jid, rev, hash, -1, true) && nonce < 32) { char *nonce_str = StrInt(nonce); char *input = StrConcat(3, sender, name, nonce_str); diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 0e1ee04..541c0a4 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -77,6 +77,7 @@ ParseeSetThreads(int xmpp, int http) { if (!config) { + Achievement("THREAD COUNT REQUEST WITHOUT CONFIG", true); return; } config->http_threads = http; @@ -88,6 +89,7 @@ ParseeExportConfigYAML(Stream *stream) { if (!stream || !config) { + Achievement("YAML EXPORT REQUEST WITHOUT CONFIG", true); return; } StreamPrintf(stream, "# Autogenerated YAML AS entry for %s\n", NAME); @@ -109,6 +111,7 @@ ParseeExportConfigYAML(Stream *stream) StreamPrintf(stream, " aliases:\n"); StreamPrintf(stream, " - exclusive: true\n"); StreamPrintf(stream, " regex: \"#%s_.*\"\n", config->namespace_base); + StreamFlush(stream); } void diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 87b2263..3d2bbb8 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -337,6 +337,15 @@ ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id, char *id, cha } /* TODO */ + { + ref = DbLock(data->db, 2, "chats", chat_id); + j = DbJson(ref); + if (j) + { + JsonValueFree(HashMapSet(j, "ts", JsonValueInteger(age))); + } + DbUnlock(data->db, ref); + } { ref = DbCreate(data->db, 4, "chats", chat_id, "stanzas", stanza_id); j = DbJson(ref); diff --git a/src/Parsee/User.c b/src/Parsee/User.c index fe7d00b..5614ca2 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -552,10 +552,16 @@ ParseeSendPresence(ParseeData *data) while (HashMapIterate(mucs, &muc, (void **) &val)) { char *rev = StrConcat(2, muc, "/parsee"); + char *chat_id = ParseeGetFromMUCID(data, muc); + DbRef *chat = DbLockIntent(data->db, DB_HINT_READONLY, 2, "chats", chat_id); + uint64_t ts = GrabInteger(DbJson(chat), 1, "ts"); + int diff = ts ? (UtilTsMillis() - ts) / 1000 : -1; /* Make a fake user join the MUC */ - Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(data->jabber, "parsee", rev, NULL, false); + Log(LOG_NOTICE, "Sending presence to %s last=%ds", rev, diff); + XMPPJoinMUC(data->jabber, "parsee", rev, NULL, diff, false); + DbUnlock(data->db, chat); + Free(chat_id); Free(rev); } DbUnlock(data->db, ref); diff --git a/src/Routes/Root.c b/src/Routes/Root.c index e0e3e87..a68bfbc 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -173,7 +173,7 @@ RouteHead(RouteRoot, arr, argp) P("

"); { P("More information available at "); - P("the actual page."); } diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c index 54ca96e..50029ba 100644 --- a/src/Routes/UserAck.c +++ b/src/Routes/UserAck.c @@ -131,7 +131,7 @@ RouteHead(RouteRoomAck, arr, argp) { char *rev = StrConcat(2, muc, "/parsee"); Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, false); + XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, -1, false); Free(rev); } diff --git a/src/Signal.c b/src/Signal.c index 89e48e2..4274561 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -25,6 +25,7 @@ SignalHandler(int signal) if (signal == SIGPIPE) { Log(LOG_DEBUG, "Caught a SIGPIPE..."); + return; } } diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index f518a67..56d5317 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -134,6 +134,7 @@ ParseeXMPPThread(void *argp) ParseeData *args = argp; XMPPComponent *jabber = args->jabber; XMLElement *stanza = NULL; + HashMap *await_table2; size_t i; /* Initialise the await table */ @@ -268,7 +269,9 @@ ParseeXMPPThread(void *argp) } ArrayFree(info.stanzas); - HashMapFree(await_table); + await_table2 = await_table; + await_table = NULL; + HashMapFree(await_table2); pthread_mutex_destroy(&info.lock); diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 0a4cfe7..b3f4c09 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -30,7 +30,7 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); /* Makes a user join/leave a MUC */ -extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, bool ret); +extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int secs, bool ret); extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ From 147e430a471f6023425c3fb190fc52703e823e32 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 11 Oct 2024 19:49:19 +0200 Subject: [PATCH 110/186] [FIX] Do NOT use strlen in a loop Never. Do. This. Never. It should never cross your mind. Doing so will punish you. Basic computer science concepts will tell you it's O(n^2). And it WILL actually matter. Never. Never. Never. Never. Never. Never. NEVER FUCKING EVER DO THAT EVER AGAIN. NEVER FUCKING EVER DO THAT EVER AGAIN. NEVER FUCKING EVER DO THAT EVER AGAIN. NEVER FUCKING EVER DO THAT EVER AGAIN. NEVER FUCKING EVER DO THAT EVER AGAIN. Anyways, also fixes licensing year. On est en octobre et il comprend toujours pas qu'on est plus en 2023. --- src/Events.c | 5 +++-- src/Main.c | 4 ++-- src/Parsee/User.c | 31 ++++++++++++++++++------------- src/XML/Parser.c | 9 +++++++-- src/XML/SAX.c | 7 ++++--- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/Events.c b/src/Events.c index a78e756..e9edf12 100644 --- a/src/Events.c +++ b/src/Events.c @@ -91,9 +91,10 @@ MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info) matrix_type = "m.file"; if (mime) { - size_t i; + size_t i, len; mime_type = StrDuplicate(mime); - for (i = 0; i < strlen(mime); i++) + len = strlen(mime); + for (i = 0; i < len; i++) { if (mime_type[i] == '/') { diff --git a/src/Main.c b/src/Main.c index af2496d..2ddd35f 100644 --- a/src/Main.c +++ b/src/Main.c @@ -79,7 +79,7 @@ Main(Array *args, HashMap *env) ); ParseePrintASCII(); Log(LOG_INFO, "======================="); - Log(LOG_INFO, "(C)opyright 2023 LDA"); + Log(LOG_INFO, "(C)opyright 2024 LDA"); Log(LOG_INFO, "(This program is free software, see LICENSE.)"); LogConfigIndent(LogConfigGlobal()); @@ -153,7 +153,6 @@ Main(Array *args, HashMap *env) } } Free(opts); - ParseeSetThreads(xmpp, http); } if (verbose >= PARSEE_VERBOSE_COMICAL) @@ -167,6 +166,7 @@ Main(Array *args, HashMap *env) { goto end; } + ParseeSetThreads(xmpp, http); Log(LOG_NOTICE, "Connecting to XMPP..."); diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 5614ca2..6d6d0be 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -147,14 +147,15 @@ char * ParseeEncodeJID(const ParseeConfig *c, char *jid, bool trim) { char *ret, *tmp; - size_t i; + size_t i, len; if (!c || !jid) { return NULL; } ret = StrConcat(2, c->namespace_base, "_l_"); - for (i = 0; i < strlen(jid); i++) + len = strlen(jid); + for (i = 0; i < len; i++) { char cpy = jid[i]; char cs[4] = { 0 }; @@ -193,7 +194,7 @@ char * ParseeGetLocal(char *mxid) { char *cpy; - size_t i; + size_t i, len; if (!mxid) { return NULL; @@ -203,12 +204,14 @@ ParseeGetLocal(char *mxid) return StrDuplicate(mxid); } - mxid++; - cpy = Malloc(strlen(mxid) + 1); - memset(cpy, '\0', strlen(mxid) + 1); - memcpy(cpy, mxid, strlen(mxid)); + len = strlen(mxid); - for (i = 0; i < strlen(mxid); i++) + mxid++; + cpy = Malloc(len + 1); + memset(cpy, '\0', len + 1); + memcpy(cpy, mxid, len); + + for (i = 0; i < len; i++) { if (cpy[i] == ':') { @@ -224,15 +227,16 @@ char * ParseeEncodeMXID(char *mxid) { char *ret; - size_t i, j; + size_t i, j, len; if (!mxid) { return NULL; } /* Worst case scenario of 3-bytes the char */ - ret = Malloc(strlen(mxid) * 3 + 1); - for (i = 0, j = 0; i < strlen(mxid); i++) + len = strlen(mxid); + ret = Malloc(len * 3 + 1); + for (i = 0, j = 0; i < len; i++) { char src = mxid[i]; @@ -372,14 +376,15 @@ char * ParseeTrimJID(char *jid) { char *ret; - size_t i; + size_t i, len; if (!jid) { return NULL; } ret = StrDuplicate(jid); - for (i = 0; i < strlen(ret); i++) + len = strlen(ret); + for (i = 0; i < len; i++) { if (ret[i] == '/') { diff --git a/src/XML/Parser.c b/src/XML/Parser.c index 359e637..506e49d 100644 --- a/src/XML/Parser.c +++ b/src/XML/Parser.c @@ -114,14 +114,19 @@ XMLCDecode(Stream *stream, bool autofree, bool html) void XMLEncodeString(Stream *stream, char *data) { - size_t i; + size_t i, len; if (!stream || !data) { return; } - for (i = 0; i < strlen(data); i++) + /* TODO: I should write a "Parsee Best Practice" guideline and make sure + * people understand to NOT constantly recompute lengths parameter on + * these kinds of loops. ArraySize is fine(since its indirection), but + * operations like strlen take time! */ + len = strlen(data); + for (i = 0; i < len; i++) { char c = data[i]; if (c == '<') diff --git a/src/XML/SAX.c b/src/XML/SAX.c index f2eb814..d21113c 100644 --- a/src/XML/SAX.c +++ b/src/XML/SAX.c @@ -295,7 +295,7 @@ static bool XMLookahead(XMLexer *lexer, const char *str, bool skip) { int *stack; - size_t top, i; + size_t top, i, len; ssize_t ntop; bool ret = false; if (!lexer || !str) @@ -304,9 +304,10 @@ XMLookahead(XMLexer *lexer, const char *str, bool skip) } top = 0; - stack = Malloc(strlen(str) * sizeof(*stack)); + len = strlen(str); + stack = Malloc(len * sizeof(*stack)); - for (i = 0; i < strlen(str); i++) + for (i = 0; i < len; i++) { char c = str[i]; int getc = XMLGetc(lexer); From 27223a5896ba2c957007067672e0555c78a11d4c Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 11 Oct 2024 19:58:28 +0200 Subject: [PATCH 111/186] [FIX/CI] Listen to CI --- src/XMPP/MUC.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 498ddfa..5d39d78 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -168,10 +168,10 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) Free(identifier); } bool -XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, bool ret) +XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool ret) { XMLElement *presence, *x, *reply, *history, *photo; - char *from, *id; + char *from, *id, *stime = "3600"; if (!comp || !fr || !muc) { return false; @@ -186,7 +186,17 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, bool ret) XMLAddAttr(presence, "id", (id = StrRandom(8))); XMLAddAttr(x, "xmlns", "http://jabber.org/protocol/muc"); history = XMLCreateTag("history"); - XMLAddAttr(history, "seconds", "3600"); /* TODO: Custom timeout */ + + if (time > 0) + { + stime = StrInt(time); + } + XMLAddAttr(history, "seconds", stime); + if (time > 0) + { + Free(stime); + stime = NULL; + } XMLAddChild(x, history); XMLAddChild(presence, x); From 1be19d4b8d32abc007560b9cf2d569748604593c Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 11 Oct 2024 20:03:41 +0200 Subject: [PATCH 112/186] [CI/FIX] Proper casts --- src/Parsee/User.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 6d6d0be..e68082b 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -560,7 +560,7 @@ ParseeSendPresence(ParseeData *data) char *chat_id = ParseeGetFromMUCID(data, muc); DbRef *chat = DbLockIntent(data->db, DB_HINT_READONLY, 2, "chats", chat_id); uint64_t ts = GrabInteger(DbJson(chat), 1, "ts"); - int diff = ts ? (UtilTsMillis() - ts) / 1000 : -1; + int diff = ts ? (int) ((UtilTsMillis() - ts) / 1000) : -1; /* Make a fake user join the MUC */ Log(LOG_NOTICE, "Sending presence to %s last=%ds", rev, diff); XMPPJoinMUC(data->jabber, "parsee", rev, NULL, diff, false); From ecbc211003d9db5f9cf4b09c5d147c37fe6fa12e Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Thu, 17 Oct 2024 06:44:18 +0200 Subject: [PATCH 113/186] [FIX] configure.c: Fix '.' and '..' detection Otherwise, hidden files such as '.file.' would be ignored. --- configure.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.c b/configure.c index b01b351..b0cbee6 100644 --- a/configure.c +++ b/configure.c @@ -293,7 +293,8 @@ collect_sources(char *dir, bool head, char *ext) while ((ent = readdir(handle))) { char *name = ent->d_name; - if (*name == '.') continue; + + if (!strcmp(name, ".") || !strcmp(name, "..")) continue; if (strlen(name) > strlen(ext) && !strcmp(name + strlen(name) - strlen(ext), ext)) From a66021bf46fb2a32041a1ffb078761d1b33d17fd Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Thu, 17 Oct 2024 06:45:42 +0200 Subject: [PATCH 114/186] [FIX] configure.c: Improve recursion rule So far, collect_sources was called recursively when the entry name did not match a pre-defined list. However, this assumption broke with files such as `etc/media/README`, that were not in the list. Therefore, a deterministic way to distinguish files from directories is to rely on the S_ISDIR macro. This avoids the need for a pre-defined list. --- configure.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/configure.c b/configure.c index b0cbee6..6d1f1a7 100644 --- a/configure.c +++ b/configure.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -306,22 +307,29 @@ collect_sources(char *dir, bool head, char *ext) free(na); continue; } - if (!strchr(name, '.') && - strcmp(name, "out") && - strcmp(name, "Makefile")) { - str_array_t *sub; char *d1 = string_cat(dir, "/"); char *d2 = string_cat(d1, name); size_t i; + struct stat sb; - sub = collect_sources(d2, false, ext); - for (i = 0; i < str_array_len(sub); i++) + if (stat(d2, &sb)) { - char *file = str_array_get(sub, i); - str_array_add(ret, file); + fprintf(stderr, "stat(2) %s: %s\n", d2, strerror(errno)); + free(d2); + free(d1); } - str_array_free(sub); + else if (S_ISDIR(sb.st_mode)) + { + str_array_t *sub = collect_sources(d2, false, ext); + for (i = 0; i < str_array_len(sub); i++) + { + char *file = str_array_get(sub, i); + str_array_add(ret, file); + } + str_array_free(sub); + } + free(d2); free(d1); } From e0f76e7929a3a3a5216852a05752ee06db958ed8 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Thu, 17 Oct 2024 07:00:59 +0200 Subject: [PATCH 115/186] [FIX] configure.c: Add missing -I $(CYTO_INC) Some tools depend on header files defined by Cytoplasm. --- configure.c | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.c b/configure.c index 6d1f1a7..e04b8e0 100644 --- a/configure.c +++ b/configure.c @@ -564,6 +564,7 @@ main_build(int argc, char *argv[]) fprintf(makefile, " -static"); } fprintf(makefile, " $<"); + fprintf(makefile, " -I $(CYTO_INC)"); fprintf(makefile, " -L $(CYTO_LIB)"); if (with_static) { From 2074d8e7680c122e0d501d7c37734c4d891066d4 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Thu, 17 Oct 2024 07:28:07 +0200 Subject: [PATCH 116/186] [FIX] configure.c: Do not assume git If parsee were downloaded from sources other than git-clone(1) (e.g.: a tarball), perror(3) fails and/or git(1) is not available on the system, "git remote get-url origin" would have unexpected results or even return a NULL pointer, which would cause undefined behaviour on strchr(repo, ...); In such conditions, a placeholder string, namely "N/A", is strdup(3)ed to `repo`. --- configure.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/configure.c b/configure.c index e04b8e0..574b75f 100644 --- a/configure.c +++ b/configure.c @@ -186,18 +186,34 @@ cmd_stdout(char *cmd) FILE *f; char *line = NULL; size_t size; + int result; if (!cmd) { - return NULL; + goto failure; } if (!(f = popen(cmd, "r"))) { - return NULL; + goto failure; } getline(&line, &size, f); - pclose(f); + result = pclose(f); + + if (result < 0) + { + perror("pclose(3)"); + goto failure; + } + else if (result) + { + fprintf(stderr, "command exited with status %d: %s\n", result, cmd); + goto failure; + } return line; + +failure: + free(line); + return NULL; } static int exec_code(char *program, char *argv[]) @@ -426,10 +442,13 @@ main_build(int argc, char *argv[]) int opt; str_array_t *sources, *images, *utils, *aya; - if (strchr(repo, '\n')) + if (repo) { - *(strchr(repo, '\n')) = '\0'; + char *lf = strchr(repo, '\n'); + *lf = '\0'; } + else + repo = strdup("N/A"); while ((opt = getopt(argc, argv, "sl")) != -1) { From ff5f085b7fdd332156b03d404a23582e80f84630 Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 19 Oct 2024 16:58:48 +0200 Subject: [PATCH 117/186] [FIX/MOD] Stanza send function, fix some errors Negociating stanza sizes seems to be real trouble. Also this code is now `-fanalyzer'-safe! Also kills the last GNUMakefile present. It wasn't even used... --- .forgejo/workflows/check-gcc.yaml | 2 +- README.MD | 3 ++ configure.c | 12 ++++++-- src/FileInfo.c | 2 ++ src/Main.c | 8 +++++ src/Parsee/Config.c | 6 ++++ src/Parsee/Data.c | 4 +-- src/Signal.c | 2 ++ src/StanzaBuilder.c | 7 +---- src/XMPP/Component.c | 21 +++++++++++-- src/XMPP/MUC.c | 28 +++-------------- src/XMPP/Stanza.c | 13 +++----- src/XMPPCommand/Manager.c | 15 ++------- src/XMPPThread/PEPs/Avatar.c | 6 +--- src/XMPPThread/PEPs/VCard.c | 5 +-- src/XMPPThread/PresenceSub.c | 6 +--- src/XMPPThread/ReListener.c | 1 + src/XMPPThread/Stanzas/IQ.c | 51 +++++++++++++++---------------- src/XMPPThread/Stanzas/Message.c | 10 ++---- src/XMPPThread/Stanzas/Presence.c | 15 ++++----- src/include/Parsee.h | 5 +++ src/include/StringStream.h | 2 +- src/include/XMPP.h | 7 +++++ tools/Makefile | 35 --------------------- 24 files changed, 114 insertions(+), 152 deletions(-) delete mode 100644 tools/Makefile diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index bcf2c00..5404fa6 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -33,7 +33,7 @@ jobs: - name: Build Parsee run: | cc configure.c -o configure && ./configure - echo 'CFLAGS=-Werror -Wall -Wextra -pedantic' >> build.conf + echo 'CFLAGS=-Werror -Wall -Wextra -pedantic -fanalyzer' >> build.conf cat build.conf make && make ayadoc - name: Install Parsee diff --git a/README.MD b/README.MD index 786e905..e6e7185 100644 --- a/README.MD +++ b/README.MD @@ -97,6 +97,9 @@ restricted to Parsee admins, with permission from MUC owners, too support XMPP->Matrix bridging. - Manage MUC DMs in a reasonable manner. Thanks `@freeoffers4u:matrix.org` for being a fucking annoyance and DMing an old Parsee semi-anon user for no clear reason. +- Make Parsee cope well with unexcepted stream closures (e.g: with an XMPP server +turning off, etc...). Shutting it off seems like an easy solution, but would go +against principles. ## DONATING/CONTRIBUTING If you know things about XMPP or Matrix, yet aren't familiar with C99, or just diff --git a/configure.c b/configure.c index 574b75f..75d56f4 100644 --- a/configure.c +++ b/configure.c @@ -445,10 +445,15 @@ main_build(int argc, char *argv[]) if (repo) { char *lf = strchr(repo, '\n'); - *lf = '\0'; + if (lf) + { + *lf = '\0'; + } } else + { repo = strdup("N/A"); + } while ((opt = getopt(argc, argv, "sl")) != -1) { @@ -465,8 +470,9 @@ main_build(int argc, char *argv[]) } makefile = fopen("Makefile", "w"); - fprintf(makefile, "# Autogenerated POSIX Makefile\n"); - fprintf(makefile, "# Ideally do not touch.\n\n"); + fprintf(makefile, "# Autogenerated POSIX Makefile from Parsee\n"); + fprintf(makefile, "# Ideally do not touch, unless you have a very "); + fprintf(makefile, "good reason to do it. \n\n"); fprintf(makefile, ".POSIX: \n"); fprintf(makefile, "include build.conf\n\n"); fprintf(makefile, "AYAYAS=ayaya\n"); diff --git a/src/FileInfo.c b/src/FileInfo.c index e242e9d..17974d0 100644 --- a/src/FileInfo.c +++ b/src/FileInfo.c @@ -40,6 +40,8 @@ FileInfoFromXMPP(XMLElement *stanza) file = XMLookForTKV(sims, "file", "xmlns", "urn:xmpp:jingle:apps:file-transfer:5" ); + /* TODO: We'll definitely need MIME types to do things like + * WebXDC */ if (!file) { return NULL; diff --git a/src/Main.c b/src/Main.c index 2ddd35f..d407d60 100644 --- a/src/Main.c +++ b/src/Main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -81,6 +82,13 @@ Main(Array *args, HashMap *env) Log(LOG_INFO, "======================="); Log(LOG_INFO, "(C)opyright 2024 LDA"); Log(LOG_INFO, "(This program is free software, see LICENSE.)"); + +#ifdef PLATFORM_IPHONE + Log(LOG_WARNING, "Wait. Are you running this on an iPhone?"); + Log(LOG_WARNING, "You *ought* to have spoofed this, haven't you?"); + Log(LOG_WARNING, "Simply jealous of you for doing this."); +#endif + LogConfigIndent(LogConfigGlobal()); { diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 541c0a4..c5c23ec 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -62,6 +62,12 @@ ParseeConfigLoad(char *conf) CopyToInt(component_port, "component_port"); CopyToStr(component_host, "component_host"); CopyToStr(shared_comp_secret, "shared_secret"); + CopyToInt(max_stanza_size, "max_stanza_size"); + if (!config->max_stanza_size) + { + /* Standard XMPP "minimum" maximum */ + config->max_stanza_size = 10 KB; + } CopyToStr(media_base, "media_base"); diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 3d2bbb8..0ca2dce 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -59,6 +59,7 @@ ParseeInitData(XMPPComponent *comp) { Log(LOG_WARNING, "Version mismatch(curr=%s db=%s).", VERSION, version); Log(LOG_WARNING, "Yeah. You may want to _not_ do that."); + Log(LOG_WARNING, "(Parsee still needs an upgradepath mechanism.)"); DbUnlock(data->db, ref); DbClose(data->db); @@ -126,8 +127,6 @@ ParseeCleanup(void *datp) uint64_t ts = UtilTsMillis(); size_t entries = 0; - Log(LOG_DEBUG, "Cleaning up..."); - chats = DbList(data->db, 1, "chats"); for (i = 0; i < ArraySize(chats); i++) @@ -242,7 +241,6 @@ ParseeCleanup(void *datp) DbUnlock(data->db, ref); } DbListFree(chats); - Log(LOG_DEBUG, "Cleant up %d entries...", entries); } void diff --git a/src/Signal.c b/src/Signal.c index 4274561..9335897 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -25,6 +25,8 @@ SignalHandler(int signal) if (signal == SIGPIPE) { Log(LOG_DEBUG, "Caught a SIGPIPE..."); + XMPPFinishCompStream(jabber); + pthread_join(xmpp_thr, NULL); return; } } diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 811c6d3..96f22e3 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -237,13 +237,8 @@ WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber) } elem = ExportStanza(builder); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, elem); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, elem); XMLFreeElement(elem); - return; } StanzaBuilder * diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 71f617a..0722460 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -134,7 +135,7 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) } break; } - if (ev->type != XML_LEXER_STARTELEM || + if (!ev || ev->type != XML_LEXER_STARTELEM || !StrEquals(ev->element, "stream:stream")) { Log(LOG_ERR, "Excepted stream:stream element."); @@ -159,10 +160,9 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) } break; } - if (ev->type != XML_LEXER_ELEM || + if (!ev || ev->type != XML_LEXER_ELEM || !StrEquals(ev->element, "handshake")) { - Log(LOG_DEBUG, "type=%d elem='%s'", ev->type, ev->element); Log(LOG_ERR, "Excepted empty handshake reply, got nonsense."); Log(LOG_ERR, "Another service (possibly Parsee) may have taken over."); Log(LOG_ERR, ""); @@ -213,3 +213,18 @@ XMPPEndCompStream(XMPPComponent *comp) Free(comp->host); Free(comp); } +void +XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza) +{ + if (!comp || !stanza) + { + return; + } + + pthread_mutex_lock(&comp->write_lock); + /* TODO: Find a way to negociate to the server about stanza size + * (beyond the 10KB limit that is REQUIRED by XMPP standards) */ + XMLEncode(comp->stream, stanza); + StreamFlush(comp->stream); + pthread_mutex_unlock(&comp->write_lock); +} diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 5d39d78..f97f664 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -18,8 +18,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) return false; } - pthread_mutex_lock(&jabber->write_lock); - iq_query = XMLCreateTag("iq"); query = XMLCreateTag("query"); @@ -35,8 +33,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { XMLElement *identity; - XMLEncode(jabber->stream, iq_query); - StreamFlush(jabber->stream); + XMPPSendStanza(jabber, iq_query); XMLFreeElement(iq_query); /* Except an IQ reply. 10 seconds of timeout is pretty @@ -46,7 +43,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) if (!iq_query || !StrEquals(iq_query->name, "iq")) { XMLFreeElement(iq_query); - pthread_mutex_unlock(&jabber->write_lock); return false; } query = XMLookForUnique(iq_query, "query"); @@ -57,7 +53,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) "conference")) { XMLFreeElement(iq_query); - pthread_mutex_unlock(&jabber->write_lock); return false; } @@ -73,7 +68,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) XMLFreeElement(iq_query); } } - pthread_mutex_unlock(&jabber->write_lock); return true; } @@ -116,7 +110,6 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) return; } - pthread_mutex_lock(&jabber->write_lock); stanza = XMLCreateTag("message"); XMLAddAttr(stanza, "id", (identifier = StrRandom(32))); XMLAddAttr(stanza, "from", from); @@ -160,9 +153,7 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) } XMLAddChild(stanza, x); } - XMLEncode(jabber->stream, stanza); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, stanza); XMLFreeElement(stanza); Free(identifier); @@ -177,8 +168,6 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool return false; } - pthread_mutex_lock(&comp->write_lock); - presence = XMLCreateTag("presence"); x = XMLCreateTag("x"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); @@ -212,14 +201,10 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(presence, x); } - XMLEncode(comp->stream, presence); - StreamFlush(comp->stream); - + XMPPSendStanza(comp, presence); XMLFreeElement(presence); Free(from); - pthread_mutex_unlock(&comp->write_lock); - if (ret && (reply = ParseeAwaitStanza(id, 500))) { bool exit_code = true; @@ -246,8 +231,6 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) return; } - pthread_mutex_lock(&comp->write_lock); - presence = XMLCreateTag("presence"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(presence, "to", muc); @@ -265,12 +248,9 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMPPAnnotatePresence(presence); - XMLEncode(comp->stream, presence); - StreamFlush(comp->stream); + XMPPSendStanza(comp, presence); XMLFreeElement(presence); Free(from); Free(id); - - pthread_mutex_unlock(&comp->write_lock); } diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index e731792..310b2d1 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -66,13 +66,9 @@ XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) } - pthread_mutex_lock(&comp->write_lock); - XMLEncode(comp->stream, message); - StreamFlush(comp->stream); + XMPPSendStanza(comp, message); XMLFreeElement(message); - pthread_mutex_unlock(&comp->write_lock); - Free(from); Free(ident); } @@ -85,6 +81,8 @@ XMPPIsParseeStanza(XMLElement *stanza) return false; } + /* TODO: Check if the user is a trustworthy Parsee puppet instead of some + * guy sending random stanzas */ return !!XMLookForUnique(stanza, "x-parsee"); } @@ -266,10 +264,7 @@ XMPPSendDisco(ParseeData *data, char *from, char *to) XMLAddChild(iq, query); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); ret = ParseeAwaitStanza(identifier, 1.25 SECONDS); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index 580773f..f5714b9 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -274,10 +274,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) x = XMPPFormifyCommand(m, cmd, from); XMLAddChild(command_xml, x); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); goto end; @@ -305,10 +302,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, NULL); XMLAddChild(iq, command_xml); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); InvalidateSession(m, session_id); @@ -348,10 +342,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, x_form); XMLAddChild(iq, command_xml); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); InvalidateSession(m, session_given); diff --git a/src/XMPPThread/PEPs/Avatar.c b/src/XMPPThread/PEPs/Avatar.c index 819bcd0..e2ea636 100644 --- a/src/XMPPThread/PEPs/Avatar.c +++ b/src/XMPPThread/PEPs/Avatar.c @@ -72,11 +72,7 @@ PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) char *url = HashMapGet(item->attrs, "url"); XMLElement *request = CreateAvatarRequest(from, to, id); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, request); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, request); XMLFreeElement(request); (void) url; /* TODO */ diff --git a/src/XMPPThread/PEPs/VCard.c b/src/XMPPThread/PEPs/VCard.c index 1859e97..0ca65be 100644 --- a/src/XMPPThread/PEPs/VCard.c +++ b/src/XMPPThread/PEPs/VCard.c @@ -113,10 +113,7 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) } } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, reply); XMLFreeElement(reply); (void) item; } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c index 3f55bce..13ee9d5 100644 --- a/src/XMPPThread/PresenceSub.c +++ b/src/XMPPThread/PresenceSub.c @@ -131,11 +131,7 @@ ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza) /* TODO: Should we store IDs somewhere? */ XMLAddAttr(sub, "id", (storm_id = StrRandom(16))); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, sub); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, sub); XMLFreeElement(sub); Free(storm_id); end: diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 56d5317..1b5e5f1 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -198,6 +198,7 @@ ParseeXMPPThread(void *argp) stanza = XMLDecode(jabber->stream, false); if (!stanza) { + /* Try to check if an error is abound */ if (args->verbosity >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "RECEIVED EOF."); diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 0f25c4c..44c3697 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -65,6 +65,14 @@ GenerateAvatarData(ParseeData *data, char *mxid) goto end; } b64 = Base64Encode(out, len); + if (!b64 || strlen(b64) > 64 KB) /* We still have stanza limitations. Thanks, Array. + * TODO: Communicate with the server to discover it. */ + { + Free(b64); + Free(mime); + b64 = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ + mime = StrDuplicate("image/png"); + } elem = XMLCreateTag("PHOTO"); type = XMLCreateTag("TYPE"); @@ -145,11 +153,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) } XMLAddChild(iq_reply, query); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq_reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, iq_reply); XMLFreeElement(iq_reply); (void) args; @@ -386,10 +390,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMPPShoveCommandList(thr->info->m, to, q); XMLAddChild(iq_reply, q); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq_reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq_reply); XMLFreeElement(iq_reply); } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) @@ -427,10 +428,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iqVCard); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iqVCard); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -457,10 +455,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iqVCard); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iqVCard); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -474,7 +469,10 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ); if (a_items) { - /* Do, without regret, start shoving an avatar out the bus */ + /* Do, without regret, start shoving an avatar out the bus. + * NOTE: I explicitely choose to not do any manipulation + * because messing with random user images is inherently a + * risk I do *not* want to take. */ char *to_matrix = ParseeDecodeMXID(to); char *avatar = ASGetAvatar(args->config, NULL, to_matrix); char *buf, *mime; @@ -484,6 +482,13 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ASGrab(args->config, avatar, &mime, &buf, &len); b64 = Base64Encode(buf, len); + if (!b64 || strlen(b64) > 64 KB) + { + Free(b64); + Free(mime); + b64 = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ + mime = StrDuplicate("image/png"); + } Free(buf); Log(LOG_DEBUG, "IQ-GET: PUBSUB AVATAR OF=%s", to_matrix); @@ -513,10 +518,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(reply, ps); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, reply); XMLFreeElement(reply); Free(to_matrix); @@ -554,10 +556,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(query, version); XMLAddChild(iq_reply, query); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq_reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq_reply); XMLFreeElement(iq_reply); } else diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 6181616..b9c5810 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -370,19 +370,13 @@ end_error: ps = CreatePubsubRequest( parsee, decode_from, "urn:xmpp:avatar:metadata" ); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, ps); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, ps); XMLFreeElement(ps); ps = CreatePubsubRequest( parsee, trim, "urn:xmpp:avatar:metadata" ); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, ps); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, ps); XMLFreeElement(ps); if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) { diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index dc825f3..2885714 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -158,13 +158,17 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *room = ParseeGetBridgedRoom(args, stanza); char *decode_from, *real_matrix; char *matrix_user_pl = ParseeEncodeJID(args->config, trim, false); - char *affiliation = HashMapGet(item->attrs, "affiliation"); - char *role = HashMapGet(item->attrs, "role"); + char *affiliation = item ? HashMapGet(item->attrs, "affiliation") : NULL; + char *role = item ? HashMapGet(item->attrs, "role") : NULL; int power_level = 0; char *parsee = ParseeMXID(args); char *parsee_j = ParseeJID(args); Free(trim); + if (!item) + { + goto end_item; + } if (jid) { @@ -280,7 +284,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) Free(chat_id); } - +end_item: Free(from); Free(decode_from); Free(real_matrix); @@ -376,11 +380,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) vcard_request = CreateVCardRequest( from, HashMapGet(stanza->attrs, "from") ); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, vcard_request); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, vcard_request); XMLFreeElement(vcard_request); Free(from); } diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 158f563..ea9edcf 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -45,6 +45,7 @@ typedef struct ParseeConfig { char *component_host; char *shared_comp_secret; int component_port; + size_t max_stanza_size; /* ------- DB -------- */ char *db_path; @@ -80,6 +81,7 @@ typedef struct Argument { const char *description; } Argument; +/* A few helpful macros to make JSON less of a PITA */ #define GrabString(obj, ...) JsonValueAsString(JsonGet(obj, __VA_ARGS__)) #define GrabInteger(obj, ...) JsonValueAsInteger(JsonGet(obj, __VA_ARGS__)) #define GrabBoolean(obj, ...) JsonValueAsBoolean(JsonGet(obj, __VA_ARGS__)) @@ -114,6 +116,9 @@ extern void ParseePrintASCII(void); /** * Checks if two versions of Parsee can be considered "compatible". + * This is mainly used for things like database operations. TODO: + * Make an auto-upgrade system to comply with the (undocumented) + * rule of "Don't Make The Sysadmin Think About Parsee Too Much". * --------------- * Modifies: NOTHING */ extern bool ParseeIsCompatible(char *ver1, char *ver2); diff --git a/src/include/StringStream.h b/src/include/StringStream.h index 007a66b..03a25ab 100644 --- a/src/include/StringStream.h +++ b/src/include/StringStream.h @@ -4,7 +4,7 @@ #include /* Creates a string stream writer. The referenced buffer must be in the heap, - * or NULL. */ + * or NULL for an empty string. */ extern Stream * StrStreamWriter(char **buffer); /* Creates a string stream reader. The referenced buffer may be everywhere. */ diff --git a/src/include/XMPP.h b/src/include/XMPP.h index b3f4c09..27cecd0 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -29,6 +29,13 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); * after XMPPInitialiseCompStream. */ extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); +/** Writes an XML stanza through a component, while making sure any locking + * work is done. + * ----------------------- + * Modifies: {comp}, the XMPP stream + * See-Also: XMPPInitialiseCompStream, XMPPAuthenticateCompStream, XMPP-core RFC */ +extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza); + /* Makes a user join/leave a MUC */ extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int secs, bool ret); extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r); diff --git a/tools/Makefile b/tools/Makefile deleted file mode 100644 index 7fa93bc..0000000 --- a/tools/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# Makefile for building Parsee -# ================================ -# TODO: Consider making something akin to a configure script that checks -# for dependencies, or maybe even use *autoconf* (the devil!) - - -# =========================== Parsee Flags ============================= -NAME=Parsee -VERSION=0.0.0 -REPOSITORY=$(shell git remote get-url origin) - -# =========================== Compilation Flags ============================ -CYTO_INC=/usr/local/include/ # Where Cytoplasm's include path is - # located. -CYTO_LIB=/usr/local/lib # Where's Cytoplasm's library is - # located. - -SOURCE=. -OBJECT=out -CC=cc -CFLAGS=-I$(SOURCE) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -g -ggdb -Wall -Werror -LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -g -ggdb -# ============================ Compilation ================================= -SRC_FILES:=$(shell find $(SOURCE) -name '*.c') -OBJ_FILES:=${subst $(SOURCE)/,$(OBJECT)/,$(patsubst %.c, %, $(SRC_FILES))} - -all: $(OBJ_FILES) - -$(OBJECT)/%: $(SOURCE)/%.c - @mkdir -p $(shell dirname "$@") - $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ - -clean: - rm -rf $(OBJECT) - From 02a89270c04e3d395d77d14cac410ead3c8f95c2 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 20 Oct 2024 12:53:07 +0200 Subject: [PATCH 118/186] [FIX] Kill Parsee on unexcepted stream closure --- README.MD | 11 ++++++++--- src/Main.c | 3 ++- src/Parsee/Data.c | 4 ++++ src/Signal.c | 21 +++++++++++---------- src/XMPPThread/ReListener.c | 14 ++++++++++++++ src/include/Parsee.h | 11 ++++++++++- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/README.MD b/README.MD index e6e7185..7522deb 100644 --- a/README.MD +++ b/README.MD @@ -92,14 +92,19 @@ restricted to Parsee admins, with permission from MUC owners, too be false by default. - Currently, MUC owners may kick Parsee out, with the effect of unlinking the MUC. +- Rewrite the XMPP command management to actually be aware of context, instead of +being a baked-in X-macro. It could be useful for MUC admins, which may use commands +specifically within the MUC's own context rather than the global Parsee context(for +Parsee admins). - Look at XEPS-TBD.TXT for XEPs to be done - Add a MUC server to Parsee, such that it may be able to hook onto it and therefore support XMPP->Matrix bridging. - Manage MUC DMs in a reasonable manner. Thanks `@freeoffers4u:matrix.org` for being a fucking annoyance and DMing an old Parsee semi-anon user for no clear reason. -- Make Parsee cope well with unexcepted stream closures (e.g: with an XMPP server -turning off, etc...). Shutting it off seems like an easy solution, but would go -against principles. +- Make Parsee cope with stream closures(i.e: XMPP server turning off) better. As of +now, it just kills itself when that happens, instead of trying to negociate a new +connection, which would be a better method that would actually fit Parsee's own +principles. ## DONATING/CONTRIBUTING If you know things about XMPP or Matrix, yet aren't familiar with C99, or just diff --git a/src/Main.c b/src/Main.c index d407d60..42cc40d 100644 --- a/src/Main.c +++ b/src/Main.c @@ -265,8 +265,9 @@ Main(Array *args, HashMap *env) } server = HttpServerCreate(&conf); + ((ParseeData *) conf.handlerArgs)->server = server; - if (!ParseeInitialiseSignals(server, xmpp_thr, jabber)) + if (!ParseeInitialiseSignals(conf.handlerArgs, xmpp_thr)) { goto end; } diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 0ca2dce..446e766 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -32,6 +32,9 @@ ParseeInitData(XMPPComponent *comp) data->oid_servers = HashMapCreate(); pthread_mutex_init(&data->oidl, NULL); + data->halted = false; + pthread_mutex_init(&data->halt_lock, NULL); + if (data->config->db_size) { data->db = DbOpenLMDB(data->config->db_path, data->config->db_size); @@ -109,6 +112,7 @@ ParseeFreeData(ParseeData *data) } HashMapFree(data->oid_servers); pthread_mutex_destroy(&data->oidl); + pthread_mutex_destroy(&data->halt_lock); Free(data->id); XMPPEndCompStream(data->jabber); DbClose(data->db); diff --git a/src/Signal.c b/src/Signal.c index 9335897..e9d00e8 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -6,39 +6,40 @@ #include -static HttpServer *server = NULL; +static ParseeData *data; static pthread_t xmpp_thr; -static XMPPComponent *jabber = NULL; static void SignalHandler(int signal) { - if (server && (signal == SIGTERM || signal == SIGINT)) + if (data->server && (signal == SIGTERM || signal == SIGINT)) { Log(LOG_INFO, "Killing thread..."); - XMPPFinishCompStream(jabber); + + pthread_mutex_lock(&data->halt_lock); + data->halted = true; + pthread_mutex_unlock(&data->halt_lock); + + XMPPFinishCompStream(data->jabber); pthread_join(xmpp_thr, NULL); Log(LOG_INFO, "Stopping server..."); - HttpServerStop(server); + HttpServerStop(data->server); return; } if (signal == SIGPIPE) { Log(LOG_DEBUG, "Caught a SIGPIPE..."); - XMPPFinishCompStream(jabber); - pthread_join(xmpp_thr, NULL); return; } } bool -ParseeInitialiseSignals(HttpServer *s, pthread_t xmpp, XMPPComponent *j) +ParseeInitialiseSignals(ParseeData *d, pthread_t xmpp) { struct sigaction sa; - server = s; + data = d; xmpp_thr = xmpp; - jabber = j; sigfillset(&sa.sa_mask); sa.sa_handler = SignalHandler; diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 1b5e5f1..0bbfbd5 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -136,6 +136,8 @@ ParseeXMPPThread(void *argp) XMLElement *stanza = NULL; HashMap *await_table2; size_t i; + + bool error = false; /* Initialise the await table */ await_table = HashMapCreate(); @@ -243,6 +245,14 @@ ParseeXMPPThread(void *argp) * few threads to be busy, while the rest of Parsee works. */ PushStanza(&info, stanza); } + pthread_mutex_lock(&args->halt_lock); + if (!args->halted) + { + Log(LOG_WARNING, "XMPP server is closing stream..."); + Log(LOG_WARNING, "Stopping %s...", NAME); + error = true; + } + pthread_mutex_unlock(&args->halt_lock); info.running = false; for (i = 0; i < info.available_dispatchers; i++) @@ -278,6 +288,10 @@ ParseeXMPPThread(void *argp) DestroyPEPManager(info.pep_manager); XMPPFreeManager(info.m); + if (error) + { + HttpServerStop(args->server); /* minor trolling */ + } return NULL; } diff --git a/src/include/Parsee.h b/src/include/Parsee.h index ea9edcf..1cc93bf 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -60,6 +60,7 @@ typedef struct ParseeData { HttpRouter *router; CommandRouter *handler; + HttpServer *server; XMPPComponent *jabber; Db *db; @@ -69,6 +70,10 @@ typedef struct ParseeData { HashMap *oid_servers; pthread_mutex_t oidl; + + /* If Parsee was intentionally halted */ + bool halted; + pthread_mutex_t halt_lock; } ParseeData; typedef struct Argument { @@ -285,7 +290,11 @@ extern bool ParseeGetDMOrigin(ParseeData *data, char *chat_id, char *ev, char ** /* Sends presence requests for every MUC around as a fake JID */ extern void ParseeSendPresence(ParseeData *); -extern bool ParseeInitialiseSignals(HttpServer *, pthread_t, XMPPComponent *); +/** Initialises signal-handling code within Parsee. + * -------------------- + * Modifies: the signal handler + * Returns: whenever it has properly been setup */ +extern bool ParseeInitialiseSignals(ParseeData *data, pthread_t xmpp); /* Job used to cleanup Parsee data that isn't necessary anymore. */ extern void ParseeCleanup(void *data); From 44d6df3be8edb2b3df697293768fdab016b9df48 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 20 Oct 2024 15:12:08 +0200 Subject: [PATCH 119/186] [FIX/CI] Make the C compiler less stupid (You may notice that the dates for these commits are off. I'm currently writing them without an Internet connection, and the device I'm writing this through doesn't have an RTC. Oops!) --- CHANGELOG.md | 27 +++++++++++++++++++++------ src/Parsee/Data.c | 7 ++++--- src/XMPPThread/Bridged.c | 7 ++++--- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d5c0f4..6a99582 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,17 +13,22 @@ commit done between releases. *There is currently no beta releases of Parsee* ## Alpha -### v0.2.0[star-of-hope] +### v0.2.0[star-of-hope] Fixes some media metadata things, replaces the build system, tries out avatar support some more and speeds up Parsee a tad bit. #### New things -- Start dealing with some basic PEP and vCard-based avatars. -- Allows experimental MbedTLS through a specific Cytoplasm -patch. -- Banning Parsee from a XMPP MUC effectively unlinks it. -- Start adding basic documentation to Parsee +- Start dealing with some basic PEP and vCard-based avatar +support from both sides. +- Banning Parsee from a XMPP MUC effectively unlinks it from +the MUC. +- Start adding basic documentation to Parsee, through the +wiki page. - Add MUC whitelists for plumbing, alongside a `whitelist` tool +- Add (yet unused) parameter for setting the max stanza size +allowed. +- Allows experimental MbedTLS through a specific Cytoplasm +patch (though still unstable AND slow). #### Bugfixes - Adds more information to media events so that clients can @@ -34,10 +39,20 @@ Android's weird rendering. - Start fixing bug where Parsee takes several seconds to send a message coming from XMPP with MbedTLS(it is still slow and unstable) +- Fix issue where the XMPP server would kill Parsee if avatars +are too large. +- Refactor some of the code to abstract sending stanzas down +the wire to a specific function, thus allowing us to check +for certain conditions more easily(for example, verifying the +size on the fly, or having extensions being able to postprocess +the stanza). +- Parsee now stops when a stream error is received, instead of +being in a limbo state. #### Deprecated features - The old `build.c` and `Makefile`s used for building are removed, and replaced by the `configure.c` C file(/script via TCC). + ### v0.1.0[tomboyish-bridges-adventure] <9/9/2024> Nothing much to say, but this is the first alpha release of Parsee. May occasionally deadlock. diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 446e766..f858060 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -588,7 +588,7 @@ ParseeUnlinkRoom(ParseeData *data, char *chat_id) bool ParseeIsMUCWhitelisted(ParseeData *data, char *muc) { - char *server, *serv_start; + char *server, *serv_start, *postserv; DbRef *ref; bool ret; if (!data || !muc) @@ -604,9 +604,10 @@ ParseeIsMUCWhitelisted(ParseeData *data, char *muc) serv_start = strchr(muc, '@'); serv_start = serv_start ? serv_start : muc; server = StrDuplicate(serv_start + 1); - if (strchr(server, '/')) + postserv = server ? strchr(server, '/') : NULL; + if (postserv) /* GCC doesn't know strchr is pure. */ { - *(strchr(server, '/')) = '\0'; + *postserv = '\0'; } ref = DbLockIntent(data->db, diff --git a/src/XMPPThread/Bridged.c b/src/XMPPThread/Bridged.c index 7e047a4..0ad23ab 100644 --- a/src/XMPPThread/Bridged.c +++ b/src/XMPPThread/Bridged.c @@ -121,7 +121,7 @@ ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza) bool ServerHasXEP421(ParseeData *data, char *from) { - char *server = NULL, *parsee; + char *server = NULL, *postserv, *parsee; XMLElement *disco; bool ret = false; if (!data || !from) @@ -140,9 +140,10 @@ ServerHasXEP421(ParseeData *data, char *from) } server = StrDuplicate(server); - if (strchr(server, '/')) + postserv = server ? strchr(server, '/') : NULL; + if (postserv) { - *(strchr(server, '/')) = '\0'; + *postserv = '\0'; } parsee = ParseeJID(data); From b0cf0961a32ab1ac221a63aca30273a2910e0a76 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 22 Oct 2024 10:21:54 +0200 Subject: [PATCH 120/186] [FIX] Make codebase *slightly* NetBSD-friendly I need to make it so that NetBSD targets get their own correctness/build checks in CI. I also had to do some hacks with Cytoplasm, will make a PR for those soon. --- CONTRIBUTORS | 14 ++++++++++++++ configure.c | 12 ++++++------ src/AS/Room.c | 4 ++-- src/Command/Parser.c | 4 ++-- src/Main.c | 2 +- src/MatrixEventHandler.c | 2 -- src/Parsee/User.c | 2 +- src/StrSplit.c | 1 - src/XEP-0393.c | 4 ++-- src/XML/SAX.c | 4 ++-- src/XMPPThread/ReListener.c | 1 - src/XMPPThread/Stanzas/IQ.c | 2 +- tools/aya.c | 8 ++++---- 13 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 CONTRIBUTORS diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..c7f8b75 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,14 @@ +# Lines starting with a '#' are ignored. +# This is a list of people who have contributed to Parsee. +# You *may* add some information about yourself after having made a change +# to the repository(or wiki!), with those fields: +# (N) - A nickname +# (L) - An approximate place of residence +# (X) - An XMPP URI +# (M) - A Matrix MXID +# (D) - A short description about yourself +(N): LDA +(L): France +(X): xmpp:lda@monocles.eu +(M): @fourier:ari.lt +(M): @fourier:ari.lt diff --git a/configure.c b/configure.c index 75d56f4..48b541b 100644 --- a/configure.c +++ b/configure.c @@ -531,7 +531,7 @@ main_build(int argc, char *argv[]) fprintf(makefile, "-DNAME=\"\\\"$(NAME)\\\"\" "); fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" "); fprintf(makefile, "-DREPOSITORY=\"\\\"%s\\\"\" ", repo); - fprintf(makefile, "$(CFLAGS) $< -o $@\n"); + fprintf(makefile, "$(CFLAGS) %s -o %s\n", src, obj); } free(ofl); free(obj); @@ -560,8 +560,8 @@ main_build(int argc, char *argv[]) sym = string_rep_ext(sym, ".o", ""); str_array_free(s); - fprintf(makefile, "\ttools/out/b64 $< 'media_%s' '%s.c'\n", sym, obj); - fprintf(makefile, "\t$(CC) -c %s.c -o $@\n", obj); + fprintf(makefile, "\ttools/out/b64 %s 'media_%s' '%s.c'\n", src, sym, obj); + fprintf(makefile, "\t$(CC) -c %s.c -o %s\n", obj, obj); free(sym); } free(obj); @@ -583,12 +583,12 @@ main_build(int argc, char *argv[]) fprintf(makefile, "%s: %s\n", obj, src); { fprintf(makefile, "\t@mkdir -p tools/out\n"); - fprintf(makefile, "\t$(CC) -o $@"); + fprintf(makefile, "\t$(CC) -o %s", obj); if (with_static) { fprintf(makefile, " -static"); } - fprintf(makefile, " $<"); + fprintf(makefile, " %s", src); fprintf(makefile, " -I $(CYTO_INC)"); fprintf(makefile, " -L $(CYTO_LIB)"); if (with_static) @@ -632,7 +632,7 @@ main_build(int argc, char *argv[]) "\ttools/out/aya " "-C etc/ayadoc/style.css " "-p $(NAME) " - "-i $< -o $@\n" + "-i %s -o %s\n", src, obj ); } diff --git a/src/AS/Room.c b/src/AS/Room.c index 3bc7cbf..9e10579 100644 --- a/src/AS/Room.c +++ b/src/AS/Room.c @@ -73,7 +73,7 @@ ASBan(const ParseeConfig *conf, char *id, char *banned) Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); + HashMapSet(json, "reason", JsonValueString(NAME " felt jealous.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); @@ -108,7 +108,7 @@ ASKick(const ParseeConfig *conf, char *id, char *banned) Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); + HashMapSet(json, "reason", JsonValueString(NAME " felt jealous.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); diff --git a/src/Command/Parser.c b/src/Command/Parser.c index fea5007..65f295b 100644 --- a/src/Command/Parser.c +++ b/src/Command/Parser.c @@ -53,7 +53,7 @@ CommandParse(char *cmd) switch (state) { case STATE_WHITE: - if (!isblank(c)) + if (!isblank((int) c)) { state = STATE_NAME; namestart = cur; @@ -84,7 +84,7 @@ CommandParse(char *cmd) { char c = *cur; char cb[2] = { c, '\0' }; - if ((type && c == char_type) || (!type && isblank(c))) + if ((type && c == char_type) || (!type && isblank((int) c))) { break; } diff --git a/src/Main.c b/src/Main.c index 42cc40d..cd1f089 100644 --- a/src/Main.c +++ b/src/Main.c @@ -80,7 +80,7 @@ Main(Array *args, HashMap *env) ); ParseePrintASCII(); Log(LOG_INFO, "======================="); - Log(LOG_INFO, "(C)opyright 2024 LDA"); + Log(LOG_INFO, "(C)opyright 2024 LDA and other contributors"); Log(LOG_INFO, "(This program is free software, see LICENSE.)"); #ifdef PLATFORM_IPHONE diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 0f84789..bae2f3e 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -12,8 +12,6 @@ #include #include -#include - static const char * GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to); diff --git a/src/Parsee/User.c b/src/Parsee/User.c index e68082b..e77f20a 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -165,7 +165,7 @@ ParseeEncodeJID(const ParseeConfig *c, char *jid, bool trim) /* RID: Break everything and die. */ break; } - if (islower(*cs) || isalnum(*cs) || *cs == '_' || + if (islower((int) *cs) || isalnum((int) *cs) || *cs == '_' || *cs == '=' || *cs == '-' || *cs == '/' || *cs == '+' || *cs == '.') { diff --git a/src/StrSplit.c b/src/StrSplit.c index aef23f5..eccd97f 100644 --- a/src/StrSplit.c +++ b/src/StrSplit.c @@ -7,7 +7,6 @@ #include #include #include -#include char ** StrSplitLines(char *text) diff --git a/src/XEP-0393.c b/src/XEP-0393.c index 2976563..a0f6be9 100644 --- a/src/XEP-0393.c +++ b/src/XEP-0393.c @@ -87,7 +87,7 @@ DecodeQuote(StringRect rect, size_t *skip) * > four but that's for Nerds * > seasons See, Touhou reference! * concealing!) */ - while ((ch = StrGet(&rect, lines - 1, shift_by)) && isspace(ch)) + while ((ch = StrGet(&rect, lines - 1, shift_by)) && isspace((int) ch)) { shift_by++; } @@ -132,7 +132,7 @@ DecodeSpan(StringRect rect, char del, size_t *skip) { return StrFullRect(NULL); } - if (!ret.source_lines && isspace(c)) + if (!ret.source_lines && isspace((int) c)) { return StrFullRect(NULL); } diff --git a/src/XML/SAX.c b/src/XML/SAX.c index d21113c..21430bb 100644 --- a/src/XML/SAX.c +++ b/src/XML/SAX.c @@ -337,8 +337,8 @@ seekback: return ret; } -#define IsNamestart(c) ((c == ':') || isalpha(c) || (c == '_')) -#define IsNamepart(c) (IsNamestart(c) || (c == '-') || isdigit(c)) +#define IsNamestart(c) ((c == ':') || isalpha((int) c) || (c == '_')) +#define IsNamepart(c) (IsNamestart(c) || (c == '-') || isdigit((int) c)) static char * XMLParseName(XMLexer *lexer) { diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 0bbfbd5..e8b619f 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 44c3697..33556aa 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -32,7 +32,7 @@ TrimBase64(char *b64) while (*b64) { char ch[2] = { *b64, 0 }; - if (isspace(*b64)) + if (isspace((int) *b64)) { b64++; continue; diff --git a/tools/aya.c b/tools/aya.c index b49fd6b..dc49421 100644 --- a/tools/aya.c +++ b/tools/aya.c @@ -83,7 +83,7 @@ ParseAyadoc(char *raw) if (!strncmp(start, " *", 2) || !strncmp(start, "*", 1)) { start += 1 + (*start == ' '); - while (start && isspace(*start)) + while (start && isspace((int) *start)) { start++; } @@ -112,7 +112,7 @@ ParseAyadoc(char *raw) char *val = del ? del + 1 : NULL; if (del && strlen(del) >= 1) { - while (*val && isspace(*val)) + while (*val && isspace((int) *val)) { val++; } @@ -214,7 +214,7 @@ HandleSeeValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *field { \ char *temporary, *field = NULL, *index; \ char *last_char; \ - while (*start_of_arg && isspace(*start_of_arg)) \ + while (*start_of_arg && isspace((int) *start_of_arg)) \ { \ start_of_arg++; \ } \ @@ -230,7 +230,7 @@ HandleSeeValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *field \ /* Trim out spaces */ \ last_char = separator - 1; \ - while (*last_char && isspace(*last_char)) \ + while (*last_char && isspace((int) *last_char)) \ { \ last_char--; \ } \ From 4b5a759ce7aba05462493230dc79b0124ca60afd Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 22 Oct 2024 10:26:38 +0200 Subject: [PATCH 121/186] [FIX] Fix uninitialised variables I'm not sure why Debian's GCC didn't catch this, but NetBSD's did. Another reason to add CI checks for NetBSD, then, though I am not sure how to do it safely through VMs(and I doubt Docker/Podman would help me for weird architectures). Hm. --- src/XMPPThread/Stanzas/Message.c | 4 ++-- src/XMPPThread/Stanzas/Presence.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index b9c5810..cd606dc 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -230,8 +230,8 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (StrEquals(type, "error")) { - char *type, *text, *user, *parsee; - char *message, *room; + char *type = NULL, *text = NULL, *user = NULL, *parsee = NULL; + char *message = NULL, *room = NULL; from = HashMapGet(stanza->attrs, "from"); to = HashMapGet(stanza->attrs, "to"); diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 2885714..12c06cd 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -156,7 +156,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *trim = ParseeTrimJID(jid); char *from = NULL; char *room = ParseeGetBridgedRoom(args, stanza); - char *decode_from, *real_matrix; + char *decode_from = NULL, *real_matrix = NULL; char *matrix_user_pl = ParseeEncodeJID(args->config, trim, false); char *affiliation = item ? HashMapGet(item->attrs, "affiliation") : NULL; char *role = item ? HashMapGet(item->attrs, "role") : NULL; From fced11269123e1d12cc884024ce228d68008a88f Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 24 Oct 2024 13:26:46 +0200 Subject: [PATCH 122/186] [FIX] Fix CI --- src/XMPPThread/PEP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMPPThread/PEP.c b/src/XMPPThread/PEP.c index f49dcd0..2196ba7 100644 --- a/src/XMPPThread/PEP.c +++ b/src/XMPPThread/PEP.c @@ -116,7 +116,7 @@ static bool PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) { PEPEvent *call = NULL; - XMLElement *event, *ps, *ev; + XMLElement *event = NULL, *ps = NULL, *ev = NULL; size_t i; if (!manager || !stanza) { From ce8bbb554059ea76fd87621f2b21c110b967fb28 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 25 Oct 2024 13:46:55 +0200 Subject: [PATCH 123/186] [MOD] Hide avatar code behind another function --- CHANGELOG.md | 1 + src/XMPPThread/Stanzas/IQ.c | 67 ++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a99582..5aaf0a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ wiki page. allowed. - Allows experimental MbedTLS through a specific Cytoplasm patch (though still unstable AND slow). +- Does basic work towards NetBSD support #### Bugfixes - Adds more information to media events so that clients can diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 33556aa..1cf6de2 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -46,10 +46,43 @@ TrimBase64(char *b64) return ret; } +static bool +AvatarGrab(ParseeData *data, char *mxc, char **mime, char **b64, size_t *len) +{ + char *mimei = NULL, *outi = NULL, *b64i = NULL; + size_t sizei; + if (!data || !mxc || !mime || !b64 || !len) + { + return false; + } + + if (!ASGrab(data->config, mxc, &mimei, &outi, &sizei)) + { + Free(mimei); + Free(outi); + return false; + } + + b64i = Base64Encode(outi, sizei); + Free(outi); + if (!b64i || strlen(b64i) > 64 KB) + { + Free(b64i); + Free(mimei); + b64i = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ + mimei = StrDuplicate("image/png"); + } + + *mime = mimei; + *b64 = b64i; + *len = sizei; + return true; +} + XMLElement * GenerateAvatarData(ParseeData *data, char *mxid) { - char *mxc = NULL, *mime = NULL, *out = NULL, *b64 = NULL; + char *mxc = NULL, *mime = NULL, *b64 = NULL; XMLElement *elem = NULL, *type, *binval; size_t len = 0; if (!data || !mxid) @@ -57,22 +90,12 @@ GenerateAvatarData(ParseeData *data, char *mxid) return NULL; } - /* TODO: Use the right room */ + /* TODO: Use the right room for the avatar! */ mxc = ASGetAvatar(data->config, NULL, mxid); - - if (!mxc || !ASGrab(data->config, mxc, &mime, &out, &len)) + if (!mxc || !AvatarGrab(data, mxc, &mime, &b64, &len)) { goto end; } - b64 = Base64Encode(out, len); - if (!b64 || strlen(b64) > 64 KB) /* We still have stanza limitations. Thanks, Array. - * TODO: Communicate with the server to discover it. */ - { - Free(b64); - Free(mime); - b64 = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ - mime = StrDuplicate("image/png"); - } elem = XMLCreateTag("PHOTO"); type = XMLCreateTag("TYPE"); @@ -86,7 +109,6 @@ GenerateAvatarData(ParseeData *data, char *mxid) end: Free(mime); - Free(out); Free(mxc); Free(b64); return elem; @@ -475,21 +497,12 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) * risk I do *not* want to take. */ char *to_matrix = ParseeDecodeMXID(to); char *avatar = ASGetAvatar(args->config, NULL, to_matrix); - char *buf, *mime; - char *b64; - size_t len; + char *mime = NULL; + char *b64 = NULL; + size_t len = 0; XMLElement *reply; - ASGrab(args->config, avatar, &mime, &buf, &len); - b64 = Base64Encode(buf, len); - if (!b64 || strlen(b64) > 64 KB) - { - Free(b64); - Free(mime); - b64 = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ - mime = StrDuplicate("image/png"); - } - Free(buf); + AvatarGrab(args, avatar, &mime, &b64, &len); Log(LOG_DEBUG, "IQ-GET: PUBSUB AVATAR OF=%s", to_matrix); /* Strike back with a response */ From 7c60ab28cb14c473b9069e27c297280e1043f17e Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 25 Oct 2024 18:03:05 +0200 Subject: [PATCH 124/186] [ADD] Proper stanza limits --- CHANGELOG.md | 6 +++--- etc/man/man1/parsee-config.1 | 7 ++++++- src/MatrixEventHandler.c | 5 ++--- src/Parsee/Config.c | 2 +- src/StanzaBuilder.c | 8 ++++++-- src/XMPP/Component.c | 25 +++++++++++++++++++++---- src/XMPP/MUC.c | 8 ++++---- src/XMPP/Stanza.c | 4 ++-- src/XMPPCommand/Manager.c | 6 +++--- src/XMPPThread/PEPs/Avatar.c | 2 +- src/XMPPThread/PEPs/VCard.c | 2 +- src/XMPPThread/PresenceSub.c | 2 +- src/XMPPThread/Stanzas/IQ.c | 12 ++++++------ src/XMPPThread/Stanzas/Message.c | 4 ++-- src/XMPPThread/Stanzas/Presence.c | 2 +- src/include/StanzaBuilder.h | 2 +- src/include/XMPP.h | 5 +++-- tools/config.c | 11 ++++++++++- 18 files changed, 74 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aaf0a9..cee509e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ commit done between releases. *There is currently no beta releases of Parsee* ## Alpha -### v0.2.0[star-of-hope] +### v0.2.0[star-of-hope] <8/11/2024?> Fixes some media metadata things, replaces the build system, tries out avatar support some more and speeds up Parsee a tad bit. @@ -25,8 +25,8 @@ the MUC. - Start adding basic documentation to Parsee, through the wiki page. - Add MUC whitelists for plumbing, alongside a `whitelist` tool -- Add (yet unused) parameter for setting the max stanza size -allowed. +- Add parameter for setting the max stanza size allowed, with +the default being the XMPP minimum of 10000 bytes. - Allows experimental MbedTLS through a specific Cytoplasm patch (though still unstable AND slow). - Does basic work towards NetBSD support diff --git a/etc/man/man1/parsee-config.1 b/etc/man/man1/parsee-config.1 index cb6e999..a297075 100644 --- a/etc/man/man1/parsee-config.1 +++ b/etc/man/man1/parsee-config.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-config 1 "Parsee Utility" "tomboyish-bridges-adventure" +.TH parsee-config 1 "Parsee Utility" "star-of-hope" .SH NAME parsee-config - generate a basic configuration file @@ -13,6 +13,7 @@ parsee-config .B [-J JABBER_HOST] .B [-p JABBER_PORT] .B [-d DATABASE] +.B [-M MAX_STANZA] .B [-S DATABASE size] .SH DESCRIPTION @@ -54,6 +55,10 @@ For example, if you except Parsee users to be on .I SHARED_SECRET is a shared secret known by Parsee and the XMPP component to authenticate. .TP +.BR -M MAX_STANZA +.I MAX_STANZA +is the maximum stanza size accepted by the XMPP host. If it is less than 10000 bytes, then it shall be set to that limit(the standardised value). +.TP .BR -m MEDIA_URL .I MEDIA_URL is an optional field used by Parsee as an address that points to Matrix diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index bae2f3e..234001b 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -487,7 +487,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) SetStanzaEdit(builder, origin_id); SetStanzaXParsee(builder, event); - WriteoutStanza(builder, jabber); + WriteoutStanza(builder, jabber, data->config->max_stanza_size); DestroyStanzaBuilder(builder); if (direct) @@ -542,8 +542,7 @@ ParseeEventHandler(ParseeData *data, HashMap *event) return; } else if (StrEquals(event_type, "m.room.message") || - StrEquals(event_type, "m.sticker")) /* TODO: Actual sticker - * support here... */ + StrEquals(event_type, "m.sticker")) { ParseeMessageHandler(data, event); Free(parsee); diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index c5c23ec..5361d2a 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -66,7 +66,7 @@ ParseeConfigLoad(char *conf) if (!config->max_stanza_size) { /* Standard XMPP "minimum" maximum */ - config->max_stanza_size = 10 KB; + config->max_stanza_size = 10000; } CopyToStr(media_base, "media_base"); diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 96f22e3..f03c3b6 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -228,16 +228,20 @@ ExportStanza(StanzaBuilder *builder) } void -WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber) +WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max) { XMLElement *elem; if (!builder || !jabber) { return; } + if (!max) + { + max = 10000; /* XMPP recommended limit */ + } elem = ExportStanza(builder); - XMPPSendStanza(jabber, elem); + XMPPSendStanza(jabber, elem, max); XMLFreeElement(elem); } diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 0722460..4440ff0 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -214,17 +214,34 @@ XMPPEndCompStream(XMPPComponent *comp) Free(comp); } void -XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza) +XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max) { + size_t len; + char *c = NULL; + Stream *stringWriter; if (!comp || !stanza) { return; } + stringWriter = StrStreamWriter(&c); + XMLEncode(stringWriter, stanza); + StreamFlush(stringWriter); + StreamClose(stringWriter); + if (c && max && (len = strlen(c)) > max) + { + Log(LOG_WARNING, + "Unexceptedly large stanza received (len=%d max=%d).", + (int) len, (int) max + ); + Free(c); + return; + } + + pthread_mutex_lock(&comp->write_lock); - /* TODO: Find a way to negociate to the server about stanza size - * (beyond the 10KB limit that is REQUIRED by XMPP standards) */ - XMLEncode(comp->stream, stanza); + StreamPrintf(comp->stream, c); StreamFlush(comp->stream); pthread_mutex_unlock(&comp->write_lock); + Free(c); } diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index f97f664..7064698 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -33,7 +33,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { XMLElement *identity; - XMPPSendStanza(jabber, iq_query); + XMPPSendStanza(jabber, iq_query, 10000); XMLFreeElement(iq_query); /* Except an IQ reply. 10 seconds of timeout is pretty @@ -153,7 +153,7 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) } XMLAddChild(stanza, x); } - XMPPSendStanza(jabber, stanza); + XMPPSendStanza(jabber, stanza, 10000); XMLFreeElement(stanza); Free(identifier); @@ -201,7 +201,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(presence, x); } - XMPPSendStanza(comp, presence); + XMPPSendStanza(comp, presence, 10000); XMLFreeElement(presence); Free(from); @@ -248,7 +248,7 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMPPAnnotatePresence(presence); - XMPPSendStanza(comp, presence); + XMPPSendStanza(comp, presence, 10000); XMLFreeElement(presence); Free(from); diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 310b2d1..451c16f 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -66,7 +66,7 @@ XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) } - XMPPSendStanza(comp, message); + XMPPSendStanza(comp, message, 10000); XMLFreeElement(message); Free(from); @@ -264,7 +264,7 @@ XMPPSendDisco(ParseeData *data, char *from, char *to) XMLAddChild(iq, query); } - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, 10000); XMLFreeElement(iq); ret = ParseeAwaitStanza(identifier, 1.25 SECONDS); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index f5714b9..bd38579 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -274,7 +274,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) x = XMPPFormifyCommand(m, cmd, from); XMLAddChild(command_xml, x); - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, data->config->max_stanza_size); XMLFreeElement(iq); goto end; @@ -302,7 +302,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, NULL); XMLAddChild(iq, command_xml); - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, data->config->max_stanza_size); XMLFreeElement(iq); InvalidateSession(m, session_id); @@ -342,7 +342,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, x_form); XMLAddChild(iq, command_xml); - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, data->config->max_stanza_size); XMLFreeElement(iq); InvalidateSession(m, session_given); diff --git a/src/XMPPThread/PEPs/Avatar.c b/src/XMPPThread/PEPs/Avatar.c index e2ea636..c42d260 100644 --- a/src/XMPPThread/PEPs/Avatar.c +++ b/src/XMPPThread/PEPs/Avatar.c @@ -72,7 +72,7 @@ PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) char *url = HashMapGet(item->attrs, "url"); XMLElement *request = CreateAvatarRequest(from, to, id); - XMPPSendStanza(jabber, request); + XMPPSendStanza(jabber, request, args->config->max_stanza_size); XMLFreeElement(request); (void) url; /* TODO */ diff --git a/src/XMPPThread/PEPs/VCard.c b/src/XMPPThread/PEPs/VCard.c index 0ca65be..086e248 100644 --- a/src/XMPPThread/PEPs/VCard.c +++ b/src/XMPPThread/PEPs/VCard.c @@ -113,7 +113,7 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) } } - XMPPSendStanza(jabber, reply); + XMPPSendStanza(jabber, reply, data->config->max_stanza_size); XMLFreeElement(reply); (void) item; } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c index 13ee9d5..dc30400 100644 --- a/src/XMPPThread/PresenceSub.c +++ b/src/XMPPThread/PresenceSub.c @@ -131,7 +131,7 @@ ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza) /* TODO: Should we store IDs somewhere? */ XMLAddAttr(sub, "id", (storm_id = StrRandom(16))); - XMPPSendStanza(jabber, sub); + XMPPSendStanza(jabber, sub, data->config->max_stanza_size); XMLFreeElement(sub); Free(storm_id); end: diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 1cf6de2..d185e4c 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -175,7 +175,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) } XMLAddChild(iq_reply, query); - XMPPSendStanza(jabber, iq_reply); + XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); (void) args; @@ -412,7 +412,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMPPShoveCommandList(thr->info->m, to, q); XMLAddChild(iq_reply, q); } - XMPPSendStanza(jabber, iq_reply); + XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) @@ -450,7 +450,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - XMPPSendStanza(jabber, iqVCard); + XMPPSendStanza(jabber, iqVCard, args->config->max_stanza_size); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -477,7 +477,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - XMPPSendStanza(jabber, iqVCard); + XMPPSendStanza(jabber, iqVCard, args->config->max_stanza_size); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -531,7 +531,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(reply, ps); } - XMPPSendStanza(jabber, reply); + XMPPSendStanza(jabber, reply, args->config->max_stanza_size); XMLFreeElement(reply); Free(to_matrix); @@ -569,7 +569,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(query, version); XMLAddChild(iq_reply, query); - XMPPSendStanza(jabber, iq_reply); + XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); } else diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index cd606dc..69342ca 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -370,13 +370,13 @@ end_error: ps = CreatePubsubRequest( parsee, decode_from, "urn:xmpp:avatar:metadata" ); - XMPPSendStanza(jabber, ps); + XMPPSendStanza(jabber, ps, args->config->max_stanza_size); XMLFreeElement(ps); ps = CreatePubsubRequest( parsee, trim, "urn:xmpp:avatar:metadata" ); - XMPPSendStanza(jabber, ps); + XMPPSendStanza(jabber, ps, args->config->max_stanza_size); XMLFreeElement(ps); if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) { diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 12c06cd..4a66f94 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -381,7 +381,7 @@ end_item: from, HashMapGet(stanza->attrs, "from") ); - XMPPSendStanza(jabber, vcard_request); + XMPPSendStanza(jabber, vcard_request, args->config->max_stanza_size); XMLFreeElement(vcard_request); Free(from); } diff --git a/src/include/StanzaBuilder.h b/src/include/StanzaBuilder.h index e434e43..18b56bb 100644 --- a/src/include/StanzaBuilder.h +++ b/src/include/StanzaBuilder.h @@ -16,7 +16,7 @@ extern StanzaBuilder * SetStanzaID(StanzaBuilder *builder, char *id); extern StanzaBuilder * SetStanzaXParsee(StanzaBuilder *builder, HashMap *e); extern StanzaBuilder * AddStanzaElem(StanzaBuilder *builder, XMLElement *item); extern XMLElement * ExportStanza(StanzaBuilder *builder); -extern void WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber); +extern void WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max); extern void DestroyStanzaBuilder(StanzaBuilder *builder); #endif diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 27cecd0..b2c5293 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -30,11 +30,12 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); /** Writes an XML stanza through a component, while making sure any locking - * work is done. + * work is done. If {max} is non-zero, then this function will not send + * stanzas beyond {max} bytes. * ----------------------- * Modifies: {comp}, the XMPP stream * See-Also: XMPPInitialiseCompStream, XMPPAuthenticateCompStream, XMPP-core RFC */ -extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza); +extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max); /* Makes a user join/leave a MUC */ extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int secs, bool ret); diff --git a/tools/config.c b/tools/config.c index 3881eb1..b949c14 100644 --- a/tools/config.c +++ b/tools/config.c @@ -23,11 +23,12 @@ Main(Array *args, HashMap *env) int flag, code = EXIT_FAILURE; int port = 5347; size_t lmdb_size = 0; + size_t max_stanza = 10000; listen = "localhost"; ArgParseStateInit(&state); - while ((flag = ArgParse(&state, args, "H:J:s:d:p:m:l:S:")) != -1) + while ((flag = ArgParse(&state, args, "H:J:s:d:p:m:l:S:M:")) != -1) { switch (flag) { @@ -56,6 +57,12 @@ Main(Array *args, HashMap *env) case 'S': lmdb_size = strtol(state.optArg, NULL, 10) * 1024 * 1024; break; + case 'M': + max_stanza = strtol(state.optArg, NULL, 10); + if (max_stanza < 10000) + { + max_stanza = 10000; + } } } @@ -71,6 +78,7 @@ Main(Array *args, HashMap *env) "-l [Host/IP to listen as] " "-p [XMPP component port=5347] " "-J [parsee.xmppserver.ex]", + "-M [max stanza size>=10000]", "-S [LMDB size]", ArrayGet(args, 0) ); @@ -109,6 +117,7 @@ Main(Array *args, HashMap *env) JsonSet(json, JsonValueString(jabber), 1, "component_host"); JsonSet(json, JsonValueInteger(port), 1, "component_port"); + JsonSet(json, JsonValueInteger(max_stanza), 1, "max_stanza_size"); JsonSet(json, JsonValueString(jcp), 1, "shared_secret"); From 9a16d96323ed085354c1e8d86ce3b199bbf5bc47 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 27 Oct 2024 19:08:37 +0100 Subject: [PATCH 125/186] [ADD] Filtering XMPP commands This allows us to have commands apply to admins or MUCs only(which would help with many things I want to implement). --- README.MD | 8 +++++- build.conf | 4 +-- src/Routes/Root.c | 8 +++++- src/XMPPCommand/Manager.c | 37 +++++++++++++++++++------ src/XMPPThread/ReListener.c | 46 +++++++++++++++++++++++++++++++- src/XMPPThread/Stanzas/IQ.c | 2 +- src/XMPPThread/Stanzas/Message.c | 4 +-- src/include/XMPPCommand.h | 24 +++++++++++++---- src/include/XMPPCommands.x.h | 25 ++++++++++------- 9 files changed, 127 insertions(+), 31 deletions(-) diff --git a/README.MD b/README.MD index 7522deb..e02db11 100644 --- a/README.MD +++ b/README.MD @@ -55,7 +55,8 @@ parsee-config \ -H 'blow.hole' \ # Matrix homeserver name -J 'parsee.blow.hole' \ # XMPP component host, must be reachable -s 'A very secure XMPP component secret' \ - -p 5347 + -p 5347 \ + -M 65535 # Maximum stanza size. Stanzas larger than this from Parsee will be dropped to avoid stream closures. Leave this empty if you're unsure. ``` If everything goes well, it should generate a `parsee.json` file. @@ -72,7 +73,12 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th ## TODOS before 1.0 rolls around - Make Parsee actually go *vroooooooooommmmmmm*. +- Make sure Parsee can easily run on just about any reasonable POSIX +system. - Avoid making 'back-puppets' from Matrix as much as possible +- Extension support. I'd need to design a good system, and maybe do it +with either shared libraries(`dlopen`/`dlclose` on POSIX) or use a +language like Janet or Lua. - Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency. - It depends on more stuff anyways, and I don't want to weigh down the dependency list of Parsee for that. diff --git a/build.conf b/build.conf index 3e06176..9ebf253 100644 --- a/build.conf +++ b/build.conf @@ -1,6 +1,6 @@ -CODE=tomboyish-bridges-adventure +CODE=star-of-hope NAME=Parsee -VERSION=0.1.0 +VERSION=0.2.0 BINARY=parsee SOURCE=src INCLUDES=src/include diff --git a/src/Routes/Root.c b/src/Routes/Root.c index a68bfbc..0ddb731 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -54,7 +54,13 @@ GetRandomQuote(void) NAME ": the federated world's little little kobashi", "Go take a look at your stanzas!", - "Go take a look at your objects!" + "Go take a look at your objects!", + + "DEC Alpha AXP-Certified!", + + "this is the moment parsee started parsing or smth idk" + " - another wise person", + "Ah, merde, mon TGV est en retard de 53 minutes !" }; const size_t count = sizeof(quotes)/sizeof(*quotes); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index bd38579..69f409a 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -34,7 +34,14 @@ struct XMPPCommandManager { HashMap *sessions; void *cookie; + + XMPPCmdFilter filter; }; +static bool +XMPPDefaultFilter(XMPPCommandManager *manager, char *id, XMLElement *stanza) +{ + return true; +} static void XMPPDestroySession(XMPPSession *session) { @@ -118,6 +125,7 @@ XMPPCreateManager(void *cookie) ret->commands = HashMapCreate(); ret->sessions = HashMapCreate(); ret->cookie = cookie; + ret->filter = XMPPDefaultFilter; return ret; } @@ -161,12 +169,12 @@ XMPPFreeManager(XMPPCommandManager *manager) Free(manager); } void -XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p) +XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement *s) { char *node_name; XMPPCommand *val; XMLElement *item; - if (!m || !p || !jid) + if (!m || !p || !jid || !s) { return; } @@ -174,11 +182,14 @@ XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p) pthread_mutex_lock(&m->lock); while (HashMapIterate(m->commands, &node_name, (void **) &val)) { - item = XMLCreateTag("item"); - XMLAddAttr(item, "jid", jid); - XMLAddAttr(item, "node", node_name); - XMLAddAttr(item, "name", XMPPGetCommandDesc(val)); - XMLAddChild(p, item); + if (m->filter(m, node_name, s)) + { + item = XMLCreateTag("item"); + XMLAddAttr(item, "jid", jid); + XMLAddAttr(item, "node", node_name); + XMLAddAttr(item, "name", XMPPGetCommandDesc(val)); + XMLAddChild(p, item); + } } pthread_mutex_unlock(&m->lock); } @@ -206,6 +217,16 @@ XMPPVerifySession(XMPPCommandManager *mgr, char *s_id, char *from, char *to) return ret; } + +void +XMPPManagerSetFilter(XMPPCommandManager *manager, XMPPCmdFilter filter) +{ + if (!manager || !filter) + { + return; + } + manager->filter = filter; +} bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) { @@ -242,7 +263,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) /* This is an execution. */ cmd = HashMapGet(m->commands, node); - if (!cmd) + if (!cmd || !m->filter(m, node, stanza)) { /* TODO: Set an error note */ goto end; diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index e8b619f..559ffcb 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -126,6 +126,49 @@ ParseeCongestion(void) return congestion; } +bool +XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza) +{ + ParseeData *args = XMPPGetManagerCookie(m); + char *trimmed_from; + char *from; + char *chat_id; + bool is_muc; + if (!m || !id || !stanza) + { + return false; + } + + from = HashMapGet(stanza->attrs, "from"); + trimmed_from = ParseeTrimJID(from); + is_muc = !!(chat_id = ParseeGetFromMUCID(args, trimmed_from)); + Free(trimmed_from); + Free(chat_id); +#define XMPP_COMMAND(f,l,n,t,s) \ + if (StrEquals(n, id)) \ + { \ + if (l == XMPPCMD_ALL) \ + { \ + return true; \ + } \ + else if (l == XMPPCMD_MUC) \ + { \ + return is_muc; \ + } \ + else if (l == XMPPCMD_ADMINS) \ + { \ + bool is_admin; \ + trimmed_from = ParseeTrimJID(from); \ + is_admin = ParseeIsAdmin(args, trimmed_from); \ + Free(trimmed_from); \ + return is_admin; \ + } \ + } + XMPPCOMMANDS +#undef XMPP_COMMAND + + return false; +} void * ParseeXMPPThread(void *argp) @@ -143,9 +186,10 @@ ParseeXMPPThread(void *argp) /* Initialise the managers, and add all handlers. */ info.m = XMPPCreateManager(args); + XMPPManagerSetFilter(info.m, XMPPCommandFilter); { XMPPCommand *cmd; -#define XMPP_COMMAND(f,n,t,s) \ +#define XMPP_COMMAND(f,l,n,t,s) \ cmd = XMPPBasicCmd( \ n, t, f \ ); \ diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index d185e4c..e944168 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -409,7 +409,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLElement *q = XMLCreateTag("query"); XMLAddAttr(q, "xmlns", "http://jabber.org/protocol/disco#items"); XMLAddAttr(q, "node", "http://jabber.org/protocol/commands"); - XMPPShoveCommandList(thr->info->m, to, q); + XMPPShoveCommandList(thr->info->m, to, q, stanza); XMLAddChild(iq_reply, q); } XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 69342ca..d72d4d9 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -472,13 +472,13 @@ end_error: reaction = ArrayGet(react_child, i); react_data = ArrayGet(reaction->children, 0); - event_id = LazySend( + Free(LazySend( args, encoded, mroom_id, "m.reaction", ShoveStanza( MatrixCreateReact(event_id, react_data->data), stanza ) - ); + )); } Free(event_id); event_id = NULL; diff --git a/src/include/XMPPCommand.h b/src/include/XMPPCommand.h index 2680a64..33b121f 100644 --- a/src/include/XMPPCommand.h +++ b/src/include/XMPPCommand.h @@ -12,6 +12,7 @@ typedef struct XMPPCommand XMPPCommand; typedef struct XMPPOption XMPPOption; typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, XMLElement *, XMLElement *); typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *); +typedef bool (*XMPPCmdFilter)(XMPPCommandManager *, char *id, XMLElement *stanza); /** Creates a simple XMPP command manager, which routes commands * with a single-stage form system, with a {cookie} @@ -19,16 +20,28 @@ typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *); * Returns: An opaque command manager[LA:HEAP] * Modifies: NOTHING * See-Also: XMPPFreeManager */ -extern XMPPCommandManager * XMPPCreateManager(void *cookie); +extern XMPPCommandManager * XMPPCreateManager(void *cookie); extern void * XMPPGetManagerCookie(XMPPCommandManager *manager); +/** Changes the filter used for the command manager. This function + * takes in the source stanza and the command "ID" to filter, and + * returns true IFF the command should be shown to the requester. + * ----------- + * Returns: NOTHING + * Modifies: the manager's filter + * See-Also: XMPPCreateManager */ +extern void +XMPPManagerSetFilter(XMPPCommandManager *manager, XMPPCmdFilter filter); + /** Create a basic command with a node and name description * ----------------------------------------------------- * Returns: A command to be used with {XMPPRegisterCommand}[LA:HEAP] * Modifies: NOTHING * See-Also: XMPPRegisterCommand */ -extern XMPPCommand * XMPPBasicCmd(char *node, char *name, XMPPCmdCallback cb); -extern void XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer); +extern XMPPCommand * + XMPPBasicCmd(char *node, char *name, XMPPCmdCallback cb); +extern void +XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer); extern void XMPPAddOption(XMPPCommand *cmd, XMPPOption *opt); extern XMLElement * XMPPFormifyCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from); extern char * XMPPGetCommandNode(XMPPCommand *cmd); @@ -71,11 +84,12 @@ extern bool XMPPVerifyForm(XMPPCommand *cmd, XMLElement *form); extern void XMPPRegisterCommand(XMPPCommandManager *m, XMPPCommand *cmd); /** Shoves all {m} commands into XML as children of {p}, and a {jid} + * (and with the stanza source) * ----------------------------------------------------- * Returns: NOTHING * Modifies: {p} * See-Also: XMPPCreateManager */ -extern void XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p); +extern void XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement *s); /** Destroys all memory related to the command {manager}. * ----------------------------------------------------- @@ -95,7 +109,7 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD /* --------------------------------- COMMANDS --------------------------------- */ /* Please edit stc/XMPPThread.c (you can just force-save) for these to apply! */ -#define XMPP_COMMAND(f,n,t,s) \ +#define XMPP_COMMAND(f,l,n,t,s) \ extern void \ f(XMPPCommandManager *, char *, XMLElement *, XMLElement *); \ /* This symbol might not exist. We do, however, not care, as diff --git a/src/include/XMPPCommands.x.h b/src/include/XMPPCommands.x.h index eaeb5b9..5000a2f 100644 --- a/src/include/XMPPCommands.x.h +++ b/src/include/XMPPCommands.x.h @@ -1,10 +1,15 @@ /* C X-macro file */ +typedef enum XMPPCommandFlags { + XMPPCMD_ALL = 0, + XMPPCMD_MUC , /* Only for MUCs */ + XMPPCMD_ADMINS /* Only for administrators */ +} XMPPCommandFlags; #define XMPPCOMMANDS \ - XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \ - XMPP_COMMAND(CleanCallback, "clean", "Cleanup temporary Parsee data", {}) \ - XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \ - XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) \ - XMPP_COMMAND(AddAdminCallback, "add-admin", "Adds glob as admin", { \ + XMPP_COMMAND(StatusCallback, XMPPCMD_ALL, "stats", "Get Parsee statistics", {}) \ + XMPP_COMMAND(CleanCallback, XMPPCMD_ADMINS, "clean", "Cleanup temporary Parsee data", {}) \ + XMPP_COMMAND(AdminsCallback, XMPPCMD_ALL, "admin", "Get Parsee admin list", {}) \ + XMPP_COMMAND(NoflyCallback, XMPPCMD_ADMINS, "nofly", "Get Parsee nofly list", {}) \ + XMPP_COMMAND(AddAdminCallback, XMPPCMD_ADMINS, "add-admin", "Adds glob as admin", { \ XMPPOption *glob = XMPPCreateText(true, "glob", ""); \ XMPPSetDescription(glob, "Glob pattern to set as admin"); \ XMPPAddOption(cmd, glob); \ @@ -12,12 +17,12 @@ XMPPSetFormTitle(cmd, "Admin addition form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to add as an admin"); \ }) \ - XMPP_COMMAND(DelAdminCallback, "del-admin", "Removes glob from being admin", { \ + XMPP_COMMAND(DelAdminCallback, XMPPCMD_ADMINS, "del-admin", "Removes glob from being admin", { \ XMPPCmdOptionsCreator(cmd, FormDelAdminCallback); \ XMPPSetFormTitle(cmd, "Admin removal form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to remove as an admin"); \ }) \ - XMPP_COMMAND(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \ + XMPP_COMMAND(AddNoflyCallback, XMPPCMD_ADMINS, "add-nofly", "Adds user to nofly", { \ XMPPOption *entity = XMPPCreateText(true, "entity", ""); \ XMPPOption *reason = XMPPCreateText(false, "reason", "Not behaving"); \ XMPPSetDescription(entity, "Entity(glob) to no-fly"); \ @@ -28,8 +33,8 @@ XMPPSetFormTitle(cmd, "No-fly addition form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \ }) \ - XMPP_COMMAND(ClearWhitelistCallback, "clear-wl", "Removes the chat whitelist", {}) \ - XMPP_COMMAND(AddWhitelistCallback, "add-wl", "Adds server to chat whitelist", { \ + XMPP_COMMAND(ClearWhitelistCallback, XMPPCMD_ADMINS, "clear-wl", "Removes the chat whitelist", {}) \ + XMPP_COMMAND(AddWhitelistCallback, XMPPCMD_ADMINS, "add-wl", "Adds server to chat whitelist", { \ XMPPOption *serv = XMPPCreateText(true, "entity", ""); \ XMPPSetDescription(serv, "Server to mark as admin"); \ XMPPAddOption(cmd, serv); \ @@ -37,6 +42,6 @@ XMPPSetFormTitle(cmd, "Chatlist addition form"); \ XMPPSetFormInstruction(cmd, "Add a server to whitelist"); \ }) \ - XMPP_COMMAND(WhitelistCallback, "wl", "Get Parsee's chat whitelist", {}) \ + XMPP_COMMAND(WhitelistCallback, XMPPCMD_ADMINS, "wl", "Get Parsee's chat whitelist", {}) \ XMPPCOMMANDS From d4371ac30b951af605368cf5049b838884dfb954 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 27 Oct 2024 20:40:25 +0100 Subject: [PATCH 126/186] [META] Update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cee509e..2c9f368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,8 @@ wiki page. the default being the XMPP minimum of 10000 bytes. - Allows experimental MbedTLS through a specific Cytoplasm patch (though still unstable AND slow). -- Does basic work towards NetBSD support +- Does basic work towards NetBSD support(especially with DEC Alpha) +- Start contextualising XMPP commands(all/Parsee admins/MUCs). #### Bugfixes - Adds more information to media events so that clients can From 7f7ab41afa8b94b1da05e1a0b6d742ad1d84b10a Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Oct 2024 08:57:17 +0100 Subject: [PATCH 127/186] [ADD] Add a few basic MUC commands --- src/XMPPCommands/Admins.c | 6 ---- src/XMPPCommands/MUCInformation.c | 49 +++++++++++++++++++++++++++++++ src/XMPPCommands/Status.c | 7 ----- src/XMPPThread/Stanzas/IQ.c | 20 ++++++++++++- src/include/XMPPCommands.x.h | 2 ++ 5 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 src/XMPPCommands/MUCInformation.c diff --git a/src/XMPPCommands/Admins.c b/src/XMPPCommands/Admins.c index 1baf789..f126fc4 100644 --- a/src/XMPPCommands/Admins.c +++ b/src/XMPPCommands/Admins.c @@ -21,12 +21,6 @@ AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * XMLElement *title; XMLElement *reported, *item, *field, *value, *txt; - if (!ParseeIsAdmin(data, trimmed)) - { - SetNote("error", "User is not authorised to execute command."); - Free(trimmed); - return; - } Free(trimmed); x = XMLCreateTag("x"); title = XMLCreateTag("title"); diff --git a/src/XMPPCommands/MUCInformation.c b/src/XMPPCommands/MUCInformation.c new file mode 100644 index 0000000..53dc684 --- /dev/null +++ b/src/XMPPCommands/MUCInformation.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +void +MUCInformationID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *muc = ParseeTrimJID(from); + char *chat_id = ParseeGetFromMUCID(data, muc); + char *room_id = ParseeGetRoomID(data, chat_id); + char *msg = StrConcat(5, + "The MUC ", muc, " is bridged to ", room_id, "." + ); + + SetNote("info", msg); + + Free(muc); + Free(msg); + Free(room_id); + Free(chat_id); + (void) form; +} +void +MUCInformationCID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *muc = ParseeTrimJID(from); + char *chat_id = ParseeGetFromMUCID(data, muc); + char *msg = StrConcat(5, + "The MUC ", muc, "'s internal ID is ", chat_id, "." + ); + + SetNote("info", msg); + + Free(muc); + Free(msg); + Free(chat_id); + (void) form; +} diff --git a/src/XMPPCommands/Status.c b/src/XMPPCommands/Status.c index f1a0b73..8e72c98 100644 --- a/src/XMPPCommands/Status.c +++ b/src/XMPPCommands/Status.c @@ -26,13 +26,6 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * XMLElement *x; XMLElement *title, *txt; - if (!ParseeIsAdmin(data, trimmed)) - { - SetNote("error", "User is not authorised to execute command."); - - Free(trimmed); - return; - } Free(trimmed); x = XMLCreateTag("x"); title = XMLCreateTag("title"); diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index e944168..562fc22 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -387,6 +387,16 @@ IQIsCommandList(ParseeData *args, XMLElement *stanza) return ret; } +static bool +IsInMUC(ParseeData *data, char *jid) +{ + char *trimmed = ParseeTrimJID(jid); + char *chat_id = ParseeGetFromMUCID(data, trimmed); + + Free(trimmed); + Free(chat_id); + return !!chat_id; +} void IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { @@ -401,19 +411,27 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (IQIsCommandList(args, stanza)) { XMLElement *iq_reply = XMLCreateTag("iq"); + char *trimmed = ParseeTrimJID(from); + XMLAddAttr(iq_reply, "type", "result"); XMLAddAttr(iq_reply, "from", to); XMLAddAttr(iq_reply, "to", from); XMLAddAttr(iq_reply, "id", id); { XMLElement *q = XMLCreateTag("query"); + char *parsee_muc_jid = StrConcat(3, trimmed, "/", "parsee"); XMLAddAttr(q, "xmlns", "http://jabber.org/protocol/disco#items"); XMLAddAttr(q, "node", "http://jabber.org/protocol/commands"); - XMPPShoveCommandList(thr->info->m, to, q, stanza); + XMPPShoveCommandList(thr->info->m, + IsInMUC(args, from) ? parsee_muc_jid : to, + q, stanza + ); XMLAddChild(iq_reply, q); + Free(parsee_muc_jid); } XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); + Free(trimmed); } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) { diff --git a/src/include/XMPPCommands.x.h b/src/include/XMPPCommands.x.h index 5000a2f..01b27fb 100644 --- a/src/include/XMPPCommands.x.h +++ b/src/include/XMPPCommands.x.h @@ -43,5 +43,7 @@ typedef enum XMPPCommandFlags { XMPPSetFormInstruction(cmd, "Add a server to whitelist"); \ }) \ XMPP_COMMAND(WhitelistCallback, XMPPCMD_ADMINS, "wl", "Get Parsee's chat whitelist", {}) \ + XMPP_COMMAND(MUCInformationID, XMPPCMD_MUC, "muc-info-id", "Get bridged Matrix room ID", {}) \ + XMPP_COMMAND(MUCInformationCID, XMPPCMD_MUC, "muc-info-cid", "Get MUC's internal ID", {}) \ XMPPCOMMANDS From 6aef0349b85ad7a9dea610dada6db624e8e1d87c Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Oct 2024 09:08:08 +0100 Subject: [PATCH 128/186] [CI/FIX] Make CI happy again --- src/XMPPCommands/Admins.c | 2 -- src/XMPPCommands/Status.c | 1 - 2 files changed, 3 deletions(-) diff --git a/src/XMPPCommands/Admins.c b/src/XMPPCommands/Admins.c index f126fc4..3219b71 100644 --- a/src/XMPPCommands/Admins.c +++ b/src/XMPPCommands/Admins.c @@ -15,13 +15,11 @@ void AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) { ParseeData *data = XMPPGetManagerCookie(m); - char *trimmed = ParseeTrimJID(from); size_t i; XMLElement *x; XMLElement *title; XMLElement *reported, *item, *field, *value, *txt; - Free(trimmed); x = XMLCreateTag("x"); title = XMLCreateTag("title"); diff --git a/src/XMPPCommands/Status.c b/src/XMPPCommands/Status.c index 8e72c98..16265ff 100644 --- a/src/XMPPCommands/Status.c +++ b/src/XMPPCommands/Status.c @@ -14,7 +14,6 @@ void StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) { - ParseeData *data = XMPPGetManagerCookie(m); char *trimmed = ParseeTrimJID(from); size_t alloc = MemoryAllocated(); size_t kb = alloc >> 10; From dcd31201ab9217c9f9872b99115452a62d8278fb Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Oct 2024 10:44:23 +0100 Subject: [PATCH 129/186] [CI/FIX] Fix unused argument --- src/XMPPCommands/Admins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/XMPPCommands/Admins.c b/src/XMPPCommands/Admins.c index 3219b71..5749165 100644 --- a/src/XMPPCommands/Admins.c +++ b/src/XMPPCommands/Admins.c @@ -52,4 +52,5 @@ AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * XMLAddChild(out, x); (void) form; + (void) from; } From 947c2d48d2f608998a9859b433fd48da6fe8219d Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Oct 2024 10:47:54 +0100 Subject: [PATCH 130/186] [CI/FIX] Fix unused argument again --- src/XMPPCommands/Status.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/XMPPCommands/Status.c b/src/XMPPCommands/Status.c index 16265ff..1b19129 100644 --- a/src/XMPPCommands/Status.c +++ b/src/XMPPCommands/Status.c @@ -69,4 +69,5 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * XMLAddChild(out, x); (void) form; + (void) m; } From ca5f8fd5c526c1fb746ea1cb2745e47ea363cf98 Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Oct 2024 10:51:49 +0100 Subject: [PATCH 131/186] [CI/FIX] Fix unused argument again (again) --- src/XMPPCommand/Manager.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index 69f409a..00a8c89 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -40,6 +40,9 @@ struct XMPPCommandManager { static bool XMPPDefaultFilter(XMPPCommandManager *manager, char *id, XMLElement *stanza) { + (void) manager; + (void) stanza; + (void) id; return true; } static void From 55ac682d26d2787cd2b291c1ebfd7b1df9aea3dd Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Oct 2024 13:26:25 +0100 Subject: [PATCH 132/186] [MOD] Timestamp Matrix messages --- etc/media/unknown.png | Bin 0 -> 542 bytes src/AS/Send.c | 30 +++++++++++++++++++++++++++--- src/MatrixEventHandler.c | 4 ++-- src/XMPPThread/Stanzas/IQ.c | 2 +- src/XMPPThread/Stanzas/Message.c | 19 ++++++++++--------- src/XMPPThread/Stanzas/Presence.c | 3 ++- src/include/AS.h | 3 ++- src/include/Bot.h | 4 ++-- src/include/Parsee.h | 2 ++ 9 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 etc/media/unknown.png diff --git a/etc/media/unknown.png b/etc/media/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..00ccf916cadd9c3b5995a00dade4d053fc87089f GIT binary patch literal 542 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`Bn0?`xB_V) zaMiF$vo!1vv%X)bc5^}6yTh}7e=?i-G$3oAf%%j??@aw5Zxx16M+O%YgM_B&yobrN z|Hq$wa{Bh4|NsBbUc0@eu01m=D>5vo%&BXQkrB{91tp&T>0Vv=2FIrb90l=9g8YIR zfU5CEaj?(fanP@1_<79+n4p8n{<{w|_QesoIjy%qeMx+?A_0zWBy` z)cyGM=6g-sAJ}u<68x8I^eA%SgPynNE$Y{B{xT`o;qdvhYK9oYzU&#o1ukZWW)@5{ z_gV5LAGED(7L@E!IML1~((>~}LzBgM-jxq#J$)`Yozr0b{NsPQS;|-irfc7m+TyS_ z;kZq8lB55<#Y}tI1UwEMd+Ni(n)RU1kMq)>SqDz8=bTgHyI`H@H;4GBIl z-_)wIH?S6nU74Z%f}QIaZ?x71md))_4NRZyPwr#+5bEl9_~o<97m64q-Yn;QF5PJM z!137cYNp(VJ#*i3NY(XE`fbfrT$13<)}(S)wlhIuzqZoBE0IU`F8KGaxbm+_#?OBV z3%vH_F9_O~{h(>PwA55zFA|>gTe~ HDWM4f=^pg& literal 0 HcmV?d00001 diff --git a/src/AS/Send.c b/src/AS/Send.c index 4032423..766f393 100644 --- a/src/AS/Send.c +++ b/src/AS/Send.c @@ -1,21 +1,38 @@ #include #include +#include #include #include #include +#include #include #include +#include #include +static char * +TSToStr(uint64_t ts) +{ + size_t len; + char *str; + + len = snprintf(NULL, 0, "%"PRIu64, ts); + str = Malloc(len+1); + snprintf(str, len+1, "%"PRIu64, ts); + + return str; +} + char * -ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) +ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c, uint64_t ts) { HttpClientContext *ctx = NULL; char *path; char *txn, *ret; + char *ts_str; HashMap *reply; if (!conf || !id || !type || !user || !c) { @@ -23,13 +40,20 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) return NULL; } + if (!ts) + { + ts = UtilTsMillis(); + } + ts_str = TSToStr(ts); + txn = StrRandom(16); - path = StrConcat(9, + path = StrConcat(11, "/_matrix/client/v3/rooms/", id, "/send/", type, "/", txn, "?", - "user_id=", user + "user_id=", user, "&ts=", ts_str ); Free(txn); + Free(ts_str); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 234001b..3d6a69e 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -263,7 +263,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) Free(ASSend( data->config, id, profile, "m.room.message", - MatrixCreateNotice("Please enter a valid command") + MatrixCreateNotice("Please enter a valid command"), 0 )); Free(profile); return; @@ -274,7 +274,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) Free(ASSend( data->config, id, profile, "m.room.message", - MatrixCreateNotice("You are not authorised to do this.") + MatrixCreateNotice("You are not authorised to do this."), 0 )); Free(profile); return; diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 562fc22..32aa0c9 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -69,7 +69,7 @@ AvatarGrab(ParseeData *data, char *mxc, char **mime, char **b64, size_t *len) { Free(b64i); Free(mimei); - b64i = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ + b64i = StrDuplicate(media_unknown); /* TODO: Different assets! */ mimei = StrDuplicate("image/png"); } diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index d72d4d9..0962fc0 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -43,7 +43,7 @@ LazyRegister(ParseeData *data, char *mxid, char *name) Free(hash); } static char * -LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev) +LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev, uint64_t ts) { HashMap *duplicate; char *event; @@ -59,8 +59,7 @@ LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev) duplicate = JsonDuplicate(ev); event = ASSend( args->config, mroom_id, mxid, - type, - ev + type, ev, ts ); if (event) { @@ -73,7 +72,7 @@ LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev) return ASSend( args->config, mroom_id, mxid, - type, duplicate + type, duplicate, ts ); } @@ -254,7 +253,8 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) room = ParseeGetBridgedRoom(args, stanza); Free(LazySend( args, parsee, room, NULL, - MatrixCreateNotice(message) + MatrixCreateNotice(message), + time )); end_error: @@ -431,7 +431,7 @@ end_error: event_id = LazySend( args, encoded, mroom_id, NULL, - content + content, time ); Free(mxc); } @@ -477,7 +477,8 @@ end_error: ShoveStanza( MatrixCreateReact(event_id, react_data->data), stanza - ) + ), + time )); } Free(event_id); @@ -510,7 +511,7 @@ end_error: ShoveStanza(ev, stanza); event_id = LazySend( args, encoded, mroom_id, NULL, - ev + ev, time ); } pthread_mutex_lock(&thr->info->chk_lock); @@ -533,7 +534,7 @@ end_error: Log(LOG_DEBUG, "Replacing events in %s(%s)", mroom_id, event_id); Free(LazySend( args, encoded, mroom_id, NULL, - ev + ev, time )); ParseePushAllStanza(args, stanza, event_id); pthread_mutex_unlock(&thr->info->chk_lock); diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 4a66f94..5c7c21d 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -278,7 +278,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) Free(ASSend( args->config, room, parsee, "m.room.message", - MatrixCreateNotice("This room has been unlinked.") + MatrixCreateNotice("This room has been unlinked."), + 0 )); ASLeave(args->config, room, parsee); Free(chat_id); diff --git a/src/include/AS.h b/src/include/AS.h index ad91e60..8afef6f 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -67,7 +67,8 @@ extern HashMap * ASFind(const ParseeConfig *, char *, char *); /* Sends a message event with a specific type and body. * Said body is freed during the function's execution. */ -extern char * ASSend(const ParseeConfig *, char *, char *, char *, HashMap *); +extern char * +ASSend(const ParseeConfig *, char *, char *, char *, HashMap *, uint64_t ts); extern void ASType(const ParseeConfig *, char *, char *, bool); extern void ASPresence(const ParseeConfig *, char *, char *, char *); diff --git a/src/include/Bot.h b/src/include/Bot.h index e2c0340..3154a3a 100644 --- a/src/include/Bot.h +++ b/src/include/Bot.h @@ -26,7 +26,7 @@ Free(ASSend( \ data->config, id, profile, \ "m.room.message", \ - MatrixCreateNotice(rep) \ + MatrixCreateNotice(rep), 0 \ )); \ } \ while(0) @@ -45,7 +45,7 @@ Free(ASSend( \ data->config, id, profile, \ "m.room.message", \ - MatrixCreateNotice(formatted) \ + MatrixCreateNotice(formatted), 0 \ )); \ Free(formatted); \ } \ diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 1cc93bf..6b2d9cc 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -107,6 +107,8 @@ typedef struct Argument { /* A base64-encoded Parsee logo */ extern const char media_parsee_logo[]; +/* "Unknown avatar" */ +extern const char media_unknown[]; /* An ASCII-art rendition of "小橋". * I'm sorry for its quality. If anyone wants to redraw it, feel free. */ From 064040c18f5035f999b80f2a3f11a079bb377d24 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 29 Oct 2024 14:44:55 +0100 Subject: [PATCH 133/186] [ADD/WIP] Chat settings Right now, they are currently unused. Extensions, and Parsee itself will be able to use those, though. --- DATES.TXT | 6 +- README.MD | 4 - etc/man/man1/parsee-adminify.1 | 2 +- etc/man/man1/parsee-aya.1 | 2 +- etc/man/man1/parsee.1 | 2 +- src/Main.c | 7 ++ src/Parsee/Config.c | 1 + src/Parsee/Data.c | 87 ++++++++++++++++++++++ src/Parsee/Tables/Affiliation.c | 106 +++++++++++++++++++++++++++ src/Parsee/Utils/Formatting.c | 1 + src/XMPPCommands/MUCKV.c | 117 ++++++++++++++++++++++++++++++ src/XMPPCommands/MUCUnlink.c | 67 +++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 2 +- src/XMPPThread/Stanzas/Presence.c | 1 + src/include/Parsee.h | 43 +++++++++++ src/include/XMPPCommands.x.h | 13 ++++ tools/adminify.c | 2 +- 17 files changed, 449 insertions(+), 14 deletions(-) create mode 100644 src/Parsee/Tables/Affiliation.c create mode 100644 src/XMPPCommands/MUCKV.c create mode 100644 src/XMPPCommands/MUCUnlink.c diff --git a/DATES.TXT b/DATES.TXT index f54dbc0..4da14dc 100644 --- a/DATES.TXT +++ b/DATES.TXT @@ -1,7 +1,3 @@ Some dates for Parsee-related events. They mostly serve as LDA's TODOs with a strict deadline: - - ~September 2024[tomboyish-bridges-adventure]: - Get Parsee into the _Phantasmagoria of Bug View_ stage (essentially - v0.0.1 for a public testing) once I can afford `yama`, and start - bridging the Matrix room alongside a shiny XMPP MUC, bridged by - yours truly. + - Get star-of-hope out by November 8 diff --git a/README.MD b/README.MD index e02db11..1d4b711 100644 --- a/README.MD +++ b/README.MD @@ -98,10 +98,6 @@ restricted to Parsee admins, with permission from MUC owners, too be false by default. - Currently, MUC owners may kick Parsee out, with the effect of unlinking the MUC. -- Rewrite the XMPP command management to actually be aware of context, instead of -being a baked-in X-macro. It could be useful for MUC admins, which may use commands -specifically within the MUC's own context rather than the global Parsee context(for -Parsee admins). - Look at XEPS-TBD.TXT for XEPs to be done - Add a MUC server to Parsee, such that it may be able to hook onto it and therefore support XMPP->Matrix bridging. diff --git a/etc/man/man1/parsee-adminify.1 b/etc/man/man1/parsee-adminify.1 index fd4a582..9015d20 100644 --- a/etc/man/man1/parsee-adminify.1 +++ b/etc/man/man1/parsee-adminify.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-adminify 1 "Parsee Utility" "tomboyish-bridges-adventure" +.TH parsee-adminify 1 "Parsee Utility" "star-of-hope" .SH NAME parsee-adminify - bootstrap an admin to a new Parsee server diff --git a/etc/man/man1/parsee-aya.1 b/etc/man/man1/parsee-aya.1 index bb5caac..b51afa0 100644 --- a/etc/man/man1/parsee-aya.1 +++ b/etc/man/man1/parsee-aya.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-aya 1 "Parsee Utility" "tomboyish-bridges-adventure" +.TH parsee-aya 1 "Parsee Utility" "star-of-hope" .SH NAME parsee-aya - generate some nice Ayaya! documentation diff --git a/etc/man/man1/parsee.1 b/etc/man/man1/parsee.1 index 093af7b..d7eeedf 100644 --- a/etc/man/man1/parsee.1 +++ b/etc/man/man1/parsee.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee 1 "Parsee Utility" "tomboyish-bridges-adventure" +.TH parsee 1 "Parsee Utility" "star-of-hope" .SH NAME parsee - the jealous XMPP-Matrix bridge diff --git a/src/Main.c b/src/Main.c index cd1f089..cebb055 100644 --- a/src/Main.c +++ b/src/Main.c @@ -222,6 +222,12 @@ Main(Array *args, HashMap *env) } ParseeInitialiseNickTable(); + if (verbose >= PARSEE_VERBOSE_COMICAL) + { + Log(LOG_DEBUG, "Initialising affiliation table"); + } + ParseeInitialiseAffiliationTable(); + conf.port = parsee_conf->port; conf.threads = parsee_conf->http_threads; conf.maxConnections = conf.threads << 2; @@ -291,6 +297,7 @@ end: CronStop(cron); CronFree(cron); ParseeFreeData(conf.handlerArgs); + ParseeDestroyAffiliationTable(); ParseeDestroyNickTable(); ParseeDestroyOIDTable(); ParseeDestroyHeadTable(); diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 5361d2a..0898063 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -109,6 +109,7 @@ ParseeExportConfigYAML(Stream *stream) StreamPrintf(stream, "hs_token: \"%s\"\n", config->hs_token); StreamPrintf(stream, "sender_localpart: \"%s\"\n", config->sender_localpart); StreamPrintf(stream, "protocols: [\"xmpp\", \"jabber\"]\n"); + StreamPrintf(stream, "receive_ephemeral: true\n"); /* TODO: Actually use that field */ StreamPrintf(stream, "\n"); StreamPrintf(stream, "namespaces: \n"); StreamPrintf(stream, " users:\n"); diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index f858060..180f389 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -620,3 +620,90 @@ ParseeIsMUCWhitelisted(ParseeData *data, char *muc) return ret; } + +extern HashMap * +ParseeGetChatSettings(ParseeData *data, char *chat) +{ + HashMap *ret, *json; + DbRef *ref; + + char *key; + JsonValue *value; + if (!data || !chat) + { + return NULL; + } + + ref = DbLockIntent(data->db, DB_HINT_READONLY, + 3, "chats", chat, "settings" + ); + json = DbJson(ref); + if (!ref) + { + return HashMapCreate(); + } + + ret = HashMapCreate(); + while (HashMapIterate(json, &key, (void **) &value)) + { + char *str = JsonValueAsString(value); + HashMapSet(ret, key, StrDuplicate(str)); + } + DbUnlock(data->db, ref); + return ret; +} +void +ParseeFreeChatSettings(HashMap *settings) +{ + char *key; + void *val; + if (!settings) + { + return; + } + while (HashMapIterate(settings, &key, &val)) + { + Free(val); + } + HashMapFree(settings); +} +char * +ParseeGetChatSetting(ParseeData *data, char *chat, char *key) +{ + HashMap *map; + char *ret; + if (!data || !chat || !key) + { + return NULL; + } + + map = ParseeGetChatSettings(data, chat); + ret = StrDuplicate(HashMapGet(map, key)); + ParseeFreeChatSettings(map); + + return ret; +} +void +ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val) +{ + DbRef *ref; + HashMap *json; + if (!data || !chat || !key || !val) + { + return; + } + + ref = DbLockIntent(data->db, DB_HINT_WRITE, + 3, "chats", chat, "settings" + ); + if (!ref) + { + ref = DbCreate(data->db, 3, "chats", chat, "settings"); + } + json = DbJson(ref); + + JsonValueFree(HashMapSet(json, key, JsonValueString(val))); + + DbUnlock(data->db, ref); + return; +} diff --git a/src/Parsee/Tables/Affiliation.c b/src/Parsee/Tables/Affiliation.c new file mode 100644 index 0000000..e3b5f55 --- /dev/null +++ b/src/Parsee/Tables/Affiliation.c @@ -0,0 +1,106 @@ +#include + +#include +#include +#include +#include + +static pthread_mutex_t affi_lock; +static HashMap *affi_table = NULL; + +typedef struct XMPPStatus { + char *role; + char *affiliation; +} XMPPStatus; +static XMPPStatus * +CreateStatus(char *role, char *affiliation) +{ + XMPPStatus *ret; + if (!role || !affiliation) + { + return NULL; + } + + ret = Malloc(sizeof(*ret)); + ret->role = StrDuplicate(role); + ret->affiliation = StrDuplicate(affiliation); + + return ret; +} +static void +FreeStatus(XMPPStatus *status) +{ + if (!status) + { + return; + } + + Free(status->affiliation); + Free(status->role); + Free(status); +} + +void +ParseeInitialiseAffiliationTable(void) +{ + if (affi_table) + { + return; + } + pthread_mutex_init(&affi_lock, NULL); + pthread_mutex_lock(&affi_lock); + affi_table = HashMapCreate(); + pthread_mutex_unlock(&affi_lock); +} +void +ParseePushAffiliationTable(char *user, char *affi, char *role) +{ + XMPPStatus *status; + if (!user || !affi || !role) + { + return; + } + pthread_mutex_lock(&affi_lock); + + status = CreateStatus(role, affi); + FreeStatus(HashMapSet(affi_table, user, status)); + + pthread_mutex_unlock(&affi_lock); +} +bool +ParseeLookupAffiliation(char *user, char **affiliation, char **role) +{ + XMPPStatus *status; + if (!user || !affiliation || !role) + { + return false; + } + pthread_mutex_lock(&affi_lock); + + status = HashMapGet(affi_table, user); + *affiliation = StrDuplicate(status ? status->affiliation : NULL); + *role = StrDuplicate(status ? status->role : NULL); + + pthread_mutex_unlock(&affi_lock); + return !!status; +} +void +ParseeDestroyAffiliationTable(void) +{ + char *key; + void *val; + if (!affi_table) + { + return; + } + pthread_mutex_lock(&affi_lock); + while (HashMapIterate(affi_table, &key, &val)) + { + FreeStatus(val); + } + HashMapFree(affi_table); + affi_table = NULL; + pthread_mutex_unlock(&affi_lock); + pthread_mutex_destroy(&affi_lock); +} + diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 77a3d9b..da6194f 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -233,6 +233,7 @@ ParseeGenerateMTO(char *common_id) return NULL; } + /* TODO: Is HttpUrlEncode okay? */ common_id = HttpUrlEncode(common_id); matrix_to = StrConcat(2, "https://matrix.to/#/", common_id); Free(common_id); diff --git a/src/XMPPCommands/MUCKV.c b/src/XMPPCommands/MUCKV.c new file mode 100644 index 0000000..4bcf010 --- /dev/null +++ b/src/XMPPCommands/MUCKV.c @@ -0,0 +1,117 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void +MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *affiliation, *role; + char *chat_id; + char *muc; + + char *key, *val; + + ParseeLookupAffiliation(from, &affiliation, &role); + Free(role); + if (!StrEquals(affiliation, "owner")) + { + SetNote("error", "Setting MUC properties requires the 'owner' affiliation."); + Free(affiliation); + return; + } + + GetFieldValue(key, "key", form); + GetFieldValue(val, "val", form); + if (!key || !val) + { + SetNote("error", "No keys or no value given."); + goto end; + } + + muc = ParseeTrimJID(from); + chat_id = ParseeGetFromMUCID(data, muc); + ParseeSetChatSetting(data, chat_id, key, val); + + SetNote("info", "Set key-value pair!"); +end: + Free(affiliation); + Free(chat_id); + Free(muc); + (void) form; +} +void +MUCGetKeys(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *affiliation = NULL, *role = NULL; + char *chat_id = NULL; + char *muc = NULL; + + XMLElement *x; + XMLElement *title; + XMLElement *reported, *item, *field, *value, *txt; + + HashMap *settings = NULL; + + ParseeLookupAffiliation(from, &affiliation, &role); + Free(role); + if (!StrEquals(affiliation, "owner")) + { + SetNote("error", "Getting MUC roperties requires the 'owner' affiliation."); + goto end; + } + + + muc = ParseeTrimJID(from); + chat_id = ParseeGetFromMUCID(data, muc); + settings = ParseeGetChatSettings(data, chat_id); + + x = XMLCreateTag("x"); + title = XMLCreateTag("title"); + + SetTitle(x, "MUC/room settings"); + + XMLAddChild(x, title); + + XMLAddAttr(x, "xmlns", "jabber:x:data"); + XMLAddAttr(x, "type", "result"); + { + char *key, *val; + reported = XMLCreateTag("reported"); + XMLAddChild(x, reported); + + /* Report */ + Report("key", "Setting's key"); + Report("val", "Setting's value"); + + /* Set */ + while (HashMapIterate(settings, &key, (void **) &val)) + { + BeginItem(); + SetField("key", key); + SetField("val", val); + EndItem(); + } + } + XMLAddChild(out, x); + +end: + ParseeFreeChatSettings(settings); + Free(affiliation); + Free(chat_id); + Free(muc); + (void) form; +} diff --git a/src/XMPPCommands/MUCUnlink.c b/src/XMPPCommands/MUCUnlink.c new file mode 100644 index 0000000..f5560d3 --- /dev/null +++ b/src/XMPPCommands/MUCUnlink.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void +MUCUnlink(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *affiliation, *role; + char *chat_id; + char *parsee; + char *room; + char *muc; + + ParseeLookupAffiliation(from, &affiliation, &role); + Free(role); + if (!StrEquals(affiliation, "owner")) + { + SetNote("error", "Unlinking a MUC requires the 'owner' affiliation."); + Free(affiliation); + return; + } + + muc = ParseeTrimJID(from); + chat_id = ParseeGetFromMUCID(data, muc); + room = ParseeGetRoomID(data, chat_id); + if (!chat_id) + { + SetNote("error", "Couldn't fetch chat ID."); + Free(muc); + return; + } + ParseeUnlinkRoom(data, chat_id); + + parsee = ParseeMXID(data); + Free(ASSend( + data->config, room, parsee, + "m.room.message", + MatrixCreateNotice("This room has been unlinked."), + 0 + )); + ASLeave(data->config, room, parsee); + + XMPPLeaveMUC(data->jabber, "parsee", muc, "Unlinked by MUC admin."); + + /* Setting an error here won't work, as we're communicating through + * the MUC, which we *left*. I guess we can try to defer the leave. */ + SetNote("info", "Unlinked MUC."); + + Free(affiliation); + Free(chat_id); + Free(parsee); + Free(room); + Free(muc); + (void) form; +} diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 0962fc0..839b930 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -189,6 +189,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) time = UtilTsMillis(); rectime = time; + from = HashMapGet(stanza->attrs, "from"); if (ParseeManageBan(args, from, NULL)) { @@ -202,7 +203,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) return false; } - if (ServerHasXEP421(args, from)) { XMLElement *occupant = XMLookForTKV( diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 5c7c21d..fb6011b 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -174,6 +174,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { ParseePushJIDTable(oid, jid); } + ParseePushAffiliationTable(oid, affiliation, role); decode_from = ParseeLookupJID(oid); real_matrix = ParseeDecodeMXID(decode_from); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 6b2d9cc..456c4fe 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -276,6 +276,44 @@ extern char * ParseeGetRoomID(ParseeData *, char *chat_id); /* Finds the MUC JID from a chat ID */ extern char * ParseeGetMUCID(ParseeData *, char *chat_id); +/** Fetches a configuration value from a key in a chat(given a Chat ID), + * as a string or NULL. Keys are to be stored like Java packages(reveres DNS). + * Parsee has the right over any key with the 'p.' prefix. + * ----------------------------------- + * Returns: a valid string[HEAP] | NULL + * Modifies: NOTHING + * See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeSetChatSetting */ +extern char * +ParseeGetChatSetting(ParseeData *data, char *chat, char *key); + +/** Fetches the entire configuration in a chat(given a Chat ID), as an hashmap + * of strings. + * ----------------------------------- + * Returns: a valid string[HEAP] | NULL + * Modifies: NOTHING + * Thrasher: ParseeFreeChatSettings + * See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeSetChatSetting, ParseeGetChatSetting */ +extern HashMap * +ParseeGetChatSettings(ParseeData *data, char *chat); + +/** Destroys memory allocated from a call to {ParseeGetChatSettings}. + * ----------------------- + * Returns: NOTHING + * Modifies: {settings} + * Thrashes: {settings} + * See-Also: ParseeGetChatSettings */ +extern void +ParseeFreeChatSettings(HashMap *settings); + +/** Replaces a configuration key-value pair within the chat's context, which + * can be read with {ParseeGetChatSetting}. + * ------------------------------------- + * Returns: NOTHING + * Modifies: the chat context + * See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeGetChatSetting */ +extern void +ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val); + /* Pushes a stanza ID to a chat ID */ extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender); extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender); @@ -327,6 +365,11 @@ extern void ParseePushOIDTable(char *muc, char *occupant); extern char *ParseeLookupOID(char *muc); extern void ParseeDestroyOIDTable(void); +extern void ParseeInitialiseAffiliationTable(void); +extern void ParseePushAffiliationTable(char *user, char *affiliation, char *role); +extern bool ParseeLookupAffiliation(char *muc, char **affiliation, char **role); +extern void ParseeDestroyAffiliationTable(void); + extern void ParseeInitialiseJIDTable(void); extern void ParseePushJIDTable(char *muc, char *bare); extern char *ParseeLookupJID(char *muc); diff --git a/src/include/XMPPCommands.x.h b/src/include/XMPPCommands.x.h index 01b27fb..dba6f48 100644 --- a/src/include/XMPPCommands.x.h +++ b/src/include/XMPPCommands.x.h @@ -45,5 +45,18 @@ typedef enum XMPPCommandFlags { XMPP_COMMAND(WhitelistCallback, XMPPCMD_ADMINS, "wl", "Get Parsee's chat whitelist", {}) \ XMPP_COMMAND(MUCInformationID, XMPPCMD_MUC, "muc-info-id", "Get bridged Matrix room ID", {}) \ XMPP_COMMAND(MUCInformationCID, XMPPCMD_MUC, "muc-info-cid", "Get MUC's internal ID", {}) \ + XMPP_COMMAND(MUCUnlink, XMPPCMD_MUC, "muc-unlink", "Unlinks MUC", {}) \ + XMPP_COMMAND(MUCSetKey, XMPPCMD_MUC, "muc-set-key", "Sets a key within the MUC/room's context", { \ + XMPPOption *key = XMPPCreateText(true, "key", ""); \ + XMPPOption *val = XMPPCreateText(true, "val", ""); \ + XMPPSetDescription(key, "Key"); \ + XMPPSetDescription(val, "Value"); \ + XMPPAddOption(cmd, key); \ + XMPPAddOption(cmd, val); \ + \ + XMPPSetFormTitle(cmd, "Set a key-value pair"); \ + XMPPSetFormInstruction(cmd, "Replace a key with a specific value"); \ + }) \ + XMPP_COMMAND(MUCGetKeys, XMPPCMD_MUC, "muc-get-keys", "Get all key-values in the MUC/room.", {}) \ XMPPCOMMANDS diff --git a/tools/adminify.c b/tools/adminify.c index ee9e749..e87d97e 100644 --- a/tools/adminify.c +++ b/tools/adminify.c @@ -113,7 +113,7 @@ Main(Array *args, HashMap *env) return EXIT_SUCCESS; } - Log(LOG_ERR, "%s: couldn't open DB '%s'", exec, db_path); + Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path); (void) env; return EXIT_FAILURE; } From cf3bb5260bf15df59e6f12f59c999326a1bc33f2 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 29 Oct 2024 14:51:58 +0100 Subject: [PATCH 134/186] [CI/FIX] Fix potentially uninitialised key-values --- src/XMPPCommands/MUCKV.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMPPCommands/MUCKV.c b/src/XMPPCommands/MUCKV.c index 4bcf010..6dba478 100644 --- a/src/XMPPCommands/MUCKV.c +++ b/src/XMPPCommands/MUCKV.c @@ -22,7 +22,7 @@ MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) char *chat_id; char *muc; - char *key, *val; + char *key = NULL, *val = NULL; ParseeLookupAffiliation(from, &affiliation, &role); Free(role); From 033dba6840dea65b0c64a01a41dabf2b1c3747be Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 29 Oct 2024 16:58:48 +0100 Subject: [PATCH 135/186] [META] Fix typo --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 1d4b711..9a7fc6f 100644 --- a/README.MD +++ b/README.MD @@ -123,7 +123,7 @@ You may also donate to [the LiberaPay](https://en.liberapay.com/Parsee), alongsi currently maintaining Cytoplasm. ## IM chats -Please avoid asking for help/issues here. If you *really* want, you may just open +Please avoid asking for help/issues there. If you *really* want, you may just open an issue and link it over it. Basic respect for others/not being an asshat is required. (Also, these are temporary room aliases.) - [#parsee:tedomum.net](https://matrix.to/#/%23parsee:tedomum.net) From 960599d9837e061a0f790d1b0dffd4faa0c6cbff Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 30 Oct 2024 09:21:20 +0100 Subject: [PATCH 136/186] [FIX/ADD/WIP] Fix very silly printf, media flags --- src/Parsee/Data.c | 18 ++++++++++++++++++ src/XMPP/Component.c | 2 +- src/XMPPThread/Stanzas/Message.c | 8 +++++++- src/include/Parsee.h | 3 +++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 180f389..46a31ee 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -707,3 +707,21 @@ ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val) DbUnlock(data->db, ref); return; } +bool +ParseeIsMediaEnabled(ParseeData *data, char *chat_id) +{ + char *value; + bool ret; + if (!data || !chat_id) + { + return false; + } + + ret = !StrEquals( + (value = ParseeGetChatSetting(data, chat_id, "p.media.enabled")), + "false" + ); + Free(value); + + return ret; +} diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 4440ff0..42e2992 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -240,7 +240,7 @@ XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max) pthread_mutex_lock(&comp->write_lock); - StreamPrintf(comp->stream, c); + StreamPrintf(comp->stream, "%s", c); StreamFlush(comp->stream); pthread_mutex_unlock(&comp->write_lock); Free(c); diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 839b930..3c57e69 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -390,6 +390,12 @@ end_error: if (ParseeVerifyAllStanza(args, stanza) && !replaced) { XMLElement *oob, *oob_data; + char *chat_id = ParseeGetFromMUCID(args, from); + bool media_enabled = chat_id ? + ParseeIsMediaEnabled(args, chat_id) : + true ; + + Free(chat_id); pthread_mutex_unlock(&thr->info->chk_lock); @@ -405,7 +411,7 @@ end_error: /* Check if it is a media link */ oob = XMLookForTKV(stanza, "x", "xmlns", "jabber:x:oob"); - if (oob && data) + if (oob && data && media_enabled) { char *mxc, *mime = NULL; HashMap *content = NULL; diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 456c4fe..30c8b61 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -314,6 +314,9 @@ ParseeFreeChatSettings(HashMap *settings); extern void ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val); +extern bool +ParseeIsMediaEnabled(ParseeData *data, char *chat_id); + /* Pushes a stanza ID to a chat ID */ extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender); extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender); From dddf1680a0d6ac8d9a0bd068eb3b704e6596d47f Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 8 Nov 2024 17:43:41 +0100 Subject: [PATCH 137/186] [RELEASE/FIX] Fix ban-unlinks, actually get 0.2. --- CHANGELOG.md | 8 +++++--- src/XMPPThread/Stanzas/Presence.c | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c9f368..5999d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,10 @@ commit done between releases. *There is currently no beta releases of Parsee* ## Alpha -### v0.2.0[star-of-hope] <8/11/2024?> +### v0.2.0[star-of-hope] <8/11/2024> Fixes some media metadata things, replaces the build system, -tries out avatar support some more and speeds up Parsee a tad -bit. +tries out avatar support some more, MUC contexts, and speeds +up Parsee just a bit. MbedTLS support is still highly unstable. #### New things - Start dealing with some basic PEP and vCard-based avatar support from both sides. @@ -50,6 +50,8 @@ size on the fly, or having extensions being able to postprocess the stanza). - Parsee now stops when a stream error is received, instead of being in a limbo state. +- The format for links has been changed to be slighlty *less* +annoying. #### Deprecated features - The old `build.c` and `Makefile`s used for building are removed, diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index fb6011b..65c2082 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -163,6 +163,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) int power_level = 0; char *parsee = ParseeMXID(args); char *parsee_j = ParseeJID(args); + char *muc = ParseeTrimJID(HashMapGet(stanza->attrs, "from")); + char *parsee_muc = StrConcat(3, muc, "/", "parsee"); Free(trim); if (!item) @@ -206,15 +208,12 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (!StrEquals(HashMapGet(stanza->attrs, "to"), parsee_j) && IsStatus(110)) { - char *muc = ParseeTrimJID(HashMapGet(stanza->attrs, "from")); char *usr = HashMapGet(stanza->attrs, "to"); /* Ask for voice in a visitor self-presence. We do not notify * the user, as an error MUST occur, which is handled and * logged out. */ XMPPRequestVoice(args->jabber, usr, muc); - - Free(muc); } } @@ -270,7 +269,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) } } if (StrEquals(type, "unavailable") && - StrEquals(dst, parsee_j) && IsStatus(301)) + (StrEquals(jid, parsee_muc) || StrEquals(jid, parsee_j)) + && IsStatus(301)) { char *chat_id = ParseeGetFromRoomID(args, room); @@ -287,7 +287,9 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) } end_item: + Free(muc); Free(from); + Free(parsee_muc); Free(decode_from); Free(real_matrix); Free(matrix_user_pl); From 954c588310bf0cd2783b9e212612d65411446a6b Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 11 Nov 2024 11:00:26 +0100 Subject: [PATCH 138/186] [FIX] Don't check for upgrades on start. --- src/Parsee/Data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 46a31ee..2fcee5e 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -58,7 +58,7 @@ ParseeInitData(XMPPComponent *comp) } version = GrabString(DbJson(ref), 1, "version"); - if (!ParseeIsCompatible(VERSION, version)) + if (version && !ParseeIsCompatible(VERSION, version)) { Log(LOG_WARNING, "Version mismatch(curr=%s db=%s).", VERSION, version); Log(LOG_WARNING, "Yeah. You may want to _not_ do that."); From 7f41a85a8a4d60204fec8e031a34aabc0d321007 Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 11 Nov 2024 11:23:10 +0100 Subject: [PATCH 139/186] [FIX] Oh, and set the version --- src/Parsee/Data.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 2fcee5e..cb1b64b 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -54,6 +54,7 @@ ParseeInitData(XMPPComponent *comp) char *id = StrRandom(64); ref = DbCreate(data->db, 1, "info"); HashMapSet(DbJson(ref), "identifier", JsonValueString(id)); + HashMapSet(DbJson(ref), "version", JsonValueString(VERSION)); Free(id); } From 5d13410ac4417bf135ca2a0f552147d484fd1db6 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 17 Nov 2024 16:22:10 +0100 Subject: [PATCH 140/186] [ADD] Ping homeserver to see if Parsee works --- src/AS/Ping.c | 9 ++++++--- src/Main.c | 29 +++++++++++++++++++++++++++++ src/Routes/Ping.c | 38 ++++++++++++++++++++++++++++++++++++++ src/include/AS.h | 2 +- src/include/Routes.h | 1 + 5 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 src/Routes/Ping.c diff --git a/src/AS/Ping.c b/src/AS/Ping.c index 88ac7cb..3a8ffb7 100644 --- a/src/AS/Ping.c +++ b/src/AS/Ping.c @@ -10,15 +10,16 @@ #include -void +bool ASPing(const ParseeConfig *conf) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path; + bool ret; if (!conf) { - return; + return false; } path = StrConcat(3, @@ -33,7 +34,9 @@ ASPing(const ParseeConfig *conf) Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); + ret = ParseeSetRequestJSON(ctx, json) == HTTP_OK; HttpClientContextFree(ctx); JsonFree(json); + + return ret; } diff --git a/src/Main.c b/src/Main.c index cebb055..a9b0a50 100644 --- a/src/Main.c +++ b/src/Main.c @@ -58,6 +58,34 @@ static const Argument arguments[] = #undef Argument }; +void +ParseeCheckMatrix(void *datp) +{ + static volatile uint64_t streak = 0; + ParseeData *data = datp; + if (!ASPing(data->config)) + { + Log(LOG_ERR, "Cannot reach '%s' properly...", data->config->homeserver_host); + if (++streak >= 5) + { + Log(LOG_ERR, "This has been at least the fifth time in a row."); + Log(LOG_ERR, "Please check if your homeserver is active."); + Log(LOG_ERR, "%s shall now exit...", NAME); + + pthread_mutex_lock(&data->halt_lock); + data->halted = true; + pthread_mutex_unlock(&data->halt_lock); + + XMPPFinishCompStream(data->jabber); + pthread_join(xmpp_thr, NULL); + Log(LOG_INFO, "Stopping server..."); + HttpServerStop(data->server); + } + return; + } + streak = 0; +} + int Main(Array *args, HashMap *env) { @@ -259,6 +287,7 @@ Main(Array *args, HashMap *env) Log(LOG_NOTICE, "Starting up local cronjobs..."); cron = CronCreate(10 SECONDS); CronEvery(cron, 5 MINUTES, ParseeCleanup, conf.handlerArgs); + CronEvery(cron, 10 SECONDS, ParseeCheckMatrix, conf.handlerArgs); ParseeCleanup(conf.handlerArgs); CronStart(cron); diff --git a/src/Routes/Ping.c b/src/Routes/Ping.c new file mode 100644 index 0000000..a508336 --- /dev/null +++ b/src/Routes/Ping.c @@ -0,0 +1,38 @@ +#include + +#include + +#include +#include + +RouteHead(RoutePing, arr, argp) +{ + ParseeHttpArg *args = argp; + HashMap *request = NULL; + HashMap *response = NULL; + Array *events; + size_t i; + + response = ASVerifyRequest(args); + if (response) + { + goto end; + } + if (HttpRequestMethodGet(args->ctx) != HTTP_POST) + { + HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); + response = MatrixCreateError( + "M_UNRECOGNIZED", + "Path /ping only accepts POST as a valid method." + ); + goto end; + } + + RequestJSON(); + + response = HashMapCreate(); +end: + (void) arr; + JsonFree(request); + return response; +} diff --git a/src/include/AS.h b/src/include/AS.h index 8afef6f..562d172 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -29,7 +29,7 @@ extern void ASAuthenticateRequest(const ParseeConfig *, HttpClientContext *); extern bool ASRegisterUser(const ParseeConfig *, char *); /* Pings the homeserver to get attention. */ -extern void ASPing(const ParseeConfig *); +extern bool ASPing(const ParseeConfig *); /** Joins a room from an {id} and a given {user} we want to masquerade * as. diff --git a/src/include/Routes.h b/src/include/Routes.h index 369a0d7..8d233e6 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -74,6 +74,7 @@ typedef struct ParseeCmdArg { X_ROUTE("/_matrix/app/v1/transactions/(.*)", RouteTxns) \ X_ROUTE("/_matrix/app/v1/users/(.*)", RouteUserAck) \ X_ROUTE("/_matrix/app/v1/rooms/(.*)", RouteRoomAck) \ + X_ROUTE("/_matrix/app/v1/ping", RoutePing) \ X_ROUTE("/_matrix/client/v1/media/download/(.*)/(.*)", RouteMedia) #define X_ROUTE(path, name) extern void * name(Array *, void *); From 56433fc69c3a793bdd2af0d07af00f5bd9e0e75a Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 18 Nov 2024 21:46:59 +0100 Subject: [PATCH 141/186] [DEL] Remove 64KB avatar hardlimit --- src/XMPPThread/Stanzas/IQ.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 32aa0c9..4ced5dc 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -65,9 +65,8 @@ AvatarGrab(ParseeData *data, char *mxc, char **mime, char **b64, size_t *len) b64i = Base64Encode(outi, sizei); Free(outi); - if (!b64i || strlen(b64i) > 64 KB) + if (!b64i) { - Free(b64i); Free(mimei); b64i = StrDuplicate(media_unknown); /* TODO: Different assets! */ mimei = StrDuplicate("image/png"); From 5ff92dda3dcbdd84538ca6955679e40975143a1d Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 20 Nov 2024 22:05:54 +0100 Subject: [PATCH 142/186] [ADD] Basic header check in configure It doesn't exactly conform to C99 standards, but it is good enough for Parsee as a whole. --- configure.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/configure.c b/configure.c index 48b541b..a72a68a 100644 --- a/configure.c +++ b/configure.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -431,6 +432,81 @@ write_ayas(FILE *makefile, str_array_t *sources) free(obj); } } + +static void +analyse_dependencies(FILE *makefile, char *src) +{ + FILE *source = fopen(src, "r"); + char *lineptr = NULL; + char *dn = strdup(src), *dirn; + size_t len = 0; + + dirn = dirname(dn); + + while (getline(&lineptr, &len, source) != -1) + { + char *corrptr = lineptr, *nl, *chevron, *quote, *cutoff; + char *basedir, *srcdir, *incdir, *tmp; + struct stat statinfo; + + /* try to parse the line */ + if ((nl = strchr(corrptr, '\n'))) + { + *nl = '\0'; + } + + while (*corrptr && isblank(*corrptr)) + { + corrptr++; + } + if (strncmp(corrptr, "#include \"", 10) && + strncmp(corrptr, "#include <", 10)) + { + continue; + } + corrptr += 10; + chevron = strchr(corrptr, '>'); + chevron = chevron ? chevron : corrptr + strlen(corrptr); + quote = strchr(corrptr, '"'); + quote = quote ? quote : corrptr + strlen(corrptr); + cutoff = chevron < quote ? chevron : quote; + + *cutoff = '\0'; + + /* if we found something, try to resolve it */ + tmp = string_cat(dirn, "/"); + basedir = string_cat(tmp, corrptr); + free(tmp); + if (!stat(basedir, &statinfo)) + { + fprintf(makefile, " %s", basedir); + free(basedir); + continue; + } + free(basedir); + + srcdir = string_cat("src/", corrptr); + if (!stat(srcdir, &statinfo)) + { + fprintf(makefile, " %s", srcdir); + free(srcdir); + continue; + } + free(srcdir); + + incdir = string_cat("src/include/", corrptr); + if (!stat(incdir, &statinfo)) + { + fprintf(makefile, " %s", incdir); + free(incdir); + continue; + } + free(incdir); + } + free(lineptr); + free(dn); + fclose(source); +} static int main_build(int argc, char *argv[]) { @@ -513,7 +589,9 @@ main_build(int argc, char *argv[]) char *ofl = string_rep_ext(src, ".c", ".o"); char *obj = string_cat("build", ofl + 3); - fprintf(makefile, "%s: %s\n", obj, src); + fprintf(makefile, "%s: %s", obj, src); + analyse_dependencies(makefile, src); + fprintf(makefile, "\n"); { str_array_t *s = split(obj); ssize_t j; From 2e566c73fcca4b9ba940eb37c9bddea3c6d1f519 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 29 Nov 2024 13:58:49 +0100 Subject: [PATCH 143/186] [MOD] Start not hardcoding discovery features The eventual goal here is to have different disco replies for specific kinds of JID, effectively allowing us to have MUCs. Yeah. --- src/XMPP/MUC.c | 25 +++++++- src/XMPP/Stanza.c | 21 ------ src/XMPPThread/Caps.c | 125 +++++++++++++++++++++++++++--------- src/XMPPThread/Stanzas/IQ.c | 10 ++- src/XMPPThread/internal.h | 25 +++++++- src/include/XMPP.h | 10 --- 6 files changed, 149 insertions(+), 67 deletions(-) diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 7064698..5813cd2 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -8,6 +8,8 @@ #include #include +#include "XMPPThread/internal.h" + bool XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { @@ -162,6 +164,7 @@ bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool ret) { XMLElement *presence, *x, *reply, *history, *photo; + IQFeatures *features; char *from, *id, *stime = "3600"; if (!comp || !fr || !muc) { @@ -189,7 +192,15 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(x, history); XMLAddChild(presence, x); - XMPPAnnotatePresence(presence); + features = CreateIQFeatures(); +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple + XMPPAnnotatePresence(presence, features); + FreeIQFeatures(features); if (hash) { @@ -225,6 +236,7 @@ void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) { XMLElement *presence; + IQFeatures *features; char *from, *id; if (!comp || !fr || !muc) { @@ -246,7 +258,16 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMLAddChild(presence, status); } - XMPPAnnotatePresence(presence); + features = CreateIQFeatures(); +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple + XMPPAnnotatePresence(presence, features); + FreeIQFeatures(features); + XMPPSendStanza(comp, presence, 10000); diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 451c16f..27a658e 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -159,27 +159,6 @@ XMPPGetReply(XMLElement *elem) return HashMapGet(rep->attrs, "id"); } -void -XMPPAnnotatePresence(XMLElement *presence) -{ - XMLElement *c; - char *ver; - if (!presence) - { - return; - } - - ver = XMPPGenerateVer(); - c = XMLCreateTag("c"); - XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); - XMLAddAttr(c, "hash", "sha-1"); - XMLAddAttr(c, "node", REPOSITORY); - XMLAddAttr(c, "ver", ver); - - Free(ver); - XMLAddChild(presence, c); -} - char * XMPPGetModeration(XMLElement *stanza) { diff --git a/src/XMPPThread/Caps.c b/src/XMPPThread/Caps.c index 867adbd..5e53ee1 100644 --- a/src/XMPPThread/Caps.c +++ b/src/XMPPThread/Caps.c @@ -12,33 +12,86 @@ #include "XMPPThread/internal.h" +IQFeatures * +CreateIQFeatures(void) +{ + IQFeatures *ret = Malloc(sizeof(*ret)); + + ret->identity = ArrayCreate(); + ret->adverts = ArrayCreate(); + + return ret; +} +void +FreeIQFeatures(IQFeatures *features) +{ + size_t i; + if (!features) + { + return; + } + + for (i = 0; i < ArraySize(features->adverts); i++) + { + Free(ArrayGet(features->adverts, i)); + } + ArrayFree(features->adverts); + + for (i = 0; i < ArraySize(features->identity); i++) + { + XMPPIdentity *identity = ArrayGet(features->identity, i); + + Free(identity->category); + Free(identity->type); + Free(identity->lang); + Free(identity->name); + + Free(identity); + } + ArrayFree(features->identity); + + Free(features); +} + +void +AdvertiseIQFeature(IQFeatures *f, char *feature) +{ + if (!f || !feature) + { + return; + } + + ArrayAdd(f->adverts, StrDuplicate(feature)); +} +void +AddIQIdentity(IQFeatures *f, char *cat, char *lang, char *type, char *name) +{ + XMPPIdentity *identity; + if (!f) + { + return; + } + + identity = Malloc(sizeof(*identity)); + identity->category = StrDuplicate(cat); + identity->type = StrDuplicate(type); + identity->lang = StrDuplicate(lang); + identity->name = StrDuplicate(name); + ArrayAdd(f->identity, identity); +} /* Generates a SHA-256 hash of the ver field. */ char * -XMPPGenerateVer(void) +XMPPGenerateVer(IQFeatures *features) { char *S = NULL; unsigned char *Sha = NULL; - Array *identities = ArrayCreate(); - Array *features = ArrayCreate(); size_t i; /* Initialise identity table, to be sorted */ -#define IdentitySimple(cat, Type, Name) { \ - XMPPIdentity *id = Malloc(sizeof(*id)); \ - id->category = cat; \ - id->lang = NULL; \ - id->type = Type; \ - id->name = Name; \ - ArrayAdd(identities, id); } - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(feature) ArrayAdd(features, feature); - IQ_ADVERT -#undef AdvertiseSimple - ArraySort(identities, IdentitySort); - for (i = 0; i < ArraySize(identities); i++) + ArraySort(features->identity, IdentitySort); + for (i = 0; i < ArraySize(features->identity); i++) { - XMPPIdentity *identity = ArrayGet(identities, i); + XMPPIdentity *identity = ArrayGet(features->identity, i); char *id_chunk = StrConcat(7, identity->category, "/", identity->type, "/", @@ -50,10 +103,10 @@ XMPPGenerateVer(void) Free(id_chunk); } - ArraySort(features, ((int (*) (void *, void *)) ICollate)); - for (i = 0; i < ArraySize(features); i++) + ArraySort(features->adverts, ((int (*) (void *, void *)) ICollate)); + for (i = 0; i < ArraySize(features->adverts); i++) { - char *feature = ArrayGet(features, i); + char *feature = ArrayGet(features->adverts, i); char *tmp = S; S = StrConcat(3, S, feature, "<"); Free(tmp); @@ -64,16 +117,28 @@ XMPPGenerateVer(void) S = Base64Encode((const char *) Sha, 20); Free(Sha); - ArrayFree(features); - for (i = 0; i < ArraySize(identities); i++) - { - XMPPIdentity *identity = ArrayGet(identities, i); - /* We don't have to do anything here. */ - Free(identity); - } - ArrayFree(identities); - return S; } +void +XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features) +{ + XMLElement *c; + char *ver; + if (!presence || !features) + { + return; + } + + ver = XMPPGenerateVer(features); + c = XMLCreateTag("c"); + XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); + XMLAddAttr(c, "hash", "sha-1"); + XMLAddAttr(c, "node", REPOSITORY); + XMLAddAttr(c, "ver", ver); + + Free(ver); + XMLAddChild(presence, c); +} + diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 4ced5dc..396fec4 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -151,6 +151,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) { char *from, *to, *id; XMLElement *iq_reply, *query; + IQFeatures *features = CreateIQFeatures(); from = HashMapGet(stanza->attrs, "from"); to = HashMapGet(stanza->attrs, "to"); @@ -164,8 +165,14 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) XMLAddAttr(iq_reply, "id", id); query = IQGenerateQuery(); +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple { - char *ver = XMPPGenerateVer(); + char *ver = XMPPGenerateVer(features); char *node = StrConcat(3, REPOSITORY, "#", ver); XMLAddAttr(query, "node", node); @@ -173,6 +180,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) Free(ver); } XMLAddChild(iq_reply, query); + FreeIQFeatures(features); XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index 3a158b5..8602621 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -32,13 +32,17 @@ IdentitySimple("client", "pc", NAME " v" VERSION " bridge") \ IdentitySimple("component", "generic", "Parsee's component") -typedef struct PEPManager PEPManager; -typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item); - +typedef struct IQFeatures { + Array *identity; + Array *adverts; +} IQFeatures; typedef struct XMPPIdentity { char *category, *type, *lang, *name; } XMPPIdentity; +typedef struct PEPManager PEPManager; +typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item); + typedef struct XMPPThread XMPPThread; typedef struct XMPPThreadInfo { /* A FIFO of stanzas inbound, to be read by dispatcher @@ -65,6 +69,21 @@ struct XMPPThread { int ICollate(unsigned char *cata, unsigned char *catb); int IdentitySort(void *idap, void *idbp); +IQFeatures * CreateIQFeatures(void); +void AddIQIdentity(IQFeatures *, char *category, char *lang, char *type, char *name); +void AdvertiseIQFeature(IQFeatures *, char *feature); +void FreeIQFeatures(IQFeatures *); + +/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. + * -------- + * Returns: A base64 encoded ver hash[LA:HEAP] + * Modifies: NOTHING + * See-Also: https://xmpp.org/extensions/xep-0115.html */ +char * XMPPGenerateVer(IQFeatures *features); + +/* Annotates a presence with https://xmpp.org/extensions/xep-0115.html */ +void XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features); + char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza); char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id); char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza); diff --git a/src/include/XMPP.h b/src/include/XMPP.h index b2c5293..92a5d80 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -98,16 +98,6 @@ extern char * XMPPGetReply(XMLElement *elem); * See-Also: https://xmpp.org/extensions/xep-0425.html */ extern char * XMPPGetModeration(XMLElement *stanza); -/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. - * -------- - * Returns: A base64 encoded ver hash[LA:HEAP] - * Modifies: NOTHING - * See-Also: https://xmpp.org/extensions/xep-0115.html */ -extern char * XMPPGenerateVer(void); - -/* Annotates a presence with https://xmpp.org/extensions/xep-0115.html */ -extern void XMPPAnnotatePresence(XMLElement *presence); - extern bool XMPPHasError(XMLElement *stanza, char *type); #include From 5ddc5d3e5cb4aec90ba260f7114fa18c4b902162 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 19 Dec 2024 20:59:12 +0100 Subject: [PATCH 144/186] [WIP/ADD] Try to separate discovery, make links nicer --- configure.c | 71 +++------------- src/Main.c | 3 +- src/MatrixID.c | 34 ++++++++ src/Parsee/Data.c | 2 + src/Parsee/Utils/Formatting.c | 48 ++++++++--- src/Routes/Media.c | 43 +++++++--- src/XMPP/MUC.c | 4 +- src/XMPP/MUCServ.c | 153 ++++++++++++++++++++++++++++++++++ src/XMPPThread/Caps.c | 37 ++++++++ src/XMPPThread/ReListener.c | 6 ++ src/XMPPThread/Stanzas/IQ.c | 69 +++++++-------- src/XMPPThread/internal.h | 8 ++ src/include/MUCServ.h | 39 +++++++++ src/include/Matrix.h | 7 ++ src/include/Parsee.h | 3 + 15 files changed, 409 insertions(+), 118 deletions(-) create mode 100644 src/XMPP/MUCServ.c create mode 100644 src/include/MUCServ.h diff --git a/configure.c b/configure.c index a72a68a..d3a01d0 100644 --- a/configure.c +++ b/configure.c @@ -90,22 +90,6 @@ string_cat(char *in1, char *in2) return out; } -static char * -trim_nl(char *in) -{ - char *tc; - if (!in) - { - return NULL; - } - - while ((tc = strrchr(in, '\n'))) - { - *tc = '\0'; - } - - return in; -} typedef struct str_array { char **values; @@ -115,6 +99,10 @@ static str_array_t * str_array_create(void) { str_array_t *ret = malloc(sizeof(*ret)); + if (!ret) + { + return NULL; + } ret->values = NULL; ret->quantity = 0; @@ -216,36 +204,6 @@ failure: free(line); return NULL; } -static int -exec_code(char *program, char *argv[]) -{ - pid_t forkRet; - if (!program || !argv) - { - return -1; - } - - forkRet = fork(); - if (forkRet == 0) - { - /* Child */ - execvp(program, argv); - exit(0); - } - else - { - /* Parent */ - int status; - if (waitpid(forkRet, &status, 0) == -1) - { - return -1; - } - return status; - } - - /* We're not meant to ever be there, but TCC is stupid. */ - return -1; -} static char * strchrn(char *s, char c) @@ -253,17 +211,6 @@ strchrn(char *s, char c) s = strchr(s, c); return s ? s+1 : NULL; } -static char * -strchrl(char *s, char c) -{ - char *s1 = NULL; - while ((s = strchr(s, c))) - { - s1 = s; - s++; - } - return s1; -} static str_array_t * split(char *dir) { @@ -512,8 +459,7 @@ main_build(int argc, char *argv[]) { FILE *makefile; char *repo = cmd_stdout("git remote get-url origin"); - size_t size, i; - ssize_t nread; + size_t i; bool with_static = false, with_lmdb = false; int opt; str_array_t *sources, *images, *utils, *aya; @@ -546,6 +492,13 @@ main_build(int argc, char *argv[]) } makefile = fopen("Makefile", "w"); + if (!makefile) + { + fprintf(stderr, "Couldn't create Makefile.\n"); + fprintf(stderr, "This isn't good, actually.\n"); + + return EXIT_FAILURE; + } fprintf(makefile, "# Autogenerated POSIX Makefile from Parsee\n"); fprintf(makefile, "# Ideally do not touch, unless you have a very "); fprintf(makefile, "good reason to do it. \n\n"); diff --git a/src/Main.c b/src/Main.c index a9b0a50..633e117 100644 --- a/src/Main.c +++ b/src/Main.c @@ -72,12 +72,13 @@ ParseeCheckMatrix(void *datp) Log(LOG_ERR, "Please check if your homeserver is active."); Log(LOG_ERR, "%s shall now exit...", NAME); + /* TODO: SEGV! */ pthread_mutex_lock(&data->halt_lock); data->halted = true; pthread_mutex_unlock(&data->halt_lock); XMPPFinishCompStream(data->jabber); - pthread_join(xmpp_thr, NULL); + //pthread_join(xmpp_thr, NULL); Log(LOG_INFO, "Stopping server..."); HttpServerStop(data->server); } diff --git a/src/MatrixID.c b/src/MatrixID.c index 4488fd4..bb7c584 100644 --- a/src/MatrixID.c +++ b/src/MatrixID.c @@ -1,6 +1,9 @@ #include #include +#include +#include +#include #include @@ -32,3 +35,34 @@ MatrixParseID(char *user) return ret; } +UserID * +MatrixParseIDFromMTO(Uri *uri) +{ + UserID *id = NULL; + char *path, *params, *decoded; + if (!uri) + { + return NULL; + } + + if (!StrEquals(uri->proto, "https") || !StrEquals(uri->host, "matrix.to")) + { + return NULL; + } + if (strncmp(uri->path, "/#/", 3)) + { + return NULL; + } + path = StrDuplicate(uri->path + 3); + params = path ? strchr(path, '?') : NULL; + if (params) + { + *params = '\0'; + } + decoded = HttpUrlDecode(path); + id = MatrixParseID(decoded); + Free(decoded); + Free(path); + + return id; +} diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index cb1b64b..68ddf3c 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -27,6 +27,7 @@ ParseeInitData(XMPPComponent *comp) data->config = ParseeConfigGet(); data->router = HttpRouterCreate(); data->jabber = comp; + data->muc = CreateMUCServer(data); data->handler = CommandCreateRouter(); data->oid_servers = HashMapCreate(); @@ -116,6 +117,7 @@ ParseeFreeData(ParseeData *data) pthread_mutex_destroy(&data->halt_lock); Free(data->id); XMPPEndCompStream(data->jabber); + FreeMUCServer(data->muc); DbClose(data->db); HttpRouterFree(data->router); CommandFreeRouter(data->handler); diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index da6194f..5a2c6b8 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -5,11 +5,13 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -151,20 +153,42 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) else if (StrEquals(elem->name, "a")) { char *href = HashMapGet(elem->attrs, "href"); - /* TODO: Check if the element here is a Matrix.TO - * pointing to a Parsee user. */ - Concat("("); - for (i = 0; i < ArraySize(elem->children); i++) + Uri *pref = UriParse(href); + if (StrEquals(pref->host, "matrix.to")) { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); - - Concat(subxep); - Free(subxep); + /* TODO: Check if the element here is a Matrix.TO + * pointing to a Parsee user. */ + UserID *id = MatrixParseIDFromMTO(pref); + if (id) + { + /* TODO: Detect if it already is a Parsee user */ + Concat("@"); + Concat(id->localpart); + Concat(":"); + Concat(id->server); + } + else + { + Concat(href); + } + + Free(id); } - Concat(" points to "); - Concat(href); - Concat(" )"); + else + { + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + Concat(" < "); + Concat(href); + Concat(" >"); + } + UriFree(pref); } else { diff --git a/src/Routes/Media.c b/src/Routes/Media.c index 7d6bc68..004a854 100644 --- a/src/Routes/Media.c +++ b/src/Routes/Media.c @@ -10,6 +10,37 @@ #include +static HttpClientContext * +TryDownload(ParseeData *data, char *server, char *identi) +{ + HttpClientContext *cctx; + char *path; + server = HttpUrlEncode(server); + identi = HttpUrlEncode(identi); + + path = StrConcat(4, "/_matrix/media/v3/download/", server, "/", identi); + cctx = ParseeCreateRequest(data->config, HTTP_GET, path); + ASAuthenticateRequest(data->config, cctx); + Free(path); + + HttpRequestSendHeaders(cctx); + if (HttpRequestSend(cctx) != HTTP_OK) + { + Log(LOG_WARNING, "Failing back."); + HttpClientContextFree(cctx); + path = StrConcat(4, "/_matrix/client/v1/media/download/", server, "/", identi); + cctx = ParseeCreateRequest(data->config, HTTP_GET, path); + ASAuthenticateRequest(data->config, cctx); + Free(path); + HttpRequestSendHeaders(cctx); + HttpRequestSend(cctx); + } + + Free(server); + Free(identi); + return cctx; +} + RouteHead(RouteMedia, arr, argp) { ParseeHttpArg *args = argp; @@ -44,15 +75,7 @@ RouteHead(RouteMedia, arr, argp) /* Proxy the media through an authenticated endpoint if the HMAC * is valid. */ - server = HttpUrlEncode(server); - identi = HttpUrlEncode(identi); - path = StrConcat(4, "/_matrix/media/v3/download/", server, "/", identi); - cctx = ParseeCreateRequest(args->data->config, HTTP_GET, path); - ASAuthenticateRequest(args->data->config, cctx); - Free(path); - - HttpRequestSendHeaders(cctx); - HttpRequestSend(cctx); + cctx = TryDownload(args->data, server, identi); reqh = HttpResponseHeaders(cctx); while (HashMapIterate(reqh, &key, (void **) &val)) { @@ -65,8 +88,6 @@ RouteHead(RouteMedia, arr, argp) } HttpClientContextFree(cctx); - Free(server); - Free(identi); return NULL; } diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 5813cd2..67bc9d1 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -192,7 +192,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(x, history); XMLAddChild(presence, x); - features = CreateIQFeatures(); + features = LookupJIDFeatures(from); #define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); IQ_IDENTITY #undef IdentitySimple @@ -258,7 +258,7 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMLAddChild(presence, status); } - features = CreateIQFeatures(); + features = LookupJIDFeatures(from); #define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); IQ_IDENTITY #undef IdentitySimple diff --git a/src/XMPP/MUCServ.c b/src/XMPP/MUCServ.c new file mode 100644 index 0000000..66f4840 --- /dev/null +++ b/src/XMPP/MUCServ.c @@ -0,0 +1,153 @@ +#include + +#include +#include +#include + +#include +#include + +#define MUCNS "http://jabber.org/protocol/muc" + +struct MUCServer { + pthread_mutex_t mut; + + ParseeData *data; +}; + +static char * +GetMUCName(char *jid) +{ + char *name, *at; + size_t len; + if (!jid || *jid != '#') + { + return NULL; + } + + jid++; + + at = strchr(jid, '@'); + if (!at) + { + return StrDuplicate(jid); + } + len = at - jid; + name = Malloc(len + 1); + memset(name, '\0', len + 1); + memcpy(name, jid, len); + + return name; +} + +MUCServer * +CreateMUCServer(ParseeData *data) +{ + MUCServer *server; + if (!data) + { + return NULL; + } + + server = Malloc(sizeof(*server)); + pthread_mutex_init(&server->mut, NULL); + server->data = data; + return server; +} + +static bool +MUCManagePresence(MUCServer *serv, XMLElement *stanza, char *from, char *to) +{ + char *name; + XMLElement *x = XMLookForTKV(stanza, "x", "xmlns", MUCNS); + char *type = HashMapGet(stanza->attrs, "type"); + if (x && !type) + { + /* The user is trying to join the MUC */ + name = GetMUCName(to); + Log(LOG_WARNING, "%s is trying to join MUC '%s'", from, name); + + /* TODO: Check if the user should be joining. If so, make them. + * Implementing MUCs is gonna be fun. */ + + /* TODO: Presence broadcast hell. */ + Free(name); + } + return false; +} + +static bool +MUCManageMessage(MUCServer *serv, XMLElement *stanza, char *from, char *to) +{ + Log(LOG_WARNING, "MUCSERV: got a message %s->%s", from, to); + return false; +} + +bool +ManageMUCStanza(MUCServer *serv, XMLElement *stanza) +{ + char *stype, *from, *to; + bool ret; + if (!serv || !stanza) + { + return false; + } + + from = HashMapGet(stanza->attrs, "from"); + to = HashMapGet(stanza->attrs, "to"); + stype = stanza->name; + + if (to && *to != '#') + { + /* We aren't interacting with a MUC at all. Don't do anything. */ + return false; + } + if (StrEquals(stype, "iq")) + { + /* TODO: Worry about IQ later */ + return false; + } + + ret = false; + pthread_mutex_lock(&serv->mut); + if (StrEquals(stype, "presence")) + { + ret = MUCManagePresence(serv, stanza, from, to); + } + else if (StrEquals(stype, "message")) + { + ret = MUCManageMessage(serv, stanza, from, to); + } + /* TODO: Do stuff while locked */ + pthread_mutex_unlock(&serv->mut); + + /* TODO: Verify the destination, and make sure we aren't doing + * anything stupid(especially with discovery) */ + return false; +} + +bool +MUCServerExists(MUCServer *serv, char *muc) +{ + if (!serv || !muc) + { + return false; + } + + return false; +} + +void +FreeMUCServer(MUCServer *serv) +{ + if (!serv) + { + return; + } + + pthread_mutex_lock(&serv->mut); + /* TODO */ + pthread_mutex_unlock(&serv->mut); + pthread_mutex_destroy(&serv->mut); + Free(serv); +} diff --git a/src/XMPPThread/Caps.c b/src/XMPPThread/Caps.c index 5e53ee1..d79a30c 100644 --- a/src/XMPPThread/Caps.c +++ b/src/XMPPThread/Caps.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -142,3 +143,39 @@ XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features) XMLAddChild(presence, c); } + +IQFeatures * +LookupJIDFeatures(char *jid) +{ + IQFeatures *features; + if (!jid) + { + return NULL; + } + + features = CreateIQFeatures(); + + if (*jid == '#') + { + /* This is a MUC. As such, we need to advertise MUCs */ +#define ID(...) AddIQIdentity(features, __VA_ARGS__) +#define AD(var) AdvertiseIQFeature(features, var) + ID("gateway", NULL, "matrix", "Parsee MUC gateway"); + ID("conference", NULL, "text", "Parsee MUC gateway"); + ID("component", NULL, "generic", "Parsee component"); + + AD("http://jabber.org/protocol/muc"); +#undef AD +#undef ID + } + else + { +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple + } + return features; +} diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 559ffcb..f68b887 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -65,6 +65,12 @@ XMPPDispatcher(void *argp) Log(LOG_DEBUG, "Received stanza='%s'.", stanza->name); } + if (ManageMUCStanza(args->muc, stanza)) + { + XMLFreeElement(stanza); + continue; + } + if (StrEquals(stanza->name, "presence")) { PresenceStanza(args, stanza, thread); diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 396fec4..17092b0 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -115,33 +115,37 @@ end: #define DISCO "http://jabber.org/protocol/disco#info" static XMLElement * -IQGenerateQuery(void) +IQGenerateQuery(IQFeatures *features) { - XMLElement *query = XMLCreateTag("query"); + XMLElement *query; + if (!features) + { + return NULL; + } + query = XMLCreateTag("query"); XMLAddAttr(query, "xmlns", DISCO); { XMLElement *feature; -#define IdentitySimple(c,t,n) do \ - { \ - feature = XMLCreateTag("identity"); \ - XMLAddAttr(feature, "category", c); \ - XMLAddAttr(feature, "type", t); \ - XMLAddAttr(feature, "name", n); \ - XMLAddChild(query, feature); \ - } \ - while (0); - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(f) do \ - { \ - feature = XMLCreateTag("feature"); \ - XMLAddAttr(feature, "var", f); \ - XMLAddChild(query, feature); \ - } \ - while (0); + size_t i; + for (i = 0; i < ArraySize(features->identity); i++) + { + XMPPIdentity *identity = ArrayGet(features->identity, i); - IQ_ADVERT -#undef AdvertiseSimple + feature = XMLCreateTag("identity"); + XMLAddAttr(feature, "category", identity->category); + XMLAddAttr(feature, "type", identity->type); + XMLAddAttr(feature, "name", identity->name); + + XMLAddChild(query, feature); + } + for (i = 0; i < ArraySize(features->adverts); i++) + { + char *var = ArrayGet(features->adverts, i); + + feature = XMLCreateTag("feature"); + XMLAddAttr(feature, "var", var); + XMLAddChild(query, feature); + } } return query; @@ -151,7 +155,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) { char *from, *to, *id; XMLElement *iq_reply, *query; - IQFeatures *features = CreateIQFeatures(); + IQFeatures *features; from = HashMapGet(stanza->attrs, "from"); to = HashMapGet(stanza->attrs, "to"); @@ -164,13 +168,8 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) XMLAddAttr(iq_reply, "type", "result"); XMLAddAttr(iq_reply, "id", id); - query = IQGenerateQuery(); -#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); - IQ_ADVERT -#undef AdvertiseSimple + features = LookupJIDFeatures(to); + query = IQGenerateQuery(features); { char *ver = XMPPGenerateVer(features); char *node = StrConcat(3, REPOSITORY, "#", ver); @@ -599,10 +598,14 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) } else { + char *buf = NULL; + Stream *s = StrStreamWriter(&buf); Log(LOG_WARNING, "Unknown I/Q received:"); - XMLEncode(StreamStdout(), stanza); - StreamPrintf(StreamStdout(),"\n"); - StreamFlush(StreamStdout()); + XMLEncode(s, stanza); + StreamFlush(s); + StreamClose(s); + Log(LOG_WARNING, "%s", buf); + Free(buf); } } diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index 8602621..efdd300 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -74,6 +74,14 @@ void AddIQIdentity(IQFeatures *, char *category, char *lang, char *type, char *n void AdvertiseIQFeature(IQFeatures *, char *feature); void FreeIQFeatures(IQFeatures *); +/** + * Looks up the features supported by a JID + * ---------------------- + * Returns: an IQ featureset[LA:HEAP] | NULL + * Thrasher: FreeIQFeatures + * Modifies: NOTHING */ +IQFeatures * LookupJIDFeatures(char *jid); + /** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. * -------- * Returns: A base64 encoded ver hash[LA:HEAP] diff --git a/src/include/MUCServ.h b/src/include/MUCServ.h new file mode 100644 index 0000000..f9a2e4b --- /dev/null +++ b/src/include/MUCServ.h @@ -0,0 +1,39 @@ +#ifndef PARSEE_MUCSERV_H +#define PARSEE_MUCSERV_H + +/*-* An easy interface for handling MUCs. + */ + +typedef struct MUCServer MUCServer; + +#include + +#include + +/** Creates a MUC server handle given a ParseeData handle. + * This handle shall be used for all MUC-related operations. + * ---------------------------------------------------------- + * Returns: a MUC server handle[HEAP] | NULL + * Thrasher: FreeMUCServer + * See-Also: https://xmpp.org/extensions/xep-0045.html */ +extern MUCServer * CreateMUCServer(ParseeData *data); + +/** Manages a stanza from a MUC, and returns true if the stanza + * was actually processed by the MUC server. + * ------------------------------------------------------------- + * See-Also: CreateMUCServer */ +extern bool ManageMUCStanza(MUCServer *serv, XMLElement *stanza); + +/** Checks if a MUC(from its localpart, so + * '#foobar@bridge.blow.hole' -> 'foobar') exists. + * -------------- + * Returns: whenever the MUC exists */ +extern bool MUCServerExists(MUCServer *serv, char *muc); + +/** Destroys all memory and references from a MUC server handle. + * -------------- + * Thrashes: CreateMUCServer + * See-Also: https://xmpp.org/extensions/xep-0045.html */ +extern void FreeMUCServer(MUCServer *serv); + +#endif diff --git a/src/include/Matrix.h b/src/include/Matrix.h index a408389..fb0b5f7 100644 --- a/src/include/Matrix.h +++ b/src/include/Matrix.h @@ -2,6 +2,7 @@ #define PARSEE_MATRIX_H #include +#include #include "FileInfo.h" @@ -20,6 +21,12 @@ typedef struct UserID { * Thrasher: Free */ extern UserID * MatrixParseID(char *user); +/** Attempts to parse a Matrix ID from a matrix.to URL. + * ------------------------------------------------- + * Returns: a valid user ID[HEAP] | NULL + * Thrasher: Free */ +extern UserID * MatrixParseIDFromMTO(Uri *uri); + /* Creates an error message JSON, with the specified code and message. */ extern HashMap * MatrixCreateError(char *err, char *msg); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 30c8b61..228bf27 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -18,6 +18,8 @@ typedef struct ParseeData ParseeData; #include #include +#include + #define PARSEE_VERBOSE_NONE 0 #define PARSEE_VERBOSE_LOG 1 #define PARSEE_VERBOSE_TIMINGS 2 @@ -62,6 +64,7 @@ typedef struct ParseeData { HttpServer *server; XMPPComponent *jabber; + MUCServer *muc; Db *db; char *id; From 86deab29afefeac7f16e7227323de831a2e1e09c Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 28 Dec 2024 20:17:03 +0100 Subject: [PATCH 145/186] [FIX] Properly handle new contents with Matrix No more ugly asterisks. It annoyed me enough. --- src/MatrixEventHandler.c | 8 +++++++- src/Parsee/Utils/Formatting.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 3d6a69e..1202484 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -370,6 +370,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) DbRef *ref = NULL; HashMap *json; + char *unedited_id = MatrixGetEdit(event); char *body = GrabString(event, 2, "content", "body"); char *id = GrabString(event, 1, "room_id"); char *ev_id = GrabString(event, 1, "event_id"); @@ -381,12 +382,17 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *unauth = NULL; char *origin_id = NULL, *stanza = NULL; char *sender = NULL; - char *unedited_id = MatrixGetEdit(event); char *url = GrabString(event, 2, "content", "url"); char *encoded_from = NULL; bool direct = false; + if (unedited_id) + { + char *new_content = GrabString(event, 3, "content", "m.new_content", "body"); + if (new_content) body = new_content; + } + if (ParseeIsPuppet(data->config, m_sender) || ParseeManageBan(data, m_sender, id)) { diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 5a2c6b8..2abf3b5 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -207,6 +207,32 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) } return xepd; } +static char * +GetRawBody(HashMap *event) +{ + if (MatrixGetEdit(event)) + { + char *new = GrabString(event, 3, "content", "m.new_content", "body"); + if (new) + { + return new; + } + } + return GrabString(event, 2, "content", "body"); +} +static char * +GetHTMLBody(HashMap *event) +{ + if (MatrixGetEdit(event)) + { + char *new = GrabString(event, 3, "content", "m.new_content", "formatted_body"); + if (new) + { + return new; + } + } + return GrabString(event, 2, "content", "formatted_body"); +} char * ParseeXMPPify(HashMap *event) { @@ -231,11 +257,12 @@ ParseeXMPPify(HashMap *event) if (!StrEquals(format, "org.matrix.custom.html")) { /* Settle for the raw body instead. */ - char *body = JsonValueAsString(JsonGet(event, 2, "content", "body")); + char *body = GetRawBody(event); return StrDuplicate(body); } - html = JsonValueAsString(JsonGet(event, 2, "content", "formatted_body")); + html = GetHTMLBody(event); + html = StrConcat(3, "", html, ""); elem = XMLCDecode(StrStreamReader(html), true, true); From c365681fcbd5af5a411ea8004a63a5ce82592836 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 3 Jan 2025 15:01:35 +0100 Subject: [PATCH 146/186] [MOD] Notify MUCs about errors --- src/Main.c | 43 +++++++++++++++++++++++++++------------- src/Parsee/Data.c | 3 --- src/Parsee/User.c | 3 +-- src/Routes/Media.c | 2 +- src/Routes/Ping.c | 2 -- src/XMPP/MUCServ.c | 1 + src/XMPPCommands/MUCKV.c | 6 +++--- 7 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Main.c b/src/Main.c index 633e117..47a9576 100644 --- a/src/Main.c +++ b/src/Main.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include @@ -66,21 +66,36 @@ ParseeCheckMatrix(void *datp) if (!ASPing(data->config)) { Log(LOG_ERR, "Cannot reach '%s' properly...", data->config->homeserver_host); - if (++streak >= 5) + if (++streak == 10) { - Log(LOG_ERR, "This has been at least the fifth time in a row."); - Log(LOG_ERR, "Please check if your homeserver is active."); - Log(LOG_ERR, "%s shall now exit...", NAME); + DbRef *ref = DbLockIntent(data->db, DB_HINT_READONLY, 1, "chats"); + HashMap *json = DbJson(ref); + HashMap *mucs = GrabObject(json, 1, "mucs"); + char *muc; + void *ignored; - /* TODO: SEGV! */ - pthread_mutex_lock(&data->halt_lock); - data->halted = true; - pthread_mutex_unlock(&data->halt_lock); - XMPPFinishCompStream(data->jabber); - //pthread_join(xmpp_thr, NULL); - Log(LOG_INFO, "Stopping server..."); - HttpServerStop(data->server); + /* Notify any potential MUCs about this */ + while (HashMapIterate(mucs, &muc, &ignored)) + { + char *id = StrRandom(32); + char *sender = StrConcat(3, "parsee@", data->jabber->host, "/parsee"); + StanzaBuilder *b = CreateStanzaBuilder(sender, muc, id); + SetStanzaType(b, "groupchat"); + SetStanzaBody(b, + "This bridge hasn't been able to reach the Matrix host, and " + "as such, some messages may not have been sent over." + ); + + WriteoutStanza(b, data->jabber, 0); + DestroyStanzaBuilder(b); + + Free(sender); + Free(id); + } + (void) ignored; + + DbUnlock(data->db, ref); } return; } @@ -109,7 +124,7 @@ Main(Array *args, HashMap *env) ); ParseePrintASCII(); Log(LOG_INFO, "======================="); - Log(LOG_INFO, "(C)opyright 2024 LDA and other contributors"); + Log(LOG_INFO, "(C)opyright 2024-2025 LDA and other contributors"); Log(LOG_INFO, "(This program is free software, see LICENSE.)"); #ifdef PLATFORM_IPHONE diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 68ddf3c..46d1433 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -132,7 +132,6 @@ ParseeCleanup(void *datp) char *chat; size_t i; uint64_t ts = UtilTsMillis(); - size_t entries = 0; chats = DbList(data->db, 1, "chats"); @@ -176,7 +175,6 @@ ParseeCleanup(void *datp) if (cleaned > threshold) \ { \ DbDelete(data->db, 4, "chats", chat, #field"s", field); \ - entries++; \ } \ Free(field); \ } \ @@ -233,7 +231,6 @@ ParseeCleanup(void *datp) if (cleaned > threshold) \ { \ JsonValueFree(HashMapDelete(field##s, field)); \ - entries++; \ } \ Free(field); \ } \ diff --git a/src/Parsee/User.c b/src/Parsee/User.c index e77f20a..31ce6ff 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -538,7 +538,6 @@ ParseeGetMUCID(ParseeData *data, char *chat_id) return ret; } - void ParseeSendPresence(ParseeData *data) { @@ -562,7 +561,7 @@ ParseeSendPresence(ParseeData *data) uint64_t ts = GrabInteger(DbJson(chat), 1, "ts"); int diff = ts ? (int) ((UtilTsMillis() - ts) / 1000) : -1; /* Make a fake user join the MUC */ - Log(LOG_NOTICE, "Sending presence to %s last=%ds", rev, diff); + Log(LOG_NOTICE, "Sending presence to %s", rev); XMPPJoinMUC(data->jabber, "parsee", rev, NULL, diff, false); DbUnlock(data->db, chat); diff --git a/src/Routes/Media.c b/src/Routes/Media.c index 004a854..498eba2 100644 --- a/src/Routes/Media.c +++ b/src/Routes/Media.c @@ -48,7 +48,7 @@ RouteHead(RouteMedia, arr, argp) HashMap *reqh, *params; char *server = ArrayGet(arr, 0); char *identi = ArrayGet(arr, 1); - char *path, *key, *val; + char *key, *val; char *hmac, *chkmak = NULL; params = HttpRequestParams(args->ctx); diff --git a/src/Routes/Ping.c b/src/Routes/Ping.c index a508336..1d4191e 100644 --- a/src/Routes/Ping.c +++ b/src/Routes/Ping.c @@ -10,8 +10,6 @@ RouteHead(RoutePing, arr, argp) ParseeHttpArg *args = argp; HashMap *request = NULL; HashMap *response = NULL; - Array *events; - size_t i; response = ASVerifyRequest(args); if (response) diff --git a/src/XMPP/MUCServ.c b/src/XMPP/MUCServ.c index 66f4840..557c4a2 100644 --- a/src/XMPP/MUCServ.c +++ b/src/XMPP/MUCServ.c @@ -123,6 +123,7 @@ ManageMUCStanza(MUCServer *serv, XMLElement *stanza) /* TODO: Verify the destination, and make sure we aren't doing * anything stupid(especially with discovery) */ + (void) ret; return false; } diff --git a/src/XMPPCommands/MUCKV.c b/src/XMPPCommands/MUCKV.c index 6dba478..80ac9c4 100644 --- a/src/XMPPCommands/MUCKV.c +++ b/src/XMPPCommands/MUCKV.c @@ -18,9 +18,9 @@ void MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) { ParseeData *data = XMPPGetManagerCookie(m); - char *affiliation, *role; - char *chat_id; - char *muc; + char *affiliation = NULL, *role = NULL; + char *chat_id = NULL; + char *muc = NULL; char *key = NULL, *val = NULL; From c433e314610e22d1b145b83a8979ae58e194397d Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 3 Jan 2025 16:00:24 +0100 Subject: [PATCH 147/186] [DEL] Please enter a valid command Please enter a valid command --- src/MatrixEventHandler.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 1202484..aab9f25 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -260,11 +260,6 @@ ParseeBotHandler(ParseeData *data, HashMap *event) if (*body != '!') { /* All commands are to be marked with a ! */ - Free(ASSend( - data->config, id, profile, - "m.room.message", - MatrixCreateNotice("Please enter a valid command"), 0 - )); Free(profile); return; } From 5e1931a19f8954628287802e9f15a26145001d7b Mon Sep 17 00:00:00 2001 From: lda Date: Mon, 6 Jan 2025 17:09:36 +0000 Subject: [PATCH 148/186] [MOD] Change media path, connect to component through another address --- README.MD | 3 +-- src/HttParsee.c | 2 +- src/Main.c | 3 ++- src/Parsee/Config.c | 10 ++++++++++ src/Parsee/User.c | 2 +- src/XMPP/Component.c | 13 +++++++++++-- src/include/Parsee.h | 2 ++ src/include/Routes.h | 2 +- src/include/XMPP.h | 2 +- 9 files changed, 30 insertions(+), 9 deletions(-) diff --git a/README.MD b/README.MD index 9a7fc6f..ce51662 100644 --- a/README.MD +++ b/README.MD @@ -18,8 +18,7 @@ A more "up-to-date" reason may be to have a small, 'Just Werks' bridging solutio and maybe as a testing ground for Cytoplasm features I sometimes add. (Well, I'm *trying* to do that, at least. -Please scream at me if that fails(or just doesn't run on a overclocked Raspberry -Pi 4B, which, by the way, is literally where Parsee+XMPP is running for now.)) +Please scream at me if that fails(or just doesn't run on a overclocked Raspberry Pi 4B)) ### "Why not just use Matrix lol" ### "Why not just use XMPP lol" diff --git a/src/HttParsee.c b/src/HttParsee.c index 724f9ff..572487c 100644 --- a/src/HttParsee.c +++ b/src/HttParsee.c @@ -73,7 +73,7 @@ ParseeCreateRequest(const ParseeConfig *conf, HttpRequestMethod meth, char *path ctx = HttpRequest( meth, - HTTP_FLAG_TLS, + conf->homeserver_tls ? HTTP_FLAG_TLS : HTTP_FLAG_NONE, conf->homeserver_port, conf->homeserver_host, path ); diff --git a/src/Main.c b/src/Main.c index 47a9576..3e740ed 100644 --- a/src/Main.c +++ b/src/Main.c @@ -223,9 +223,11 @@ Main(Array *args, HashMap *env) Log(LOG_NOTICE, "Connecting to XMPP..."); jabber = XMPPInitialiseCompStream( + parsee_conf->component_addr, parsee_conf->component_host, parsee_conf->component_port ); + Log(LOG_NOTICE, "Connecting to XMPP... %p", jabber); if (!XMPPAuthenticateCompStream( jabber, parsee_conf->shared_comp_secret @@ -290,7 +292,6 @@ Main(Array *args, HashMap *env) { char *parsee = ParseeMXID(conf.handlerArgs); - /* TODO: An hardcoded avatar like this sucks. */ ASSetAvatar(parsee_conf, parsee, "mxc://tedomum.net/" diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 0898063..3b4ce45 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -44,6 +44,9 @@ ParseeConfigLoad(char *conf) #define CopyToInt(to, str) config->to = (int) ( \ JsonValueAsInteger(HashMapGet(json, str)) \ ) +#define CopyToBool(to, str) config->to = (int) ( \ + JsonValueAsBoolean(HashMapGet(json, str)) \ + ) config->http_threads = 8; config->xmpp_threads = 8; @@ -58,8 +61,14 @@ ParseeConfigLoad(char *conf) CopyToStr(server_base, "hs_base"); CopyToStr(homeserver_host, "hs_host"); CopyToInt(homeserver_port, "hs_port"); + CopyToBool(homeserver_tls, "hs_tls"); + if (!HashMapGet(json, "hs_tls")) + { + config->homeserver_tls = true; + } CopyToInt(component_port, "component_port"); + CopyToStr(component_addr, "component_addr"); CopyToStr(component_host, "component_host"); CopyToStr(shared_comp_secret, "shared_secret"); CopyToInt(max_stanza_size, "max_stanza_size"); @@ -129,6 +138,7 @@ ParseeConfigFree(void) return; } Free(config->component_host); + Free(config->component_addr); Free(config->shared_comp_secret); Free(config->db_path); Free(config->homeserver_host); diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 31ce6ff..5a945ea 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -692,7 +692,7 @@ ParseeToUnauth(ParseeData *data, char *mxc) Uri *url = NULL; char *ret; char *key, *hmac; -#define PAT "%s/_matrix/client/v1/media/download/%s%s?hmac=%s" +#define PAT "%s/media/%s%s?hmac=%s" size_t l; if (!data || !mxc) { diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 42e2992..840bec2 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -19,7 +19,7 @@ #define DEFAULT_PROSODY_PORT 5347 XMPPComponent * -XMPPInitialiseCompStream(char *host, int port) +XMPPInitialiseCompStream(char *addr, char *host, int port) { int sd = -1; struct addrinfo hints, *res, *res0; @@ -28,12 +28,17 @@ XMPPInitialiseCompStream(char *host, int port) Stream *stream; XMPPComponent *comp; + if (!addr) + { + addr = host; + } + snprintf(serv, sizeof(serv), "%hu", port ? port : DEFAULT_PROSODY_PORT); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(host, serv, &hints, &res0); + error = getaddrinfo(addr, serv, &hints, &res0); if (error) { const char *error_str = gai_strerror(error); @@ -66,6 +71,10 @@ XMPPInitialiseCompStream(char *host, int port) if (sd < 0) { + Log(LOG_ERR, + "%s: cannot connect to '%s': no socket available", __func__, + host + ); return NULL; } freeaddrinfo(res0); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 228bf27..a2c73d2 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -41,9 +41,11 @@ typedef struct ParseeConfig { /* Homeserver port info */ char *homeserver_host; int homeserver_port; + int homeserver_tls; /* ------- JABBER -------- */ + char *component_addr; char *component_host; char *shared_comp_secret; int component_port; diff --git a/src/include/Routes.h b/src/include/Routes.h index 8d233e6..cfeea4f 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -75,7 +75,7 @@ typedef struct ParseeCmdArg { X_ROUTE("/_matrix/app/v1/users/(.*)", RouteUserAck) \ X_ROUTE("/_matrix/app/v1/rooms/(.*)", RouteRoomAck) \ X_ROUTE("/_matrix/app/v1/ping", RoutePing) \ - X_ROUTE("/_matrix/client/v1/media/download/(.*)/(.*)", RouteMedia) + X_ROUTE("/media/(.*)/(.*)", RouteMedia) #define X_ROUTE(path, name) extern void * name(Array *, void *); ROUTES diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 92a5d80..22e98f6 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -22,7 +22,7 @@ typedef struct XMPPComponent { /* Initialises a raw component stream to host, with an optional port. * If said port is 0, then it is set to the default Prosody port */ -extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); +extern XMPPComponent * XMPPInitialiseCompStream(char *addr, char *host, int port); /* Authenticates a component stream with a given shared secret, * with a stream ID from the server. This should be called right From 0facbaa5e5e4c0d90fd9742a4b4f86f48b9ef7d6 Mon Sep 17 00:00:00 2001 From: lda Date: Tue, 7 Jan 2025 15:14:47 +0000 Subject: [PATCH 149/186] [ADD/FIX/WIP] Allow reverting noflys, ignore MUC DMs (for now) --- src/Commands/BanUser.c | 19 +++++++++++++++++++ src/MatrixEventHandler.c | 14 +++++++------- src/Parsee/Utils/Nofly.c | 22 ++++++++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 17 ++++++++++++++--- src/include/Parsee.h | 9 ++++++++- src/include/Routes.h | 4 ++++ 6 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/Commands/BanUser.c b/src/Commands/BanUser.c index adc505e..dd380ed 100644 --- a/src/Commands/BanUser.c +++ b/src/Commands/BanUser.c @@ -28,6 +28,25 @@ CommandHead(CmdBanUser, cmd, argp) BotDestroy(); } +CommandHead(CmdNoFlyListDel, cmd, argp) +{ + ParseeCmdArg *args = argp; + ParseeData *data = args->data; + HashMap *event = args->event; + char *user = HashMapGet(cmd->arguments, "user"); + BotInitialise(); + + if (!user) + { + BotDestroy(); + return; + } + + ReplySprintf("Unbanning %s", user); + ParseeGlobalUnban(data, user); + + BotDestroy(); +} CommandHead(CmdNoFlyList, cmd, argp) { ParseeCmdArg *args = argp; diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index aab9f25..89e342d 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -291,10 +291,10 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) char *room_id = GrabString(event, 1, "room_id"); char *matrix_sender = GrabString(event, 1, "sender"); char *chat_id = NULL, *muc_id = NULL; - char *user; + char *user = NULL; - DbRef *room_data; - HashMap *data_json; + DbRef *room_data = NULL; + HashMap *data_json = NULL; bool direct = false; if (!data || !event || !from || !to) @@ -326,8 +326,8 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } else { - char *matrix_name, *matrix_avatar; - char *mime, *sha; + char *matrix_name = NULL, *matrix_avatar = NULL; + char *mime = NULL, *sha = NULL; muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -361,9 +361,9 @@ static void ParseeMessageHandler(ParseeData *data, HashMap *event) { XMPPComponent *jabber = data->jabber; - StanzaBuilder *builder; + StanzaBuilder *builder = NULL; DbRef *ref = NULL; - HashMap *json; + HashMap *json = NULL; char *unedited_id = MatrixGetEdit(event); char *body = GrabString(event, 2, "content", "body"); diff --git a/src/Parsee/Utils/Nofly.c b/src/Parsee/Utils/Nofly.c index 8a82c0f..439c7d0 100644 --- a/src/Parsee/Utils/Nofly.c +++ b/src/Parsee/Utils/Nofly.c @@ -6,6 +6,28 @@ #include #include +void +ParseeGlobalUnban(ParseeData *data, char *glob) +{ + DbRef *ref; + HashMap *j; + if (!data || !glob) + { + return; + } + + ref = DbLock(data->db, 1, "global_bans"); + if (!ref) + { + ref = DbCreate(data->db, 1, "global_bans"); + } + + j = DbJson(ref); + + JsonValueFree(HashMapDelete(j, glob)); + + DbUnlock(data->db, ref); +} void ParseeGlobalBan(ParseeData *data, char *glob, char *reason) { diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 3c57e69..5497f19 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -394,11 +394,17 @@ end_error: bool media_enabled = chat_id ? ParseeIsMediaEnabled(args, chat_id) : true ; - + bool is_parsee; + /* Note that chat_id still has meaningful info as a boolean + * despite being freed */ Free(chat_id); - pthread_mutex_unlock(&thr->info->chk_lock); + parsee = ParseeJID(args); + is_parsee = StrEquals(to, parsee); + Free(parsee); + parsee = NULL; + LazyRegister(args, encoded, !chat ? res : NULL); if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) { @@ -411,7 +417,12 @@ end_error: /* Check if it is a media link */ oob = XMLookForTKV(stanza, "x", "xmlns", "jabber:x:oob"); - if (oob && data && media_enabled) + if (chat_id && StrEquals(type, "chat") && !is_parsee) + { + /* Very clearly a MUC DM. */ + event_id = NULL; + } + else if (oob && data && media_enabled) { char *mxc, *mime = NULL; HashMap *content = NULL; diff --git a/src/include/Parsee.h b/src/include/Parsee.h index a2c73d2..8bc4429 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -397,10 +397,17 @@ extern void ParseeDestroyNickTable(void); * to ban them from rooms where Parsee has the ability to do so ("noflying"). * --------------- * Returns: NOTHING - * See-Also: ParseeManageBan + * See-Also: ParseeManageBan, ParseeGlobalUnban * Modifies: the database */ extern void ParseeGlobalBan(ParseeData *, char *user, char *reason); +/** Revokes a user/room/MUC's nofly status + * --------------- + * Returns: NOTHING + * See-Also: ParseeManageBan, ParseeGlobalBan + * Modifies: the database */ +extern void ParseeGlobalUnban(ParseeData *, char *user); + /** Verifies if a user was banned globally. If so (and if {room} is set), * tries to ban the user from it. * --------------- diff --git a/src/include/Routes.h b/src/include/Routes.h index cfeea4f..b927eff 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -27,6 +27,10 @@ typedef struct ParseeCmdArg { "ban-list", CmdNoFlyList, \ "Globally bans a user from using Parsee" \ ) \ + X_COMMAND( \ + "unban-list", CmdNoFlyListDel, \ + "Globally unbans a user from using Parsee" \ + ) \ X_COMMAND( \ "nuke-muc", CmdUnlinkMUC, \ "Removes a MUC. Users should then run " \ From 389870c5d361597023b324e0c71a49541e7f9509 Mon Sep 17 00:00:00 2001 From: lda Date: Sat, 25 Jan 2025 12:20:47 +0000 Subject: [PATCH 150/186] [FIX] Ignore unavailable statuses They aren't that useful, especially in MUCs. --- etc/man/man7/.parsee-bridge-guidebook.7.swp | Bin 0 -> 12288 bytes etc/man/man7/.parsee-cmd-syntax.7.swp | Bin 0 -> 12288 bytes etc/man/man7/parsee-bridge-guidebook.7 | 70 ++++++++++++++++++++ src/MatrixEventHandler.c | 18 +++-- src/Parsee/Utils/Formatting.c | 4 +- src/Unistr.c | 10 +++ src/XMPPThread/Stanzas/IQ.c | 5 +- src/XMPPThread/Stanzas/Presence.c | 4 +- src/include/Unistring.h | 6 ++ 9 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 etc/man/man7/.parsee-bridge-guidebook.7.swp create mode 100644 etc/man/man7/.parsee-cmd-syntax.7.swp create mode 100644 etc/man/man7/parsee-bridge-guidebook.7 diff --git a/etc/man/man7/.parsee-bridge-guidebook.7.swp b/etc/man/man7/.parsee-bridge-guidebook.7.swp new file mode 100644 index 0000000000000000000000000000000000000000..50976eabdb0b742fe8fbb5be8a1dc7c97357d1b7 GIT binary patch literal 12288 zcmeHN&5ImG6fYIOjf$T1ATKMJ1a^88KZwS!Y<9?+_o|nz z(ZNT0YjjU^P~dgF5O?17+T>Mnv-oCsgUAxeS1Acif2}jBbTUz$Nv#t#GUiNl_@7t}V*&$#feSKFyK(34J)3vje#n>ltqXhU#v3*- zI4uka3NJ|NZ~@bwa!aJOMloYy#H; zdw}1r72;RmLm&li0nY6a;wRue;0@pv;6>mC;A!AE@Br}hH9~v^dfc_{f7^TXyXKJbi1^Ca${YHVX7@9Ca!Z; zIKub3NK{2-J<4>98#n@2ERv~cW#u60F%`y<%rY}o35{lynOJ6&$!X;6p6so3`x{*$ zw4;eCRE424(#4j^wv?sZZ0TY`E|rePI#c8f%}iZUYI0>oW@G}hx;XE$s&eAYzp(a`S7XCk5jtrr;PQq^9Kp0b$k0|9Z3@nn%B@)l|f6Jp!jsb*&t z0)!{9J||rzk?48qWrmQBWYDcYsNYph!@Gyc9De%lWcUCJ@Jq(SbyFatw~quvp(5~(e$OM=sAa@=Kj7?UALWa)+iR5^x+!j#JiBS~Y1OLY8fUP7H^Gd7%5Jsg6@$*cQXN zesYztgRLM?32gx!X#Hv^K+t3zmdRPnT=rO16>&8yol5q$l1=p_MHHwplcR%h`TFW^ zJ>f#~o-&8fZ(f>$`;2cJoEe|ZUh_MJAdein{f;}gOtJA;IE8xnXvsut&Z=M{uotO0}h z+=;jrEJDoCSA1c&{<2uK+h@tvqjnSr%MNer9r~<%363FPnDs8R+OP)qkW_9Vns$*L zpS*NICHFD(V9gE9PuR=4h|vxvjVogqg`MjBz7f$NQ)mF37fzPJ*BI`OYhNnR2c~g_ zkVxWRI_ZHbjMR#VIdm959V!dKS&k97OP-gWUDN!y3VeGSiL zmgKt7C{u|o&PD_>nFZeBd;Q_*_0`Q4PKFTWUmrxL4lT3S=sG+0Q6yE})Qg;_qdCFu z4fmJVu)#;e6Z6N5Kb~%YVfTY@=jDCbM$I7 M2BeIpau$i-0os$Jhx%iV+&`&e|jG4|iwX z)UC>o8$EC-f*XSWg1>_^;*7+F0~|PT;5+MesMzP5W0g2|HfKd! z&5whcT_m}>3E5CdXB z42Xf}+(15Cqt7sh7s`1w%KO@5_wrG0Vn7Ut0Wly3#DEwO17bi7hygJm2E@Q~Xg~!- zS6?A|=^T>B|NmEi|NrzV(RV)0QbQs-~@aCZi4He1ulS> z0fE2I6a5AL1b=|v!EfLf@HKb{z5-u@&%sUb9=HbH20tUu@4>g=A$S1pfx939Z-Fb| zP2lGAB9KcAhygJm2E>3E5CdXB42Xfp40wCIJcheoze?Wl1`pe9ZXOH|iH@ema*+D- zSSLB-_dE%7#>8TEQyx=JHRm71x^@_L$omRUy zY!hYL&a|JK+d5j{)gF)5Gg~2*1gnQC^s-~o4=y?*n0 zd&ut}4!GYO6gzX!=HuRe8x6;M*iyWI*ll)tm`{b>T8fm-IW#&7iVaXK#6Tx1)^NEf KR_3X~w)+SCjabber, jid, rev, hash, -1, true) && nonce < 32) { char *nonce_str = StrInt(nonce); char *input = StrConcat(3, sender, name, nonce_str); char *hex = ParseeHMACS(data->id, input); + Unistr *filterASCII = UnistrFilter(uninick, UnistrIsASCII); if (strlen(hex) >= 8) { @@ -45,6 +48,7 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char Free(nick); Free(rev); + Free(revscii); nick = StrConcat(4, name, "[", hex, "]"); rev = StrConcat(3, muc, "/", nick); @@ -364,13 +368,13 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) StanzaBuilder *builder = NULL; DbRef *ref = NULL; HashMap *json = NULL; - - char *unedited_id = MatrixGetEdit(event); + + char *m_sender = GrabString(event, 1, "sender"); + char *unedited_id = NULL; char *body = GrabString(event, 2, "content", "body"); char *id = GrabString(event, 1, "room_id"); char *ev_id = GrabString(event, 1, "event_id"); - char *m_sender = GrabString(event, 1, "sender"); - char *chat_id, *muc_id; + char *chat_id = NULL, *muc_id = NULL; char *reply_id = MatrixGetReply(event); char *xepd = ParseeXMPPify(event); char *type, *user, *xmppified_user = NULL, *to = NULL; @@ -381,6 +385,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *encoded_from = NULL; bool direct = false; + unedited_id = MatrixGetEdit(event); if (unedited_id) { @@ -455,6 +460,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) Free(name); Free(avatar); } + if (reply_id) { /* TODO: Monocles chat DM users HATE this trick! @@ -511,8 +517,8 @@ end: Free(stanza); Free(sender); Free(unauth); - Free(unedited_id); Free(encoded_from); + Free(unedited_id); DbUnlock(data->db, ref); ref = NULL; diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 2abf3b5..8f41a56 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -210,9 +210,11 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) static char * GetRawBody(HashMap *event) { - if (MatrixGetEdit(event)) + void *id; + if ((id = MatrixGetEdit(event))) { char *new = GrabString(event, 3, "content", "m.new_content", "body"); + Free(id); if (new) { return new; diff --git a/src/Unistr.c b/src/Unistr.c index 5eaae43..a1eb1e4 100644 --- a/src/Unistr.c +++ b/src/Unistr.c @@ -192,6 +192,16 @@ UnistrGetch(Unistr *unistr, size_t i) return i < unistr->length ? unistr->codepoints[i] : 0; } bool +UnistrIsASCII(uint32_t u) +{ + if (u == 0) + { + return NULL; + } + + return u < 0x7F; +} +bool UnistrIsBMP(uint32_t u) { if (u == 0) diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 17092b0..af71cca 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -572,7 +572,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) else if (XMLookForTKV(stanza, "query", "xmlns", "jabber:iq:version")) { XMLElement *iq_reply, *query; - XMLElement *name, *version; + XMLElement *name, *version, *os; iq_reply = XMLCreateTag("iq"); XMLAddAttr(iq_reply, "to", from); @@ -585,12 +585,15 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { name = XMLCreateTag("name"); version = XMLCreateTag("version"); + os = XMLCreateTag("os"); XMLAddChild(name, XMLCreateText(NAME)); XMLAddChild(version, XMLCreateText(VERSION "[" CODE "]")); + XMLAddChild(os, XMLCreateText(VERSION "POSIX-like")); } XMLAddChild(query, name); XMLAddChild(query, version); + XMLAddChild(query, os); XMLAddChild(iq_reply, query); XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 65c2082..947fc4b 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -298,7 +298,7 @@ end_item: Free(room); FreeStatuses(statuses); } - if (status) + if (status && !StrEquals(type, "unavailable")) { XMLElement *status_data = ArrayGet(status->children, 0); char *decode_from = ParseeLookupJID(oid); @@ -309,6 +309,8 @@ end_item: status_str = status_data->data; } + + /* TODO: "The server will automatically set a user's presence to * unavailable if their last active time was over a threshold value * (e.g. 5 minutes)." diff --git a/src/include/Unistring.h b/src/include/Unistring.h index 6fbc296..d90d61c 100644 --- a/src/include/Unistring.h +++ b/src/include/Unistring.h @@ -64,6 +64,12 @@ extern void UnistrFree(Unistr *unistr); * Returns: whenever the character is within the BMP */ extern bool UnistrIsBMP(uint32_t u); +/** Returns true IFF the character is within the 7-bit ASCII range + * not 0x0000 + * ------------------------------------------------------------ + * Returns: whenever the character is within ASCII */ +extern bool UnistrIsASCII(uint32_t u); + typedef bool (*UnistrFilterFunc)(uint32_t u); /** "Filters" characters in a Unistring by codepoint, removing * those with callbacks which return false into a new unistring. From f9de7f17504c01759d59e4b581d36a3832cd8c70 Mon Sep 17 00:00:00 2001 From: lda Date: Tue, 28 Jan 2025 15:01:57 +0000 Subject: [PATCH 151/186] [MOD/FIX] Be a bit more specific with component errors --- src/MatrixEventHandler.c | 10 ++-------- src/Signal.c | 7 +------ src/XMPP/Component.c | 8 ++++++++ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 60a41c7..bf42124 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -26,20 +26,15 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char char *rev = StrConcat(3, muc, "/", nick); int nonce = 0; - Log(LOG_DEBUG, "MUCJOINER: filtered '%s' to '%s'", name, nick); - UnistrFree(uninick); UnistrFree(filtered); - UnistrFree(filterASCII); - /* TODO: Make sure that we fall back to plain ASCII if it fails too many - * times. */ + /* TODO: vCards! */ while (!XMPPJoinMUC(data->jabber, jid, rev, hash, -1, true) && nonce < 32) { char *nonce_str = StrInt(nonce); char *input = StrConcat(3, sender, name, nonce_str); char *hex = ParseeHMACS(data->id, input); - Unistr *filterASCII = UnistrFilter(uninick, UnistrIsASCII); if (strlen(hex) >= 8) { @@ -48,7 +43,6 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char Free(nick); Free(rev); - Free(revscii); nick = StrConcat(4, name, "[", hex, "]"); rev = StrConcat(3, muc, "/", nick); @@ -368,7 +362,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) StanzaBuilder *builder = NULL; DbRef *ref = NULL; HashMap *json = NULL; - + char *m_sender = GrabString(event, 1, "sender"); char *unedited_id = NULL; char *body = GrabString(event, 2, "content", "body"); diff --git a/src/Signal.c b/src/Signal.c index e9d00e8..3f01dcb 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -26,11 +26,6 @@ SignalHandler(int signal) HttpServerStop(data->server); return; } - if (signal == SIGPIPE) - { - Log(LOG_DEBUG, "Caught a SIGPIPE..."); - return; - } } bool @@ -46,7 +41,7 @@ ParseeInitialiseSignals(ParseeData *d, pthread_t xmpp) sa.sa_flags = SA_RESTART; #define Register(act) (sigaction(act, &sa, NULL) >= 0) - if (!Register(SIGTERM) || !Register(SIGINT) || !Register(SIGPIPE)) + if (!Register(SIGTERM) || !Register(SIGINT)) { Log(LOG_ERR, "Couldn't register signals..."); return false; diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 840bec2..1bdff53 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -61,6 +61,10 @@ XMPPInitialiseCompStream(char *addr, char *host, int port) if (connect(sd, res->ai_addr, res->ai_addrlen) < 0) { + Log(LOG_ERR, + "%s: cannot connect to '%s': %s", __func__, + host, strerror(errno) + ); close(sd); sd = -1; continue; @@ -82,6 +86,10 @@ XMPPInitialiseCompStream(char *addr, char *host, int port) stream = StreamFd(sd); if (!stream) { + Log(LOG_ERR, + "%s: cannot connect to '%s': %s", __func__, + host, "couldn't create a Cytoplasm stream" + ); close(sd); return NULL; } From b485298fbc6893582ef4623ae6cea7643119fa49 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 29 Jan 2025 19:15:23 +0100 Subject: [PATCH 152/186] [FIX] Log error if the config was not parsed --- src/Parsee/Config.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 3b4ce45..46a391f 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -36,6 +36,12 @@ ParseeConfigLoad(char *conf) return; } json = JsonDecode(stream); + if (!json) + { + Log(LOG_ERR, "Could not parse config JSON"); + StreamClose(stream); + return; + } config = Malloc(sizeof(*config)); #define CopyToStr(to, str) config->to = StrDuplicate( \ From 1e7d71f9f61890675a987257592217e32de0dbd2 Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 5 Feb 2025 08:54:45 +0100 Subject: [PATCH 153/186] [ADD] Allow people to see component errors --- src/XMPP/Component.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 1bdff53..12f9f9e 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -182,6 +182,49 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) { Log(LOG_ERR, "Excepted empty handshake reply, got nonsense."); Log(LOG_ERR, "Another service (possibly Parsee) may have taken over."); + while ((ev = XMLCrank(sax))) + { + char *key, *val; + switch (ev->type) + { + case XML_LEXER_STARTELEM: + Log(LOG_DEBUG, "<%s>", ev->element); + + LogConfigIndent(LogConfigGlobal()); + LogConfigIndent(LogConfigGlobal()); + /* TODO: Log out attributes a little better */ + while (HashMapIterate(ev->attrs, &key, (void **) &val)) + { + Log(LOG_DEBUG, "(%s=%s)", key, val); + } + LogConfigUnindent(LogConfigGlobal()); + LogConfigUnindent(LogConfigGlobal()); + + LogConfigIndent(LogConfigGlobal()); + break; + case XML_LEXER_ELEM: + Log(LOG_DEBUG, "<%s/>", ev->element); + LogConfigIndent(LogConfigGlobal()); + LogConfigIndent(LogConfigGlobal()); + /* TODO: Log out attributes a little better */ + while (HashMapIterate(ev->attrs, &key, (void **) &val)) + { + Log(LOG_DEBUG, "(%s=%s)", key, val); + } + LogConfigUnindent(LogConfigGlobal()); + LogConfigUnindent(LogConfigGlobal()); + break; + case XML_LEXER_ENDELEM: + Log(LOG_DEBUG, "", ev->element); + LogConfigIndent(LogConfigGlobal()); + break; + case XML_LEXER_DATA: + Log(LOG_DEBUG, "%s", ev->data); + break; + } + XMLFreeEvent(ev); + } + LogConfigIndentSet(LogConfigGlobal(), 0); Log(LOG_ERR, ""); Log(LOG_ERR, "Simply jealous of that other service..."); Free(stream_id); From 110a1b695f2689b982944971bfb654d3ba43bc1c Mon Sep 17 00:00:00 2001 From: LDA Date: Wed, 5 Feb 2025 08:58:25 +0100 Subject: [PATCH 154/186] [FIX] Fix the indenting --- src/XMPP/Component.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 12f9f9e..e3ff4e4 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -215,8 +215,8 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) LogConfigUnindent(LogConfigGlobal()); break; case XML_LEXER_ENDELEM: + LogConfigUnindent(LogConfigGlobal()); Log(LOG_DEBUG, "", ev->element); - LogConfigIndent(LogConfigGlobal()); break; case XML_LEXER_DATA: Log(LOG_DEBUG, "%s", ev->data); From 4f694129fc9ff297cae318fb53fe238948a5bab1 Mon Sep 17 00:00:00 2001 From: lda Date: Fri, 7 Feb 2025 18:34:45 +0000 Subject: [PATCH 155/186] [FIX] Fix silly SEGV Thanks, EP --- src/MatrixEventHandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index bf42124..fa44d2d 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -255,7 +255,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) return; } - if (*body != '!') + if (!body || *body != '!') { /* All commands are to be marked with a ! */ Free(profile); From c2536c2e846bb764bcb59ebd42866af81e94a745 Mon Sep 17 00:00:00 2001 From: lda Date: Fri, 7 Feb 2025 18:52:58 +0000 Subject: [PATCH 156/186] [FIX] Log out some MUC information --- src/XMPP/MUC.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 67bc9d1..9ecfcf2 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -44,6 +44,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) Free(uuid); if (!iq_query || !StrEquals(iq_query->name, "iq")) { + Log(LOG_ERR, "Didn't receive an stanza"); XMLFreeElement(iq_query); return false; } @@ -55,6 +56,11 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) "conference")) { XMLFreeElement(iq_query); + Log(LOG_DEBUG, "MUC INFO ERROR"); + Log(LOG_DEBUG, + "identityp=%p category=%s", identity, + identity ? HashMapGet(identity->attrs, "category") : NULL + ); return false; } From 1936be0078dcd7a53b35577220bca8228792356a Mon Sep 17 00:00:00 2001 From: lda Date: Sat, 8 Feb 2025 08:45:21 +0000 Subject: [PATCH 157/186] [FIX] Fix minor DB fuckup with tools Used to open a flatfile database whenever it couldn't find an LMDB one, which obviously caused *problems* --- tools/adminify.c | 39 +++++++++++++++++++-------------------- tools/common.h | 2 +- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/tools/adminify.c b/tools/adminify.c index e87d97e..1fdd6cf 100644 --- a/tools/adminify.c +++ b/tools/adminify.c @@ -89,31 +89,30 @@ Main(Array *args, HashMap *env) glob = ArrayGet(args, 2); parsee = GetDB(db_path); - if (parsee) + if (!parsee) { + Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path); + (void) env; + return EXIT_FAILURE; + } - if (glob) - { - Log(LOG_NOTICE, "Adding glob '%s' to database %s", glob, db_path); - AddAdmin(parsee, glob); - Log(LOG_INFO, "Successfully added glob %s.", glob); - Log(LOG_INFO, "*I'm jealous of all these admins!*"); - - DbClose(parsee); - return EXIT_SUCCESS; - } - - /* List admins */ - Log(LOG_INFO, "Admin list:"); - LogConfigIndent(LogConfigGlobal()); - ListAdmins(parsee); - LogConfigUnindent(LogConfigGlobal()); + if (glob) + { + Log(LOG_NOTICE, "Adding glob '%s' to database %s", glob, db_path); + AddAdmin(parsee, glob); + Log(LOG_INFO, "Successfully added glob %s.", glob); + Log(LOG_INFO, "*I'm jealous of all these admins!*"); DbClose(parsee); return EXIT_SUCCESS; } - Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path); - (void) env; - return EXIT_FAILURE; + /* List admins */ + Log(LOG_INFO, "Admin list:"); + LogConfigIndent(LogConfigGlobal()); + ListAdmins(parsee); + LogConfigUnindent(LogConfigGlobal()); + + DbClose(parsee); + return EXIT_SUCCESS; } diff --git a/tools/common.h b/tools/common.h index eee4793..9687ea3 100644 --- a/tools/common.h +++ b/tools/common.h @@ -108,7 +108,7 @@ GetDB(char *config) { ret = DbOpenLMDB(db_path, lmdb_size); } - if (!ret) + else { ret = DbOpen(db_path, 0); } From f94db460ac6459f8ebe94d63f7140c2e40325dcc Mon Sep 17 00:00:00 2001 From: lda Date: Sun, 9 Feb 2025 21:51:38 +0000 Subject: [PATCH 158/186] [FIX/WIP] Fix annoying formatting bug Fixes #16 --- src/Parsee/Utils/Formatting.c | 9 ++ src/XML/Parser.c | 6 ++ src/XML/SAX.c | 37 ++++++++- src/include/XML.h | 2 + tools/plumb.c | 152 ++++++++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 tools/plumb.c diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 8f41a56..17f513f 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -267,6 +268,14 @@ ParseeXMPPify(HashMap *event) html = StrConcat(3, "", html, ""); elem = XMLCDecode(StrStreamReader(html), true, true); + if (!elem) + { + /* Settle for the raw body instead. + * TODO: Have the parser be more leinent on errors in HTML mode. */ + char *body = GetRawBody(event); + Free(html); + return StrDuplicate(body); + } flags.quote = false; xepd = XMPPifyElement(event, elem, flags); diff --git a/src/XML/Parser.c b/src/XML/Parser.c index 506e49d..350f0e4 100644 --- a/src/XML/Parser.c +++ b/src/XML/Parser.c @@ -31,6 +31,12 @@ XMLCDecode(Stream *stream, bool autofree, bool html) bool flag = false; switch (event->type) { + case XML_ERROR: + XMLFreeEvent(event); + XMLFreeElement(ret); + ArrayFree(stack); + XMLFreeLexer(lexer); + return NULL; case XML_LEXER_STARTELEM: /* Create a new element that will populated. */ top = XMLCreateTag(event->element); diff --git a/src/XML/SAX.c b/src/XML/SAX.c index 21430bb..defea6b 100644 --- a/src/XML/SAX.c +++ b/src/XML/SAX.c @@ -58,6 +58,7 @@ static char * XMLPopElement(XMLexer *lexer); static XMLEvent * XMLCreateEmptyElem(XMLexer *lexer, HashMap *attrs); static XMLEvent * XMLCreateStart(XMLexer *lexer, HashMap *attrs); static XMLEvent * XMLCreateRelax(XMLexer *lexer); +static XMLEvent * XMLCreateError(XMLexer *lexer); static XMLEvent * XMLCreateEnd(XMLexer *lexer, char *end); static XMLEvent * XMLCreateData(XMLexer *lexer); @@ -198,7 +199,9 @@ XMLCrank(XMLexer *lexer) else if (XMLookahead(lexer, "--", false)) { /* Throw error */ - return NULL; + XMLFreeEvent(event); + event = XMLCreateError(lexer); + break; } break; case XML_STATE_PI: @@ -215,6 +218,9 @@ XMLCrank(XMLexer *lexer) if (!attrname) { /* TODO: Throw error */ + XMLFreeEvent(event); + event = XMLCreateError(lexer); + break; } XMLPushElement(lexer, attrname); @@ -241,7 +247,10 @@ XMLCrank(XMLexer *lexer) } else if (XMLookahead(lexer, "'", true)) { - while (true); + //while (true); uh oh + XMLFreeEvent(event); + event = XMLCreateError(lexer); + break; } break; case XML_STATE_ATTRTAIL: @@ -250,6 +259,8 @@ XMLCrank(XMLexer *lexer) if (!XMLookahead(lexer, ">", true)) { /* TODO: Throw error. */ + XMLFreeEvent(event); + event = XMLCreateError(lexer); break; } lexer->state = XML_STATE_NONE; @@ -258,6 +269,8 @@ XMLCrank(XMLexer *lexer) break; default: /* TODO */ + XMLFreeEvent(event); + event = XMLCreateError(lexer); break; } /* TODO: Crank our XML parser. */ @@ -693,6 +706,26 @@ XMLCreateData(XMLexer *lexer) return event; } static XMLEvent * +XMLCreateError(XMLexer *lexer) +{ + XMLEvent *event = Malloc(sizeof(*event)); + size_t elements = ArraySize(lexer->data.elements); + + event->type = XML_ERROR; + event->element = elements ? + StrDuplicate(ArrayGet(lexer->data.elements, elements - 1)) : + NULL; + event->attrs = NULL; + event->data = NULL; + + /* TODO */ + event->line = 0; + event->col = 0; + event->offset = 0; + + return event; +} +static XMLEvent * XMLCreateRelax(XMLexer *lexer) { XMLEvent *event = Malloc(sizeof(*event)); diff --git a/src/include/XML.h b/src/include/XML.h index 8fd108d..c7b6610 100644 --- a/src/include/XML.h +++ b/src/include/XML.h @@ -13,6 +13,8 @@ typedef struct XMLEvent { XML_LEXER_DATA, XML_LEXER_ELEM, /* Empty attr */ XML_LEXER_ENDELEM, + + XML_ERROR, XML_RELAX } type; diff --git a/tools/plumb.c b/tools/plumb.c new file mode 100644 index 0000000..1bc9e14 --- /dev/null +++ b/tools/plumb.c @@ -0,0 +1,152 @@ +/* plumb.c - Small utility to manage plumbings from a shutoff instance. + * ============================================================ + * TODO: write other commands, and move some code to common.h + * + * Under CC0, as its a rather useful example of a Parsee tool. + * See LICENSE for more information about Parsee's licensing. */ + +#include "common.h" + +#include + +static void +DeletePlumbID(Db *parsee, char *chat_id) +{ + DbRef *chat_id_ref = DbLockIntent(parsee, DB_HINT_READONLY, 2, "chats", chat_id); + DbRef *chats = DbLock(parsee, 1, "chats"); + char *matrix_id = GrabString(DbJson(chat_id_ref), 1, "room_id"); + char *jabber_id = GrabString(DbJson(chat_id_ref), 1, "jabber_id"); + + HashMap *rooms = GrabObject(DbJson(chats), 1, "rooms"); + HashMap *mucs = GrabObject(DbJson(chats), 1, "mucs"); + + JsonValueFree(HashMapDelete(rooms, matrix_id)); + JsonValueFree(HashMapDelete(mucs, jabber_id)); + + DbUnlock(parsee, chat_id_ref); + DbUnlock(parsee, chats); + DbDelete(parsee, 2, "chats", chat_id); +} +static void +DeletePlumb(Db *parsee, char *potential_id) +{ + if (!parsee || !potential_id) + { + return; + } + + if (!strncmp(potential_id, "xmpp:", 5)) + { + DbRef *ref; + HashMap *mucs; + char *chat_id; + /* Try to parse it as an XMPP address */ + potential_id += 5; + + ref = DbLockIntent(parsee, DB_HINT_READONLY, 1, "chats"); + mucs = GrabObject(DbJson(ref), 1, "mucs"); + chat_id = StrDuplicate(GrabString(mucs, 1, potential_id)); + DbUnlock(parsee, ref); + + DeletePlumbID(parsee, chat_id); + Free(chat_id); + + return; + } + if (*potential_id == '!') + { + /* Try to parse it as a Matrix room ID */ + DbRef *ref; + HashMap *rooms; + char *chat_id; + + ref = DbLockIntent(parsee, DB_HINT_READONLY, 1, "chats"); + rooms = GrabObject(DbJson(ref), 1, "rooms"); + chat_id = StrDuplicate(GrabString(rooms, 1, potential_id)); + DbUnlock(parsee, ref); + + DeletePlumbID(parsee, chat_id); + Free(chat_id); + + return; + } + + /* Try to parse it as a chat ID */ + DeletePlumbID(parsee, potential_id); +} +static void +ListPlumbs(Db *parsee) +{ + DbRef *ref; + HashMap *mucs; + + char *muc; + JsonValue *value; + if (!parsee) + { + return; + } + + ref = DbLockIntent(parsee, DB_HINT_READONLY, 1, "chats"); + mucs = GrabObject(DbJson(ref), 1, "mucs"); + while (HashMapIterate(mucs, &muc, (void **) &value)) + { + char *chat_id = JsonValueAsString(value); + DbRef *chat_id_ref = DbLockIntent(parsee, DB_HINT_READONLY, 2, "chats", chat_id); + char *matrix_id = GrabString(DbJson(chat_id_ref), 1, "room_id"); + + /* TODO */ + Log(LOG_INFO, "- Plumb xmpp:%s <=> %s", muc, matrix_id); + Log(LOG_INFO, " - ID=%s", chat_id); + + DbUnlock(parsee, chat_id_ref); + } + + DbUnlock(parsee, ref); +} + +int +Main(Array *args, HashMap *env) +{ + char *db_path, *action, *exec; + int ret = EXIT_SUCCESS; + Db *parsee; + + exec = ArrayGet(args, 0); + + if (ArraySize(args) < 3) + { + Log(LOG_ERR, "Usage: %s [config] [action] ", exec); + return EXIT_FAILURE; + } + + db_path = ArrayGet(args, 1); + action = ArrayGet(args, 2); + + parsee = GetDB(db_path); + if (!parsee) + { + Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path); + return EXIT_FAILURE; + } + + if (StrEquals(action, "list") || StrEquals(action, "ls")) + { + ListPlumbs(parsee); + } + else if (StrEquals(action, "del")) + { + if (ArraySize(args) != 4) + { + Log(LOG_ERR, "%s: please show a !roomid:matrix.org, xmpp:mucid@jabber.org, or local hash", exec); + ret = EXIT_FAILURE; + goto end; + } + DeletePlumb(parsee, ArrayGet(args, 3)); + } + + +end: + DbClose(parsee); + return ret; +} From 176f390c4bfd7f624cbce992c411d6ed70cc4716 Mon Sep 17 00:00:00 2001 From: lda Date: Tue, 11 Feb 2025 17:18:01 +0000 Subject: [PATCH 159/186] [FIX] Use the puppet's name when pinged if possible --- src/MatrixEventHandler.c | 2 +- src/Parsee/Utils/Formatting.c | 36 +++++++++++++++++++++-------------- src/XMPPThread/ReListener.c | 2 ++ src/include/Parsee.h | 2 +- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index fa44d2d..2c5c5bd 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -370,7 +370,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *ev_id = GrabString(event, 1, "event_id"); char *chat_id = NULL, *muc_id = NULL; char *reply_id = MatrixGetReply(event); - char *xepd = ParseeXMPPify(event); + char *xepd = ParseeXMPPify(data, event); char *type, *user, *xmppified_user = NULL, *to = NULL; char *unauth = NULL; char *origin_id = NULL, *stanza = NULL; diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 17f513f..44e255a 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -20,7 +20,7 @@ typedef struct XMPPFlags { bool quote; } XMPPFlags; static char * -XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) +XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPFlags flags) { char *xepd = NULL, *tmp = NULL; @@ -70,7 +70,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -83,7 +83,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -96,7 +96,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -129,7 +129,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -144,7 +144,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -162,11 +162,19 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) UserID *id = MatrixParseIDFromMTO(pref); if (id) { + char *real_id = StrConcat(4, "@", id->localpart, ":", id->server); /* TODO: Detect if it already is a Parsee user */ - Concat("@"); - Concat(id->localpart); - Concat(":"); - Concat(id->server); + if (ParseeIsPuppet(conf, real_id)) + { + char *name = ASGetName(conf, NULL, real_id); + Concat((name ? name : real_id)); + Free(name); + } + else + { + Concat(real_id); + } + Free(real_id); } else { @@ -180,7 +188,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -196,7 +204,7 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(event, child, flags); + subxep = XMPPifyElement(conf, event, child, flags); Concat(subxep); Free(subxep); @@ -237,7 +245,7 @@ GetHTMLBody(HashMap *event) return GrabString(event, 2, "content", "formatted_body"); } char * -ParseeXMPPify(HashMap *event) +ParseeXMPPify(ParseeData *data, HashMap *event) { char *type, *format, *html; char *xepd = NULL; @@ -278,7 +286,7 @@ ParseeXMPPify(HashMap *event) } flags.quote = false; - xepd = XMPPifyElement(event, elem, flags); + xepd = XMPPifyElement(data ? data->config : NULL, event, elem, flags); XMLFreeElement(elem); Free(html); diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index f68b887..28d117b 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -56,6 +56,8 @@ XMPPDispatcher(void *argp) if (!stanza) { + /* TODO: We shouldn't be busywaiting. Even with a sleep call. + */ UtilSleepMillis(10); continue; } diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 8bc4429..92aacec 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -356,7 +356,7 @@ extern int ParseeFindDatastartU(char *data); /* XMPP-ifies a message event to XEP-0393 if possible. */ -extern char * ParseeXMPPify(HashMap *event); +extern char * ParseeXMPPify(ParseeData *data, HashMap *event); /* Finds an event ID from an ID in the stanza's attributes */ extern char * ParseeEventFromID(ParseeData *d, char *c_id, char *ori_id); From 1c51d573558ca1c591f660325e79c6495fa390ae Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 12 Feb 2025 08:24:18 +0000 Subject: [PATCH 160/186] [ADD] Add accept_pings parameters This is off by default, but highly encouraged for Synapse deployments --- .gitignore | 6 ++++-- CHANGELOG.md | 13 +++++++++++++ build.conf | 4 ++-- src/Main.c | 2 +- src/Parsee/Config.c | 1 + src/include/Parsee.h | 2 ++ 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 05919ab..5f7d56c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,11 @@ parsee* parsee *.swp .* -data -data/* +data* +data*/* Makefile configure +gmon.out tools/out tools/out/* @@ -24,3 +25,4 @@ tags !.forgejo !.forgejo/* !.forgejo/** + diff --git a/CHANGELOG.md b/CHANGELOG.md index 5999d7f..04358d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,19 @@ commit done between releases. *There is currently no beta releases of Parsee* ## Alpha + +### v0.3.0[lunar-rainbow] +This is the first release of 2025! +TBD +#### New things +- Allow admins to remove users from the nofly list. +- Parsee can now access the homeserver/component locally (rather than over the network) +- The endpoint for media has been changed to '/media/[SERV]/[ID]?hmac=...' +- Add parsee-plumb tool to manage plumbing from outside Parsee if it is not running. +#### Bugfixes +- Fix potential infinite loops when processing some messages. +- Parsee now handles pinging puppets from Matrix more sanely. + ### v0.2.0[star-of-hope] <8/11/2024> Fixes some media metadata things, replaces the build system, tries out avatar support some more, MUC contexts, and speeds diff --git a/build.conf b/build.conf index 9ebf253..a2e17c1 100644 --- a/build.conf +++ b/build.conf @@ -1,6 +1,6 @@ -CODE=star-of-hope +CODE=lunar-rainbow NAME=Parsee -VERSION=0.2.0 +VERSION=0.3.0 BINARY=parsee SOURCE=src INCLUDES=src/include diff --git a/src/Main.c b/src/Main.c index 3e740ed..f596126 100644 --- a/src/Main.c +++ b/src/Main.c @@ -63,7 +63,7 @@ ParseeCheckMatrix(void *datp) { static volatile uint64_t streak = 0; ParseeData *data = datp; - if (!ASPing(data->config)) + if (data->config->accept_pings && !ASPing(data->config)) { Log(LOG_ERR, "Cannot reach '%s' properly...", data->config->homeserver_host); if (++streak == 10) diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 46a391f..fa4b96e 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -68,6 +68,7 @@ ParseeConfigLoad(char *conf) CopyToStr(homeserver_host, "hs_host"); CopyToInt(homeserver_port, "hs_port"); CopyToBool(homeserver_tls, "hs_tls"); + CopyToBool(homeserver_tls, "accept_pings"); if (!HashMapGet(json, "hs_tls")) { config->homeserver_tls = true; diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 92aacec..5726286 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -43,6 +43,8 @@ typedef struct ParseeConfig { int homeserver_port; int homeserver_tls; + bool accept_pings; + /* ------- JABBER -------- */ char *component_addr; From 7f396a037927330d0063a9bfffcebd76b73457f3 Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 12 Feb 2025 08:33:05 +0000 Subject: [PATCH 161/186] [FIX] Write config to the proper field! --- src/Parsee/Config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index fa4b96e..45e6fe5 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -68,11 +68,11 @@ ParseeConfigLoad(char *conf) CopyToStr(homeserver_host, "hs_host"); CopyToInt(homeserver_port, "hs_port"); CopyToBool(homeserver_tls, "hs_tls"); - CopyToBool(homeserver_tls, "accept_pings"); if (!HashMapGet(json, "hs_tls")) { config->homeserver_tls = true; } + CopyToBool(accept_pings, "accept_pings"); CopyToInt(component_port, "component_port"); CopyToStr(component_addr, "component_addr"); From 9a2d4188e2d3886d600d9a6dfe77182bfe6bca9b Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 12 Feb 2025 16:43:43 +0000 Subject: [PATCH 162/186] [FIX] Do not put version in the OS field --- src/XMPPThread/Stanzas/IQ.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index af71cca..1b55bf4 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -589,7 +589,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(name, XMLCreateText(NAME)); XMLAddChild(version, XMLCreateText(VERSION "[" CODE "]")); - XMLAddChild(os, XMLCreateText(VERSION "POSIX-like")); + XMLAddChild(os, XMLCreateText("POSIX-like")); } XMLAddChild(query, name); XMLAddChild(query, version); From 71f3836ee1dc0c7056156b9e1ec3386df53f5132 Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 12 Feb 2025 16:47:48 +0000 Subject: [PATCH 163/186] [ADD] Use actual OS as information --- src/XMPPThread/Stanzas/IQ.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 1b55bf4..5dc9bc3 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -583,13 +584,15 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) query = XMLCreateTag("query"); XMLAddAttr(query, "xmlns", "jabber:iq:version"); { + struct utsname info; name = XMLCreateTag("name"); version = XMLCreateTag("version"); os = XMLCreateTag("os"); + uname(&info); XMLAddChild(name, XMLCreateText(NAME)); XMLAddChild(version, XMLCreateText(VERSION "[" CODE "]")); - XMLAddChild(os, XMLCreateText("POSIX-like")); + XMLAddChild(os, XMLCreateText(info.sysname)); } XMLAddChild(query, name); XMLAddChild(query, version); From 3bef6afa5dae72d34996c891c225fb3edd8985a7 Mon Sep 17 00:00:00 2001 From: lda Date: Fri, 14 Feb 2025 19:10:26 +0000 Subject: [PATCH 164/186] [FIX/WIP] Try escaping room IDs First attempt at dealing with #20 --- src/AS/Send.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/AS/Send.c b/src/AS/Send.c index 766f393..a787c53 100644 --- a/src/AS/Send.c +++ b/src/AS/Send.c @@ -47,11 +47,13 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c, u ts_str = TSToStr(ts); txn = StrRandom(16); + id = HttpUrlEncode(id); path = StrConcat(11, "/_matrix/client/v3/rooms/", id, "/send/", type, "/", txn, "?", "user_id=", user, "&ts=", ts_str ); + Free(id); Free(txn); Free(ts_str); From 43175e32e52fc14bfa64203ad0123658146001e6 Mon Sep 17 00:00:00 2001 From: lda Date: Fri, 14 Feb 2025 20:28:49 +0000 Subject: [PATCH 165/186] [FIX/WIP] Log out error info on ASSend --- src/AS/Send.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/AS/Send.c b/src/AS/Send.c index a787c53..9b81a71 100644 --- a/src/AS/Send.c +++ b/src/AS/Send.c @@ -33,6 +33,11 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c, u char *path; char *txn, *ret; char *ts_str; + HttpStatus status; + if (!ret) + { + Log(LOG_ERR, "%", ret); + } HashMap *reply; if (!conf || !id || !type || !user || !c) { @@ -60,10 +65,17 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c, u ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, c); + status = ParseeSetRequestJSON(ctx, c); reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); + if (!ret) + { + Log(LOG_ERR, "Got %s from HTTP", HttpStatusToString(status)); + JsonEncode(reply, StreamStdout(), JSON_PRETTY); + StreamPrintf(StreamStdout(), "\n"); + StreamFlush(StreamStdout()); + } JsonFree(reply); HttpClientContextFree(ctx); From d12255b2265b9cc79891d53e1740ab6071a89484 Mon Sep 17 00:00:00 2001 From: lda Date: Fri, 14 Feb 2025 21:58:42 +0000 Subject: [PATCH 166/186] [FIX/WIP] Do not use room ID for plumbing --- src/Commands/Plumb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index f51e4e6..bee94f2 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -59,7 +59,7 @@ CommandHead(CmdPlumb, cmd, argp) goto end; } - chat_id = ParseePushMUC(args->data, room_id, muc); + chat_id = ParseePushMUC(args->data, room, muc); // ew. if (chat_id) { char *rev = StrConcat(2, muc, "/parsee"); From e2b014d00056d8e39a5c277e8d286249a16d44e9 Mon Sep 17 00:00:00 2001 From: lda Date: Sat, 15 Feb 2025 08:44:25 +0000 Subject: [PATCH 167/186] [FIX/WIP] Fix replies and try fixing a bug with MUCs --- src/AS/Room.c | 18 +++++++++-- src/Main.c | 1 + src/MatrixEventHandler.c | 4 +-- src/Parsee/User.c | 51 ++++++++++++++++++++++++-------- src/Unistr.c | 35 ++++++++++++++++++++++ src/XMPP/Stanza.c | 25 ++++++++++++++++ src/XMPPThread/Stanzas/Message.c | 14 ++++++++- src/include/Parsee.h | 2 +- src/include/Routes.h | 3 +- src/include/Unistring.h | 6 ++++ src/include/XMPP.h | 3 ++ 11 files changed, 142 insertions(+), 20 deletions(-) diff --git a/src/AS/Room.c b/src/AS/Room.c index 9e10579..e9691e1 100644 --- a/src/AS/Room.c +++ b/src/AS/Room.c @@ -25,11 +25,13 @@ ASInvite(const ParseeConfig *conf, char *id, char *invited) "@", conf->sender_localpart, ":", conf->server_base ); + id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/invite", "?user_id=", bridge ); Free(bridge); + Free(id); ctx = ParseeCreateRequest( conf, @@ -60,11 +62,13 @@ ASBan(const ParseeConfig *conf, char *id, char *banned) "@", conf->sender_localpart, ":", conf->server_base ); + id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/ban", "?user_id=", bridge ); Free(bridge); + Free(id); ctx = ParseeCreateRequest( conf, @@ -95,11 +99,13 @@ ASKick(const ParseeConfig *conf, char *id, char *banned) "@", conf->sender_localpart, ":", conf->server_base ); + id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/kick", "?user_id=", bridge ); Free(bridge); + Free(id); ctx = ParseeCreateRequest( conf, @@ -120,7 +126,8 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) { HttpClientContext *ctx = NULL; HashMap *json = NULL; - char *path, *ret; + char *path, *ret, *serv; + int status; if (!conf || !id) { return NULL; @@ -139,6 +146,11 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) { masquerade = HttpUrlEncode(masquerade); } + serv = strchr(id, ':'); + if (serv) + { + serv = serv + 1; + } id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/join/", id, "?", @@ -152,7 +164,7 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); + status = ParseeSetRequestJSON(ctx, json); JsonFree(json); json = JsonDecode(HttpClientStream(ctx)); @@ -163,6 +175,8 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) Free(masquerade); Free(id); + (void) serv; // TODO + return ret; } void diff --git a/src/Main.c b/src/Main.c index f596126..10c809f 100644 --- a/src/Main.c +++ b/src/Main.c @@ -298,6 +298,7 @@ Main(Array *args, HashMap *env) "7e228734ec8e792960bb5633e43f0cb845f709f61825130490034651136" ); ASSetName(parsee_conf, parsee, "Parsee bridge"); + Free(parsee); } diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 2c5c5bd..32050dd 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -100,7 +100,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) char *jid = ParseeEncodeMXID(state_key); char *sha = NULL, *mime = NULL; char *avatar = ASGetAvatar(data->config, NULL, state_key); - char *url = ParseeToUnauth(data, avatar); + char *url = ParseeToUnauth(data, avatar, NULL); chat_id = ParseeGetFromRoomID(data, room_id); ASGetMIMESHA(data->config, avatar, &mime, &sha); @@ -417,7 +417,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) type = direct ? "chat" : "groupchat"; user = GrabString(json, 1, "xmpp_user"); - unauth = ParseeToUnauth(data, url); + unauth = ParseeToUnauth(data, url, GrabString(event, 2, "content", "filename")); encoded_from = ParseeEncodeMXID(m_sender); xmppified_user = StrConcat(3, diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 5a945ea..a9320d8 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -687,12 +687,13 @@ end: #include char * -ParseeToUnauth(ParseeData *data, char *mxc) +ParseeToUnauth(ParseeData *data, char *mxc, char *filename) { Uri *url = NULL; char *ret; char *key, *hmac; #define PAT "%s/media/%s%s?hmac=%s" +#define PATF "%s/media/%s%s/%s?hmac=%s" size_t l; if (!data || !mxc) { @@ -713,19 +714,43 @@ ParseeToUnauth(ParseeData *data, char *mxc) hmac = ParseeHMACS(data->id, key); Free(key); - l = snprintf(NULL, 0, - PAT, - data->config->media_base, - url->host, url->path, - hmac - ); + if (!filename) + { + l = snprintf(NULL, 0, + PAT, + data->config->media_base, + url->host, url->path, + hmac + ); + } + else + { + l = snprintf(NULL, 0, + PATF, + data->config->media_base, + url->host, url->path, filename, + hmac + ); + } ret = Malloc(l + 3); - snprintf(ret, l + 1, - PAT, - data->config->media_base, - url->host, url->path, - hmac - ); + if (!filename) + { + snprintf(ret, l + 1, + PAT, + data->config->media_base, + url->host, url->path, + hmac + ); + } + else + { + snprintf(ret, l + 1, + PATF, + data->config->media_base, + url->host, url->path, filename, + hmac + ); + } UriFree(url); Free(hmac); return ret; diff --git a/src/Unistr.c b/src/Unistr.c index a1eb1e4..7eab2e0 100644 --- a/src/Unistr.c +++ b/src/Unistr.c @@ -277,3 +277,38 @@ UnistrGetOffset(Unistr *str, uint32_t sep) } return 0; } +size_t +UnistrGetUTFOffset(char *cstr, size_t unicode) +{ + Unistr *tmp; + size_t ret = 0; + if (!cstr) + { + return 0; + } + + tmp = UnistrCreate(cstr); + for (size_t i = 0; i < unicode && i < tmp->length; i++) + { + uint32_t codepoint = tmp->codepoints[i]; + if (codepoint >= 0x0000 && codepoint <= 0x007F) + { + ret += 1; + } + else if (codepoint >= 0x0080 && codepoint <= 0x07FF) + { + ret += 2; + } + else if (codepoint >= 0x0800 && codepoint <= 0xFFFF) + { + ret += 3; + } + else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) + { + ret += 4; + } + } +end: + Free(tmp); + return ret; +} diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 27a658e..58c3876 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -159,6 +159,31 @@ XMPPGetReply(XMLElement *elem) return HashMapGet(rep->attrs, "id"); } +ssize_t +XMPPGetReplyOffset(XMLElement *elem) +{ + if (!elem) + { + return -1; + } + for (size_t i = 0; i < ArraySize(elem->children); i++) + { + XMLElement *child = ArrayGet(elem->children, i); + char *xmlns = HashMapGet(child->attrs, "xmlns"); + char *xfor = HashMapGet(child->attrs, "for"); + if (StrEquals(child->name, "fallback") && + StrEquals(xmlns, "urn:xmpp:feature-fallback:0") && + StrEquals(xfor, "urn:xmpp:reply:0")) + { + XMLElement *body = XMLookForUnique(child, "body"); + if (body && HashMapGet(body->attrs, "end")) + { + return strtol(HashMapGet(body->attrs, "end"), NULL, 10); + } + } + } + return -1; +} char * XMPPGetModeration(XMLElement *stanza) { diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 5497f19..c4066d9 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -324,8 +325,9 @@ end_error: { Log(LOG_DEBUG, "Fetching bridge: %fs", Elapsed(rectime)); } + char *trim = ParseeTrimJID(from); if (!mroom_id && !room && !XMPPIsParseeStanza(stanza) && - to && *to == '@') + to && *to == '@' && !XMPPQueryMUC(jabber, trim, NULL)) { DbRef *room_ref; HashMap *room_json; @@ -344,6 +346,7 @@ end_error: ParseePushDMRoom(args, to, from, room); } } + Free(trim); /* TODO: THIS IS A HACK. THIS CODE IGNORES ALL MUC MESSAGES EVER * SENT TO NON-PARSEE PUPPETS, AS A "FIX" TO THE MULTITHREADED @@ -518,6 +521,15 @@ end_error: * too. Go figure. */ size_t off = reply_to ? ParseeFindDatastart(data->data) : 0; + size_t stanzaoff = XMPPGetReplyOffset(stanza); + if (reply_to && stanzaoff != -1) + { + off = UnistrGetUTFOffset(data->data, stanzaoff); + } + if (data->data && off >= strlen(data->data)) + { + off = 0; + } HashMap *ev = MatrixCreateMessage(data->data + off); if (reply_to) { diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 5726286..ea5d18b 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -368,7 +368,7 @@ extern char * ParseeDMEventFromID(ParseeData *d, char *r_id, char *ori_id); extern char * ParseeDMEventFromSID(ParseeData *d, char *r_id, char *ori_id); /* Gets a Parsee "shim" link to an MXC, usable as unauth for a limited time */ -extern char * ParseeToUnauth(ParseeData *data, char *mxc); +extern char * ParseeToUnauth(ParseeData *data, char *mxc, char *filename); extern void ParseeInitialiseOIDTable(void); extern void ParseePushOIDTable(char *muc, char *occupant); diff --git a/src/include/Routes.h b/src/include/Routes.h index b927eff..664032b 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -79,7 +79,8 @@ typedef struct ParseeCmdArg { X_ROUTE("/_matrix/app/v1/users/(.*)", RouteUserAck) \ X_ROUTE("/_matrix/app/v1/rooms/(.*)", RouteRoomAck) \ X_ROUTE("/_matrix/app/v1/ping", RoutePing) \ - X_ROUTE("/media/(.*)/(.*)", RouteMedia) + X_ROUTE("/media/(.*)/(.*)", RouteMedia) \ + X_ROUTE("/media/(.*)/(.*)/(.*)", RouteMedia) #define X_ROUTE(path, name) extern void * name(Array *, void *); ROUTES diff --git a/src/include/Unistring.h b/src/include/Unistring.h index d90d61c..7eff7a1 100644 --- a/src/include/Unistring.h +++ b/src/include/Unistring.h @@ -82,4 +82,10 @@ extern Unistr * UnistrFilter(Unistr *str, UnistrFilterFunc filter); * -------- * Returns: an offset of the first line to not start by {c} | 0 */ extern size_t UnistrGetOffset(Unistr *str, uint32_t sep); + +/** Locates the new index within a regular UTF-8 sequence from an index + * within all codepoints. + * ----------------------------------- + * Returns: an offset */ +extern size_t UnistrGetUTFOffset(char *cstr, size_t unicode); #endif diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 22e98f6..3b53f04 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -90,6 +90,9 @@ extern char * XMPPGetRetractedID(XMLElement *); /* Get the replied-to stanza ID, if existent. */ extern char * XMPPGetReply(XMLElement *elem); +/* Get the replied-to stanza offset, if existent. */ +extern ssize_t XMPPGetReplyOffset(XMLElement *elem); + /** Get the moderated message ID(as a stanza ID/plain ID) from a moderation * stanza, that lives *alongside* the stanza itself. * ---------------------------------------------------------------------- From c96f0486ff48a2a0ea99cde3bff86fe17127470e Mon Sep 17 00:00:00 2001 From: lda Date: Mon, 17 Feb 2025 08:30:18 +0000 Subject: [PATCH 168/186] [FIX/WIP] Chrck URI before doing anything funny --- src/MatrixEventHandler.c | 4 ++++ src/Parsee/Utils/Formatting.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 32050dd..17a3bb9 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -358,6 +358,10 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) static void ParseeMessageHandler(ParseeData *data, HashMap *event) { + if (!data || !event) + { + return; + } XMPPComponent *jabber = data->jabber; StanzaBuilder *builder = NULL; DbRef *ref = NULL; diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 44e255a..dc7b1a6 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -58,7 +58,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF } \ } \ while (0) - switch (elem->type) + switch (elem ? elem->type : -1) { case XML_ELEMENT_DATA: Concat(elem->data); @@ -155,7 +155,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF { char *href = HashMapGet(elem->attrs, "href"); Uri *pref = UriParse(href); - if (StrEquals(pref->host, "matrix.to")) + if (pref && StrEquals(pref->host, "matrix.to")) { /* TODO: Check if the element here is a Matrix.TO * pointing to a Parsee user. */ From cdbdc9345ad963fcbd9babe6a9d185efebc79441 Mon Sep 17 00:00:00 2001 From: lda Date: Mon, 17 Feb 2025 17:44:09 +0000 Subject: [PATCH 169/186] [MOD] Don't always add two newlines --- src/Parsee/Utils/Formatting.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index dc7b1a6..07cc191 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -149,7 +149,10 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF Concat(subxep); Free(subxep); } - Concat("\n"); + if (i != 0) + { + Concat("\n"); + } } else if (StrEquals(elem->name, "a")) { From 0a4aa45de5f76625ca9f97ff4303f08a3cbd126b Mon Sep 17 00:00:00 2001 From: lda Date: Mon, 17 Feb 2025 20:24:06 +0000 Subject: [PATCH 170/186] [FIX] Add proper includes --- src/XMPP/Stanza.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 58c3876..a2daf5a 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -7,6 +7,8 @@ #include #include +#include + void XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) From fb44ad4bf63816c34678ee088b84829f6b8aeb05 Mon Sep 17 00:00:00 2001 From: lda Date: Tue, 18 Feb 2025 22:52:44 +0000 Subject: [PATCH 171/186] [FIX] Go back to using room IDs I already gave up on urandom anyways. --- src/Commands/Plumb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index bee94f2..f51e4e6 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -59,7 +59,7 @@ CommandHead(CmdPlumb, cmd, argp) goto end; } - chat_id = ParseePushMUC(args->data, room, muc); // ew. + chat_id = ParseePushMUC(args->data, room_id, muc); if (chat_id) { char *rev = StrConcat(2, muc, "/parsee"); From fd1b3499b684cb4be69bc0ce4474d74c1ef1ef17 Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 19 Feb 2025 15:32:52 +0000 Subject: [PATCH 172/186] [ADD] Allow the main component to be used to issue commands --- src/AS/Send.c | 7 ------- src/XMPPThread/Stanzas/IQ.c | 5 +++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/AS/Send.c b/src/AS/Send.c index 9b81a71..6811548 100644 --- a/src/AS/Send.c +++ b/src/AS/Send.c @@ -69,13 +69,6 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c, u reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); - if (!ret) - { - Log(LOG_ERR, "Got %s from HTTP", HttpStatusToString(status)); - JsonEncode(reply, StreamStdout(), JSON_PRETTY); - StreamPrintf(StreamStdout(), "\n"); - StreamFlush(StreamStdout()); - } JsonFree(reply); HttpClientContextFree(ctx); diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 5dc9bc3..1b5087d 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -374,7 +374,7 @@ IQResult(ParseeData *args, XMLElement *stanza, XMPPThread *thr) bool IQIsCommandList(ParseeData *args, XMLElement *stanza) { - char *parsee = NULL; + char *parsee = NULL, *to; XMLElement *query = XMLookForTKV( stanza, "query", "xmlns", "http://jabber.org/protocol/disco#items" @@ -389,7 +389,8 @@ IQIsCommandList(ParseeData *args, XMLElement *stanza) } parsee = ParseeJID(args); - ret = StrEquals(HashMapGet(stanza->attrs, "to"), parsee); + to = HashMapGet(stanza->attrs, "to"); + ret = StrEquals(to, parsee) || StrEquals(to, args->config->component_host); Free(parsee); return ret; From b78f7b6ab32f90a719d546c10f4ae2182bd21af2 Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 19 Feb 2025 15:38:22 +0000 Subject: [PATCH 173/186] [ADD/TOOL] Add -j flag for parsee-config --- etc/man/man1/parsee-config.1 | 10 +++++++++- tools/config.c | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/etc/man/man1/parsee-config.1 b/etc/man/man1/parsee-config.1 index a297075..5dc258b 100644 --- a/etc/man/man1/parsee-config.1 +++ b/etc/man/man1/parsee-config.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-config 1 "Parsee Utility" "star-of-hope" +.TH parsee-config 1 "Parsee Utility" "lunar-rainbow" .SH NAME parsee-config - generate a basic configuration file @@ -11,6 +11,7 @@ parsee-config .B [-s SHARED_SECRET] .B [-m MEDIA_URL] .B [-J JABBER_HOST] +.B [-j JABBER_ADDR] .B [-p JABBER_PORT] .B [-d DATABASE] .B [-M MAX_STANZA] @@ -34,6 +35,7 @@ $ parsee-config \\ -H 'blow.hole' \\ -s 'The Dark Shared Secret' \\ -J 'xmpp.blow.hole' \\ + -j 'localhost' \\ -S 128 .fi .if n \{\ @@ -68,6 +70,12 @@ media. It must be publicly accessible (behind a reverse proxy to HTTP:7642) .I JABBER_HOST is used as the component host for Parsee. .TP +.BR -j JABBER_ADDR +.I JABBER_ADDR +can optionally be used to change the hostname Parsee will try to contact +for XMPP. Users should ideally use localhost (or a hostname pointing to +the server itself), as XMPP component streams are not encrypted. +.TP .BR -p JABBER_PORT .I JABBER_PORT is used as the component post for Parsee. Parsee uses it alongside diff --git a/tools/config.c b/tools/config.c index b949c14..d8e0aea 100644 --- a/tools/config.c +++ b/tools/config.c @@ -20,6 +20,7 @@ Main(Array *args, HashMap *env) Uri *api_base; char *homeserver = NULL, *jcp = NULL, *jabber = NULL; char *data = NULL, *media = NULL, *listen = NULL; + char *component_as = NULL; int flag, code = EXIT_FAILURE; int port = 5347; size_t lmdb_size = 0; @@ -28,7 +29,7 @@ Main(Array *args, HashMap *env) listen = "localhost"; ArgParseStateInit(&state); - while ((flag = ArgParse(&state, args, "H:J:s:d:p:m:l:S:M:")) != -1) + while ((flag = ArgParse(&state, args, "H:J:j:s:d:p:m:l:S:M:")) != -1) { switch (flag) { @@ -45,6 +46,9 @@ Main(Array *args, HashMap *env) case 'J': jabber = state.optArg; break; + case 'j': + component_as = state.optArg; + break; case 'd': data = state.optArg; break; @@ -123,6 +127,7 @@ Main(Array *args, HashMap *env) JsonSet(json, JsonValueString(media), 1, "media_base"); JsonSet(json, JsonValueString(listen), 1, "listen_as"); + JsonSet(json, JsonValueString(component_as), 1, "component_addr"); JsonEncode(json, file, JSON_PRETTY); StreamFlush(file); From 40e324246510585ea6fab202fcaac8e2aa6f6650 Mon Sep 17 00:00:00 2001 From: lda Date: Wed, 19 Feb 2025 16:14:30 +0000 Subject: [PATCH 174/186] [ADD] Try to renegociate an XMPP stream on failure --- src/XMPPThread/ReListener.c | 126 ++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 48 deletions(-) diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 28d117b..44f22f8 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -244,66 +244,96 @@ ParseeXMPPThread(void *argp) } } - while (true) + while (!args->halted) { - char *id; - - stanza = XMLDecode(jabber->stream, false); - if (!stanza) + while (true) { - /* Try to check if an error is abound */ - if (args->verbosity >= PARSEE_VERBOSE_COMICAL) + char *id; + + stanza = XMLDecode(jabber->stream, false); + if (!stanza) { - Log(LOG_DEBUG, "RECEIVED EOF."); + /* Try to check if an error is abound */ + if (args->verbosity >= PARSEE_VERBOSE_COMICAL) + { + Log(LOG_DEBUG, "RECEIVED EOF."); + } + break; } - break; - } - if (args->verbosity >= PARSEE_VERBOSE_STANZA) - { - Stream *output = StreamStderr(); - StreamPrintf(output, "-------STANZA BEGIN-------" "\n"); - XMLEncode(output, stanza); - StreamPrintf(output, "\n--------STANZA END--------" "\n"); - StreamFlush(output); - } - - id = HashMapGet(stanza->attrs, "id"); - if (id) - { - XMPPAwait *await; - /* Lock out the table to see if we're awaiting. */ - pthread_mutex_lock(&await_lock); - if ((await = HashMapGet(await_table, id))) + if (args->verbosity >= PARSEE_VERBOSE_STANZA) { - pthread_mutex_lock(&await->cond_lock); - await->stanza = stanza; - pthread_cond_signal(&await->condition); - pthread_mutex_unlock(&await->cond_lock); + Stream *output = StreamStderr(); + StreamPrintf(output, "-------STANZA BEGIN-------" "\n"); + XMLEncode(output, stanza); + StreamPrintf(output, "\n--------STANZA END--------" "\n"); + StreamFlush(output); + } - HashMapDelete(await_table, id); + id = HashMapGet(stanza->attrs, "id"); + if (id) + { + XMPPAwait *await; + /* Lock out the table to see if we're awaiting. */ + pthread_mutex_lock(&await_lock); + if ((await = HashMapGet(await_table, id))) + { + pthread_mutex_lock(&await->cond_lock); + await->stanza = stanza; + pthread_cond_signal(&await->condition); + pthread_mutex_unlock(&await->cond_lock); + HashMapDelete(await_table, id); + + pthread_mutex_unlock(&await_lock); + continue; + } pthread_mutex_unlock(&await_lock); - continue; } - pthread_mutex_unlock(&await_lock); - } - /* Push it into the stanza FIFO. A dispatcher thread should then - * be able to freely grab a value(locked by a mutex). We can't make - * dispatchers read stanzas on their own, since that's _not_ how - * streams work, but this should mitigate some issues, and allow a - * few threads to be busy, while the rest of Parsee works. */ - PushStanza(&info, stanza); + /* Push it into the stanza FIFO. A dispatcher thread should then + * be able to freely grab a value(locked by a mutex). We can't make + * dispatchers read stanzas on their own, since that's _not_ how + * streams work, but this should mitigate some issues, and allow a + * few threads to be busy, while the rest of Parsee works. */ + PushStanza(&info, stanza); + } + pthread_mutex_lock(&args->halt_lock); + if (!args->halted) + { + Log(LOG_WARNING, "XMPP server is closing stream..."); + for (size_t i = 0; i < 50; i++) + { + UtilSleepMillis(100); /* Wait a bit so that temporary failures don't fuck everything up */ + + Log(LOG_WARNING, "Restarting XMPP stream."); + /* This is the part where a new connection is being considered */ + XMPPFinishCompStream(jabber); + XMPPEndCompStream(jabber); + + args->jabber = XMPPInitialiseCompStream( + args->config->component_addr, + args->config->component_host, + args->config->component_port + ); + jabber = args->jabber; + if (!jabber || !XMPPAuthenticateCompStream(jabber, args->config->shared_comp_secret)) + { + /* Oops, there is something wrong! */ + Log(LOG_ERR, "Couldn't authenticate to XMPP server"); + XMPPEndCompStream(jabber); + args->jabber = NULL; + jabber = NULL; + if (i == 4) + { + pthread_mutex_unlock(&args->halt_lock); + break; + } + } + } + } + pthread_mutex_unlock(&args->halt_lock); } - pthread_mutex_lock(&args->halt_lock); - if (!args->halted) - { - Log(LOG_WARNING, "XMPP server is closing stream..."); - Log(LOG_WARNING, "Stopping %s...", NAME); - error = true; - } - pthread_mutex_unlock(&args->halt_lock); info.running = false; for (i = 0; i < info.available_dispatchers; i++) From 6762d1c1ce777ee8529afbc6e4d5aff2d994a8db Mon Sep 17 00:00:00 2001 From: Hank Date: Mon, 10 Feb 2025 18:15:49 +0100 Subject: [PATCH 175/186] [FIX/WIP] remove .guix from gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5f7d56c..09b6fd1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ tags !.forgejo/* !.forgejo/** +!.guix +!.guix/* +!.guix/** + From a2c1de52dceb9ef39e1afacd0afafddd86141b1b Mon Sep 17 00:00:00 2001 From: Hank Date: Mon, 10 Feb 2025 18:16:24 +0100 Subject: [PATCH 176/186] [ADD] new guix.scm with cytoplasm --- .guix/modules/parsee.scm | 43 ++++++++++++++++++++++++++++++++++++++++ guix.scm | 1 + 2 files changed, 44 insertions(+) create mode 100644 .guix/modules/parsee.scm create mode 120000 guix.scm diff --git a/.guix/modules/parsee.scm b/.guix/modules/parsee.scm new file mode 100644 index 0000000..f2d6f48 --- /dev/null +++ b/.guix/modules/parsee.scm @@ -0,0 +1,43 @@ +(define-module (parsee) + #:use-module (guix packages) + #:use-module (guix git-download) + #:use-module (guix build-system gnu) + #:use-module (guix gexp) + #:use-module (guix utils) + #:use-module (gnu packages tls) + #:use-module ((guix licenses) #:prefix license:)) + +(define-public cytoplasm + (package + (name "cytoplasm") + (version "0.4.1") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://git.telodendria.io/Telodendria/Cytoplasm") + (commit (string-append "v" version)))) + (sha256 + (base32 "13iwh37xfmz98vmb6dzl4v6vlxcis5q85c8rzmv3fs28khsfk45n")))) + (build-system gnu-build-system) + (arguments + (list + #:tests? #f + #:phases #~(modify-phases %standard-phases + (add-before 'configure 'add-ld-flags + (lambda _ + (substitute* "./configure" + (("(LDFLAGS=\"\\$\\{LIBS\\} \\$\\{LDFLAGS\\})\"" all flags) + (string-append flags " -Wl,-rpath=" #$output "/lib\""))) + (mkdir-p (string-append #$output "/lib")))) + (replace 'configure + (lambda* (#:key configure-flags #:allow-other-keys) + (apply invoke `("./configure" + ,(string-append "--prefix=" #$output) + ,@configure-flags))))))) + (inputs (list openssl)) + (home-page "https://git.telodendria.io/Telodendria/Cytoplasm") + (synopsis "General-purpose high-level networked C library") + (description "Cytoplasm is a general-purpose C library for creating +high-level (particularly networked and multi-threaded) C applications.") + (license license:expat))) diff --git a/guix.scm b/guix.scm new file mode 120000 index 0000000..021acc5 --- /dev/null +++ b/guix.scm @@ -0,0 +1 @@ +.guix/modules/parsee.scm \ No newline at end of file From b50b9bd6155ffc03baa7c683e35702c4b84127e3 Mon Sep 17 00:00:00 2001 From: Hank Date: Mon, 10 Feb 2025 22:23:03 +0100 Subject: [PATCH 177/186] [FIX] pin cytoplasm to the latest commit --- .guix/modules/parsee.scm | 68 +++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/.guix/modules/parsee.scm b/.guix/modules/parsee.scm index f2d6f48..3c5ce83 100644 --- a/.guix/modules/parsee.scm +++ b/.guix/modules/parsee.scm @@ -8,36 +8,40 @@ #:use-module ((guix licenses) #:prefix license:)) (define-public cytoplasm - (package - (name "cytoplasm") - (version "0.4.1") - (source - (origin - (method git-fetch) - (uri (git-reference - (url "https://git.telodendria.io/Telodendria/Cytoplasm") - (commit (string-append "v" version)))) - (sha256 - (base32 "13iwh37xfmz98vmb6dzl4v6vlxcis5q85c8rzmv3fs28khsfk45n")))) - (build-system gnu-build-system) - (arguments - (list - #:tests? #f - #:phases #~(modify-phases %standard-phases - (add-before 'configure 'add-ld-flags - (lambda _ - (substitute* "./configure" - (("(LDFLAGS=\"\\$\\{LIBS\\} \\$\\{LDFLAGS\\})\"" all flags) - (string-append flags " -Wl,-rpath=" #$output "/lib\""))) - (mkdir-p (string-append #$output "/lib")))) - (replace 'configure - (lambda* (#:key configure-flags #:allow-other-keys) - (apply invoke `("./configure" - ,(string-append "--prefix=" #$output) - ,@configure-flags))))))) - (inputs (list openssl)) - (home-page "https://git.telodendria.io/Telodendria/Cytoplasm") - (synopsis "General-purpose high-level networked C library") - (description "Cytoplasm is a general-purpose C library for creating + (let ((commit "32f31fe6d61583630995d956ed7bd7566c4dc14f") + (revision "0")) + (package + (name "cytoplasm") + (version (git-version "0.4.1" revision commit)) + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://git.telodendria.io/Telodendria/Cytoplasm") + (commit commit))) + (file-name (git-file-name name version)) + (sha256 + (base32 "09x5xfswryf3wjs1synh972yr2fmpjmffi7pjyjdzb4asqh4whrv")))) + (build-system gnu-build-system) + (arguments + (list + #:tests? #f + #:configure-flags #~'("--with-lmdb") + #:phases #~(modify-phases %standard-phases + (add-before 'configure 'add-ld-flags + (lambda _ + (substitute* "./configure" + (("(LDFLAGS=\"\\$\\{LIBS\\} \\$\\{LDFLAGS\\})\"" all flags) + (string-append flags " -Wl,-rpath=" #$output "/lib\""))) + (mkdir-p (string-append #$output "/lib")))) + (replace 'configure + (lambda* (#:key configure-flags #:allow-other-keys) + (apply invoke `("./configure" + ,(string-append "--prefix=" #$output) + ,@configure-flags))))))) + (inputs (list openssl lmdb)) + (home-page "https://git.telodendria.io/Telodendria/Cytoplasm") + (synopsis "General-purpose high-level networked C library") + (description "Cytoplasm is a general-purpose C library for creating high-level (particularly networked and multi-threaded) C applications.") - (license license:expat))) + (license license:expat)))) From 44473878d09b806e40d0ad146b867610712dd8a9 Mon Sep 17 00:00:00 2001 From: Hank Date: Mon, 10 Feb 2025 22:23:39 +0100 Subject: [PATCH 178/186] [ADD] add parsee guix package --- .guix/modules/parsee.scm | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.guix/modules/parsee.scm b/.guix/modules/parsee.scm index 3c5ce83..75b8b64 100644 --- a/.guix/modules/parsee.scm +++ b/.guix/modules/parsee.scm @@ -5,8 +5,14 @@ #:use-module (guix gexp) #:use-module (guix utils) #:use-module (gnu packages tls) + #:use-module (gnu packages databases) #:use-module ((guix licenses) #:prefix license:)) +(define vcs-file? + (or (git-predicate + (dirname (dirname (current-source-directory)))) + (const #t))) + (define-public cytoplasm (let ((commit "32f31fe6d61583630995d956ed7bd7566c4dc14f") (revision "0")) @@ -45,3 +51,32 @@ (description "Cytoplasm is a general-purpose C library for creating high-level (particularly networked and multi-threaded) C applications.") (license license:expat)))) + +(define-public parsee + (package + (name "parsee") + (version "0.0.1-git") + (source + (local-file "../.." "parsee-checkout" + #:recursive? #t + #:select? vcs-file?)) + (build-system gnu-build-system) + (arguments + (list + #:tests? #f + #:make-flags #~(list "CC=gcc" + (string-append "CYTO_INC=" #$cytoplasm "/include") + (string-append "CYTO_LIB=" #$cytoplasm "/lib") + (string-append "PREFIX=" #$output)) + #:phases #~(modify-phases %standard-phases + (replace 'configure + (lambda* (#:key inputs #:allow-other-keys) + (let ((gcc (string-append (assoc-ref inputs "gcc") "/bin/gcc"))) + (invoke gcc "configure.c" "-o" "configure") + (invoke "./configure"))))))) + (home-page "https://git.kappach.at/lda/Parsee") + (synopsis "Jealous Matrix to XMPP bridge") + (description "Parsee is a Matrix-XMPP bridge written in C99 with Cytoplasm.") + (license license:agpl3+))) + +parsee From 680b4261c25f74ed1551ec75d9efc07346e6bf56 Mon Sep 17 00:00:00 2001 From: Hank Date: Mon, 10 Feb 2025 22:54:45 +0100 Subject: [PATCH 179/186] [ADD] small documentation paragraph --- README.MD | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.MD b/README.MD index ce51662..ee223de 100644 --- a/README.MD +++ b/README.MD @@ -43,6 +43,13 @@ Parsee tries to avoid dependencies aside from [Cytoplasm](https://git.telodendri Itself optionally depends on a good POSIX implementation, and optionally OpenSSL/LMDB (highly recommended, but you can get away without those if you're adventurous). +### BUILDING WITH GUIX +If you have [Guix](https://guix.gnu.org/) installed, you can build Parsee using `guix package -f guix.scm`, or test it +using `guix shell -f guix.scm`. You can also generate a Docker/OCI image. +```sh +guix pack -f docker -S /bin=bin -L.guix/modules parsee +``` + ## RUNNING First off, you may want to configure Parsee by running the `config` tool(generally named `parsee-config` in most cases), with the correct flags, like here. From e21ebed134bd553dd7dd8e79f431467494b66fd6 Mon Sep 17 00:00:00 2001 From: lda Date: Sun, 23 Feb 2025 22:38:38 +0000 Subject: [PATCH 180/186] [META/ADD] Add Guix to the CHANGELOG quick und dirty --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04358d7..9b12530 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ TBD - Parsee can now access the homeserver/component locally (rather than over the network) - The endpoint for media has been changed to '/media/[SERV]/[ID]?hmac=...' - Add parsee-plumb tool to manage plumbing from outside Parsee if it is not running. +- Add packaging for Guix (see #18) #### Bugfixes - Fix potential infinite loops when processing some messages. - Parsee now handles pinging puppets from Matrix more sanely. From 7454c8c597e93c4c19d98ee0946a555bb445f71e Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 9 Mar 2025 11:05:55 +0000 Subject: [PATCH 181/186] [FIX] Fix a few bugs about edits and XEP-393 formatting --- src/Parsee/Utils/Formatting.c | 12 ++++++++++-- src/XEP-0393.c | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index 07cc191..ec95aef 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -247,6 +247,15 @@ GetHTMLBody(HashMap *event) } return GrabString(event, 2, "content", "formatted_body"); } +static char * +GetBodyFormat(HashMap *event) +{ + if (MatrixGetEdit(event)) + { + return GrabString(event, 3, "content", "m.new_content", "format"); + } + return GrabString(event, 2, "content", "format"); +} char * ParseeXMPPify(ParseeData *data, HashMap *event) { @@ -267,8 +276,7 @@ ParseeXMPPify(ParseeData *data, HashMap *event) return NULL; } - format = JsonValueAsString(JsonGet(event, 2, "content", "format")); - if (!StrEquals(format, "org.matrix.custom.html")) + if (!StrEquals(GetBodyFormat(event), "org.matrix.custom.html")) { /* Settle for the raw body instead. */ char *body = GetRawBody(event); diff --git a/src/XEP-0393.c b/src/XEP-0393.c index a0f6be9..784bacf 100644 --- a/src/XEP-0393.c +++ b/src/XEP-0393.c @@ -329,8 +329,8 @@ ShoveXML(XEP393Element *element, XMLElement *xmlparent) break; case XEP393_MONO: head = XMLCreateTag("code"); + XMLAddChild(xmlparent, XMLCreateText("`")); XMLAddChild(xmlparent, head); - XMLAddChild(head, XMLCreateText("`")); break; case XEP393_SRKE: head = XMLCreateTag("s"); @@ -372,7 +372,7 @@ ShoveXML(XEP393Element *element, XMLElement *xmlparent) XMLAddChild(head, XMLCreateText("_")); break; case XEP393_MONO: - XMLAddChild(head, XMLCreateText("`")); + XMLAddChild(xmlparent, XMLCreateText("`")); break; case XEP393_SRKE: XMLAddChild(head, XMLCreateText("~")); From 45250096ad60ecc731bc70ada02106dd2e704749 Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 13 Apr 2025 10:23:51 +0000 Subject: [PATCH 182/186] [FIX] argh --- src/AS/Media.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AS/Media.c b/src/AS/Media.c index 65f049c..5fbc659 100644 --- a/src/AS/Media.c +++ b/src/AS/Media.c @@ -150,7 +150,7 @@ ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha) return false; } - path = StrConcat(3, "/_matrix/media/v3/download/", uri->host, uri->path); + path = StrConcat(3, "/_matrix/client/v1/media/download/", uri->host, uri->path); cctx = ParseeCreateRequest(c, HTTP_GET, path); ASAuthenticateRequest(c, cctx); HttpRequestSendHeaders(cctx); @@ -195,7 +195,7 @@ ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len) return false; } - path = StrConcat(3, "/_matrix/media/v3/download/", uri->host, uri->path); + path = StrConcat(3, "/_matrix/client/v1/media/download/", uri->host, uri->path); cctx = ParseeCreateRequest(c, HTTP_GET, path); ASAuthenticateRequest(c, cctx); HttpRequestSendHeaders(cctx); From 7b8ed08e881da531f68f425db8f50b0c1943e5ac Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 13 Apr 2025 10:39:15 +0000 Subject: [PATCH 183/186] [ADD] Optionally allow instance admins to ignore m.notice events --- CHANGELOG.md | 2 ++ README.MD | 2 +- src/MatrixEventHandler.c | 8 ++++++++ src/Parsee/Config.c | 2 ++ src/include/Parsee.h | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b12530..f4ffcde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ TBD - The endpoint for media has been changed to '/media/[SERV]/[ID]?hmac=...' - Add parsee-plumb tool to manage plumbing from outside Parsee if it is not running. - Add packaging for Guix (see #18) +- Parsee is now dependent on authenticated media to function. + (Please, Matrix, do _not_ touch anything, I do _not_ want to mess with this anymore) #### Bugfixes - Fix potential infinite loops when processing some messages. - Parsee now handles pinging puppets from Matrix more sanely. diff --git a/README.MD b/README.MD index ee223de..f9522e8 100644 --- a/README.MD +++ b/README.MD @@ -22,7 +22,7 @@ Please scream at me if that fails(or just doesn't run on a overclocked Raspberry ### "Why not just use Matrix lol" ### "Why not just use XMPP lol" -These two having the same answer should be enough information. Also can I *just* have fun? +These two having the same answer should be enough information. One could also argue that both sides need to migrate(onboard) the other side, so a bridge may be a good way to start. diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 17a3bb9..638b5a3 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -367,6 +367,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) DbRef *ref = NULL; HashMap *json = NULL; + char *msgtype = GrabString(event, 2, "content", "msgtype"); char *m_sender = GrabString(event, 1, "sender"); char *unedited_id = NULL; char *body = GrabString(event, 2, "content", "body"); @@ -391,6 +392,13 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) if (new_content) body = new_content; } + if (data->config->ignore_bots && StrEquals(msgtype, "m.notice")) + { + Free(reply_id); + Free(xepd); + Free(unedited_id); + return; + } if (ParseeIsPuppet(data->config, m_sender) || ParseeManageBan(data, m_sender, id)) { diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 45e6fe5..b95e5e1 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -85,6 +85,8 @@ ParseeConfigLoad(char *conf) config->max_stanza_size = 10000; } + CopyToBool(ignore_bots, "ignore_bots"); + CopyToStr(media_base, "media_base"); CopyToStr(db_path, "db"); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index ea5d18b..4b1f7aa 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -44,6 +44,7 @@ typedef struct ParseeConfig { int homeserver_tls; bool accept_pings; + bool ignore_bots; /* ------- JABBER -------- */ From e3749817d3585aa0218bb9602f222ecac85f526f Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 13 Apr 2025 10:49:40 +0000 Subject: [PATCH 184/186] [MOD/FIX] Be even more strict with Unicode filtering Now, only ASCII characters get to fit. --- src/MatrixEventHandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 638b5a3..6311fac 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -21,7 +21,7 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char char *sender = GrabString(event, 1, "sender"); Unistr *uninick = UnistrCreate(name); - Unistr *filtered = UnistrFilter(uninick, UnistrIsBMP); + Unistr *filtered = UnistrFilter(uninick, UnistrIsASCII); /* I'm not even going to try messing with the BMP anymore. */ char *nick = UnistrC(filtered); char *rev = StrConcat(3, muc, "/", nick); int nonce = 0; From e617b5e8d47dfd8955c5e3565394e9f2b14a1204 Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 28 Apr 2025 02:18:57 +0200 Subject: [PATCH 185/186] [FIX/WIP] Unique redactions for moderation stanzas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also, I'll consider Parsee dev to be dead until July 2026. J'ai le bac et déja un projet à faire, et si je peux même pas me concentrer sur mon futur en ne comptant pas Parsee. Feel free to make a good XMPP bridge, I don't really even want to touch either Matrix or XMPP anymore, you know? --- src/XMPPThread/Stanzas/Message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index c4066d9..13021df 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -277,7 +277,7 @@ end_error: Log(LOG_DEBUG, "Error management: %fs", Elapsed(rectime)); } - if (moderated) + if (moderated && !(!chat && strncmp(HashMapGet(stanza->attrs, "to"), "parsee@", 7))) { /* TODO: Parsee MUST check if it is a valid MUC */ char *resource = ParseeGetResource(from); From e331d110c7fa57e1a3fd96f8ff993cf59d714f9c Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 22 Jun 2025 14:00:12 +0200 Subject: [PATCH 186/186] [FIX] URL encode filenames --- src/Parsee/User.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Parsee/User.c b/src/Parsee/User.c index a9320d8..6e673bb 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -725,12 +726,14 @@ ParseeToUnauth(ParseeData *data, char *mxc, char *filename) } else { + char *encoded = HttpUrlEncode(filename); l = snprintf(NULL, 0, PATF, data->config->media_base, - url->host, url->path, filename, + url->host, url->path, encoded, hmac ); + Free(encoded); } ret = Malloc(l + 3); if (!filename)