diff --git a/.forgejo/workflows/check-gcc.yaml b/.forgejo/workflows/check-gcc.yaml index bcf2c00..5404fa6 100644 --- a/.forgejo/workflows/check-gcc.yaml +++ b/.forgejo/workflows/check-gcc.yaml @@ -33,7 +33,7 @@ jobs: - name: Build Parsee run: | cc configure.c -o configure && ./configure - echo 'CFLAGS=-Werror -Wall -Wextra -pedantic' >> build.conf + echo 'CFLAGS=-Werror -Wall -Wextra -pedantic -fanalyzer' >> build.conf cat build.conf make && make ayadoc - name: Install Parsee diff --git a/README.MD b/README.MD index 786e905..e6e7185 100644 --- a/README.MD +++ b/README.MD @@ -97,6 +97,9 @@ restricted to Parsee admins, with permission from MUC owners, too 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 well with unexcepted stream closures (e.g: with an XMPP server +turning off, etc...). Shutting it off seems like an easy solution, but would go +against principles. ## DONATING/CONTRIBUTING If you know things about XMPP or Matrix, yet aren't familiar with C99, or just diff --git a/configure.c b/configure.c index 574b75f..75d56f4 100644 --- a/configure.c +++ b/configure.c @@ -445,10 +445,15 @@ main_build(int argc, char *argv[]) if (repo) { char *lf = strchr(repo, '\n'); - *lf = '\0'; + if (lf) + { + *lf = '\0'; + } } else + { repo = strdup("N/A"); + } while ((opt = getopt(argc, argv, "sl")) != -1) { @@ -465,8 +470,9 @@ main_build(int argc, char *argv[]) } makefile = fopen("Makefile", "w"); - fprintf(makefile, "# Autogenerated POSIX Makefile\n"); - fprintf(makefile, "# Ideally do not touch.\n\n"); + 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"); diff --git a/src/FileInfo.c b/src/FileInfo.c index e242e9d..17974d0 100644 --- a/src/FileInfo.c +++ b/src/FileInfo.c @@ -40,6 +40,8 @@ FileInfoFromXMPP(XMLElement *stanza) 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; diff --git a/src/Main.c b/src/Main.c index 2ddd35f..d407d60 100644 --- a/src/Main.c +++ b/src/Main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -81,6 +82,13 @@ Main(Array *args, HashMap *env) Log(LOG_INFO, "======================="); Log(LOG_INFO, "(C)opyright 2024 LDA"); 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()); { diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index 541c0a4..c5c23ec 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -62,6 +62,12 @@ ParseeConfigLoad(char *conf) CopyToInt(component_port, "component_port"); 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 = 10 KB; + } CopyToStr(media_base, "media_base"); diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 3d2bbb8..0ca2dce 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -59,6 +59,7 @@ ParseeInitData(XMPPComponent *comp) { 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); @@ -126,8 +127,6 @@ ParseeCleanup(void *datp) uint64_t ts = UtilTsMillis(); size_t entries = 0; - Log(LOG_DEBUG, "Cleaning up..."); - chats = DbList(data->db, 1, "chats"); for (i = 0; i < ArraySize(chats); i++) @@ -242,7 +241,6 @@ ParseeCleanup(void *datp) DbUnlock(data->db, ref); } DbListFree(chats); - Log(LOG_DEBUG, "Cleant up %d entries...", entries); } void diff --git a/src/Signal.c b/src/Signal.c index 4274561..9335897 100644 --- a/src/Signal.c +++ b/src/Signal.c @@ -25,6 +25,8 @@ SignalHandler(int signal) if (signal == SIGPIPE) { Log(LOG_DEBUG, "Caught a SIGPIPE..."); + XMPPFinishCompStream(jabber); + pthread_join(xmpp_thr, NULL); return; } } diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 811c6d3..96f22e3 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -237,13 +237,8 @@ WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber) } elem = ExportStanza(builder); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, elem); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, elem); XMLFreeElement(elem); - return; } StanzaBuilder * diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 71f617a..0722460 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -134,7 +135,7 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) } break; } - if (ev->type != XML_LEXER_STARTELEM || + if (!ev || ev->type != XML_LEXER_STARTELEM || !StrEquals(ev->element, "stream:stream")) { Log(LOG_ERR, "Excepted stream:stream element."); @@ -159,10 +160,9 @@ XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared) } break; } - if (ev->type != XML_LEXER_ELEM || + if (!ev || 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."); Log(LOG_ERR, ""); @@ -213,3 +213,18 @@ XMPPEndCompStream(XMPPComponent *comp) Free(comp->host); Free(comp); } +void +XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza) +{ + if (!comp || !stanza) + { + return; + } + + pthread_mutex_lock(&comp->write_lock); + /* TODO: Find a way to negociate to the server about stanza size + * (beyond the 10KB limit that is REQUIRED by XMPP standards) */ + XMLEncode(comp->stream, stanza); + StreamFlush(comp->stream); + pthread_mutex_unlock(&comp->write_lock); +} diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 5d39d78..f97f664 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -18,8 +18,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) return false; } - pthread_mutex_lock(&jabber->write_lock); - iq_query = XMLCreateTag("iq"); query = XMLCreateTag("query"); @@ -35,8 +33,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { XMLElement *identity; - XMLEncode(jabber->stream, iq_query); - StreamFlush(jabber->stream); + XMPPSendStanza(jabber, iq_query); XMLFreeElement(iq_query); /* Except an IQ reply. 10 seconds of timeout is pretty @@ -46,7 +43,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) if (!iq_query || !StrEquals(iq_query->name, "iq")) { XMLFreeElement(iq_query); - pthread_mutex_unlock(&jabber->write_lock); return false; } query = XMLookForUnique(iq_query, "query"); @@ -57,7 +53,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) "conference")) { XMLFreeElement(iq_query); - pthread_mutex_unlock(&jabber->write_lock); return false; } @@ -73,7 +68,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) XMLFreeElement(iq_query); } } - pthread_mutex_unlock(&jabber->write_lock); return true; } @@ -116,7 +110,6 @@ 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); @@ -160,9 +153,7 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) } XMLAddChild(stanza, x); } - XMLEncode(jabber->stream, stanza); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, stanza); XMLFreeElement(stanza); Free(identifier); @@ -177,8 +168,6 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool return false; } - pthread_mutex_lock(&comp->write_lock); - presence = XMLCreateTag("presence"); x = XMLCreateTag("x"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); @@ -212,14 +201,10 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(presence, x); } - XMLEncode(comp->stream, presence); - StreamFlush(comp->stream); - + XMPPSendStanza(comp, presence); XMLFreeElement(presence); Free(from); - pthread_mutex_unlock(&comp->write_lock); - if (ret && (reply = ParseeAwaitStanza(id, 500))) { bool exit_code = true; @@ -246,8 +231,6 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) return; } - pthread_mutex_lock(&comp->write_lock); - presence = XMLCreateTag("presence"); XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); XMLAddAttr(presence, "to", muc); @@ -265,12 +248,9 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMPPAnnotatePresence(presence); - XMLEncode(comp->stream, presence); - StreamFlush(comp->stream); + XMPPSendStanza(comp, presence); XMLFreeElement(presence); Free(from); Free(id); - - pthread_mutex_unlock(&comp->write_lock); } diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index e731792..310b2d1 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -66,13 +66,9 @@ XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) } - pthread_mutex_lock(&comp->write_lock); - XMLEncode(comp->stream, message); - StreamFlush(comp->stream); + XMPPSendStanza(comp, message); XMLFreeElement(message); - pthread_mutex_unlock(&comp->write_lock); - Free(from); Free(ident); } @@ -85,6 +81,8 @@ 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"); } @@ -266,10 +264,7 @@ XMPPSendDisco(ParseeData *data, char *from, char *to) XMLAddChild(iq, query); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); ret = ParseeAwaitStanza(identifier, 1.25 SECONDS); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index 580773f..f5714b9 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -274,10 +274,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) x = XMPPFormifyCommand(m, cmd, from); XMLAddChild(command_xml, x); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); goto end; @@ -305,10 +302,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, NULL); XMLAddChild(iq, command_xml); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); InvalidateSession(m, session_id); @@ -348,10 +342,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, x_form); XMLAddChild(iq, command_xml); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq); XMLFreeElement(iq); InvalidateSession(m, session_given); diff --git a/src/XMPPThread/PEPs/Avatar.c b/src/XMPPThread/PEPs/Avatar.c index 819bcd0..e2ea636 100644 --- a/src/XMPPThread/PEPs/Avatar.c +++ b/src/XMPPThread/PEPs/Avatar.c @@ -72,11 +72,7 @@ PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) char *url = HashMapGet(item->attrs, "url"); XMLElement *request = CreateAvatarRequest(from, to, id); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, request); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, request); XMLFreeElement(request); (void) url; /* TODO */ diff --git a/src/XMPPThread/PEPs/VCard.c b/src/XMPPThread/PEPs/VCard.c index 1859e97..0ca65be 100644 --- a/src/XMPPThread/PEPs/VCard.c +++ b/src/XMPPThread/PEPs/VCard.c @@ -113,10 +113,7 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) } } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, reply); XMLFreeElement(reply); (void) item; } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c index 3f55bce..13ee9d5 100644 --- a/src/XMPPThread/PresenceSub.c +++ b/src/XMPPThread/PresenceSub.c @@ -131,11 +131,7 @@ ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza) /* TODO: Should we store IDs somewhere? */ XMLAddAttr(sub, "id", (storm_id = StrRandom(16))); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, sub); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, sub); XMLFreeElement(sub); Free(storm_id); end: diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 56d5317..1b5e5f1 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -198,6 +198,7 @@ ParseeXMPPThread(void *argp) stanza = XMLDecode(jabber->stream, false); if (!stanza) { + /* Try to check if an error is abound */ if (args->verbosity >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "RECEIVED EOF."); diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 0f25c4c..44c3697 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -65,6 +65,14 @@ GenerateAvatarData(ParseeData *data, char *mxid) goto end; } b64 = Base64Encode(out, len); + if (!b64 || strlen(b64) > 64 KB) /* We still have stanza limitations. Thanks, Array. + * TODO: Communicate with the server to discover it. */ + { + Free(b64); + Free(mime); + b64 = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ + mime = StrDuplicate("image/png"); + } elem = XMLCreateTag("PHOTO"); type = XMLCreateTag("TYPE"); @@ -145,11 +153,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) } XMLAddChild(iq_reply, query); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq_reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); - + XMPPSendStanza(jabber, iq_reply); XMLFreeElement(iq_reply); (void) args; @@ -386,10 +390,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMPPShoveCommandList(thr->info->m, to, q); XMLAddChild(iq_reply, q); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq_reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq_reply); XMLFreeElement(iq_reply); } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) @@ -427,10 +428,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iqVCard); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iqVCard); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -457,10 +455,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iqVCard); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iqVCard); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -474,7 +469,10 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ); if (a_items) { - /* Do, without regret, start shoving an avatar out the bus */ + /* 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 *buf, *mime; @@ -484,6 +482,13 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) ASGrab(args->config, avatar, &mime, &buf, &len); b64 = Base64Encode(buf, len); + if (!b64 || strlen(b64) > 64 KB) + { + Free(b64); + Free(mime); + b64 = StrDuplicate(media_parsee_logo); /* TODO: Different assets! */ + mime = StrDuplicate("image/png"); + } Free(buf); Log(LOG_DEBUG, "IQ-GET: PUBSUB AVATAR OF=%s", to_matrix); @@ -513,10 +518,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(reply, ps); } - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, reply); XMLFreeElement(reply); Free(to_matrix); @@ -554,10 +556,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(query, version); XMLAddChild(iq_reply, query); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, iq_reply); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, iq_reply); XMLFreeElement(iq_reply); } else diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 6181616..b9c5810 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -370,19 +370,13 @@ end_error: ps = CreatePubsubRequest( parsee, decode_from, "urn:xmpp:avatar:metadata" ); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, ps); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, ps); XMLFreeElement(ps); ps = CreatePubsubRequest( parsee, trim, "urn:xmpp:avatar:metadata" ); - pthread_mutex_lock(&jabber->write_lock); - XMLEncode(jabber->stream, ps); - StreamFlush(jabber->stream); - pthread_mutex_unlock(&jabber->write_lock); + XMPPSendStanza(jabber, ps); XMLFreeElement(ps); if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) { diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index dc825f3..2885714 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -158,13 +158,17 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *room = ParseeGetBridgedRoom(args, stanza); char *decode_from, *real_matrix; char *matrix_user_pl = ParseeEncodeJID(args->config, trim, false); - char *affiliation = HashMapGet(item->attrs, "affiliation"); - char *role = HashMapGet(item->attrs, "role"); + char *affiliation = item ? HashMapGet(item->attrs, "affiliation") : NULL; + char *role = item ? HashMapGet(item->attrs, "role") : NULL; int power_level = 0; char *parsee = ParseeMXID(args); char *parsee_j = ParseeJID(args); Free(trim); + if (!item) + { + goto end_item; + } if (jid) { @@ -280,7 +284,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) Free(chat_id); } - +end_item: Free(from); Free(decode_from); Free(real_matrix); @@ -376,11 +380,8 @@ PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) 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); XMLFreeElement(vcard_request); Free(from); } diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 158f563..ea9edcf 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -45,6 +45,7 @@ typedef struct ParseeConfig { char *component_host; char *shared_comp_secret; int component_port; + size_t max_stanza_size; /* ------- DB -------- */ char *db_path; @@ -80,6 +81,7 @@ 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__)) @@ -114,6 +116,9 @@ 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); diff --git a/src/include/StringStream.h b/src/include/StringStream.h index 007a66b..03a25ab 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. */ + * or NULL for an empty string. */ extern Stream * StrStreamWriter(char **buffer); /* Creates a string stream reader. The referenced buffer may be everywhere. */ diff --git a/src/include/XMPP.h b/src/include/XMPP.h index b3f4c09..27cecd0 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -29,6 +29,13 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); * after XMPPInitialiseCompStream. */ extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); +/** Writes an XML stanza through a component, while making sure any locking + * work is done. + * ----------------------- + * Modifies: {comp}, the XMPP stream + * See-Also: XMPPInitialiseCompStream, XMPPAuthenticateCompStream, XMPP-core RFC */ +extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza); + /* Makes a user join/leave a MUC */ extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int secs, bool ret); extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r); diff --git a/tools/Makefile b/tools/Makefile deleted file mode 100644 index 7fa93bc..0000000 --- a/tools/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# 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) -