/* Copyright (C) 2020 C. McEnroe * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #define SQL(...) #__VA_ARGS__ enum { DatabaseVersion = 4 }; static sqlite3 *db; static void dbClose(void) { // TODO: Finalize statements. sqlite3_close(db); } #define ENUM_PAGES \ X(Networks, "networks") \ X(Contexts, "contexts") \ X(Events, "events") \ X(Search, "search") enum { #define X(page, path) page, ENUM_PAGES #undef X PagesLen, }; static const char *Pages[PagesLen] = { #define X(page, path) [page] = path, ENUM_PAGES #undef X }; #define ENUM_KEYS \ X(Network, "network", kvalid_string) \ X(Context, "context", kvalid_string) \ X(After, "after", kvalid_string) \ X(Query, "query", kvalid_string) enum { #define X(key, name, valid) key, ENUM_KEYS #undef X KeysLen, }; static const struct kvalid Keys[KeysLen] = { #define X(key, name, valid) [key] = { valid, name }, ENUM_KEYS #undef X }; static void request(struct kreq *req) { } int main(int argc, char *argv[]) { bool fastCGI = false; bool public = false; const char *stylesheet = NULL; for (int opt; 0 < (opt = getopt(argc, argv, "fps:"));) { switch (opt) { break; case 'f': fastCGI = true; break; case 'p': public = true; break; case 's': stylesheet = optarg; break; default: return EX_USAGE; } } if (optind == argc) errx(EX_USAGE, "database path required"); int error = sqlite3_open_v2(argv[optind], &db, SQLITE_OPEN_READONLY, NULL); if (error) errx(EX_NOINPUT, "%s: %s", argv[optind], sqlite3_errmsg(db)); atexit(dbClose); sqlite3_stmt *stmt; error = sqlite3_prepare_v2( db, SQL(PRAGMA user_version;), -1, &stmt, NULL ); if (error) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db)); error = sqlite3_step(stmt); if (error != SQLITE_ROW) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db)); int version = sqlite3_column_int(stmt, 0); if (version != DatabaseVersion) { errx(EX_DATAERR, "unsupported database version %d", version); } sqlite3_finalize(stmt); // TODO: Prepare all statements with persist flag. if (fastCGI) { struct kfcgi *fcgi; enum kcgi_err error = khttp_fcgi_init( &fcgi, Keys, KeysLen, Pages, PagesLen, Networks ); if (error) errx(EX_CONFIG, "khttp_fcgi_init: %s", kcgi_strerror(error)); for ( struct kreq req; KCGI_OK == (error = khttp_fcgi_parse(fcgi, &req)); khttp_free(&req) ) { request(&req); } errx(EX_DATAERR, "khttp_fcgi_parse: %s", kcgi_strerror(error)); } else { struct kreq req; enum kcgi_err error = khttp_parse( &req, Keys, KeysLen, Pages, PagesLen, Networks ); if (error) errx(EX_DATAERR, "khttp_parse: %s", kcgi_strerror(error)); request(&req); khttp_free(&req); } }