#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static HttpServer *server = NULL; static pthread_t xmpp_thr; static XMPPComponent *jabber = NULL; static volatile uint64_t start; uint64_t ParseeUptime(void) { return UtilTsMillis() - start; } static const Argument arguments[] = { #define Arg(c, req, vdesc, desc) \ { \ .end = false, \ .argument = c, .value_req = req, \ .value_descr = vdesc, \ .description = desc \ }, #define EndOfArgs { .end = true } Arg('H', true, "number(=8)", "Sets the number of HTTP threads") Arg('J', true, "number(=8)", "Sets the number of XMPP threads") Arg('C', true, "file(='parsee.json')", "Sets the JSON config to use") Arg('g', false, NULL, "Generates a parsee.yaml AS file before exiting") Arg('v', false, NULL, "Forces Parsee to print in a more verbose fashion " "(-vv prints stanzas to stderr)") Arg('h', false, NULL, "Generates an help screen(this one!)") EndOfArgs #undef EndOfArgs #undef Argument }; int Main(Array *args, HashMap *env) { HttpServerConfig conf; const ParseeConfig *parsee_conf; Stream *yaml; Cron *cron = NULL; char *configuration = "parsee.json"; int xmpp = 8; int http = 8; int verbose = 0; start = UtilTsMillis(); memset(&conf, 0, sizeof(conf)); Log(LOG_INFO, "%s - v%s[%s] (Cytoplasm %s)", NAME, VERSION, CODE, CytoplasmGetVersionStr() ); ParseePrintASCII(); Log(LOG_INFO, "======================="); LogConfigIndent(LogConfigGlobal()); { ArgParseState state; char *opts = ParseeGenerateGetopt(arguments); int flag; ArgParseStateInit(&state); while ((flag = ArgParse(&state, args, opts)) != -1) { switch (flag) { case 'h': ParseeGenerateHelp(arguments); Free(opts); goto end; case 'H': http = strtol(state.optArg, NULL, 10); break; case 'J': xmpp = strtol(state.optArg, NULL, 10); break; case 'g': /* Write out the config file to a YAML document */ Log(LOG_INFO, "Generating YAML..."); yaml = StreamOpen("parsee.yaml", "w"); ParseeExportConfigYAML(yaml); StreamClose(yaml); Free(opts); goto end; case 'v': switch (++verbose) { case PARSEE_VERBOSE_LOG: LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG); break; case PARSEE_VERBOSE_STANZA: Log(LOG_DEBUG, "Enabling stanza printing."); break; case PARSEE_VERBOSE_COMICAL: Log(LOG_DEBUG, "What?"); Log(LOG_DEBUG, "No, but like, what do you except?"); Log(LOG_DEBUG, "Like do you want to log _every_ instruction?"); Log(LOG_DEBUG, "Like just every single thing %s does?", NAME); Log(LOG_DEBUG, " ( why??? )"); Log(LOG_DEBUG, "....................................."); Log(LOG_DEBUG, "Argh."); Log(LOG_DEBUG, "Alright. I'll do my best."); Log(LOG_DEBUG, "Get what you paid for."); break; } break; case 'C': if (!UtilLastModified(state.optArg)) { Log(LOG_ERR, "Invalid config: %s", state.optArg); Log(LOG_ERR, "Ignoring."); break; } configuration = state.optArg; break; case '?': Log(LOG_ERR, "INVALID ARGUMENT GIVEN"); Free(opts); goto end; } } Free(opts); ParseeSetThreads(xmpp, http); } if (verbose >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "Loading configuration..."); } ParseeConfigLoad(configuration); ParseeConfigInit(); parsee_conf = ParseeConfigGet(); if (!parsee_conf) { goto end; } Log(LOG_NOTICE, "Connecting to XMPP..."); jabber = XMPPInitialiseCompStream( parsee_conf->component_host, parsee_conf->component_port ); if (!XMPPAuthenticateCompStream( jabber, parsee_conf->shared_comp_secret )) { Log(LOG_ERR, "Could not connect to XMPP..."); if (verbose >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "Destroying component..."); } XMPPEndCompStream(jabber); goto end; } Log(LOG_NOTICE, "Creating volatile tables..."); if (verbose >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "Initialising JID table"); } ParseeInitialiseJIDTable(); if (verbose >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "Initialising OID table"); } ParseeInitialiseOIDTable(); if (verbose >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "Initialising head table"); } ParseeInitialiseHeadTable(); if (verbose >= PARSEE_VERBOSE_COMICAL) { Log(LOG_DEBUG, "Initialising nick table"); } ParseeInitialiseNickTable(); conf.port = parsee_conf->port; conf.threads = parsee_conf->http_threads; conf.maxConnections = conf.threads << 2; conf.handlerArgs = ParseeInitData(jabber); conf.handler = ParseeRequest; if (!conf.handlerArgs) { goto end; } Log(LOG_DEBUG, "Verbosity level: %d", verbose); ((ParseeData *) conf.handlerArgs)->verbosity = verbose; Log(LOG_NOTICE, "Setting up local Matrix user..."); if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart)) { char *parsee = ParseeMXID(conf.handlerArgs); ASSetAvatar(parsee_conf, parsee, "mxc://tedomum.net/" "7e228734ec8e792960bb5633e43f0cb845f709f61825130490034651136" ); ASSetName(parsee_conf, parsee, "Parsee bridge"); Free(parsee); } Log(LOG_NOTICE, "Starting up local cronjobs..."); cron = CronCreate(10 SECONDS); CronEvery(cron, 5 MINUTES, ParseeCleanup, conf.handlerArgs); ParseeCleanup(conf.handlerArgs); CronStart(cron); Log(LOG_NOTICE, "Creating XMPP listener thread..."); if (pthread_create(&xmpp_thr, NULL, ParseeXMPPThread, conf.handlerArgs)) { Log(LOG_ERR, "Couldn't start XMPP listener thread."); goto end; } server = HttpServerCreate(&conf); if (!ParseeInitialiseSignals(server, xmpp_thr, jabber)) { goto end; } HttpServerStart(server); Log(LOG_NOTICE, "Listening to MUCs..."); LogConfigIndent(LogConfigGlobal()); ParseeSendPresence(conf.handlerArgs); LogConfigUnindent(LogConfigGlobal()); LogConfigUnindent(LogConfigGlobal()); Log(LOG_INFO, "======================="); HttpServerJoin(server); end: Log(LOG_INFO, "Exiting..."); HttpServerFree(server); ParseeConfigFree(); CronStop(cron); CronFree(cron); ParseeFreeData(conf.handlerArgs); ParseeDestroyNickTable(); ParseeDestroyOIDTable(); ParseeDestroyHeadTable(); ParseeDestroyJIDTable(); (void) env; return 0; }