diff --git a/.forgejo/workflows/build-release.yaml b/.forgejo/workflows/build-release.yaml deleted file mode 100644 index c649ab1..0000000 --- a/.forgejo/workflows/build-release.yaml +++ /dev/null @@ -1,85 +0,0 @@ -name: Builds static Parsee -on: [push] -jobs: - compile: - strategy: - matrix: - distro: - - debian - arch: - - amd64 - - arm64 - runs-on: - - ${{ matrix.distro }} - - ${{ matrix.arch }} - container: - image: ${{ matrix.distro }} - steps: - - 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 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 - 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 - 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 MbedTLS - run: | - alias musl-gcc="musl-gcc -Wl,-Bstatic -L ${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" - 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 - git fetch - rm configure - wget https://kappach.at/configure - chmod +x configure - ./configure --cc=musl-gcc --prefix=${PREFIX} --with-lmdb --with-mbed - make -j$(nproc) - make install - - 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" - musl-gcc -static configure.c -o configure && ./configure -s -l - make CC=musl-gcc CYTO_INC=${PREFIX}/include CYTO_LIB=${PREFIX}/lib LDFLAGS=-s - make PREFIX=bins install - - name: Create a final archive - run: | - cd parsee - 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 }} - path: ${{ env.DIR }} - compression-level: 9 diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml deleted file mode 100644 index 5404fa6..0000000 --- a/.forgejo/workflows/check-gcc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: Checks Parsee's correctness on GCC+Debian -on: [push] -jobs: - compile: - strategy: - matrix: - distro: - - debian - arch: - - amd64 - runs-on: - - ${{ matrix.distro }} - - ${{ matrix.arch }} - container: - image: ${{ matrix.distro }} - steps: - - 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/Configure Cytoplasm - run: | - git clone https://git.kappach.at/KappaChat/Cytoplasm --depth=1 - cd Cytoplasm - ./configure --with-lmdb --prefix=/usr - - name: Build Cytoplasm - run: 'cd Cytoplasm && make -j$(nproc)' - - name: Install Cytoplasm - run: 'cd Cytoplasm && make install' - - name: Clone Parsee - uses: actions/checkout@v3 - - name: Build Parsee - run: | - cc configure.c -o configure && ./configure - echo 'CFLAGS=-Werror -Wall -Wextra -pedantic -fanalyzer' >> build.conf - cat build.conf - make && make ayadoc - - name: Install Parsee - run: 'make install' - diff --git a/.gitignore b/.gitignore index 09b6fd1..ff7606f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,29 +4,11 @@ parsee* parsee *.swp .* -data* -data*/* -Makefile -configure -gmon.out +data +data/* tools/out tools/out/* ayaya/* ayaya - -#ctags -tags - -# Whitelists -!etc/* -!etc/** -!.forgejo -!.forgejo/* -!.forgejo/** - -!.guix -!.guix/* -!.guix/** - diff --git a/.guix/modules/parsee.scm b/.guix/modules/parsee.scm deleted file mode 100644 index 75b8b64..0000000 --- a/.guix/modules/parsee.scm +++ /dev/null @@ -1,82 +0,0 @@ -(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 (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")) - (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)))) - -(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 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f4ffcde..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,84 +0,0 @@ -# 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. - -## Release -*There is currently no full releases of Parsee* - -## Beta -*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. -- 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. - -### 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 -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. -- 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 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(especially with DEC Alpha) -- Start contextualising XMPP commands(all/Parsee admins/MUCs). - -#### 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 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. -- 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, -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/CONTRIBUTORS b/CONTRIBUTORS deleted file mode 100644 index c7f8b75..0000000 --- a/CONTRIBUTORS +++ /dev/null @@ -1,14 +0,0 @@ -# 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/DATES.TXT b/DATES.TXT index 4da14dc..8e32ab3 100644 --- a/DATES.TXT +++ b/DATES.TXT @@ -1,3 +1,7 @@ Some dates for Parsee-related events. They mostly serve as LDA's TODOs with a strict deadline: - - Get star-of-hope out by November 8 + - ~September 2024[star-of-hope]: + 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. diff --git a/LICENSE b/LICENSE index cb9aa73..5d9765c 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(AGPL-3.0-or-later) +For the files src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, see COPYING.CC0 +to be present. +For any other file in src/, see COPYING.AGPL as the primary license. As Parsee depends on Cytoplasm, its license is left here in COPYING.CYTO diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..733bd71 --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +# 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 ============================= + +# phantasmagoria - test runs without an actual code +CODE=phantasmagoria +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. +PREFIX ?=/usr/local + +SOURCE=src +OBJECT=build +AYAS=ayaya +ETC=etc +INCLUDES=src/include +CC=cc +CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -DCODE=\"$(CODE)\" -g -ggdb -Wall -Werror +LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -g -ggdb +AFLAGS=-C "$(ETC)/ayadoc/style.css" -p "$(NAME)" +BINARY=parsee +# ============================ Compilation ================================= +SRC_FILES:=$(shell find $(SOURCE) -name '*.c') +OBJ_FILES:=${subst $(SOURCE)/,$(OBJECT)/,$(patsubst %.c, %.o, $(SRC_FILES))} + +CPP_FILES:=$(shell find $(INCLUDES) -name '*.h') +AYA_FILES:=${subst $(INCLUDES)/,$(AYAS)/,$(patsubst %.h, %.html, $(CPP_FILES))} + +all: binary utils + +binary: $(OBJ_FILES) + $(CC) $(LDFLAGS) $(OBJ_FILES) -o $(BINARY) + +clean: + rm -rf $(OBJECT) $(BINARY) $(AYAS) + +$(OBJECT)/%.o: $(SOURCE)/%.c + @mkdir -p $(shell dirname "$@") + $(CC) -c $(CFLAGS) $< -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/README.MD b/README.MD index f9522e8..672d11b 100644 --- a/README.MD +++ b/README.MD @@ -1,54 +1,39 @@ # 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, and it may behave strangely at times. +Parsee is a Matrix<=>XMPP bridge written in C99, with Cytoplasm, similar to Bifrost, but it is NOT a drop-in replacment. ## Why? ### Naming -The name 'Parsee' is actually a reference to [Parsee Mizuhashi](https://en.touhouwiki.net/wiki/Parsee_Mizuhashi), -a "*bridge* princess". The other name you actually can sometimes see explains itself, so I won't -be talking about it. +The name 'Parsee' is actually a reference to [Parsee Mizuhashi](https://en.touhouwiki.net/wiki/Parsee_Mizuhashi), a +"*bridge* princess". ### 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*, -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)) +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*. +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, was literally where Parsee+XMPP ran for +a good chunk of Parsee's start.) ### "Why not just use Matrix lol" ### "Why not just use XMPP lol" -These two having the same answer should be enough information. +These two having the same answer should be enough information. Also can I *just* have fun? One could also argue that both sides need to migrate(onboard) the other side, so a bridge may be a good way to start. ## BUILDING ```sh -$ 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 +$ 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. ``` 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. +change a few variables (you can set `CYTO_INC` and `CYTO_LIB`) ### DEPENDENCIES -Parsee tries to avoid dependencies aside from [Cytoplasm](https://git.telodendria.io/Telodendria/Cytoplasm). -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 -``` +Parsee tries to avoid dependencies aside from [Cytoplasm](https://git.telodendria.io/Telodendria/Cytoplasm). Itself optionally depends on a good POSIX implementation, and optionally OpenSSL/LMDB (highly recommended, but you can get away without those). ## RUNNING First off, you may want to configure Parsee by running the `config` tool(generally named @@ -61,8 +46,7 @@ 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 \ - -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. + -p 5347 ``` If everything goes well, it should generate a `parsee.json` file. @@ -75,44 +59,31 @@ 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 -- 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. +## TODOS +- Add [libomemo](https://github.com/gkdr/libomemo) 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~~ 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. + put in the work of either forking off libolm or making a binding to KappaChat. - Get rid of the '?'-syntax and use another invalid Matrix char/valid XMPP char ('$'?) for escaped? +- PROPER FUCKING AVATARS + XEP-0084 IS THE WORST PIECE OF SHIT KNOWN TO MAN. If any Jabberbros want to + look at terrible code/XML and suggest things to have *proper* avatar support, + I'm all in. - 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 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. - 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 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 @@ -129,7 +100,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 there. If you *really* want, you may just open +Please avoid asking for help/issues here. 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) diff --git a/XEPS-TBD.TXT b/XEPS-TBD.TXT index 9ed28cf..02a68ca 100644 --- a/XEPS-TBD.TXT +++ b/XEPS-TBD.TXT @@ -1,19 +1,6 @@ XEPs current supported are in src/XMPPThread, at the IQ disco advertising. Somewhat implemented XEPs: - v https://xmpp.org/extensions/xep-0050.html - Ad-hoc commands that bridge maintainers can deal with XMPP-style are - also a nice to have. - There are commands, but not a lot of them as of now, and localisation - is missing. - v https://xmpp.org/extensions/xep-0421.html - Using the occupant ID in semi-anonymous MUCs is a desirable property. - I dont know of a lot of places that don't use the occupant ID anymore - within Parsee. - v "also it [Bifrost] doesn't respect voice either" - As far as I am aware, works. - v https://xmpp.org/extensions/xep-0425.html - As mentionned in #2, moderation _needs_ to be done. ~ https://xmpp.org/extensions/xep-0085.html Only XMPP->Matrix at the moment. Still need to figure out how to get typing indicators as an AS. @@ -21,14 +8,21 @@ 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 - TODO: Add support from Matrix. + HALF-IMPLEMENTED: Removing reacts won't work. ~ 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 + ~ https://xmpp.org/extensions/xep-0050.html + Ad-hoc commands that bridge maintainers can deal with XMPP-style are + also a nice to have. + There are commands, but not a lot of them as of now, and localisation + is missing. + ~ https://xmpp.org/extensions/xep-0421.html + Using the occupant ID in semi-anonymous MUCs is a desirable property. + I dont know of a lot of places that don't use the occupant ID anymore + within Parsee. + ~ https://xmpp.org/extensions/xep-0425.html + As mentionned in #2, moderation _needs_ to be done. For future XEPs: - https://xmpp.org/extensions/xep-0449.html @@ -38,16 +32,22 @@ 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: +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 unreliable, however. x https://xmpp.org/extensions/xep-0080.html Can't think of a good analogy to these... Not XEPs, but ideas that _needs_ to be added: + v "also it [Bifrost] doesn't respect voice either" -> Send a form on moderated + MUCs (which is standard, so its not too bad!). Currently WIP, and barely tested. ~ "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 deleted file mode 100644 index a2e17c1..0000000 --- a/build.conf +++ /dev/null @@ -1,10 +0,0 @@ -CODE=lunar-rainbow -NAME=Parsee -VERSION=0.3.0 -BINARY=parsee -SOURCE=src -INCLUDES=src/include -OBJECT=build -CC=cc -CFLAGS=-O3 -PREFIX=/usr diff --git a/configure.c b/configure.c deleted file mode 100644 index d3a01d0..0000000 --- a/configure.c +++ /dev/null @@ -1,727 +0,0 @@ -/* 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 -#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; -} - -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)); - if (!ret) - { - return NULL; - } - - 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; - int result; - if (!cmd) - { - goto failure; - } - if (!(f = popen(cmd, "r"))) - { - goto failure; - } - - getline(&line, &size, 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 char * -strchrn(char *s, char c) -{ - s = strchr(s, c); - return s ? s+1 : NULL; -} -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 (!strcmp(name, ".") || !strcmp(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; - } - { - char *d1 = string_cat(dir, "/"); - char *d2 = string_cat(d1, name); - size_t i; - struct stat sb; - - if (stat(d2, &sb)) - { - fprintf(stderr, "stat(2) %s: %s\n", d2, strerror(errno)); - free(d2); - free(d1); - } - 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); - } - } - 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 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[]) -{ - FILE *makefile; - char *repo = cmd_stdout("git remote get-url origin"); - size_t i; - bool with_static = false, with_lmdb = false; - int opt; - str_array_t *sources, *images, *utils, *aya; - - if (repo) - { - char *lf = strchr(repo, '\n'); - if (lf) - { - *lf = '\0'; - } - } - else - { - repo = strdup("N/A"); - } - - 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"); - 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"); - 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) -o $(BINARY)"); - if (with_static) - { - fprintf(makefile, " -static"); - } - fprintf(makefile, " -L $(CYTO_LIB)"); - write_objects(makefile, sources); - write_images(makefile, images); - if (with_static) - { - fprintf(makefile, " -lm -lpthread -lmbedtls -lmbedx509 -lmbedcrypto -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto"); - if (with_lmdb) fprintf(makefile, " -llmdb"); - } - fprintf(makefile, " -lCytoplasm $(LDFLAGS)\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", obj, src); - analyse_dependencies(makefile, src); - fprintf(makefile, "\n"); - { - 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=\"\\\"$(VERSION)\\\"\" "); - fprintf(makefile, "-DNAME=\"\\\"$(NAME)\\\"\" "); - fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" "); - fprintf(makefile, "-DREPOSITORY=\"\\\"%s\\\"\" ", repo); - fprintf(makefile, "$(CFLAGS) %s -o %s\n", src, obj); - } - 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 %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); - 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) -o %s", obj); - if (with_static) - { - fprintf(makefile, " -static"); - } - fprintf(makefile, " %s", src); - fprintf(makefile, " -I $(CYTO_INC)"); - fprintf(makefile, " -L $(CYTO_LIB)"); - if (with_static) - { - fprintf(makefile, " -lm -lpthread -lmbedtls -lmbedx509 -lmbedcrypto"); - fprintf(makefile, " -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto"); - if (with_lmdb) fprintf(makefile, " -llmdb"); - } - fprintf(makefile, " -lCytoplasm $(CFLAGS)\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 %s -o %s\n", src, obj - ); - } - - 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); -} diff --git a/etc/man/man1/parsee-adminify.1 b/etc/man/man1/parsee-adminify.1 deleted file mode 100644 index 9015d20..0000000 --- a/etc/man/man1/parsee-adminify.1 +++ /dev/null @@ -1,40 +0,0 @@ -." The last field is the codename, by the way. -." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-adminify 1 "Parsee Utility" "star-of-hope" - -.SH NAME -parsee-adminify - bootstrap an admin to a new Parsee server - -.SH SYNOPSIS -parsee-adminify -.B [DB path] -.B [user] - -.SH DESCRIPTION -.I parsee-adminify -is a tool to add/list the Parsee administrator list. It currently only -allows you to see/add admins to it, using simplified globrules. - -.SH OPTIONS -.TP -.B [config] -The configuration file used by the Parsee daemon. -.TP -.B [user] -If set, adds the glob -.I [user] -as a Parsee administrator. Otherwise, lists all administrators in -the Parsee instance. - -.SH BUGS -.PP -None as I know of. If anyone notices any issues with this, please -let me know. - -.SH LICENSE -Unlike Parsee, -.B parsee-adminify -is under the CC0/PD. - -.SH SEE ALSO -.B parsee-config(1), parsee-aya(1), parsee(1) diff --git a/etc/man/man1/parsee-aya.1 b/etc/man/man1/parsee-aya.1 deleted file mode 100644 index b51afa0..0000000 --- a/etc/man/man1/parsee-aya.1 +++ /dev/null @@ -1,40 +0,0 @@ -." The last field is the codename, by the way. -." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-aya 1 "Parsee Utility" "star-of-hope" - -.SH NAME -parsee-aya - generate some nice Ayaya! documentation - -.SH SYNOPSIS -parsee-aya -.B [-i HEADER] -.B [-o HTML] -.B [-C STYLESHEET] -.B [-p NAME] - -.SH DESCRIPTION -.I parsee-aya -is a tool to generate Ayadocs(HTML documentation) from a formatted -header file. See a Parsee header file for an example of the inner usage. - -.SH OPTIONS -.TP -.BR -i HEADER -The input header file to process out. -.TP -.BR -o HTML -The HTML file to write out the Ayadoc. -.TP -.BR -C STYLESHEET -A stylesheet file to use for Ayadocs. -.TP -.BR -p NAME -The project's name. If unavailable, defaults to Ayaya! - -.SH LICENSE -Unlike Parsee, -.B parsee-aya -is under the CC0/PD. - -.SH SEE ALSO -.B parsee-config(1), parsee-adminify(1), parsee(1) diff --git a/etc/man/man1/parsee-config.1 b/etc/man/man1/parsee-config.1 deleted file mode 100644 index 5dc258b..0000000 --- a/etc/man/man1/parsee-config.1 +++ /dev/null @@ -1,103 +0,0 @@ -." The last field is the codename, by the way. -." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-config 1 "Parsee Utility" "lunar-rainbow" - -.SH NAME -parsee-config - generate a basic configuration file - -.SH SYNOPSIS -parsee-config -.B [-H HOMESERVER_NAME] -.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] -.B [-S DATABASE size] - -.SH DESCRIPTION -.I parsee-config -creates a basic configuration file to initialise a Parsee instance with the -given input flags, and makes a basic database. A basic example of -.I parsee-config -would be this(for a blow.hole server, with a xmpp.blow.hole JCP on Prosody, -and a 128MB LMDB backend) -.sp -.if n \{\ -.RS 4 -.\} -.nf -$ parsee-config \\ - -d '/var/lib/parsee' \\ - -m 'https://pmedia.blow.hole' \\ - -H 'blow.hole' \\ - -s 'The Dark Shared Secret' \\ - -J 'xmpp.blow.hole' \\ - -j 'localhost' \\ - -S 128 -.fi -.if n \{\ -.RE -.\} -.sp - -.SH OPTIONS -.TP -.BR -H HOMESERVER_NAME -.I HOMESERVER_NAME -points to the homeserver name, without delegation (which is autosensed). -For example, if you except Parsee users to be on -.IR @something:blow.hole -, then it should be set to -.IR blow.hole . -.TP -.BR -s SHARED_SECRET -.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 -media. It must be publicly accessible (behind a reverse proxy to HTTP:7642) -.TP -.BR -J JABBER_HOST -.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 -.I JABBER_HOST -to connect to -.I JABBER_HOST:JABBER_PORT -over TCP. -.TP -.BR -d DATABASE -The directory inwhich Parsee stores its database(LMDB/flat-file). Whenever the -database is flat or LMDB is dictated by the presence of the -S flag, and -whenever Cytoplasm has LMDB enabled. -.TP -.BR -S SIZE -If set, enables LMDB in Parsee, and sets its max DB size to -.BR SIZE MiB . - - -.SH LICENSE -Unlike Parsee, -.B parsee-config -is under the CC0/PD. - -.SH SEE ALSO -.B parsee-aya(1), parsee-adminify(1), parsee(1) diff --git a/etc/man/man1/parsee.1 b/etc/man/man1/parsee.1 deleted file mode 100644 index d7eeedf..0000000 --- a/etc/man/man1/parsee.1 +++ /dev/null @@ -1,118 +0,0 @@ -." The last field is the codename, by the way. -." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee 1 "Parsee Utility" "star-of-hope" - -.SH NAME -parsee - the jealous XMPP-Matrix bridge - -.SH SYNOPSIS -parsee -.B [-J num] -.B [-H num] -.B [-C file] -.B [-g] -.B [-v] -.B [-h] - -.SH DESCRIPTION -Parsee is a -.B bridging program -, that is, it connects two chat protocols together (here, XMPP/Jabber, -and Matrix). -.PP -As such, a user on XMPP can communicate with Matrix users, and -vice-versa with it. -.PP -Currently, Parsee is under -.BI alpha . -This means that it is still subject to bugs, flaws, and may change in a -backwards-incompatible manner at any time. - -.SH FIRST RUN -To start with a new install of Parsee(assuming you have a homeserver -with AS support and a XMPP server with JCP support, and that you know -the shared secret/domain for that component. Guides for that are -outside the scope of this manpage.), start by running -.B parsee-config(1) -with the flags provided in it, according to your configuration. -.PP -This should generate a -.I parsee.json -file, which is the configuration files for Parsee, and a directory where -the Parsee database may reside. You can then run -.I parsee -g -in that directory, which should generate a -.I parsee.yaml -file, this time with the generated AS configuration file, which you can -apply to your homeserver(how is implementation-dependent, but it is -generally a matter of modifying a configuration file to add the path -to such file). - -.SH OPTIONS -.TP -.BR -J num -Set the number of threads used for XMPP stanza processing to -.I num\[char46] -.TP -.BR -H num -Set the number of threads used for HTTP request processing to -.I num\[char46] -.TP -.BR -C file -Sets the configuration JSON path to -.I file\[char46] -.PP -Defaults to -.I parsee.json -if none can be found. -.TP -.BR -g -Generates a -.I parsee.yaml -file to be used as an Application-Service entry within Matrix, and -exits. -.TP -.BR -v -Verbose logging of Parsee's behaviour. Recommended when testing Parsee -for bugs/hints. -.TP -.BR -h -Prints the command list with descriptions. - -.SH BUGS -.PP -Sometimes Parsee will not respond to ^C requests properly, which -causes a system administrator to have to invoke SIGKILL. -.PP -Parsee seems to grow slowly in memory usage when messages are bridged -which, in the long run, could cause a memory error. All of the memory is -tracked, however, which means that this isn't exactly a leak. -.PP -Some important features still aren't implemented yet(e.g being able to join -a MUC from XMPP) - -.SH CHATROOMS -You may talk about Parsee on these rooms(on Matrix and XMPP): -.RE -.IP xmpp:parsee@conference.monocles.eu?join -for XMPP, which is bridged along Matrix -.IP #parsee:tedomum.net -for Matrix, which is bridged along Parsee -.RS - -.SH AUTHORS -." Contributors, feel free to put your names here in a PR, as long as -." it is acceptable -. PP -.BR LDA: -main maintainer of Parsee, accessible over XMPP at lda@freetards.xyz -and over Matrix as @fourier:ari.lt. - -.SH LICENSE -Parsee is available under the AGPL3, but has some code under CC0/PD, and -some from Cytoplasm itself. Please see -.I https://git.kappach.at/lda/Parsee -for more information. - -.SH SEE ALSO -.B parsee-config(1), parsee-adminify(1), parsee-aya(1) diff --git a/etc/man/man7/.parsee-bridge-guidebook.7.swp b/etc/man/man7/.parsee-bridge-guidebook.7.swp deleted file mode 100644 index 50976ea..0000000 Binary files a/etc/man/man7/.parsee-bridge-guidebook.7.swp and /dev/null differ diff --git a/etc/man/man7/.parsee-cmd-syntax.7.swp b/etc/man/man7/.parsee-cmd-syntax.7.swp deleted file mode 100644 index 64990b7..0000000 Binary files a/etc/man/man7/.parsee-cmd-syntax.7.swp and /dev/null differ diff --git a/etc/man/man7/parsee-bridge-guidebook.7 b/etc/man/man7/parsee-bridge-guidebook.7 deleted file mode 100644 index b5932f2..0000000 --- a/etc/man/man7/parsee-bridge-guidebook.7 +++ /dev/null @@ -1,70 +0,0 @@ -." The last field is the codename, by the way. -." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-bridge-guidebook 7 "Parsee Utility" "star-of-hope" - -.SH NAME -parsee-bridge-guidebook - A short guidebook on running a Parsee bridge - -.SH INTRODUCTION -.P -This manpage is intended to be a guidebook for Parsee administrators. It -is meant to show how to create an instance with an XMPP-Matrix server -(though it cannot be specific, due to their ecosystem diversity), how to -plumb rooms, and moderate them through. -.P -It also assumes Parsee is properly built and installed, in which case you -are seeing this from -.I man -itself. - -.SH CONVENTIONS -This page shall assume a few things that -.B must -be changed to fit your configuration. Please read those carefully, or it -will come and bite at you! - -.P -First off, it assumes that you have a domain at -.I blow.hole -and that any other domains related to Parsee are it's subdomains, as -you'll see. - -.P -We also assume you're planning on making the XMPP component available at -.I j.blow.hole , -and that Parsee can reach it by using -.I localhost:1234 . -It is highly recommended that Parsee can reach the component locally, as -the stream cannot be encrypted! - -.P -The Parsee HTTP server (which is used for media and the appservice) shall -be reached through -.I https://p.blow.hole/ -via a reverse proxy. This manual shall only show you what port to make -available, as there are many reverse proxy options available. - -.P -Finally, the Matrix server will be publicly known as -.I m.blow.hole -. - -That is, if -.B bob -is in it, then they shall be known as -.I @bob:m.blow.hole . - -.SH SETTING UP -Setting up Parsee mainly involves creating a valid configuration file -and the database. Most of this however is dealt with by -.I parsee-config(1) -TODO - -.P - -.SH LICENSE -This document is under public domain, or CC0 if not allowed by local law. - -.SH SEE ALSO -.B parsee(1), parsee-cmd-syntax(7) - diff --git a/etc/man/man7/parsee-cmd-syntax.7 b/etc/man/man7/parsee-cmd-syntax.7 deleted file mode 100644 index ba11e67..0000000 --- a/etc/man/man7/parsee-cmd-syntax.7 +++ /dev/null @@ -1,50 +0,0 @@ -." 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/etc/media/README b/etc/media/README deleted file mode 100644 index 2ef7300..0000000 --- a/etc/media/README +++ /dev/null @@ -1,5 +0,0 @@ -This directory is for any PNG media that needs to be integrated into Parsee. -Each file here is Base64-encoded then defined as a const char[] symbol with -the name being a function of the PNG filename: N(FILE.png)=media_FILE - -NOTE: Medias should be about ~1024B MAX. Avoid to stride for anything larger. diff --git a/etc/media/parsee_logo.png b/etc/media/parsee_logo.png deleted file mode 100644 index 1e0a8a1..0000000 Binary files a/etc/media/parsee_logo.png and /dev/null differ diff --git a/etc/media/unknown.png b/etc/media/unknown.png deleted file mode 100644 index 00ccf91..0000000 Binary files a/etc/media/unknown.png and /dev/null differ diff --git a/guix.scm b/guix.scm deleted file mode 120000 index 021acc5..0000000 --- a/guix.scm +++ /dev/null @@ -1 +0,0 @@ -.guix/modules/parsee.scm \ No newline at end of file diff --git a/src/AS.c b/src/AS.c index f9d1700..81ce4a9 100644 --- a/src/AS.c +++ b/src/AS.c @@ -55,5 +55,976 @@ ASAuthenticateRequest(const ParseeConfig *data, HttpClientContext *ctx) HttpRequestHeader(ctx, "Authorization", bearer); Free(bearer); } +bool +ASRegisterUser(const ParseeConfig *conf, char *user) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + HttpStatus status; + if (!conf || !user) + { + return false; + } + /* Create user. We don't actually care about the value as we can + * masquerade, as long as it exists. */ + ctx = ParseeCreateRequest( + conf, + HTTP_POST, "/_matrix/client/v3/register" + ); + json = HashMapCreate(); + HashMapSet(json,"type",JsonValueString("m.login.application_service")); + + user = ParseeGetLocal(user); + HashMapSet(json,"username",JsonValueString(user)); + + ASAuthenticateRequest(conf, ctx); + status = ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); + + Free(user); + + return status == HTTP_OK; +} + +void +ASPing(const ParseeConfig *conf) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path; + if (!conf) + { + return; + } + + path = StrConcat(3, + "/_matrix/client/v1/appservice/", + "Parsee%20XMPP", + "/ping" + ); + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + HttpClientContextFree(ctx); + JsonFree(json); +} +void +ASInvite(const ParseeConfig *conf, char *id, char *invited) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *bridge; + if (!conf || !id || !invited) + { + return; + } + + bridge = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/invite", + "?user_id=", bridge + ); + Free(bridge); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + HashMapSet(json, "user_id", JsonValueString(invited)); + HashMapSet(json, "reason", JsonValueString("Pass over.")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); +} +void +ASBan(const ParseeConfig *conf, char *id, char *banned) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *bridge; + if (!conf || !id || !banned) + { + return; + } + + bridge = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/ban", + "?user_id=", bridge + ); + Free(bridge); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + HashMapSet(json, "user_id", JsonValueString(banned)); + HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); +} +void +ASKick(const ParseeConfig *conf, char *id, char *banned) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *bridge; + if (!conf || !id || !banned) + { + return; + } + + bridge = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/kick", + "?user_id=", bridge + ); + Free(bridge); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + HashMapSet(json, "user_id", JsonValueString(banned)); + HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); +} +char * +ASJoin(const ParseeConfig *conf, char *id, char *masquerade) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *ret; + if (!conf || !id) + { + return NULL; + } + + if (!masquerade) + { + char *raw = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + masquerade = HttpUrlEncode(raw); + Free(raw); + } + else + { + masquerade = HttpUrlEncode(masquerade); + } + id = HttpUrlEncode(id); + path = StrConcat(5, + "/_matrix/client/v3/join/", id, "?", + "user_id=", masquerade + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + json = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate(GrabString(json, 1, "room_id")); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(masquerade); + Free(id); + + return ret; +} +void +ASLeave(const ParseeConfig *conf, char *id, char *masquerade) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path; + if (!conf || !id) + { + return; + } + + if (!masquerade) + { + char *raw = StrConcat(4, + "@", conf->sender_localpart, + ":", conf->server_base + ); + masquerade = HttpUrlEncode(raw); + Free(raw); + } + else + { + masquerade = HttpUrlEncode(masquerade); + } + id = HttpUrlEncode(id); + path = StrConcat(5, + "/_matrix/client/v3/rooms/", id, "/leave?", + "user_id=", masquerade + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(masquerade); + Free(id); +} +void +ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *state) +{ + HttpClientContext *ctx = NULL; + char *path; + if (!conf || !id || !type || !mask || !state) + { + JsonFree(state); + return; + } + + path = StrConcat(9, + "/_matrix/client/v3/rooms/", id, "/state/", + type, "/", key, "?", "user_id=", mask + ); + + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, state); + + HttpClientContextFree(ctx); + JsonFree(state); +} +char * +ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) +{ + HttpClientContext *ctx = NULL; + char *path; + char *txn, *ret; + HashMap *reply; + if (!conf || !id || !type || !user || !c) + { + JsonFree(c); + return NULL; + } + + txn = StrRandom(16); + path = StrConcat(9, + "/_matrix/client/v3/rooms/", + id, "/send/", type, "/", txn, "?", + "user_id=", user + ); + Free(txn); + + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, c); + + reply = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); + JsonFree(reply); + + HttpClientContextFree(ctx); + JsonFree(c); + + return ret; +} +char * +ASCreateRoom(const ParseeConfig *conf, char *by, char *alias) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *id; + if (!conf || !by) + { + return NULL; + } + + path = StrConcat(3, + "/_matrix/client/v3/createRoom", + "?user_id=", by + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + if (alias) + { + char *trimmed = StrDuplicate(alias); + if (*alias == '#') + { + char *tmp, cb[2] = { 0 }; + alias++; + Free(trimmed); + trimmed = NULL; + + while (*alias && *alias != ':') + { + cb[0] = *alias; + tmp = trimmed; + trimmed = StrConcat(2, trimmed, cb); + Free(tmp); + alias ++; + } + } + HashMapSet(json, "room_alias_name", JsonValueString(trimmed)); + Free(trimmed); + } + HashMapSet(json, "visibility", JsonValueString("public")); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + JsonFree(json); + json = JsonDecode(HttpClientStream(ctx)); + id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); + HttpClientContextFree(ctx); + JsonFree(json); + + return id; +} +char * +ASCreateDM(const ParseeConfig *conf, char *by, char *with) +{ + HttpClientContext *ctx = NULL; + HashMap *json = NULL; + char *path, *id; + if (!conf || !by || !with) + { + return NULL; + } + + path = StrConcat(3, + "/_matrix/client/v3/createRoom", + "?user_id=", by + ); + + ctx = ParseeCreateRequest( + conf, + HTTP_POST, path + ); + Free(path); + json = HashMapCreate(); + { + Array *invitees = ArrayCreate(); + + ArrayAdd(invitees, JsonValueString(with)); + HashMapSet(json, "invite", JsonValueArray(invitees)); + HashMapSet(json, "is_direct", JsonValueBoolean(true)); + } + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + JsonFree(json); + json = JsonDecode(HttpClientStream(ctx)); + id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); + HttpClientContextFree(ctx); + JsonFree(json); + + return id; +} +void +ASSetAvatar(const ParseeConfig *conf, char *user, char *mxc) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!conf || !user || !mxc) + { + return; + } + + user = HttpUrlEncode(user); + path = StrConcat(6, + "/_matrix/client/v3/profile/", + user, "/avatar_url", "?", + "user_id=", user + ); + + json = HashMapCreate(); + HashMapSet(json, "avatar_url", JsonValueString(mxc)); + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); + Free(user); +} +void +ASSetName(const ParseeConfig *conf, char *user, char *name) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!conf || !user || !name) + { + return; + } + + user = HttpUrlEncode(user); + path = StrConcat(6, + "/_matrix/client/v3/profile/", + user, "/displayname", "?", + "user_id=", user + ); + + json = HashMapCreate(); + HashMapSet(json, "displayname", JsonValueString(name)); + ctx = ParseeCreateRequest(conf, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(conf, ctx); + ParseeSetRequestJSON(ctx, json); + + HttpClientContextFree(ctx); + JsonFree(json); + Free(user); +} +HashMap * +ASFind(const ParseeConfig *c, char *room, char *event) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path, *user; + if (!c || !room || !event) + { + return NULL; + } + + user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); + path = StrConcat(7, + "/_matrix/client/v3/rooms/", + room, "/event/", event, "?", + "user_id=", user + ); + + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(path); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + json = JsonDecode(HttpClientStream(ctx)); + + HttpClientContextFree(ctx); + Free(user); + + return json; +} +char * +ASGetName(const ParseeConfig *c, char *room, char *user) +{ + HttpClientContext *ctx; + HashMap *reply; + char *path, *ret; + char *u2 = user; + if (!c || !user) + { + return NULL; + } + + if (!room) + { + user = HttpUrlEncode(user); + path = StrConcat(3, + "/_matrix/client/v3/profile/", user, "/displayname" + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(user); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "displayname")) + ); + HttpClientContextFree(ctx); + JsonFree(reply); + Free(path); + + if (!ret) + { + ret = StrDuplicate(u2); + } + return ret; + } + user = HttpUrlEncode(user); + room = HttpUrlEncode(room); + path = StrConcat(4, + "/_matrix/client/v3/rooms/", room, + "/state/m.room.member/", user + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(user); + Free(room); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "displayname")) + ); + HttpClientContextFree(ctx); + JsonFree(reply); + Free(path); + + if (!ret) + { + ret = StrDuplicate(u2); + } + return ret; +} +HashMap * +ASGetPL(const ParseeConfig *c, char *room) +{ + char *path; + HttpClientContext *ctx; + HashMap *reply; + if (!c || !room) + { + return NULL; + } + room = HttpUrlEncode(room); + path = StrConcat(4, + "/_matrix/client/v3/rooms/", room, + "/state/m.room.power_levels/", "" + ); + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(room); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + reply = JsonDecode(HttpClientStream(ctx)); + + HttpClientContextFree(ctx); + Free(path); + + return reply; +} +void +ASSetPL(const ParseeConfig *conf, char *id, HashMap *m) +{ + char *user; + if (!conf || !id || !m) + { + return; + } + user = StrConcat(4, + "@",conf->sender_localpart, + ":",conf->server_base + ); + ASSetState(conf, id, "m.room.power_levels", "", user, m); + Free(user); +} + +char * +ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) +{ + char *size_str, *path, *ret, *user; + int i; + HttpClientContext *ctx; + HashMap *reply; + if (!c || !from) + { + return NULL; + } + + size_str = StrInt(size); + user = StrConcat(4, "@",c->sender_localpart,":",c->server_base); + path = StrConcat(2, + "/_matrix/media/v3/upload?user_id=", user + ); + ctx = ParseeCreateRequest(c, HTTP_POST, path); + ASAuthenticateRequest(c, ctx); + if (size) + { + HttpRequestHeader(ctx, "Content-Length", size_str); + } + if (mime) + { + HttpRequestHeader(ctx, "Content-Type", mime); + } + HttpRequestSendHeaders(ctx); + + for (i = 0; i < size; i++) + { + int ch = StreamGetc(from); + if (ch == EOF) + { + break; + } + StreamPutc(HttpClientStream(ctx), ch); + } + HttpRequestSend(ctx); + reply = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate( + JsonValueAsString(HashMapGet(reply, "content_uri")) + ); + if (!ret) + { + JsonEncode(reply, StreamStdout(), JSON_PRETTY); + StreamFlush(StreamStdout()); + } + HttpClientContextFree(ctx); + JsonFree(reply); + Free(size_str); + Free(path); + Free(user); + + return ret; +} +char * +ASReupload(const ParseeConfig *c, char *from, char **mime) +{ + Uri *uri; + HttpClientContext *ctx; + unsigned short port; + int size = 0, flags = HTTP_FLAG_NONE; + char *ret, *content_len; + + if (!c || !from) + { + return NULL; + } + + uri = UriParse(from); + if (!uri) + { + return NULL; + } + if (uri->port) + { + port = uri->port; + } + else if (StrEquals(uri->proto, "https")) + { + port = 443; + } + else + { + port = 80; + } + + if (StrEquals(uri->proto, "https")) + { + flags |= HTTP_FLAG_TLS; + } + + ctx = HttpRequest( + HTTP_GET, flags, port, uri->host, uri->path + ); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + if (mime) + { + *mime = HashMapGet(HttpResponseHeaders(ctx), "content-type"); + *mime = StrDuplicate(*mime); + } + + content_len = HashMapGet(HttpResponseHeaders(ctx), "content-length"); + if (content_len) + { + size = strtol(content_len, NULL, 10); + } + ret = ASUpload(c, HttpClientStream(ctx), size, mime ? *mime : NULL); + + HttpClientContextFree(ctx); + UriFree(uri); + return ret; +} +void +ASType(const ParseeConfig *c, char *user, char *room, bool status) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!c || !user || !room) + { + return; + } + + user = HttpUrlEncode(user); + path = StrConcat(6, + "/_matrix/client/v3/rooms/", + room, "/typing/", user, + "?user_id=", user + ); + + json = HashMapCreate(); + HashMapSet(json, "typing", JsonValueBoolean(status)); + /* If someone types for 10 minutes straight, they got something weird man. */ + HashMapSet(json, "timeout", JsonValueBoolean(10 MINUTES)); + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(user); +} + +void +ASPresence(const ParseeConfig *c, char *user, char *room, char *ev) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!c || !user || !room || !ev) + { + return; + } + + user = HttpUrlEncode(user); + room = HttpUrlEncode(room); + ev = HttpUrlEncode(ev); + path = StrConcat(6, + "/_matrix/client/v3/rooms/", + room, "/receipt/m.read/", ev, + "?user_id=", user + ); + + json = HashMapCreate(); + ctx = ParseeCreateRequest(c, HTTP_POST, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, json); + JsonFree(json); + + HttpClientContextFree(ctx); + Free(user); + Free(room); + Free(ev); +} + +HashMap * +ASGetUserConfig(const ParseeConfig *c, char *user, char *key) +{ + HttpClientContext *ctx = NULL; + HashMap *json; + char *path; + if (!c || !key) + { + return NULL; + } + + if (!user) + { + char *raw = StrConcat(4, + "@", c->sender_localpart, + ":", c->server_base + ); + user = HttpUrlEncode(raw); + Free(raw); + } + else + { + user = HttpUrlEncode(user); + } + path = StrConcat(7, + "/_matrix/client/v3/user/", + user, "/account_data/", key, "?", + "user_id=", user + ); + + ctx = ParseeCreateRequest(c, HTTP_GET, path); + Free(path); + ASAuthenticateRequest(c, ctx); + HttpRequestSendHeaders(ctx); + HttpRequestSend(ctx); + + json = JsonDecode(HttpClientStream(ctx)); + + HttpClientContextFree(ctx); + Free(user); + + return json; +} +void +ASSetUserConfig(const ParseeConfig *c, char *user, char *key, HashMap *map) +{ + HttpClientContext *ctx = NULL; + char *path; + if (!c || !key || !map) + { + JsonFree(map); + return; + } + + if (!user) + { + char *raw = StrConcat(4, + "@", c->sender_localpart, + ":", c->server_base + ); + user = HttpUrlEncode(raw); + Free(raw); + } + else + { + user = HttpUrlEncode(user); + } + + path = StrConcat(7, + "/_matrix/client/v3/user/", + user, "/account_data/", key, "?", + "user_id=", user + ); + + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, map); + + HttpClientContextFree(ctx); + Free(user); + JsonFree(map); + + return; +} +void +ASRedact(const ParseeConfig *c, char *room, char *user, char *e_id) +{ + HttpClientContext *ctx = NULL; + HashMap *request; + char *path, *txn; + if (!c || !room || !e_id) + { + return; + } + + if (!user) + { + char *raw = StrConcat(4, + "@", c->sender_localpart, + ":", c->server_base + ); + user = HttpUrlEncode(raw); + Free(raw); + } + else + { + user = HttpUrlEncode(user); + } + room = HttpUrlEncode(room); + e_id = HttpUrlEncode(e_id); + txn = StrRandom(16); + + path = StrConcat(9, + "/_matrix/client/v3/rooms/", + room, "/redact/", e_id, "/", txn, + "?", "user_id=", user + ); + + request = HashMapCreate(); + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + Free(path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, request); + JsonFree(request); + + HttpClientContextFree(ctx); + Free(user); + Free(room); + Free(e_id); + Free(txn); + + return; +} +void +ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, char *msg) +{ + HttpClientContext *ctx = NULL; + HashMap *request; + char *path; + char *status_str = NULL; + if (!c || !user) + { + return; + } + + switch (status) + { + case USER_STATUS_ONLINE: status_str = "online"; break; + case USER_STATUS_OFFLINE: status_str = "offline"; break; + case USER_STATUS_UNAVAILABLE: status_str = "unavailable"; break; + default: return; + } + + user = HttpUrlEncode(user); + path = StrConcat(5, + "/_matrix/client/v3/presence/",user,"/status", + "?user_id=", user + ); + Free(user); + + request = HashMapCreate(); + HashMapSet(request, "presence", JsonValueString(status_str)); + if (msg) + { + HashMapSet(request, "status_msg", JsonValueString(msg)); + } + + ctx = ParseeCreateRequest(c, HTTP_PUT, path); + ASAuthenticateRequest(c, ctx); + ParseeSetRequestJSON(ctx, request); + JsonFree(request); + + HttpClientContextFree(ctx); + Free(path); +} diff --git a/src/AS/Events.c b/src/AS/Events.c deleted file mode 100644 index 83ce147..0000000 --- a/src/AS/Events.c +++ /dev/null @@ -1,93 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -HashMap * -ASFind(const ParseeConfig *c, char *room, char *event) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path, *user; - if (!c || !room || !event) - { - return NULL; - } - - user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); - path = StrConcat(7, - "/_matrix/client/v3/rooms/", - room, "/event/", event, "?", - "user_id=", user - ); - - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(path); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - json = JsonDecode(HttpClientStream(ctx)); - - HttpClientContextFree(ctx); - Free(user); - - return json; -} - -void -ASRedact(const ParseeConfig *c, char *room, char *user, char *e_id) -{ - HttpClientContext *ctx = NULL; - HashMap *request; - char *path, *txn; - if (!c || !room || !e_id) - { - return; - } - - if (!user) - { - char *raw = StrConcat(4, - "@", c->sender_localpart, - ":", c->server_base - ); - user = HttpUrlEncode(raw); - Free(raw); - } - else - { - user = HttpUrlEncode(user); - } - room = HttpUrlEncode(room); - e_id = HttpUrlEncode(e_id); - txn = StrRandom(16); - - path = StrConcat(9, - "/_matrix/client/v3/rooms/", - room, "/redact/", e_id, "/", txn, - "?", "user_id=", user - ); - - request = HashMapCreate(); - ctx = ParseeCreateRequest(c, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, request); - JsonFree(request); - - HttpClientContextFree(ctx); - Free(user); - Free(room); - Free(e_id); - Free(txn); - - return; -} diff --git a/src/AS/Indicators.c b/src/AS/Indicators.c deleted file mode 100644 index 9797649..0000000 --- a/src/AS/Indicators.c +++ /dev/null @@ -1,120 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -void -ASType(const ParseeConfig *c, char *user, char *room, bool status) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!c || !user || !room) - { - return; - } - - user = HttpUrlEncode(user); - path = StrConcat(6, - "/_matrix/client/v3/rooms/", - room, "/typing/", user, - "?user_id=", user - ); - - json = HashMapCreate(); - HashMapSet(json, "typing", JsonValueBoolean(status)); - /* If someone types for 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); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(user); -} - -void -ASPresence(const ParseeConfig *c, char *user, char *room, char *ev) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!c || !user || !room || !ev) - { - return; - } - - user = HttpUrlEncode(user); - room = HttpUrlEncode(room); - ev = HttpUrlEncode(ev); - path = StrConcat(6, - "/_matrix/client/v3/rooms/", - room, "/receipt/m.read/", ev, - "?user_id=", user - ); - - json = HashMapCreate(); - ctx = ParseeCreateRequest(c, HTTP_POST, path); - Free(path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(user); - Free(room); - Free(ev); -} - -void -ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, char *msg) -{ - HttpClientContext *ctx = NULL; - HashMap *request; - char *path; - char *status_str = NULL; - if (!c || !user) - { - return; - } - - switch (status) - { - case USER_STATUS_ONLINE: status_str = "online"; break; - case USER_STATUS_OFFLINE: status_str = "offline"; break; - case USER_STATUS_UNAVAILABLE: status_str = "unavailable"; break; - default: return; - } - - user = HttpUrlEncode(user); - path = StrConcat(5, - "/_matrix/client/v3/presence/",user,"/status", - "?user_id=", user - ); - Free(user); - - request = HashMapCreate(); - HashMapSet(request, "presence", JsonValueString(status_str)); - if (msg) - { - HashMapSet(request, "status_msg", JsonValueString(msg)); - } - - ctx = ParseeCreateRequest(c, HTTP_PUT, path); - ASAuthenticateRequest(c, ctx); - ParseeSetRequestJSON(ctx, request); - JsonFree(request); - - HttpClientContextFree(ctx); - Free(path); -} diff --git a/src/AS/Media.c b/src/AS/Media.c deleted file mode 100644 index 5fbc659..0000000 --- a/src/AS/Media.c +++ /dev/null @@ -1,220 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include - -char * -ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) -{ - char *size_str, *path, *ret, *user; - unsigned int i; - HttpClientContext *ctx; - HashMap *reply; - if (!c || !from) - { - return NULL; - } - - size_str = StrInt(size); - user = StrConcat(4, "@",c->sender_localpart,":",c->server_base); - path = StrConcat(2, - "/_matrix/media/v3/upload?user_id=", user - ); - ctx = ParseeCreateRequest(c, HTTP_POST, path); - ASAuthenticateRequest(c, ctx); - if (size) - { - HttpRequestHeader(ctx, "Content-Length", size_str); - } - if (mime) - { - HttpRequestHeader(ctx, "Content-Type", mime); - } - HttpRequestSendHeaders(ctx); - - for (i = 0; i < size; i++) - { - int ch = StreamGetc(from); - if (ch == EOF) - { - break; - } - StreamPutc(HttpClientStream(ctx), ch); - } - HttpRequestSend(ctx); - reply = JsonDecode(HttpClientStream(ctx)); - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "content_uri")) - ); - if (!ret) - { - JsonEncode(reply, StreamStdout(), JSON_PRETTY); - StreamFlush(StreamStdout()); - } - HttpClientContextFree(ctx); - JsonFree(reply); - Free(size_str); - Free(path); - Free(user); - - return ret; -} -char * -ASReupload(const ParseeConfig *c, char *from, char **mime) -{ - Uri *uri; - HttpClientContext *ctx; - unsigned short port; - int size = 0, flags = HTTP_FLAG_NONE; - char *ret, *content_len; - - if (!c || !from) - { - return NULL; - } - - uri = UriParse(from); - if (!uri) - { - return NULL; - } - if (uri->port) - { - port = uri->port; - } - else if (StrEquals(uri->proto, "https")) - { - port = 443; - } - else - { - port = 80; - } - - if (StrEquals(uri->proto, "https")) - { - flags |= HTTP_FLAG_TLS; - } - - ctx = HttpRequest( - HTTP_GET, flags, port, uri->host, uri->path - ); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - if (mime) - { - *mime = HashMapGet(HttpResponseHeaders(ctx), "content-type"); - *mime = StrDuplicate(*mime); - } - - content_len = HashMapGet(HttpResponseHeaders(ctx), "content-length"); - if (content_len) - { - size = strtol(content_len, NULL, 10); - } - ret = ASUpload(c, HttpClientStream(ctx), size, mime ? *mime : NULL); - - HttpClientContextFree(ctx); - UriFree(uri); - return ret; -} - -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; - 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/client/v1/media/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((unsigned char *) 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; - 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/client/v1/media/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/Ping.c b/src/AS/Ping.c deleted file mode 100644 index 3a8ffb7..0000000 --- a/src/AS/Ping.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -bool -ASPing(const ParseeConfig *conf) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path; - bool ret; - if (!conf) - { - return false; - } - - path = StrConcat(3, - "/_matrix/client/v1/appservice/", - "Parsee%20XMPP", - "/ping" - ); - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - ASAuthenticateRequest(conf, ctx); - ret = ParseeSetRequestJSON(ctx, json) == HTTP_OK; - HttpClientContextFree(ctx); - JsonFree(json); - - return ret; -} diff --git a/src/AS/Profile.c b/src/AS/Profile.c deleted file mode 100644 index 1f1a0da..0000000 --- a/src/AS/Profile.c +++ /dev/null @@ -1,206 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -void -ASSetAvatar(const ParseeConfig *conf, char *user, char *mxc) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!conf || !user || !mxc) - { - return; - } - - user = HttpUrlEncode(user); - path = StrConcat(6, - "/_matrix/client/v3/profile/", - user, "/avatar_url", "?", - "user_id=", user - ); - - json = HashMapCreate(); - HashMapSet(json, "avatar_url", JsonValueString(mxc)); - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); - Free(user); -} -void -ASSetName(const ParseeConfig *conf, char *user, char *name) -{ - HttpClientContext *ctx = NULL; - HashMap *json; - char *path; - if (!conf || !user || !name) - { - return; - } - - user = HttpUrlEncode(user); - path = StrConcat(6, - "/_matrix/client/v3/profile/", - user, "/displayname", "?", - "user_id=", user - ); - - json = HashMapCreate(); - HashMapSet(json, "displayname", JsonValueString(name)); - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); - Free(user); -} - -char * -ASGetName(const ParseeConfig *c, char *room, char *user) -{ - HttpClientContext *ctx; - HashMap *reply; - char *path, *ret; - char *u2 = user; - if (!c || !user) - { - return NULL; - } - - if (!room) - { - user = HttpUrlEncode(user); - path = StrConcat(3, - "/_matrix/client/v3/profile/", user, "/displayname" - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(user); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "displayname")) - ); - HttpClientContextFree(ctx); - JsonFree(reply); - Free(path); - - if (!ret) - { - ret = StrDuplicate(u2); - } - return ret; - } - user = HttpUrlEncode(user); - room = HttpUrlEncode(room); - path = StrConcat(4, - "/_matrix/client/v3/rooms/", room, - "/state/m.room.member/", user - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(user); - Free(room); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "displayname")) - ); - HttpClientContextFree(ctx); - JsonFree(reply); - Free(path); - - if (!ret) - { - ret = StrDuplicate(u2); - } - return ret; -} -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")) - ); - 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/AS/Register.c b/src/AS/Register.c deleted file mode 100644 index cbb8881..0000000 --- a/src/AS/Register.c +++ /dev/null @@ -1,46 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -bool -ASRegisterUser(const ParseeConfig *conf, char *user) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - HttpStatus status; - if (!conf || !user) - { - return false; - } - - /* Create user. We don't actually care about the value as we can - * masquerade, as long as it exists. */ - ctx = ParseeCreateRequest( - conf, - HTTP_POST, "/_matrix/client/v3/register" - ); - json = HashMapCreate(); - - HashMapSet(json,"type",JsonValueString("m.login.application_service")); - - user = ParseeGetLocal(user); - HashMapSet(json,"username",JsonValueString(user)); - - ASAuthenticateRequest(conf, ctx); - status = ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); - - Free(user); - - return status == HTTP_OK; -} diff --git a/src/AS/Relations.c b/src/AS/Relations.c deleted file mode 100644 index e9baa5a..0000000 --- a/src/AS/Relations.c +++ /dev/null @@ -1,82 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -Array * -ASGetRelations(const ParseeConfig *c, size_t n, char *room, char *event, char *type) -{ - HttpClientContext *ctx = NULL; - Array *ret, *chunk; - HashMap *json = NULL; - char *path; - char *user; - size_t i; - if (!c || !n || !room || !event) - { - return NULL; - } - - user = StrConcat(4, "@", c->sender_localpart, ":", c->server_base); - if (type) - { - path = StrConcat(8, - "/_matrix/client/v1/rooms/", room, - "/relations/", event, "/", type, - "?user_id=", user - ); - } - else - { - path = StrConcat(6, - "/_matrix/client/v1/rooms/", room, - "/relations/", event, - "?user_id=", user - ); - } - Free(user); - - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(path); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - - json = JsonDecode(HttpClientStream(ctx)); - ret = ArrayCreate(); - chunk = GrabArray(json, 1, "chunk"); - for (i = 0; i < ArraySize(chunk); i++) - { - HashMap *obj = JsonValueAsObject(ArrayGet(chunk, i)); - ArrayAdd(ret, JsonDuplicate(obj)); - } - - HttpClientContextFree(ctx); - JsonFree(json); - return ret; -} - -void -ASFreeRelations(Array *relations) -{ - size_t i; - if (!relations) - { - return; - } - - for (i = 0; i < ArraySize(relations); i++) - { - JsonFree(ArrayGet(relations, i)); - } - - ArrayFree(relations); -} diff --git a/src/AS/Room.c b/src/AS/Room.c deleted file mode 100644 index e9691e1..0000000 --- a/src/AS/Room.c +++ /dev/null @@ -1,366 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -void -ASInvite(const ParseeConfig *conf, char *id, char *invited) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *bridge; - if (!conf || !id || !invited) - { - return; - } - - bridge = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/invite", - "?user_id=", bridge - ); - Free(bridge); - Free(id); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - HashMapSet(json, "user_id", JsonValueString(invited)); - HashMapSet(json, "reason", JsonValueString("Pass over.")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); -} -void -ASBan(const ParseeConfig *conf, char *id, char *banned) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *bridge; - if (!conf || !id || !banned) - { - return; - } - - bridge = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/ban", - "?user_id=", bridge - ); - Free(bridge); - Free(id); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString(NAME " felt jealous.")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); -} -void -ASKick(const ParseeConfig *conf, char *id, char *banned) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *bridge; - if (!conf || !id || !banned) - { - return; - } - - bridge = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/kick", - "?user_id=", bridge - ); - Free(bridge); - Free(id); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString(NAME " felt jealous.")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - HttpClientContextFree(ctx); - JsonFree(json); -} -char * -ASJoin(const ParseeConfig *conf, char *id, char *masquerade) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *ret, *serv; - int status; - if (!conf || !id) - { - return NULL; - } - - if (!masquerade) - { - char *raw = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - masquerade = HttpUrlEncode(raw); - Free(raw); - } - else - { - masquerade = HttpUrlEncode(masquerade); - } - serv = strchr(id, ':'); - if (serv) - { - serv = serv + 1; - } - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/join/", id, "?", - "user_id=", masquerade - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - ASAuthenticateRequest(conf, ctx); - status = ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - json = JsonDecode(HttpClientStream(ctx)); - ret = StrDuplicate(GrabString(json, 1, "room_id")); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(masquerade); - Free(id); - - (void) serv; // TODO - - return ret; -} -void -ASLeave(const ParseeConfig *conf, char *id, char *masquerade) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path; - if (!conf || !id) - { - return; - } - - if (!masquerade) - { - char *raw = StrConcat(4, - "@", conf->sender_localpart, - ":", conf->server_base - ); - masquerade = HttpUrlEncode(raw); - Free(raw); - } - else - { - masquerade = HttpUrlEncode(masquerade); - } - id = HttpUrlEncode(id); - path = StrConcat(5, - "/_matrix/client/v3/rooms/", id, "/leave?", - "user_id=", masquerade - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - JsonFree(json); - - HttpClientContextFree(ctx); - Free(masquerade); - Free(id); -} - -char * -ASCreateRoom(const ParseeConfig *conf, char *by, char *alias) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *id; - if (!conf || !by) - { - return NULL; - } - - path = StrConcat(3, - "/_matrix/client/v3/createRoom", - "?user_id=", by - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - if (alias) - { - char *trimmed = StrDuplicate(alias); - if (*alias == '#') - { - char *tmp, cb[2] = { 0 }; - alias++; - Free(trimmed); - trimmed = NULL; - - while (*alias && *alias != ':') - { - cb[0] = *alias; - tmp = trimmed; - trimmed = StrConcat(2, trimmed, cb); - Free(tmp); - alias ++; - } - } - HashMapSet(json, "room_alias_name", JsonValueString(trimmed)); - Free(trimmed); - } - HashMapSet(json, "visibility", JsonValueString("public")); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - JsonFree(json); - json = JsonDecode(HttpClientStream(ctx)); - id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); - HttpClientContextFree(ctx); - JsonFree(json); - - return id; -} -char * -ASCreateDM(const ParseeConfig *conf, char *by, char *with) -{ - HttpClientContext *ctx = NULL; - HashMap *json = NULL; - char *path, *id; - if (!conf || !by || !with) - { - return NULL; - } - - path = StrConcat(3, - "/_matrix/client/v3/createRoom", - "?user_id=", by - ); - - ctx = ParseeCreateRequest( - conf, - HTTP_POST, path - ); - Free(path); - json = HashMapCreate(); - { - Array *invitees = ArrayCreate(); - - ArrayAdd(invitees, JsonValueString(with)); - HashMapSet(json, "invite", JsonValueArray(invitees)); - HashMapSet(json, "is_direct", JsonValueBoolean(true)); - } - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, json); - - JsonFree(json); - json = JsonDecode(HttpClientStream(ctx)); - id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); - HttpClientContextFree(ctx); - JsonFree(json); - - return id; -} - -HashMap * -ASGetPL(const ParseeConfig *c, char *room) -{ - char *path; - HttpClientContext *ctx; - HashMap *reply; - if (!c || !room) - { - return NULL; - } - room = HttpUrlEncode(room); - path = StrConcat(4, - "/_matrix/client/v3/rooms/", room, - "/state/m.room.power_levels/", "" - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(room); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - HttpClientContextFree(ctx); - Free(path); - - return reply; -} -void -ASSetPL(const ParseeConfig *conf, char *id, HashMap *m) -{ - char *user; - if (!conf || !id || !m) - { - return; - } - user = StrConcat(4, - "@",conf->sender_localpart, - ":",conf->server_base - ); - ASSetState(conf, id, "m.room.power_levels", "", user, m); - Free(user); -} diff --git a/src/AS/Send.c b/src/AS/Send.c deleted file mode 100644 index 6811548..0000000 --- a/src/AS/Send.c +++ /dev/null @@ -1,79 +0,0 @@ -#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, uint64_t ts) -{ - HttpClientContext *ctx = NULL; - char *path; - char *txn, *ret; - char *ts_str; - HttpStatus status; - if (!ret) - { - Log(LOG_ERR, "%", ret); - } - HashMap *reply; - if (!conf || !id || !type || !user || !c) - { - JsonFree(c); - return NULL; - } - - if (!ts) - { - ts = UtilTsMillis(); - } - 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); - - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - status = ParseeSetRequestJSON(ctx, c); - - reply = JsonDecode(HttpClientStream(ctx)); - ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); - JsonFree(reply); - - HttpClientContextFree(ctx); - JsonFree(c); - - return ret; -} - diff --git a/src/AS/State.c b/src/AS/State.c deleted file mode 100644 index ef2ff14..0000000 --- a/src/AS/State.c +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -#include - -void -ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *state) -{ - HttpClientContext *ctx = NULL; - char *path; - if (!conf || !id || !type || !mask || !state) - { - JsonFree(state); - return; - } - - path = StrConcat(9, - "/_matrix/client/v3/rooms/", id, "/state/", - type, "/", key, "?", "user_id=", mask - ); - - ctx = ParseeCreateRequest(conf, HTTP_PUT, path); - Free(path); - ASAuthenticateRequest(conf, ctx); - ParseeSetRequestJSON(ctx, state); - - HttpClientContextFree(ctx); - JsonFree(state); -} - diff --git a/src/Command/Parser.c b/src/Command/Parser.c index 65f295b..6ff55d3 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 || (cmd > end_data)) + if (!end_data) { ret = Malloc(sizeof(*ret)); ret->command = StrDuplicate(cmd); @@ -49,11 +49,11 @@ CommandParse(char *cmd) char c = *cur; char *tmp; bool type; - char char_type = '\0'; + char char_type; switch (state) { case STATE_WHITE: - if (!isblank((int) c)) + if (!isblank(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((int) c))) + if ((type && c == char_type) || (!type && isblank(c))) { break; } diff --git a/src/Command/Router.c b/src/Command/Router.c index 0a09d28..d188640 100644 --- a/src/Command/Router.c +++ b/src/Command/Router.c @@ -15,47 +15,35 @@ CommandCreateRouter(void) void CommandAddCommand(CommandRouter *rter, char *c, CommandRoute rte) { - CommandRoute *indirect; if (!rter || !c || !rte) { return; } - - /* 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); + HashMapSet(rter->routes, c, rte); } void RouteCommand(CommandRouter *rter, Command *cmd, void *d) { - CommandRoute *route; + CommandRoute route; if (!rter || !cmd) { return; } route = HashMapGet(rter->routes, cmd->command); - if (route && *route) + if (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/BanUser.c b/src/Commands/BanUser.c index dd380ed..6e42356 100644 --- a/src/Commands/BanUser.c +++ b/src/Commands/BanUser.c @@ -22,28 +22,11 @@ CommandHead(CmdBanUser, cmd, argp) BotDestroy(); return; } - ASBan(data->config, room, user); - ReplySprintf("Banning %s from '%s'...", user, room); - 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); + ReplySprintf("Banning %s from '%s'...", + user, room + ); BotDestroy(); } diff --git a/src/Commands/Help.c b/src/Commands/Help.c index 0e25009..f60980c 100644 --- a/src/Commands/Help.c +++ b/src/Commands/Help.c @@ -25,6 +25,4 @@ 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 50d9d31..109c5d4 100644 --- a/src/Commands/ListBans.c +++ b/src/Commands/ListBans.c @@ -32,6 +32,4 @@ CommandHead(CmdListBans, cmd, argp) DbUnlock(data->db, listed); BotDestroy(); - - (void) cmd; } diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index f51e4e6..d7b3ba0 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -24,8 +24,7 @@ CommandHead(CmdPlumb, cmd, argp) BotRequired(room); /* Check MUC viability */ - if (ParseeManageBan(args->data, muc, NULL) || - !ParseeIsMUCWhitelisted(args->data, muc)) + if (ParseeManageBan(args->data, muc, NULL)) { ReplySprintf("MUC '%s' is not allowed on this bridge.", muc); goto end; @@ -63,7 +62,7 @@ CommandHead(CmdPlumb, cmd, argp) if (chat_id) { char *rev = StrConcat(2, muc, "/parsee"); - XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, -1, false); + XMPPJoinMUC(args->data->jabber, "parsee", rev); Free(rev); } diff --git a/src/Commands/Stats.c b/src/Commands/Stats.c index 0df0b44..1102f89 100644 --- a/src/Commands/Stats.c +++ b/src/Commands/Stats.c @@ -24,6 +24,7 @@ CommandHead(CmdStats, cmd, argp) BotInitialise(); + /* TODO: Separate these into different "categories" */ ReplySprintf("Information for %s v%s (Cytoplasm %s)", NAME, VERSION, CytoplasmGetVersionStr() ); @@ -40,6 +41,4 @@ CommandHead(CmdStats, cmd, argp) ReplyBasic("*Written with a shoelace and UHU glue by LDA <3 !*"); BotDestroy(); - - (void) cmd; } diff --git a/src/Commands/UnlinkMUC.c b/src/Commands/UnlinkMUC.c index 7f7cc50..3e2ae81 100644 --- a/src/Commands/UnlinkMUC.c +++ b/src/Commands/UnlinkMUC.c @@ -9,60 +9,43 @@ #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 *event = args->event; + HashMap *json, *event = args->event, *mucs; + DbRef *ref; char *muc = NULL, *chat_id = NULL, *room = NULL; BotInitialise(); - if (!Grab(data, cmd, &muc, &chat_id, &room)) + muc = HashMapGet(cmd->arguments, "muc"); + if (!muc) { - ReplyBasic("`muc`|`room` REQUIRED"); + ReplyBasic("`muc` field REQUIRED."); goto end; } - chat_id = ParseeGetFromMUCID(data, muc); - room = ParseeGetRoomID(data, chat_id); + ref = DbLock(data->db, 1, "chats"); + json = DbJson(ref); + chat_id = StrDuplicate(GrabString(json, 2, "mucs", muc)); 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); - ParseeUnlinkRoom(data, chat_id); + 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); /* TODO: Do it automatically, if *not plumbed* */ ReplySprintf("The MUC %s is now *unlinked*.", muc); diff --git a/src/Events.c b/src/Events.c index e9edf12..2a3f5b3 100644 --- a/src/Events.c +++ b/src/Events.c @@ -37,10 +37,12 @@ MatrixCreateMessage(char *body) HashMapSet(map, "msgtype", JsonValueString("m.text")); HashMapSet(map, "body", JsonValueString(body)); { + /* TODO */ XEP393Element *e = XEP393(body); text = XEP393ToXMLString(e); XEP393FreeElement(e); + HashMapSet(map, "formatted_body", JsonValueString(text)); HashMapSet(map, "format", JsonValueString("org.matrix.custom.html")); Free(text); @@ -79,7 +81,7 @@ MatrixCreateNickChange(char *nick) return map; } HashMap * -MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info) +MatrixCreateMedia(char *mxc, char *body, char *mime) { HashMap *map; char *mime_type = NULL, *matrix_type = NULL; @@ -91,10 +93,9 @@ MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info) matrix_type = "m.file"; if (mime) { - size_t i, len; + size_t i; mime_type = StrDuplicate(mime); - len = strlen(mime); - for (i = 0; i < len; i++) + for (i = 0; i < strlen(mime); i++) { if (mime_type[i] == '/') { @@ -120,12 +121,6 @@ MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info) } 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)); @@ -187,18 +182,6 @@ MatrixCreateReplace(char *event, char *body) HashMapSet(map, "m.new_content", JsonValueObject(new)); HashMapSet(map, "m.relates_to", JsonValueObject(rel)); - { - XEP393Element *e = XEP393(body); - char *text = XEP393ToXMLString(e); - XEP393FreeElement(e); - - HashMapSet(map, "formatted_body", JsonValueString(text)); - HashMapSet(map, "format", JsonValueString("org.matrix.custom.html")); - HashMapSet(new, "formatted_body", JsonValueString(text)); - HashMapSet(new, "format", JsonValueString("org.matrix.custom.html")); - Free(text); - } - return map; } HashMap * diff --git a/src/FileInfo.c b/src/FileInfo.c deleted file mode 100644 index 17974d0..0000000 --- a/src/FileInfo.c +++ /dev/null @@ -1,68 +0,0 @@ -#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" - ); - /* TODO: We'll definitely need MIME types to do things like - * WebXDC */ - 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/Glob.c b/src/Glob.c index 02765dd..805f5a6 100644 --- a/src/Glob.c +++ b/src/Glob.c @@ -19,6 +19,7 @@ GlobMatches(char *rule, char *string) switch (c1) { case '*': + /* TODO */ while ((c2 = *string) && (c2 != next)) { string++; diff --git a/src/HttParsee.c b/src/HttParsee.c index 572487c..d6fd86b 100644 --- a/src/HttParsee.c +++ b/src/HttParsee.c @@ -29,18 +29,19 @@ ParseeRequest(HttpServerContext *ctx, void *argp) arg.stream = stream; - Log(LOG_DEBUG, "%s %s", + Log(LOG_NOTICE, "%s %s", HttpRequestMethodToString(HttpRequestMethodGet(ctx)), path ); if (!HttpRouterRoute(data->router, path, &arg, (void **) &response)) { - Log(LOG_DEBUG, "Couldn't route %s", path); + Log(LOG_NOTICE, "Couldn't route %s", path); HttpResponseStatus(ctx, HTTP_NOT_FOUND); JsonFree(response); response = MatrixCreateError("M_NOT_FOUND", "Route not found."); + /* TODO: Set a thing */ } /* Whatever, we routed a thing. */ @@ -55,11 +56,8 @@ ParseeRequest(HttpServerContext *ctx, void *argp) HttpSendHeaders(ctx); JsonEncode(response, stream, JSON_DEFAULT); JsonFree(response); + return; } - Log(LOG_DEBUG, "%s %s (%d)", - HttpRequestMethodToString(HttpRequestMethodGet(ctx)), - path, HttpResponseStatusGet(ctx) - ); } HttpClientContext * @@ -73,7 +71,7 @@ ParseeCreateRequest(const ParseeConfig *conf, HttpRequestMethod meth, char *path ctx = HttpRequest( meth, - conf->homeserver_tls ? HTTP_FLAG_TLS : HTTP_FLAG_NONE, + HTTP_FLAG_TLS, conf->homeserver_port, conf->homeserver_host, path ); diff --git a/src/Main.c b/src/Main.c index 10c809f..226a9e4 100644 --- a/src/Main.c +++ b/src/Main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -13,7 +12,6 @@ #include #include -#include #include #include #include @@ -29,79 +27,6 @@ ParseeUptime(void) return UtilTsMillis() - start; } -static const Argument arguments[] = -{ -#define Arg(c, req, vdesc, desc) \ - { \ - .end = false, \ - .argument = c, .value_req = req, \ - .value_descr = vdesc, \ - .description = desc \ - }, -#define EndOfArgs { .end = true } - - Arg('H', true, "number(=8)", "Sets the number of HTTP threads") - Arg('J', true, "number(=8)", "Sets the number of XMPP threads") - Arg('C', true, "file(='parsee.json')", "Sets the JSON config to use") - - Arg('g', false, NULL, - "Generates a parsee.yaml AS file before exiting") - Arg('v', false, NULL, - "Forces Parsee to print in a more verbose fashion " - "(-vvv prints stanzas to stderr)") - Arg('h', false, NULL, - "Generates an help screen(this one!)") - - EndOfArgs - -#undef EndOfArgs -#undef Argument -}; - -void -ParseeCheckMatrix(void *datp) -{ - static volatile uint64_t streak = 0; - ParseeData *data = datp; - if (data->config->accept_pings && !ASPing(data->config)) - { - Log(LOG_ERR, "Cannot reach '%s' properly...", data->config->homeserver_host); - if (++streak == 10) - { - DbRef *ref = DbLockIntent(data->db, DB_HINT_READONLY, 1, "chats"); - HashMap *json = DbJson(ref); - HashMap *mucs = GrabObject(json, 1, "mucs"); - char *muc; - void *ignored; - - - /* 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; - } - streak = 0; -} - int Main(Array *args, HashMap *env) { @@ -110,11 +35,6 @@ Main(Array *args, HashMap *env) Stream *yaml; Cron *cron = NULL; - char *configuration = "parsee.json"; - int xmpp = 8; - int http = 8; - int verbose = 0; - start = UtilTsMillis(); memset(&conf, 0, sizeof(conf)); @@ -122,32 +42,24 @@ Main(Array *args, HashMap *env) "%s - v%s[%s] (Cytoplasm %s)", NAME, VERSION, CODE, CytoplasmGetVersionStr() ); - ParseePrintASCII(); Log(LOG_INFO, "======================="); - Log(LOG_INFO, "(C)opyright 2024-2025 LDA and other contributors"); - 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()); + ParseeConfigLoad("parsee.json"); + ParseeConfigInit(); + parsee_conf = ParseeConfigGet(); + { ArgParseState state; - char *opts = ParseeGenerateGetopt(arguments); int flag; + int xmpp = 8; + int http = 8; + ArgParseStateInit(&state); - while ((flag = ArgParse(&state, args, opts)) != -1) + while ((flag = ArgParse(&state, args, "gH:J:")) != -1) { switch (flag) { - case 'h': - ParseeGenerateHelp(arguments); - Free(opts); - goto end; case 'H': http = strtol(state.optArg, NULL, 10); break; @@ -158,155 +70,46 @@ 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); - goto end; - case 'v': - switch (++verbose) - { - 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; - case PARSEE_VERBOSE_COMICAL: - Log(LOG_DEBUG, "What?"); - Log(LOG_DEBUG, "No, but like, what do you except?"); - Log(LOG_DEBUG, "Like do you want to log _every_ instruction?"); - Log(LOG_DEBUG, "Like just every single thing %s does?", NAME); - Log(LOG_DEBUG, " ( why??? )"); - Log(LOG_DEBUG, "....................................."); - Log(LOG_DEBUG, "Argh."); - Log(LOG_DEBUG, "Alright. I'll do my best."); - Log(LOG_DEBUG, "Get what you paid for."); - break; - } - break; - case 'C': - if (!UtilLastModified(state.optArg)) - { - Log(LOG_ERR, "Invalid config: %s", state.optArg); - Log(LOG_ERR, "Ignoring."); - break; - } - configuration = state.optArg; - break; - case '?': - Log(LOG_ERR, "INVALID ARGUMENT GIVEN"); - Free(opts); goto end; } } - Free(opts); + ParseeSetThreads(xmpp, http); } - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Loading configuration..."); - } - ParseeConfigLoad(configuration); - ParseeConfigInit(); - parsee_conf = ParseeConfigGet(); - if (!parsee_conf) - { - goto end; - } - ParseeSetThreads(xmpp, http); - - 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 )) { Log(LOG_ERR, "Could not connect to XMPP..."); - - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Destroying component..."); - } XMPPEndCompStream(jabber); goto end; } Log(LOG_NOTICE, "Creating volatile tables..."); - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Initialising JID table"); - } ParseeInitialiseJIDTable(); - - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Initialising OID table"); - } ParseeInitialiseOIDTable(); - - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Initialising head table"); - } ParseeInitialiseHeadTable(); - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Initialising nick table"); - } - ParseeInitialiseNickTable(); - - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Initialising affiliation table"); - } - ParseeInitialiseAffiliationTable(); + Log(LOG_NOTICE, "Setting up local Matrix user..."); + ASRegisterUser(parsee_conf, parsee_conf->sender_localpart); conf.port = parsee_conf->port; conf.threads = parsee_conf->http_threads; conf.maxConnections = conf.threads << 2; conf.handlerArgs = ParseeInitData(jabber); conf.handler = ParseeRequest; - if (!conf.handlerArgs) - { - goto end; - } - - Log(LOG_DEBUG, "Verbosity level: %d", verbose); - ((ParseeData *) conf.handlerArgs)->verbosity = verbose; - - Log(LOG_NOTICE, "Setting up local Matrix user..."); - if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart)) - { - char *parsee = ParseeMXID(conf.handlerArgs); - - ASSetAvatar(parsee_conf, - parsee, - "mxc://tedomum.net/" - "7e228734ec8e792960bb5633e43f0cb845f709f61825130490034651136" - ); - ASSetName(parsee_conf, parsee, "Parsee bridge"); - - Free(parsee); - } 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); + cron = CronCreate( 10 SECONDS ); + CronEvery(cron, 5 MINUTES, ParseeCleanup, conf.handlerArgs); CronStart(cron); @@ -318,9 +121,8 @@ Main(Array *args, HashMap *env) } server = HttpServerCreate(&conf); - ((ParseeData *) conf.handlerArgs)->server = server; - if (!ParseeInitialiseSignals(conf.handlerArgs, xmpp_thr)) + if (!ParseeInitialiseSignals(server, xmpp_thr, jabber)) { goto end; } @@ -344,12 +146,8 @@ end: CronStop(cron); CronFree(cron); ParseeFreeData(conf.handlerArgs); - ParseeDestroyAffiliationTable(); - ParseeDestroyNickTable(); ParseeDestroyOIDTable(); ParseeDestroyHeadTable(); ParseeDestroyJIDTable(); - - (void) env; return 0; } diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 6311fac..ce24854 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -8,56 +8,9 @@ #include #include -#include #include #include -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, char *hash) -{ - char *sender = GrabString(event, 1, "sender"); - - Unistr *uninick = UnistrCreate(name); - 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; - - UnistrFree(uninick); - UnistrFree(filtered); - - /* 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); - - if (strlen(hex) >= 8) - { - hex[8] = '\0'; - } - - Free(nick); - Free(rev); - - nick = StrConcat(4, name, "[", hex, "]"); - rev = StrConcat(3, muc, "/", nick); - nonce++; - - Free(nonce_str); - Free(input); - Free(hex); - } - - ParseePushNickTable(muc, sender, nick); - Free(nick); - return (rev); -} - static void ParseeMemberHandler(ParseeData *data, HashMap *event) { @@ -98,95 +51,20 @@ 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, NULL, state_key); - char *url = ParseeToUnauth(data, avatar, NULL); 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 *jabber = JoinMUC(data, event, jid, muc, name, sha); - avatar = ASGetAvatar(data->config, NULL, state_key); - Log(LOG_DEBUG, "MATRIX: Joining as '%s' (avatar=%s)", jabber, avatar); + char *rev = StrConcat(2, muc, "/parsee"); - Free(jabber); - Free(avatar); - Free(name); + XMPPJoinMUC(data->jabber, jid, rev); + Free(rev); Free(muc); - avatar = NULL; /* TODO: XEP-0084 magic to advertise a new avatar if possible. */ } - else - { - 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)", jid, state_key); - - elem = XMLCreateTag("message"); - { -#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); - - 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(chat_id); - Free(avatar); - Free(mime); - Free(sha); Free(jid); - Free(url); + Free(chat_id); } else if ((StrEquals(membership, "leave") || StrEquals(membership, "ban")) @@ -204,29 +82,14 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) { - /* If it can't be found, try to see if it's as a DM */ - char *info_from = NULL, *info_to = NULL; - const char *type = GetXMPPInformation(data, event, &info_from, &info_to); - - if (StrEquals(type, "chat")) - { - char *jid_to = ParseeTrimJID(info_to); - Log(LOG_DEBUG, "('%s'->'%s') is gone.", state_key, info_to); - /* TODO: Send a last DM, signifying that all is gone. */ - ParseeDeleteDM(data, state_key, jid_to); - Free(jid_to); - } - - Free(info_from); - Free(info_to); goto end; } - name = StrDuplicate(ParseeLookupNick(muc_id, sender)); - rev = StrConcat(3, muc_id, "/", name); + /* TODO: Check the name's validity */ + name = ASGetName(data->config, room_id, state_key); + rev = StrConcat(4, muc_id, "/", name, "[p]"); XMPPLeaveMUC(jabber, jid, rev, reason); - ParseePushNickTable(muc_id, sender, NULL); end: Free(chat_id); Free(muc_id); @@ -255,9 +118,14 @@ ParseeBotHandler(ParseeData *data, HashMap *event) return; } - if (!body || *body != '!') + 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") + )); Free(profile); return; } @@ -267,7 +135,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) Free(ASSend( data->config, id, profile, "m.room.message", - MatrixCreateNotice("You are not authorised to do this."), 0 + MatrixCreateNotice("You are not authorised to do this.") )); Free(profile); return; @@ -289,10 +157,12 @@ 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 = NULL; + char *user; - DbRef *room_data = NULL; - HashMap *data_json = NULL; + DbRef *room_data; + HashMap *data_json; + + XMPPComponent *jabber = data ? data->jabber : NULL; bool direct = false; if (!data || !event || !from || !to) @@ -324,8 +194,7 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } else { - char *matrix_name = NULL, *matrix_avatar = NULL; - char *mime = NULL, *sha = NULL; + char *matrix_name, *muc_join_as; muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -339,16 +208,18 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } matrix_name = ASGetName(data->config, room_id, matrix_sender); - matrix_avatar = ASGetAvatar(data->config, NULL, matrix_sender); + muc_join_as = StrConcat(4, muc_id, "/", matrix_name, "[p]"); + + /* TODO: Manage name conflicts. That would have been an easy + * task(try the original one, and use a counter if it fails), + * but that'd involve modifying the rest of the code, which + * I'm not doing at 01:39 ... */ + XMPPJoinMUC(jabber, *from, muc_join_as); - 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(muc_join_as); } Free(chat_id); @@ -358,47 +229,27 @@ 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; + StanzaBuilder *builder; DbRef *ref = NULL; - HashMap *json = NULL; + HashMap *json; - 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"); char *id = GrabString(event, 1, "room_id"); char *ev_id = GrabString(event, 1, "event_id"); - char *chat_id = NULL, *muc_id = NULL; + char *m_sender = GrabString(event, 1, "sender"); + char *chat_id, *muc_id; char *reply_id = MatrixGetReply(event); - char *xepd = ParseeXMPPify(data, event); + char *xepd = ParseeXMPPify(event); char *type, *user, *xmppified_user = NULL, *to = NULL; 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; - unedited_id = MatrixGetEdit(event); - if (unedited_id) - { - char *new_content = GrabString(event, 3, "content", "m.new_content", "body"); - 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)) { @@ -410,6 +261,9 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) chat_id = ParseeGetFromRoomID(data, id); + /* TODO: This ref should be marked as read-only, + * as LMDB doesn't seem to like having two concurrent RW + * transactions running. */ ref = DbLockIntent(data->db, DB_HINT_READONLY, 3, "rooms", id, "data"); json = DbJson(ref); direct = JsonValueAsBoolean(HashMapGet(json, "is_direct")); @@ -429,44 +283,38 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) type = direct ? "chat" : "groupchat"; user = GrabString(json, 1, "xmpp_user"); - unauth = ParseeToUnauth(data, url, GrabString(event, 2, "content", "filename")); - - encoded_from = ParseeEncodeMXID(m_sender); - xmppified_user = StrConcat(3, - encoded_from, "@", jabber->host - ); + unauth = ParseeToUnauth(data, url); if (direct) { + xmppified_user = ParseeEncodeMXID(m_sender); to = StrDuplicate(user); Free(chat_id); } else { - char *name, *mime = NULL, *sha = NULL; - char *avatar; + char *name, *rev; /* Try to find the chat ID */ muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) { goto end; } + xmppified_user = ParseeEncodeMXID(m_sender); - /* TODO: Avoid using the AS endpoints */ + /* 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); - avatar = ASGetAvatar(data->config, NULL, m_sender); - ASGetMIMESHA(data->config, avatar, &mime, &sha); + rev = StrConcat(4, muc_id, "/", name, "[p]"); - Free(JoinMUC(data, event, encoded_from, muc_id, name, sha)); + XMPPJoinMUC(jabber, xmppified_user, rev); to = muc_id; - Free(sha); - Free(mime); Free(name); - Free(avatar); + Free(rev); } - if (reply_id) { /* TODO: Monocles chat DM users HATE this trick! @@ -494,13 +342,13 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *xmpp_ident = StrRandom(32); builder = CreateStanzaBuilder(xmppified_user, to, xmpp_ident); SetStanzaType(builder, type); - SetStanzaBody(builder, unauth ? unauth : (xepd ? xepd : body)); + SetStanzaBody(builder, xepd ? xepd : body); SetStanzaReply(builder, stanza, sender); SetStanzaLink(builder, unauth); SetStanzaEdit(builder, origin_id); SetStanzaXParsee(builder, event); - WriteoutStanza(builder, jabber, data->config->max_stanza_size); + WriteoutStanza(builder, jabber); DestroyStanzaBuilder(builder); if (direct) @@ -523,7 +371,6 @@ end: Free(stanza); Free(sender); Free(unauth); - Free(encoded_from); Free(unedited_id); DbUnlock(data->db, ref); @@ -555,7 +402,8 @@ ParseeEventHandler(ParseeData *data, HashMap *event) return; } else if (StrEquals(event_type, "m.room.message") || - StrEquals(event_type, "m.sticker")) + StrEquals(event_type, "m.sticker")) /* TODO: Actual sticker + * support here... */ { ParseeMessageHandler(data, event); Free(parsee); diff --git a/src/MatrixID.c b/src/MatrixID.c deleted file mode 100644 index bb7c584..0000000 --- a/src/MatrixID.c +++ /dev/null @@ -1,68 +0,0 @@ -#include - -#include -#include -#include -#include - -#include - -UserID * -MatrixParseID(char *user) -{ - UserID *ret = NULL; - char *localstart, *serverstart; - if (!user || *user != '@') - { - return NULL; - } - - localstart = user + 1; - serverstart = strchr(user, ':'); - if (!*localstart || !serverstart || localstart == serverstart) - { - return NULL; - } - if (!*++serverstart) - { - return NULL; - } - - ret = Malloc(sizeof(*ret)); - memset(ret, '\0', sizeof(*ret)); - memcpy(ret->localpart, localstart, serverstart - localstart - 1); - memcpy(ret->server, serverstart, strlen(serverstart)); - - 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/Config.c b/src/Parsee/Config.c index b95e5e1..4bad59f 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -11,15 +11,210 @@ static ParseeConfig *config = NULL; +static char * +GetLine(void) +{ + Stream *input = StreamStdin(); + char *out = NULL; + size_t length; + UtilGetLine(&out, &length, input); + + if (out) + { + char *line = strchr(out, '\n'); + if (line) + { + *line = '\0'; + } + } + + return out; +} + +#include +static char * +PromptString(const char *expression, const char *def, ...) +{ + Stream *output = StreamStdout(); + char *out = NULL; + va_list ap; + + while (!out) + { + va_start(ap, def); + + StreamVprintf(output, expression, ap); + if (def) + { + StreamPrintf(output, " [%s]", def); + } + StreamPrintf(output, ": "); + StreamFlush(output); + + va_end(ap); + + out = GetLine(); + if (!*out) + { + Free(out); + out = NULL; + if (def) + { + return StrDuplicate(def); + } + } + Log(LOG_INFO, "R=%s", out); + } + + return out; +} +static int +PromptInteger(const char *expression, int def, ...) +{ + Stream *output = StreamStdout(); + char *out; + long l; + va_list ap; + + va_start(ap, def); + + StreamVprintf(output, expression, ap); + if (def >= 0) + { + StreamPrintf(output, " [%d]", def); + } + StreamPrintf(output, ": "); + StreamFlush(output); + + va_end(ap); + while (true) + { + char *inval; + out = GetLine(); + l = strtol(out, &inval, 10); + Free(out); + + /* Not a use-after-free, as we reference only the addresses. */ + if (l != 0 || inval != out) + { + break; + } + + if (def >= 0) + { + return def; + } + } + + return l; +} + +/* TODO: Memleaks, galore! */ void ParseeConfigInit(void) { + Stream *stream; + HashMap *json; if (config) { return; } - Log(LOG_ERR, "No config file found."); - Log(LOG_ERR, "Please use parsee-config to initialise %s.", NAME); + + /* TODO: Give the user an achievement at the end, just because they're + * cool. */ + Log(LOG_NOTICE, "It seems like it is the first time you have configured "); + Log(LOG_NOTICE, "Parsee."); + Log(LOG_NOTICE, "As such, I need to ask you a couple of questions before "); + Log(LOG_NOTICE, "being able to use it."); + Log(LOG_NOTICE, "(don't worry; it won't take too long.)"); + Log(LOG_NOTICE, ""); + Log(LOG_NOTICE, ""); + + config = Malloc(sizeof(*config)); + config->as_token = StrRandom(32); + config->hs_token = StrRandom(32); + config->http_threads = 8; + config->xmpp_threads = 8; + config->db_size = 64 MB; + + /* TODO: This is NOT user friendly, and I know it! */ + config->sender_localpart = PromptString( + "Name of the bridge bot, used for commands and bridged rooms", + "_parsee_bridge" + ); + config->namespace_base = PromptString( + "Base namespace for Parsee (so foo@bar.com => @[NS]_foo=40bar.com)", + "_jabber" + ); + + config->listen_as = StrDuplicate("localhost"); + config->port = PromptInteger( + "Matrix port for the AS service to use", + 7642 /* proposed by Saint */ + ); + + + config->component_host = PromptString( + "XMPP component to be used for the configuration", + NULL + ); + config->component_port = PromptInteger( + "XMPP port for to use for '%s'", + 5347, config->component_host + ); + config->shared_comp_secret = PromptString( + "%s's shared secret", + NULL, config->component_host + ); + + config->homeserver_host = PromptString( + "Delegated homeserver to be used for the configuration", + NULL + ); + config->homeserver_port = PromptInteger( + "HTTP port for to use for '%s'", + 443, config->homeserver_host + ); + + config->db_path = PromptString( + "Base directory for Parsee data", + NULL + ); + config->media_base = PromptString( + "Base media URL for bridged media", + NULL + ); + + /* TODO: Make that configurable. */ + config->server_base = StrDuplicate(config->homeserver_host); + + Log(LOG_NOTICE, "Done! Please look over to the parsee.yaml file, "); + Log(LOG_NOTICE, "and follow the instructions listed in it. Then, "); + Log(LOG_NOTICE, "restart Parsee. "); + Log(LOG_NOTICE, "------------------------------------------------"); + + stream = StreamOpen("parsee.json", "w"); + json = HashMapCreate(); + HashMapSet(json, "as_token", JsonValueString(config->as_token)); + HashMapSet(json, "hs_token", JsonValueString(config->hs_token)); + + HashMapSet(json, "sender", JsonValueString(config->sender_localpart)); + HashMapSet(json, "namespace", JsonValueString(config->namespace_base)); + HashMapSet(json, "listen_as", JsonValueString(config->listen_as)); + HashMapSet(json, "port", JsonValueInteger(config->port)); + + HashMapSet(json, "hs_base", JsonValueString(config->server_base)); + HashMapSet(json, "hs_host", JsonValueString(config->homeserver_host)); + HashMapSet(json, "hs_port", JsonValueInteger(config->homeserver_port)); + + HashMapSet(json, "component_host", JsonValueString(config->component_host)); + HashMapSet(json, "component_port", JsonValueInteger(config->component_port)); + HashMapSet(json, "shared_comp_secret", JsonValueString(config->shared_comp_secret)); + HashMapSet(json, "db", JsonValueString(config->db_path)); + + JsonEncode(json, stream, JSON_PRETTY); + JsonFree(json); + StreamClose(stream); } void ParseeConfigLoad(char *conf) @@ -30,18 +225,12 @@ ParseeConfigLoad(char *conf) { return; } - stream = StreamOpen(conf ? conf : "parsee.json", "r"); + stream = StreamOpen("parsee.json", "r"); if (!stream) { 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( \ @@ -50,9 +239,6 @@ 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; @@ -67,25 +253,10 @@ 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; - } - CopyToBool(accept_pings, "accept_pings"); 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"); - if (!config->max_stanza_size) - { - /* Standard XMPP "minimum" maximum */ - config->max_stanza_size = 10000; - } - - CopyToBool(ignore_bots, "ignore_bots"); CopyToStr(media_base, "media_base"); @@ -101,7 +272,6 @@ ParseeSetThreads(int xmpp, int http) { if (!config) { - Achievement("THREAD COUNT REQUEST WITHOUT CONFIG", true); return; } config->http_threads = http; @@ -113,7 +283,6 @@ ParseeExportConfigYAML(Stream *stream) { if (!stream || !config) { - Achievement("YAML EXPORT REQUEST WITHOUT CONFIG", true); return; } StreamPrintf(stream, "# Autogenerated YAML AS entry for %s\n", NAME); @@ -127,7 +296,6 @@ 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"); @@ -136,7 +304,6 @@ ParseeExportConfigYAML(Stream *stream) StreamPrintf(stream, " aliases:\n"); StreamPrintf(stream, " - exclusive: true\n"); StreamPrintf(stream, " regex: \"#%s_.*\"\n", config->namespace_base); - StreamFlush(stream); } void @@ -147,7 +314,6 @@ 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/Data.c b/src/Parsee/Data.c index 46d1433..e92e3e4 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -6,18 +6,17 @@ #include #include -#include #include +#include #include +#include #include ParseeData * ParseeInitData(XMPPComponent *comp) { - char *version; ParseeData *data; - DbRef *ref; if (!ParseeConfigGet()) { return NULL; @@ -27,15 +26,8 @@ ParseeInitData(XMPPComponent *comp) data->config = ParseeConfigGet(); data->router = HttpRouterCreate(); data->jabber = comp; - data->muc = CreateMUCServer(data); data->handler = CommandCreateRouter(); - 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); @@ -43,47 +35,10 @@ ParseeInitData(XMPPComponent *comp) if (!data->db) { Log(LOG_WARNING, "LMDB doesn't seem to be setup."); - if (data->config->db_size) - { - Log(LOG_WARNING, "Falling back to flat-file."); - } + Log(LOG_WARNING, "Falling back to flat-file."); data->db = DbOpen(data->config->db_path, 0); } - if (!(ref = DbLock(data->db, 1, "info"))) - { - char *id = StrRandom(64); - ref = DbCreate(data->db, 1, "info"); - HashMapSet(DbJson(ref), "identifier", JsonValueString(id)); - HashMapSet(DbJson(ref), "version", JsonValueString(VERSION)); - Free(id); - } - - version = GrabString(DbJson(ref), 1, "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."); - Log(LOG_WARNING, "(Parsee still needs an upgradepath mechanism.)"); - - DbUnlock(data->db, ref); - DbClose(data->db); - - HashMapFree(data->oid_servers); - pthread_mutex_destroy(&data->oidl); - - XMPPEndCompStream(data->jabber); - - HttpRouterFree(data->router); - CommandFreeRouter(data->handler); - - Free(data); - return NULL; - } - - data->id = StrDuplicate(GrabString(DbJson(ref), 1, "identifier")); - DbUnlock(data->db, ref); - #define X_ROUTE(path, func) do {\ if (!HttpRouterAdd(data->router, path, func))\ {\ @@ -101,23 +56,12 @@ ParseeInitData(XMPPComponent *comp) void ParseeFreeData(ParseeData *data) { - char *entity; - XMLElement *disco; if (!data) { return; } - while (HashMapIterate(data->oid_servers, &entity, (void **) &disco)) - { - XMLFreeElement(disco); - } - HashMapFree(data->oid_servers); - pthread_mutex_destroy(&data->oidl); - pthread_mutex_destroy(&data->halt_lock); - Free(data->id); XMPPEndCompStream(data->jabber); - FreeMUCServer(data->muc); DbClose(data->db); HttpRouterFree(data->router); CommandFreeRouter(data->handler); @@ -133,6 +77,8 @@ ParseeCleanup(void *datp) size_t i; uint64_t ts = UtilTsMillis(); + Log(LOG_NOTICE, "Cleaning up..."); + chats = DbList(data->db, 1, "chats"); for (i = 0; i < ArraySize(chats); i++) @@ -182,12 +128,9 @@ ParseeCleanup(void *datp) } \ while (0) - /* TODO: Custom retention period for any 1.0 */ - CleanupField(stanza, 30 MINUTES, 500); - CleanupField(event, 30 MINUTES, 500); - CleanupField(id, 30 MINUTES, 500); - - /* TODO: Also cleanup user cache information */ + CleanupField(stanza, 30 MINUTES, 50); + CleanupField(event, 30 MINUTES, 50); + CleanupField(id, 30 MINUTES, 50); #undef CleanupField } DbListFree(chats); @@ -238,15 +181,252 @@ ParseeCleanup(void *datp) } \ while (0) - CleanupField(stanza, 3 HOURS, 500); - CleanupField(event, 3 HOURS, 500); - CleanupField(id, 3 HOURS, 500); + CleanupField(stanza, 3 HOURS, 50); + CleanupField(event, 3 HOURS, 50); + CleanupField(id, 3 HOURS, 50); DbUnlock(data->db, ref); } DbListFree(chats); } +int +ParseeFindDatastart(char *data) +{ + char *startline; + bool found = false; + if (!data) + { + return 0; + } + startline = data; + while (startline) + { + char *endline = strchr(startline, '\n'); + + if (*startline != '>') + { + found = true; + break; + } + + startline = endline ? endline + 1 : NULL; + } + + if (!found) + { + return 0; + } + + return (int) (startline - data); +} + +#include +typedef struct XMPPFlags { + bool quote; +} XMPPFlags; +static char * +XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) +{ + char *xepd = NULL, *tmp = NULL; + + size_t i; + XMLElement *child; + char *reply_id = JsonValueAsString( + JsonGet(event, 4, + "content", "m.relates_to", "m.in_reply_to", "event_id" + )); + char *room_id = JsonValueAsString(HashMapGet(event, "room_id")); + HashMap *referenced; + char *subxep; +#define Concat(strp) do \ + { \ + size_t cidx; \ + size_t len = strp ? strlen(strp) : 0; \ + for (cidx = 0; cidx < len; cidx++) \ + { \ + char cch[2] = { strp[cidx], 0 }; \ + char nch = *cch ? strp[cidx+1] : '\0'; \ + bool c = *cch == '\n' && nch != '>'; \ + if (c && flags.quote) \ + { \ + tmp = xepd; \ + xepd = StrConcat(2, xepd, "\n>"); \ + Free(tmp); \ + continue; \ + } \ + tmp = xepd; \ + xepd = StrConcat(2, xepd, cch); \ + Free(tmp); \ + } \ + } \ + while (0) + switch (elem->type) + { + case XML_ELEMENT_DATA: + Concat(elem->data); + break; + case XML_ELEMENT_TAG: + if (StrEquals(elem->name, "b") || StrEquals(elem->name, "strong")) + { + Concat("*"); + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + Concat("*"); + } + else if (StrEquals(elem->name, "em")) + { + Concat("_"); + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + Concat("_"); + } + else if (StrEquals(elem->name, "code")) + { + Concat("`"); + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + Concat("`"); + } + else if (StrEquals(elem->name, "mx-reply")) + { + char *str; + referenced = ASFind(ParseeConfigGet(), room_id, reply_id); + str = JsonValueAsString( + JsonGet(referenced, 2, "content", "body") + ); + if (!str) + { + JsonFree(referenced); + return xepd; + } + Concat(">"); + flags.quote = true; + Concat(str); + flags.quote = false; + Concat("\n"); + JsonFree(referenced); + } + else if (StrEquals(elem->name, "blockquote")) + { + Concat(">"); + flags.quote = true; + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + flags.quote = false; + Concat("\n"); + } + else if (StrEquals(elem->name, "br")) + { + Concat("\n"); + /* HTML fucking SUCKS */ + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + Concat("\n"); + } + else if (StrEquals(elem->name, "a")) + { + char *href = HashMapGet(elem->attrs, "href"); + Concat("("); + for (i = 0; i < ArraySize(elem->children); i++) + { + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); + + Concat(subxep); + Free(subxep); + } + 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); + } + } + break; + default: + break; + } + return xepd; +} +char * +ParseeXMPPify(HashMap *event) +{ + char *type, *format, *html; + char *xepd = NULL; + XMLElement *elem; + + XMPPFlags flags; + if (!event) + { + return NULL; + } + + /* Check if it is a message event. */ + type = JsonValueAsString(HashMapGet(event, "type")); + if (!StrEquals(type, "m.room.message")) + { + return NULL; + } + + format = JsonValueAsString(JsonGet(event, 2, "content", "format")); + if (!StrEquals(format, "org.matrix.custom.html")) + { + /* Settle for the raw body instead. */ + char *body = JsonValueAsString(JsonGet(event, 2, "content", "body")); + return StrDuplicate(body); + } + + html = JsonValueAsString(JsonGet(event, 2, "content", "formatted_body")); + html = StrConcat(3, "", html, ""); + elem = XMLCDecode(StrStreamReader(html), true, true); + + flags.quote = false; + xepd = XMPPifyElement(event, elem, flags); + + XMLFreeElement(elem); + Free(html); + + return xepd; +} void ParseePushDMStanza(ParseeData *data, char *room_id, char *stanza_id, char *id, char *ev, char *sender) { @@ -339,15 +519,6 @@ 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); @@ -550,178 +721,140 @@ 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); -} -bool -ParseeIsMUCWhitelisted(ParseeData *data, char *muc) -{ - char *server, *serv_start, *postserv; - 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); - postserv = server ? strchr(server, '/') : NULL; - if (postserv) /* GCC doesn't know strchr is pure. */ - { - *postserv = '\0'; - } - - ref = DbLockIntent(data->db, - DB_HINT_READONLY, - 1, "whitelist" - ); - ret = HashMapGet(DbJson(ref), server); - DbUnlock(data->db, ref); - Free(server); - - 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) +ParseeGlobalBan(ParseeData *data, char *glob, char *reason) { DbRef *ref; - HashMap *json; - if (!data || !chat || !key || !val) + HashMap *j, *obj; + if (!data || !glob) { return; } - ref = DbLockIntent(data->db, DB_HINT_WRITE, - 3, "chats", chat, "settings" - ); + ref = DbLock(data->db, 1, "global_bans"); if (!ref) { - ref = DbCreate(data->db, 3, "chats", chat, "settings"); + ref = DbCreate(data->db, 1, "global_bans"); } - json = DbJson(ref); - JsonValueFree(HashMapSet(json, key, JsonValueString(val))); + j = DbJson(ref); + + obj = HashMapCreate(); + if (reason) + { + HashMapSet(obj, "reason", JsonValueString(reason)); + } + HashMapSet(obj, "date", JsonValueInteger(UtilTsMillis())); + JsonValueFree(HashMapSet(j, glob, JsonValueObject(obj))); DbUnlock(data->db, ref); - return; } bool -ParseeIsMediaEnabled(ParseeData *data, char *chat_id) +ParseeManageBan(ParseeData *data, char *user, char *room) { - char *value; - bool ret; - if (!data || !chat_id) + DbRef *ref; + HashMap *j; + char *key; + JsonValue *val; + bool banned = false , matches = false; + if (!data || !user) { return false; } - ret = !StrEquals( - (value = ParseeGetChatSetting(data, chat_id, "p.media.enabled")), - "false" - ); - Free(value); - - return ret; + ref = DbLock(data->db, 1, "global_bans"); + j = DbJson(ref); + while (HashMapIterate(j, &key, (void **) &val)) + { + HashMap *obj = JsonValueAsObject(val); + if (matches) + { + continue; + } + if (GlobMatches(key, user)) + { + banned = true; + matches = true; + if (room) + { + /* TODO: Use the object to set the reason */ + ASBan(data->config, room, user); + (void) obj; + } + } + } + DbUnlock(data->db, ref); + + return banned; +} +char * +ParseeStringifyDate(uint64_t millis) +{ + uint64_t rest = millis; + uint64_t hours, minutes, seconds; + char *hs, *ms, *ss, *out; + + hours = rest / (1 HOURS); + rest = rest % (1 HOURS); + + minutes = rest / (1 MINUTES); + rest = rest % (1 MINUTES); + + seconds = rest / (1 SECONDS); + + hs = StrInt(hours); + ms = StrInt(minutes); + ss = StrInt(seconds); + + out = StrConcat(8, + hours ? hs : "", + hours ? " hours" : "", + (hours && minutes) ? ", " : "", + + minutes ? ms : "", + minutes ? " minutes" : "", + (minutes && seconds) ? ", " : "", + + seconds ? ss : "", + seconds ? " seconds" : "" + ); + Free(hs); + Free(ms); + Free(ss); + + return out; +} + +void +ParseeAchievement(const char *func, const char *msg, bool die) +{ + Log(LOG_ERR, "=========== Achievement GET! ==========="); + Log(LOG_ERR, "%s: %s.", func, msg); + Log(LOG_ERR, "THIS IS, LET'S SAY, NOT GOOD, AND A SIGN OF "); + Log(LOG_ERR, "A PROGRAMMER ERROR. PLEASE KILLALL -9 PARSEE."); + Log(LOG_ERR, ""); + Log(LOG_ERR, "YOU, HOWEVER, GET TO WIN AN AWARD FOR THIS."); + Log(LOG_ERR, "I AM SIMPLY JEALOUS OF YOU GETTING SUCH A "); + Log(LOG_ERR, "GOOD ERROR MESSAGE."); + Log(LOG_ERR, "=========== Achievement GET! ==========="); + + if (die) + { + abort(); + } +} +char * +ParseeGenerateMTO(char *common_id) +{ + char *matrix_to; + if (!common_id) + { + return NULL; + } + + common_id = HttpUrlEncode(common_id); + matrix_to = StrConcat(2, "https://matrix.to/#/", common_id); + Free(common_id); + + return matrix_to; } diff --git a/src/Parsee/HMAC.c b/src/Parsee/HMAC.c deleted file mode 100644 index abb65ef..0000000 --- a/src/Parsee/HMAC.c +++ /dev/null @@ -1,74 +0,0 @@ -/* CC0 implementation of a HMAC system based on Cytoplasm. - * Ignore the scary "Parsee.h", its practically unused. */ -#include - -#include -#include -#include - -#include - -static void -ComputeKPad(char *key, uint8_t pad, uint8_t *kopad) -{ - size_t klen; - uint8_t *kp; - uint8_t kpi[64] = { 0 }; - size_t i; - if ((klen = strlen(key)) <= 64) - { - kp = Malloc(klen * sizeof(uint8_t)); - memcpy(kp, key, klen); - } - else - { - kp = (uint8_t *) Sha256(key); - klen = 32; - } - - memset(kpi, 0x00, 64); - memcpy(kpi, kp, klen); - Free(kp); - - /* Now that we have K', lets compute it XORd with opad */ - for (i = 0; i < 64; i++) - { - uint8_t byte = kpi[i]; - kopad[i] = byte ^ pad; - } -} - -char * -ParseeHMAC(char *key, uint8_t *msg, size_t msglen) -{ - uint8_t opad[64], ipad[64 + msglen]; - uint8_t outer[64 + 32]; - - uint8_t *innersha; - uint8_t *sha; - char *str; - if (!key || !msg || !msglen) - { - return NULL; - } - - /* Initialise K' XOR opad and K' XOR ipad */ - ComputeKPad(key, 0x5C, opad); - ComputeKPad(key, 0x36, ipad); - - /* Compute H((K' XOR ipad) || msg) */ - memcpy(ipad + 64, msg, msglen); - innersha = Sha256Raw(ipad, 64 + msglen); - - /* Compute (K' XOR opad) || H((K' XOR ipad) || msg) */ - memcpy(outer, opad, 64); - memcpy(outer + 64, innersha, 32); - - /* Compute H((K' XOR opad) || H((K' XOR ipad) || msg)) */ - sha = Sha256Raw(outer, 64 + 32); - str = ShaToHex(sha, HASH_SHA256); - - Free(innersha); - Free(sha); - return str; -} diff --git a/src/Parsee/JIDTable.c b/src/Parsee/JIDTable.c new file mode 100644 index 0000000..772b975 --- /dev/null +++ b/src/Parsee/JIDTable.c @@ -0,0 +1,194 @@ +#include + +#include +#include +#include +#include + +static pthread_mutex_t lock; +static HashMap *jid_table = NULL; + +void +ParseeInitialiseJIDTable(void) +{ + if (jid_table) + { + return; + } + pthread_mutex_init(&lock, NULL); + pthread_mutex_lock(&lock); + jid_table = HashMapCreate(); + pthread_mutex_unlock(&lock); +} +void +ParseePushJIDTable(char *muc, char *bare) +{ + if (!muc || !bare || !jid_table) + { + return; + } + pthread_mutex_lock(&lock); + bare = ParseeTrimJID(bare); + Free(HashMapSet(jid_table, muc, bare)); + pthread_mutex_unlock(&lock); +} +char * +ParseeLookupJID(char *muc) +{ + char *bare; + if (!muc || !jid_table) + { + return NULL; + } + pthread_mutex_lock(&lock); + bare = StrDuplicate(HashMapGet(jid_table, muc)); + pthread_mutex_unlock(&lock); + + if (!bare) + { + bare = StrDuplicate(muc); + } + return bare; +} +void +ParseeDestroyJIDTable(void) +{ + char *key; + void *val; + if (!jid_table) + { + return; + } + pthread_mutex_lock(&lock); + while (HashMapIterate(jid_table, &key, &val)) + { + Free(val); + } + HashMapFree(jid_table); + jid_table = NULL; + pthread_mutex_unlock(&lock); + pthread_mutex_destroy(&lock); +} + +static pthread_mutex_t head_lock; +static HashMap *head_table = NULL; +void +ParseeInitialiseHeadTable(void) +{ + if (head_table) + { + return; + } + pthread_mutex_init(&head_lock, NULL); + pthread_mutex_lock(&head_lock); + head_table = HashMapCreate(); + pthread_mutex_unlock(&head_lock); +} +void +ParseePushHeadTable(char *room, char *event) +{ + if (!room || !event || !head_table) + { + return; + } + pthread_mutex_lock(&head_lock); + event = StrDuplicate(event); + Free(HashMapSet(head_table, room, event)); + pthread_mutex_unlock(&head_lock); +} +char * +ParseeLookupHead(char *room) +{ + char *event; + if (!room || !head_table) + { + return NULL; + } + pthread_mutex_lock(&head_lock); + event = StrDuplicate(HashMapGet(head_table, room)); + pthread_mutex_unlock(&head_lock); + + return event; +} +void +ParseeDestroyHeadTable(void) +{ + char *key; + void *val; + if (!head_table) + { + return; + } + pthread_mutex_lock(&head_lock); + while (HashMapIterate(head_table, &key, &val)) + { + Free(val); + } + HashMapFree(head_table); + head_table = NULL; + pthread_mutex_unlock(&head_lock); + pthread_mutex_destroy(&head_lock); +} + + +static pthread_mutex_t oid_lock; +static HashMap *oid_table = NULL; + +void +ParseeInitialiseOIDTable(void) +{ + if (oid_table) + { + return; + } + pthread_mutex_init(&oid_lock, NULL); + pthread_mutex_lock(&oid_lock); + oid_table = HashMapCreate(); + pthread_mutex_unlock(&oid_lock); +} +void +ParseePushOIDTable(char *muc, char *bare) +{ + if (!muc || !bare || !oid_table) + { + return; + } + pthread_mutex_lock(&oid_lock); + bare = StrDuplicate(bare); + Free(HashMapSet(oid_table, muc, bare)); + pthread_mutex_unlock(&oid_lock); +} +char * +ParseeLookupOID(char *muc) +{ + char *bare; + if (!muc || !oid_table) + { + return NULL; + } + pthread_mutex_lock(&oid_lock); + bare = StrDuplicate(HashMapGet(oid_table, muc)); + pthread_mutex_unlock(&oid_lock); + + return bare; +} +void +ParseeDestroyOIDTable(void) +{ + char *key; + void *val; + if (!oid_table) + { + return; + } + pthread_mutex_lock(&oid_lock); + while (HashMapIterate(oid_table, &key, &val)) + { + Free(val); + } + HashMapFree(oid_table); + oid_table = NULL; + pthread_mutex_unlock(&oid_lock); + pthread_mutex_destroy(&oid_lock); +} + diff --git a/src/Parsee/Logo.c b/src/Parsee/Logo.c deleted file mode 100644 index 30885d9..0000000 --- a/src/Parsee/Logo.c +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#include - -const char *parsee_ascii[PARSEE_ASCII_LINES] = -{ - " =+======", - " || | _ _/__----", - " / || \\ ==+= _/_____\\_", - " | || | -|- L___J ", - "_/ || \\_ ||| .______\\", - " || | | | |.____.|", - " || / | \\ |L____||", - " _// | | J" -}; - -void -ParseePrintASCII(void) -{ - size_t i; - for (i = 0; i < PARSEE_ASCII_LINES; i++) - { - Log(LOG_INFO, "%s", parsee_ascii[i]); - } -} diff --git a/src/Parsee/SHA.c b/src/Parsee/SHA.c deleted file mode 100644 index 9cd4484..0000000 --- a/src/Parsee/SHA.c +++ /dev/null @@ -1,57 +0,0 @@ -#include - -#include -#include - -static char * -ToHex(unsigned char *input, size_t length) -{ - char *hex = Malloc(length * 2 + 1); - size_t i; - - for (i = 0; i < length; i++) - { - const char *table = - "0123456789abcdef"; - unsigned char byte = input[i]; - hex[2 * i] = table[(byte >> 4) & 0xF]; - hex[2*i+1] = table[(byte >> 0) & 0xF]; - } - - hex[length * 2] = '\0'; - - return hex; -} - -char * -ParseeSHA256(char *string) -{ - unsigned char *sha; - char *returnString; - if (!string) - { - return NULL; - } - - sha = Sha256(string); - returnString = ToHex(sha, 32); - Free(sha); - - return returnString; -} -char * -ParseeSHA1(char *string) -{ - unsigned char *sha; - char *returnString; - if (!string) - { - return NULL; - } - - sha = Sha1(string); - returnString = ToHex(sha, 20); - Free(sha); - - return returnString; -} diff --git a/src/Parsee/Tables/Affiliation.c b/src/Parsee/Tables/Affiliation.c deleted file mode 100644 index e3b5f55..0000000 --- a/src/Parsee/Tables/Affiliation.c +++ /dev/null @@ -1,106 +0,0 @@ -#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/Tables/HeadTable.c b/src/Parsee/Tables/HeadTable.c deleted file mode 100644 index f910af5..0000000 --- a/src/Parsee/Tables/HeadTable.c +++ /dev/null @@ -1,67 +0,0 @@ -#include - -#include -#include -#include -#include - -static pthread_mutex_t head_lock; -static HashMap *head_table = NULL; -void -ParseeInitialiseHeadTable(void) -{ - if (head_table) - { - return; - } - pthread_mutex_init(&head_lock, NULL); - pthread_mutex_lock(&head_lock); - head_table = HashMapCreate(); - pthread_mutex_unlock(&head_lock); -} -void -ParseePushHeadTable(char *room, char *event) -{ - if (!room || !event || !head_table) - { - return; - } - pthread_mutex_lock(&head_lock); - event = StrDuplicate(event); - Free(HashMapSet(head_table, room, event)); - pthread_mutex_unlock(&head_lock); -} -char * -ParseeLookupHead(char *room) -{ - char *event; - if (!room || !head_table) - { - return NULL; - } - pthread_mutex_lock(&head_lock); - event = StrDuplicate(HashMapGet(head_table, room)); - pthread_mutex_unlock(&head_lock); - - return event; -} -void -ParseeDestroyHeadTable(void) -{ - char *key; - void *val; - if (!head_table) - { - return; - } - pthread_mutex_lock(&head_lock); - while (HashMapIterate(head_table, &key, &val)) - { - Free(val); - } - HashMapFree(head_table); - head_table = NULL; - pthread_mutex_unlock(&head_lock); - pthread_mutex_destroy(&head_lock); -} - diff --git a/src/Parsee/Tables/JIDTable.c b/src/Parsee/Tables/JIDTable.c deleted file mode 100644 index e5663c9..0000000 --- a/src/Parsee/Tables/JIDTable.c +++ /dev/null @@ -1,72 +0,0 @@ -#include - -#include -#include -#include -#include - -static pthread_mutex_t lock; -static HashMap *jid_table = NULL; - -void -ParseeInitialiseJIDTable(void) -{ - if (jid_table) - { - return; - } - pthread_mutex_init(&lock, NULL); - pthread_mutex_lock(&lock); - jid_table = HashMapCreate(); - pthread_mutex_unlock(&lock); -} -void -ParseePushJIDTable(char *muc, char *bare) -{ - if (!muc || !bare || !jid_table) - { - return; - } - pthread_mutex_lock(&lock); - bare = ParseeTrimJID(bare); - Free(HashMapSet(jid_table, muc, bare)); - pthread_mutex_unlock(&lock); -} -char * -ParseeLookupJID(char *muc) -{ - char *bare; - if (!muc || !jid_table) - { - return NULL; - } - pthread_mutex_lock(&lock); - bare = StrDuplicate(HashMapGet(jid_table, muc)); - pthread_mutex_unlock(&lock); - - if (!bare) - { - bare = StrDuplicate(muc); - } - return bare; -} -void -ParseeDestroyJIDTable(void) -{ - char *key; - void *val; - if (!jid_table) - { - return; - } - pthread_mutex_lock(&lock); - while (HashMapIterate(jid_table, &key, &val)) - { - Free(val); - } - HashMapFree(jid_table); - jid_table = NULL; - pthread_mutex_unlock(&lock); - pthread_mutex_destroy(&lock); -} - diff --git a/src/Parsee/Tables/NickTable.c b/src/Parsee/Tables/NickTable.c deleted file mode 100644 index 1778927..0000000 --- a/src/Parsee/Tables/NickTable.c +++ /dev/null @@ -1,100 +0,0 @@ -#include - -#include -#include -#include -#include - -static pthread_mutex_t nick_lock; -static HashMap *nick_table = NULL; - -static char * -GenerateKey(char *muc, char *mxid) -{ - char *concatStr; - char *hexDigest; - if (!muc || !mxid) - { - return NULL; - } - - concatStr = StrConcat(3, muc, ":", mxid); - hexDigest = ParseeSHA256(concatStr); - - Free (concatStr); - return hexDigest; -} - -void -ParseeInitialiseNickTable(void) -{ - if (nick_table) - { - return; - } - pthread_mutex_init(&nick_lock, NULL); - pthread_mutex_lock(&nick_lock); - nick_table = HashMapCreate(); - pthread_mutex_unlock(&nick_lock); -} -void -ParseePushNickTable(char *muc, char *mxid, char *nick) -{ - char *key; - if (!muc || !mxid || !nick_table) - { - return; - } - pthread_mutex_lock(&nick_lock); - - key = GenerateKey(muc, mxid); - nick = StrDuplicate(nick); - if (nick) - { - Free(HashMapSet(nick_table, key, nick)); - } - else - { - Free(HashMapDelete(nick_table, key)); - } - Free(key); - - pthread_mutex_unlock(&nick_lock); -} -char * -ParseeLookupNick(char *muc, char *mxid) -{ - char *ret, *key; - if (!muc || !nick_table) - { - return NULL; - } - pthread_mutex_lock(&nick_lock); - - key = GenerateKey(muc, mxid); - ret = HashMapGet(nick_table, key); - Free(key); - - pthread_mutex_unlock(&nick_lock); - return ret; -} -void -ParseeDestroyNickTable(void) -{ - char *key; - void *val; - if (!nick_table) - { - return; - } - pthread_mutex_lock(&nick_lock); - while (HashMapIterate(nick_table, &key, &val)) - { - Free(val); - } - HashMapFree(nick_table); - nick_table = NULL; - pthread_mutex_unlock(&nick_lock); - pthread_mutex_destroy(&nick_lock); -} - diff --git a/src/Parsee/Tables/OIDTable.c b/src/Parsee/Tables/OIDTable.c deleted file mode 100644 index 29569c8..0000000 --- a/src/Parsee/Tables/OIDTable.c +++ /dev/null @@ -1,68 +0,0 @@ -#include - -#include -#include -#include -#include - -static pthread_mutex_t oid_lock; -static HashMap *oid_table = NULL; - -void -ParseeInitialiseOIDTable(void) -{ - if (oid_table) - { - return; - } - pthread_mutex_init(&oid_lock, NULL); - pthread_mutex_lock(&oid_lock); - oid_table = HashMapCreate(); - pthread_mutex_unlock(&oid_lock); -} -void -ParseePushOIDTable(char *muc, char *bare) -{ - if (!muc || !bare || !oid_table) - { - return; - } - pthread_mutex_lock(&oid_lock); - bare = StrDuplicate(bare); - Free(HashMapSet(oid_table, muc, bare)); - pthread_mutex_unlock(&oid_lock); -} -char * -ParseeLookupOID(char *muc) -{ - char *bare; - if (!muc || !oid_table) - { - return NULL; - } - pthread_mutex_lock(&oid_lock); - bare = StrDuplicate(HashMapGet(oid_table, muc)); - pthread_mutex_unlock(&oid_lock); - - return bare; -} -void -ParseeDestroyOIDTable(void) -{ - char *key; - void *val; - if (!oid_table) - { - return; - } - pthread_mutex_lock(&oid_lock); - while (HashMapIterate(oid_table, &key, &val)) - { - Free(val); - } - HashMapFree(oid_table); - oid_table = NULL; - pthread_mutex_unlock(&oid_lock); - pthread_mutex_destroy(&oid_lock); -} - diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 6e673bb..e1e2710 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -1,46 +1,42 @@ #include #include -#include #include #include #include +#include #include #include #include #include -#include - bool ParseeIsPuppet(const ParseeConfig *conf, char *user) { - UserID *id; + char *localpart; bool flag = true; size_t len; - if (!user || - !conf || - *user != '@' || - !(id = MatrixParseID(user))) + if (!user || !conf || *user != '@') { return false; } + localpart = user + 1; len = strlen(conf->namespace_base); - if (strncmp(id->localpart, conf->namespace_base, len)) + if (strncmp(localpart, conf->namespace_base, len)) { flag = false; } - if (StrEquals(id->localpart, conf->sender_localpart)) + len = strlen(conf->sender_localpart); + if (!strncmp(localpart, conf->sender_localpart, len)) { flag = true; } - flag = flag && StrEquals(id->server, conf->server_base); - - Free(id); + /* TODO: Check serverpart. 2 Parsee instances may be running in the same + * room. */ return flag; } char * @@ -97,7 +93,7 @@ ParseeDecodeLocalJID(const ParseeConfig *c, char *mxid) data_start = jid_flags; while (*data_start && *data_start != '_') { - /* TODO: Get rid of this */ + /* TODO: Make this a macro */ if (*data_start == 'l') { plain_jid = true; @@ -127,7 +123,7 @@ ParseeDecodeLocalMUC(const ParseeConfig *c, char *alias) data_start = jid_flags; while (*data_start && *data_start != '_') { - /* TODO: Get rid of this */ + /* TODO: Make this a macro */ if (*data_start == 'm') { plain_jid = true; @@ -148,15 +144,14 @@ char * ParseeEncodeJID(const ParseeConfig *c, char *jid, bool trim) { char *ret, *tmp; - size_t i, len; + size_t i; if (!c || !jid) { return NULL; } ret = StrConcat(2, c->namespace_base, "_l_"); - len = strlen(jid); - for (i = 0; i < len; i++) + for (i = 0; i < strlen(jid); i++) { char cpy = jid[i]; char cs[4] = { 0 }; @@ -166,7 +161,7 @@ ParseeEncodeJID(const ParseeConfig *c, char *jid, bool trim) /* RID: Break everything and die. */ break; } - if (islower((int) *cs) || isalnum((int) *cs) || *cs == '_' || + if (islower(*cs) || isalnum(*cs) || *cs == '_' || *cs == '=' || *cs == '-' || *cs == '/' || *cs == '+' || *cs == '.') { @@ -195,7 +190,7 @@ char * ParseeGetLocal(char *mxid) { char *cpy; - size_t i, len; + size_t i; if (!mxid) { return NULL; @@ -205,14 +200,12 @@ ParseeGetLocal(char *mxid) return StrDuplicate(mxid); } - len = strlen(mxid); - mxid++; - cpy = Malloc(len + 1); - memset(cpy, '\0', len + 1); - memcpy(cpy, mxid, len); + cpy = Malloc(strlen(mxid) + 1); + memset(cpy, '\0', strlen(mxid) + 1); + memcpy(cpy, mxid, strlen(mxid)); - for (i = 0; i < len; i++) + for (i = 0; i < strlen(mxid); i++) { if (cpy[i] == ':') { @@ -228,19 +221,19 @@ char * ParseeEncodeMXID(char *mxid) { char *ret; - size_t i, j, len; + size_t i, j; if (!mxid) { return NULL; } /* Worst case scenario of 3-bytes the char */ - len = strlen(mxid); - ret = Malloc(len * 3 + 1); - for (i = 0, j = 0; i < len; i++) + ret = Malloc(strlen(mxid) * 3 + 1); + for (i = 0, j = 0; i < strlen(mxid); i++) { char src = mxid[i]; + /* TODO: More robust system */ if (src <= 0x20 || (src == '"' || src == '&' || src == '\'' || src == '/' || @@ -302,17 +295,19 @@ char * ParseeGetDMID(char *mxid, char *jid) { char *concat, *sha; + unsigned char *raw; if (!mxid || !jid) { return NULL; } - /* We really don't care about safety here. */ jid = ParseeTrimJID(jid); concat = StrConcat(2, mxid, jid); - sha = ParseeSHA1(concat); + raw = Sha1(concat); + sha = ShaToHex(raw); Free(concat); + Free(raw); Free(jid); return sha; @@ -358,34 +353,19 @@ ParseePushDMRoom(ParseeData *d, char *mxid, char *jid, char *r) Free(dmid); return; } -void -ParseeDeleteDM(ParseeData *d, char *mxid, char *jid) -{ - char *dmid; - if (!d || !mxid || !jid) - { - return; - } - - dmid = ParseeGetDMID(mxid, jid); - DbDelete(d->db, 2, "users", dmid); - Free(dmid); - return; -} char * ParseeTrimJID(char *jid) { char *ret; - size_t i, len; + size_t i; if (!jid) { return NULL; } ret = StrDuplicate(jid); - len = strlen(ret); - for (i = 0; i < len; i++) + for (i = 0; i < strlen(ret); i++) { if (ret[i] == '/') { @@ -539,6 +519,7 @@ ParseeGetMUCID(ParseeData *data, char *chat_id) return ret; } + void ParseeSendPresence(ParseeData *data) { @@ -557,16 +538,10 @@ 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 ? (int) ((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, diff, false); + XMPPJoinMUC(data->jabber, "parsee", rev); - DbUnlock(data->db, chat); - Free(chat_id); Free(rev); } DbUnlock(data->db, ref); @@ -688,13 +663,11 @@ end: #include char * -ParseeToUnauth(ParseeData *data, char *mxc, char *filename) +ParseeToUnauth(ParseeData *data, char *mxc) { 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" +#define PAT "%s/_matrix/client/v1/media/download/%s%s" size_t l; if (!data || !mxc) { @@ -711,51 +684,19 @@ ParseeToUnauth(ParseeData *data, char *mxc, char *filename) return NULL; } - key = StrConcat(2, url->host, url->path); - hmac = ParseeHMACS(data->id, key); - Free(key); - - if (!filename) - { - l = snprintf(NULL, 0, - PAT, - data->config->media_base, - url->host, url->path, - hmac - ); - } - else - { - char *encoded = HttpUrlEncode(filename); - l = snprintf(NULL, 0, - PATF, - data->config->media_base, - url->host, url->path, encoded, - hmac - ); - Free(encoded); - } + /* TODO: HTTPS */ + l = snprintf(NULL, 0, + PAT, + data->config->media_base, + url->host, url->path + ); ret = Malloc(l + 3); - 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 - ); - } + snprintf(ret, l + 1, + PAT, + data->config->media_base, + url->host, url->path + ); UriFree(url); - Free(hmac); return ret; } diff --git a/src/Parsee/Utils/Achievement.c b/src/Parsee/Utils/Achievement.c deleted file mode 100644 index 136f6a0..0000000 --- a/src/Parsee/Utils/Achievement.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -#include - -#include - -void -ParseeAchievement(const char *func, const char *msg, bool die) -{ - Log(LOG_ERR, "=========== Achievement GET! ==========="); - Log(LOG_ERR, "%s: %s.", func, msg); - Log(LOG_ERR, "THIS IS, LET'S SAY, NOT GOOD, AND A SIGN OF "); - Log(LOG_ERR, "A PROGRAMMER ERROR. PLEASE KILLALL -9 PARSEE."); - Log(LOG_ERR, ""); - Log(LOG_ERR, "YOU, HOWEVER, GET TO WIN AN AWARD FOR THIS."); - Log(LOG_ERR, "I AM SIMPLY JEALOUS OF YOU GETTING SUCH A "); - Log(LOG_ERR, "GOOD ERROR MESSAGE."); - Log(LOG_ERR, "=========== Achievement GET! ==========="); - - if (die) - { - abort(); - } -} - - diff --git a/src/Parsee/Utils/Arguments.c b/src/Parsee/Utils/Arguments.c deleted file mode 100644 index 9d4c897..0000000 --- a/src/Parsee/Utils/Arguments.c +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include -#include -#include - -void -ParseeGenerateHelp(const Argument *list) -{ - if (!list) - { - return; - } - - while (!list->end) - { - char *str = list->value_req ? - StrConcat(3, " [", list->value_descr, "]") : - StrDuplicate(""); - Log(LOG_INFO, "-%c%s", list->argument, str); - LogConfigIndent(LogConfigGlobal()); - Log(LOG_INFO, "%s", list->description); - LogConfigUnindent(LogConfigGlobal()); - list++; - - Free(str); - } - return; -} -char * -ParseeGenerateGetopt(const Argument *list) -{ - char *ret = NULL, *tmp = NULL; - if (!list) - { - return NULL; - } - - while (!list->end) - { - char buffer[3] = { - list->argument, list->value_req ? ':' : '\0', - '\0' - }; - - tmp = ret; - ret = StrConcat(2, ret, buffer); - Free(tmp); - - list++; - } - return ret; -} diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c deleted file mode 100644 index ec95aef..0000000 --- a/src/Parsee/Utils/Formatting.c +++ /dev/null @@ -1,323 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -typedef struct XMPPFlags { - bool quote; -} XMPPFlags; -static char * -XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPFlags flags) -{ - char *xepd = NULL, *tmp = NULL; - - size_t i; - XMLElement *child; - char *reply_id = GrabString( - event, - 4, "content", - "m.relates_to", "m.in_reply_to", "event_id" - ); - char *room_id = JsonValueAsString(HashMapGet(event, "room_id")); - HashMap *referenced; - char *subxep; -#define Concat(strp) do \ - { \ - size_t cidx; \ - size_t len = strp ? strlen(strp) : 0; \ - for (cidx = 0; cidx < len; cidx++) \ - { \ - char cch[2]; \ - cch[0] = strp[cidx]; \ - cch[1] = '\0'; \ - char nch = *cch ? strp[cidx+1] : '\0'; \ - bool c = *cch == '\n' && nch != '>'; \ - if (c && flags.quote) \ - { \ - tmp = xepd; \ - xepd = StrConcat(2, xepd, "\n>"); \ - Free(tmp); \ - continue; \ - } \ - tmp = xepd; \ - xepd = StrConcat(2, xepd, cch); \ - Free(tmp); \ - } \ - } \ - while (0) - switch (elem ? elem->type : -1) - { - case XML_ELEMENT_DATA: - Concat(elem->data); - break; - case XML_ELEMENT_TAG: - if (StrEquals(elem->name, "b") || StrEquals(elem->name, "strong")) - { - Concat("*"); - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - Concat("*"); - } - else if (StrEquals(elem->name, "em")) - { - Concat("_"); - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - Concat("_"); - } - else if (StrEquals(elem->name, "code")) - { - Concat("`"); - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - Concat("`"); - } - else if (StrEquals(elem->name, "mx-reply")) - { - char *str; - referenced = ASFind(ParseeConfigGet(), room_id, reply_id); - str = JsonValueAsString( - JsonGet(referenced, 2, "content", "body") - ); - if (!str) - { - JsonFree(referenced); - return xepd; - } - Concat(">"); - flags.quote = true; - Concat(str); - flags.quote = false; - Concat("\n"); - JsonFree(referenced); - } - else if (StrEquals(elem->name, "blockquote")) - { - Concat(">"); - flags.quote = true; - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - flags.quote = false; - Concat("\n"); - } - else if (StrEquals(elem->name, "br")) - { - Concat("\n"); - /* HTML fucking SUCKS */ - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - if (i != 0) - { - Concat("\n"); - } - } - else if (StrEquals(elem->name, "a")) - { - char *href = HashMapGet(elem->attrs, "href"); - Uri *pref = UriParse(href); - if (pref && StrEquals(pref->host, "matrix.to")) - { - /* TODO: Check if the element here is a Matrix.TO - * pointing to a Parsee user. */ - UserID *id = MatrixParseIDFromMTO(pref); - if (id) - { - char *real_id = StrConcat(4, "@", id->localpart, ":", id->server); - /* TODO: Detect if it already is a Parsee user */ - 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 - { - Concat(href); - } - - Free(id); - } - else - { - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - Concat(" < "); - Concat(href); - Concat(" >"); - } - UriFree(pref); - } - else - { - for (i = 0; i < ArraySize(elem->children); i++) - { - child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); - - Concat(subxep); - Free(subxep); - } - } - break; - default: - break; - } - return xepd; -} -static char * -GetRawBody(HashMap *event) -{ - void *id; - if ((id = MatrixGetEdit(event))) - { - char *new = GrabString(event, 3, "content", "m.new_content", "body"); - Free(id); - 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"); -} -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) -{ - char *type, *format, *html; - char *xepd = NULL; - XMLElement *elem; - - XMPPFlags flags; - if (!event) - { - return NULL; - } - - /* Check if it is a message event. */ - type = JsonValueAsString(HashMapGet(event, "type")); - if (!StrEquals(type, "m.room.message")) - { - return NULL; - } - - if (!StrEquals(GetBodyFormat(event), "org.matrix.custom.html")) - { - /* Settle for the raw body instead. */ - char *body = GetRawBody(event); - return StrDuplicate(body); - } - - html = GetHTMLBody(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(data ? data->config : NULL, event, elem, flags); - - XMLFreeElement(elem); - Free(html); - - return xepd; -} - -char * -ParseeGenerateMTO(char *common_id) -{ - char *matrix_to; - if (!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); - - return matrix_to; -} diff --git a/src/Parsee/Utils/Nofly.c b/src/Parsee/Utils/Nofly.c deleted file mode 100644 index 439c7d0..0000000 --- a/src/Parsee/Utils/Nofly.c +++ /dev/null @@ -1,97 +0,0 @@ -#include - -#include -#include - -#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) -{ - DbRef *ref; - HashMap *j, *obj; - if (!data || !glob) - { - return; - } - - ref = DbLock(data->db, 1, "global_bans"); - if (!ref) - { - ref = DbCreate(data->db, 1, "global_bans"); - } - - j = DbJson(ref); - - obj = HashMapCreate(); - if (reason) - { - HashMapSet(obj, "reason", JsonValueString(reason)); - } - HashMapSet(obj, "date", JsonValueInteger(UtilTsMillis())); - JsonValueFree(HashMapSet(j, glob, JsonValueObject(obj))); - - DbUnlock(data->db, ref); -} -bool -ParseeManageBan(ParseeData *data, char *user, char *room) -{ - DbRef *ref; - HashMap *j; - char *key; - JsonValue *val; - bool banned = false , matches = false; - if (!data || !user) - { - return false; - } - - ref = DbLockIntent(data->db, DB_HINT_READONLY, 1, "global_bans"); - j = DbJson(ref); - while (HashMapIterate(j, &key, (void **) &val)) - { - HashMap *obj = JsonValueAsObject(val); - if (matches) - { - continue; - } - if (GlobMatches(key, user)) - { - banned = true; - matches = true; - if (room) - { - /* TODO: Use the object to set the reason */ - ASBan(data->config, room, user); - (void) obj; - } - } - } - DbUnlock(data->db, ref); - - return banned; -} - diff --git a/src/Parsee/Utils/String.c b/src/Parsee/Utils/String.c deleted file mode 100644 index c054d13..0000000 --- a/src/Parsee/Utils/String.c +++ /dev/null @@ -1,95 +0,0 @@ -#include - -#include -#include - -#include - -#include -#include - -int -ParseeFindDatastart(char *data) -{ - char *startline; - bool found = false; - if (!data) - { - return 0; - } - - startline = data; - while (startline) - { - char *endline = strchr(startline, '\n'); - - if (*startline != '>') - { - found = true; - break; - } - - startline = endline ? endline + 1 : NULL; - } - - if (!found) - { - return 0; - } - - 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) -{ - uint64_t rest = millis; - uint64_t hours, minutes, seconds; - char *hs, *ms, *ss, *out; - - hours = rest / (1 HOURS); - rest = rest % (1 HOURS); - - minutes = rest / (1 MINUTES); - rest = rest % (1 MINUTES); - - seconds = rest / (1 SECONDS); - - hs = StrInt(hours); - ms = StrInt(minutes); - ss = StrInt(seconds); - - out = StrConcat(8, - hours ? hs : "", - hours ? " hours" : "", - (hours && minutes) ? ", " : "", - - minutes ? ms : "", - minutes ? " minutes" : "", - (minutes && seconds) ? ", " : "", - - seconds ? ss : "", - seconds ? " seconds" : "" - ); - Free(hs); - Free(ms); - Free(ss); - - return out; -} diff --git a/src/Parsee/Versions.c b/src/Parsee/Versions.c deleted file mode 100644 index b5398c0..0000000 --- a/src/Parsee/Versions.c +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include -#include - -bool -ParseeIsCompatible(char *ver1, char *ver2) -{ - char *major1 = NULL; - char *major2 = NULL; - char *tmp; - if (!ver1 || !ver2) - { - return false; - } - - /* Check if one of them is a "flipped"(joke) version. If so, - * then the user should definitely NOT try funny things with - * their data. */ - if (*ver1 == '-' || *ver2 == '-') - { - return false; - } - -#define GetMajor(v) do \ - { \ - while (*ver##v != '.') \ - { \ - char cb[2]; \ - cb[0] = *ver##v; \ - cb[1] = '\0'; \ - tmp = major##v; \ - major##v = StrConcat(2, major##v, cb); \ - Free(tmp); \ - ver##v++; \ - } \ - } \ - while (0) - - GetMajor(1); - GetMajor(2); - - if (!StrEquals(major1, major2)) - { - Free(major1); - Free(major2); - return false; - } - - Free(major1); - Free(major2); - return true; -} diff --git a/src/Routes/Media.c b/src/Routes/Media.c index 498eba2..45d79d0 100644 --- a/src/Routes/Media.c +++ b/src/Routes/Media.c @@ -2,80 +2,37 @@ #include #include -#include #include #include #include -#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; HttpClientContext *cctx; - HashMap *reqh, *params; + HashMap *reqh; char *server = ArrayGet(arr, 0); char *identi = ArrayGet(arr, 1); - char *key, *val; - char *hmac, *chkmak = NULL; + char *path, *key, *val; - params = HttpRequestParams(args->ctx); - hmac = HashMapGet(params, "hmac"); - - /* TODO: Make it check the DB for its validicity. "Purging" would be - * useful, alongside checking if someone isn't just a little idiotic. */ + /* TODO: Make it check the DB for its validicity. "Purging" would be useful. + */ + if (!server || !identi) { - char *concat = StrConcat(3, server, "/", identi); - chkmak = ParseeHMACS(args->data->id, concat); - Free(concat); - } - if (!server || !identi || !hmac || !StrEquals(hmac, chkmak)) - { - char *err = - hmac && StrEquals(hmac, chkmak) ? - "No server/identifier/HMAC code" : - "Hah! You _dirty_ little liar! Try a little harder!"; - Free(chkmak); HttpResponseStatus(args->ctx, HTTP_BAD_REQUEST); - return MatrixCreateError("M_NOT_YET_UPLOADED", err); + return MatrixCreateError("M_NOT_YET_UPLOADED", "No server/identifier"); } - Free(chkmak); - /* Proxy the media through an authenticated endpoint if the HMAC - * is valid. */ - cctx = TryDownload(args->data, server, identi); + 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); reqh = HttpResponseHeaders(cctx); while (HashMapIterate(reqh, &key, (void **) &val)) { @@ -88,6 +45,8 @@ RouteHead(RouteMedia, arr, argp) } HttpClientContextFree(cctx); + Free(server); + Free(identi); return NULL; } diff --git a/src/Routes/Ping.c b/src/Routes/Ping.c index 1d4191e..88dc533 100644 --- a/src/Routes/Ping.c +++ b/src/Routes/Ping.c @@ -25,12 +25,13 @@ RouteHead(RoutePing, arr, argp) ); goto end; } + Log(LOG_INFO, "Pong!"); RequestJSON(); + /* TODO: Load ping info */ response = HashMapCreate(); end: - (void) arr; JsonFree(request); return response; } diff --git a/src/Routes/Root.c b/src/Routes/Root.c index 0ddb731..578dc20 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -41,26 +41,13 @@ GetRandomQuote(void) "We truly live in a " CODE "...", "You truly lack the Desire Drive for this!", "Eeh? Bifrost mode? Only bad servers use Bifrost mode!", - "'Wow parsee can save the world' - said a wise guy", "As small as a dwarf, and can run on your pie!", "It's all wicked unsafe, memory slow 🚀🚀🚀🚀", "XMPP kinda sucks.", "Matrix kinda sucks.", - "Throw jabs!", - "'Won't you hold my <presence/> safe?' - Kanako", - - NAME ": the federated world's little little kobashi", - - "Go take a look at your stanzas!", - "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 !" + "Throw jabs!" }; const size_t count = sizeof(quotes)/sizeof(*quotes); @@ -82,7 +69,6 @@ RouteHead(RouteRoot, arr, argp) { P("%s Lander", NAME); P(""); - P("", media_parsee_logo); P("