diff --git a/.gitignore b/.gitignore index 7afd29b..4f9cdf1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ obj **/*.o probotic config.h +.gdb_history *.sqlite diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..78616d1 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +main: + ./build.sh diff --git a/bootstrap/init.sql b/bootstrap/init.sql index 51787de..9e61c26 100644 --- a/bootstrap/init.sql +++ b/bootstrap/init.sql @@ -1,3 +1,4 @@ +DROP TABLE IF EXISTS project; CREATE TABLE project ( title VARCHAR(64) NOT NULL, body TEXT DEFAULT NULL, @@ -8,32 +9,25 @@ CREATE TABLE project ( span INT NOT NULL DEFAULT 7 -- time to last for in days ); +DROP TABLE IF EXISTS difficulty; CREATE TABLE difficulty ( diff VARCHAR(16) ); + -INSERT INTO difficulty VALUES('Easy'); -INSERT INTO difficulty VALUES('Medium'); -INSERT INTO difficulty VALUES('Hard'); -INSERT INTO difficulty VALUES('Fuck You'); - - +DROP TABLE IF EXISTS tag; CREATE TABLE tag ( t VARCHAR(16) ); --- Some default (not all) tags -INSERT INTO tag VALUES('AI'); -INSERT INTO tag VALUES('Algorithm'); -INSERT INTO tag VALUES('Calculators'); -INSERT INTO tag VALUES('Games'); -INSERT INTO tag VALUES('Math'); -INSERT INTO tag VALUES('Networking'); -INSERT INTO tag VALUES('Rendering'); -INSERT INTO tag VALUES('Simulation'); -INSERT INTO tag VALUES('Tools'); - +DROP TABLE IF EXISTS project_tag; CREATE TABLE project_tag ( project INT REFERENCES project(rowid), tag INT REFERENCES tag(rowid) ); + +DROP TABLE IF EXISTS assignment; +CREATE TABLE assignment ( + who VARCHAR(32) NOT NULL, + project INT NOT NULL REFERENCES project(rowid) +); diff --git a/build.sh b/build.sh index 6e6984c..ccda8c3 100755 --- a/build.sh +++ b/build.sh @@ -9,8 +9,8 @@ PREFIX=${PREFIX:-$DIR} CC=${CC-cc} CFLAGS='-std=c99 -Wall -Wextra -Wpedantic' -CPPFLAGS="-I/usr/bin/ircclient/ -Iinclude -D_GNU_SOURCE -DDELC=static -DPROGN=\"$PROGN\"" -LDFLAGS='-lircclient' +CPPFLAGS="-I/usr/include/libircclient/ -Iinclude -D_GNU_SOURCE -DDELC=static -DPROGN=\"$PROGN\"" +LDFLAGS='-lircclient -lsqlite3' mkdir -p $PREFIX && echo "Made directory: $PREFIX" diff --git a/defaults.sql b/defaults.sql new file mode 100644 index 0000000..ca02da9 --- /dev/null +++ b/defaults.sql @@ -0,0 +1,22 @@ +INSERT INTO difficulty VALUES('easy'); +INSERT INTO difficulty VALUES('medium'); +INSERT INTO difficulty VALUES('hard'); +INSERT INTO difficulty VALUES('fuck you'); + +INSERT INTO tag VALUES('math'); +INSERT INTO tag VALUES('AI'); +INSERT INTO tag VALUES('networking'); +INSERT INTO tag VALUES('games'); +INSERT INTO tag VALUES('rendering'); +INSERT INTO tag VALUES('simulation'); + +-- +INSERT INTO project (title, body) VALUES ( + 'test project', + 'desc' +); + +INSERT INTO assignment VALUES ( + '#/g/chad', + 1 +); diff --git a/include/api.h b/include/api.h new file mode 100644 index 0000000..c8499a3 --- /dev/null +++ b/include/api.h @@ -0,0 +1,9 @@ +#ifndef API_H_ + +DELC int api_init(void); +DELC void api_rope(void); +DELC void rope(void); +DELC char * remind(char * who); + +#define API_H_ +#endif diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..2ee5c4b --- /dev/null +++ b/include/error.h @@ -0,0 +1,13 @@ +#ifndef ERROR_H_ + +#include + +#define ERR(ret,msg) do { fputs(msg "\n", stderr); return (ret); } while (0) +#define ERRMSG(msg) fputs(msg "\n", stderr) +#define PERROR(name) perror(name) + +#define DB_ERROR 100 +#define IRC_ERROR 200 + +#define ERROR_H_ +#endif diff --git a/include/irc.h b/include/irc.h index c85d0e5..0f7a0b0 100644 --- a/include/irc.h +++ b/include/irc.h @@ -7,5 +7,7 @@ extern irc_callbacks_t callbacks; extern char const * channel; +DELC int init(char const * username, char const * server, int port); + #define IRC_H_ #endif diff --git a/include/irccolors.h b/include/irccolors.h new file mode 100644 index 0000000..ccc5de4 --- /dev/null +++ b/include/irccolors.h @@ -0,0 +1,16 @@ +#define IRC_COLOR_WHITE "\x0300" +#define IRC_COLOR_BLACK "\x0301" +#define IRC_COLOR_BLUE "\x0302" +#define IRC_COLOR_GREEN "\x0303" +#define IRC_COLOR_RED "\x0304" +#define IRC_COLOR_BROWN "\x0305" +#define IRC_COLOR_PURPLE "\x0306" +#define IRC_COLOR_ORANGE "\x0307" +#define IRC_COLOR_YELLOW "\x0308" +#define IRC_COLOR_LIGHT_GREEN "\x0309" +#define IRC_COLOR_TEAL "\x0310" +#define IRC_COLOR_LIGHT_CYAN "\x0311" +#define IRC_COLOR_LIGHT_BLUE "\x0312" +#define IRC_COLOR_PINK "\x0313" +#define IRC_COLOR_GREY "\x0314" +#define IRC_COLOR_LIGHT_GREY "\x0315" diff --git a/include/parse.h b/include/parse.h index b18d655..64e6144 100644 --- a/include/parse.h +++ b/include/parse.h @@ -6,8 +6,8 @@ typedef struct char * password; } creds_t; -int parse_creds(creds_t * creds, char const * creds_file); -void clean_creds(creds_t * creds); +DELC int parse_creds(creds_t * creds, char const * creds_file); +DELC void clean_creds(creds_t * creds); #define CREDS_PARSER_H #endif diff --git a/include/stmt.h b/include/stmt.h new file mode 100644 index 0000000..2a8d78b --- /dev/null +++ b/include/stmt.h @@ -0,0 +1,16 @@ +static sqlite3_stmt* remind_stmt; +static const char remind_stmt_template[] = + "SELECT " + "title," + "body," + "difficulty," + "repo_link," + "trigger_date," + "started DATE," + "span" + " FROM assignment INNER JOIN project on assignment.project = project.rowid " + "WHERE who = ?;" +; + +#define stmt_prepare(stmt) \ + sqlite3_prepare_v2(connection, stmt ## _template, -1, &stmt, NULL) diff --git a/include/utils.h b/include/utils.h index 02123f8..ba703c7 100644 --- a/include/utils.h +++ b/include/utils.h @@ -1,10 +1,5 @@ #ifndef UTILS_H_ -#include - -#define ERR(ret,msg) do { fputs(msg "\n", stderr); return (ret); } while (0) -#define ERRMSG(msg) fputs(msg "\n", stderr) -#define PERROR(name) perror(name) #define UTILS_H_ #endif diff --git a/src/api.c b/src/api.c new file mode 100644 index 0000000..89d8c5c --- /dev/null +++ b/src/api.c @@ -0,0 +1,62 @@ +#include + +#include + +#include "stmt.h" +#include "irccolors.h" +#include "error.h" +#include "irc.h" + +#define DBFILE "test.sqlite" + +#define DBERR(line) do { \ + const int e = line; \ + if(e != SQLITE_OK && e != SQLITE_ROW && e != SQLITE_DONE) \ + { \ + fprintf(stderr, \ + "sqlite (%d): %s\n", \ + sqlite3_errcode(connection), sqlite3_errmsg(connection)); \ + exit(DB_ERROR); \ + } \ + } while (0) + +static sqlite3 * connection = NULL; + +DELC int +api_init(void) +{ + DBERR(sqlite3_open(DBFILE, &connection)); + stmt_prepare(remind_stmt); + return 0; +} + +DELC void +api_rope(void) +{ + DBERR(sqlite3_finalize(remind_stmt)); + sqlite3_close(connection); +} + +DELC void +rope(void) +{ + if (session) + { irc_destroy_session(session); } + api_rope(); +} + +DELC char * +remind(char * who) +{ + char * r; + char * title; + char * desc; + DBERR(sqlite3_bind_text(remind_stmt, 1, who, -1, SQLITE_STATIC)); + DBERR(sqlite3_step(remind_stmt)); + title = (char *) sqlite3_column_text(remind_stmt, 0); + title = strdup(title); + desc = (char *) sqlite3_column_text(remind_stmt, 1); + desc = strdup(desc); + asprintf(&r, IRC_COLOR_RED "%s: " IRC_COLOR_YELLOW "%s", title, desc); + return r; +} diff --git a/src/irc.c b/src/irc.c index fe7e068..140ae5e 100644 --- a/src/irc.c +++ b/src/irc.c @@ -18,8 +18,13 @@ */ -#include +#include #include +#include + +#include "irc.h" +#include "api.h" +#include "error.h" irc_session_t * session; irc_callbacks_t callbacks; @@ -71,7 +76,7 @@ event_connect(irc_session_t * session, (void) origin; (void) params; (void) count; - irc_cmd_join(session, CHANNEL, 0); + irc_cmd_join(session, channel, 0); } DELC void @@ -125,19 +130,17 @@ event_channel(irc_session_t * session, free(swp); } -DELC int +int init(char const * username, char const * server, int port) { + if(api_init()) + { ERR(DB_ERROR, "Error initializing database."); } memset(&callbacks, 0, sizeof(callbacks)); callbacks.event_connect = event_connect; callbacks.event_channel = event_channel; - session = irc_create_session(&callbacks); if (!session) { ERR(1, "Error creating IRC session"); } irc_connect(session, server, port, 0, username, username, username); - /* We should figure out how the failure happens so we can tell the user that. */ - if (irc_run(session) != 0) - { ERR(1, "Error running IRC session\nPossible issue: bad URL, no network connection, bad port, refused connection."); } return 0; } diff --git a/src/main.c b/src/main.c index 094e9cc..51b8039 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,12 @@ /* args: server port channel [username] username defaults to probotic */ + +extern void rope(void); + +/* args: server port channel [username] - defaults to probotic */ + +/* I'd have to give up constification for server:port */ int main(int argc, char const ** argv) @@ -50,8 +56,11 @@ main(int argc, #endif /* NDEBUG */ if (!init(username, server, port)) { - while(1) - {} + atexit(rope); + /* We should figure out how the failure happens so we can tell the user that. */ + if (irc_run(session) != 0) + { ERR(1, "Error running IRC session\nPossible issue: bad URL," + " no network connection, bad port, refused connection."); } irc_destroy_session(session); return 0; } diff --git a/src/unity.c b/src/unity.c index f4f411b..3d00a80 100644 --- a/src/unity.c +++ b/src/unity.c @@ -1,3 +1,5 @@ +#include "irc.c" +#include "api.c" #include "parse.c" #include "fetch.c" #include "main.c"