mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 16:45:10 +00:00
[ADD/FIX/WIP] "Fix" concurrency, prepare XEP-0421
I'll need to break down my commits more...
This commit is contained in:
parent
a686449a4d
commit
63c1bc819e
14 changed files with 356 additions and 162 deletions
4
Makefile
4
Makefile
|
|
@ -19,8 +19,8 @@ SOURCE=src
|
||||||
OBJECT=build
|
OBJECT=build
|
||||||
INCLUDES=src/include
|
INCLUDES=src/include
|
||||||
CC=cc
|
CC=cc
|
||||||
CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -O2 -g -ggdb -Wall -Werror
|
CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -g -ggdb -Wall -Werror
|
||||||
LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -Wl,--export-dynamic -O2 -g -ggdb
|
LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -g -ggdb
|
||||||
BINARY=parsee
|
BINARY=parsee
|
||||||
# ============================ Compilation =================================
|
# ============================ Compilation =================================
|
||||||
SRC_FILES:=$(shell find $(SOURCE) -name '*.c')
|
SRC_FILES:=$(shell find $(SOURCE) -name '*.c')
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,10 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to)
|
||||||
matrix_name = ASGetName(data->config, room_id, matrix_sender);
|
matrix_name = ASGetName(data->config, room_id, matrix_sender);
|
||||||
muc_join_as = StrConcat(4, muc_id, "/", matrix_name, "[p]");
|
muc_join_as = StrConcat(4, muc_id, "/", matrix_name, "[p]");
|
||||||
|
|
||||||
|
/* TODO: Manage name conflicts. That would have been an easy
|
||||||
|
* task(try the original one, and use a counter if it fails),
|
||||||
|
* but that'd involve modifying the rest of the code, which
|
||||||
|
* I'm not doing at 01:39 ... */
|
||||||
XMPPJoinMUC(jabber, *from, muc_join_as);
|
XMPPJoinMUC(jabber, *from, muc_join_as);
|
||||||
|
|
||||||
*to = muc_id;
|
*to = muc_id;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <Routes.h>
|
#include <Routes.h>
|
||||||
#include <Glob.h>
|
#include <Glob.h>
|
||||||
|
|
@ -861,3 +862,22 @@ ParseeStringifyDate(uint64_t millis)
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParseeAchievement(const char *func, const char *msg, bool die)
|
||||||
|
{
|
||||||
|
Log(LOG_ERR, "=========== Achievement GET! ===========");
|
||||||
|
Log(LOG_ERR, "%s: %s.", func, msg);
|
||||||
|
Log(LOG_ERR, "THIS IS, LET'S SAY, NOT GOOD, AND A SIGN OF ");
|
||||||
|
Log(LOG_ERR, "A PROGRAMMER ERROR. PLEASE KILLALL -9 PARSEE.");
|
||||||
|
Log(LOG_ERR, "");
|
||||||
|
Log(LOG_ERR, "YOU, HOWEVER, GET TO WIN AN AWARD FOR THIS.");
|
||||||
|
Log(LOG_ERR, "I AM SIMPLY JEALOUS OF YOU GETTING SUCH A ");
|
||||||
|
Log(LOG_ERR, "GOOD ERROR MESSAGE.");
|
||||||
|
Log(LOG_ERR, "=========== Achievement GET! ===========");
|
||||||
|
|
||||||
|
if (die)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
#include <Cytoplasm/Log.h>
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
XMLElement *
|
XMLElement *
|
||||||
XMLCreateTag(char *name)
|
XMLCreateTag(char *name)
|
||||||
{
|
{
|
||||||
|
|
@ -43,8 +45,10 @@ XMLCreateText(char *data)
|
||||||
elem->data = StrDuplicate(data);
|
elem->data = StrDuplicate(data);
|
||||||
|
|
||||||
return elem;
|
return elem;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
XMLAddAttr(XMLElement *element, char *key, char *val)
|
XMLAddAttr(XMLElement *element, char *key, char *val)
|
||||||
{
|
{
|
||||||
|
|
@ -52,12 +56,12 @@ XMLAddAttr(XMLElement *element, char *key, char *val)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (element->type != XML_ELEMENT_TAG)
|
if (element->type != XML_ELEMENT_TAG || !element->attrs)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMapSet(element->attrs, key, StrDuplicate(val));
|
Free(HashMapSet(element->attrs, key, StrDuplicate(val)));
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
XMLAddChild(XMLElement *element, XMLElement *child)
|
XMLAddChild(XMLElement *element, XMLElement *child)
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc)
|
||||||
|
|
||||||
pthread_mutex_unlock(&comp->write_lock);
|
pthread_mutex_unlock(&comp->write_lock);
|
||||||
|
|
||||||
if ((reply = ParseeAwaitStanza(id, 500)))
|
/*if ((reply = ParseeAwaitStanza(id, 500)))
|
||||||
{
|
{
|
||||||
bool exit_code = true;
|
bool exit_code = true;
|
||||||
|
|
||||||
|
|
@ -325,7 +325,8 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc)
|
||||||
XMLFreeElement(reply);
|
XMLFreeElement(reply);
|
||||||
Free(id);
|
Free(id);
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}*/
|
||||||
|
(void) reply;
|
||||||
Free(id);
|
Free(id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -485,3 +486,57 @@ XMPPHasError(XMLElement *stanza, char *type)
|
||||||
}
|
}
|
||||||
return XMLookForUnique(err, type);
|
return XMLookForUnique(err, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XMLElement *
|
||||||
|
XMPPSendDisco(XMPPComponent *jabber, char *from, char *to)
|
||||||
|
{
|
||||||
|
XMLElement *ret, *iq;
|
||||||
|
char *identifier;
|
||||||
|
|
||||||
|
if (!jabber || !from || !to)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iq = XMLCreateTag("iq");
|
||||||
|
XMLAddAttr(iq, "type", "get");
|
||||||
|
XMLAddAttr(iq, "from", from);
|
||||||
|
XMLAddAttr(iq, "to", to);
|
||||||
|
XMLAddAttr(iq, "id", (identifier = StrRandom(69)));
|
||||||
|
{
|
||||||
|
XMLElement *query = XMLCreateTag("query");
|
||||||
|
XMLAddAttr(query, "xmlns", "http://jabber.org/protocol/disco#info");
|
||||||
|
XMLAddChild(iq, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&jabber->write_lock);
|
||||||
|
XMLEncode(jabber->stream, iq);
|
||||||
|
StreamFlush(jabber->stream);
|
||||||
|
pthread_mutex_unlock(&jabber->write_lock);
|
||||||
|
XMLFreeElement(iq);
|
||||||
|
|
||||||
|
ret = ParseeAwaitStanza(identifier, 250);
|
||||||
|
Free(identifier);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
XMPPDiscoAdvertises(XMLElement *disco, char *var)
|
||||||
|
{
|
||||||
|
XMLElement *query;
|
||||||
|
if (!disco || !var)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
query = XMLookForTKV(
|
||||||
|
disco,
|
||||||
|
"query", "xmlns",
|
||||||
|
"http://jabber.org/protocol/disco#info"
|
||||||
|
);
|
||||||
|
if (!query)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!XMLookForTKV(query, "feature", "var", var);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
#include "XMPPThread/internal.h"
|
#include "XMPPThread/internal.h"
|
||||||
|
|
||||||
#include <Cytoplasm/Memory.h>
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
char *
|
char *
|
||||||
ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza)
|
ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza)
|
||||||
|
|
@ -111,3 +115,70 @@ ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ServerHasXEP421(ParseeData *data, char *from)
|
||||||
|
{
|
||||||
|
char *server = NULL, *parsee;
|
||||||
|
XMLElement *disco;
|
||||||
|
bool ret;
|
||||||
|
if (!data || !from)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = strchr(from, '@');
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
server = from;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
server++;
|
||||||
|
}
|
||||||
|
server = StrDuplicate(server);
|
||||||
|
|
||||||
|
if (strchr(server, '/'))
|
||||||
|
{
|
||||||
|
*(strchr(server, '/')) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
parsee = ParseeJID(data);
|
||||||
|
disco = XMPPSendDisco(data->jabber, parsee, server);
|
||||||
|
|
||||||
|
ret = XMPPDiscoAdvertises(disco, "urn:xmpp:occupant-id:0");
|
||||||
|
|
||||||
|
XMLFreeElement(disco);
|
||||||
|
Free(parsee);
|
||||||
|
Free(server);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
char *
|
||||||
|
ParseeGetBridgedUser(ParseeData *data, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
char *user, *xmpp_from, *type;
|
||||||
|
char *decode_from;
|
||||||
|
|
||||||
|
if (!data || !stanza)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_from = HashMapGet(stanza->attrs, "from");
|
||||||
|
type = HashMapGet(stanza->attrs, "type");
|
||||||
|
decode_from = ParseeLookupJID(xmpp_from);
|
||||||
|
|
||||||
|
/* TODO: On semi-anonymous MUCs, it might be preferable to use a
|
||||||
|
* form of the occupant ID as the base, as it is more unique, and
|
||||||
|
* less prone to trigger the character limit on Matrix.
|
||||||
|
* I'll need to detect these first....
|
||||||
|
*
|
||||||
|
* See: https://xmpp.org/extensions/xep-0421.html */
|
||||||
|
user = ParseeEncodeJID(
|
||||||
|
data->config,
|
||||||
|
decode_from,
|
||||||
|
StrEquals(type, "chat")
|
||||||
|
);
|
||||||
|
Free(decode_from);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
|
||||||
79
src/XMPPThread/Caps.c
Normal file
79
src/XMPPThread/Caps.c
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Base64.h>
|
||||||
|
#include <Cytoplasm/Util.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Sha.h>
|
||||||
|
|
||||||
|
#include <StringStream.h>
|
||||||
|
#include <XMPPCommand.h>
|
||||||
|
#include <Matrix.h>
|
||||||
|
#include <XMPP.h>
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
#include "XMPPThread/internal.h"
|
||||||
|
|
||||||
|
/* Generates a SHA-256 hash of the ver field. */
|
||||||
|
char *
|
||||||
|
XMPPGenerateVer(void)
|
||||||
|
{
|
||||||
|
char *S = NULL;
|
||||||
|
unsigned char *Sha = NULL;
|
||||||
|
Array *identities = ArrayCreate();
|
||||||
|
Array *features = ArrayCreate();
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Initialise identity table, to be sorted */
|
||||||
|
#define IdentitySimple(cat, Type, Name) { \
|
||||||
|
XMPPIdentity *id = Malloc(sizeof(*id)); \
|
||||||
|
id->category = cat; \
|
||||||
|
id->lang = NULL; \
|
||||||
|
id->type = Type; \
|
||||||
|
id->name = Name; \
|
||||||
|
ArrayAdd(identities, id); }
|
||||||
|
IQ_IDENTITY
|
||||||
|
#undef IdentitySimple
|
||||||
|
#define AdvertiseSimple(feature) ArrayAdd(features, feature);
|
||||||
|
IQ_ADVERT
|
||||||
|
#undef AdvertiseSimple
|
||||||
|
ArraySort(identities, IdentitySort);
|
||||||
|
for (i = 0; i < ArraySize(identities); i++)
|
||||||
|
{
|
||||||
|
XMPPIdentity *identity = ArrayGet(identities, i);
|
||||||
|
char *id_chunk = StrConcat(7,
|
||||||
|
identity->category, "/",
|
||||||
|
identity->type, "/",
|
||||||
|
identity->lang, "/",
|
||||||
|
identity->name);
|
||||||
|
char *tmp = S;
|
||||||
|
S = StrConcat(3, S, id_chunk, "<");
|
||||||
|
Free(tmp);
|
||||||
|
Free(id_chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArraySort(features, ((int (*) (void *, void *)) ICollate));
|
||||||
|
for (i = 0; i < ArraySize(features); i++)
|
||||||
|
{
|
||||||
|
char *feature = ArrayGet(features, i);
|
||||||
|
char *tmp = S;
|
||||||
|
S = StrConcat(3, S, feature, "<");
|
||||||
|
Free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sha = Sha1(S);
|
||||||
|
Free(S);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include <Cytoplasm/Memory.h>
|
#include <Cytoplasm/Memory.h>
|
||||||
#include <Cytoplasm/Base64.h>
|
#include <Cytoplasm/Base64.h>
|
||||||
|
|
@ -21,70 +24,6 @@
|
||||||
|
|
||||||
#include "XMPPThread/internal.h"
|
#include "XMPPThread/internal.h"
|
||||||
|
|
||||||
/* Generates a SHA-256 hash of the ver field. */
|
|
||||||
char *
|
|
||||||
XMPPGenerateVer(void)
|
|
||||||
{
|
|
||||||
char *S = NULL;
|
|
||||||
unsigned char *Sha = NULL;
|
|
||||||
Array *identities = ArrayCreate();
|
|
||||||
Array *features = ArrayCreate();
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* Initialise identity table, to be sorted */
|
|
||||||
#define IdentitySimple(cat, Type, Name) { \
|
|
||||||
XMPPIdentity *id = Malloc(sizeof(*id)); \
|
|
||||||
id->category = cat; \
|
|
||||||
id->lang = NULL; \
|
|
||||||
id->type = Type; \
|
|
||||||
id->name = Name; \
|
|
||||||
ArrayAdd(identities, id); }
|
|
||||||
IQ_IDENTITY
|
|
||||||
#undef IdentitySimple
|
|
||||||
#define AdvertiseSimple(feature) ArrayAdd(features, feature);
|
|
||||||
IQ_ADVERT
|
|
||||||
#undef AdvertiseSimple
|
|
||||||
ArraySort(identities, IdentitySort);
|
|
||||||
for (i = 0; i < ArraySize(identities); i++)
|
|
||||||
{
|
|
||||||
XMPPIdentity *identity = ArrayGet(identities, i);
|
|
||||||
char *id_chunk = StrConcat(7,
|
|
||||||
identity->category, "/",
|
|
||||||
identity->type, "/",
|
|
||||||
identity->lang, "/",
|
|
||||||
identity->name);
|
|
||||||
char *tmp = S;
|
|
||||||
S = StrConcat(3, S, id_chunk, "<");
|
|
||||||
Free(tmp);
|
|
||||||
Free(id_chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArraySort(features, ((int (*) (void *, void *)) ICollate));
|
|
||||||
for (i = 0; i < ArraySize(features); i++)
|
|
||||||
{
|
|
||||||
char *feature = ArrayGet(features, i);
|
|
||||||
char *tmp = S;
|
|
||||||
S = StrConcat(3, S, feature, "<");
|
|
||||||
Free(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sha = Sha1(S);
|
|
||||||
Free(S);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLElement *
|
XMLElement *
|
||||||
RetrieveStanza(XMPPThread *thread)
|
RetrieveStanza(XMPPThread *thread)
|
||||||
{
|
{
|
||||||
|
|
@ -152,11 +91,11 @@ XMPPDispatcher(void *argp)
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct XMPPAwait {
|
typedef struct XMPPAwait {
|
||||||
pthread_mutex_t cond_lock;
|
XMLElement *stanza;
|
||||||
pthread_cond_t condition;
|
|
||||||
bool usable;
|
bool usable;
|
||||||
|
|
||||||
XMLElement *stanza;
|
pthread_mutex_t cond_lock;
|
||||||
|
pthread_cond_t condition;
|
||||||
} XMPPAwait;
|
} XMPPAwait;
|
||||||
|
|
||||||
static pthread_mutex_t await_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t await_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
@ -243,7 +182,7 @@ ParseeXMPPThread(void *argp)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&await->cond_lock);
|
pthread_mutex_lock(&await->cond_lock);
|
||||||
await->stanza = stanza;
|
await->stanza = stanza;
|
||||||
pthread_cond_broadcast(&await->condition);
|
pthread_cond_signal(&await->condition);
|
||||||
pthread_mutex_unlock(&await->cond_lock);
|
pthread_mutex_unlock(&await->cond_lock);
|
||||||
|
|
||||||
HashMapDelete(await_table, id);
|
HashMapDelete(await_table, id);
|
||||||
|
|
@ -286,25 +225,37 @@ ParseeXMPPThread(void *argp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/* TODO: This function does NIT behave well. */
|
|
||||||
XMLElement *
|
XMLElement *
|
||||||
ParseeAwaitStanza(char *identifier, int64_t timeout)
|
ParseeAwaitStanza(char *identifier, int64_t timeout)
|
||||||
{
|
{
|
||||||
/* TODO: Pthreads HATE me using Malloc here, so I'm abusing stackspace.
|
XMPPAwait *awa;
|
||||||
* Not *too much* of a problem, just a weird oddity. If anyone has a clue
|
|
||||||
* on why that happens (at least on ARM64 with a Pi4 running Debian), let
|
|
||||||
* me know! */
|
|
||||||
XMPPAwait awa;
|
|
||||||
XMLElement *stanza;
|
XMLElement *stanza;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
if (!identifier)
|
if (!identifier)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX: You may be wondering _why_ I am using stdlib's malloc, instead of
|
||||||
|
* Cytoplasm's Malloc wrapper(which are essentially the same thing, plus
|
||||||
|
* some memchecking as of now), or the stack, as done previously.
|
||||||
|
* The reasons are that:
|
||||||
|
* - Cytoplasm's heap causes a fun bus error on ARM64. I have _no clue_ why,
|
||||||
|
* since, as I said, it is as of now just malloc with extra metadata prepended
|
||||||
|
* to it. A _guess_ may be that the metadata makes everything unaligned, which,
|
||||||
|
* just sounds silly. pthreads should be able to cope fine with that, I think.
|
||||||
|
* - The stack seems to be a prime candidate to cause a stack corruption, which
|
||||||
|
* puzzled me for a comically long while("why is the value being swapped for
|
||||||
|
* the key?" "why does duplicating twice cause the former problem to disappear,
|
||||||
|
* but still obviously creating another one?", ...).
|
||||||
|
*
|
||||||
|
* I am open to issues talking about such fun behaviour and ideas to fix this.
|
||||||
|
* This is a bodge, and potentially a problem, or vulnerability with Cytoplasm/
|
||||||
|
* Parsee. As long as it isn't "use Rust". Please don't say that. */
|
||||||
|
awa = malloc(sizeof(XMPPAwait));
|
||||||
|
|
||||||
/* Convert into an absolute timeout.
|
/* Convert into an absolute timeout.
|
||||||
* =================================
|
* =================================
|
||||||
* XXX: For anyone using timespecs: MAKE ABSOLUTELY FUCKING SURE YOUR NANOS
|
* XXX: For anyone using timespecs: MAKE ABSOLUTELY FUCKING SURE YOUR NANOS
|
||||||
|
|
@ -327,30 +278,33 @@ ParseeAwaitStanza(char *identifier, int64_t timeout)
|
||||||
ts.tv_nsec = nsc_delta;
|
ts.tv_nsec = nsc_delta;
|
||||||
ts.tv_sec += sec_delta;
|
ts.tv_sec += sec_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) msecond;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&await_lock);
|
pthread_mutex_lock(&await_lock);
|
||||||
|
|
||||||
pthread_cond_init(&awa.condition, NULL);
|
pthread_cond_init(&awa->condition, NULL);
|
||||||
pthread_mutex_init(&awa.cond_lock, NULL);
|
pthread_mutex_init(&awa->cond_lock, NULL);
|
||||||
awa.stanza = NULL;
|
awa->stanza = NULL;
|
||||||
|
|
||||||
HashMapSet(await_table, identifier, &awa);
|
if (HashMapGet(await_table, identifier))
|
||||||
|
{
|
||||||
|
HashMapDelete(await_table, identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapSet(await_table, identifier, awa);
|
||||||
pthread_mutex_unlock(&await_lock);
|
pthread_mutex_unlock(&await_lock);
|
||||||
|
|
||||||
pthread_mutex_lock(&awa.cond_lock);
|
pthread_mutex_lock(&awa->cond_lock);
|
||||||
while (!awa.stanza)
|
while (!awa->stanza)
|
||||||
{
|
{
|
||||||
int code;
|
int code;
|
||||||
|
|
||||||
if (timeout <= 0)
|
if (timeout <= 0)
|
||||||
{
|
{
|
||||||
pthread_cond_wait(&awa.condition, &awa.cond_lock);
|
pthread_cond_wait(&awa->condition, &awa->cond_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
code = pthread_cond_timedwait(&awa.condition, &awa.cond_lock, &ts);
|
code = pthread_cond_timedwait(&awa->condition, &awa->cond_lock, &ts);
|
||||||
if (code == ETIMEDOUT)
|
if (code == ETIMEDOUT)
|
||||||
{
|
{
|
||||||
/* Timeout detected, give up regardless of the status of our
|
/* Timeout detected, give up regardless of the status of our
|
||||||
|
|
@ -361,22 +315,15 @@ ParseeAwaitStanza(char *identifier, int64_t timeout)
|
||||||
}
|
}
|
||||||
if (code == EINVAL)
|
if (code == EINVAL)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "=========== Achievement GET! ===========");
|
Achievement("TIMEDWAIT RETURNED WEIRD EINVAL", true);
|
||||||
Log(LOG_ERR, "%s: TIMEDWAIT RETURNED EINVAL.", __func__);
|
|
||||||
Log(LOG_ERR, "THIS IS, LET'S SAY, NOT GOOD, AND A SIGN OF ");
|
|
||||||
Log(LOG_ERR, "A PROGRAMMER ERROR. PLEASE KILLALL -9 PARSEE.");
|
|
||||||
Log(LOG_ERR, "");
|
|
||||||
Log(LOG_ERR, "YOU, HOWEVER, GET TO WIN AN AWARD FOR THIS.");
|
|
||||||
Log(LOG_ERR, "I AM SIMPLY JEALOUS OF YOU GETTING SUCH A ");
|
|
||||||
Log(LOG_ERR, "GOOD ERROR MESSAGE.");
|
|
||||||
Log(LOG_ERR, "=========== Achievement GET! ===========");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stanza = awa.stanza;
|
stanza = awa->stanza;
|
||||||
pthread_mutex_unlock(&awa.cond_lock);
|
pthread_mutex_unlock(&awa->cond_lock);
|
||||||
|
|
||||||
pthread_cond_destroy(&awa.condition);
|
pthread_cond_destroy(&awa->condition);
|
||||||
pthread_mutex_destroy(&awa.cond_lock);
|
pthread_mutex_destroy(&awa->cond_lock);
|
||||||
|
free(awa);
|
||||||
return stanza;
|
return stanza;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,11 +148,11 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: On semi-anonymous MUCs, it might be preferable to use a
|
if (ServerHasXEP421(args, HashMapGet(stanza->attrs, "from")))
|
||||||
* form of the occupant ID as the base, as it is more unique, and
|
{
|
||||||
* less prone to trigger the character limit on Matrix.
|
|
||||||
*
|
}
|
||||||
* See: https://xmpp.org/extensions/xep-0421.html */
|
|
||||||
to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
||||||
decode_from = ParseeLookupJID(from);
|
decode_from = ParseeLookupJID(from);
|
||||||
from_matrix = ParseeEncodeJID(args->config, decode_from, true);
|
from_matrix = ParseeEncodeJID(args->config, decode_from, true);
|
||||||
|
|
@ -198,16 +198,9 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
if (mroom_id && !XMPPIsParseeStanza(stanza))
|
if (mroom_id && !XMPPIsParseeStanza(stanza))
|
||||||
{
|
{
|
||||||
char *res = ParseeGetResource(from);
|
char *res = ParseeGetResource(from);
|
||||||
char *encoded = ParseeEncodeJID(args->config, decode_from, false);
|
char *encoded = ParseeGetBridgedUser(args, stanza);
|
||||||
char *event_id = NULL;
|
char *event_id = NULL;
|
||||||
bool chat = false;
|
bool chat = StrEquals(HashMapGet(stanza->attrs, "type"), "chat");
|
||||||
|
|
||||||
if (StrEquals(HashMapGet(stanza->attrs, "type"), "chat"))
|
|
||||||
{
|
|
||||||
Free(encoded);
|
|
||||||
encoded = StrDuplicate(from_matrix);
|
|
||||||
chat = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
char *parsee = ParseeJID(args);
|
char *parsee = ParseeJID(args);
|
||||||
|
|
|
||||||
|
|
@ -58,20 +58,24 @@ struct XMPPThread {
|
||||||
XMPPThreadInfo *info;
|
XMPPThreadInfo *info;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int ICollate(unsigned char *cata, unsigned char *catb);
|
int ICollate(unsigned char *cata, unsigned char *catb);
|
||||||
extern int IdentitySort(void *idap, void *idbp);
|
int IdentitySort(void *idap, void *idbp);
|
||||||
|
|
||||||
extern char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza);
|
char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza);
|
||||||
extern char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id);
|
char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id);
|
||||||
extern char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza);
|
char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza);
|
||||||
extern void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event);
|
void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event);
|
||||||
extern bool ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza);
|
bool ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza);
|
||||||
|
|
||||||
extern HashMap * ShoveStanza(HashMap *content, XMLElement *stanza);
|
HashMap * ShoveStanza(HashMap *content, XMLElement *stanza);
|
||||||
extern void ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPThread *thr);
|
void ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPThread *thr);
|
||||||
extern XMLElement * CreatePubsubRequest(char *from, char *to, char *node);
|
XMLElement * CreatePubsubRequest(char *from, char *to, char *node);
|
||||||
|
|
||||||
|
|
||||||
extern bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr);
|
bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr);
|
||||||
extern void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr);
|
void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr);
|
||||||
extern void PresenceStanza(ParseeData *args, XMLElement *stanza);
|
void PresenceStanza(ParseeData *args, XMLElement *stanza);
|
||||||
|
|
||||||
|
bool ServerHasXEP421(ParseeData *data, char *from);
|
||||||
|
|
||||||
|
char * ParseeGetBridgedUser(ParseeData *data, XMLElement *stanza);
|
||||||
|
|
|
||||||
|
|
@ -240,4 +240,14 @@ extern char * ParseeStringifyDate(uint64_t millis);
|
||||||
/* Generates the JID of the Parsee bridge user. */
|
/* Generates the JID of the Parsee bridge user. */
|
||||||
extern char * ParseeJID(ParseeData *data);
|
extern char * ParseeJID(ParseeData *data);
|
||||||
extern char * ParseeMXID(ParseeData *data);
|
extern char * ParseeMXID(ParseeData *data);
|
||||||
|
|
||||||
|
/** Prints an _fatal_ and _strange_, error message, then congratulates
|
||||||
|
* the user for it(an "achievement").
|
||||||
|
* Use this for errors that have _no business_ happening, at all.
|
||||||
|
* NOTE to users: If you see this, _*OPEN AN ISSUE*_.
|
||||||
|
* ---------------------------------------------------
|
||||||
|
* Returns: NOTHING | NORETURN */
|
||||||
|
extern void ParseeAchievement(const char *func, const char *msg, bool die);
|
||||||
|
#define Achievement(msg, die) ParseeAchievement(__func__, msg, die)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -98,4 +98,8 @@ extern char * XMPPGenerateVer(void);
|
||||||
extern void XMPPAnnotatePresence(XMLElement *presence);
|
extern void XMPPAnnotatePresence(XMLElement *presence);
|
||||||
|
|
||||||
extern bool XMPPHasError(XMLElement *stanza, char *type);
|
extern bool XMPPHasError(XMLElement *stanza, char *type);
|
||||||
|
|
||||||
|
extern XMLElement * XMPPSendDisco(XMPPComponent *jabber, char *from, char *to);
|
||||||
|
|
||||||
|
extern bool XMPPDiscoAdvertises(XMLElement *disco, char *var);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -94,35 +94,6 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD
|
||||||
|
|
||||||
/* --------------------------------- COMMANDS --------------------------------- */
|
/* --------------------------------- COMMANDS --------------------------------- */
|
||||||
/* Please edit stc/XMPPThread.c (you can just force-save) for these to apply! */
|
/* Please edit stc/XMPPThread.c (you can just force-save) for these to apply! */
|
||||||
#define XMPPCOMMANDS \
|
|
||||||
XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \
|
|
||||||
XMPP_COMMAND(CleanCallback, "clean", "Cleanup temporary Parsee data", {}) \
|
|
||||||
XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \
|
|
||||||
XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) \
|
|
||||||
XMPP_COMMAND(AddAdminCallback, "add-admin", "Adds glob as admin", { \
|
|
||||||
XMPPOption *glob = XMPPCreateText(true, "glob", ""); \
|
|
||||||
XMPPSetDescription(glob, "Glob pattern to set as admin"); \
|
|
||||||
XMPPAddOption(cmd, glob); \
|
|
||||||
\
|
|
||||||
XMPPSetFormTitle(cmd, "Admin addition form"); \
|
|
||||||
XMPPSetFormInstruction(cmd, "Select a glob pattern to add as an admin"); \
|
|
||||||
}) \
|
|
||||||
XMPP_COMMAND(DelAdminCallback, "del-admin", "Removes a glob from admin rights", { \
|
|
||||||
XMPPCmdOptionsCreator(cmd, FormDelAdminCallback); \
|
|
||||||
XMPPSetFormTitle(cmd, "Admin removal form"); \
|
|
||||||
XMPPSetFormInstruction(cmd, "Select a glob pattern to remove as an admin"); \
|
|
||||||
}) \
|
|
||||||
XMPP_COMMAND(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \
|
|
||||||
XMPPOption *entity = XMPPCreateText(true, "entity", ""); \
|
|
||||||
XMPPOption *reason = XMPPCreateText(false, "reason", "Not behaving"); \
|
|
||||||
XMPPSetDescription(entity, "Entity(glob) to no-fly"); \
|
|
||||||
XMPPAddOption(cmd, entity); \
|
|
||||||
XMPPSetDescription(reason, "Reason for the no-fly"); \
|
|
||||||
XMPPAddOption(cmd, reason); \
|
|
||||||
\
|
|
||||||
XMPPSetFormTitle(cmd, "No-fly addition form"); \
|
|
||||||
XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \
|
|
||||||
}) \
|
|
||||||
|
|
||||||
#define XMPP_COMMAND(f,n,t,s) \
|
#define XMPP_COMMAND(f,n,t,s) \
|
||||||
extern void \
|
extern void \
|
||||||
|
|
@ -132,7 +103,7 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD
|
||||||
extern void \
|
extern void \
|
||||||
Form##f(XMPPCommandManager *, XMPPCommand *, char *); \
|
Form##f(XMPPCommandManager *, XMPPCommand *, char *); \
|
||||||
|
|
||||||
XMPPCOMMANDS
|
#include "XMPPCommands.x"
|
||||||
|
|
||||||
#undef XMPP_COMMAND
|
#undef XMPP_COMMAND
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
32
src/include/XMPPCommands.x
Normal file
32
src/include/XMPPCommands.x
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* C X-macro file */
|
||||||
|
#define XMPPCOMMANDS \
|
||||||
|
XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \
|
||||||
|
XMPP_COMMAND(CleanCallback, "clean", "Cleanup temporary Parsee data", {}) \
|
||||||
|
XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \
|
||||||
|
XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) \
|
||||||
|
XMPP_COMMAND(AddAdminCallback, "add-admin", "Adds glob as admin", { \
|
||||||
|
XMPPOption *glob = XMPPCreateText(true, "glob", ""); \
|
||||||
|
XMPPSetDescription(glob, "Glob pattern to set as admin"); \
|
||||||
|
XMPPAddOption(cmd, glob); \
|
||||||
|
\
|
||||||
|
XMPPSetFormTitle(cmd, "Admin addition form"); \
|
||||||
|
XMPPSetFormInstruction(cmd, "Select a glob pattern to add as an admin"); \
|
||||||
|
}) \
|
||||||
|
XMPP_COMMAND(DelAdminCallback, "del-admin", "Removes a glob from admin rights", { \
|
||||||
|
XMPPCmdOptionsCreator(cmd, FormDelAdminCallback); \
|
||||||
|
XMPPSetFormTitle(cmd, "Admin removal form"); \
|
||||||
|
XMPPSetFormInstruction(cmd, "Select a glob pattern to remove as an admin"); \
|
||||||
|
}) \
|
||||||
|
XMPP_COMMAND(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \
|
||||||
|
XMPPOption *entity = XMPPCreateText(true, "entity", ""); \
|
||||||
|
XMPPOption *reason = XMPPCreateText(false, "reason", "Not behaving"); \
|
||||||
|
XMPPSetDescription(entity, "Entity(glob) to no-fly"); \
|
||||||
|
XMPPAddOption(cmd, entity); \
|
||||||
|
XMPPSetDescription(reason, "Reason for the no-fly"); \
|
||||||
|
XMPPAddOption(cmd, reason); \
|
||||||
|
\
|
||||||
|
XMPPSetFormTitle(cmd, "No-fly addition form"); \
|
||||||
|
XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \
|
||||||
|
}) \
|
||||||
|
|
||||||
|
XMPPCOMMANDS
|
||||||
Loading…
Add table
Add a link
Reference in a new issue