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..f2c57e6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,11 +4,8 @@ parsee* parsee *.swp .* -data* -data*/* -Makefile -configure -gmon.out +data +data/* tools/out tools/out/* @@ -22,11 +19,3 @@ 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 index f4ffcde..5762504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,73 +6,7 @@ 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. 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..f54dbc0 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[tomboyish-bridges-adventure]: + Get Parsee into the _Phantasmagoria of Bug View_ stage (essentially + v0.0.1 for a public testing) once I can afford `yama`, and start + bridging the Matrix room alongside a shiny XMPP MUC, bridged by + yours truly. diff --git a/LICENSE b/LICENSE index cb9aa73..1e1282b 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, +For the files src/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 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..c1125b3 --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +# (GNU)Makefile for building Parsee +# ================================ +# TODO: Consider making something akin to a configure script that checks +# for dependencies, or maybe even use *autoconf* (the devil!) + + +# =========================== Parsee Flags ============================= + +include build.conf + +REPOSITORY=$(shell git remote get-url origin) + +# =========================== Compilation Flags ============================ +CYTO_INC ?=/usr/local/include/ # Where Cytoplasm's include path is + # located. +CYTO_LIB ?=/usr/local/lib # Where's Cytoplasm's library is + # located. +PREFIX ?=/usr/local + +AYAS=ayaya +ETC=etc +FCFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -DCODE=\"$(CODE)\" $(CFLAGS) +FLDFLAGS=-L $(CYTO_LIB) -lCytoplasm $(LDFLAGS) +AFLAGS=-C "$(ETC)/ayadoc/style.css" -p "$(NAME)" +# ============================ Compilation ================================= +SRC_FILES:=$(shell find $(SOURCE) -name '*.c') $(shell find $(ETC)/media -name '*.png') +OBJ_FILES:=${subst $(ETC)/media/,$(OBJECT)/,${subst $(SOURCE)/,$(OBJECT)/,$(patsubst %.png, %.o, $(patsubst %.c, %.o, $(SRC_FILES)))}} + +CPP_FILES:=$(shell find $(INCLUDES) -name '*.h') +AYA_FILES:=${subst $(INCLUDES)/,$(AYAS)/,$(patsubst %.h, %.html, $(CPP_FILES))} + +all: utils binary + +binary: $(OBJ_FILES) + $(CC) $(FLDFLAGS) $(OBJ_FILES) -o $(BINARY) +tags: $(SRC_FILES) + @ctags --recurse $(SOURCE)/ + +clean: + rm -rf $(OBJECT) $(BINARY) $(AYAS) + +$(OBJECT)/%.o: $(ETC)/media/%.png + @mkdir -p $(shell dirname "$@") + @echo "const char media_$(shell basename $< .png)[] =" > $@.c + @base64 $< | \ + sed -e 's/^\(.*\)$$/ "\1"/' | \ + sed -e '$$ s/^\(.*\)$$/\1;/' >> $@.c + $(CC) -c $(FCFLAGS) $@.c -o $@ +$(OBJECT)/%.o: $(SOURCE)/%.c + @mkdir -p $(shell dirname "$@") + $(CC) -c $(FCFLAGS) $< -o $@ + +utils: + (cd tools && make) + +ayadoc: utils $(AYA_FILES) + +$(AYAS)/%.html: $(INCLUDES)/%.h + @mkdir -p $(shell dirname "$@") + tools/out/aya $(AFLAGS) -i $< -o $@ + + +# Installs everything. +install: binary utils ayadoc install_setup install_parsee install_tools install_aya install_man + @echo Installed $(NAME) to $(PREFIX)! + +install_setup: + install -dm755 "$(PREFIX)/bin" + install -dm755 "$(PREFIX)/share/doc" + install -dm755 "$(PREFIX)/man" + +install_parsee: + install -Dm755 "$(BINARY)" "$(PREFIX)/bin/$(BINARY)" + +TOOLS:=$(shell find 'tools/out' -name '*') +ITOOL:=${subst tools/out/,$(PREFIX)/bin/,$(patsubst tools/out/%, tools/out/$(BINARY)-%, $(TOOLS))} +install_tools: $(ITOOL) +$(PREFIX)/bin/$(BINARY)-%: tools/out/% + install -Dm755 "$<" "$@" + +IHTML:=${subst $(AYAS)/,$(PREFIX)/share/doc/$(BINARY)/,$(AYA_FILES)} +install_aya: $(IHTML) +$(PREFIX)/share/doc/$(BINARY)/%: $(AYAS)/% + install -Dm644 "$<" "$@" + +MPAGE:=$(shell find 'etc/man' -name '*.*') +PPAGE:=${subst etc/man/,$(PREFIX)/man/,$(MPAGE)} +install_man: $(PPAGE) +$(PREFIX)/man/%: etc/man/% + install -Dm644 "$<" "$@" diff --git a/README.MD b/README.MD index f9522e8..51fcf7f 100644 --- a/README.MD +++ b/README.MD @@ -1,55 +1,45 @@ # 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. ## 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. +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. +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)) +Well, I'm *trying* to do that, at least. +Please scream at me if that fails(or just doesn't run on a overclocked Raspberry +Pi 4B, which, by the way, is literally where Parsee+XMPP is running for now.) ### "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. ### 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 -``` - ## RUNNING First off, you may want to configure Parsee by running the `config` tool(generally named `parsee-config` in most cases), with the correct flags, like here. @@ -61,8 +51,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 +64,33 @@ 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. - 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). + put in the work of either forking off libolm or making a binding to KappaChat. - 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. - Get rid of the '?'-syntax and use another invalid Matrix char/valid XMPP char ('$'?) for escaped? +- PROPER FUCKING AVATARS + XMPP->Matrix is decent, Matrix->XMPP is effectiveny not done - Consider making room/MUC admins/owners be able to plumb instead of it being restricted to Parsee admins, with permission from MUC owners, too - Limiting to admins may be a way to "control" consent for both, but this is 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. +- Deadlocks. It's always deadlocks. ## DONATING/CONTRIBUTING If you know things about XMPP or Matrix, yet aren't familiar with C99, or just @@ -129,7 +107,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..ae74f4f 100644 --- a/XEPS-TBD.TXT +++ b/XEPS-TBD.TXT @@ -21,14 +21,10 @@ 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 For future XEPs: - https://xmpp.org/extensions/xep-0449.html @@ -38,7 +34,12 @@ 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... @@ -47,7 +48,7 @@ On Standby: Not XEPs, but ideas that _needs_ to be added: ~ "GIVE THE PUPPETS APPROPRIATE PLS/ROLES" - Hydro/t4d Happens on Matrix. I'll need to handle that on XMPP as well. - ~ Standalone/Static Parsee, ideally as small as it can be(if not as APE). + - Standalone/Static Parsee, ideally as small as it can be(if not as APE). - Kappa-like extension system(maybe bridging more than just Matrix-XMPP.) - https://www.youtube.com/watch?v=InL414iDZmY diff --git a/build.c b/build.c new file mode 100644 index 0000000..b80a7d9 --- /dev/null +++ b/build.c @@ -0,0 +1,863 @@ +/* build.c - Simple, POSIX, non-Cytoplasm utility to build out + * the entirety of Parsee from scratch, without any Makefiles. + * + * The main reason why this tool exists is merely because the + * current Make-based building is not POSIX compliant, and I + * am simply not porting it to be. The Makefile shall stay + * supported however, but if possible, use build.c. + * To run it, just build it with: + * cc build.c -o /tmp/build && /tmp/build + * + * TODO: Parallel jobs, CFLAGS and LDFLAGS. + * Note that this bit is formatted differently. + * -------------------------------- + * LICENSE: CC0 + * Written-By: LDA [lda@freetards.xyz] [@fourier:ari.lt] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_BUILD_PATH "build.conf" +#define DEFAULT_COMPILER "cc" +#define Compiler(info) (info.basic.cc ? info.basic.cc : DEFAULT_COMPILER) + +static char * +string_rep_ext(char *in, char *ext1, char *ext2) +{ + char *end; + size_t inLen; + if (!in || !ext1 || !ext2) + { + return NULL; + } + + inLen = strlen(in); + end = inLen + in; + + while (end >= in) + { + if (!strcmp(end, ext1)) + { + size_t cpyLen = end - in; + size_t extLen = strlen(ext2); + char *ret = malloc(cpyLen + extLen + 1); + + memcpy(ret, in, cpyLen); + memcpy(ret + cpyLen, ext2, extLen); + ret[cpyLen + extLen] = '\0'; + return ret; + } + end--; + } + return NULL; +} +static char * +string_dup(char *in) +{ + char *out; + size_t len; + if (!in) + { + return NULL; + } + len = strlen(in); + out = malloc(len + 1); + memcpy(out, in, len); + out[len] = '\0'; + + return out; +} +static char * +string_cat(char *in1, char *in2) +{ + char *out; + size_t len1, len2; + if (!in1) + { + return string_dup(in2); + } + if (!in2) + { + return string_dup(in1); + } + + len1 = strlen(in1); + len2 = strlen(in2); + out = malloc(len1 + len2 + 1); + memcpy(out, in1, len1); + memcpy(out + len1, in2, len2); + out[len1 + len2] = '\0'; + + return out; +} +static char * +trim_nl(char *in) +{ + char *tc; + if (!in) + { + return NULL; + } + + while ((tc = strrchr(in, '\n'))) + { + *tc = '\0'; + } + + return in; +} + +typedef struct str_array { + char **values; + size_t quantity; +} str_array_t; +static str_array_t * +str_array_create(void) +{ + str_array_t *ret = malloc(sizeof(*ret)); + + ret->values = NULL; + ret->quantity = 0; + return ret; +} +static void +str_array_free(str_array_t *arr) +{ + size_t i; + if (!arr) + { + return; + } + + for (i = 0; i < arr->quantity; i++) + { + if (arr->values[i]) free(arr->values[i]); + } + if (arr->values) free(arr->values); + free(arr); +} +static void +str_array_set(str_array_t *arr, size_t i, char *str) +{ + if (!arr) + { + return; + } + + if (i >= arr->quantity) + { + size_t size = (i+1) * sizeof(*arr->values); + size_t j; + arr->values = realloc(arr->values, size); + for (j = arr->quantity; j <= i; j++) + { + arr->values[j] = NULL; + } + arr->quantity = i + 1 ; + } + if (arr->values[i]) free(arr->values[i]); + arr->values[i] = string_dup(str); +} +static void +str_array_add(str_array_t *arr, char *str) +{ + if (!arr) + { + return; + } + str_array_set(arr, arr->quantity, str); +} +static char * +str_array_get(str_array_t *arr, size_t i) +{ + if (!arr) + { + return NULL; + } + return i < arr->quantity ? arr->values[i] : NULL; +} +static size_t +str_array_len(str_array_t *arr) +{ + return arr ? arr->quantity : 0; +} + +typedef struct buildinfo { + struct basic { + char *codename; + char *version; + + char *name; + + char *binary; + + char *src; + char *inc; + char *obj; + + char *cflags, *ldflags; + + char *cc; + } basic; + + char *repo; +} buildinfo_t; +static void +destroy_buildinfo(buildinfo_t *info) +{ + if (!info) + { + return; + } + +#define FreeIfExistent(v) do \ + { \ + if (v) \ + { \ + free(v); \ + v = NULL; \ + } \ + } while (0) + + FreeIfExistent(info->basic.codename); + FreeIfExistent(info->basic.version); + FreeIfExistent(info->basic.ldflags); + FreeIfExistent(info->basic.binary); + FreeIfExistent(info->basic.cflags); + FreeIfExistent(info->basic.name); + FreeIfExistent(info->basic.src); + FreeIfExistent(info->basic.inc); + FreeIfExistent(info->basic.obj); + FreeIfExistent(info->basic.cc); + FreeIfExistent(info->repo); +} + +static char * +cmd_stdout(char *cmd) +{ + FILE *f; + char *line = NULL; + size_t size; + if (!cmd) + { + return NULL; + } + if (!(f = popen(cmd, "r"))) + { + return NULL; + } + + getline(&line, &size, f); + pclose(f); + return line; +} +static int +exec_code(char *program, char *argv[]) +{ + pid_t forkRet; + if (!program || !argv) + { + return -1; + } + + forkRet = fork(); + if (forkRet == 0) + { + /* Child */ + execvp(program, argv); + exit(0); + } + else + { + /* Parent */ + int status; + if (waitpid(forkRet, &status, 0) == -1) + { + return -1; + } + return status; + } + + /* We're not meant to ever be there, but TCC is stupid. */ + return -1; +} + +static char * +strchrn(char *s, char c) +{ + s = strchr(s, c); + return s ? s+1 : NULL; +} +static char * +strchrl(char *s, char c) +{ + char *s1 = NULL; + while ((s = strchr(s, c))) + { + s1 = s; + s++; + } + return s1; +} +static void +mkdir_rec(char *dir) +{ + char tmp[PATH_MAX]; + char *start; + if (!dir || strlen(dir) >= PATH_MAX - 1) + { + return; + } + + memset(tmp, '\0', sizeof(tmp)); + for (start = dir; start && *start; start = strchrn(start, '/')) + { + char subtmp[PATH_MAX]; + char *next = strchr(start, '/'); + if (!next) + { + next = start + strlen(start); + } + memcpy(subtmp, start, next - start); + subtmp[next - start] = '\0'; + + { + memcpy(tmp, dir, start - dir); + tmp[strlen(tmp) - 1] = '\0'; + mkdir(tmp, 0770); + } + } +} +static str_array_t * +split(char *dir) +{ + str_array_t *ret; + char *start; + if (!dir || strlen(dir) >= PATH_MAX - 1) + { + return NULL; + } + + ret = str_array_create(); + for (start = dir; start; start = strchrn(start, ' ')) + { + char subtmp[PATH_MAX]; + char *next = strchr(start, ' '); + if (!next) + { + next = start + strlen(start); + } + memcpy(subtmp, start, next - start); + subtmp[next - start] = '\0'; + + str_array_add(ret, subtmp); + } + return ret; +} +static time_t +mod_date(char *file) +{ + struct stat s; + if (stat(file, &s)) + { + return (time_t) 0; + } + return s.st_mtime; +} +static bool +build_file(char *cSource, buildinfo_t info, bool isTool) +{ + str_array_t *args, *cflags; + char *oFileName, *objPath, *oFile; + int ret, i = 0; + int srclen; + + char *code, *name, *vers, *repo; + if (!cSource) + { + return false; + } + + if (!isTool) + { + srclen = strncmp(cSource, "src", 3) ? + strlen(info.basic.obj) + 1 : + strlen(info.basic.src) + 1 ; + objPath = string_cat(info.basic.obj, "/"); + oFile = string_rep_ext(cSource + srclen, ".c", ".o"); + oFileName = string_cat(objPath, oFile); + } + else + { + srclen = 6; + objPath = string_dup("tools/out/"); + oFile = string_rep_ext(cSource + srclen, ".c", ""); + oFileName = string_cat(objPath, oFile); + } + mkdir_rec(oFileName); + + if (!isTool && (mod_date(cSource) < mod_date(oFileName))) + { + free(objPath); + free(oFileName); + free(oFile); + return true; + } + + args = str_array_create(); + if (!isTool) + { + printf("\tCC %s...\n", cSource); + } + + str_array_add(args, Compiler(info)); + if (isTool) + { + str_array_add(args, "-lCytoplasm"); + str_array_add(args, "-I."); + } + else + { + str_array_add(args, "-c"); + } + str_array_add(args, cSource); + + cflags = split(info.basic.cflags); + for (i = 0; i < str_array_len(cflags); i++) + { + str_array_add(args, str_array_get(cflags, i)); + } + str_array_free(cflags); + + str_array_add(args, "-o"); + str_array_add(args, oFileName); + + str_array_add(args, "-I"); + str_array_add(args, info.basic.inc); + str_array_add(args, "-I"); + str_array_add(args, info.basic.src); + + { + char *pre = string_cat("\"", info.basic.version); + char *pos = string_cat(pre, "\""); + vers = string_cat("-DVERSION=", pos); + str_array_add(args, vers); + + free(pos); + free(pre); + } + { + char *pre = string_cat("\"", info.basic.name); + char *pos = string_cat(pre, "\""); + name = string_cat("-DNAME=", pos); + str_array_add(args, name); + + free(pos); + free(pre); + } + { + char *pre = string_cat("\"", info.basic.codename); + char *pos = string_cat(pre, "\""); + code = string_cat("-DCODE=", pos); + str_array_add(args, code); + + free(pos); + free(pre); + } + { + char *pre = string_cat("\"", info.repo); + char *pos = string_cat(pre, "\""); + repo = string_cat("-DREPOSITORY=", pos); + str_array_add(args, repo); + + free(pos); + free(pre); + } + + str_array_add(args, NULL); + + ret = exec_code(Compiler(info), args->values); + + str_array_free(args); + free(objPath); + free(oFileName); + free(oFile); + free(vers); + free(name); + free(code); + free(repo); + return ret == EXIT_SUCCESS; +} +static bool +finalise_file(str_array_t *arr, buildinfo_t info) +{ + str_array_t *flags, *ldflags; + size_t i; + bool ret = true; + if (!arr) + { + return false; + } + + flags = str_array_create(); + str_array_add(flags, Compiler(info)); + + ldflags = split(info.basic.cflags); + for (i = 0; i < str_array_len(ldflags); i++) + { + str_array_add(flags, str_array_get(ldflags, i)); + } + str_array_free(ldflags); + + str_array_add(flags, "-lCytoplasm"); + + for (i = 0; i < str_array_len(arr); i++) + { + char *file = str_array_get(arr, i); + if (file) + { + size_t srclen = strncmp(file, "src", 3) ? + strlen(info.basic.obj) + 1 : + strlen(info.basic.src) + 1 ; + char *objPath = string_cat(info.basic.obj, "/"); + char *oFile = string_rep_ext(file + srclen, ".c", ".o"); + char *oFileName = string_cat(objPath, oFile); + + str_array_add(flags, oFileName); + + free(oFileName); + free(oFile); + free(objPath); + } + } + + str_array_add(flags, "-o"); + str_array_add(flags, info.basic.binary); + str_array_add(flags, NULL); + ret = exec_code(Compiler(info), flags->values); + + str_array_free(flags); + return ret; +} + +static str_array_t * +collect_sources(char *dir, bool head, char *ext) +{ + DIR *handle; + str_array_t *ret; + struct dirent *ent; + if (!dir) + { + return NULL; + } + + ret = str_array_create(); + handle = opendir(dir); + if (!handle) + { + printf("error: cannot open directory '%s'\n", dir); + return ret; + } + while ((ent = readdir(handle))) + { + char *name = ent->d_name; + if (*name == '.') continue; + + if (strlen(name) > strlen(ext) && + !strcmp(name + strlen(name) - strlen(ext), ext)) + { + char *d1 = string_cat(dir, "/"); + char *na = string_cat(d1, name); + str_array_add(ret, na); + free(d1); + free(na); + continue; + } + if (!strchr(name, '.') && + strcmp(name, "out") && + strcmp(name, "Makefile")) + { + str_array_t *sub; + char *d1 = string_cat(dir, "/"); + char *d2 = string_cat(d1, name); + size_t i; + + sub = collect_sources(d2, false, ext); + for (i = 0; i < str_array_len(sub); i++) + { + char *file = str_array_get(sub, i); + str_array_add(ret, file); + } + str_array_free(sub); + free(d2); + free(d1); + } + } + closedir(handle); + return ret; +} + +static char * +process_png(char *png, buildinfo_t info) +{ + size_t i = 0; + char *symbol; + char *cFile, *oFile; + char *pcFile, *poFile; + char *pcFile1, *poFile1; + char *filename, *symbol1; + char *arguments[8] = { 0 }; + if (!png) + { + return NULL; + } + + if (!(filename = strchrl(png, '/'))) + { + return NULL; + } + filename++; + + pcFile1= string_cat(info.basic.obj, "/"); + pcFile = string_cat(pcFile1, filename); + cFile = string_rep_ext(pcFile, ".png", ".c"); + free(pcFile); + free(pcFile1); + + poFile1= string_cat(info.basic.obj, "/"); + poFile = string_cat(poFile1, filename); + oFile = string_rep_ext(poFile, ".png", ".o"); + free(poFile); + free(poFile1); + + symbol1 = string_rep_ext(filename, ".png", ""); + symbol = string_cat("media_", symbol1); + free(symbol1); + + mkdir_rec(oFile); + mkdir_rec(cFile); + + /* Build the image into Base64 */ + arguments[i++] = "tools/out/b64"; + arguments[i++] = png; + arguments[i++] = symbol; + arguments[i++] = cFile; + arguments[i++] = NULL; + + if (exec_code(arguments[0], arguments)) + { + free(symbol); + free(cFile); + free(oFile); + return NULL; + } + + /* Compile it out */ + i = 0; + arguments[i++] = Compiler(info); + arguments[i++] = "-c"; + arguments[i++] = cFile; + arguments[i++] = "-o"; + arguments[i++] = oFile; + arguments[i++] = NULL; + + if (exec_code(arguments[0], arguments)) + { + free(symbol); + free(cFile); + free(oFile); + return NULL; + } + + free(symbol); + free(oFile); + return cFile; +} +/* Builds the entirety of Parsee. */ +static int +main_build(int argc, char *argv[]) +{ + buildinfo_t info = { 0 }; + FILE *buildinfo = NULL; + char *line = NULL; + size_t size, i; + ssize_t nread; + str_array_t *sources, *images; + + /* Step 1: Get all basic information from build.conf */ + if (!(buildinfo = fopen(DEFAULT_BUILD_PATH, "r"))) + { + printf("error: cannot open '%s'\n", DEFAULT_BUILD_PATH); + goto fail; + } + while ((nread = getline(&line, &size, buildinfo)) != -1) + { + char *eq = strchr(line, '='); + char *end = strchr(line, '\n'); + + char *key, *val; + if (!eq) + { + free(line); + printf( + "error: line in '%s' does not contain '='\n", + DEFAULT_BUILD_PATH + ); + goto fail; + } + + /* Set delimiters */ + *eq = '\0'; + if (end) *end = '\0'; + + key = line; + val = eq + 1; + + /* Now, we have KV mappings. */ +#define If(k, v, d) do \ + { \ + if (!strcmp(key, k) && !info.v) \ + { \ + info.v = string_dup(val); \ + printf("%s: %s\n", d, val); \ + } \ + } while (0) + + If("CODE", basic.codename, "Codename"); + If("NAME", basic.name, "Name"); + If("VERSION", basic.version, "Version"); + If("BINARY", basic.binary, "Binary name"); + + If("CFLAGS", basic.cflags, "C compiler arguments"); + If("LDFLAGS", basic.ldflags, "Linker arguments"); + + If("INCLUDES", basic.inc, "Include path"); + If("SOURCE", basic.src, "Source path"); + If("OBJECT", basic.obj, "Object path"); + If("CC", basic.cc, "Compiler"); + } + if (line) + { + free(line); + line = NULL; + } + + fclose(buildinfo); + buildinfo = NULL; + + /* Step 2: Get all information from commands. */ + if (!(info.repo = cmd_stdout("git remote get-url origin"))) + { + printf("error: cannot find origins url\n"); + goto fail; + } + info.repo = trim_nl(info.repo); + + if (argc >= 2 && !strcmp(argv[1], "clean")) + { + char *args[8]; + size_t i; + unlink(info.basic.binary); + + args[i++] = "rm"; + args[i++] = "-r"; + args[i++] = info.basic.obj; + args[i++] = NULL; + exec_code(args[0], args); + goto end; + } + + + /* Step 3: Build all utilities. */ + sources = collect_sources("tools", true, ".c"); + for (i = 0; i < str_array_len(sources); i++) + { + char *file = str_array_get(sources, i); + printf("\tTOOL %s...\n", file); + if (!build_file(file, info, true)) + { + str_array_free(sources); + goto fail; + } + } + str_array_free(sources); + + /* Step 4: Build all media files. */ + sources = collect_sources(info.basic.src, true, ".c"); + images = collect_sources("etc/media", true, ".png"); + for (i = 0; i < str_array_len(images); i++) + { + char *file = str_array_get(images, i); + char *out; + + out = process_png(file, info); + if (!out) + { + str_array_free(images); + str_array_free(sources); + goto fail; + } + printf("\tPNG %s\n", file); + str_array_add(sources, out); + free(out); + } + str_array_free(images); + + /* Step 5: Build all of Parsee itself */ + for (i = 0; i < str_array_len(sources); i++) + { + char *file = str_array_get(sources, i); + if (!build_file(file, info, false)) + { + str_array_free(sources); + goto fail; + } + } + printf("\tLINK\n"); + if (!finalise_file(sources, info)) + { + str_array_free(sources); + goto fail; + } + str_array_free(sources); + /* TODO: Step 6: Build every Ayadoc */ +end: + destroy_buildinfo(&info); + return EXIT_SUCCESS; +fail: + if (buildinfo) + { + fclose(buildinfo); + buildinfo = NULL; + } + destroy_buildinfo(&info); + return EXIT_FAILURE; +} + +int +main(int argc, char *argv[]) +{ + /* TODO: Multiple flags(build/install/ayadoc/...) */ + if ((argc - 1) < 1) + { + /* No arguments, let's just build. */ + return main_build(argc, argv); + } + + if (!strcmp(argv[1], "build") || + !strcmp(argv[1], "clean")) + { + return main_build(argc, argv); + } + + printf("%s: unknown verb: %s\n", argv[0], argv[1]); + return EXIT_FAILURE; +} diff --git a/build.conf b/build.conf index a2e17c1..b3ce98b 100644 --- a/build.conf +++ b/build.conf @@ -1,10 +1,8 @@ -CODE=lunar-rainbow +CODE=tomboyish-bridges-adventure NAME=Parsee -VERSION=0.3.0 +VERSION=0.1.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 index 9015d20..fd4a582 100644 --- a/etc/man/man1/parsee-adminify.1 +++ b/etc/man/man1/parsee-adminify.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-adminify 1 "Parsee Utility" "star-of-hope" +.TH parsee-adminify 1 "Parsee Utility" "tomboyish-bridges-adventure" .SH NAME parsee-adminify - bootstrap an admin to a new Parsee server diff --git a/etc/man/man1/parsee-aya.1 b/etc/man/man1/parsee-aya.1 index b51afa0..bb5caac 100644 --- a/etc/man/man1/parsee-aya.1 +++ b/etc/man/man1/parsee-aya.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-aya 1 "Parsee Utility" "star-of-hope" +.TH parsee-aya 1 "Parsee Utility" "tomboyish-bridges-adventure" .SH NAME parsee-aya - generate some nice Ayaya! documentation diff --git a/etc/man/man1/parsee-config.1 b/etc/man/man1/parsee-config.1 index 5dc258b..cb6e999 100644 --- a/etc/man/man1/parsee-config.1 +++ b/etc/man/man1/parsee-config.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-config 1 "Parsee Utility" "lunar-rainbow" +.TH parsee-config 1 "Parsee Utility" "tomboyish-bridges-adventure" .SH NAME parsee-config - generate a basic configuration file @@ -11,10 +11,8 @@ parsee-config .B [-s SHARED_SECRET] .B [-m MEDIA_URL] .B [-J JABBER_HOST] -.B [-j JABBER_ADDR] .B [-p JABBER_PORT] .B [-d DATABASE] -.B [-M MAX_STANZA] .B [-S DATABASE size] .SH DESCRIPTION @@ -35,7 +33,6 @@ $ parsee-config \\ -H 'blow.hole' \\ -s 'The Dark Shared Secret' \\ -J 'xmpp.blow.hole' \\ - -j 'localhost' \\ -S 128 .fi .if n \{\ @@ -57,10 +54,6 @@ For example, if you except Parsee users to be on .I SHARED_SECRET is a shared secret known by Parsee and the XMPP component to authenticate. .TP -.BR -M MAX_STANZA -.I MAX_STANZA -is the maximum stanza size accepted by the XMPP host. If it is less than 10000 bytes, then it shall be set to that limit(the standardised value). -.TP .BR -m MEDIA_URL .I MEDIA_URL is an optional field used by Parsee as an address that points to Matrix @@ -70,12 +63,6 @@ media. It must be publicly accessible (behind a reverse proxy to HTTP:7642) .I JABBER_HOST is used as the component host for Parsee. .TP -.BR -j JABBER_ADDR -.I JABBER_ADDR -can optionally be used to change the hostname Parsee will try to contact -for XMPP. Users should ideally use localhost (or a hostname pointing to -the server itself), as XMPP component streams are not encrypted. -.TP .BR -p JABBER_PORT .I JABBER_PORT is used as the component post for Parsee. Parsee uses it alongside diff --git a/etc/man/man1/parsee.1 b/etc/man/man1/parsee.1 index d7eeedf..093af7b 100644 --- a/etc/man/man1/parsee.1 +++ b/etc/man/man1/parsee.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee 1 "Parsee Utility" "star-of-hope" +.TH parsee 1 "Parsee Utility" "tomboyish-bridges-adventure" .SH NAME parsee - the jealous XMPP-Matrix bridge 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/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/Indicators.c b/src/AS/Indicators.c index 9797649..afe860a 100644 --- a/src/AS/Indicators.c +++ b/src/AS/Indicators.c @@ -30,9 +30,8 @@ ASType(const ParseeConfig *c, char *user, char *room, bool status) 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)); + /* 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); diff --git a/src/AS/Media.c b/src/AS/Media.c index 5fbc659..4e642e9 100644 --- a/src/AS/Media.c +++ b/src/AS/Media.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -15,7 +14,7 @@ char * ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) { char *size_str, *path, *ret, *user; - unsigned int i; + int i; HttpClientContext *ctx; HashMap *reply; if (!c || !from) @@ -128,93 +127,3 @@ ASReupload(const ParseeConfig *c, char *from, char **mime) return ret; } -bool -ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha) -{ - HttpClientContext *cctx; - Stream *stream; - Stream *fake; - Uri *uri; - char *path, *buf = NULL; - unsigned char *sha1; - size_t len; - 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 index 3a8ffb7..88ac7cb 100644 --- a/src/AS/Ping.c +++ b/src/AS/Ping.c @@ -10,16 +10,15 @@ #include -bool +void ASPing(const ParseeConfig *conf) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path; - bool ret; if (!conf) { - return false; + return; } path = StrConcat(3, @@ -34,9 +33,7 @@ ASPing(const ParseeConfig *conf) Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); - ret = ParseeSetRequestJSON(ctx, json) == HTTP_OK; + ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); - - return ret; } diff --git a/src/AS/Profile.c b/src/AS/Profile.c index 1f1a0da..73e9b4b 100644 --- a/src/AS/Profile.c +++ b/src/AS/Profile.c @@ -136,71 +136,3 @@ ASGetName(const ParseeConfig *c, char *room, char *user) } return ret; } -char * -ASGetAvatar(const ParseeConfig *c, char *room, char *user) -{ - HttpClientContext *ctx; - HashMap *reply; - char *path = NULL, *ret = NULL; - char *u2 = user; - if (!c || !user) - { - return NULL; - } - - if (room) - { - user = HttpUrlEncode(user); - room = HttpUrlEncode(room); - path = StrConcat(4, - "/_matrix/client/v3/rooms/", room, - "/state/m.room.member/", user - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(user); - Free(room); - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "avatar_url")) - ); - HttpClientContextFree(ctx); - JsonFree(reply); - Free(path); - - user = u2; - - Log(LOG_DEBUG, "ASGetAvatar: trying to grab avatar from room, got %s", ret); - } - - if (!ret) - { - user = HttpUrlEncode(user); - path = StrConcat(3, - "/_matrix/client/v3/profile/", user, "/avatar_url" - ); - ctx = ParseeCreateRequest(c, HTTP_GET, path); - Free(user); - user = u2; - ASAuthenticateRequest(c, ctx); - HttpRequestSendHeaders(ctx); - HttpRequestSend(ctx); - - reply = JsonDecode(HttpClientStream(ctx)); - - ret = StrDuplicate( - JsonValueAsString(HashMapGet(reply, "avatar_url")) - ); - 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/Relations.c b/src/AS/Relations.c index e9baa5a..4809413 100644 --- a/src/AS/Relations.c +++ b/src/AS/Relations.c @@ -25,15 +25,7 @@ ASGetRelations(const ParseeConfig *c, size_t n, char *room, char *event, char *t } 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 + if (event) { path = StrConcat(6, "/_matrix/client/v1/rooms/", room, @@ -41,6 +33,13 @@ ASGetRelations(const ParseeConfig *c, size_t n, char *room, char *event, char *t "?user_id=", user ); } + else + { + path = StrConcat(4, + "/_matrix/client/v1/rooms/", room, + "/relations?user_id=", user + ); + } Free(user); ctx = ParseeCreateRequest(c, HTTP_GET, path); diff --git a/src/AS/Room.c b/src/AS/Room.c index e9691e1..3bc7cbf 100644 --- a/src/AS/Room.c +++ b/src/AS/Room.c @@ -25,13 +25,11 @@ ASInvite(const ParseeConfig *conf, char *id, char *invited) "@", conf->sender_localpart, ":", conf->server_base ); - id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/invite", "?user_id=", bridge ); Free(bridge); - Free(id); ctx = ParseeCreateRequest( conf, @@ -62,13 +60,11 @@ ASBan(const ParseeConfig *conf, char *id, char *banned) "@", conf->sender_localpart, ":", conf->server_base ); - id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/ban", "?user_id=", bridge ); Free(bridge); - Free(id); ctx = ParseeCreateRequest( conf, @@ -77,7 +73,7 @@ ASBan(const ParseeConfig *conf, char *id, char *banned) Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString(NAME " felt jealous.")); + HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); @@ -99,13 +95,11 @@ ASKick(const ParseeConfig *conf, char *id, char *banned) "@", conf->sender_localpart, ":", conf->server_base ); - id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/kick", "?user_id=", bridge ); Free(bridge); - Free(id); ctx = ParseeCreateRequest( conf, @@ -114,7 +108,7 @@ ASKick(const ParseeConfig *conf, char *id, char *banned) Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(banned)); - HashMapSet(json, "reason", JsonValueString(NAME " felt jealous.")); + HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); @@ -126,8 +120,7 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) { HttpClientContext *ctx = NULL; HashMap *json = NULL; - char *path, *ret, *serv; - int status; + char *path, *ret; if (!conf || !id) { return NULL; @@ -146,11 +139,6 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) { masquerade = HttpUrlEncode(masquerade); } - serv = strchr(id, ':'); - if (serv) - { - serv = serv + 1; - } id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/join/", id, "?", @@ -164,7 +152,7 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); - status = ParseeSetRequestJSON(ctx, json); + ParseeSetRequestJSON(ctx, json); JsonFree(json); json = JsonDecode(HttpClientStream(ctx)); @@ -175,8 +163,6 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade) Free(masquerade); Free(id); - (void) serv; // TODO - return ret; } void diff --git a/src/AS/Send.c b/src/AS/Send.c index 6811548..4032423 100644 --- a/src/AS/Send.c +++ b/src/AS/Send.c @@ -1,43 +1,21 @@ #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) +ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) { 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) { @@ -45,27 +23,18 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c, u return NULL; } - if (!ts) - { - ts = UtilTsMillis(); - } - ts_str = TSToStr(ts); - txn = StrRandom(16); - id = HttpUrlEncode(id); - path = StrConcat(11, + path = StrConcat(9, "/_matrix/client/v3/rooms/", id, "/send/", type, "/", txn, "?", - "user_id=", user, "&ts=", ts_str + "user_id=", user ); - Free(id); Free(txn); - Free(ts_str); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); ASAuthenticateRequest(conf, ctx); - status = ParseeSetRequestJSON(ctx, c); + ParseeSetRequestJSON(ctx, c); reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); diff --git a/src/Command/Parser.c b/src/Command/Parser.c index 65f295b..2101254 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); @@ -53,7 +53,7 @@ CommandParse(char *cmd) 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..e3c4ff3 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, false); Free(rev); } diff --git a/src/Commands/Stats.c b/src/Commands/Stats.c index 0df0b44..219204a 100644 --- a/src/Commands/Stats.c +++ b/src/Commands/Stats.c @@ -40,6 +40,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..e625d07 100644 --- a/src/Events.c +++ b/src/Events.c @@ -79,7 +79,7 @@ MatrixCreateNickChange(char *nick) return map; } HashMap * -MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info) +MatrixCreateMedia(char *mxc, char *body, char *mime) { HashMap *map; char *mime_type = NULL, *matrix_type = NULL; @@ -91,10 +91,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 +119,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)); 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/HttParsee.c b/src/HttParsee.c index 572487c..724f9ff 100644 --- a/src/HttParsee.c +++ b/src/HttParsee.c @@ -73,7 +73,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..652512c 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 @@ -48,7 +46,7 @@ static const Argument arguments[] = "Generates a parsee.yaml AS file before exiting") Arg('v', false, NULL, "Forces Parsee to print in a more verbose fashion " - "(-vvv prints stanzas to stderr)") + "(-vv prints stanzas to stderr)") Arg('h', false, NULL, "Generates an help screen(this one!)") @@ -58,50 +56,6 @@ static const Argument arguments[] = #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) { @@ -124,15 +78,6 @@ Main(Array *args, HashMap *env) ); 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()); { @@ -158,8 +103,6 @@ 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); @@ -170,9 +113,6 @@ Main(Array *args, HashMap *env) case PARSEE_VERBOSE_LOG: LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG); break; - case PARSEE_VERBOSE_TIMINGS: - Log(LOG_DEBUG, "Logging bench information."); - break; case PARSEE_VERBOSE_STANZA: Log(LOG_DEBUG, "Enabling stanza printing."); break; @@ -205,6 +145,7 @@ Main(Array *args, HashMap *env) } } Free(opts); + ParseeSetThreads(xmpp, http); } if (verbose >= PARSEE_VERBOSE_COMICAL) @@ -218,16 +159,13 @@ Main(Array *args, HashMap *env) { 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 @@ -268,12 +206,6 @@ Main(Array *args, HashMap *env) } ParseeInitialiseNickTable(); - if (verbose >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "Initialising affiliation table"); - } - ParseeInitialiseAffiliationTable(); - conf.port = parsee_conf->port; conf.threads = parsee_conf->http_threads; conf.maxConnections = conf.threads << 2; @@ -291,21 +223,18 @@ Main(Array *args, HashMap *env) 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); CronStart(cron); @@ -318,9 +247,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 +272,9 @@ 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..82d4cf8 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -8,29 +8,24 @@ #include #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) +static void +JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) { 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 *nick = StrDuplicate(name); 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) + while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 32) { char *nonce_str = StrInt(nonce); char *input = StrConcat(3, sender, name, nonce_str); @@ -55,7 +50,7 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name, char ParseePushNickTable(muc, sender, nick); Free(nick); - return (rev); + Free(rev); } static void @@ -98,95 +93,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); - Free(jabber); - Free(avatar); + JoinMUC(data, event, jid, muc, name); Free(name); 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")) @@ -255,9 +175,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 +192,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 +214,10 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) char *room_id = GrabString(event, 1, "room_id"); char *matrix_sender = GrabString(event, 1, "sender"); char *chat_id = NULL, *muc_id = NULL; - char *user = NULL; + char *user; - DbRef *room_data = NULL; - HashMap *data_json = NULL; + DbRef *room_data; + HashMap *data_json; bool direct = false; if (!data || !event || !from || !to) @@ -324,8 +249,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_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -339,16 +263,10 @@ 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); - - ASGetMIMESHA(data->config, matrix_avatar, &mime, &sha); - Free(JoinMUC(data, event, *from, muc_id, matrix_name, sha)); + JoinMUC(data, event, *from, muc_id, matrix_name); *to = muc_id; - Free(matrix_avatar); Free(matrix_name); - Free(mime); - Free(sha); } Free(chat_id); @@ -358,47 +276,28 @@ 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)) { @@ -429,7 +328,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) type = direct ? "chat" : "groupchat"; user = GrabString(json, 1, "xmpp_user"); - unauth = ParseeToUnauth(data, url, GrabString(event, 2, "content", "filename")); + unauth = ParseeToUnauth(data, url); encoded_from = ParseeEncodeMXID(m_sender); xmppified_user = StrConcat(3, @@ -443,8 +342,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) } else { - char *name, *mime = NULL, *sha = NULL; - char *avatar; + char *name; /* Try to find the chat ID */ muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -452,21 +350,17 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) goto end; } - /* 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); - Free(JoinMUC(data, event, encoded_from, muc_id, name, sha)); + JoinMUC(data, event, encoded_from, muc_id, name); to = muc_id; - Free(sha); - Free(mime); Free(name); - Free(avatar); } - if (reply_id) { /* TODO: Monocles chat DM users HATE this trick! @@ -500,7 +394,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) SetStanzaEdit(builder, origin_id); SetStanzaXParsee(builder, event); - WriteoutStanza(builder, jabber, data->config->max_stanza_size); + WriteoutStanza(builder, jabber); DestroyStanzaBuilder(builder); if (direct) @@ -523,8 +417,8 @@ end: Free(stanza); Free(sender); Free(unauth); - Free(encoded_from); Free(unedited_id); + Free(encoded_from); DbUnlock(data->db, ref); ref = NULL; @@ -555,7 +449,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 index bb7c584..4488fd4 100644 --- a/src/MatrixID.c +++ b/src/MatrixID.c @@ -1,9 +1,6 @@ #include #include -#include -#include -#include #include @@ -35,34 +32,3 @@ MatrixParseID(char *user) return ret; } -UserID * -MatrixParseIDFromMTO(Uri *uri) -{ - UserID *id = NULL; - char *path, *params, *decoded; - if (!uri) - { - return NULL; - } - - if (!StrEquals(uri->proto, "https") || !StrEquals(uri->host, "matrix.to")) - { - return NULL; - } - if (strncmp(uri->path, "/#/", 3)) - { - return NULL; - } - path = StrDuplicate(uri->path + 3); - params = path ? strchr(path, '?') : NULL; - if (params) - { - *params = '\0'; - } - decoded = HttpUrlDecode(path); - id = MatrixParseID(decoded); - Free(decoded); - Free(path); - - return id; -} diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index b95e5e1..72eff53 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -30,18 +30,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 +44,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 +58,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 +77,6 @@ ParseeSetThreads(int xmpp, int http) { if (!config) { - Achievement("THREAD COUNT REQUEST WITHOUT CONFIG", true); return; } config->http_threads = http; @@ -113,7 +88,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 +101,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 +109,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 +119,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..f5c20fe 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -27,15 +26,11 @@ 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); @@ -55,16 +50,14 @@ ParseeInitData(XMPPComponent *comp) char *id = StrRandom(64); ref = DbCreate(data->db, 1, "info"); HashMapSet(DbJson(ref), "identifier", JsonValueString(id)); - HashMapSet(DbJson(ref), "version", JsonValueString(VERSION)); Free(id); } version = GrabString(DbJson(ref), 1, "version"); - if (version && !ParseeIsCompatible(VERSION, version)) + if (!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); @@ -114,10 +107,8 @@ ParseeFreeData(ParseeData *data) } 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); @@ -132,6 +123,9 @@ ParseeCleanup(void *datp) char *chat; size_t i; uint64_t ts = UtilTsMillis(); + size_t entries = 0; + + Log(LOG_DEBUG, "Cleaning up..."); chats = DbList(data->db, 1, "chats"); @@ -175,6 +169,7 @@ ParseeCleanup(void *datp) if (cleaned > threshold) \ { \ DbDelete(data->db, 4, "chats", chat, #field"s", field); \ + entries++; \ } \ Free(field); \ } \ @@ -182,12 +177,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); @@ -231,6 +223,7 @@ ParseeCleanup(void *datp) if (cleaned > threshold) \ { \ JsonValueFree(HashMapDelete(field##s, field)); \ + entries++; \ } \ Free(field); \ } \ @@ -238,13 +231,14 @@ 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); + Log(LOG_DEBUG, "Cleant up %d entries...", entries); } void @@ -339,15 +333,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 +535,3 @@ 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) -{ - DbRef *ref; - HashMap *json; - if (!data || !chat || !key || !val) - { - return; - } - - ref = DbLockIntent(data->db, DB_HINT_WRITE, - 3, "chats", chat, "settings" - ); - if (!ref) - { - ref = DbCreate(data->db, 3, "chats", chat, "settings"); - } - json = DbJson(ref); - - JsonValueFree(HashMapSet(json, key, JsonValueString(val))); - - DbUnlock(data->db, ref); - return; -} -bool -ParseeIsMediaEnabled(ParseeData *data, char *chat_id) -{ - char *value; - bool ret; - if (!data || !chat_id) - { - return false; - } - - ret = !StrEquals( - (value = ParseeGetChatSetting(data, chat_id, "p.media.enabled")), - "false" - ); - Free(value); - - return ret; -} diff --git a/src/Parsee/Logo.c b/src/Parsee/Logo.c index 30885d9..245a91c 100644 --- a/src/Parsee/Logo.c +++ b/src/Parsee/Logo.c @@ -4,10 +4,11 @@ const char *parsee_ascii[PARSEE_ASCII_LINES] = { + "----------------------------", " =+======", " || | _ _/__----", " / || \\ ==+= _/_____\\_", - " | || | -|- L___J ", + " | || | -|- L___J", "_/ || \\_ ||| .______\\", " || | | | |.____.|", " || / | \\ |L____||", 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/User.c b/src/Parsee/User.c index 6e673bb..c751731 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -1,7 +1,6 @@ #include #include -#include #include #include #include @@ -148,15 +147,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 +164,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 +193,7 @@ char * ParseeGetLocal(char *mxid) { char *cpy; - size_t i, len; + size_t i; if (!mxid) { return NULL; @@ -205,14 +203,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,16 +224,15 @@ 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]; @@ -361,6 +356,8 @@ ParseePushDMRoom(ParseeData *d, char *mxid, char *jid, char *r) void ParseeDeleteDM(ParseeData *d, char *mxid, char *jid) { + DbRef *ref; + HashMap *j; char *dmid; if (!d || !mxid || !jid) { @@ -377,15 +374,14 @@ 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 +535,7 @@ ParseeGetMUCID(ParseeData *data, char *chat_id) return ret; } + void ParseeSendPresence(ParseeData *data) { @@ -557,16 +554,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, false); - DbUnlock(data->db, chat); - Free(chat_id); Free(rev); } DbUnlock(data->db, ref); @@ -688,13 +679,12 @@ 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?hmac=%s" size_t l; if (!data || !mxc) { @@ -715,45 +705,19 @@ ParseeToUnauth(ParseeData *data, char *mxc, char *filename) 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); - } + l = snprintf(NULL, 0, + PAT, + data->config->media_base, + url->host, url->path, + hmac + ); 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, + hmac + ); UriFree(url); Free(hmac); return ret; diff --git a/src/Parsee/Utils/Formatting.c b/src/Parsee/Utils/Formatting.c index ec95aef..4e89aec 100644 --- a/src/Parsee/Utils/Formatting.c +++ b/src/Parsee/Utils/Formatting.c @@ -5,14 +5,11 @@ #include #include #include -#include -#include #include #include #include -#include #include #include @@ -20,7 +17,7 @@ typedef struct XMPPFlags { bool quote; } XMPPFlags; static char * -XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPFlags flags) +XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags) { char *xepd = NULL, *tmp = NULL; @@ -58,7 +55,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF } \ } \ while (0) - switch (elem ? elem->type : -1) + switch (elem->type) { case XML_ELEMENT_DATA: Concat(elem->data); @@ -70,7 +67,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); + subxep = XMPPifyElement(event, child, flags); Concat(subxep); Free(subxep); @@ -83,7 +80,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); + subxep = XMPPifyElement(event, child, flags); Concat(subxep); Free(subxep); @@ -96,7 +93,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); + subxep = XMPPifyElement(event, child, flags); Concat(subxep); Free(subxep); @@ -129,7 +126,7 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); + subxep = XMPPifyElement(event, child, flags); Concat(subxep); Free(subxep); @@ -144,70 +141,35 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); + subxep = XMPPifyElement(event, child, flags); Concat(subxep); Free(subxep); } - if (i != 0) - { - Concat("\n"); - } + 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")) + Concat("("); + for (i = 0; i < ArraySize(elem->children); i++) { - /* 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); + child = ArrayGet(elem->children, i); + subxep = XMPPifyElement(event, child, flags); - Concat(subxep); - Free(subxep); - } - Concat(" < "); - Concat(href); - Concat(" >"); + Concat(subxep); + Free(subxep); } - UriFree(pref); + Concat(" points to "); + Concat(href); + Concat(" )"); } else { for (i = 0; i < ArraySize(elem->children); i++) { child = ArrayGet(elem->children, i); - subxep = XMPPifyElement(conf, event, child, flags); + subxep = XMPPifyElement(event, child, flags); Concat(subxep); Free(subxep); @@ -219,45 +181,8 @@ XMPPifyElement(const ParseeConfig *conf, HashMap *event, XMLElement *elem, XMPPF } 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) +ParseeXMPPify(HashMap *event) { char *type, *format, *html; char *xepd = NULL; @@ -276,28 +201,20 @@ ParseeXMPPify(ParseeData *data, HashMap *event) return NULL; } - if (!StrEquals(GetBodyFormat(event), "org.matrix.custom.html")) + format = JsonValueAsString(JsonGet(event, 2, "content", "format")); + if (!StrEquals(format, "org.matrix.custom.html")) { /* Settle for the raw body instead. */ - char *body = GetRawBody(event); + char *body = JsonValueAsString(JsonGet(event, 2, "content", "body")); return StrDuplicate(body); } - html = GetHTMLBody(event); - + html = JsonValueAsString(JsonGet(event, 2, "content", "formatted_body")); 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); + xepd = XMPPifyElement(event, elem, flags); XMLFreeElement(elem); Free(html); @@ -314,7 +231,6 @@ ParseeGenerateMTO(char *common_id) return NULL; } - /* TODO: Is HttpUrlEncode okay? */ common_id = HttpUrlEncode(common_id); matrix_to = StrConcat(2, "https://matrix.to/#/", common_id); Free(common_id); diff --git a/src/Parsee/Utils/Nofly.c b/src/Parsee/Utils/Nofly.c index 439c7d0..8a82c0f 100644 --- a/src/Parsee/Utils/Nofly.c +++ b/src/Parsee/Utils/Nofly.c @@ -6,28 +6,6 @@ #include #include -void -ParseeGlobalUnban(ParseeData *data, char *glob) -{ - DbRef *ref; - HashMap *j; - if (!data || !glob) - { - return; - } - - ref = DbLock(data->db, 1, "global_bans"); - if (!ref) - { - ref = DbCreate(data->db, 1, "global_bans"); - } - - j = DbJson(ref); - - JsonValueFree(HashMapDelete(j, glob)); - - DbUnlock(data->db, ref); -} void ParseeGlobalBan(ParseeData *data, char *glob, char *reason) { diff --git a/src/Parsee/Utils/String.c b/src/Parsee/Utils/String.c index c054d13..89d6f4a 100644 --- a/src/Parsee/Utils/String.c +++ b/src/Parsee/Utils/String.c @@ -3,8 +3,6 @@ #include #include -#include - #include #include @@ -39,22 +37,6 @@ ParseeFindDatastart(char *data) return (int) (startline - data); } -int -ParseeFindDatastartU(char *data) -{ - Unistr *str; - size_t ret; - if (!data) - { - return 0; - } - - str = UnistrCreate(data); - ret = UnistrGetOffset(str, (uint32_t) '>'); - UnistrFree(str); - - return (int) ret; -} char * ParseeStringifyDate(uint64_t millis) diff --git a/src/Routes/Media.c b/src/Routes/Media.c index 498eba2..7d6bc68 100644 --- a/src/Routes/Media.c +++ b/src/Routes/Media.c @@ -10,37 +10,6 @@ #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; @@ -48,7 +17,7 @@ RouteHead(RouteMedia, arr, argp) HashMap *reqh, *params; char *server = ArrayGet(arr, 0); char *identi = ArrayGet(arr, 1); - char *key, *val; + char *path, *key, *val; char *hmac, *chkmak = NULL; params = HttpRequestParams(args->ctx); @@ -75,7 +44,15 @@ RouteHead(RouteMedia, arr, argp) /* 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 +65,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 deleted file mode 100644 index 1d4191e..0000000 --- a/src/Routes/Ping.c +++ /dev/null @@ -1,36 +0,0 @@ -#include - -#include - -#include -#include - -RouteHead(RoutePing, arr, argp) -{ - ParseeHttpArg *args = argp; - HashMap *request = NULL; - HashMap *response = NULL; - - response = ASVerifyRequest(args); - if (response) - { - goto end; - } - if (HttpRequestMethodGet(args->ctx) != HTTP_POST) - { - HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); - response = MatrixCreateError( - "M_UNRECOGNIZED", - "Path /ping only accepts POST as a valid method." - ); - goto end; - } - - RequestJSON(); - - response = HashMapCreate(); -end: - (void) arr; - JsonFree(request); - return response; -} diff --git a/src/Routes/Root.c b/src/Routes/Root.c index 0ddb731..af89909 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -54,13 +54,7 @@ GetRandomQuote(void) 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 !" + "Go take a look at your objects!" }; const size_t count = sizeof(quotes)/sizeof(*quotes); @@ -90,13 +84,11 @@ RouteHead(RouteRoot, arr, argp) P("color: #eee;"); P("font-family: sans-serif;"); P("}"); - P("#ascii {"); - P("text-align: center;"); - P("color: #be1337;"); - P("}"); - P("#ascii pre {"); - P("display: inline-block;"); - P("text-align: left;"); + P("#cols {"); + P("column-count: 3;"); + P("min-width: 100%;"); + P("max-width: 100%;"); + P("width: 100%;"); P("}"); P("img {"); P("image-rendering: pixelated;"); @@ -123,7 +115,6 @@ RouteHead(RouteRoot, arr, argp) P(""); { - size_t i; P("
"); P("

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

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

"); { @@ -179,7 +161,7 @@ RouteHead(RouteRoot, arr, argp) P("

"); { P("More information available at "); - P("the actual page."); } @@ -254,6 +236,5 @@ RouteHead(RouteRoot, arr, argp) P(""); #undef P - (void) arr; return NULL; } diff --git a/src/Routes/Transactions.c b/src/Routes/Transactions.c index 580e43c..27e7393 100644 --- a/src/Routes/Transactions.c +++ b/src/Routes/Transactions.c @@ -42,7 +42,6 @@ RouteHead(RouteTxns, arr, argp) response = HashMapCreate(); end: - (void) arr; JsonFree(request); return response; } diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c index 50029ba..9bb17e2 100644 --- a/src/Routes/UserAck.c +++ b/src/Routes/UserAck.c @@ -67,8 +67,7 @@ RouteHead(RouteRoomAck, arr, argp) } muc = ParseeDecodeLocalMUC(args->data->config, room); - if (ParseeManageBan(args->data, muc, NULL) || - ParseeIsMUCWhitelisted(args->data, muc)) + if (ParseeManageBan(args->data, muc, NULL)) { HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); response = MatrixCreateError( @@ -131,7 +130,7 @@ RouteHead(RouteRoomAck, arr, argp) { char *rev = StrConcat(2, muc, "/parsee"); Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(args->data->jabber, "parsee", rev, NULL, -1, false); + XMPPJoinMUC(args->data->jabber, "parsee", rev, false); Free(rev); } diff --git a/src/Signal.c b/src/Signal.c index 3f01dcb..85e771c 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -6,35 +6,32 @@ #include -static ParseeData *data; +static HttpServer *server = NULL; static pthread_t xmpp_thr; +static XMPPComponent *jabber = NULL; static void SignalHandler(int signal) { - if (data->server && (signal == SIGTERM || signal == SIGINT)) + if (server && (signal == SIGTERM || signal == SIGINT)) { Log(LOG_INFO, "Killing thread..."); - - pthread_mutex_lock(&data->halt_lock); - data->halted = true; - pthread_mutex_unlock(&data->halt_lock); - - XMPPFinishCompStream(data->jabber); + XMPPFinishCompStream(jabber); pthread_join(xmpp_thr, NULL); Log(LOG_INFO, "Stopping server..."); - HttpServerStop(data->server); + HttpServerStop(server); return; } } bool -ParseeInitialiseSignals(ParseeData *d, pthread_t xmpp) +ParseeInitialiseSignals(HttpServer *s, pthread_t xmpp, XMPPComponent *j) { struct sigaction sa; - data = d; + server = s; xmpp_thr = xmpp; + jabber = j; sigfillset(&sa.sa_mask); sa.sa_handler = SignalHandler; diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index f03c3b6..5426f80 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -40,7 +40,6 @@ CreateStanzaBuilder(char *from, char *to, char *id) builder->replying_to_stanza = NULL; builder->replying_to_sender = NULL; - builder->editing = NULL; builder->type = NULL; builder->body = NULL; builder->oob = NULL; @@ -185,7 +184,7 @@ ExportStanza(StanzaBuilder *builder) builder->replying_to_sender && builder->body) { - int off = ParseeFindDatastartU(builder->body); + int off = ParseeFindDatastart(builder->body); char *ostr = StrInt(off); XMLElement *reply = XMLCreateTag("reply"); XMLElement *fallback = XMLCreateTag("fallback"); @@ -228,21 +227,22 @@ ExportStanza(StanzaBuilder *builder) } void -WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max) +WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber) { XMLElement *elem; if (!builder || !jabber) { return; } - if (!max) - { - max = 10000; /* XMPP recommended limit */ - } elem = ExportStanza(builder); - XMPPSendStanza(jabber, elem, max); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, elem); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + XMLFreeElement(elem); + return; } StanzaBuilder * @@ -258,6 +258,7 @@ SetStanzaXParsee(StanzaBuilder *builder, HashMap *e) { XMLElement *parsee_version, *ver_elem; XMLElement *parsee_link, *link_elem; + XMLElement *parsee_text, *text_elem; XMLElement *parsee_event, *event_elem; XMLElement *parsee_json, *json_elem; char *event_id = GrabString(e, 1, "event_id"); @@ -284,6 +285,16 @@ SetStanzaXParsee(StanzaBuilder *builder, HashMap *e) XMLAddChild(parsee_link, link_elem); XMLAddChild(parsee, parsee_link); + parsee_text = XMLCreateTag("zayds-note"); + text_elem = XMLCreateText("\"LDA HANG YOURSELF\" - Zayd"); + XMLAddChild(parsee_text, text_elem); + XMLAddChild(parsee, parsee_text); + + parsee_text = XMLCreateTag("mcnebs-note"); + text_elem = XMLCreateText("LDA will never beat the allegations"); + XMLAddChild(parsee_text, text_elem); + XMLAddChild(parsee, parsee_text); + if (event_id) { parsee_event = XMLCreateTag("event-id"); diff --git a/src/StrSplit.c b/src/StrSplit.c index eccd97f..91ecec7 100644 --- a/src/StrSplit.c +++ b/src/StrSplit.c @@ -7,6 +7,7 @@ #include #include #include +#include char ** StrSplitLines(char *text) @@ -116,7 +117,7 @@ StrFullRect(char **split) char StrGet(StringRect *rect, int line, int col) { - size_t actual_line, actual_col; + int actual_line, actual_col; char *linep; if (!rect || !rect->source_lines) { @@ -149,7 +150,7 @@ StrGet(StringRect *rect, int line, int col) size_t StrViewChars(StringRect rect, int line) { - size_t actual_line; + int actual_line; char *linep; if (!rect.source_lines) { @@ -173,7 +174,7 @@ StrViewChars(StringRect rect, int line) StringRect StrGetl(StringRect *rect, int line, bool extend) { - size_t actual_line; + int actual_line; StringRect ret; if (!rect->source_lines) { @@ -203,7 +204,7 @@ StrGetl(StringRect *rect, int line, bool extend) StringRect StrShift(StringRect rect, int n) { - size_t new = rect.start_char + n; + int new = rect.start_char + n; if (new > rect.end_char) { new = rect.end_char; diff --git a/src/Streams/Reader.c b/src/Streams/Reader.c index bca261a..2c0613a 100644 --- a/src/Streams/Reader.c +++ b/src/Streams/Reader.c @@ -10,10 +10,10 @@ Stream * StrStreamReaderN(char *buffer, int n) { - if (!buffer || n < 0) + if (!buffer) { return NULL; } - return StreamFile(fmemopen(buffer, n ? (size_t) n : strlen(buffer), "rb")); + return StreamFile(fmemopen(buffer, n ? n : strlen(buffer), "rb")); } diff --git a/src/Streams/Writer.c b/src/Streams/Writer.c index c29b026..88bc7ee 100644 --- a/src/Streams/Writer.c +++ b/src/Streams/Writer.c @@ -11,9 +11,6 @@ static ssize_t ReadStreamWriter(void *coop, void *to, size_t n) { /* Reading from a stream writer is silly. */ - (void) coop; - (void) to; - (void) n; return 0; } static ssize_t @@ -36,9 +33,6 @@ static off_t SeekStreamWriter(void *coop, off_t mag, int sgn) { /* TODO: Seeking would be useful, though not supported yet. */ - (void) coop; - (void) mag; - (void) sgn; return 0; } @@ -46,11 +40,10 @@ static int CloseStreamWriter(void *coop) { /* Nothing to free as of now. */ - (void) coop; return 0; } -static const IoFunctions Functions = { +const static IoFunctions Functions = { .read = ReadStreamWriter, .seek = SeekStreamWriter, .write = WriteStreamWriter, diff --git a/src/Unistr.c b/src/Unistr.c deleted file mode 100644 index 7eab2e0..0000000 --- a/src/Unistr.c +++ /dev/null @@ -1,314 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include - -struct Unistr { - size_t length; - uint32_t *codepoints; -}; - -void -UnistrAddch(Unistr *unistr, uint32_t u) -{ - if (!unistr || !u) - { - return; - } - unistr->length++; - unistr->codepoints = Realloc( - unistr->codepoints, - unistr->length * sizeof(*unistr->codepoints) - ); - - unistr->codepoints[unistr->length - 1] = u; -} - -static bool -UTFIsN(char *off, size_t available, size_t n, uint8_t pc) -{ - size_t i; - uint8_t *offu = (uint8_t *) off; - if (((available < n) || ((*offu >> (8-n-1)) != pc)) && (n >= 1)) - { - return false; - } - - for (i = 0; i < n - 1; i++) - { - if ((offu[i+1] >> 6) != 0x2) - { - return false; - } - } - return true; -} - -Unistr * -UnistrCreate(char *src) -{ - size_t len, i; - Unistr *str; - if (!src) - { - return NULL; - } - - len = strlen(src); - str = Malloc(sizeof(*str)); - str->length = 0; - str->codepoints = NULL; - - /* We can't just set the length to {len}. */ - for (i = 0; i < len; i++) - { - char byte = src[i]; - size_t available = len - i; - if ((byte & 0x80) == 0) - { - /* This is a regular codepoint */ - UnistrAddch(str, byte & 0x7F); - continue; - } - else if (UTFIsN(&src[i], available, 2, 0x06)) - { - char a = src[i+0] & 0x1F; - char b = src[i+1] & 0x3F; - uint32_t u = (a << (6 * 1)) | b; - - /* Overlongs are errors. */ - if (u < 0x0080 || u > 0x07FF) - { - UnistrFree(str); - return NULL; - } - - UnistrAddch(str, u); - i += 2 - 1; - continue; - } - else if (UTFIsN(&src[i], available, 3, 0x0E)) - { - char a = src[i+0] & 0x0F; - char b = src[i+1] & 0x3F; - char c = src[i+2] & 0x3F; - uint32_t u = - (a << (6 * 2)) | - (b << (6 * 1)) | - (c << (6 * 0)) ; - - /* Overlongs are errors. */ - if (u < 0x0800 || u > 0xFFFF) - { - UnistrFree(str); - return NULL; - } - - UnistrAddch(str, u); - i += 3 - 1; - continue; - } - else if (UTFIsN(&src[i], available, 4, 0x1E)) - { - char a = src[i+0] & 0x07; - char b = src[i+1] & 0x3F; - char c = src[i+2] & 0x3F; - char d = src[i+3] & 0x3F; - uint32_t u = - (a << (6 * 3)) | - (b << (6 * 2)) | - (c << (6 * 1)) | - (d << (6 * 0)) ; - - /* Overlongs are errors. */ - if (u < 0x10000 || u > 0x10FFFF) - { - UnistrFree(str); - return NULL; - } - - UnistrAddch(str, u); - i += 4 - 1; - continue; - - } - } - - return str; -} -void -UnistrFree(Unistr *unistr) -{ - if (!unistr) - { - return; - } - - Free(unistr->codepoints); - Free(unistr); -} -char * -UnistrC(Unistr *unistr) -{ - char *ret, *tmp, *utf; - size_t i; - if (!unistr) - { - return NULL; - } - - ret = NULL; - for (i = 0; i < unistr->length; i++) - { - uint32_t code = unistr->codepoints[i]; - utf = StrUtf8Encode(code); - - tmp = ret; - ret = StrConcat(2, ret, utf); - Free(tmp); - Free(utf); - } - - return ret; -} -size_t -UnistrSize(Unistr *unistr) -{ - return unistr ? unistr->length : 0; -} -uint32_t -UnistrGetch(Unistr *unistr, size_t i) -{ - if (!unistr) - { - return 0; - } - - return i < unistr->length ? unistr->codepoints[i] : 0; -} -bool -UnistrIsASCII(uint32_t u) -{ - if (u == 0) - { - return NULL; - } - - return u < 0x7F; -} -bool -UnistrIsBMP(uint32_t u) -{ - if (u == 0) - { - return NULL; - } - - return u <= 0xFFFF; -} -Unistr * -UnistrFilter(Unistr *str, UnistrFilterFunc filter) -{ - Unistr *unistr; - size_t i; - if (!str || !filter) - { - return NULL; - } - - unistr = UnistrCreate(""); - for (i = 0; i < UnistrSize(str); i++) - { - uint32_t code = UnistrGetch(str, i); - if (!filter(code)) - { - continue; - } - UnistrAddch(unistr, code); - } - - return unistr; -} - -Unistr * -UnistrConcat(size_t n, ...) -{ - va_list list; - size_t i; - Unistr *ret = UnistrCreate(""); - - va_start(list, n); - for (i = 0; i < n; i++) - { - Unistr *to_concat = va_arg(list, Unistr *); - size_t j; - for (j = 0; j < UnistrSize(to_concat); j++) - { - UnistrAddch(ret, UnistrGetch(to_concat, j)); - } - } - - va_end(list); - return ret; -} -size_t -UnistrGetOffset(Unistr *str, uint32_t sep) -{ - size_t i; - uint32_t prev = 0x0A; - if (!str || !sep) - { - return 0; - } - - for (i = 0; i < str->length; i++) - { - uint32_t curr = str->codepoints[i]; - if (prev == 0x0A && curr != sep) - { - return i; - } - prev = curr; - } - return 0; -} -size_t -UnistrGetUTFOffset(char *cstr, size_t unicode) -{ - Unistr *tmp; - size_t ret = 0; - if (!cstr) - { - return 0; - } - - tmp = UnistrCreate(cstr); - for (size_t i = 0; i < unicode && i < tmp->length; i++) - { - uint32_t codepoint = tmp->codepoints[i]; - if (codepoint >= 0x0000 && codepoint <= 0x007F) - { - ret += 1; - } - else if (codepoint >= 0x0080 && codepoint <= 0x07FF) - { - ret += 2; - } - else if (codepoint >= 0x0800 && codepoint <= 0xFFFF) - { - ret += 3; - } - else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) - { - ret += 4; - } - } -end: - Free(tmp); - return ret; -} diff --git a/src/XEP-0393.c b/src/XEP-0393.c index 784bacf..a90b4a1 100644 --- a/src/XEP-0393.c +++ b/src/XEP-0393.c @@ -87,7 +87,7 @@ DecodeQuote(StringRect rect, size_t *skip) * > four but that's for Nerds * > seasons See, Touhou reference! * concealing!) */ - while ((ch = StrGet(&rect, lines - 1, shift_by)) && isspace((int) ch)) + while ((ch = StrGet(&rect, lines - 1, shift_by)) && isspace(ch)) { shift_by++; } @@ -132,7 +132,7 @@ DecodeSpan(StringRect rect, char del, size_t *skip) { return StrFullRect(NULL); } - if (!ret.source_lines && isspace((int) c)) + if (!ret.source_lines && isspace(c)) { return StrFullRect(NULL); } @@ -329,8 +329,8 @@ ShoveXML(XEP393Element *element, XMLElement *xmlparent) break; case XEP393_MONO: head = XMLCreateTag("code"); - XMLAddChild(xmlparent, XMLCreateText("`")); XMLAddChild(xmlparent, head); + XMLAddChild(head, XMLCreateText("`")); break; case XEP393_SRKE: head = XMLCreateTag("s"); @@ -372,7 +372,7 @@ ShoveXML(XEP393Element *element, XMLElement *xmlparent) XMLAddChild(head, XMLCreateText("_")); break; case XEP393_MONO: - XMLAddChild(xmlparent, XMLCreateText("`")); + XMLAddChild(head, XMLCreateText("`")); break; case XEP393_SRKE: XMLAddChild(head, XMLCreateText("~")); @@ -399,37 +399,21 @@ ShoveXML(XEP393Element *element, XMLElement *xmlparent) char * XEP393ToXMLString(XEP393Element *xepd) { - XMLElement *root, *act_root; - XMLElement *child; + XMLElement *root; Stream *writer; char *ret = NULL; - size_t i, children; if (!xepd) { return NULL; } root = XMLCreateTag("span"); - act_root = root; ShoveXML(xepd, root); writer = StrStreamWriter(&ret); - children = ArraySize(root->children); - - child = ArrayGet(root->children, 0); - if (children == 1 && StrEquals(child->name, "p")) - { - children = ArraySize(child->children); - root = child; - } - for (i = 0; i < children; i++) - { - child = ArrayGet(root->children, i); - - XMLEncode(writer, child); - } - XMLFreeElement(act_root); + XMLEncode(writer, root); + XMLFreeElement(root); StreamFlush(writer); StreamClose(writer); diff --git a/src/XML/Parser.c b/src/XML/Parser.c index 350f0e4..1b8d30a 100644 --- a/src/XML/Parser.c +++ b/src/XML/Parser.c @@ -31,12 +31,6 @@ XMLCDecode(Stream *stream, bool autofree, bool html) bool flag = false; switch (event->type) { - case XML_ERROR: - XMLFreeEvent(event); - XMLFreeElement(ret); - ArrayFree(stack); - XMLFreeLexer(lexer); - return NULL; case XML_LEXER_STARTELEM: /* Create a new element that will populated. */ top = XMLCreateTag(event->element); @@ -120,19 +114,9 @@ XMLCDecode(Stream *stream, bool autofree, bool html) void XMLEncodeString(Stream *stream, char *data) { - size_t i, len; + size_t i; - if (!stream || !data) - { - return; - } - - /* TODO: I should write a "Parsee Best Practice" guideline and make sure - * people understand to NOT constantly recompute lengths parameter on - * these kinds of loops. ArraySize is fine(since its indirection), but - * operations like strlen take time! */ - len = strlen(data); - for (i = 0; i < len; i++) + for (i = 0; i < strlen(data); i++) { char c = data[i]; if (c == '<') @@ -161,9 +145,6 @@ XMLEncodeString(Stream *stream, char *data) continue; } StreamPrintf(stream, "%c", c); - /* TODO: Maybe consider Unistrings and encode arbitrary Unicode - * codepoints * with special XML. Oughta make it printable, you know? - */ } } void diff --git a/src/XML/SAX.c b/src/XML/SAX.c index defea6b..07c920a 100644 --- a/src/XML/SAX.c +++ b/src/XML/SAX.c @@ -58,7 +58,6 @@ static char * XMLPopElement(XMLexer *lexer); static XMLEvent * XMLCreateEmptyElem(XMLexer *lexer, HashMap *attrs); static XMLEvent * XMLCreateStart(XMLexer *lexer, HashMap *attrs); static XMLEvent * XMLCreateRelax(XMLexer *lexer); -static XMLEvent * XMLCreateError(XMLexer *lexer); static XMLEvent * XMLCreateEnd(XMLexer *lexer, char *end); static XMLEvent * XMLCreateData(XMLexer *lexer); @@ -199,9 +198,7 @@ XMLCrank(XMLexer *lexer) else if (XMLookahead(lexer, "--", false)) { /* Throw error */ - XMLFreeEvent(event); - event = XMLCreateError(lexer); - break; + return NULL; } break; case XML_STATE_PI: @@ -218,9 +215,6 @@ XMLCrank(XMLexer *lexer) if (!attrname) { /* TODO: Throw error */ - XMLFreeEvent(event); - event = XMLCreateError(lexer); - break; } XMLPushElement(lexer, attrname); @@ -247,10 +241,7 @@ XMLCrank(XMLexer *lexer) } else if (XMLookahead(lexer, "'", true)) { - //while (true); uh oh - XMLFreeEvent(event); - event = XMLCreateError(lexer); - break; + while (true); } break; case XML_STATE_ATTRTAIL: @@ -259,8 +250,6 @@ XMLCrank(XMLexer *lexer) if (!XMLookahead(lexer, ">", true)) { /* TODO: Throw error. */ - XMLFreeEvent(event); - event = XMLCreateError(lexer); break; } lexer->state = XML_STATE_NONE; @@ -269,8 +258,6 @@ XMLCrank(XMLexer *lexer) break; default: /* TODO */ - XMLFreeEvent(event); - event = XMLCreateError(lexer); break; } /* TODO: Crank our XML parser. */ @@ -308,7 +295,7 @@ static bool XMLookahead(XMLexer *lexer, const char *str, bool skip) { int *stack; - size_t top, i, len; + size_t top, i; ssize_t ntop; bool ret = false; if (!lexer || !str) @@ -317,10 +304,9 @@ XMLookahead(XMLexer *lexer, const char *str, bool skip) } top = 0; - len = strlen(str); - stack = Malloc(len * sizeof(*stack)); + stack = Malloc(strlen(str) * sizeof(*stack)); - for (i = 0; i < len; i++) + for (i = 0; i < strlen(str); i++) { char c = str[i]; int getc = XMLGetc(lexer); @@ -350,8 +336,8 @@ seekback: return ret; } -#define IsNamestart(c) ((c == ':') || isalpha((int) c) || (c == '_')) -#define IsNamepart(c) (IsNamestart(c) || (c == '-') || isdigit((int) c)) +#define IsNamestart(c) ((c == ':') || isalpha(c) || (c == '_')) +#define IsNamepart(c) (IsNamestart(c) || (c == '-') || isdigit(c)) static char * XMLParseName(XMLexer *lexer) { @@ -596,8 +582,6 @@ XMLCreateEnd(XMLexer *lexer, char *end) event->col = 0; event->offset = 0; - (void) lexer; - return event; } static XMLEvent * @@ -706,26 +690,6 @@ XMLCreateData(XMLexer *lexer) return event; } static XMLEvent * -XMLCreateError(XMLexer *lexer) -{ - XMLEvent *event = Malloc(sizeof(*event)); - size_t elements = ArraySize(lexer->data.elements); - - event->type = XML_ERROR; - event->element = elements ? - StrDuplicate(ArrayGet(lexer->data.elements, elements - 1)) : - NULL; - event->attrs = NULL; - event->data = NULL; - - /* TODO */ - event->line = 0; - event->col = 0; - event->offset = 0; - - return event; -} -static XMLEvent * XMLCreateRelax(XMLexer *lexer) { XMLEvent *event = Malloc(sizeof(*event)); diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index e3ff4e4..71f617a 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -19,7 +18,7 @@ #define DEFAULT_PROSODY_PORT 5347 XMPPComponent * -XMPPInitialiseCompStream(char *addr, char *host, int port) +XMPPInitialiseCompStream(char *host, int port) { int sd = -1; struct addrinfo hints, *res, *res0; @@ -28,17 +27,12 @@ XMPPInitialiseCompStream(char *addr, char *host, int port) Stream *stream; XMPPComponent *comp; - if (!addr) - { - addr = host; - } - snprintf(serv, sizeof(serv), "%hu", port ? port : DEFAULT_PROSODY_PORT); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(addr, serv, &hints, &res0); + error = getaddrinfo(host, serv, &hints, &res0); if (error) { const char *error_str = gai_strerror(error); @@ -61,10 +55,6 @@ XMPPInitialiseCompStream(char *addr, char *host, int port) if (connect(sd, res->ai_addr, res->ai_addrlen) < 0) { - Log(LOG_ERR, - "%s: cannot connect to '%s': %s", __func__, - host, strerror(errno) - ); close(sd); sd = -1; continue; @@ -75,10 +65,6 @@ XMPPInitialiseCompStream(char *addr, char *host, int port) if (sd < 0) { - Log(LOG_ERR, - "%s: cannot connect to '%s': no socket available", __func__, - host - ); return NULL; } freeaddrinfo(res0); @@ -86,10 +72,6 @@ XMPPInitialiseCompStream(char *addr, char *host, int port) stream = StreamFd(sd); if (!stream) { - Log(LOG_ERR, - "%s: cannot connect to '%s': %s", __func__, - host, "couldn't create a Cytoplasm stream" - ); close(sd); return NULL; } @@ -152,7 +134,7 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) } break; } - if (!ev || ev->type != XML_LEXER_STARTELEM || + if (ev->type != XML_LEXER_STARTELEM || !StrEquals(ev->element, "stream:stream")) { Log(LOG_ERR, "Excepted stream:stream element."); @@ -177,54 +159,12 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) } break; } - if (!ev || ev->type != XML_LEXER_ELEM || + if (ev->type != XML_LEXER_ELEM || !StrEquals(ev->element, "handshake")) { + Log(LOG_DEBUG, "type=%d elem='%s'", ev->type, ev->element); Log(LOG_ERR, "Excepted empty handshake reply, got nonsense."); Log(LOG_ERR, "Another service (possibly Parsee) may have taken over."); - while ((ev = XMLCrank(sax))) - { - char *key, *val; - switch (ev->type) - { - case XML_LEXER_STARTELEM: - Log(LOG_DEBUG, "<%s>", ev->element); - - LogConfigIndent(LogConfigGlobal()); - LogConfigIndent(LogConfigGlobal()); - /* TODO: Log out attributes a little better */ - while (HashMapIterate(ev->attrs, &key, (void **) &val)) - { - Log(LOG_DEBUG, "(%s=%s)", key, val); - } - LogConfigUnindent(LogConfigGlobal()); - LogConfigUnindent(LogConfigGlobal()); - - LogConfigIndent(LogConfigGlobal()); - break; - case XML_LEXER_ELEM: - Log(LOG_DEBUG, "<%s/>", ev->element); - LogConfigIndent(LogConfigGlobal()); - LogConfigIndent(LogConfigGlobal()); - /* TODO: Log out attributes a little better */ - while (HashMapIterate(ev->attrs, &key, (void **) &val)) - { - Log(LOG_DEBUG, "(%s=%s)", key, val); - } - LogConfigUnindent(LogConfigGlobal()); - LogConfigUnindent(LogConfigGlobal()); - break; - case XML_LEXER_ENDELEM: - LogConfigUnindent(LogConfigGlobal()); - Log(LOG_DEBUG, "", ev->element); - break; - case XML_LEXER_DATA: - Log(LOG_DEBUG, "%s", ev->data); - break; - } - XMLFreeEvent(ev); - } - LogConfigIndentSet(LogConfigGlobal(), 0); Log(LOG_ERR, ""); Log(LOG_ERR, "Simply jealous of that other service..."); Free(stream_id); @@ -273,35 +213,3 @@ XMPPEndCompStream(XMPPComponent *comp) Free(comp->host); Free(comp); } -void -XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max) -{ - size_t len; - char *c = NULL; - Stream *stringWriter; - if (!comp || !stanza) - { - return; - } - - stringWriter = StrStreamWriter(&c); - XMLEncode(stringWriter, stanza); - StreamFlush(stringWriter); - StreamClose(stringWriter); - if (c && max && (len = strlen(c)) > max) - { - Log(LOG_WARNING, - "Unexceptedly large stanza received (len=%d max=%d).", - (int) len, (int) max - ); - Free(c); - return; - } - - - pthread_mutex_lock(&comp->write_lock); - StreamPrintf(comp->stream, "%s", c); - StreamFlush(comp->stream); - pthread_mutex_unlock(&comp->write_lock); - Free(c); -} diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 9ecfcf2..832fdfe 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -8,8 +8,6 @@ #include #include -#include "XMPPThread/internal.h" - bool XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { @@ -20,6 +18,8 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) return false; } + pthread_mutex_lock(&jabber->write_lock); + iq_query = XMLCreateTag("iq"); query = XMLCreateTag("query"); @@ -35,7 +35,8 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { XMLElement *identity; - XMPPSendStanza(jabber, iq_query, 10000); + XMLEncode(jabber->stream, iq_query); + StreamFlush(jabber->stream); XMLFreeElement(iq_query); /* Except an IQ reply. 10 seconds of timeout is pretty @@ -44,8 +45,8 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) Free(uuid); if (!iq_query || !StrEquals(iq_query->name, "iq")) { - Log(LOG_ERR, "Didn't receive an stanza"); XMLFreeElement(iq_query); + pthread_mutex_unlock(&jabber->write_lock); return false; } query = XMLookForUnique(iq_query, "query"); @@ -56,11 +57,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) "conference")) { XMLFreeElement(iq_query); - Log(LOG_DEBUG, "MUC INFO ERROR"); - Log(LOG_DEBUG, - "identityp=%p category=%s", identity, - identity ? HashMapGet(identity->attrs, "category") : NULL - ); + pthread_mutex_unlock(&jabber->write_lock); return false; } @@ -76,6 +73,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) XMLFreeElement(iq_query); } } + pthread_mutex_unlock(&jabber->write_lock); return true; } @@ -118,6 +116,7 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) return; } + pthread_mutex_lock(&jabber->write_lock); stanza = XMLCreateTag("message"); XMLAddAttr(stanza, "id", (identifier = StrRandom(32))); XMLAddAttr(stanza, "from", from); @@ -161,68 +160,44 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) } XMLAddChild(stanza, x); } - XMPPSendStanza(jabber, stanza, 10000); + XMLEncode(jabber->stream, stanza); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(stanza); Free(identifier); } bool -XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool ret) +XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) { - XMLElement *presence, *x, *reply, *history, *photo; - IQFeatures *features; - char *from, *id, *stime = "3600"; + XMLElement *presence, *x, *reply; + char *from, *id; if (!comp || !fr || !muc) { return false; } + pthread_mutex_lock(&comp->write_lock); + presence = XMLCreateTag("presence"); x = XMLCreateTag("x"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(presence, "to", muc); XMLAddAttr(presence, "id", (id = StrRandom(8))); XMLAddAttr(x, "xmlns", "http://jabber.org/protocol/muc"); - history = XMLCreateTag("history"); - - if (time > 0) - { - stime = StrInt(time); - } - XMLAddAttr(history, "seconds", stime); - if (time > 0) - { - Free(stime); - stime = NULL; - } - XMLAddChild(x, history); XMLAddChild(presence, x); - features = LookupJIDFeatures(from); -#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); - IQ_ADVERT -#undef AdvertiseSimple - XMPPAnnotatePresence(presence, features); - FreeIQFeatures(features); + XMPPAnnotatePresence(presence); - if (hash) - { - x = XMLCreateTag("x"); - XMLAddAttr(x, "xmlns", "vcard-temp:x:update"); - photo = XMLCreateTag("photo"); - XMLAddChild(photo, XMLCreateText(hash)); - XMLAddChild(x, photo); - XMLAddChild(presence, x); - } + XMLEncode(comp->stream, presence); + StreamFlush(comp->stream); - XMPPSendStanza(comp, presence, 10000); XMLFreeElement(presence); Free(from); - if (ret && (reply = ParseeAwaitStanza(id, 500))) + pthread_mutex_unlock(&comp->write_lock); + + if (care && (reply = ParseeAwaitStanza(id, 500))) { bool exit_code = true; @@ -242,13 +217,14 @@ void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) { XMLElement *presence; - IQFeatures *features; char *from, *id; if (!comp || !fr || !muc) { return; } + pthread_mutex_lock(&comp->write_lock); + presence = XMLCreateTag("presence"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(presence, "to", muc); @@ -264,20 +240,14 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMLAddChild(presence, status); } - features = LookupJIDFeatures(from); -#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); - IQ_ADVERT -#undef AdvertiseSimple - XMPPAnnotatePresence(presence, features); - FreeIQFeatures(features); + XMPPAnnotatePresence(presence); - - XMPPSendStanza(comp, presence, 10000); + XMLEncode(comp->stream, presence); + StreamFlush(comp->stream); XMLFreeElement(presence); Free(from); Free(id); + + pthread_mutex_unlock(&comp->write_lock); } diff --git a/src/XMPP/MUCServ.c b/src/XMPP/MUCServ.c deleted file mode 100644 index 557c4a2..0000000 --- a/src/XMPP/MUCServ.c +++ /dev/null @@ -1,154 +0,0 @@ -#include - -#include -#include -#include - -#include -#include - -#define MUCNS "http://jabber.org/protocol/muc" - -struct MUCServer { - pthread_mutex_t mut; - - ParseeData *data; -}; - -static char * -GetMUCName(char *jid) -{ - char *name, *at; - size_t len; - if (!jid || *jid != '#') - { - return NULL; - } - - jid++; - - at = strchr(jid, '@'); - if (!at) - { - return StrDuplicate(jid); - } - len = at - jid; - name = Malloc(len + 1); - memset(name, '\0', len + 1); - memcpy(name, jid, len); - - return name; -} - -MUCServer * -CreateMUCServer(ParseeData *data) -{ - MUCServer *server; - if (!data) - { - return NULL; - } - - server = Malloc(sizeof(*server)); - pthread_mutex_init(&server->mut, NULL); - server->data = data; - return server; -} - -static bool -MUCManagePresence(MUCServer *serv, XMLElement *stanza, char *from, char *to) -{ - char *name; - XMLElement *x = XMLookForTKV(stanza, "x", "xmlns", MUCNS); - char *type = HashMapGet(stanza->attrs, "type"); - if (x && !type) - { - /* The user is trying to join the MUC */ - name = GetMUCName(to); - Log(LOG_WARNING, "%s is trying to join MUC '%s'", from, name); - - /* TODO: Check if the user should be joining. If so, make them. - * Implementing MUCs is gonna be fun. */ - - /* TODO: Presence broadcast hell. */ - Free(name); - } - return false; -} - -static bool -MUCManageMessage(MUCServer *serv, XMLElement *stanza, char *from, char *to) -{ - Log(LOG_WARNING, "MUCSERV: got a message %s->%s", from, to); - return false; -} - -bool -ManageMUCStanza(MUCServer *serv, XMLElement *stanza) -{ - char *stype, *from, *to; - bool ret; - if (!serv || !stanza) - { - return false; - } - - from = HashMapGet(stanza->attrs, "from"); - to = HashMapGet(stanza->attrs, "to"); - stype = stanza->name; - - if (to && *to != '#') - { - /* We aren't interacting with a MUC at all. Don't do anything. */ - return false; - } - if (StrEquals(stype, "iq")) - { - /* TODO: Worry about IQ later */ - return false; - } - - ret = false; - pthread_mutex_lock(&serv->mut); - if (StrEquals(stype, "presence")) - { - ret = MUCManagePresence(serv, stanza, from, to); - } - else if (StrEquals(stype, "message")) - { - ret = MUCManageMessage(serv, stanza, from, to); - } - /* TODO: Do stuff while locked */ - pthread_mutex_unlock(&serv->mut); - - /* TODO: Verify the destination, and make sure we aren't doing - * anything stupid(especially with discovery) */ - (void) ret; - return false; -} - -bool -MUCServerExists(MUCServer *serv, char *muc) -{ - if (!serv || !muc) - { - return false; - } - - return false; -} - -void -FreeMUCServer(MUCServer *serv) -{ - if (!serv) - { - return; - } - - pthread_mutex_lock(&serv->mut); - /* TODO */ - pthread_mutex_unlock(&serv->mut); - pthread_mutex_destroy(&serv->mut); - Free(serv); -} diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index a2daf5a..e731792 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -7,8 +7,6 @@ #include #include -#include - void XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) @@ -68,9 +66,13 @@ XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) } - XMPPSendStanza(comp, message, 10000); + pthread_mutex_lock(&comp->write_lock); + XMLEncode(comp->stream, message); + StreamFlush(comp->stream); XMLFreeElement(message); + pthread_mutex_unlock(&comp->write_lock); + Free(from); Free(ident); } @@ -83,8 +85,6 @@ XMPPIsParseeStanza(XMLElement *stanza) return false; } - /* TODO: Check if the user is a trustworthy Parsee puppet instead of some - * guy sending random stanzas */ return !!XMLookForUnique(stanza, "x-parsee"); } @@ -161,31 +161,27 @@ XMPPGetReply(XMLElement *elem) return HashMapGet(rep->attrs, "id"); } -ssize_t -XMPPGetReplyOffset(XMLElement *elem) +void +XMPPAnnotatePresence(XMLElement *presence) { - if (!elem) + XMLElement *c; + char *ver; + if (!presence) { - return -1; + return; } - for (size_t i = 0; i < ArraySize(elem->children); i++) - { - XMLElement *child = ArrayGet(elem->children, i); - char *xmlns = HashMapGet(child->attrs, "xmlns"); - char *xfor = HashMapGet(child->attrs, "for"); - if (StrEquals(child->name, "fallback") && - StrEquals(xmlns, "urn:xmpp:feature-fallback:0") && - StrEquals(xfor, "urn:xmpp:reply:0")) - { - XMLElement *body = XMLookForUnique(child, "body"); - if (body && HashMapGet(body->attrs, "end")) - { - return strtol(HashMapGet(body->attrs, "end"), NULL, 10); - } - } - } - return -1; + + ver = XMPPGenerateVer(); + c = XMLCreateTag("c"); + XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); + XMLAddAttr(c, "hash", "sha-1"); + XMLAddAttr(c, "node", REPOSITORY); + XMLAddAttr(c, "ver", ver); + + Free(ver); + XMLAddChild(presence, c); } + char * XMPPGetModeration(XMLElement *stanza) { @@ -270,7 +266,10 @@ XMPPSendDisco(ParseeData *data, char *from, char *to) XMLAddChild(iq, query); } - XMPPSendStanza(jabber, iq, 10000); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq); ret = ParseeAwaitStanza(identifier, 1.25 SECONDS); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index 00a8c89..580773f 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -34,17 +34,7 @@ struct XMPPCommandManager { HashMap *sessions; void *cookie; - - XMPPCmdFilter filter; }; -static bool -XMPPDefaultFilter(XMPPCommandManager *manager, char *id, XMLElement *stanza) -{ - (void) manager; - (void) stanza; - (void) id; - return true; -} static void XMPPDestroySession(XMPPSession *session) { @@ -128,7 +118,6 @@ XMPPCreateManager(void *cookie) ret->commands = HashMapCreate(); ret->sessions = HashMapCreate(); ret->cookie = cookie; - ret->filter = XMPPDefaultFilter; return ret; } @@ -172,12 +161,12 @@ XMPPFreeManager(XMPPCommandManager *manager) Free(manager); } void -XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement *s) +XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p) { char *node_name; XMPPCommand *val; XMLElement *item; - if (!m || !p || !jid || !s) + if (!m || !p || !jid) { return; } @@ -185,14 +174,11 @@ XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement pthread_mutex_lock(&m->lock); while (HashMapIterate(m->commands, &node_name, (void **) &val)) { - if (m->filter(m, node_name, s)) - { - item = XMLCreateTag("item"); - XMLAddAttr(item, "jid", jid); - XMLAddAttr(item, "node", node_name); - XMLAddAttr(item, "name", XMPPGetCommandDesc(val)); - XMLAddChild(p, item); - } + item = XMLCreateTag("item"); + XMLAddAttr(item, "jid", jid); + XMLAddAttr(item, "node", node_name); + XMLAddAttr(item, "name", XMPPGetCommandDesc(val)); + XMLAddChild(p, item); } pthread_mutex_unlock(&m->lock); } @@ -220,16 +206,6 @@ XMPPVerifySession(XMPPCommandManager *mgr, char *s_id, char *from, char *to) return ret; } - -void -XMPPManagerSetFilter(XMPPCommandManager *manager, XMPPCmdFilter filter) -{ - if (!manager || !filter) - { - return; - } - manager->filter = filter; -} bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) { @@ -266,7 +242,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) /* This is an execution. */ cmd = HashMapGet(m->commands, node); - if (!cmd || !m->filter(m, node, stanza)) + if (!cmd) { /* TODO: Set an error note */ goto end; @@ -298,7 +274,10 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) x = XMPPFormifyCommand(m, cmd, from); XMLAddChild(command_xml, x); - XMPPSendStanza(jabber, iq, data->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq); goto end; @@ -326,7 +305,10 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, NULL); XMLAddChild(iq, command_xml); - XMPPSendStanza(jabber, iq, data->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq); InvalidateSession(m, session_id); @@ -366,7 +348,10 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, x_form); XMLAddChild(iq, command_xml); - XMPPSendStanza(jabber, iq, data->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq); InvalidateSession(m, session_given); diff --git a/src/XMPPCommands/Admins.c b/src/XMPPCommands/Admins.c index 5749165..7f0b172 100644 --- a/src/XMPPCommands/Admins.c +++ b/src/XMPPCommands/Admins.c @@ -15,11 +15,19 @@ void AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) { ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); size_t i; XMLElement *x; XMLElement *title; XMLElement *reported, *item, *field, *value, *txt; + if (!ParseeIsAdmin(data, trimmed)) + { + SetNote("error", "User is not authorised to execute command."); + Free(trimmed); + return; + } + Free(trimmed); x = XMLCreateTag("x"); title = XMLCreateTag("title"); @@ -50,7 +58,4 @@ AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * DbUnlock(data->db, ref); } XMLAddChild(out, x); - - (void) form; - (void) from; } diff --git a/src/XMPPCommands/Cleanup.c b/src/XMPPCommands/Cleanup.c index 22780ff..4554f53 100644 --- a/src/XMPPCommands/Cleanup.c +++ b/src/XMPPCommands/Cleanup.c @@ -29,6 +29,4 @@ CleanCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o ParseeCleanup(data); /* TODO: Cleanup old sessions? */ SetNote("info", "Parsee data was sucessfully cleant up."); - - (void) form; } diff --git a/src/XMPPCommands/MUCInformation.c b/src/XMPPCommands/MUCInformation.c deleted file mode 100644 index 53dc684..0000000 --- a/src/XMPPCommands/MUCInformation.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -void -MUCInformationID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *muc = ParseeTrimJID(from); - char *chat_id = ParseeGetFromMUCID(data, muc); - char *room_id = ParseeGetRoomID(data, chat_id); - char *msg = StrConcat(5, - "The MUC ", muc, " is bridged to ", room_id, "." - ); - - SetNote("info", msg); - - Free(muc); - Free(msg); - Free(room_id); - Free(chat_id); - (void) form; -} -void -MUCInformationCID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *muc = ParseeTrimJID(from); - char *chat_id = ParseeGetFromMUCID(data, muc); - char *msg = StrConcat(5, - "The MUC ", muc, "'s internal ID is ", chat_id, "." - ); - - SetNote("info", msg); - - Free(muc); - Free(msg); - Free(chat_id); - (void) form; -} diff --git a/src/XMPPCommands/MUCKV.c b/src/XMPPCommands/MUCKV.c deleted file mode 100644 index 80ac9c4..0000000 --- a/src/XMPPCommands/MUCKV.c +++ /dev/null @@ -1,117 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -void -MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *affiliation = NULL, *role = NULL; - char *chat_id = NULL; - char *muc = NULL; - - char *key = NULL, *val = NULL; - - ParseeLookupAffiliation(from, &affiliation, &role); - Free(role); - if (!StrEquals(affiliation, "owner")) - { - SetNote("error", "Setting MUC properties requires the 'owner' affiliation."); - Free(affiliation); - return; - } - - GetFieldValue(key, "key", form); - GetFieldValue(val, "val", form); - if (!key || !val) - { - SetNote("error", "No keys or no value given."); - goto end; - } - - muc = ParseeTrimJID(from); - chat_id = ParseeGetFromMUCID(data, muc); - ParseeSetChatSetting(data, chat_id, key, val); - - SetNote("info", "Set key-value pair!"); -end: - Free(affiliation); - Free(chat_id); - Free(muc); - (void) form; -} -void -MUCGetKeys(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *affiliation = NULL, *role = NULL; - char *chat_id = NULL; - char *muc = NULL; - - XMLElement *x; - XMLElement *title; - XMLElement *reported, *item, *field, *value, *txt; - - HashMap *settings = NULL; - - ParseeLookupAffiliation(from, &affiliation, &role); - Free(role); - if (!StrEquals(affiliation, "owner")) - { - SetNote("error", "Getting MUC roperties requires the 'owner' affiliation."); - goto end; - } - - - muc = ParseeTrimJID(from); - chat_id = ParseeGetFromMUCID(data, muc); - settings = ParseeGetChatSettings(data, chat_id); - - x = XMLCreateTag("x"); - title = XMLCreateTag("title"); - - SetTitle(x, "MUC/room settings"); - - XMLAddChild(x, title); - - XMLAddAttr(x, "xmlns", "jabber:x:data"); - XMLAddAttr(x, "type", "result"); - { - char *key, *val; - reported = XMLCreateTag("reported"); - XMLAddChild(x, reported); - - /* Report */ - Report("key", "Setting's key"); - Report("val", "Setting's value"); - - /* Set */ - while (HashMapIterate(settings, &key, (void **) &val)) - { - BeginItem(); - SetField("key", key); - SetField("val", val); - EndItem(); - } - } - XMLAddChild(out, x); - -end: - ParseeFreeChatSettings(settings); - Free(affiliation); - Free(chat_id); - Free(muc); - (void) form; -} diff --git a/src/XMPPCommands/MUCUnlink.c b/src/XMPPCommands/MUCUnlink.c deleted file mode 100644 index f5560d3..0000000 --- a/src/XMPPCommands/MUCUnlink.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -void -MUCUnlink(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *affiliation, *role; - char *chat_id; - char *parsee; - char *room; - char *muc; - - ParseeLookupAffiliation(from, &affiliation, &role); - Free(role); - if (!StrEquals(affiliation, "owner")) - { - SetNote("error", "Unlinking a MUC requires the 'owner' affiliation."); - Free(affiliation); - return; - } - - muc = ParseeTrimJID(from); - chat_id = ParseeGetFromMUCID(data, muc); - room = ParseeGetRoomID(data, chat_id); - if (!chat_id) - { - SetNote("error", "Couldn't fetch chat ID."); - Free(muc); - return; - } - ParseeUnlinkRoom(data, chat_id); - - parsee = ParseeMXID(data); - Free(ASSend( - data->config, room, parsee, - "m.room.message", - MatrixCreateNotice("This room has been unlinked."), - 0 - )); - ASLeave(data->config, room, parsee); - - XMPPLeaveMUC(data->jabber, "parsee", muc, "Unlinked by MUC admin."); - - /* Setting an error here won't work, as we're communicating through - * the MUC, which we *left*. I guess we can try to defer the leave. */ - SetNote("info", "Unlinked MUC."); - - Free(affiliation); - Free(chat_id); - Free(parsee); - Free(room); - Free(muc); - (void) form; -} diff --git a/src/XMPPCommands/Nofly.c b/src/XMPPCommands/Nofly.c index dcbef67..86a7bb1 100644 --- a/src/XMPPCommands/Nofly.c +++ b/src/XMPPCommands/Nofly.c @@ -87,6 +87,4 @@ NoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o } DbUnlock(data->db, ref); } - - (void) form; } diff --git a/src/XMPPCommands/Status.c b/src/XMPPCommands/Status.c index 1b19129..41a923a 100644 --- a/src/XMPPCommands/Status.c +++ b/src/XMPPCommands/Status.c @@ -14,6 +14,7 @@ void StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) { + ParseeData *data = XMPPGetManagerCookie(m); char *trimmed = ParseeTrimJID(from); size_t alloc = MemoryAllocated(); size_t kb = alloc >> 10; @@ -25,6 +26,13 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * XMLElement *x; XMLElement *title, *txt; + if (!ParseeIsAdmin(data, trimmed)) + { + SetNote("error", "User is not authorised to execute command."); + + Free(trimmed); + return; + } Free(trimmed); x = XMLCreateTag("x"); title = XMLCreateTag("title"); @@ -67,7 +75,4 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement * EndItem(); } XMLAddChild(out, x); - - (void) form; - (void) m; } diff --git a/src/XMPPCommands/Whitelist.c b/src/XMPPCommands/Whitelist.c deleted file mode 100644 index 8e097a8..0000000 --- a/src/XMPPCommands/Whitelist.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -void -ClearWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *trimmed = ParseeTrimJID(from); - - if (!ParseeIsAdmin(data, trimmed)) - { - SetNote("error", "User is not authorised to execute command."); - - Free(trimmed); - return; - } - Free(trimmed); - - if (!DbDelete(data->db, 1, "whitelist")) - { - SetNote("error", "Parsee whitelist was non-existent or could not be removed."); - return; - } - /* TODO: Cleanup old sessions? */ - SetNote("info", "Parsee whitelist was removed."); - - (void) form; -} -void -AddWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *trimmed = ParseeTrimJID(from); - char *entity = NULL; - DbRef *ref; - - GetFieldValue(entity, "entity", form); - - if (!ParseeIsAdmin(data, trimmed)) - { - SetNote("error", "User is not authorised to execute command."); - - Free(trimmed); - return; - } - if (!entity) - { - SetNote("error", "No entity found."); - Free(trimmed); - return; - } - - Free(trimmed); - - ref = DbLock(data->db, 1, "whitelist"); - if (!ref) - { - ref = DbCreate(data->db, 1, "whitelist"); - } - if (!ref) - { - SetNote("error", "Couldn't get a database entry. You're cooked."); - return; - } - JsonValueFree(HashMapSet( - DbJson(ref), - entity, JsonValueObject(HashMapCreate()) - )); - DbUnlock(data->db, ref); - - SetNote("info", "Server successfully whitelisted."); -} -void -WhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out) -{ - ParseeData *data = XMPPGetManagerCookie(m); - char *trimmed = ParseeTrimJID(from); - XMLElement *x; - XMLElement *title; - XMLElement *reported, *item, *field, *value, *txt; - - if (!ParseeIsAdmin(data, trimmed)) - { - SetNote("error", "User is not authorised to execute command."); - - Free(trimmed); - return; - } - - x = XMLCreateTag("x"); - XMLAddAttr(x, "xmlns", "jabber:x:data"); - title = XMLCreateTag("title"); - XMLAddChild(x, title); - XMLAddChild(out, x); - - Free(trimmed); - - SetTitle(x, NAME " chat whitelist"); - - XMLAddAttr(x, "type", "result"); - { - DbRef *ref = DbLock(data->db, 1, "whitelist"); - HashMap *obj; - char *serv; - JsonValue *obj_val; - reported = XMLCreateTag("reported"); - XMLAddChild(x, reported); - - if (!ref) - { - ref = DbCreate(data->db, 1, "global_bans"); - } - - obj = DbJson(ref); - - /* Report */ - Report("server", "Allowed servers"); - - /* Set */ - while (HashMapIterate(obj, &serv, (void **) &obj_val)) - { - BeginItem(); - SetField("server", serv); - EndItem(); - - (void) obj_val; - } - DbUnlock(data->db, ref); - } - - (void) form; -} diff --git a/src/XMPPThread/Bridged.c b/src/XMPPThread/Bridged.c index 0ad23ab..58fb571 100644 --- a/src/XMPPThread/Bridged.c +++ b/src/XMPPThread/Bridged.c @@ -121,7 +121,7 @@ ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza) bool ServerHasXEP421(ParseeData *data, char *from) { - char *server = NULL, *postserv, *parsee; + char *server = NULL, *parsee; XMLElement *disco; bool ret = false; if (!data || !from) @@ -140,10 +140,9 @@ ServerHasXEP421(ParseeData *data, char *from) } server = StrDuplicate(server); - postserv = server ? strchr(server, '/') : NULL; - if (postserv) + if (strchr(server, '/')) { - *postserv = '\0'; + *(strchr(server, '/')) = '\0'; } parsee = ParseeJID(data); @@ -227,6 +226,7 @@ ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force) { ParseePushOIDTable(xmpp_from, occ_id); } + Log(LOG_DEBUG, "Trying Occ ID for %s{%s}", xmpp_from, occ_id); } if (!occ_id) diff --git a/src/XMPPThread/Caps.c b/src/XMPPThread/Caps.c index d79a30c..867adbd 100644 --- a/src/XMPPThread/Caps.c +++ b/src/XMPPThread/Caps.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -13,86 +12,33 @@ #include "XMPPThread/internal.h" -IQFeatures * -CreateIQFeatures(void) -{ - IQFeatures *ret = Malloc(sizeof(*ret)); - - ret->identity = ArrayCreate(); - ret->adverts = ArrayCreate(); - - return ret; -} -void -FreeIQFeatures(IQFeatures *features) -{ - size_t i; - if (!features) - { - return; - } - - for (i = 0; i < ArraySize(features->adverts); i++) - { - Free(ArrayGet(features->adverts, i)); - } - ArrayFree(features->adverts); - - for (i = 0; i < ArraySize(features->identity); i++) - { - XMPPIdentity *identity = ArrayGet(features->identity, i); - - Free(identity->category); - Free(identity->type); - Free(identity->lang); - Free(identity->name); - - Free(identity); - } - ArrayFree(features->identity); - - Free(features); -} - -void -AdvertiseIQFeature(IQFeatures *f, char *feature) -{ - if (!f || !feature) - { - return; - } - - ArrayAdd(f->adverts, StrDuplicate(feature)); -} -void -AddIQIdentity(IQFeatures *f, char *cat, char *lang, char *type, char *name) -{ - XMPPIdentity *identity; - if (!f) - { - return; - } - - identity = Malloc(sizeof(*identity)); - identity->category = StrDuplicate(cat); - identity->type = StrDuplicate(type); - identity->lang = StrDuplicate(lang); - identity->name = StrDuplicate(name); - ArrayAdd(f->identity, identity); -} /* Generates a SHA-256 hash of the ver field. */ char * -XMPPGenerateVer(IQFeatures *features) +XMPPGenerateVer(void) { char *S = NULL; unsigned char *Sha = NULL; + Array *identities = ArrayCreate(); + Array *features = ArrayCreate(); size_t i; /* Initialise identity table, to be sorted */ - ArraySort(features->identity, IdentitySort); - for (i = 0; i < ArraySize(features->identity); i++) +#define IdentitySimple(cat, Type, Name) { \ + XMPPIdentity *id = Malloc(sizeof(*id)); \ + id->category = cat; \ + id->lang = NULL; \ + id->type = Type; \ + id->name = Name; \ + ArrayAdd(identities, id); } + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) ArrayAdd(features, feature); + IQ_ADVERT +#undef AdvertiseSimple + ArraySort(identities, IdentitySort); + for (i = 0; i < ArraySize(identities); i++) { - XMPPIdentity *identity = ArrayGet(features->identity, i); + XMPPIdentity *identity = ArrayGet(identities, i); char *id_chunk = StrConcat(7, identity->category, "/", identity->type, "/", @@ -104,10 +50,10 @@ XMPPGenerateVer(IQFeatures *features) Free(id_chunk); } - ArraySort(features->adverts, ((int (*) (void *, void *)) ICollate)); - for (i = 0; i < ArraySize(features->adverts); i++) + ArraySort(features, ((int (*) (void *, void *)) ICollate)); + for (i = 0; i < ArraySize(features); i++) { - char *feature = ArrayGet(features->adverts, i); + char *feature = ArrayGet(features, i); char *tmp = S; S = StrConcat(3, S, feature, "<"); Free(tmp); @@ -118,64 +64,16 @@ XMPPGenerateVer(IQFeatures *features) S = Base64Encode((const char *) Sha, 20); Free(Sha); + ArrayFree(features); + for (i = 0; i < ArraySize(identities); i++) + { + XMPPIdentity *identity = ArrayGet(identities, i); + /* We don't have to do anything here. */ + Free(identity); + } + ArrayFree(identities); + return S; } -void -XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features) -{ - XMLElement *c; - char *ver; - if (!presence || !features) - { - return; - } - - ver = XMPPGenerateVer(features); - c = XMLCreateTag("c"); - XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); - XMLAddAttr(c, "hash", "sha-1"); - XMLAddAttr(c, "node", REPOSITORY); - XMLAddAttr(c, "ver", ver); - - Free(ver); - XMLAddChild(presence, c); -} - - -IQFeatures * -LookupJIDFeatures(char *jid) -{ - IQFeatures *features; - if (!jid) - { - return NULL; - } - - features = CreateIQFeatures(); - - if (*jid == '#') - { - /* This is a MUC. As such, we need to advertise MUCs */ -#define ID(...) AddIQIdentity(features, __VA_ARGS__) -#define AD(var) AdvertiseIQFeature(features, var) - ID("gateway", NULL, "matrix", "Parsee MUC gateway"); - ID("conference", NULL, "text", "Parsee MUC gateway"); - ID("component", NULL, "generic", "Parsee component"); - - AD("http://jabber.org/protocol/muc"); -#undef AD -#undef ID - } - else - { -#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); - IQ_ADVERT -#undef AdvertiseSimple - } - return features; -} diff --git a/src/XMPPThread/PEP.c b/src/XMPPThread/PEP.c index 2196ba7..be60096 100644 --- a/src/XMPPThread/PEP.c +++ b/src/XMPPThread/PEP.c @@ -10,8 +10,6 @@ #include #include -#define PUBSUB "http://jabber.org/protocol/pubsub" - XMLElement * CreatePubsubRequest(char *from, char *to, char *node) { @@ -24,7 +22,7 @@ CreatePubsubRequest(char *from, char *to, char *node) XMLAddAttr(iq_req, "type", "set"); pubsub = XMLCreateTag("pubsub"); - XMLAddAttr(pubsub, "xmlns", PUBSUB); + XMLAddAttr(pubsub, "xmlns", "http://jabber.org/protocol/pubsub"); XMLAddChild(iq_req, pubsub); sub = XMLCreateTag("subscribe"); @@ -36,40 +34,12 @@ CreatePubsubRequest(char *from, char *to, char *node) return iq_req; } -static bool -IsPubsubRequest(XMLElement *stanza) -{ - char *type = HashMapGet(stanza ? stanza->attrs : NULL, "type"); - XMLElement *pubsub; - if (!stanza) - { - return false; - } - - if (!StrEquals(stanza->name, "iq") || - !StrEquals(type, "set")) - { - return false; - } - - pubsub = XMLookForTKV(stanza, "pubsub", "xmlns", PUBSUB); - if (!pubsub) - { - return false; - } - - return XMLookForUnique(pubsub, "subscribe"); -} - - struct PEPManager { pthread_mutex_t lock; ParseeData *data; HashMap *node_table; - HashMap *followers; - void *cookie; }; @@ -86,7 +56,6 @@ CreatePEPManager(ParseeData *data, void *cookie) ret->cookie = cookie; ret->data = data; ret->node_table = HashMapCreate(); - ret->followers = HashMapCreate(); pthread_mutex_init(&ret->lock, NULL); return ret; @@ -99,32 +68,29 @@ PEPManagerCookie(PEPManager *manager) void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event) { - PEPEvent *indirect; if (!manager || !node || !event) { return; } - indirect = Malloc(sizeof(event)); - *indirect = event; pthread_mutex_lock(&manager->lock); - HashMapSet(manager->node_table, node, indirect); + HashMapSet(manager->node_table, node, event); pthread_mutex_unlock(&manager->lock); } static bool PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) { - PEPEvent *call = NULL; - XMLElement *event = NULL, *ps = NULL, *ev = NULL; + PEPEvent call = NULL; + XMLElement *event, *ps, *ev; size_t i; if (!manager || !stanza) { return false; } - - if (!(ps = XMLookForTKV(stanza, "pubsub", "xmlns", PUBSUB)) && - !(ev = XMLookForTKV(stanza, "event", "xmlns", PUBSUB "#event"))) +#define PEP_NS "http://jabber.org/protocol/pubsub" + if (!(ps = XMLookForTKV(stanza, "pubsub", "xmlns", PEP_NS)) && + !(ev = XMLookForTKV(stanza, "event", "xmlns", PEP_NS "#event"))) { return false; } @@ -135,7 +101,7 @@ PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) XMLElement *items = ArrayGet(event->children, i); char *node = HashMapGet(items->attrs, "node"); - if ((call = HashMapGet(manager->node_table, node)) && *call) + if ((call = HashMapGet(manager->node_table, node))) { size_t j; /* Use the callback over all items */ @@ -143,13 +109,13 @@ PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza) { for (j = 0; j < ArraySize(items->children); j++) { - (*call)(manager, stanza, ArrayGet(items->children, j)); + call(manager, stanza, ArrayGet(items->children, j)); } return true; } /* ... or over "items" specifically. */ - (*call)(manager, stanza, items); + call(manager, stanza, items); return true; } } @@ -166,11 +132,6 @@ PEPManagerHandle(PEPManager *manager, XMLElement *stanza) } /* Check if it is a PEP stanza */ - if (IsPubsubRequest(stanza)) - { - Log(LOG_DEBUG, "UNIMPLEMENTED PUBSUB SUBSCRIPTION"); - /* TODO */ - } if (PEPManagerHandleEvent(manager, stanza)) { return true; @@ -181,21 +142,12 @@ PEPManagerHandle(PEPManager *manager, XMLElement *stanza) void DestroyPEPManager(PEPManager *manager) { - char *key; - PEPEvent *val; if (!manager) { return; } pthread_mutex_destroy(&manager->lock); - while (HashMapIterate(manager->node_table, &key, (void **) &val)) - { - Free(val); - } HashMapFree(manager->node_table); - - HashMapFree(manager->followers); - Free(manager); } diff --git a/src/XMPPThread/PEPs/Avatar.c b/src/XMPPThread/PEPs/Avatar.c index c42d260..819bcd0 100644 --- a/src/XMPPThread/PEPs/Avatar.c +++ b/src/XMPPThread/PEPs/Avatar.c @@ -72,7 +72,11 @@ PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) char *url = HashMapGet(item->attrs, "url"); XMLElement *request = CreateAvatarRequest(from, to, id); - XMPPSendStanza(jabber, request, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, request); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + XMLFreeElement(request); (void) url; /* TODO */ diff --git a/src/XMPPThread/PEPs/VCard.c b/src/XMPPThread/PEPs/VCard.c index 086e248..a57c948 100644 --- a/src/XMPPThread/PEPs/VCard.c +++ b/src/XMPPThread/PEPs/VCard.c @@ -113,7 +113,9 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) } } - XMPPSendStanza(jabber, reply, data->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, reply); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(reply); - (void) item; } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c deleted file mode 100644 index dc30400..0000000 --- a/src/XMPPThread/PresenceSub.c +++ /dev/null @@ -1,144 +0,0 @@ -#include "XMPPThread/internal.h" - -#include -#include -#include -#include -#include -#include - -#include - -static char * -SubscriptionHash(char *from, char *to) -{ - uint8_t *sum; - char *hash; - size_t len; - - len = strlen(from) + 1 + strlen(to); - sum = Malloc(len); - memset(sum, 0x00, len); - memcpy(&sum[0], from, strlen(from)); - memcpy(&sum[strlen(from) + 1], to, strlen(to)); - - hash = Base64Encode((const char *) sum, len); - Free(sum); - - return hash; -} -static void -DecodeSubscription(ParseeData *data, char *hash, char **from, char **to) -{ - char *sum; - if (!data || !hash || !from || !to) - { - return; - } - - sum = Base64Decode(hash, strlen(hash)); - *from = StrDuplicate(sum); - *to = StrDuplicate(sum + strlen(sum) + 1); - Free(sum); -} - -void -AddPresenceSubscriber(ParseeData *data, char *from, char *to) -{ - Db *database; - DbRef *ref; - char *hash; - if (!data || !from || !to) - { - return; - } - - database = data->db; - hash = SubscriptionHash(from, to); - ref = DbCreate(database, 2, "subs", hash); - if (!ref) - { - goto end; - } - - HashMapSet(DbJson(ref), "from", JsonValueString(from)); - HashMapSet(DbJson(ref), "to", JsonValueString(to)); - /* I don't think we need more information right now */ - -end: - DbUnlock(database, ref); - Free(hash); -} - -bool -IsSubscribed(ParseeData *data, char *user, char *to) -{ - Db *database; - char *hash; - bool ret; - if (!data || !user || !to) - { - return false; - } - - database = data->db; - hash = SubscriptionHash(user, to); - ret = DbExists(database, 2, "subs", hash); - Free(hash); - - return ret; -} - -void -ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza) -{ - XMPPComponent *jabber = data ? data->jabber : NULL; - Array *entries; - size_t i; - if (!data || !from || !stanza) - { - return; - } - - /* Copy our stanza so that we can freely modify it */ - stanza = XMLCopy(stanza); - - /* Start doing a storm on Mt. Subs. */ - entries = DbList(data->db, 1, "subs"); - for (i = 0; i < ArraySize(entries); i++) - { - char *entry = ArrayGet(entries, i); - char *entry_from = NULL, *entry_to = NULL; - char *storm_id; /* ooe */ - XMLElement *sub; - - DecodeSubscription(data, entry, &entry_from, &entry_to); - - if (!StrEquals(entry_to, from)) - { - goto end; - } - - Log(LOG_DEBUG, - "PRESENCE SYSTEM: " - "We should be brotkasting straight to %s (from %s)", - entry_from, from - ); - sub = XMLCopy(stanza); - XMLAddAttr(sub, "from", from); - XMLAddAttr(sub, "to", entry_from); - - /* TODO: Should we store IDs somewhere? */ - XMLAddAttr(sub, "id", (storm_id = StrRandom(16))); - - XMPPSendStanza(jabber, sub, data->config->max_stanza_size); - XMLFreeElement(sub); - Free(storm_id); - end: - Free(entry_from); - Free(entry_to); - } - DbListFree(entries); - XMLFreeElement(stanza); - -} diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 44f22f8..5d410f6 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -56,8 +57,6 @@ XMPPDispatcher(void *argp) if (!stanza) { - /* TODO: We shouldn't be busywaiting. Even with a sleep call. - */ UtilSleepMillis(10); continue; } @@ -67,15 +66,9 @@ XMPPDispatcher(void *argp) Log(LOG_DEBUG, "Received stanza='%s'.", stanza->name); } - if (ManageMUCStanza(args->muc, stanza)) - { - XMLFreeElement(stanza); - continue; - } - if (StrEquals(stanza->name, "presence")) { - PresenceStanza(args, stanza, thread); + PresenceStanza(args, stanza); XMLFreeElement(stanza); continue; } @@ -134,49 +127,6 @@ ParseeCongestion(void) return congestion; } -bool -XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza) -{ - ParseeData *args = XMPPGetManagerCookie(m); - char *trimmed_from; - char *from; - char *chat_id; - bool is_muc; - if (!m || !id || !stanza) - { - return false; - } - - from = HashMapGet(stanza->attrs, "from"); - trimmed_from = ParseeTrimJID(from); - is_muc = !!(chat_id = ParseeGetFromMUCID(args, trimmed_from)); - Free(trimmed_from); - Free(chat_id); -#define XMPP_COMMAND(f,l,n,t,s) \ - if (StrEquals(n, id)) \ - { \ - if (l == XMPPCMD_ALL) \ - { \ - return true; \ - } \ - else if (l == XMPPCMD_MUC) \ - { \ - return is_muc; \ - } \ - else if (l == XMPPCMD_ADMINS) \ - { \ - bool is_admin; \ - trimmed_from = ParseeTrimJID(from); \ - is_admin = ParseeIsAdmin(args, trimmed_from); \ - Free(trimmed_from); \ - return is_admin; \ - } \ - } - XMPPCOMMANDS -#undef XMPP_COMMAND - - return false; -} void * ParseeXMPPThread(void *argp) @@ -184,20 +134,16 @@ ParseeXMPPThread(void *argp) ParseeData *args = argp; XMPPComponent *jabber = args->jabber; XMLElement *stanza = NULL; - HashMap *await_table2; size_t i; - - bool error = false; /* Initialise the await table */ await_table = HashMapCreate(); /* Initialise the managers, and add all handlers. */ info.m = XMPPCreateManager(args); - XMPPManagerSetFilter(info.m, XMPPCommandFilter); { XMPPCommand *cmd; -#define XMPP_COMMAND(f,l,n,t,s) \ +#define XMPP_COMMAND(f,n,t,s) \ cmd = XMPPBasicCmd( \ n, t, f \ ); \ @@ -244,95 +190,56 @@ ParseeXMPPThread(void *argp) } } - while (!args->halted) + while (true) { - while (true) + char *id; + + stanza = XMLDecode(jabber->stream, false); + if (!stanza) { - char *id; - - stanza = XMLDecode(jabber->stream, false); - if (!stanza) + if (args->verbosity >= PARSEE_VERBOSE_COMICAL) { - /* Try to check if an error is abound */ - if (args->verbosity >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, "RECEIVED EOF."); - } - break; + Log(LOG_DEBUG, "RECEIVED EOF."); } + break; + } - if (args->verbosity >= PARSEE_VERBOSE_STANZA) + if (args->verbosity >= PARSEE_VERBOSE_STANZA) + { + Stream *output = StreamStderr(); + StreamPrintf(output, "-------STANZA BEGIN-------" "\n"); + XMLEncode(output, stanza); + StreamPrintf(output, "\n--------STANZA END--------" "\n"); + StreamFlush(output); + } + + id = HashMapGet(stanza->attrs, "id"); + if (id) + { + XMPPAwait *await; + /* Lock out the table to see if we're awaiting. */ + pthread_mutex_lock(&await_lock); + if ((await = HashMapGet(await_table, id))) { - Stream *output = StreamStderr(); - StreamPrintf(output, "-------STANZA BEGIN-------" "\n"); - XMLEncode(output, stanza); - StreamPrintf(output, "\n--------STANZA END--------" "\n"); - StreamFlush(output); - } + pthread_mutex_lock(&await->cond_lock); + await->stanza = stanza; + pthread_cond_signal(&await->condition); + pthread_mutex_unlock(&await->cond_lock); - id = HashMapGet(stanza->attrs, "id"); - if (id) - { - XMPPAwait *await; - /* Lock out the table to see if we're awaiting. */ - pthread_mutex_lock(&await_lock); - if ((await = HashMapGet(await_table, id))) - { - pthread_mutex_lock(&await->cond_lock); - await->stanza = stanza; - pthread_cond_signal(&await->condition); - pthread_mutex_unlock(&await->cond_lock); + HashMapDelete(await_table, id); - HashMapDelete(await_table, id); - - pthread_mutex_unlock(&await_lock); - continue; - } pthread_mutex_unlock(&await_lock); + continue; } - - /* Push it into the stanza FIFO. A dispatcher thread should then - * be able to freely grab a value(locked by a mutex). We can't make - * dispatchers read stanzas on their own, since that's _not_ how - * streams work, but this should mitigate some issues, and allow a - * few threads to be busy, while the rest of Parsee works. */ - PushStanza(&info, stanza); + pthread_mutex_unlock(&await_lock); } - pthread_mutex_lock(&args->halt_lock); - if (!args->halted) - { - Log(LOG_WARNING, "XMPP server is closing stream..."); - for (size_t i = 0; i < 50; i++) - { - UtilSleepMillis(100); /* Wait a bit so that temporary failures don't fuck everything up */ - Log(LOG_WARNING, "Restarting XMPP stream."); - /* This is the part where a new connection is being considered */ - XMPPFinishCompStream(jabber); - XMPPEndCompStream(jabber); - - args->jabber = XMPPInitialiseCompStream( - args->config->component_addr, - args->config->component_host, - args->config->component_port - ); - jabber = args->jabber; - if (!jabber || !XMPPAuthenticateCompStream(jabber, args->config->shared_comp_secret)) - { - /* Oops, there is something wrong! */ - Log(LOG_ERR, "Couldn't authenticate to XMPP server"); - XMPPEndCompStream(jabber); - args->jabber = NULL; - jabber = NULL; - if (i == 4) - { - pthread_mutex_unlock(&args->halt_lock); - break; - } - } - } - } - pthread_mutex_unlock(&args->halt_lock); + /* Push it into the stanza FIFO. A dispatcher thread should then + * be able to freely grab a value(locked by a mutex). We can't make + * dispatchers read stanzas on their own, since that's _not_ how + * streams work, but this should mitigate some issues, and allow a + * few threads to be busy, while the rest of Parsee works. */ + PushStanza(&info, stanza); } info.running = false; @@ -361,18 +268,12 @@ ParseeXMPPThread(void *argp) } ArrayFree(info.stanzas); - await_table2 = await_table; - await_table = NULL; - HashMapFree(await_table2); + HashMapFree(await_table); pthread_mutex_destroy(&info.lock); DestroyPEPManager(info.pep_manager); XMPPFreeManager(info.m); - if (error) - { - HttpServerStop(args->server); /* minor trolling */ - } return NULL; } diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 1b5087d..ebfd84e 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -33,7 +32,7 @@ TrimBase64(char *b64) while (*b64) { char ch[2] = { *b64, 0 }; - if (isspace((int) *b64)) + if (isspace(*b64)) { b64++; continue; @@ -47,106 +46,35 @@ TrimBase64(char *b64) return ret; } -static bool -AvatarGrab(ParseeData *data, char *mxc, char **mime, char **b64, size_t *len) -{ - char *mimei = NULL, *outi = NULL, *b64i = NULL; - size_t sizei; - if (!data || !mxc || !mime || !b64 || !len) - { - return false; - } - - if (!ASGrab(data->config, mxc, &mimei, &outi, &sizei)) - { - Free(mimei); - Free(outi); - return false; - } - - b64i = Base64Encode(outi, sizei); - Free(outi); - if (!b64i) - { - Free(mimei); - b64i = StrDuplicate(media_unknown); /* TODO: Different assets! */ - mimei = StrDuplicate("image/png"); - } - - *mime = mimei; - *b64 = b64i; - *len = sizei; - return true; -} - -XMLElement * -GenerateAvatarData(ParseeData *data, char *mxid) -{ - char *mxc = NULL, *mime = NULL, *b64 = NULL; - XMLElement *elem = NULL, *type, *binval; - size_t len = 0; - if (!data || !mxid) - { - return NULL; - } - - /* TODO: Use the right room for the avatar! */ - mxc = ASGetAvatar(data->config, NULL, mxid); - if (!mxc || !AvatarGrab(data, mxc, &mime, &b64, &len)) - { - goto end; - } - - elem = XMLCreateTag("PHOTO"); - type = XMLCreateTag("TYPE"); - binval = XMLCreateTag("BINVAL"); - - XMLAddChild(type, XMLCreateText(mime)); - XMLAddChild(binval, XMLCreateText(b64)); - - XMLAddChild(elem, type); - XMLAddChild(elem, binval); - -end: - Free(mime); - Free(mxc); - Free(b64); - return elem; -} - #define DISCO "http://jabber.org/protocol/disco#info" static XMLElement * -IQGenerateQuery(IQFeatures *features) +IQGenerateQuery(void) { - XMLElement *query; - if (!features) - { - return NULL; - } - query = XMLCreateTag("query"); + XMLElement *query = XMLCreateTag("query"); XMLAddAttr(query, "xmlns", DISCO); { XMLElement *feature; - size_t i; - for (i = 0; i < ArraySize(features->identity); i++) - { - XMPPIdentity *identity = ArrayGet(features->identity, i); +#define IdentitySimple(c,t,n) do \ + { \ + feature = XMLCreateTag("identity"); \ + XMLAddAttr(feature, "category", c); \ + XMLAddAttr(feature, "type", t); \ + XMLAddAttr(feature, "name", n); \ + XMLAddChild(query, feature); \ + } \ + while (0); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(f) do \ + { \ + feature = XMLCreateTag("feature"); \ + XMLAddAttr(feature, "var", f); \ + XMLAddChild(query, feature); \ + } \ + while (0); - feature = XMLCreateTag("identity"); - XMLAddAttr(feature, "category", identity->category); - XMLAddAttr(feature, "type", identity->type); - XMLAddAttr(feature, "name", identity->name); - - XMLAddChild(query, feature); - } - for (i = 0; i < ArraySize(features->adverts); i++) - { - char *var = ArrayGet(features->adverts, i); - - feature = XMLCreateTag("feature"); - XMLAddAttr(feature, "var", var); - XMLAddChild(query, feature); - } + IQ_ADVERT +#undef AdvertiseSimple } return query; @@ -156,7 +84,6 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) { char *from, *to, *id; XMLElement *iq_reply, *query; - IQFeatures *features; from = HashMapGet(stanza->attrs, "from"); to = HashMapGet(stanza->attrs, "to"); @@ -169,10 +96,9 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) XMLAddAttr(iq_reply, "type", "result"); XMLAddAttr(iq_reply, "id", id); - features = LookupJIDFeatures(to); - query = IQGenerateQuery(features); + query = IQGenerateQuery(); { - char *ver = XMPPGenerateVer(features); + char *ver = XMPPGenerateVer(); char *node = StrConcat(3, REPOSITORY, "#", ver); XMLAddAttr(query, "node", node); @@ -180,12 +106,13 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) Free(ver); } XMLAddChild(iq_reply, query); - FreeIQFeatures(features); - XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq_reply); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + XMLFreeElement(iq_reply); - - (void) args; } void @@ -374,7 +301,7 @@ IQResult(ParseeData *args, XMLElement *stanza, XMPPThread *thr) bool IQIsCommandList(ParseeData *args, XMLElement *stanza) { - char *parsee = NULL, *to; + char *parsee = NULL; XMLElement *query = XMLookForTKV( stanza, "query", "xmlns", "http://jabber.org/protocol/disco#items" @@ -389,27 +316,15 @@ IQIsCommandList(ParseeData *args, XMLElement *stanza) } parsee = ParseeJID(args); - to = HashMapGet(stanza->attrs, "to"); - ret = StrEquals(to, parsee) || StrEquals(to, args->config->component_host); + ret = StrEquals(HashMapGet(stanza->attrs, "to"), parsee); Free(parsee); return ret; } -static bool -IsInMUC(ParseeData *data, char *jid) -{ - char *trimmed = ParseeTrimJID(jid); - char *chat_id = ParseeGetFromMUCID(data, trimmed); - - Free(trimmed); - Free(chat_id); - return !!chat_id; -} void IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { XMPPComponent *jabber = args->jabber; - XMLElement *pubsub; char *from = HashMapGet(stanza->attrs, "from"); char *to = HashMapGet(stanza->attrs, "to"); char *id = HashMapGet(stanza->attrs, "id"); @@ -419,38 +334,33 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (IQIsCommandList(args, stanza)) { XMLElement *iq_reply = XMLCreateTag("iq"); - char *trimmed = ParseeTrimJID(from); - XMLAddAttr(iq_reply, "type", "result"); XMLAddAttr(iq_reply, "from", to); XMLAddAttr(iq_reply, "to", from); XMLAddAttr(iq_reply, "id", id); { XMLElement *q = XMLCreateTag("query"); - char *parsee_muc_jid = StrConcat(3, trimmed, "/", "parsee"); XMLAddAttr(q, "xmlns", "http://jabber.org/protocol/disco#items"); XMLAddAttr(q, "node", "http://jabber.org/protocol/commands"); - XMPPShoveCommandList(thr->info->m, - IsInMUC(args, from) ? parsee_muc_jid : to, - q, stanza - ); + XMPPShoveCommandList(thr->info->m, to, q); XMLAddChild(iq_reply, q); - Free(parsee_muc_jid); } - XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq_reply); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq_reply); - Free(trimmed); } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) { - char *to_matrix = ParseeGetBridgedUser(args, stanza); - char *name = ASGetName(args->config, NULL, to_matrix); - XMLElement *iqVCard; - Log(LOG_DEBUG, "vCard information GET for %s (%s)", to, to_matrix); + Log(LOG_INFO, "vCard information GET for %s", to); + /* TODO: "a compliant server MUST respond on behalf of the + * requestor and not forward the IQ to the requestee's + * connected resource". */ if (!strncmp(to, "parsee@", 7)) { - iqVCard = XMLCreateTag("iq"); + XMLElement *iqVCard = XMLCreateTag("iq"); XMLAddAttr(iqVCard, "from", to); XMLAddAttr(iqVCard, "to", from); XMLAddAttr(iqVCard, "id", id); @@ -476,97 +386,13 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - XMPPSendStanza(jabber, iqVCard, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iqVCard); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iqVCard); - Free(to_matrix); - Free(name); - return; - } - - Free(to_matrix); - to_matrix = ParseeDecodeMXID(to); - - iqVCard = XMLCreateTag("iq"); - XMLAddAttr(iqVCard, "from", to); - XMLAddAttr(iqVCard, "to", from); - XMLAddAttr(iqVCard, "id", id); - XMLAddAttr(iqVCard, "type", "result"); - { - XMLElement *vCard = XMLCreateTag("vCard"); - char *mto_link = ParseeGenerateMTO(to_matrix); - XMLAddAttr(vCard, "xmlns", "vcard-temp"); - { - XMLAddChild(vCard, GenerateAvatarData(args, to_matrix)); - - Free(mto_link); - } - XMLAddChild(iqVCard, vCard); - } - - XMPPSendStanza(jabber, iqVCard, args->config->max_stanza_size); - XMLFreeElement(iqVCard); - Free(to_matrix); - Free(name); - } -#define PS "http://jabber.org/protocol/pubsub" - else if ((pubsub = XMLookForTKV(stanza, "pubsub", "xmlns", PS))) - { - /* TODO: Pass this through the PEP manager */ - XMLElement *a_items = XMLookForTKV(pubsub, - "items", "node", "urn:xmpp:avatar:data" - ); - if (a_items) - { - /* Do, without regret, start shoving an avatar out the bus. - * NOTE: I explicitely choose to not do any manipulation - * because messing with random user images is inherently a - * risk I do *not* want to take. */ - char *to_matrix = ParseeDecodeMXID(to); - char *avatar = ASGetAvatar(args->config, NULL, to_matrix); - char *mime = NULL; - char *b64 = NULL; - size_t len = 0; - XMLElement *reply; - - AvatarGrab(args, avatar, &mime, &b64, &len); - - Log(LOG_DEBUG, "IQ-GET: PUBSUB AVATAR OF=%s", to_matrix); - /* Strike back with a response */ - reply = XMLCreateTag("iq"); - XMLAddAttr(reply, "type", "result"); - XMLAddAttr(reply, "to", from); - XMLAddAttr(reply, "from", to); - XMLAddAttr(reply, "id", HashMapGet(stanza->attrs, "id")); - { - XMLElement *ps = XMLCreateTag("pubsub"); - XMLElement *items = XMLCreateTag("items"); - XMLAddAttr(ps, "xmlns", PS); - XMLAddAttr(items, "node", "urn:xmpp:avatar:data"); - { - XMLElement *item = XMLCreateTag("item"); - XMLElement *data = XMLCreateTag("data"); - XMLAddAttr(item, "id", "TODO"); - XMLAddAttr(data, "xmlns", "urn:xmpp:avatar:data"); - - XMLAddChild(data, XMLCreateText(b64)); - - XMLAddChild(item, data); - XMLAddChild(items, item); - } - XMLAddChild(ps, items); - XMLAddChild(reply, ps); - } - - XMPPSendStanza(jabber, reply, args->config->max_stanza_size); - XMLFreeElement(reply); - - Free(to_matrix); - Free(avatar); - Free(mime); - Free(b64); } } -#undef PS else if (XMLookForTKV(stanza, "query", "xmlns", DISCO)) { IQDiscoGet(args, jabber, stanza); @@ -574,7 +400,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) else if (XMLookForTKV(stanza, "query", "xmlns", "jabber:iq:version")) { XMLElement *iq_reply, *query; - XMLElement *name, *version, *os; + XMLElement *name, *version; iq_reply = XMLCreateTag("iq"); XMLAddAttr(iq_reply, "to", from); @@ -585,34 +411,28 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) query = XMLCreateTag("query"); XMLAddAttr(query, "xmlns", "jabber:iq:version"); { - struct utsname info; name = XMLCreateTag("name"); version = XMLCreateTag("version"); - os = XMLCreateTag("os"); - uname(&info); XMLAddChild(name, XMLCreateText(NAME)); XMLAddChild(version, XMLCreateText(VERSION "[" CODE "]")); - XMLAddChild(os, XMLCreateText(info.sysname)); } XMLAddChild(query, name); XMLAddChild(query, version); - XMLAddChild(query, os); XMLAddChild(iq_reply, query); - XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq_reply); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(iq_reply); } else { - char *buf = NULL; - Stream *s = StrStreamWriter(&buf); Log(LOG_WARNING, "Unknown I/Q received:"); - XMLEncode(s, stanza); - StreamFlush(s); - StreamClose(s); - Log(LOG_WARNING, "%s", buf); - Free(buf); + XMLEncode(StreamStdout(), stanza); + StreamPrintf(StreamStdout(),"\n"); + StreamFlush(StreamStdout()); } } @@ -620,9 +440,6 @@ void IQError(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { /* TODO */ - (void) args; - (void) stanza; - (void) thr; } void IQSet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 13021df..75722e5 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -1,82 +1,14 @@ #include "XMPPThread/internal.h" #include -#include #include #include -#include #include #include #include -static void -LazyRegister(ParseeData *data, char *mxid, char *name) -{ - DbRef *ref; - char *hash = ParseeHMACS(data->id, mxid); - char *dbname; - if (!(ref = DbLock(data->db, 2, "users", hash))) - { - ASRegisterUser(data->config, mxid); - ref = DbCreate(data->db, 2, "users", hash); - if (ref) - { - HashMapSet(DbJson(ref), "mxid", JsonValueString(mxid)); - HashMapSet(DbJson(ref), - "ts", JsonValueInteger(UtilTsMillis()) - ); - } - } - dbname = GrabString(DbJson(ref), 1, "name"); - if (name && !StrEquals(dbname, name)) - { - ASSetName(data->config, mxid, name); - if (ref) - { - JsonValueFree(HashMapSet( - DbJson(ref), "name", JsonValueString(name) - )); - } - } - DbUnlock(data->db, ref); - Free(hash); -} -static char * -LazySend(ParseeData *args, char *mxid, char *mroom_id, char *type, HashMap *ev, uint64_t ts) -{ - HashMap *duplicate; - char *event; - if (!args || !mxid || !mroom_id || !ev) - { - return NULL; - } - if (!type) - { - type = "m.room.message"; - } - - duplicate = JsonDuplicate(ev); - event = ASSend( - args->config, mroom_id, mxid, - type, ev, ts - ); - if (event) - { - JsonFree(duplicate); - return event; - } - - ASInvite(args->config, mroom_id, mxid); - Free(ASJoin(args->config, mroom_id, mxid)); - - return ASSend( - args->config, mroom_id, mxid, - type, duplicate, ts - ); -} - static void ProcessChatstates(ParseeData *args, XMLElement *stanza) { @@ -112,24 +44,7 @@ ProcessChatstates(ParseeData *args, XMLElement *stanza) from_matrix = NULL; } if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES) || - XMLookForTKV(stanza, "inactive", "xmlns", CHAT_STATES)) - { - char *latest = NULL; - from_matrix = ParseeGetBridgedUser(args, stanza); - mroom_id = ParseeGetBridgedRoom(args, stanza); - - latest = ParseeLookupHead(mroom_id); - - ASType(args->config, from_matrix, mroom_id, false); - ASPresence(args->config, from_matrix, mroom_id, latest); - - Free(from_matrix); - Free(latest); - Free(mroom_id); - mroom_id = NULL; - from_matrix = NULL; - } - if (XMLookForTKV(stanza, "received", "xmlns", "urn:xmpp:receipts") || + XMLookForTKV(stanza, "received", "xmlns", "urn:xmpp:receipts") || XMLookForTKV(stanza, "displayed", "xmlns", "urn:xmpp:chat-markers:0")) { /* TODO: Use stanza ID if possible */ @@ -150,16 +65,6 @@ ProcessChatstates(ParseeData *args, XMLElement *stanza) } #undef CHAT_STATES } - -static float -TimeElapsed(uint64_t *rectime, uint64_t v) -{ - uint64_t time = UtilTsMillis(); - float t = ((time-v)/1000.f); - *rectime = time; - - return t; -} bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { @@ -178,29 +83,18 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *type = HashMapGet(stanza->attrs, "type"); bool chat = StrEquals(type, "chat"); size_t i; - uint64_t time, rectime; -#define Elapsed(v) (TimeElapsed(&rectime, v)) - to = NULL; from = NULL; decode_from = NULL; from_matrix = NULL; Log(LOG_DEBUG, " usage=%d", MemoryAllocated()); - time = UtilTsMillis(); - rectime = time; - from = HashMapGet(stanza->attrs, "from"); if (ParseeManageBan(args, from, NULL)) { XMLFreeElement(stanza); - Log(LOG_DEBUG, - " time=%f " - "usage=%d (%s:%d)", - Elapsed(time), - MemoryAllocated(), __FILE__, __LINE__ - ); + Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); return false; } @@ -213,25 +107,18 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *occ_id = occupant ? HashMapGet(occupant->attrs, "id") : NULL; if (occ_id) { - if (args->verbosity >= PARSEE_VERBOSE_COMICAL) - { - Log(LOG_DEBUG, - "'%s' has support for XEP-421, fetching OID=%s", - from, occ_id - ); - } + Log(LOG_DEBUG, + "'%s' has support for XEP-421, fetching OID=%s", + from, occ_id + ); ParseePushOIDTable(from, occ_id); } } - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "XEP-421: %fs", Elapsed(rectime)); - } if (StrEquals(type, "error")) { - char *type = NULL, *text = NULL, *user = NULL, *parsee = NULL; - char *message = NULL, *room = NULL; + char *type, *text, *user, *parsee; + char *message, *room; from = HashMapGet(stanza->attrs, "from"); to = HashMapGet(stanza->attrs, "to"); @@ -252,10 +139,10 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) message = StrConcat(3, type, ": ", text); room = ParseeGetBridgedRoom(args, stanza); - Free(LazySend( - args, parsee, room, NULL, - MatrixCreateNotice(message), - time + Free(ASSend( + args->config, room, parsee, + "m.room.message", + MatrixCreateNotice(message) )); end_error: @@ -264,20 +151,11 @@ end_error: Free(parsee); Free(room); Free(user); - Log(LOG_DEBUG, - " time=%f " - "usage=%d (%s:%d)", - Elapsed(time), - MemoryAllocated(), __FILE__, __LINE__ - ); + Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); return false; } - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "Error management: %fs", Elapsed(rectime)); - } - if (moderated && !(!chat && strncmp(HashMapGet(stanza->attrs, "to"), "parsee@", 7))) + if (moderated) { /* TODO: Parsee MUST check if it is a valid MUC */ char *resource = ParseeGetResource(from); @@ -303,39 +181,29 @@ end_error: body = XMLookForUnique(stanza, "body"); PEPManagerHandle(thr->info->pep_manager, stanza); - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "PEP management: %fs", Elapsed(rectime)); - } + + ProcessChatstates(args, stanza); to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); decode_from = ParseeLookupJID(from); from_matrix = ParseeEncodeJID(args->config, decode_from, true); room = ParseeFindDMRoom(args, to, from); data = body ? ArrayGet(body->children, 0) : NULL; - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "Fetching user info: %fs", Elapsed(rectime)); - } /* TODO: CLEAN THAT UP INTO A CREATEDM FUNCTION */ mroom_id = ParseeGetBridgedRoom(args, stanza); Log(LOG_DEBUG, "Bridging event to '%s'...", mroom_id); - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "Fetching bridge: %fs", Elapsed(rectime)); - } - char *trim = ParseeTrimJID(from); if (!mroom_id && !room && !XMPPIsParseeStanza(stanza) && - to && *to == '@' && !XMPPQueryMUC(jabber, trim, NULL)) + to && *to == '@') { DbRef *room_ref; HashMap *room_json; char *from = HashMapGet(stanza->attrs, "from"); - LazyRegister(args, from_matrix, NULL); + ASRegisterUser(args->config, from_matrix); room = ASCreateDM(args->config, from_matrix, to); mroom_id = StrDuplicate(room); + Log(LOG_INFO, "Creating a DM to '%s'(%s)...", to, mroom_id); if (room) { room_ref = DbCreate(args->db, 3, "rooms", room, "data"); @@ -346,15 +214,12 @@ end_error: ParseePushDMRoom(args, to, from, room); } } - Free(trim); /* TODO: THIS IS A HACK. THIS CODE IGNORES ALL MUC MESSAGES EVER * SENT TO NON-PARSEE PUPPETS, AS A "FIX" TO THE MULTITHREADED * ISSUE. * - * I HATE THIS. I NEED TO FIND A BETTER WAY. - * - * Actually, is it even _that_ bad? */ + * I HATE THIS. I NEED TO FIND A BETTER WAY. */ if (!chat && strncmp(HashMapGet(stanza->attrs, "to"), "parsee@", 7)) { goto end; @@ -373,18 +238,20 @@ end_error: ps = CreatePubsubRequest( parsee, decode_from, "urn:xmpp:avatar:metadata" ); - XMPPSendStanza(jabber, ps, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, ps); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(ps); ps = CreatePubsubRequest( parsee, trim, "urn:xmpp:avatar:metadata" ); - XMPPSendStanza(jabber, ps, args->config->max_stanza_size); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, ps); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); XMLFreeElement(ps); - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "Subscription to XEP-0084: %fs", Elapsed(rectime)); - } Free(parsee); Free(trim); @@ -393,26 +260,15 @@ end_error: if (ParseeVerifyAllStanza(args, stanza) && !replaced) { XMLElement *oob, *oob_data; - char *chat_id = ParseeGetFromMUCID(args, from); - bool media_enabled = chat_id ? - ParseeIsMediaEnabled(args, chat_id) : - true ; - bool is_parsee; - /* Note that chat_id still has meaningful info as a boolean - * despite being freed */ - Free(chat_id); + pthread_mutex_unlock(&thr->info->chk_lock); - - parsee = ParseeJID(args); - is_parsee = StrEquals(to, parsee); - Free(parsee); - parsee = NULL; - - LazyRegister(args, encoded, !chat ? res : NULL); - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) + ASRegisterUser(args->config, encoded); + if (!chat) { - Log(LOG_DEBUG, "Matrix registration: %fs", Elapsed(rectime)); + ASSetName(args->config, encoded, res); } + ASInvite(args->config, mroom_id, encoded); + Free(ASJoin(args->config, mroom_id, encoded)); reactions = XMLookForTKV(stanza, "reactions", "xmlns", "urn:xmpp:reactions:0" @@ -420,12 +276,7 @@ end_error: /* Check if it is a media link */ oob = XMLookForTKV(stanza, "x", "xmlns", "jabber:x:oob"); - if (chat_id && StrEquals(type, "chat") && !is_parsee) - { - /* Very clearly a MUC DM. */ - event_id = NULL; - } - else if (oob && data && media_enabled) + if (oob && data) { char *mxc, *mime = NULL; HashMap *content = NULL; @@ -435,27 +286,24 @@ end_error: if (oob_data) { - FileInfo *info = FileInfoFromXMPP(stanza); mxc = ASReupload(args->config, oob_data->data, &mime); if (mxc) { - content = MatrixCreateMedia( - mxc, data->data, mime, info - ); + content = MatrixCreateMedia(mxc, data->data, mime); + /* Yeah, no, I'm not modifying the media creation code. */ HashMapSet(content, "at.kappach.at.parsee.external", JsonValueString(oob_data->data) ); ShoveStanza(content, stanza); - event_id = LazySend( - args, encoded, mroom_id, NULL, - content, time + event_id = ASSend( + args->config, mroom_id, encoded, + "m.room.message", content ); Free(mxc); } - FileInfoFree(info); Free(mime); } } @@ -492,13 +340,13 @@ end_error: reaction = ArrayGet(react_child, i); react_data = ArrayGet(reaction->children, 0); - Free(LazySend( - args, encoded, mroom_id, "m.reaction", + Free(ASSend( + args->config, mroom_id, encoded, + "m.reaction", ShoveStanza( MatrixCreateReact(event_id, react_data->data), stanza - ), - time + ) )); } Free(event_id); @@ -521,15 +369,6 @@ end_error: * too. Go figure. */ size_t off = reply_to ? ParseeFindDatastart(data->data) : 0; - size_t stanzaoff = XMPPGetReplyOffset(stanza); - if (reply_to && stanzaoff != -1) - { - off = UnistrGetUTFOffset(data->data, stanzaoff); - } - if (data->data && off >= strlen(data->data)) - { - off = 0; - } HashMap *ev = MatrixCreateMessage(data->data + off); if (reply_to) { @@ -538,9 +377,9 @@ end_error: Free(reply_id); } ShoveStanza(ev, stanza); - event_id = LazySend( - args, encoded, mroom_id, NULL, - ev, time + event_id = ASSend( + args->config, mroom_id, encoded, + "m.room.message", ev ); } pthread_mutex_lock(&thr->info->chk_lock); @@ -561,9 +400,9 @@ end_error: ); Log(LOG_DEBUG, "Replacing events in %s(%s)", mroom_id, event_id); - Free(LazySend( - args, encoded, mroom_id, NULL, - ev, time + Free(ASSend( + args->config, mroom_id, encoded, + "m.room.message", ev )); ParseePushAllStanza(args, stanza, event_id); pthread_mutex_unlock(&thr->info->chk_lock); @@ -589,12 +428,6 @@ end_error: } } - ProcessChatstates(args, stanza); - if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) - { - Log(LOG_DEBUG, "Chatstate management: %fs", Elapsed(rectime)); - } - end: Free(mroom_id); mroom_id = NULL; @@ -602,12 +435,7 @@ end: Free(decode_from); Free(room); Free(to); - Log(LOG_DEBUG, - " time=%f " - "usage=%d (%s:%d)", - (UtilTsMillis()-time)/1000.f, - MemoryAllocated(), __FILE__, __LINE__ - ); + Log(LOG_DEBUG, " usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__); return true; } diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 947fc4b..225a361 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -56,62 +56,8 @@ GuessStatus(XMLElement *stanza) } return USER_STATUS_ONLINE; } - -static Array * -GetStatuses(XMLElement *info) -{ - XMLElement *child; - Array *ret; - size_t i; - if (!info) - { - return NULL; - } - - ret = ArrayCreate(); - for (i = 0; i < ArraySize(info->children); i++) - { - child = ArrayGet(info->children, i); - if (StrEquals(child->name, "status")) - { - ArrayAdd(ret, HashMapGet(child->attrs, "code")); - } - } - - return ret; -} - -static void -FreeStatuses(Array *statuses) -{ - if (!statuses) - { - return; - } - - ArrayFree(statuses); -} -static bool -HasStatus(Array *statuses, const char *code) -{ - size_t i; - if (!statuses || !code) - { - return false; - } - - for (i = 0; i < ArraySize(statuses); i++) - { - if (StrEquals(ArrayGet(statuses, i), code)) - { - return true; - } - } - - return false; -} void -PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) +PresenceStanza(ParseeData *args, XMLElement *stanza) { #define MUC_USER_NS "http://jabber.org/protocol/muc#user" XMLElement *user_info; @@ -119,20 +65,6 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLElement *status = XMLookForUnique(stanza, "status"); char *oid = HashMapGet(stanza->attrs, "from"); - char *dst = HashMapGet(stanza->attrs, "to"); - char *type = HashMapGet(stanza->attrs, "type"); - - if (StrEquals(type, "subscribe")) - { - Log(LOG_WARNING, "!PRESENCE SUBSCRIPTION REQUEST! (%s:%s)", oid, dst); - AddPresenceSubscriber(args, oid, dst); /* TODO: Send presence updates - * whenever possible. */ - } - - if (PEPManagerHandle(thr->info->pep_manager, stanza)) - { - return; - } if (ServerHasXEP421(args, oid)) { @@ -143,6 +75,10 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *occ_id = occupant ? HashMapGet(occupant->attrs, "id") : NULL; if (occ_id) { + Log(LOG_DEBUG, + "'%s' has support for XEP-421, fetching OID=%s", + oid, occ_id + ); ParseePushOIDTable(oid, occ_id); } } @@ -150,33 +86,27 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if ((user_info = XMLookForTKV(stanza, "x", "xmlns", MUC_USER_NS))) { XMLElement *item = XMLookForUnique(user_info, "item"); - Array *statuses = GetStatuses(user_info); -#define IsStatus(code) (HasStatus(statuses, #code)) + XMLElement *status = XMLookForUnique(user_info, "status"); +#define IsStatus(code) (status && \ + StrEquals(HashMapGet(status->attrs, "code"), #code)) char *jid = item ? HashMapGet(item->attrs, "jid") : NULL; char *trim = ParseeTrimJID(jid); char *from = NULL; + char *type = HashMapGet(stanza->attrs, "type"); char *room = ParseeGetBridgedRoom(args, stanza); - char *decode_from = NULL, *real_matrix = NULL; + char *decode_from, *real_matrix; char *matrix_user_pl = ParseeEncodeJID(args->config, trim, false); - char *affiliation = item ? HashMapGet(item->attrs, "affiliation") : NULL; - char *role = item ? HashMapGet(item->attrs, "role") : NULL; + char *affiliation = HashMapGet(item->attrs, "affiliation"); + char *role = HashMapGet(item->attrs, "role"); int power_level = 0; char *parsee = ParseeMXID(args); - char *parsee_j = ParseeJID(args); - char *muc = ParseeTrimJID(HashMapGet(stanza->attrs, "from")); - char *parsee_muc = StrConcat(3, muc, "/", "parsee"); Free(trim); - if (!item) - { - goto end_item; - } if (jid) { ParseePushJIDTable(oid, jid); } - ParseePushAffiliationTable(oid, affiliation, role); decode_from = ParseeLookupJID(oid); real_matrix = ParseeDecodeMXID(decode_from); @@ -205,16 +135,22 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (StrEquals(role, "visitor")) { - if (!StrEquals(HashMapGet(stanza->attrs, "to"), parsee_j) && + char *parsee = ParseeJID(args); + if (!StrEquals(HashMapGet(stanza->attrs, "to"), parsee) && IsStatus(110)) { + char *muc = ParseeTrimJID(HashMapGet(stanza->attrs, "from")); char *usr = HashMapGet(stanza->attrs, "to"); /* Ask for voice in a visitor self-presence. We do not notify * the user, as an error MUST occur, which is handled and * logged out. */ XMPPRequestVoice(args->jabber, usr, muc); + + Free(muc); } + + Free(parsee); } /* Set the user's PL @@ -254,7 +190,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) { ASBan(args->config, room, real_matrix); } - else if (IsStatus(307) && !IsStatus(333)) + else if (IsStatus(307)) { ASKick(args->config, room, real_matrix); } @@ -268,37 +204,16 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ASLeave(args->config, room, real_matrix); } } - if (StrEquals(type, "unavailable") && - (StrEquals(jid, parsee_muc) || StrEquals(jid, parsee_j)) - && IsStatus(301)) - { - char *chat_id = ParseeGetFromRoomID(args, room); - ParseeUnlinkRoom(args, chat_id); - Free(ASSend( - args->config, room, parsee, - "m.room.message", - MatrixCreateNotice("This room has been unlinked."), - 0 - )); - ASLeave(args->config, room, parsee); - Free(chat_id); - } - -end_item: - Free(muc); Free(from); - Free(parsee_muc); Free(decode_from); Free(real_matrix); Free(matrix_user_pl); - Free(parsee_j); Free(parsee); Free(room); - FreeStatuses(statuses); } - if (status && !StrEquals(type, "unavailable")) + if (status) { XMLElement *status_data = ArrayGet(status->children, 0); char *decode_from = ParseeLookupJID(oid); @@ -309,8 +224,6 @@ end_item: status_str = status_data->data; } - - /* TODO: "The server will automatically set a user's presence to * unavailable if their last active time was over a threshold value * (e.g. 5 minutes)." @@ -386,8 +299,11 @@ end_item: vcard_request = CreateVCardRequest( from, HashMapGet(stanza->attrs, "from") ); + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, vcard_request); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); - XMPPSendStanza(jabber, vcard_request, args->config->max_stanza_size); XMLFreeElement(vcard_request); Free(from); } diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index efdd300..d937b8a 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -32,17 +32,13 @@ IdentitySimple("client", "pc", NAME " v" VERSION " bridge") \ IdentitySimple("component", "generic", "Parsee's component") -typedef struct IQFeatures { - Array *identity; - Array *adverts; -} IQFeatures; +typedef struct PEPManager PEPManager; +typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item); + typedef struct XMPPIdentity { char *category, *type, *lang, *name; } XMPPIdentity; -typedef struct PEPManager PEPManager; -typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item); - typedef struct XMPPThread XMPPThread; typedef struct XMPPThreadInfo { /* A FIFO of stanzas inbound, to be read by dispatcher @@ -69,29 +65,6 @@ struct XMPPThread { int ICollate(unsigned char *cata, unsigned char *catb); int IdentitySort(void *idap, void *idbp); -IQFeatures * CreateIQFeatures(void); -void AddIQIdentity(IQFeatures *, char *category, char *lang, char *type, char *name); -void AdvertiseIQFeature(IQFeatures *, char *feature); -void FreeIQFeatures(IQFeatures *); - -/** - * Looks up the features supported by a JID - * ---------------------- - * Returns: an IQ featureset[LA:HEAP] | NULL - * Thrasher: FreeIQFeatures - * Modifies: NOTHING */ -IQFeatures * LookupJIDFeatures(char *jid); - -/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. - * -------- - * Returns: A base64 encoded ver hash[LA:HEAP] - * Modifies: NOTHING - * See-Also: https://xmpp.org/extensions/xep-0115.html */ -char * XMPPGenerateVer(IQFeatures *features); - -/* Annotates a presence with https://xmpp.org/extensions/xep-0115.html */ -void XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features); - char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza); char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id); char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza); @@ -105,7 +78,7 @@ XMLElement * CreatePubsubRequest(char *from, char *to, char *node); bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); -void PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); +void PresenceStanza(ParseeData *args, XMLElement *stanza); bool ServerHasXEP421(ParseeData *data, char *from); @@ -116,7 +89,6 @@ PEPManager * CreatePEPManager(ParseeData *data, void *cookie); void * PEPManagerCookie(PEPManager *manager); void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event); bool PEPManagerHandle(PEPManager *manager, XMLElement *stanza); -void PEPManagerBroadcast(PEPManager *manager, char *as, XMLElement *item); void DestroyPEPManager(PEPManager *manager); /* PEP callbacks for the handler */ @@ -124,7 +96,3 @@ void PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item); void PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item); char * ScrambleOID(ParseeData *data, char *opaque_oid); - -/* Presence management */ -void AddPresenceSubscriber(ParseeData *data, char *from, char *to); -bool IsSubscribed(ParseeData *data, char *user, char *to); diff --git a/src/include/AS.h b/src/include/AS.h index 562d172..1d993e1 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -29,7 +29,7 @@ extern void ASAuthenticateRequest(const ParseeConfig *, HttpClientContext *); extern bool ASRegisterUser(const ParseeConfig *, char *); /* Pings the homeserver to get attention. */ -extern bool ASPing(const ParseeConfig *); +extern void ASPing(const ParseeConfig *); /** Joins a room from an {id} and a given {user} we want to masquerade * as. @@ -67,8 +67,7 @@ extern HashMap * ASFind(const ParseeConfig *, char *, char *); /* Sends a message event with a specific type and body. * Said body is freed during the function's execution. */ -extern char * -ASSend(const ParseeConfig *, char *, char *, char *, HashMap *, uint64_t ts); +extern char * ASSend(const ParseeConfig *, char *, char *, char *, HashMap *); extern void ASType(const ParseeConfig *, char *, char *, bool); extern void ASPresence(const ParseeConfig *, char *, char *, char *); @@ -142,14 +141,6 @@ extern void ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, ch * Modifies: NOTHING */ extern char * ASGetName(const ParseeConfig *c, char *room, char *user); -/** Returns the user's avatar in a room, or a the global user avatar, to be - * Free'd - * ------------- - * Returns: The user's name in the [HEAP] | NULL - * Thrasher: Free - * Modifies: NOTHING */ -extern char * ASGetAvatar(const ParseeConfig *c, char *room, char *user); - /** Uploads data to Matrix to be used later * ---------------- * Returns: A valid MXC URI[HEAP] | NULL @@ -179,16 +170,4 @@ extern Array * ASGetRelations(const ParseeConfig *c, size_t n, char *room, char * Thrashes: {relations} * See-Also: ASGetRelations */ extern void ASFreeRelations(Array *relations); - -/** Returns the MIME and SHA-1 hash of a media entry, in one fell swoop. - * ----------------- - * Returns: whenever the media exists - * Modifies: {mime}[HEAP], {sha}[HEAP] */ -extern bool ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha); - -/** Retrieves media off an MXC link. - * ------------ - * Returns: whenever the media exists - * Modifies {mime}[HEAP], {out}[HEAP], {len} */ -extern bool ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len); #endif diff --git a/src/include/Bot.h b/src/include/Bot.h index 3154a3a..e2c0340 100644 --- a/src/include/Bot.h +++ b/src/include/Bot.h @@ -26,7 +26,7 @@ Free(ASSend( \ data->config, id, profile, \ "m.room.message", \ - MatrixCreateNotice(rep), 0 \ + MatrixCreateNotice(rep) \ )); \ } \ while(0) @@ -45,7 +45,7 @@ Free(ASSend( \ data->config, id, profile, \ "m.room.message", \ - MatrixCreateNotice(formatted), 0 \ + MatrixCreateNotice(formatted) \ )); \ Free(formatted); \ } \ diff --git a/src/include/FileInfo.h b/src/include/FileInfo.h deleted file mode 100644 index 3d98c9b..0000000 --- a/src/include/FileInfo.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PARSEE_FILEINFO_H -#define PARSEE_FILEINFO_H - -#include "XML.h" - -typedef struct FileInfo { - int width; - int height; - int size; -} FileInfo; - -/** Grab file metadata through SIMS. - * ---------------- - * Returns: File information(SIMS)[HEAP] - * Thrasher: FileInfoFree */ -extern FileInfo * FileInfoFromXMPP(XMLElement *stanza); - -/** Frees all information related with file metadata. - * -------------- - * Thrashes: info */ -extern void FileInfoFree(FileInfo *info); - -#endif diff --git a/src/include/MUCServ.h b/src/include/MUCServ.h deleted file mode 100644 index f9a2e4b..0000000 --- a/src/include/MUCServ.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PARSEE_MUCSERV_H -#define PARSEE_MUCSERV_H - -/*-* An easy interface for handling MUCs. - */ - -typedef struct MUCServer MUCServer; - -#include - -#include - -/** Creates a MUC server handle given a ParseeData handle. - * This handle shall be used for all MUC-related operations. - * ---------------------------------------------------------- - * Returns: a MUC server handle[HEAP] | NULL - * Thrasher: FreeMUCServer - * See-Also: https://xmpp.org/extensions/xep-0045.html */ -extern MUCServer * CreateMUCServer(ParseeData *data); - -/** Manages a stanza from a MUC, and returns true if the stanza - * was actually processed by the MUC server. - * ------------------------------------------------------------- - * See-Also: CreateMUCServer */ -extern bool ManageMUCStanza(MUCServer *serv, XMLElement *stanza); - -/** Checks if a MUC(from its localpart, so - * '#foobar@bridge.blow.hole' -> 'foobar') exists. - * -------------- - * Returns: whenever the MUC exists */ -extern bool MUCServerExists(MUCServer *serv, char *muc); - -/** Destroys all memory and references from a MUC server handle. - * -------------- - * Thrashes: CreateMUCServer - * See-Also: https://xmpp.org/extensions/xep-0045.html */ -extern void FreeMUCServer(MUCServer *serv); - -#endif diff --git a/src/include/Matrix.h b/src/include/Matrix.h index fb0b5f7..0ffb7ec 100644 --- a/src/include/Matrix.h +++ b/src/include/Matrix.h @@ -2,9 +2,6 @@ #define PARSEE_MATRIX_H #include -#include - -#include "FileInfo.h" /* A simple representation of everything. It is not as complex as * Telodendria's CommonID parser, simply because Parsee does not @@ -21,12 +18,6 @@ typedef struct UserID { * Thrasher: Free */ extern UserID * MatrixParseID(char *user); -/** Attempts to parse a Matrix ID from a matrix.to URL. - * ------------------------------------------------- - * Returns: a valid user ID[HEAP] | NULL - * Thrasher: Free */ -extern UserID * MatrixParseIDFromMTO(Uri *uri); - /* Creates an error message JSON, with the specified code and message. */ extern HashMap * MatrixCreateError(char *err, char *msg); @@ -42,7 +33,7 @@ extern HashMap * MatrixCreateReact(char *event, char *body); extern HashMap * MatrixCreateReplace(char *event, char *body); /* Creates the content for a media file. */ -extern HashMap * MatrixCreateMedia(char *mxc, char *body, char *mime, FileInfo *info); +extern HashMap * MatrixCreateMedia(char *mxc, char *body, char *mime); /* Creates the content for a m.room.name state event */ extern HashMap * MatrixCreateNameState(char *name); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 4b1f7aa..e19fd42 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -18,12 +18,9 @@ typedef struct ParseeData ParseeData; #include #include -#include - #define PARSEE_VERBOSE_NONE 0 #define PARSEE_VERBOSE_LOG 1 -#define PARSEE_VERBOSE_TIMINGS 2 -#define PARSEE_VERBOSE_STANZA 3 +#define PARSEE_VERBOSE_STANZA 2 #define PARSEE_VERBOSE_COMICAL 53 /* MINUTES */ typedef struct ParseeConfig { @@ -41,18 +38,12 @@ typedef struct ParseeConfig { /* Homeserver port info */ char *homeserver_host; int homeserver_port; - int homeserver_tls; - - bool accept_pings; - bool ignore_bots; /* ------- JABBER -------- */ - char *component_addr; char *component_host; char *shared_comp_secret; int component_port; - size_t max_stanza_size; /* ------- DB -------- */ char *db_path; @@ -67,9 +58,7 @@ typedef struct ParseeData { HttpRouter *router; CommandRouter *handler; - HttpServer *server; XMPPComponent *jabber; - MUCServer *muc; Db *db; char *id; @@ -78,10 +67,6 @@ typedef struct ParseeData { HashMap *oid_servers; pthread_mutex_t oidl; - - /* If Parsee was intentionally halted */ - bool halted; - pthread_mutex_t halt_lock; } ParseeData; typedef struct Argument { @@ -94,7 +79,6 @@ typedef struct Argument { const char *description; } Argument; -/* A few helpful macros to make JSON less of a PITA */ #define GrabString(obj, ...) JsonValueAsString(JsonGet(obj, __VA_ARGS__)) #define GrabInteger(obj, ...) JsonValueAsInteger(JsonGet(obj, __VA_ARGS__)) #define GrabBoolean(obj, ...) JsonValueAsBoolean(JsonGet(obj, __VA_ARGS__)) @@ -115,12 +99,9 @@ typedef struct Argument { /* A base64-encoded Parsee logo */ extern const char media_parsee_logo[]; -/* "Unknown avatar" */ -extern const char media_unknown[]; -/* An ASCII-art rendition of "小橋". - * I'm sorry for its quality. If anyone wants to redraw it, feel free. */ -#define PARSEE_ASCII_LINES 8 +/* An ASCII-art rendition of "小橋" */ +#define PARSEE_ASCII_LINES 9 extern const char *parsee_ascii[PARSEE_ASCII_LINES]; /** @@ -131,9 +112,6 @@ extern void ParseePrintASCII(void); /** * Checks if two versions of Parsee can be considered "compatible". - * This is mainly used for things like database operations. TODO: - * Make an auto-upgrade system to comply with the (undocumented) - * rule of "Don't Make The Sysadmin Think About Parsee Too Much". * --------------- * Modifies: NOTHING */ extern bool ParseeIsCompatible(char *ver1, char *ver2); @@ -284,47 +262,6 @@ extern char * ParseeGetRoomID(ParseeData *, char *chat_id); /* Finds the MUC JID from a chat ID */ extern char * ParseeGetMUCID(ParseeData *, char *chat_id); -/** Fetches a configuration value from a key in a chat(given a Chat ID), - * as a string or NULL. Keys are to be stored like Java packages(reveres DNS). - * Parsee has the right over any key with the 'p.' prefix. - * ----------------------------------- - * Returns: a valid string[HEAP] | NULL - * Modifies: NOTHING - * See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeSetChatSetting */ -extern char * -ParseeGetChatSetting(ParseeData *data, char *chat, char *key); - -/** Fetches the entire configuration in a chat(given a Chat ID), as an hashmap - * of strings. - * ----------------------------------- - * Returns: a valid string[HEAP] | NULL - * Modifies: NOTHING - * Thrasher: ParseeFreeChatSettings - * See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeSetChatSetting, ParseeGetChatSetting */ -extern HashMap * -ParseeGetChatSettings(ParseeData *data, char *chat); - -/** Destroys memory allocated from a call to {ParseeGetChatSettings}. - * ----------------------- - * Returns: NOTHING - * Modifies: {settings} - * Thrashes: {settings} - * See-Also: ParseeGetChatSettings */ -extern void -ParseeFreeChatSettings(HashMap *settings); - -/** Replaces a configuration key-value pair within the chat's context, which - * can be read with {ParseeGetChatSetting}. - * ------------------------------------- - * Returns: NOTHING - * Modifies: the chat context - * See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeGetChatSetting */ -extern void -ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val); - -extern bool -ParseeIsMediaEnabled(ParseeData *data, char *chat_id); - /* Pushes a stanza ID to a chat ID */ extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender); extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender); @@ -341,11 +278,7 @@ extern bool ParseeGetDMOrigin(ParseeData *data, char *chat_id, char *ev, char ** /* Sends presence requests for every MUC around as a fake JID */ extern void ParseeSendPresence(ParseeData *); -/** Initialises signal-handling code within Parsee. - * -------------------- - * Modifies: the signal handler - * Returns: whenever it has properly been setup */ -extern bool ParseeInitialiseSignals(ParseeData *data, pthread_t xmpp); +extern bool ParseeInitialiseSignals(HttpServer *, pthread_t, XMPPComponent *); /* Job used to cleanup Parsee data that isn't necessary anymore. */ extern void ParseeCleanup(void *data); @@ -353,13 +286,9 @@ extern void ParseeCleanup(void *data); /* Finds the offset of the first line without a '>' at its start. */ extern int ParseeFindDatastart(char *data); -/* Finds the offset of the first line without a '>' at its start(as - * Unicode codepoints). */ -extern int ParseeFindDatastartU(char *data); - /* XMPP-ifies a message event to XEP-0393 if possible. */ -extern char * ParseeXMPPify(ParseeData *data, HashMap *event); +extern char * ParseeXMPPify(HashMap *event); /* Finds an event ID from an ID in the stanza's attributes */ extern char * ParseeEventFromID(ParseeData *d, char *c_id, char *ori_id); @@ -369,18 +298,13 @@ extern char * ParseeDMEventFromID(ParseeData *d, char *r_id, char *ori_id); extern char * ParseeDMEventFromSID(ParseeData *d, char *r_id, char *ori_id); /* Gets a Parsee "shim" link to an MXC, usable as unauth for a limited time */ -extern char * ParseeToUnauth(ParseeData *data, char *mxc, char *filename); +extern char * ParseeToUnauth(ParseeData *data, char *mxc); extern void ParseeInitialiseOIDTable(void); extern void ParseePushOIDTable(char *muc, char *occupant); extern char *ParseeLookupOID(char *muc); extern void ParseeDestroyOIDTable(void); -extern void ParseeInitialiseAffiliationTable(void); -extern void ParseePushAffiliationTable(char *user, char *affiliation, char *role); -extern bool ParseeLookupAffiliation(char *muc, char **affiliation, char **role); -extern void ParseeDestroyAffiliationTable(void); - extern void ParseeInitialiseJIDTable(void); extern void ParseePushJIDTable(char *muc, char *bare); extern char *ParseeLookupJID(char *muc); @@ -400,17 +324,10 @@ extern void ParseeDestroyNickTable(void); * to ban them from rooms where Parsee has the ability to do so ("noflying"). * --------------- * Returns: NOTHING - * See-Also: ParseeManageBan, ParseeGlobalUnban + * See-Also: ParseeManageBan * Modifies: the database */ extern void ParseeGlobalBan(ParseeData *, char *user, char *reason); -/** Revokes a user/room/MUC's nofly status - * --------------- - * Returns: NOTHING - * See-Also: ParseeManageBan, ParseeGlobalBan - * Modifies: the database */ -extern void ParseeGlobalUnban(ParseeData *, char *user); - /** Verifies if a user was banned globally. If so (and if {room} is set), * tries to ban the user from it. * --------------- @@ -423,8 +340,7 @@ extern bool ParseeManageBan(ParseeData *, char *user, char *room); extern bool ParseeVerifyDMStanza(ParseeData *data, char *room_id, char *id); -/** Checks if a Matrix/XMPP user is considered as "administrator" by - * Parsee. +/** Checks if a Matrix/XMPP user is considered as "administrator" by Parsee. * ---------------------- * Returns: (whenever the user is an admin) * Modifies: NOTHING */ @@ -485,22 +401,4 @@ extern void ParseeSetThreads(int xmpp, int http); extern char * ParseeHMAC(char *key, uint8_t *msg, size_t msglen); #define ParseeHMACS(key, msg) ParseeHMAC(key, (uint8_t *) msg, strlen(msg)) -/** Broadcasts a stanza from a user to any that may be interested by it - * (PEP or subscription) - * ------------------------------------- - * Returns: NOTHING */ -extern void ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *s); - -/** Destroys the mapping between a MUC and a room from a chat ID. - * ---------------- - * Modifies: the DB's room mappings - * Returns: NOTHING */ -extern void ParseeUnlinkRoom(ParseeData *data, char *chat_id); - -/** Verifies if there is no whitelists OR that a MUC's server is whitelisted. - * ---------------------- - * Returns: if a MUC is to be allowed - * Modifies: NOTHING */ -extern bool ParseeIsMUCWhitelisted(ParseeData *data, char *muc); - #endif diff --git a/src/include/Routes.h b/src/include/Routes.h index 664032b..369a0d7 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -27,10 +27,6 @@ typedef struct ParseeCmdArg { "ban-list", CmdNoFlyList, \ "Globally bans a user from using Parsee" \ ) \ - X_COMMAND( \ - "unban-list", CmdNoFlyListDel, \ - "Globally unbans a user from using Parsee" \ - ) \ X_COMMAND( \ "nuke-muc", CmdUnlinkMUC, \ "Removes a MUC. Users should then run " \ @@ -78,9 +74,7 @@ typedef struct ParseeCmdArg { X_ROUTE("/_matrix/app/v1/transactions/(.*)", RouteTxns) \ X_ROUTE("/_matrix/app/v1/users/(.*)", RouteUserAck) \ X_ROUTE("/_matrix/app/v1/rooms/(.*)", RouteRoomAck) \ - X_ROUTE("/_matrix/app/v1/ping", RoutePing) \ - X_ROUTE("/media/(.*)/(.*)", RouteMedia) \ - X_ROUTE("/media/(.*)/(.*)/(.*)", RouteMedia) + X_ROUTE("/_matrix/client/v1/media/download/(.*)/(.*)", RouteMedia) #define X_ROUTE(path, name) extern void * name(Array *, void *); ROUTES diff --git a/src/include/StanzaBuilder.h b/src/include/StanzaBuilder.h index 18b56bb..e434e43 100644 --- a/src/include/StanzaBuilder.h +++ b/src/include/StanzaBuilder.h @@ -16,7 +16,7 @@ extern StanzaBuilder * SetStanzaID(StanzaBuilder *builder, char *id); extern StanzaBuilder * SetStanzaXParsee(StanzaBuilder *builder, HashMap *e); extern StanzaBuilder * AddStanzaElem(StanzaBuilder *builder, XMLElement *item); extern XMLElement * ExportStanza(StanzaBuilder *builder); -extern void WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max); +extern void WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber); extern void DestroyStanzaBuilder(StanzaBuilder *builder); #endif diff --git a/src/include/StringStream.h b/src/include/StringStream.h index 03a25ab..007a66b 100644 --- a/src/include/StringStream.h +++ b/src/include/StringStream.h @@ -4,7 +4,7 @@ #include /* Creates a string stream writer. The referenced buffer must be in the heap, - * or NULL for an empty string. */ + * or NULL. */ extern Stream * StrStreamWriter(char **buffer); /* Creates a string stream reader. The referenced buffer may be everywhere. */ diff --git a/src/include/Unistring.h b/src/include/Unistring.h deleted file mode 100644 index 7eff7a1..0000000 --- a/src/include/Unistring.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef PARSEE_UNISTRING_H -#define PARSEE_UNISTRING_H - -/*-*

A basic datastructure to handle Unicode strings easily.

- *

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

- * -------- - * Written-By: LDA - * License: CC0 */ - -#include -#include -#include - -/* An opaque structure for a Unistring */ -typedef struct Unistr Unistr; - -/** Decodes an UTF-8 string into a separate Unistr. - * ------- - * Returns: a valid Unistr[HEAP] | NULL - * Thrasher: UnistrFree */ -extern Unistr * UnistrCreate(char *src); - -/** Returns the length of an unistring. - * ---------- - * Returns: the unistring's length | NULL */ -extern size_t UnistrSize(Unistr *unistr); - -/** Returns the character of an unistring at a location, - * or 0 if it is inaccessible. - * ---------- - * Returns: The Unicode codepoint of a specific 0-index | 0 */ -extern uint32_t UnistrGetch(Unistr *unistr, size_t i); - -/** Adds a singular codepoint to a unistring(IFF not 0 and valid). - * ------------- - * Returns: NOTHING - * Modifies: unistr */ -extern void UnistrAddch(Unistr *unistr, uint32_t u); - -/** Concats N unistrings into a new, separate unistring. - * --------------------- - * Returns: a new unistring[HEAP] - * Modifies: NOTHING - * Thrasher: UnistrFree */ -extern Unistr * UnistrConcat(size_t n, ...); - -/** Encodes a unistring into a C UTF-8 string - * -------------- - * Returns: a valid NULL-terminated string[HEAP] | NULL - * Thrasher: Free */ -extern char * UnistrC(Unistr *unistr); - -/** Destroys all memory associated with a unistring. - * ---------- - * Returns: NOTHING - * Thrashes: {unistr} */ -extern void UnistrFree(Unistr *unistr); - -/** Returns true IFF the character is within the unicode BMP and - * not 0x0000 - * ------------------------------------------------------------ - * Returns: whenever the character is within the BMP */ -extern bool UnistrIsBMP(uint32_t u); - -/** Returns true IFF the character is within the 7-bit ASCII range - * not 0x0000 - * ------------------------------------------------------------ - * Returns: whenever the character is within ASCII */ -extern bool UnistrIsASCII(uint32_t u); - -typedef bool (*UnistrFilterFunc)(uint32_t u); -/** "Filters" characters in a Unistring by codepoint, removing - * those with callbacks which return false into a new unistring. - * -------------------- - * Returns: a new unistring with filtered characters removed */ -extern Unistr * UnistrFilter(Unistr *str, UnistrFilterFunc filter); - -/** Finds the offset of the first line not starting with a specific - * characters in terms of Unicode codepoints. - * -------- - * Returns: an offset of the first line to not start by {c} | 0 */ -extern size_t UnistrGetOffset(Unistr *str, uint32_t sep); - -/** Locates the new index within a regular UTF-8 sequence from an index - * within all codepoints. - * ----------------------------------- - * Returns: an offset */ -extern size_t UnistrGetUTFOffset(char *cstr, size_t unicode); -#endif diff --git a/src/include/XML.h b/src/include/XML.h index c7b6610..8fd108d 100644 --- a/src/include/XML.h +++ b/src/include/XML.h @@ -13,8 +13,6 @@ typedef struct XMLEvent { XML_LEXER_DATA, XML_LEXER_ELEM, /* Empty attr */ XML_LEXER_ENDELEM, - - XML_ERROR, XML_RELAX } type; diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 3b53f04..24a23d9 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -22,23 +22,15 @@ typedef struct XMPPComponent { /* Initialises a raw component stream to host, with an optional port. * If said port is 0, then it is set to the default Prosody port */ -extern XMPPComponent * XMPPInitialiseCompStream(char *addr, char *host, int port); +extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); /* Authenticates a component stream with a given shared secret, * with a stream ID from the server. This should be called right * after XMPPInitialiseCompStream. */ extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); -/** Writes an XML stanza through a component, while making sure any locking - * work is done. If {max} is non-zero, then this function will not send - * stanzas beyond {max} bytes. - * ----------------------- - * Modifies: {comp}, the XMPP stream - * See-Also: XMPPInitialiseCompStream, XMPPAuthenticateCompStream, XMPP-core RFC */ -extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max); - /* Makes a user join/leave a MUC */ -extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int secs, bool ret); +extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care); extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ @@ -90,9 +82,6 @@ extern char * XMPPGetRetractedID(XMLElement *); /* Get the replied-to stanza ID, if existent. */ extern char * XMPPGetReply(XMLElement *elem); -/* Get the replied-to stanza offset, if existent. */ -extern ssize_t XMPPGetReplyOffset(XMLElement *elem); - /** Get the moderated message ID(as a stanza ID/plain ID) from a moderation * stanza, that lives *alongside* the stanza itself. * ---------------------------------------------------------------------- @@ -101,6 +90,16 @@ extern ssize_t XMPPGetReplyOffset(XMLElement *elem); * See-Also: https://xmpp.org/extensions/xep-0425.html */ extern char * XMPPGetModeration(XMLElement *stanza); +/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. + * -------- + * Returns: A base64 encoded ver hash[LA:HEAP] + * Modifies: NOTHING + * See-Also: https://xmpp.org/extensions/xep-0115.html */ +extern char * XMPPGenerateVer(void); + +/* Annotates a presence with https://xmpp.org/extensions/xep-0115.html */ +extern void XMPPAnnotatePresence(XMLElement *presence); + extern bool XMPPHasError(XMLElement *stanza, char *type); #include diff --git a/src/include/XMPPCommand.h b/src/include/XMPPCommand.h index 33b121f..2680a64 100644 --- a/src/include/XMPPCommand.h +++ b/src/include/XMPPCommand.h @@ -12,7 +12,6 @@ typedef struct XMPPCommand XMPPCommand; typedef struct XMPPOption XMPPOption; typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, XMLElement *, XMLElement *); typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *); -typedef bool (*XMPPCmdFilter)(XMPPCommandManager *, char *id, XMLElement *stanza); /** Creates a simple XMPP command manager, which routes commands * with a single-stage form system, with a {cookie} @@ -20,28 +19,16 @@ typedef bool (*XMPPCmdFilter)(XMPPCommandManager *, char *id, XMLElement *stanza * Returns: An opaque command manager[LA:HEAP] * Modifies: NOTHING * See-Also: XMPPFreeManager */ -extern XMPPCommandManager * XMPPCreateManager(void *cookie); +extern XMPPCommandManager * XMPPCreateManager(void *cookie); extern void * XMPPGetManagerCookie(XMPPCommandManager *manager); -/** Changes the filter used for the command manager. This function - * takes in the source stanza and the command "ID" to filter, and - * returns true IFF the command should be shown to the requester. - * ----------- - * Returns: NOTHING - * Modifies: the manager's filter - * See-Also: XMPPCreateManager */ -extern void -XMPPManagerSetFilter(XMPPCommandManager *manager, XMPPCmdFilter filter); - /** Create a basic command with a node and name description * ----------------------------------------------------- * Returns: A command to be used with {XMPPRegisterCommand}[LA:HEAP] * Modifies: NOTHING * See-Also: XMPPRegisterCommand */ -extern XMPPCommand * - XMPPBasicCmd(char *node, char *name, XMPPCmdCallback cb); -extern void -XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer); +extern XMPPCommand * XMPPBasicCmd(char *node, char *name, XMPPCmdCallback cb); +extern void XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer); extern void XMPPAddOption(XMPPCommand *cmd, XMPPOption *opt); extern XMLElement * XMPPFormifyCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from); extern char * XMPPGetCommandNode(XMPPCommand *cmd); @@ -84,12 +71,11 @@ extern bool XMPPVerifyForm(XMPPCommand *cmd, XMLElement *form); extern void XMPPRegisterCommand(XMPPCommandManager *m, XMPPCommand *cmd); /** Shoves all {m} commands into XML as children of {p}, and a {jid} - * (and with the stanza source) * ----------------------------------------------------- * Returns: NOTHING * Modifies: {p} * See-Also: XMPPCreateManager */ -extern void XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement *s); +extern void XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p); /** Destroys all memory related to the command {manager}. * ----------------------------------------------------- @@ -109,7 +95,7 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD /* --------------------------------- COMMANDS --------------------------------- */ /* Please edit stc/XMPPThread.c (you can just force-save) for these to apply! */ -#define XMPP_COMMAND(f,l,n,t,s) \ +#define XMPP_COMMAND(f,n,t,s) \ extern void \ f(XMPPCommandManager *, char *, XMLElement *, XMLElement *); \ /* This symbol might not exist. We do, however, not care, as diff --git a/src/include/XMPPCommands.x.h b/src/include/XMPPCommands.x.h index dba6f48..d305340 100644 --- a/src/include/XMPPCommands.x.h +++ b/src/include/XMPPCommands.x.h @@ -1,15 +1,10 @@ /* C X-macro file */ -typedef enum XMPPCommandFlags { - XMPPCMD_ALL = 0, - XMPPCMD_MUC , /* Only for MUCs */ - XMPPCMD_ADMINS /* Only for administrators */ -} XMPPCommandFlags; #define XMPPCOMMANDS \ - XMPP_COMMAND(StatusCallback, XMPPCMD_ALL, "stats", "Get Parsee statistics", {}) \ - XMPP_COMMAND(CleanCallback, XMPPCMD_ADMINS, "clean", "Cleanup temporary Parsee data", {}) \ - XMPP_COMMAND(AdminsCallback, XMPPCMD_ALL, "admin", "Get Parsee admin list", {}) \ - XMPP_COMMAND(NoflyCallback, XMPPCMD_ADMINS, "nofly", "Get Parsee nofly list", {}) \ - XMPP_COMMAND(AddAdminCallback, XMPPCMD_ADMINS, "add-admin", "Adds glob as admin", { \ + XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \ + XMPP_COMMAND(CleanCallback, "clean", "Cleanup temporary Parsee data", {}) \ + XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \ + XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) \ + XMPP_COMMAND(AddAdminCallback, "add-admin", "Adds glob as admin", { \ XMPPOption *glob = XMPPCreateText(true, "glob", ""); \ XMPPSetDescription(glob, "Glob pattern to set as admin"); \ XMPPAddOption(cmd, glob); \ @@ -17,12 +12,12 @@ typedef enum XMPPCommandFlags { XMPPSetFormTitle(cmd, "Admin addition form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to add as an admin"); \ }) \ - XMPP_COMMAND(DelAdminCallback, XMPPCMD_ADMINS, "del-admin", "Removes glob from being admin", { \ + XMPP_COMMAND(DelAdminCallback, "del-admin", "Removes glob from being admin", { \ XMPPCmdOptionsCreator(cmd, FormDelAdminCallback); \ XMPPSetFormTitle(cmd, "Admin removal form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to remove as an admin"); \ }) \ - XMPP_COMMAND(AddNoflyCallback, XMPPCMD_ADMINS, "add-nofly", "Adds user to nofly", { \ + XMPP_COMMAND(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \ XMPPOption *entity = XMPPCreateText(true, "entity", ""); \ XMPPOption *reason = XMPPCreateText(false, "reason", "Not behaving"); \ XMPPSetDescription(entity, "Entity(glob) to no-fly"); \ @@ -33,30 +28,5 @@ typedef enum XMPPCommandFlags { XMPPSetFormTitle(cmd, "No-fly addition form"); \ XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \ }) \ - XMPP_COMMAND(ClearWhitelistCallback, XMPPCMD_ADMINS, "clear-wl", "Removes the chat whitelist", {}) \ - XMPP_COMMAND(AddWhitelistCallback, XMPPCMD_ADMINS, "add-wl", "Adds server to chat whitelist", { \ - XMPPOption *serv = XMPPCreateText(true, "entity", ""); \ - XMPPSetDescription(serv, "Server to mark as admin"); \ - XMPPAddOption(cmd, serv); \ - \ - XMPPSetFormTitle(cmd, "Chatlist addition form"); \ - XMPPSetFormInstruction(cmd, "Add a server to whitelist"); \ - }) \ - XMPP_COMMAND(WhitelistCallback, XMPPCMD_ADMINS, "wl", "Get Parsee's chat whitelist", {}) \ - XMPP_COMMAND(MUCInformationID, XMPPCMD_MUC, "muc-info-id", "Get bridged Matrix room ID", {}) \ - XMPP_COMMAND(MUCInformationCID, XMPPCMD_MUC, "muc-info-cid", "Get MUC's internal ID", {}) \ - XMPP_COMMAND(MUCUnlink, XMPPCMD_MUC, "muc-unlink", "Unlinks MUC", {}) \ - XMPP_COMMAND(MUCSetKey, XMPPCMD_MUC, "muc-set-key", "Sets a key within the MUC/room's context", { \ - XMPPOption *key = XMPPCreateText(true, "key", ""); \ - XMPPOption *val = XMPPCreateText(true, "val", ""); \ - XMPPSetDescription(key, "Key"); \ - XMPPSetDescription(val, "Value"); \ - XMPPAddOption(cmd, key); \ - XMPPAddOption(cmd, val); \ - \ - XMPPSetFormTitle(cmd, "Set a key-value pair"); \ - XMPPSetFormInstruction(cmd, "Replace a key with a specific value"); \ - }) \ - XMPP_COMMAND(MUCGetKeys, XMPPCMD_MUC, "muc-get-keys", "Get all key-values in the MUC/room.", {}) \ XMPPCOMMANDS diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..7fa93bc --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,35 @@ +# Makefile for building Parsee +# ================================ +# TODO: Consider making something akin to a configure script that checks +# for dependencies, or maybe even use *autoconf* (the devil!) + + +# =========================== Parsee Flags ============================= +NAME=Parsee +VERSION=0.0.0 +REPOSITORY=$(shell git remote get-url origin) + +# =========================== Compilation Flags ============================ +CYTO_INC=/usr/local/include/ # Where Cytoplasm's include path is + # located. +CYTO_LIB=/usr/local/lib # Where's Cytoplasm's library is + # located. + +SOURCE=. +OBJECT=out +CC=cc +CFLAGS=-I$(SOURCE) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -g -ggdb -Wall -Werror +LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -g -ggdb +# ============================ Compilation ================================= +SRC_FILES:=$(shell find $(SOURCE) -name '*.c') +OBJ_FILES:=${subst $(SOURCE)/,$(OBJECT)/,$(patsubst %.c, %, $(SRC_FILES))} + +all: $(OBJ_FILES) + +$(OBJECT)/%: $(SOURCE)/%.c + @mkdir -p $(shell dirname "$@") + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +clean: + rm -rf $(OBJECT) + diff --git a/tools/adminify.c b/tools/adminify.c index 1fdd6cf..26afb92 100644 --- a/tools/adminify.c +++ b/tools/adminify.c @@ -89,30 +89,30 @@ Main(Array *args, HashMap *env) glob = ArrayGet(args, 2); parsee = GetDB(db_path); - if (!parsee) + if (parsee) { - Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path); - (void) env; - return EXIT_FAILURE; - } - if (glob) - { - Log(LOG_NOTICE, "Adding glob '%s' to database %s", glob, db_path); - AddAdmin(parsee, glob); - Log(LOG_INFO, "Successfully added glob %s.", glob); - Log(LOG_INFO, "*I'm jealous of all these admins!*"); + if (glob) + { + Log(LOG_NOTICE, "Adding glob '%s' to database %s", glob, db_path); + AddAdmin(parsee, glob); + Log(LOG_INFO, "Successfully added glob %s.", glob); + Log(LOG_INFO, "*I'm jealous of all these admins!*"); + + DbClose(parsee); + return EXIT_SUCCESS; + } + + /* List admins */ + Log(LOG_INFO, "Admin list:"); + LogConfigIndent(LogConfigGlobal()); + ListAdmins(parsee); + LogConfigUnindent(LogConfigGlobal()); DbClose(parsee); return EXIT_SUCCESS; } - /* List admins */ - Log(LOG_INFO, "Admin list:"); - LogConfigIndent(LogConfigGlobal()); - ListAdmins(parsee); - LogConfigUnindent(LogConfigGlobal()); - - DbClose(parsee); - return EXIT_SUCCESS; + Log(LOG_ERR, "%s: couldn't open DB '%s'", exec, db_path); + return EXIT_FAILURE; } diff --git a/tools/aya.c b/tools/aya.c index dc49421..04a80f5 100644 --- a/tools/aya.c +++ b/tools/aya.c @@ -83,7 +83,7 @@ ParseAyadoc(char *raw) if (!strncmp(start, " *", 2) || !strncmp(start, "*", 1)) { start += 1 + (*start == ' '); - while (start && isspace((int) *start)) + while (start && isspace(*start)) { start++; } @@ -109,10 +109,10 @@ ParseAyadoc(char *raw) if (parsing_notes) { char *del = strchr(line_content, ':'); - char *val = del ? del + 1 : NULL; + char *val = del + 1; if (del && strlen(del) >= 1) { - while (*val && isspace((int) *val)) + while (*val && isspace(*val)) { val++; } @@ -157,9 +157,6 @@ HandleReturnValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *fi *tag_del = '\0'; } - (void) aya; - (void) d; - /* Already write the field */ StreamPrintf(out, " %s", field); @@ -203,8 +200,6 @@ HandleSeeValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *field "%s", field, field ); - (void) aya; - (void) d; } #define SplitBy(sym, cb, del_str) \ char *start_of_arg = val, *separator = NULL; \ @@ -214,7 +209,7 @@ HandleSeeValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *field { \ char *temporary, *field = NULL, *index; \ char *last_char; \ - while (*start_of_arg && isspace((int) *start_of_arg)) \ + while (*start_of_arg && isspace(*start_of_arg)) \ { \ start_of_arg++; \ } \ @@ -230,7 +225,7 @@ HandleSeeValue(Stream *out, AyadocComment *aya, HeaderDeclaration d, char *field \ /* Trim out spaces */ \ last_char = separator - 1; \ - while (*last_char && isspace((int) *last_char)) \ + while (*last_char && isspace(*last_char)) \ { \ last_char--; \ } \ @@ -497,6 +492,5 @@ Main(Array *args, HashMap *env) StreamClose(output); StreamClose(input); - (void) env; return EXIT_SUCCESS; } diff --git a/tools/b64.c b/tools/b64.c index ba125f2..53c08e8 100644 --- a/tools/b64.c +++ b/tools/b64.c @@ -50,6 +50,5 @@ Main(Array *args, HashMap *env) StreamFlush(outStream); StreamClose(outStream); - (void) env; return EXIT_SUCCESS; } diff --git a/tools/common.h b/tools/common.h index 9687ea3..eee4793 100644 --- a/tools/common.h +++ b/tools/common.h @@ -108,7 +108,7 @@ GetDB(char *config) { ret = DbOpenLMDB(db_path, lmdb_size); } - else + if (!ret) { ret = DbOpen(db_path, 0); } diff --git a/tools/config.c b/tools/config.c index d8e0aea..c6ab515 100644 --- a/tools/config.c +++ b/tools/config.c @@ -20,16 +20,14 @@ Main(Array *args, HashMap *env) Uri *api_base; char *homeserver = NULL, *jcp = NULL, *jabber = NULL; char *data = NULL, *media = NULL, *listen = NULL; - char *component_as = NULL; int flag, code = EXIT_FAILURE; int port = 5347; size_t lmdb_size = 0; - size_t max_stanza = 10000; listen = "localhost"; ArgParseStateInit(&state); - while ((flag = ArgParse(&state, args, "H:J:j:s:d:p:m:l:S:M:")) != -1) + while ((flag = ArgParse(&state, args, "H:J:s:d:p:m:l:S:")) != -1) { switch (flag) { @@ -46,9 +44,6 @@ Main(Array *args, HashMap *env) case 'J': jabber = state.optArg; break; - case 'j': - component_as = state.optArg; - break; case 'd': data = state.optArg; break; @@ -61,12 +56,6 @@ Main(Array *args, HashMap *env) case 'S': lmdb_size = strtol(state.optArg, NULL, 10) * 1024 * 1024; break; - case 'M': - max_stanza = strtol(state.optArg, NULL, 10); - if (max_stanza < 10000) - { - max_stanza = 10000; - } } } @@ -82,7 +71,6 @@ Main(Array *args, HashMap *env) "-l [Host/IP to listen as] " "-p [XMPP component port=5347] " "-J [parsee.xmppserver.ex]", - "-M [max stanza size>=10000]", "-S [LMDB size]", ArrayGet(args, 0) ); @@ -121,13 +109,11 @@ Main(Array *args, HashMap *env) JsonSet(json, JsonValueString(jabber), 1, "component_host"); JsonSet(json, JsonValueInteger(port), 1, "component_port"); - JsonSet(json, JsonValueInteger(max_stanza), 1, "max_stanza_size"); JsonSet(json, JsonValueString(jcp), 1, "shared_secret"); JsonSet(json, JsonValueString(media), 1, "media_base"); JsonSet(json, JsonValueString(listen), 1, "listen_as"); - JsonSet(json, JsonValueString(component_as), 1, "component_addr"); JsonEncode(json, file, JSON_PRETTY); StreamFlush(file); @@ -145,6 +131,5 @@ Main(Array *args, HashMap *env) end: UriFree(api_base); Free(media); - (void) env; return code; } diff --git a/tools/noavatars.c b/tools/noavatars.c index 93fba1c..0c5526c 100644 --- a/tools/noavatars.c +++ b/tools/noavatars.c @@ -30,6 +30,5 @@ Main(Array *args, HashMap *env) } Log(LOG_ERR, "%s: couldn't open DB '%s'", exec, db_path); - (void) env; return EXIT_FAILURE; } diff --git a/tools/plumb.c b/tools/plumb.c deleted file mode 100644 index 1bc9e14..0000000 --- a/tools/plumb.c +++ /dev/null @@ -1,152 +0,0 @@ -/* plumb.c - Small utility to manage plumbings from a shutoff instance. - * ============================================================ - * TODO: write other commands, and move some code to common.h - * - * Under CC0, as its a rather useful example of a Parsee tool. - * See LICENSE for more information about Parsee's licensing. */ - -#include "common.h" - -#include - -static void -DeletePlumbID(Db *parsee, char *chat_id) -{ - DbRef *chat_id_ref = DbLockIntent(parsee, DB_HINT_READONLY, 2, "chats", chat_id); - DbRef *chats = DbLock(parsee, 1, "chats"); - char *matrix_id = GrabString(DbJson(chat_id_ref), 1, "room_id"); - char *jabber_id = GrabString(DbJson(chat_id_ref), 1, "jabber_id"); - - HashMap *rooms = GrabObject(DbJson(chats), 1, "rooms"); - HashMap *mucs = GrabObject(DbJson(chats), 1, "mucs"); - - JsonValueFree(HashMapDelete(rooms, matrix_id)); - JsonValueFree(HashMapDelete(mucs, jabber_id)); - - DbUnlock(parsee, chat_id_ref); - DbUnlock(parsee, chats); - DbDelete(parsee, 2, "chats", chat_id); -} -static void -DeletePlumb(Db *parsee, char *potential_id) -{ - if (!parsee || !potential_id) - { - return; - } - - if (!strncmp(potential_id, "xmpp:", 5)) - { - DbRef *ref; - HashMap *mucs; - char *chat_id; - /* Try to parse it as an XMPP address */ - potential_id += 5; - - ref = DbLockIntent(parsee, DB_HINT_READONLY, 1, "chats"); - mucs = GrabObject(DbJson(ref), 1, "mucs"); - chat_id = StrDuplicate(GrabString(mucs, 1, potential_id)); - DbUnlock(parsee, ref); - - DeletePlumbID(parsee, chat_id); - Free(chat_id); - - return; - } - if (*potential_id == '!') - { - /* Try to parse it as a Matrix room ID */ - DbRef *ref; - HashMap *rooms; - char *chat_id; - - ref = DbLockIntent(parsee, DB_HINT_READONLY, 1, "chats"); - rooms = GrabObject(DbJson(ref), 1, "rooms"); - chat_id = StrDuplicate(GrabString(rooms, 1, potential_id)); - DbUnlock(parsee, ref); - - DeletePlumbID(parsee, chat_id); - Free(chat_id); - - return; - } - - /* Try to parse it as a chat ID */ - DeletePlumbID(parsee, potential_id); -} -static void -ListPlumbs(Db *parsee) -{ - DbRef *ref; - HashMap *mucs; - - char *muc; - JsonValue *value; - if (!parsee) - { - return; - } - - ref = DbLockIntent(parsee, DB_HINT_READONLY, 1, "chats"); - mucs = GrabObject(DbJson(ref), 1, "mucs"); - while (HashMapIterate(mucs, &muc, (void **) &value)) - { - char *chat_id = JsonValueAsString(value); - DbRef *chat_id_ref = DbLockIntent(parsee, DB_HINT_READONLY, 2, "chats", chat_id); - char *matrix_id = GrabString(DbJson(chat_id_ref), 1, "room_id"); - - /* TODO */ - Log(LOG_INFO, "- Plumb xmpp:%s <=> %s", muc, matrix_id); - Log(LOG_INFO, " - ID=%s", chat_id); - - DbUnlock(parsee, chat_id_ref); - } - - DbUnlock(parsee, ref); -} - -int -Main(Array *args, HashMap *env) -{ - char *db_path, *action, *exec; - int ret = EXIT_SUCCESS; - Db *parsee; - - exec = ArrayGet(args, 0); - - if (ArraySize(args) < 3) - { - Log(LOG_ERR, "Usage: %s [config] [action] ", exec); - return EXIT_FAILURE; - } - - db_path = ArrayGet(args, 1); - action = ArrayGet(args, 2); - - parsee = GetDB(db_path); - if (!parsee) - { - Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path); - return EXIT_FAILURE; - } - - if (StrEquals(action, "list") || StrEquals(action, "ls")) - { - ListPlumbs(parsee); - } - else if (StrEquals(action, "del")) - { - if (ArraySize(args) != 4) - { - Log(LOG_ERR, "%s: please show a !roomid:matrix.org, xmpp:mucid@jabber.org, or local hash", exec); - ret = EXIT_FAILURE; - goto end; - } - DeletePlumb(parsee, ArrayGet(args, 3)); - } - - -end: - DbClose(parsee); - return ret; -} diff --git a/tools/whitelist.c b/tools/whitelist.c deleted file mode 100644 index e1348d5..0000000 --- a/tools/whitelist.c +++ /dev/null @@ -1,114 +0,0 @@ -/* whitelist.c - Manages a Parsee MUC/user whitelist manually - * ============================================================ - * Example of usage: - * parsee-whitelist [CONFIG] [add|del|remove|list] - * Under CC0, as its a rather useful example of a Parsee tool. - * See LICENSE for more information about Parsee's licensing. */ - -#include "common.h" - -#include - -int -Main(Array *args, HashMap *env) -{ - int ret = EXIT_SUCCESS; - char *verb; - Db *db; - if (ArraySize(args) <= 2) - { - Log(LOG_ERR, - "Usage: %s [CONFIG] [add|del|clear|list] ", - ArrayGet(args, 0) - ); - return EXIT_FAILURE; - } - - if (!(db = GetDB(ArrayGet(args, 1)))) - { - Log(LOG_ERR, "Couldn't load database"); - ret = EXIT_FAILURE; - goto end; - } - - verb = ArrayGet(args, 2); - if (StrEquals(verb, "add")) - { - char *user = ArrayGet(args, 3); - DbRef *ref = !user ? NULL : DbLock( - db, 1, "whitelist" - ); - if (!ref && user) - { - ref = DbCreate( - db, 1, "whitelist" - ); - } - - if (!user) - { - ret = EXIT_FAILURE; - goto end; - } - JsonValueFree(HashMapSet( - DbJson(ref), - user, JsonValueObject(HashMapCreate()) - )); - DbUnlock(db, ref); - } - else if (StrEquals(verb, "del")) - { - char *user = ArrayGet(args, 3); - DbRef *ref = !user ? NULL : DbLock( - db, 1, "whitelist" - ); - if (!ref && user) - { - ref = DbCreate( - db, 1, "whitelist" - ); - } - - if (!user) - { - ret = EXIT_FAILURE; - goto end; - } - JsonValueFree(HashMapDelete(DbJson(ref), user)); - DbUnlock(db, ref); - } - else if (StrEquals(verb, "clear")) - { - DbDelete(db, 1, "whitelist"); - } - else if (StrEquals(verb, "list")) - { - DbRef *ref = DbLockIntent( - db, DB_HINT_READONLY, - 1, "whitelist" - ); - Array *keys = HashMapKeys(DbJson(ref)); - size_t i; - - for (i = 0; i < ArraySize(keys); i++) - { - char *key = ArrayGet(keys, i); - - Log(LOG_INFO, "- %s", key); - } - - - ArrayFree(keys); - DbUnlock(db, ref); - } - else - { - ret = EXIT_FAILURE; - goto end; - } - -end: - (void) env; - DbClose(db); - return ret; -}