diff --git a/README.MD b/README.MD
index 47bb9f1..b6beb95 100644
--- a/README.MD
+++ b/README.MD
@@ -1,5 +1,5 @@
# 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.
@@ -45,6 +45,9 @@ TODO
If you know things about XMPP or Matrix, yet aren't familiar with C99, or just
want to suggest a feature, you may open an issue.
+Packaging Parsee (and Cytoplasm) for your specific platform might be a nice to have,
+to make Parsee easier to setup and manage.
+
**(DON'T FOR NOW, THERE IS LITERALLY NOWHERE THIS GOES TO)**
You may also donate to [the LiberaPay](https://en.liberapay.com/Parsee), alongside
[Telodendria's](https://en.liberapay.com/Telodendria), as it is the project
diff --git a/src/Commands/UnlinkMUC.c b/src/Commands/UnlinkMUC.c
new file mode 100644
index 0000000..a35dc57
--- /dev/null
+++ b/src/Commands/UnlinkMUC.c
@@ -0,0 +1,60 @@
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+
+CommandHead(CmdUnlinkMUC, cmd, argp)
+{
+ ParseeCmdArg *args = argp;
+ ParseeData *data = args->data;
+ HashMap *json, *event = args->event, *mucs;
+ DbRef *ref;
+ char *muc = NULL, *chat_id = NULL, *room = NULL;
+ JsonValue *val;
+
+ BotInitialise();
+
+ muc = HashMapGet(cmd->arguments, "muc");
+ if (!muc)
+ {
+ ReplyBasic("`muc` field REQUIRED.");
+ goto end;
+ }
+
+ 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);
+
+ 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);
+ ReplySprintf("Please now remove the room %s and its aliases.",
+ room
+ );
+end:
+ Free(chat_id);
+ Free(room);
+ BotDestroy();
+}
diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c
index 23ccc52..cc60d71 100644
--- a/src/Routes/UserAck.c
+++ b/src/Routes/UserAck.c
@@ -68,7 +68,15 @@ RouteHead(RouteRoomAck, arr, argp)
}
muc = ParseeDecodeLocalMUC(args->data->config, room);
- Log(LOG_INFO, "room=%s", muc);
+ if (!ParseeManageBan(args->data, muc, NULL))
+ {
+ HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED);
+ response = MatrixCreateError(
+ "M_NOT_FOUND",
+ "XMPP MUC is banned from being accessed on this instance"
+ );
+ goto end;
+ }
if (!XMPPQueryMUC(args->data->jabber, muc, &info))
{
HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED);
@@ -76,7 +84,6 @@ RouteHead(RouteRoomAck, arr, argp)
"M_UNRECOGNIZED",
"Room does not map to a real XMPP MUC"
);
- Log(LOG_INFO, "No MUC");
goto end;
}
creator = StrConcat(
diff --git a/src/include/Parsee.h b/src/include/Parsee.h
index 9c8ee2a..bf415b4 100644
--- a/src/include/Parsee.h
+++ b/src/include/Parsee.h
@@ -57,6 +57,8 @@ typedef struct ParseeData {
#define GrabObject(obj, ...) JsonValueAsObject(JsonGet(obj, __VA_ARGS__))
#define GrabArray(obj, ...) JsonValueAsArray(JsonGet(obj, __VA_ARGS__))
+/* Milliseconds to UNIT macros, to be used like 30 SECONDS and 1 MINUTE
+ * in timestamps */
#define SECONDS * 1000
#define MINUTES * 60 SECONDS
#define HOURS * 60 MINUTES
diff --git a/src/include/Routes.h b/src/include/Routes.h
index 88816b3..9243d67 100644
--- a/src/include/Routes.h
+++ b/src/include/Routes.h
@@ -22,6 +22,11 @@ typedef struct ParseeCmdArg {
"ban-list", CmdNoFlyList, \
"Globally bans a user from using Parsee" \
) \
+ X_COMMAND( \
+ "nuke-muc", CmdUnlinkMUC, \
+ "Removes a MUC. Users should then run " \
+ "!ban-list to remove all access to the MUC" \
+ ) \
X_COMMAND( \
"list-bans", CmdListBans, \
"Shows all global bans from Parsee" \