From bdb4fd2f68b6af9e26365180093aca099046f4f6 Mon Sep 17 00:00:00 2001 From: LDA Date: Mon, 17 Jun 2024 18:26:37 +0200 Subject: [PATCH] [MOD] One-way Matrix->XMPP comms. This is not sanitised. I need to make an XML writer. --- .gitignore | 2 + src/AS.c | 29 ++++----- src/HttParsee.c | 1 + src/Main.c | 73 +++++++++++++++++----- src/MatrixEventHandler.c | 60 ++++++++++++++---- src/ParseeConfig.c | 19 +++++- src/ParseeData.c | 6 +- src/ParseeUser.c | 125 ++++++++++++++++++++++++++++++++++++++ src/Routes/Root.c | 3 +- src/Routes/Transactions.c | 2 +- src/Routes/UserAck.c | 41 +++++++++++++ src/XMPP/Component.c | 28 +++++++-- src/XMPP/Stanza.c | 43 +++++++++++++ src/include/AS.h | 2 +- src/include/Parsee.h | 30 ++++++++- src/include/Routes.h | 3 +- src/include/XMPP.h | 15 ++++- 17 files changed, 421 insertions(+), 61 deletions(-) create mode 100644 src/Routes/UserAck.c create mode 100644 src/XMPP/Stanza.c diff --git a/.gitignore b/.gitignore index a8b1c25..2dc89de 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ parsee* parsee *.swp .* +data +data/* diff --git a/src/AS.c b/src/AS.c index 7046d39..40c41d2 100644 --- a/src/AS.c +++ b/src/AS.c @@ -74,18 +74,23 @@ ASRegisterUser(ParseeConfig *conf, char *user) json = HashMapCreate(); HashMapSet(json,"type",JsonValueString("m.login.application_service")); + + user = ParseeGetLocal(user); HashMapSet(json,"username",JsonValueString(user)); ASAuthenticateRequest(conf, ctx); status = ParseeSetRequestJSON(ctx, json); + HttpClientContextFree(ctx); JsonFree(json); + Free(user); + return status == HTTP_OK; } void -ASPing(ParseeConfig *conf) +ASPing(const ParseeConfig *conf) { HttpClientContext *ctx = NULL; HashMap *json = NULL; @@ -116,26 +121,20 @@ void ASJoin(ParseeConfig *conf, char *id, char *masquerade) { HttpClientContext *ctx = NULL; - HashMap *json = NULL, *params_obj; - char *path, *params; - if (!conf || !id) + HashMap *json = NULL; + char *path; + if (!conf || !id || !masquerade) { + Log(LOG_ERR, "Bad values %p %p", conf, id); return; } - params_obj = HashMapCreate(); - if (masquerade) - { - HashMapSet(params_obj, "user_id", masquerade); - } - params = HttpParamEncode(params_obj); - HashMapFree(params_obj); - path = StrConcat(4, + path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/join?", - params + "user_id=", masquerade ); - Free(params); + Log(LOG_INFO, "%s", path); ctx = ParseeCreateRequest( conf, HTTP_POST, path @@ -144,6 +143,7 @@ ASJoin(ParseeConfig *conf, char *id, char *masquerade) json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); + HttpClientContextFree(ctx); JsonFree(json); } @@ -152,6 +152,7 @@ ASSend(ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) { HttpClientContext *ctx = NULL; HashMap *json = NULL, *params_obj; + Stream *s; char *path, *params; char *txn; if (!conf || !id || !type || !c) diff --git a/src/HttParsee.c b/src/HttParsee.c index f483395..f3ee005 100644 --- a/src/HttParsee.c +++ b/src/HttParsee.c @@ -55,6 +55,7 @@ ParseeRequest(HttpServerContext *ctx, void *argp) HttpSendHeaders(ctx); JsonEncode(response, stream, JSON_DEFAULT); + JsonFree(response); return; } } diff --git a/src/Main.c b/src/Main.c index 839fa38..13867a8 100644 --- a/src/Main.c +++ b/src/Main.c @@ -2,33 +2,43 @@ #include #include +#include #include #include #include #include +static HttpServer *server = NULL; +static void +SignalHandler(int signal) +{ + size_t i; + + switch (signal) + { + case SIGPIPE: + return; + case SIGTERM: + case SIGINT: + if (!server) + { + return; + } + HttpServerStop(server); + break; + } +} + int Main(void) { - HttpServer *server = NULL; HttpServerConfig conf; ParseeData *data; const ParseeConfig *parsee_conf; Stream *yaml; - { - char *as = "TODO"; - char *shared = "TODO"; - Stream *jabber = XMPPInitialiseCompStream(as, 0); - XMPPAuthenticateCompStream(jabber, as, shared); - while (!StreamEof(jabber)) - { - StreamPutc(StreamStderr(), StreamGetc(jabber)); - StreamFlush(StreamStderr()); - } - XMPPEndCompStream(jabber); - return 0; - } + XMPPComponent *jabber; + struct sigaction sigAction; Log(LOG_INFO, "%s - v%s", NAME, VERSION); ParseeConfigLoad("parsee.json"); @@ -39,18 +49,48 @@ Main(void) StreamClose(yaml); parsee_conf = ParseeConfigGet(); + { + jabber = XMPPInitialiseCompStream( + parsee_conf->component_host, + parsee_conf->component_port + ); + XMPPAuthenticateCompStream( + jabber, + parsee_conf->shared_comp_secret + ); + } Log(LOG_INFO, "HS token: %s", parsee_conf->hs_token); ASRegisterUser(parsee_conf, parsee_conf->sender_localpart); - memset(&conf, 0, sizeof(conf)); conf.port = parsee_conf->port; conf.threads = 4; conf.maxConnections = 32; - conf.handlerArgs = ParseeInitData(); + conf.handlerArgs = ParseeInitData(jabber); conf.handler = ParseeRequest; + sigAction.sa_handler = SignalHandler; + sigfillset(&sigAction.sa_mask); + sigAction.sa_flags = SA_RESTART; + +#define SIGACTION(sig, act, oact) \ + if (sigaction(sig, act, oact) < 0) \ + { \ + Log(LOG_ERR, "Unable to install signal handler: %s", #sig); \ + } \ + else \ + { \ + Log(LOG_DEBUG, "Installed signal handler: %s", #sig); \ + } + + SIGACTION(SIGINT, &sigAction, NULL); + SIGACTION(SIGTERM, &sigAction, NULL); + SIGACTION(SIGPIPE, &sigAction, NULL); + SIGACTION(SIGUSR1, &sigAction, NULL); + +#undef SIGACTION + /* TODO: The rest of Parsee. */ server = HttpServerCreate(&conf); HttpServerStart(server); @@ -60,5 +100,6 @@ Main(void) HttpServerFree(server); ParseeConfigFree(); + ParseeFreeData(conf.handlerArgs); return 0; } diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 503872c..116d65f 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -9,42 +10,77 @@ #define GrabString(obj, ...) JsonValueAsString(JsonGet(obj, __VA_ARGS__)) static void -ParseeMemberHandler(const ParseeConfig *conf, HashMap *event) +ParseeMemberHandler(ParseeData *data, HashMap *event) { char *state_key = GrabString(event, 1, "state_key"); char *membership = GrabString(event, 2, "content", "membership"); char *room_id = GrabString(event, 1, "room_id"); + const ParseeConfig *conf = data->config; Log(LOG_INFO, "Membership '%s'->'%s'", state_key, membership); if (StrEquals(membership, "invite") && ParseeIsPuppet(conf, state_key)) { + DbRef *ref; + HashMap *json; + char *jid; Log(LOG_INFO, "Looks like %s was invited to %s", state_key, - GrabString(event, 1, "room_id") + room_id ); ASJoin(conf, room_id, state_key); + ref = DbCreate(data->db, 3, "rooms", room_id, "data"); + json = DbJson(ref); + + Log(LOG_INFO, "Grabbing JID"); + jid = ParseeDecodeLocalJID(conf, state_key); + + Log(LOG_INFO, "JID: %s", jid); + + HashMapSet(json, "is_direct", JsonValueBoolean(true)); + HashMapSet(json, "xmpp_user", JsonValueString(jid)); + + /* Pretend everything is a dm, ignoring is_direct */ + if (jid) + { + Free(jid); + } + DbUnlock(data->db, ref); } } static void -ParseeMessageHandler(const ParseeConfig *conf, HashMap *event) +ParseeMessageHandler(ParseeData *data, HashMap *event) { + XMPPComponent *jabber = data->jabber; + DbRef *ref; + HashMap *json; + char *msgtype = GrabString(event, 2, "content", "msgtype"); char *body = GrabString(event, 2, "content", "body"); char *id = GrabString(event, 1, "room_id"); - if (StrEquals(body, "!help")) + char *sender = GrabString(event, 1, "sender"); + + ref = DbLock(data->db, 3, "rooms", id, "data"); + json = DbJson(ref); + + if (JsonValueAsBoolean(HashMapGet(json, "is_direct"))) { - Log(LOG_ERR, "Not implemented!"); - ASSend(conf, id, NULL, "m.room.message", - MatrixCreateNotice("No help, pal.") - ); + char *user = GrabString(json, 1, "xmpp_user"); + char *local = ParseeEncodeMXID(sender); + + Log(LOG_INFO, "Sending to %s on XMPP", user); + XMPPSendPlain(jabber, local, user, body, NULL); + + Free(local); } + + DbUnlock(data->db, ref); } void -ParseeEventHandler(const ParseeConfig *conf, HashMap *event) +ParseeEventHandler(ParseeData *data, HashMap *event) { char *event_type; - if (!conf || !event) + if (!data || !event) { return; } @@ -57,12 +93,12 @@ ParseeEventHandler(const ParseeConfig *conf, HashMap *event) event_type = GrabString(event, 1, "type"); if (StrEquals(event_type, "m.room.member")) { - ParseeMemberHandler(conf, event); + ParseeMemberHandler(data, event); return; } if (StrEquals(event_type, "m.room.message")) { - ParseeMessageHandler(conf, event); + ParseeMessageHandler(data, event); return; } } diff --git a/src/ParseeConfig.c b/src/ParseeConfig.c index 3c5d910..1e52785 100644 --- a/src/ParseeConfig.c +++ b/src/ParseeConfig.c @@ -23,6 +23,10 @@ ParseeConfigInit(void) config->listen_as = StrDuplicate("localhost"); config->port = 7642; /* proposed by Saint */ + config->component_port = 0; + config->component_host = NULL; + config->shared_comp_secret = NULL; + stream = StreamOpen("parsee.json", "w"); json = HashMapCreate(); HashMapSet(json, "as_token", JsonValueString(config->as_token)); @@ -67,6 +71,12 @@ ParseeConfigLoad(char *conf) CopyToStr(homeserver_host, "hs_host"); CopyToInt(homeserver_port, "hs_port"); + CopyToInt(component_port, "component_port"); + CopyToStr(component_host, "component_host"); + CopyToStr(shared_comp_secret, "shared_secret"); + + CopyToStr(db_path, "db"); + JsonFree(json); StreamClose(stream); } @@ -92,10 +102,10 @@ ParseeExportConfigYAML(Stream *stream) StreamPrintf(stream, "namespaces: \n"); StreamPrintf(stream, " users:\n"); StreamPrintf(stream, " - exclusive: true\n"); - StreamPrintf(stream, " regex: \"@%s_.*\n", config->namespace_base); + StreamPrintf(stream, " regex: \"@%s_.*\"\n", config->namespace_base); StreamPrintf(stream, " aliases:\n"); StreamPrintf(stream, " - exclusive: true\n"); - StreamPrintf(stream, " regex: \"#%s_.*\n", config->namespace_base); + StreamPrintf(stream, " regex: \"#%s_.*\"\n", config->namespace_base); } void @@ -105,6 +115,11 @@ ParseeConfigFree(void) { return; } + Free(config->component_host); + Free(config->shared_comp_secret); + Free(config->db_path); + Free(config->homeserver_host); + Free(config->as_token); Free(config->hs_token); Free(config->sender_localpart); diff --git a/src/ParseeData.c b/src/ParseeData.c index 77ada85..af0dbda 100644 --- a/src/ParseeData.c +++ b/src/ParseeData.c @@ -6,7 +6,7 @@ #include ParseeData * -ParseeInitData(void) +ParseeInitData(XMPPComponent *comp) { ParseeData *data; if (!ParseeConfigGet()) @@ -17,6 +17,8 @@ ParseeInitData(void) data = Malloc(sizeof(*data)); data->config = ParseeConfigGet(); data->router = HttpRouterCreate(); + data->jabber = comp; + data->db = DbOpen(data->config->db_path, 0); #define X_ROUTE(path, func) do {\ if (!HttpRouterAdd(data->router, path, func))\ @@ -37,6 +39,8 @@ ParseeFreeData(ParseeData *data) return; } + XMPPEndCompStream(data->jabber); + DbClose(data->db); HttpRouterFree(data->router); Free(data); } diff --git a/src/ParseeUser.c b/src/ParseeUser.c index 526ecef..949f5a1 100644 --- a/src/ParseeUser.c +++ b/src/ParseeUser.c @@ -1,5 +1,8 @@ #include +#include +#include +#include #include bool @@ -30,3 +33,125 @@ ParseeIsPuppet(const ParseeConfig *conf, char *user) * room. */ return flag; } + +static char * +DecodeJID(char *str, char term) +{ + char *out = NULL; +#define Okay(c) ((c) && ((c) != term)) + while (Okay(*str)) + { + char c = *str; + char buf[3] = { 0 }; + char *tmp; + if (c == '=' && Okay(*(str + 1)) && Okay(*(str + 2))) + { + str++; + + memcpy(buf, str, 2); + buf[0] = strtol(buf, NULL, 16); + buf[1] = '\0'; + + tmp = StrConcat(2, out, buf); + Free(out); + out = tmp; + + str += 2; + continue; + } + memcpy(buf, str, 1); + tmp = StrConcat(2, out, buf); + Free(out); + out = tmp; + + str++; + } +#undef Okay + return out; +} +char * +ParseeDecodeLocalJID(const ParseeConfig *c, char *mxid) +{ + char *localpart, *jid_flags, *data_start; + bool plain_jid = false; + if (!ParseeIsPuppet(c, mxid)) + { + return NULL; + } + + localpart = mxid + 1; + jid_flags = localpart + strlen(c->namespace_base) + 1; + data_start = jid_flags; + while (*data_start && *data_start != '_') + { + /* TODO: Make this a macro */ + if (*data_start == 'l') + { + plain_jid = true; + } + data_start++; + } + if (!*data_start || !plain_jid) + { + return NULL; + } + data_start++; + /* Until the ':', data_start now is an encoded JID */ + return DecodeJID(data_start, ':'); +} +char * +ParseeGetLocal(char *mxid) +{ + char *cpy; + size_t i; + if (!mxid) + { + return NULL; + } + if (*mxid != '@') + { + return StrDuplicate(mxid); + } + + mxid++; + cpy = Malloc(strlen(mxid) + 1); + memset(cpy, '\0', strlen(mxid) + 1); + memcpy(cpy, mxid, strlen(mxid)); + + for (i = 0; i < strlen(mxid); i++) + { + if (cpy[i] == ':') + { + cpy[i] = '\0'; + break; + } + } + + return cpy; +} +char * +ParseeEncodeMXID(char *mxid) +{ + char *ret; + size_t i; + if (!mxid) + { + return NULL; + } + ret = Malloc(strlen(mxid) + 1); + for (i = 0; i < strlen(mxid) + 1; i++) + { + char src = mxid[i]; + if (src == '@') + { + src = '%'; + } + else if (src == ':') + { + src = '='; + } + ret[i] = src; + } + + return ret; +} diff --git a/src/Routes/Root.c b/src/Routes/Root.c index 74fcecb..51407e3 100644 --- a/src/Routes/Root.c +++ b/src/Routes/Root.c @@ -6,8 +6,6 @@ RouteHead(RouteRoot, arr, argp) { ParseeHttpArg *args = argp; - ASPing(args->data->config); - HttpResponseHeader(args->ctx, "Content-Type", "text/html"); HttpSendHeaders(args->ctx); StreamPrintf(args->stream, ""); @@ -30,5 +28,6 @@ RouteHead(RouteRoot, arr, argp) StreamPrintf(args->stream, "

"); StreamPrintf(args->stream, " "); StreamPrintf(args->stream, ""); + return NULL; } diff --git a/src/Routes/Transactions.c b/src/Routes/Transactions.c index 182dba1..b527218 100644 --- a/src/Routes/Transactions.c +++ b/src/Routes/Transactions.c @@ -38,7 +38,7 @@ RouteHead(RouteTxns, arr, argp) for (i = 0; i < ArraySize(events); i++) { HashMap *event = JsonValueAsObject(ArrayGet(events, i)); - ParseeEventHandler(args->data->config, event); + ParseeEventHandler(args->data, event); } /* TODO: Store TXN ID somewhere so that we can commit diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c new file mode 100644 index 0000000..08b62df --- /dev/null +++ b/src/Routes/UserAck.c @@ -0,0 +1,41 @@ +#include + +#include + +#include +#include + +RouteHead(RouteUserAck, arr, argp) +{ + ParseeHttpArg *args = argp; + HashMap *request = NULL; + HashMap *response = NULL; + Array *events; + size_t i; + + char *user = ArrayGet(arr, 0); + + Log(LOG_INFO, "Alles Politischemacht"); + response = ASVerifyRequest(args); + if (response) + { + goto end; + } + if (HttpRequestMethodGet(args->ctx) != HTTP_GET) + { + HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); + response = MatrixCreateError( + "M_UNRECOGNIZED", + "Path /users only accepts GET as a valid method." + ); + goto end; + } + + Log(LOG_INFO, "user=%s", user); + ASRegisterUser(args->data->config, user); + /* TODO: Verify the user, and create an XMPP mapping. */ + response = HashMapCreate(); +end: + JsonFree(request); + return response; +} diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index af9a0ee..b101c77 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -22,7 +22,7 @@ /* The default component port Prosody uses. */ #define DEFAULT_PROSODY_PORT 5347 -Stream * +XMPPComponent * XMPPInitialiseCompStream(char *host, int port) { /* TODO */ @@ -31,6 +31,7 @@ XMPPInitialiseCompStream(char *host, int port) int error; char serv[8]; Stream *stream; + XMPPComponent *comp; snprintf(serv, sizeof(serv), "%hu", port ? port : DEFAULT_PROSODY_PORT); @@ -74,7 +75,11 @@ XMPPInitialiseCompStream(char *host, int port) return NULL; } - return stream; + comp = Malloc(sizeof(*comp)); + comp->host = StrDuplicate(host); + comp->stream = stream; + + return comp; } #include @@ -95,17 +100,22 @@ ComputeHandshake(char *shared, char *stream) return sha; } bool -XMPPAuthenticateCompStream(Stream *stream, char *as, char *shared) +XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) { /* TODO */ XMLexer *sax; XMLEvent *ev; char *stream_id, *handshake; bool ret = false; - if (!stream || !as || !shared) + Stream *stream; + char *as; + if (!comp || !shared) { return false; } + + stream = comp->stream; + as = comp->host; StreamPrintf(stream, "stream); + Free(comp->host); + Free(comp); } diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c new file mode 100644 index 0000000..38357c6 --- /dev/null +++ b/src/XMPP/Stanza.c @@ -0,0 +1,43 @@ +#include + +void +XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type) +{ + if (!comp || !fr || !to || !msg) + { + return; + } + StreamPrintf( + comp->stream, "host, to + ); + if (type) + { + StreamPrintf(comp->stream, " type='%s'", type); + } + StreamPrintf(comp->stream, ">"); + StreamPrintf(comp->stream, + "" + "%s" + "" + "", + msg + ); + StreamFlush(comp->stream); +} +void +XMPPSendPresence(XMPPComponent *comp, char *fr, char *to) +{ + if (!comp || !fr || !to) + { + return; + } + StreamPrintf(comp->stream, + "" + "" + "", + fr, comp->host, + to + ); + StreamFlush(comp->stream); +} diff --git a/src/include/AS.h b/src/include/AS.h index 240d82e..f480f47 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -20,7 +20,7 @@ extern void ASAuthenticateRequest(ParseeConfig *, HttpClientContext *); extern bool ASRegisterUser(ParseeConfig *, char *); /* Pings the homeserver to get attention. */ -extern void ASPing(ParseeConfig *); +extern void ASPing(const ParseeConfig *); /* Joins a room from an ID and a given user we want to masquerade * as. */ diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 71e9acf..0b4c92c 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -5,8 +5,12 @@ #include #include #include +#include + +#include typedef struct ParseeConfig { + /* -------- MATRIX -------- */ char *as_token, *hs_token; /* id here is "Parsee XMPP". */ char *sender_localpart; @@ -18,11 +22,24 @@ typedef struct ParseeConfig { /* Homeserver port info */ char *homeserver_host; int homeserver_port; + + + /* ------- JABBER -------- */ + char *component_host; + char *shared_comp_secret; + int component_port; + + /* ------- DB -------- */ + char *db_path; } ParseeConfig; typedef struct ParseeData { const ParseeConfig *config; HttpRouter *router; + + XMPPComponent *jabber; + + Db *db; } ParseeData; /* Initialises a Parsee config from scratch, and writes to it @@ -42,7 +59,7 @@ extern void ParseeExportConfigYAML(Stream *); extern void ParseeConfigFree(void); /* Creates and destroys a data structure, stored on the heap. */ -extern ParseeData * ParseeInitData(void); +extern ParseeData * ParseeInitData(XMPPComponent *); extern void ParseeFreeData(ParseeData *); /* HTTP server handler for Parsee, takes in a config. */ @@ -54,8 +71,17 @@ extern HttpClientContext * ParseeCreateRequest(ParseeConfig *, HttpRequestMethod extern HttpStatus ParseeSetRequestJSON(HttpClientContext *, HashMap *); /* This function is called on every event received, and routes/manages it. */ -extern void ParseeEventHandler(const ParseeConfig *, HashMap *); +extern void ParseeEventHandler(ParseeData *, HashMap *); /* Verifies if a user is a Parsee puppet user. */ extern bool ParseeIsPuppet(const ParseeConfig *, char *); + +/* Decodes a local JID for a user into a string. */ +extern char * ParseeDecodeLocalJID(const ParseeConfig *, char *); + +/* Gets the localpart of a MXID */ +extern char * ParseeGetLocal(char *); + +/* Encodes an MXID to a valid Jabber ID head */ +extern char * ParseeEncodeMXID(char *); #endif diff --git a/src/include/Routes.h b/src/include/Routes.h index ba8f223..8f11cf6 100644 --- a/src/include/Routes.h +++ b/src/include/Routes.h @@ -11,7 +11,8 @@ typedef struct ParseeHttpArg { /* A list of all routes. */ #define ROUTES X_ROUTE("/", RouteRoot) \ X_ROUTE("/_matrix/app/v1/transactions/(.*)", RouteTxns) \ - X_ROUTE("/_matrix/app/v1/ping", RoutePing) + X_ROUTE("/_matrix/app/v1/ping", RoutePing) \ + X_ROUTE("/_matrix/app/v1/users/(.*)", RouteUserAck) #define X_ROUTE(path, name) extern void * name(Array *, void *); ROUTES diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 665be8a..5f27091 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -3,17 +3,26 @@ #include +typedef struct XMPPComponent { + char *host; + Stream *stream; +} 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 Stream * XMPPInitialiseCompStream(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(Stream *stream, char *as, char *shared); +extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); + +/* Sends a presence to a user */ +extern void XMPPSendPresence(XMPPComponent *comp, char *fr, char *to); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ +extern void XMPPSendPlain(XMPPComponent *c, char *f, char *t, char *m, char *type); /* Closes a raw component stream. */ -extern void XMPPEndCompStream(Stream *stream); +extern void XMPPEndCompStream(XMPPComponent *stream); #endif