mirror of
https://git.kappach.at/lda/Parsee.git
synced 2025-04-11 21:18:47 +02:00
[ADD/WIP] Chat settings
Right now, they are currently unused. Extensions, and Parsee itself will be able to use those, though.
This commit is contained in:
parent
55ac682d26
commit
064040c18f
17 changed files with 449 additions and 14 deletions
|
@ -1,7 +1,3 @@
|
|||
Some dates for Parsee-related events. They mostly serve as LDA's TODOs with
|
||||
a strict deadline:
|
||||
- ~September 2024[tomboyish-bridges-adventure]:
|
||||
Get Parsee into the _Phantasmagoria of Bug View_ stage (essentially
|
||||
v0.0.1 for a public testing) once I can afford `yama`, and start
|
||||
bridging the Matrix room alongside a shiny XMPP MUC, bridged by
|
||||
yours truly.
|
||||
- Get star-of-hope out by November 8
|
||||
|
|
|
@ -98,10 +98,6 @@ restricted to Parsee admins, with permission from MUC owners, too
|
|||
be false by default.
|
||||
- Currently, MUC owners may kick Parsee out, with the effect of unlinking the
|
||||
MUC.
|
||||
- Rewrite the XMPP command management to actually be aware of context, instead of
|
||||
being a baked-in X-macro. It could be useful for MUC admins, which may use commands
|
||||
specifically within the MUC's own context rather than the global Parsee context(for
|
||||
Parsee admins).
|
||||
- Look at XEPS-TBD.TXT for XEPs to be done
|
||||
- Add a MUC server to Parsee, such that it may be able to hook onto it and therefore
|
||||
support XMPP->Matrix bridging.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
." The last field is the codename, by the way.
|
||||
." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN
|
||||
.TH parsee-adminify 1 "Parsee Utility" "tomboyish-bridges-adventure"
|
||||
.TH parsee-adminify 1 "Parsee Utility" "star-of-hope"
|
||||
|
||||
.SH NAME
|
||||
parsee-adminify - bootstrap an admin to a new Parsee server
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
." The last field is the codename, by the way.
|
||||
." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN
|
||||
.TH parsee-aya 1 "Parsee Utility" "tomboyish-bridges-adventure"
|
||||
.TH parsee-aya 1 "Parsee Utility" "star-of-hope"
|
||||
|
||||
.SH NAME
|
||||
parsee-aya - generate some nice Ayaya! documentation
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
." The last field is the codename, by the way.
|
||||
." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN
|
||||
.TH parsee 1 "Parsee Utility" "tomboyish-bridges-adventure"
|
||||
.TH parsee 1 "Parsee Utility" "star-of-hope"
|
||||
|
||||
.SH NAME
|
||||
parsee - the jealous XMPP-Matrix bridge
|
||||
|
|
|
@ -222,6 +222,12 @@ Main(Array *args, HashMap *env)
|
|||
}
|
||||
ParseeInitialiseNickTable();
|
||||
|
||||
if (verbose >= PARSEE_VERBOSE_COMICAL)
|
||||
{
|
||||
Log(LOG_DEBUG, "Initialising affiliation table");
|
||||
}
|
||||
ParseeInitialiseAffiliationTable();
|
||||
|
||||
conf.port = parsee_conf->port;
|
||||
conf.threads = parsee_conf->http_threads;
|
||||
conf.maxConnections = conf.threads << 2;
|
||||
|
@ -291,6 +297,7 @@ end:
|
|||
CronStop(cron);
|
||||
CronFree(cron);
|
||||
ParseeFreeData(conf.handlerArgs);
|
||||
ParseeDestroyAffiliationTable();
|
||||
ParseeDestroyNickTable();
|
||||
ParseeDestroyOIDTable();
|
||||
ParseeDestroyHeadTable();
|
||||
|
|
|
@ -109,6 +109,7 @@ ParseeExportConfigYAML(Stream *stream)
|
|||
StreamPrintf(stream, "hs_token: \"%s\"\n", config->hs_token);
|
||||
StreamPrintf(stream, "sender_localpart: \"%s\"\n", config->sender_localpart);
|
||||
StreamPrintf(stream, "protocols: [\"xmpp\", \"jabber\"]\n");
|
||||
StreamPrintf(stream, "receive_ephemeral: true\n"); /* TODO: Actually use that field */
|
||||
StreamPrintf(stream, "\n");
|
||||
StreamPrintf(stream, "namespaces: \n");
|
||||
StreamPrintf(stream, " users:\n");
|
||||
|
|
|
@ -620,3 +620,90 @@ ParseeIsMUCWhitelisted(ParseeData *data, char *muc)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern HashMap *
|
||||
ParseeGetChatSettings(ParseeData *data, char *chat)
|
||||
{
|
||||
HashMap *ret, *json;
|
||||
DbRef *ref;
|
||||
|
||||
char *key;
|
||||
JsonValue *value;
|
||||
if (!data || !chat)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ref = DbLockIntent(data->db, DB_HINT_READONLY,
|
||||
3, "chats", chat, "settings"
|
||||
);
|
||||
json = DbJson(ref);
|
||||
if (!ref)
|
||||
{
|
||||
return HashMapCreate();
|
||||
}
|
||||
|
||||
ret = HashMapCreate();
|
||||
while (HashMapIterate(json, &key, (void **) &value))
|
||||
{
|
||||
char *str = JsonValueAsString(value);
|
||||
HashMapSet(ret, key, StrDuplicate(str));
|
||||
}
|
||||
DbUnlock(data->db, ref);
|
||||
return ret;
|
||||
}
|
||||
void
|
||||
ParseeFreeChatSettings(HashMap *settings)
|
||||
{
|
||||
char *key;
|
||||
void *val;
|
||||
if (!settings)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (HashMapIterate(settings, &key, &val))
|
||||
{
|
||||
Free(val);
|
||||
}
|
||||
HashMapFree(settings);
|
||||
}
|
||||
char *
|
||||
ParseeGetChatSetting(ParseeData *data, char *chat, char *key)
|
||||
{
|
||||
HashMap *map;
|
||||
char *ret;
|
||||
if (!data || !chat || !key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
map = ParseeGetChatSettings(data, chat);
|
||||
ret = StrDuplicate(HashMapGet(map, key));
|
||||
ParseeFreeChatSettings(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
void
|
||||
ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val)
|
||||
{
|
||||
DbRef *ref;
|
||||
HashMap *json;
|
||||
if (!data || !chat || !key || !val)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref = DbLockIntent(data->db, DB_HINT_WRITE,
|
||||
3, "chats", chat, "settings"
|
||||
);
|
||||
if (!ref)
|
||||
{
|
||||
ref = DbCreate(data->db, 3, "chats", chat, "settings");
|
||||
}
|
||||
json = DbJson(ref);
|
||||
|
||||
JsonValueFree(HashMapSet(json, key, JsonValueString(val)));
|
||||
|
||||
DbUnlock(data->db, ref);
|
||||
return;
|
||||
}
|
||||
|
|
106
src/Parsee/Tables/Affiliation.c
Normal file
106
src/Parsee/Tables/Affiliation.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
#include <Parsee.h>
|
||||
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
#include <pthread.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -233,6 +233,7 @@ ParseeGenerateMTO(char *common_id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO: Is HttpUrlEncode okay? */
|
||||
common_id = HttpUrlEncode(common_id);
|
||||
matrix_to = StrConcat(2, "https://matrix.to/#/", common_id);
|
||||
Free(common_id);
|
||||
|
|
117
src/XMPPCommands/MUCKV.c
Normal file
117
src/XMPPCommands/MUCKV.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Json.h>
|
||||
#include <Cytoplasm/Util.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
#include <Cytoplasm/Log.h>
|
||||
|
||||
#include <XMPPFormTool.h>
|
||||
#include <XMPPCommand.h>
|
||||
#include <Matrix.h>
|
||||
#include <Parsee.h>
|
||||
#include <XMPP.h>
|
||||
#include <XML.h>
|
||||
#include <AS.h>
|
||||
|
||||
void
|
||||
MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
||||
{
|
||||
ParseeData *data = XMPPGetManagerCookie(m);
|
||||
char *affiliation, *role;
|
||||
char *chat_id;
|
||||
char *muc;
|
||||
|
||||
char *key, *val;
|
||||
|
||||
ParseeLookupAffiliation(from, &affiliation, &role);
|
||||
Free(role);
|
||||
if (!StrEquals(affiliation, "owner"))
|
||||
{
|
||||
SetNote("error", "Setting MUC properties requires the 'owner' affiliation.");
|
||||
Free(affiliation);
|
||||
return;
|
||||
}
|
||||
|
||||
GetFieldValue(key, "key", form);
|
||||
GetFieldValue(val, "val", form);
|
||||
if (!key || !val)
|
||||
{
|
||||
SetNote("error", "No keys or no value given.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
muc = ParseeTrimJID(from);
|
||||
chat_id = ParseeGetFromMUCID(data, muc);
|
||||
ParseeSetChatSetting(data, chat_id, key, val);
|
||||
|
||||
SetNote("info", "Set key-value pair!");
|
||||
end:
|
||||
Free(affiliation);
|
||||
Free(chat_id);
|
||||
Free(muc);
|
||||
(void) form;
|
||||
}
|
||||
void
|
||||
MUCGetKeys(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
||||
{
|
||||
ParseeData *data = XMPPGetManagerCookie(m);
|
||||
char *affiliation = NULL, *role = NULL;
|
||||
char *chat_id = NULL;
|
||||
char *muc = NULL;
|
||||
|
||||
XMLElement *x;
|
||||
XMLElement *title;
|
||||
XMLElement *reported, *item, *field, *value, *txt;
|
||||
|
||||
HashMap *settings = NULL;
|
||||
|
||||
ParseeLookupAffiliation(from, &affiliation, &role);
|
||||
Free(role);
|
||||
if (!StrEquals(affiliation, "owner"))
|
||||
{
|
||||
SetNote("error", "Getting MUC roperties requires the 'owner' affiliation.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
muc = ParseeTrimJID(from);
|
||||
chat_id = ParseeGetFromMUCID(data, muc);
|
||||
settings = ParseeGetChatSettings(data, chat_id);
|
||||
|
||||
x = XMLCreateTag("x");
|
||||
title = XMLCreateTag("title");
|
||||
|
||||
SetTitle(x, "MUC/room settings");
|
||||
|
||||
XMLAddChild(x, title);
|
||||
|
||||
XMLAddAttr(x, "xmlns", "jabber:x:data");
|
||||
XMLAddAttr(x, "type", "result");
|
||||
{
|
||||
char *key, *val;
|
||||
reported = XMLCreateTag("reported");
|
||||
XMLAddChild(x, reported);
|
||||
|
||||
/* Report */
|
||||
Report("key", "Setting's key");
|
||||
Report("val", "Setting's value");
|
||||
|
||||
/* Set */
|
||||
while (HashMapIterate(settings, &key, (void **) &val))
|
||||
{
|
||||
BeginItem();
|
||||
SetField("key", key);
|
||||
SetField("val", val);
|
||||
EndItem();
|
||||
}
|
||||
}
|
||||
XMLAddChild(out, x);
|
||||
|
||||
end:
|
||||
ParseeFreeChatSettings(settings);
|
||||
Free(affiliation);
|
||||
Free(chat_id);
|
||||
Free(muc);
|
||||
(void) form;
|
||||
}
|
67
src/XMPPCommands/MUCUnlink.c
Normal file
67
src/XMPPCommands/MUCUnlink.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include <Cytoplasm/HashMap.h>
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Json.h>
|
||||
#include <Cytoplasm/Util.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
#include <Cytoplasm/Log.h>
|
||||
|
||||
#include <XMPPFormTool.h>
|
||||
#include <XMPPCommand.h>
|
||||
#include <Matrix.h>
|
||||
#include <Parsee.h>
|
||||
#include <XMPP.h>
|
||||
#include <XML.h>
|
||||
#include <AS.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -189,6 +189,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
|||
time = UtilTsMillis();
|
||||
rectime = time;
|
||||
|
||||
|
||||
from = HashMapGet(stanza->attrs, "from");
|
||||
if (ParseeManageBan(args, from, NULL))
|
||||
{
|
||||
|
@ -202,7 +203,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (ServerHasXEP421(args, from))
|
||||
{
|
||||
XMLElement *occupant = XMLookForTKV(
|
||||
|
|
|
@ -174,6 +174,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
|||
{
|
||||
ParseePushJIDTable(oid, jid);
|
||||
}
|
||||
ParseePushAffiliationTable(oid, affiliation, role);
|
||||
decode_from = ParseeLookupJID(oid);
|
||||
real_matrix = ParseeDecodeMXID(decode_from);
|
||||
|
||||
|
|
|
@ -276,6 +276,44 @@ extern char * ParseeGetRoomID(ParseeData *, char *chat_id);
|
|||
/* Finds the MUC JID from a chat ID */
|
||||
extern char * ParseeGetMUCID(ParseeData *, char *chat_id);
|
||||
|
||||
/** Fetches a configuration value from a key in a chat(given a Chat ID),
|
||||
* as a string or NULL. Keys are to be stored like Java packages(reveres DNS).
|
||||
* Parsee has the right over any key with the <code>'p.'</code> prefix.
|
||||
* -----------------------------------
|
||||
* Returns: a valid string[HEAP] | NULL
|
||||
* Modifies: NOTHING
|
||||
* See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeSetChatSetting */
|
||||
extern char *
|
||||
ParseeGetChatSetting(ParseeData *data, char *chat, char *key);
|
||||
|
||||
/** Fetches the entire configuration in a chat(given a Chat ID), as an hashmap
|
||||
* of strings.
|
||||
* -----------------------------------
|
||||
* Returns: a valid string[HEAP] | NULL
|
||||
* Modifies: NOTHING
|
||||
* Thrasher: ParseeFreeChatSettings
|
||||
* See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeSetChatSetting, ParseeGetChatSetting */
|
||||
extern HashMap *
|
||||
ParseeGetChatSettings(ParseeData *data, char *chat);
|
||||
|
||||
/** Destroys memory allocated from a call to {ParseeGetChatSettings}.
|
||||
* -----------------------
|
||||
* Returns: NOTHING
|
||||
* Modifies: {settings}
|
||||
* Thrashes: {settings}
|
||||
* See-Also: ParseeGetChatSettings */
|
||||
extern void
|
||||
ParseeFreeChatSettings(HashMap *settings);
|
||||
|
||||
/** Replaces a configuration key-value pair within the chat's context, which
|
||||
* can be read with {ParseeGetChatSetting}.
|
||||
* -------------------------------------
|
||||
* Returns: NOTHING
|
||||
* Modifies: the chat context
|
||||
* See-Also: ParseeGetFromMUCID, ParseeGetFromRoomID, ParseeGetChatSetting */
|
||||
extern void
|
||||
ParseeSetChatSetting(ParseeData *data, char *chat, char *key, char *val);
|
||||
|
||||
/* Pushes a stanza ID to a chat ID */
|
||||
extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender);
|
||||
extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender);
|
||||
|
@ -327,6 +365,11 @@ extern void ParseePushOIDTable(char *muc, char *occupant);
|
|||
extern char *ParseeLookupOID(char *muc);
|
||||
extern void ParseeDestroyOIDTable(void);
|
||||
|
||||
extern void ParseeInitialiseAffiliationTable(void);
|
||||
extern void ParseePushAffiliationTable(char *user, char *affiliation, char *role);
|
||||
extern bool ParseeLookupAffiliation(char *muc, char **affiliation, char **role);
|
||||
extern void ParseeDestroyAffiliationTable(void);
|
||||
|
||||
extern void ParseeInitialiseJIDTable(void);
|
||||
extern void ParseePushJIDTable(char *muc, char *bare);
|
||||
extern char *ParseeLookupJID(char *muc);
|
||||
|
|
|
@ -45,5 +45,18 @@ typedef enum XMPPCommandFlags {
|
|||
XMPP_COMMAND(WhitelistCallback, XMPPCMD_ADMINS, "wl", "Get Parsee's chat whitelist", {}) \
|
||||
XMPP_COMMAND(MUCInformationID, XMPPCMD_MUC, "muc-info-id", "Get bridged Matrix room ID", {}) \
|
||||
XMPP_COMMAND(MUCInformationCID, XMPPCMD_MUC, "muc-info-cid", "Get MUC's internal ID", {}) \
|
||||
XMPP_COMMAND(MUCUnlink, XMPPCMD_MUC, "muc-unlink", "Unlinks MUC", {}) \
|
||||
XMPP_COMMAND(MUCSetKey, XMPPCMD_MUC, "muc-set-key", "Sets a key within the MUC/room's context", { \
|
||||
XMPPOption *key = XMPPCreateText(true, "key", ""); \
|
||||
XMPPOption *val = XMPPCreateText(true, "val", ""); \
|
||||
XMPPSetDescription(key, "Key"); \
|
||||
XMPPSetDescription(val, "Value"); \
|
||||
XMPPAddOption(cmd, key); \
|
||||
XMPPAddOption(cmd, val); \
|
||||
\
|
||||
XMPPSetFormTitle(cmd, "Set a key-value pair"); \
|
||||
XMPPSetFormInstruction(cmd, "Replace a key with a specific value"); \
|
||||
}) \
|
||||
XMPP_COMMAND(MUCGetKeys, XMPPCMD_MUC, "muc-get-keys", "Get all key-values in the MUC/room.", {}) \
|
||||
|
||||
XMPPCOMMANDS
|
||||
|
|
|
@ -113,7 +113,7 @@ Main(Array *args, HashMap *env)
|
|||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Log(LOG_ERR, "%s: couldn't open DB '%s'", exec, db_path);
|
||||
Log(LOG_ERR, "%s: couldn't open config '%s' or couldnt edit DB", exec, db_path);
|
||||
(void) env;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue