@@ -10,7 +10,9 @@ LDLIBS:=-lsqlite3 | |||||
LIB:=./lib/libircclient/src/libircclient.o | LIB:=./lib/libircclient/src/libircclient.o | ||||
SRC := api.c irc.c main.c parse.c unity.c | SRC := api.c irc.c main.c parse.c unity.c | ||||
HDR := api.h error.h irc.h irccolors.h parse.h stmt.h | |||||
HDR := config.h api.h error.h irc.h irccolors.h parse.h stmt.h | |||||
VPATH := src include | |||||
ifeq (${DEBUG},1) | ifeq (${DEBUG},1) | ||||
CFLAGS += -Og -ggdb | CFLAGS += -Og -ggdb | ||||
@@ -31,17 +33,20 @@ ifeq (${ENABLE_SSL},1) | |||||
CPPFLAGS += -DIRC_SSL_SUPPORT | CPPFLAGS += -DIRC_SSL_SUPPORT | ||||
endif | endif | ||||
all: ${PROGN} | |||||
all: include/config.h ${PROGN} | |||||
${PROGN}: ${HDR} ${SRC} | ${PROGN}: ${HDR} ${SRC} | ||||
${LINK.c} -pipe ${LIB} src/unity.c -o $@ ${LDLIBS} | ${LINK.c} -pipe ${LIB} src/unity.c -o $@ ${LDLIBS} | ||||
# do nothing but update them... | # do nothing but update them... | ||||
$(SRC) $(HDR): | |||||
${SRC} ${HDR}: | |||||
submodules: | submodules: | ||||
git submodule update --init --recursive | git submodule update --init --recursive | ||||
include/config.h: config.mk.h | |||||
cp -f $< $@ | |||||
clean: | clean: | ||||
-rm ${OBJ} | -rm ${OBJ} | ||||
@@ -51,4 +56,4 @@ help: | |||||
@echo " submodules" | @echo " submodules" | ||||
@echo " clean" | @echo " clean" | ||||
.PHONY: submodules clean help | |||||
.PHONY: all submodules clean help |
@@ -1,30 +0,0 @@ | |||||
#!/bin/bash | |||||
# Script handling unity builds and options. | |||||
DIR=$(dirname $(readlink -f "$0")) | |||||
cd $DIR | |||||
PROGN=${PROGN:-probotic} | |||||
PREFIX=${PREFIX:-$DIR} | |||||
CC=${CC-cc} | |||||
CFLAGS='-std=c99 -Wall -Wextra -Wpedantic -Wno-unused-function' | |||||
CPPFLAGS="-I/usr/include/libircclient/ -Iinclude -D_GNU_SOURCE -DPROGN=\"$PROGN\"" | |||||
LDFLAGS='-lircclient -lsqlite3' | |||||
mkdir -p $PREFIX && echo "Made directory: $PREFIX" | |||||
# Bourne shell is evil | |||||
if [ ${DEBUG-0} -eq 1 ] | |||||
then | |||||
CFLAGS=`echo "${CFLAGS} -O0 -ggdb"` | |||||
else | |||||
CPPFLAGS="${CPPFLAGS} -DNDEBUG" | |||||
CFLAGS=`echo "${CFLAGS} -O2 -flto=auto -fomit-frame-pointer -s"` | |||||
fi | |||||
[ ! -z ${SAN} ] && CFLAGS=`echo "$CFLAGS -fsanitize=$SAN"` | |||||
echo "$CC $CFLAGS -pipe $DIR/src/unity.c -o $PREFIX/$PROGN $CPPFLAGS $LDFLAGS" | |||||
time $CC $CFLAGS -pipe $DIR/src/unity.c -o $PREFIX/$PROGN $CPPFLAGS $LDFLAGS | |||||
echo -e "\nStatus: $?" |
@@ -1,12 +0,0 @@ | |||||
#ifndef API_H_ | |||||
VARDECL char const * db; | |||||
DECL int api_init(void); | |||||
DECL void api_rope(void); | |||||
DECL void rope(void); | |||||
DECL char * remind(char * who); | |||||
/* DECL int is_no_assignment(char const * const who); */ | |||||
#define API_H_ | |||||
#endif |
@@ -0,0 +1 @@ | |||||
#define DBFILE "probotic_data.sqlite" |
@@ -1,7 +1,3 @@ | |||||
#ifndef ERROR_H_ | |||||
#include <stdio.h> | |||||
#define ERR(ret,msg) \ | #define ERR(ret,msg) \ | ||||
do { fputs(PROGN ": " msg "\n", stderr); return (ret); } while (0) | do { fputs(PROGN ": " msg "\n", stderr); return (ret); } while (0) | ||||
@@ -17,6 +13,3 @@ | |||||
#define DB_ERROR 100 | #define DB_ERROR 100 | ||||
#define IRC_ERROR 101 | #define IRC_ERROR 101 | ||||
#define CREDS_ERROR 102 | #define CREDS_ERROR 102 | ||||
#define ERROR_H_ | |||||
#endif |
@@ -1,22 +0,0 @@ | |||||
#ifndef FREE_H_ | |||||
#define FREE(obj) \ | |||||
do \ | |||||
{ \ | |||||
free(obj); \ | |||||
(obj) = NULL; \ | |||||
} while (0) | |||||
#define FULL_FREE(obj) \ | |||||
do \ | |||||
{ \ | |||||
if ((obj)) \ | |||||
{ \ | |||||
memset((obj), '\0', strlen((obj))); \ | |||||
FREE((obj)); \ | |||||
} \ | |||||
} while (0) | |||||
#define FREE_H_ | |||||
#endif |
@@ -1,6 +0,0 @@ | |||||
#ifndef HELP_H_ | |||||
VARDECL char const * help_msg; | |||||
#define HELP_H_ | |||||
#endif |
@@ -1,14 +0,0 @@ | |||||
#ifndef IRC_H_ | |||||
#include <libircclient.h> | |||||
#include "parse.h" | |||||
VARDECL irc_session_t * session; | |||||
VARDECL irc_callbacks_t callbacks; | |||||
VARDECL char * current_username; | |||||
DECL int init(void); | |||||
#define IRC_H_ | |||||
#endif |
@@ -1,5 +1,3 @@ | |||||
#ifndef IRCCOLOR_H_ | |||||
// Formatting macros | // Formatting macros | ||||
#define IRC_BOLD "[B]" | #define IRC_BOLD "[B]" | ||||
#define IRC_ITALIC "[I]" | #define IRC_ITALIC "[I]" | ||||
@@ -22,6 +20,3 @@ | |||||
#define IRC_DARKGRAY "[COLOR=DARKGRAY]" | #define IRC_DARKGRAY "[COLOR=DARKGRAY]" | ||||
#define IRC_LIGHTGRAY "[COLOR=LIGHTGRAY]" | #define IRC_LIGHTGRAY "[COLOR=LIGHTGRAY]" | ||||
#define IRC_STOP "[/COLOR]" | #define IRC_STOP "[/COLOR]" | ||||
#define IRCCOLOR_H_ | |||||
#endif |
@@ -1,32 +0,0 @@ | |||||
#ifndef CREDS_PARSER_H | |||||
typedef struct | |||||
{ | |||||
char * username; | |||||
char * password; | |||||
char * channel; | |||||
char * server; | |||||
int port; | |||||
} creds_t; | |||||
VARDECL creds_t creds; | |||||
/* nickserv identify password */ | |||||
VARDECL char * ident_password = NULL; | |||||
/* DECL char ** str_split(char const * s, char c); */ | |||||
/* DECL void split_clean(char ** split); */ | |||||
/* DECL int is_admin(char const * user); */ | |||||
#ifndef NO_VULN_COMMANDS | |||||
DECL char * dump(void); | |||||
DECL char * raw(char const * const sql); | |||||
#endif /* !NO_VULN_COMMANDS */ | |||||
DECL char * remind(char * who); | |||||
DECL void creds_free(void); | |||||
DECL void parse_command(char const * const cmd); | |||||
DECL void purge_assignments(char const * const who); | |||||
DECL void random_assign(char const * const sql); | |||||
DECL void set_repo(char const * const who, char const * const link); | |||||
#define CREDS_PARSER_H | |||||
#endif |
@@ -1,13 +1,20 @@ | |||||
#!/bin/sh | #!/bin/sh | ||||
echo "./uninstall.sh will destroy to whatever TARGET is set to, be careful!" | |||||
# VARIABLES AND PATH | |||||
TARGET=${TARGET-/opt/probotic} | |||||
DIR=$(dirname $(readlink -f "$0")) | DIR=$(dirname $(readlink -f "$0")) | ||||
cd $DIR | cd $DIR | ||||
[ ! -e $DIR/probotic ] && make DEBUG=0 NVULN=1 || return 1 | |||||
# run bootstrapper | |||||
[ ! -e $DIR/bootstrap/ ] && $DIR/bootstrap/bootstrap.sh || return 1 | |||||
# generate directories and install | |||||
TARGET=${TARGET-/opt/probotic} | |||||
useradd probotic -r -s /sbin/nologin -d $TARGET | |||||
# BUILD & BOOTSTRAP | |||||
make -C $DIR DEBUG=0 NVULN=1 || exit 1 | |||||
$DIR/bootstrap/bootstrap.sh || exit 1 | |||||
# INSTALL | |||||
mkdir -p $TARGET | mkdir -p $TARGET | ||||
install -g probotic -o probotic -m 744 \ | |||||
$DIR/bootstrap/probotic_data.sqlite probotic -v $TARGET | |||||
useradd probotic -r -s /sbin/nologin -d $TARGET | |||||
install -v -g probotic -o probotic -m 744 \ | |||||
$DIR/bootstrap/probotic_data.sqlite probotic \ | |||||
$TARGET | |||||
chown probotic:probotic $TARGET -R | chown probotic:probotic $TARGET -R |
@@ -1,6 +1,6 @@ | |||||
#define DBFILE "probotic_data.sqlite" | |||||
/* api.c - Database API */ | |||||
#define stmt_prepare(stmt) \ | |||||
#define stmt_prepare(stmt) \ | |||||
sqlite3_prepare_v2(connection, stmt ## _template, -1, &stmt, NULL) | sqlite3_prepare_v2(connection, stmt ## _template, -1, &stmt, NULL) | ||||
VARDECL char const * db = DBFILE; | VARDECL char const * db = DBFILE; | ||||
@@ -9,25 +9,25 @@ VARDECL sqlite3 * connection = NULL; | |||||
DECL void DBERR(const int l) | DECL void DBERR(const int l) | ||||
{ | { | ||||
if(l != SQLITE_OK && l != SQLITE_ROW && l != SQLITE_DONE) | |||||
{ | |||||
fprintf(stderr, | |||||
"sqlite (%d): %s\n", | |||||
sqlite3_errcode(connection), sqlite3_errmsg(connection)); | |||||
exit(DB_ERROR); | |||||
} | |||||
if(l != SQLITE_OK && l != SQLITE_ROW && l != SQLITE_DONE) | |||||
{ | |||||
fprintf(stderr, | |||||
"sqlite (%d): %s\n", | |||||
sqlite3_errcode(connection), sqlite3_errmsg(connection)); | |||||
exit(DB_ERROR); | |||||
} | |||||
} | } | ||||
DECL int | DECL int | ||||
api_init(void) | api_init(void) | ||||
{ | { | ||||
DBERR(sqlite3_open_v2(db, &connection, SQLITE_OPEN_READWRITE, NULL)); | DBERR(sqlite3_open_v2(db, &connection, SQLITE_OPEN_READWRITE, NULL)); | ||||
// dont you fucking dare to remove this spacing | |||||
/* dont you fucking dare to remove this spacing */ | |||||
DBERR(stmt_prepare(remind_stmt)); | DBERR(stmt_prepare(remind_stmt)); | ||||
DBERR(stmt_prepare(set_repo_stmt)); | DBERR(stmt_prepare(set_repo_stmt)); | ||||
DBERR(stmt_prepare(get_nth_id_stmt)); | DBERR(stmt_prepare(get_nth_id_stmt)); | ||||
DBERR(stmt_prepare(new_assignment_stmt)); | |||||
DBERR(stmt_prepare(purge_assignments_stmt)); | |||||
DBERR(stmt_prepare(new_assignment_stmt)); | |||||
DBERR(stmt_prepare(purge_assignments_stmt)); | |||||
DBERR(stmt_prepare(is_no_assignment_stmt)); | DBERR(stmt_prepare(is_no_assignment_stmt)); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -44,21 +44,13 @@ api_rope(void) | |||||
sqlite3_close(connection); | sqlite3_close(connection); | ||||
} | } | ||||
DECL void | |||||
rope(void) | |||||
{ | |||||
if (session) | |||||
{ irc_destroy_session(session); } | |||||
api_rope(); | |||||
} | |||||
DECL char * | DECL char * | ||||
remind(char * who) | remind(char * who) | ||||
{ | { | ||||
char * r; | char * r; | ||||
char * title; | char * title; | ||||
char * desc; | char * desc; | ||||
char * repo; | |||||
/* char * repo; */ | |||||
DBERR(sqlite3_reset(remind_stmt)); | DBERR(sqlite3_reset(remind_stmt)); | ||||
DBERR(sqlite3_bind_text(remind_stmt, 1, who, -1, SQLITE_STATIC)); | DBERR(sqlite3_bind_text(remind_stmt, 1, who, -1, SQLITE_STATIC)); | ||||
const int i = sqlite3_step(remind_stmt); | const int i = sqlite3_step(remind_stmt); | ||||
@@ -69,20 +61,24 @@ remind(char * who) | |||||
title = strdup(title); | title = strdup(title); | ||||
desc = (char *) sqlite3_column_text(remind_stmt, 1); | desc = (char *) sqlite3_column_text(remind_stmt, 1); | ||||
if (desc) { desc = strdup(desc); } else { desc = ""; } | if (desc) { desc = strdup(desc); } else { desc = ""; } | ||||
repo = (char *) sqlite3_column_text(remind_stmt, 3); | |||||
if (repo) { repo = strdup(repo); } else { repo = "<no link available>"; } | |||||
if (-1 == asprintf(&r, | |||||
IRC_RED "%s: " IRC_YELLOW "%s" IRC_GREEN | |||||
" (@" IRC_BLUE "%s" IRC_GREEN ")" IRC_STOP, | |||||
title, desc, repo)) | |||||
/* repo = (char *) sqlite3_column_text(remind_stmt, 3); */ | |||||
/* if (repo) { repo = strdup(repo); } else { repo = "<no link available>"; } */ | |||||
/* if (-1 == asprintf(&r, */ | |||||
/* IRC_RED "%s: " IRC_YELLOW "%s" IRC_GREEN */ | |||||
/* " (@" IRC_BLUE "%s" IRC_GREEN ")" IRC_STOP, */ | |||||
/* title, desc, repo)) */ | |||||
if (-1 == asprintf(&r, | |||||
IRC_RED "%s: " IRC_YELLOW "%s" IRC_GREEN, | |||||
title, desc)) | |||||
{ /* this will probably never happen. But it implies a memory failure */ | { /* this will probably never happen. But it implies a memory failure */ | ||||
r = strdup(IRC_RED "No memory!" IRC_STOP); } | |||||
} | |||||
else | |||||
{ | |||||
r = strdup(IRC_RED "No current assignment." IRC_STOP); | |||||
} | |||||
return r; | |||||
r = strdup(IRC_RED "No memory!" IRC_STOP); | |||||
} | |||||
else | |||||
{ | |||||
r = strdup(IRC_RED "No current assignment." IRC_STOP); | |||||
} | |||||
} | |||||
return r; | |||||
} | } | ||||
DECL void | DECL void | ||||
@@ -129,14 +125,14 @@ rtos(void * data, | |||||
*r = (char *)calloc(data_len, sizeof(char)); | *r = (char *)calloc(data_len, sizeof(char)); | ||||
for(int i = 0; i < argc; i++){ | for(int i = 0; i < argc; i++){ | ||||
strcat(*r, "|"); | |||||
if(argv[i]){ | |||||
strcat(*r, argv[i]); | |||||
} | |||||
else | |||||
{ | |||||
strcat(*r, "NULL"); | |||||
} | |||||
strcat(*r, "|"); | |||||
if(argv[i]){ | |||||
strcat(*r, argv[i]); | |||||
} | |||||
else | |||||
{ | |||||
strcat(*r, "NULL"); | |||||
} | |||||
} | } | ||||
strcat(*r, "|\n"); | strcat(*r, "|\n"); | ||||
@@ -164,7 +160,7 @@ raw(char const * const sql) | |||||
if (errmsg){ | if (errmsg){ | ||||
free(r); | free(r); | ||||
r = errmsg; | |||||
r = errmsg; | |||||
} else { strcat(r, "\00"); } | } else { strcat(r, "\00"); } | ||||
return r; | return r; | ||||
} | } | ||||
@@ -176,40 +172,39 @@ get_project_count_callback(void* data, int argc, char** argv, char** colname) | |||||
{ | { | ||||
(void)argc; | (void)argc; | ||||
(void)colname; | (void)colname; | ||||
int* count = (int*)data; | |||||
*count = atoi(argv[0]); | |||||
return 0; | |||||
int* count = (int*)data; | |||||
*count = atoi(argv[0]); | |||||
return 0; | |||||
} | } | ||||
DECL int | DECL int | ||||
get_project_count() | |||||
get_project_count(void) | |||||
{ | { | ||||
int r = 0; | |||||
char const * sql = "SELECT COUNT(*) FROM project;"; | |||||
DBERR(sqlite3_exec(connection, sql, get_project_count_callback, &r, NULL)); | |||||
return r; | |||||
int r = 0; | |||||
char const * sql = "SELECT COUNT(*) FROM project;"; | |||||
DBERR(sqlite3_exec(connection, sql, get_project_count_callback, &r, NULL)); | |||||
return r; | |||||
} | } | ||||
DECL int | DECL int | ||||
get_nth_id(const int i) | get_nth_id(const int i) | ||||
{ | { | ||||
int r; | |||||
DBERR(sqlite3_reset(get_nth_id_stmt)); | |||||
DBERR(sqlite3_bind_int(get_nth_id_stmt, 1, i)); | |||||
DBERR(sqlite3_step(get_nth_id_stmt)); | |||||
r = sqlite3_column_int(get_nth_id_stmt, 0); | |||||
return r; | |||||
int r; | |||||
DBERR(sqlite3_reset(get_nth_id_stmt)); | |||||
DBERR(sqlite3_bind_int(get_nth_id_stmt, 1, i)); | |||||
DBERR(sqlite3_step(get_nth_id_stmt)); | |||||
r = sqlite3_column_int(get_nth_id_stmt, 0); | |||||
return r; | |||||
} | } | ||||
DECL void | DECL void | ||||
new_assignment(char const * const who, const int project) | |||||
new_assignment(char const * const who, | |||||
int const project) | |||||
{ | { | ||||
DBERR(sqlite3_reset(new_assignment_stmt)); | |||||
DBERR(sqlite3_bind_text(new_assignment_stmt, 1, who, -1, SQLITE_STATIC)); | |||||
DBERR(sqlite3_bind_int(new_assignment_stmt, 2, project)); | |||||
DBERR(sqlite3_step(new_assignment_stmt)); | |||||
DBERR(sqlite3_reset(new_assignment_stmt)); | |||||
DBERR(sqlite3_bind_text(new_assignment_stmt, 1, who, -1, SQLITE_STATIC)); | |||||
DBERR(sqlite3_bind_int(new_assignment_stmt, 2, project)); | |||||
DBERR(sqlite3_step(new_assignment_stmt)); | |||||
} | } | ||||
DECL void | DECL void | ||||
@@ -233,9 +228,10 @@ purge_assignments(char const * const who) | |||||
DECL int | DECL int | ||||
is_no_assignment(char const * const who) | is_no_assignment(char const * const who) | ||||
{ | { | ||||
const int e; | |||||
DBERR(sqlite3_reset(is_no_assignment_stmt)); | DBERR(sqlite3_reset(is_no_assignment_stmt)); | ||||
DBERR(sqlite3_bind_text(is_no_assignment_stmt, 1, who, -1, SQLITE_STATIC)); | DBERR(sqlite3_bind_text(is_no_assignment_stmt, 1, who, -1, SQLITE_STATIC)); | ||||
const int e = sqlite3_step(is_no_assignment_stmt); | |||||
e = sqlite3_step(is_no_assignment_stmt); | |||||
DBERR(e); | DBERR(e); | ||||
return (e == SQLITE_DONE); | return (e == SQLITE_DONE); | ||||
} | } | ||||
@@ -1,18 +1,48 @@ | |||||
/* irc.c - IRC interface | |||||
/* irc.c - IRC interface */ | |||||
#define FULL_FREE(obj) \ | |||||
do \ | |||||
{ \ | |||||
if ((obj)) \ | |||||
{ \ | |||||
memset((obj), '\0', strlen((obj))); \ | |||||
free((obj)); \ | |||||
(obj) = NULL; \ | |||||
} \ | |||||
} while (0) | |||||
Probotic is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License version 3 only as | |||||
published by the Free Software Foundation. | |||||
#define PREFIX_COMMAND_CHAR '!' | |||||
Probotic 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 General Public License version 3 for more details. | |||||
#define IRCMSG(msg) irc_cmd_msg(session, creds.channel, msg) | |||||
You should have received a copy of the GNU General Public License | |||||
version 3 along with Probotic. | |||||
typedef struct | |||||
{ | |||||
char * username; | |||||
char * password; | |||||
char * channel; | |||||
char * server; | |||||
int port; | |||||
} creds_t; | |||||
VARDECL creds_t creds = | |||||
{ | |||||
.username = NULL, | |||||
.password = NULL, | |||||
.channel = NULL, | |||||
.server = NULL, /* localhost? */ | |||||
#ifndef IRC_SSL_SUPPORT | |||||
.port = 6667 | |||||
#else | |||||
.port = 6669 | |||||
#endif /* !IRC_SSL_SUPPORT */ | |||||
}; | |||||
VARDECL char * ident_password = NULL; | |||||
*/ | |||||
VARDECL irc_session_t * session; | |||||
VARDECL irc_callbacks_t callbacks; | |||||
VARDECL char * current_username = NULL; | |||||
VARDECL char const * help_msg = | VARDECL char const * help_msg = | ||||
/* IRC_GREEN "!help " IRC_STOP " : This message\n" */ | /* IRC_GREEN "!help " IRC_STOP " : This message\n" */ | ||||
@@ -24,15 +54,7 @@ IRC_GREEN "!reroll " IRC_STOP " : Rerolls assignment\n" | |||||
IRC_GREEN "!request " IRC_STOP " : Request personal project\n" | IRC_GREEN "!request " IRC_STOP " : Request personal project\n" | ||||
IRC_GREEN "!remind " IRC_STOP " : Prints your assignment\n"; | IRC_GREEN "!remind " IRC_STOP " : Prints your assignment\n"; | ||||
#define PREFIX_COMMAND_CHAR '!' | |||||
#define PREFIX_CHANNEL_COMMAND_CHAR '%' | |||||
VARDECL irc_session_t * session; | |||||
VARDECL irc_callbacks_t callbacks; | |||||
VARDECL char * current_username = NULL; | |||||
#define IRCMSG(msg) irc_cmd_msg(session, creds.channel, msg) | |||||
DECL void parse_command(char const * cmd); | |||||
DECL char * | DECL char * | ||||
get_username(const char * origin) | get_username(const char * origin) | ||||
@@ -127,15 +149,8 @@ event_channel(irc_session_t * lsession, | |||||
(void) message; | (void) message; | ||||
(void) count; | (void) count; | ||||
/* parses the command */ | /* parses the command */ | ||||
switch(*message) | |||||
{ | |||||
case PREFIX_CHANNEL_COMMAND_CHAR: | |||||
current_username = strdup(creds.channel); | |||||
break; | |||||
case PREFIX_COMMAND_CHAR: | |||||
current_username = get_username(origin); | |||||
break; | |||||
} | |||||
if (*message == PREFIX_COMMAND_CHAR) | |||||
{ current_username = get_username(origin); } | |||||
if (!current_username || | if (!current_username || | ||||
message[1] == '\0') | message[1] == '\0') | ||||
{ return; } | { return; } | ||||
@@ -144,44 +159,88 @@ event_channel(irc_session_t * lsession, | |||||
current_username = NULL; | current_username = NULL; | ||||
} | } | ||||
/* 'abc' SINGLE | |||||
'def ' SINGLE | |||||
'ghi jkl' MULTI */ | |||||
DECL int | DECL int | ||||
init(void) | |||||
has_arg(char const * cmd) | |||||
{ | { | ||||
srand(time(NULL)); | |||||
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) | |||||
while (isalnum(*cmd)) | |||||
{ | { | ||||
ERRMSG("Error creating IRC session"); | |||||
goto fail; | |||||
if (*cmd == '\0') | |||||
{ break; } | |||||
++cmd; | |||||
} | } | ||||
atexit(rope); | |||||
assert(creds.username != NULL); | |||||
assert(creds.server != NULL); | |||||
if (irc_connect(session, | |||||
creds.server, creds.port, creds.password, | |||||
creds.username, creds.username, creds.username)) | |||||
while (*cmd != '\0') | |||||
{ | { | ||||
fprintf(stderr, "IRC ERROR: %s\n", irc_strerror(irc_errno(session))); | |||||
exit(1); | |||||
if (!isspace(*(++cmd))) | |||||
{ return 1; } | |||||
} | } | ||||
FULL_FREE(creds.password); | |||||
return 0; | return 0; | ||||
fail: | |||||
FULL_FREE(creds.password); | |||||
return 1; | |||||
} | } | ||||
DECL int | |||||
loop(void) | |||||
DECL void | |||||
parse_command(char const * cmd) | |||||
{ | { | ||||
/* 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; | |||||
size_t i = 0; | |||||
char* msgswp = NULL; | |||||
/* size_t len = strlen(cmd); */ | |||||
if ((i += has_arg(cmd))) | |||||
{ | |||||
/* NO ARGUMENTS */ | |||||
if (strcmp(cmd, "remind") == 0) | |||||
{ | |||||
msgswp = remind(current_username); | |||||
ircmsg(creds.channel, "%s: %s", current_username, msgswp); | |||||
} | |||||
else if (strcmp(cmd, "help") == 0) | |||||
{ ircmsg(creds.channel, help_msg); } | |||||
else if (strcmp(cmd, "magic") == 0) | |||||
{ ircmsg(creds.channel, "%s: " IRC_YELLOW "%d" IRC_STOP, current_username, (rand() % 100) + 1); } | |||||
#ifndef NO_VULN_COMMANDS | |||||
else if (strcmp(cmd, "dump") == 0) | |||||
{ | |||||
ircmsg(creds.channel, "%s: All projects:", current_username); | |||||
msgswp = dump(); | |||||
ircmsg(creds.channel, msgswp); | |||||
} | |||||
#endif /* !NO_VULN_COMMANDS */ | |||||
else if (strcmp(cmd, "reroll") == 0) | |||||
{ | |||||
purge_assignments(current_username); | |||||
random_assign(current_username); | |||||
ircmsg(creds.channel, "%s: %s", current_username, remind(current_username)); | |||||
} | |||||
} | |||||
else /* HAS ARGUMENTS */ | |||||
{ | |||||
char const * const arg = cmd + i + 1; | |||||
#ifndef NO_VULN_COMMANDS | |||||
if (strncmp(cmd, "raw", i) == 0) | |||||
{ | |||||
/* ircmsg(creds.channel, "%s: Executing SQL `%s'.", current_username, arg); */ | |||||
msgswp = raw(arg); | |||||
ircmsg(creds.channel, msgswp); | |||||
} else | |||||
#endif /* !NO_VULN_COMMANDS */ | |||||
if (strncmp(cmd, "repo", i) == 0) | |||||
{ | |||||
/* ircmsg(creds.channel, "%s: Setting project repository...", current_username); */ | |||||
set_repo(creds.channel, arg); | |||||
msgswp = remind(creds.channel); | |||||
ircmsg(creds.channel, "%s: %s", current_username, msgswp); | |||||
} | |||||
} | |||||
free(msgswp); | |||||
} | |||||
DECL void | |||||
creds_free(void) | |||||
{ | |||||
FULL_FREE(creds.username); | |||||
FULL_FREE(creds.password); | |||||
FULL_FREE(creds.channel); | |||||
FULL_FREE(creds.server); | |||||
} | } |
@@ -1,20 +1,105 @@ | |||||
/* main.c | |||||
/* main.c */ | |||||
Probotic is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License version 3 only as | |||||
published by the Free Software Foundation. | |||||
#define VERSION_STRING "1" | |||||
/* Parses the format username[:password]@server[:port] */ | |||||
Probotic 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 General Public License version 3 for more details. | |||||
#define GENCOPY(dst,src,l) \ | |||||
do \ | |||||
{ \ | |||||
dst = malloc(sep + 1); \ | |||||
if (dst) \ | |||||
{ \ | |||||
strncpy(dst,src,l); \ | |||||
dst[len] = '\0'; \ | |||||
} \ | |||||
else \ | |||||
{ return 1; } \ | |||||
} while (0) | |||||
You should have received a copy of the GNU General Public License | |||||
version 3 along with Probotic. | |||||
DECL int | |||||
parse_url(char const * url) | |||||
{ | |||||
size_t len = strlen(url); | |||||
size_t sep = 0, ls = 0, rs; | |||||
while (++sep < len && url[sep] != '@'); | |||||
while (++ls < len && url[ls] != ':') | |||||
{ | |||||
if (ls >= sep) | |||||
{ ls = 0; break; } | |||||
} | |||||
rs = sep; | |||||
while (++rs < len && url[rs] != ':'); | |||||
if (rs == len) | |||||
{ rs = 0; } | |||||
GENCOPY(creds.username, url, ls ? ls : sep); | |||||
if (ls) | |||||
{ | |||||
GENCOPY(creds.password, url + ls + 1, sep - ls - 1); | |||||
} | |||||
if (rs) | |||||
{ | |||||
GENCOPY(creds.server, url + sep + 1, rs - sep - 1); | |||||
creds.port = atoi(url + rs + 1); | |||||
} | |||||
else | |||||
{ | |||||
GENCOPY(creds.server, url + sep + 1, len - sep - 1); | |||||
} | |||||
return 0; | |||||
} | |||||
*/ | |||||
#undef GENCOPY | |||||
#define VERSION_STRING "1" | |||||
DECL void | |||||
rope(void) | |||||
{ | |||||
if (session) | |||||
{ irc_destroy_session(session); } | |||||
api_rope(); | |||||
} | |||||
DECL int | |||||
init(void) | |||||
{ | |||||
srand(time(NULL)); | |||||
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) | |||||
{ | |||||
ERRMSG("Error creating IRC session"); | |||||
goto fail; | |||||
} | |||||
atexit(rope); | |||||
assert(creds.username != NULL); | |||||
assert(creds.server != NULL); | |||||
if (irc_connect(session, | |||||
creds.server, creds.port, creds.password, | |||||
creds.username, creds.username, creds.username)) | |||||
{ | |||||
fprintf(stderr, "IRC ERROR: %s\n", irc_strerror(irc_errno(session))); | |||||
exit(1); | |||||
} | |||||
FULL_FREE(creds.password); | |||||
return 0; | |||||
fail: | |||||
FULL_FREE(creds.password); | |||||
return 1; | |||||
} | |||||
DECL int | |||||
loop(void) | |||||
{ | |||||
/* 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; | |||||
} | |||||
DECL void | DECL void | ||||
help(void) | help(void) | ||||
@@ -24,6 +109,8 @@ help(void) | |||||
"-url URL - Sets the target URL\n" | "-url URL - Sets the target URL\n" | ||||
"-db DBFILE - Sets the database file (default: probotic_data.sqlite)\n" | "-db DBFILE - Sets the database file (default: probotic_data.sqlite)\n" | ||||
"-identify PASSWORD - Identifies against NickServ\n" | "-identify PASSWORD - Identifies against NickServ\n" | ||||
"-version - Prints Version information\n" | |||||
"-help - Prints this information\n" | |||||
"\nUse format username[:password]@server[:port], port defaults to 6667.\n"); | "\nUse format username[:password]@server[:port], port defaults to 6667.\n"); | ||||
} | } | ||||
@@ -54,7 +141,7 @@ main (int argc, | |||||
else if (strcmp(arg, "help") == 0) | else if (strcmp(arg, "help") == 0) | ||||
{ goto help; } | { goto help; } | ||||
if (argc < 2) | if (argc < 2) | ||||
{ goto nop; } | |||||
{ goto help; } | |||||
if (strcmp(arg, "db") == 0) | if (strcmp(arg, "db") == 0) | ||||
{ db = argv[1]; } | { db = argv[1]; } | ||||
else if (strcmp(arg, "url") == 0) | else if (strcmp(arg, "url") == 0) | ||||
@@ -70,7 +157,7 @@ main (int argc, | |||||
++argv; --argc; | ++argv; --argc; | ||||
} | } | ||||
else | else | ||||
{ nop: ERRFMT(1, "Oprand without option '%s'", arg); } | |||||
{ goto help; } | |||||
} | } | ||||
} | } | ||||
atexit(creds_free); | atexit(creds_free); | ||||
@@ -1,223 +0,0 @@ | |||||
/* parse.c | |||||
Probotic is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License version 3 only as | |||||
published by the Free Software Foundation. | |||||
Probotic 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 General Public License version 3 for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
version 3 along with Probotic. | |||||
*/ | |||||
#define PARAMS_COUNT 6 | |||||
VARDECL creds_t creds = | |||||
{ | |||||
.username = NULL, | |||||
.password = NULL, | |||||
.channel = NULL, | |||||
.server = NULL, /* localhost? */ | |||||
#ifndef IRC_SSL_SUPPORT | |||||
.port = 6667 | |||||
#else | |||||
.port = 6669 | |||||
#endif /* IRC_SSL_SUPPORT */ | |||||
}; | |||||
#if 0 | |||||
DECL char ** | |||||
str_split(char const * s, char c) | |||||
{ | |||||
char ** ret = NULL; | |||||
size_t i = 0; | |||||
size_t current_token_i = 0; | |||||
size_t token_start_i = 0; | |||||
size_t tokens_q = 0; | |||||
/* count tokens */ | |||||
for (i = 1; s[i]; ++i) | |||||
{ | |||||
/* end of a token*/ | |||||
if (s[i] == c && s[i - 1] != c) | |||||
{ ++tokens_q; } | |||||
} | |||||
++tokens_q; | |||||
ret = (char **)calloc(tokens_q + 1, sizeof(char *)); | |||||
if (!ret) | |||||
{ return ret; } | |||||
for (i = 1; s[i]; ++i) | |||||
{ | |||||
if ((s[i + 1] == c || !s[i + 1]) && s[i] != c) | |||||
{ | |||||
/* end of a token*/ | |||||
ret[current_token_i] = strndup(s + token_start_i, i - token_start_i + 1); | |||||
if (!ret[current_token_i]) | |||||
{ | |||||
split_clean(ret); | |||||
return NULL; | |||||
} | |||||
++current_token_i; | |||||
} | |||||
else if (s[i] != c && s[i - 1] == c) | |||||
{ | |||||
/* start of a token */ | |||||
token_start_i = i; | |||||
} | |||||
} | |||||
/* Signal that the split array is ended (for iteration purposes) */ | |||||
ret[current_token_i + 1] = NULL; | |||||
return ret; | |||||
} | |||||
DECL void | |||||
split_clean(char ** split) | |||||
{ | |||||
while (*split) | |||||
{ | |||||
free(*split); | |||||
} | |||||
free(split); | |||||
} | |||||
#endif /* 0 */ | |||||
DECL void | |||||
parse_command(char const * cmd) | |||||
{ | |||||
size_t i = 0; | |||||
char* msgswp = NULL; | |||||
/* size_t len = strlen(cmd); */ | |||||
/* TODO does not handle commands with leading space, | |||||
use custom implemented to-spec isspace implementation */ | |||||
while (cmd[i] != '\0' && | |||||
cmd[i] != ' ') | |||||
{ ++i; } | |||||
if (cmd[i] == '\0') | |||||
{ | |||||
/* no arguments */ | |||||
#ifndef NO_VULN_COMMANDS | |||||
if (strcmp(cmd, "kill") == 0) | |||||
{ exit(1); } | |||||
#endif /* !NO_VULN_COMMANDS */ | |||||
if (strcmp(cmd, "remind") == 0) | |||||
{ | |||||
msgswp = remind(current_username); | |||||
ircmsg(creds.channel, "%s: %s", current_username, msgswp); | |||||
} | |||||
else if (strcmp(cmd, "help") == 0) | |||||
{ ircmsg(creds.channel, help_msg); } | |||||
else if (strcmp(cmd, "magic") == 0) | |||||
{ ircmsg(creds.channel, "%s: " IRC_YELLOW "%d" IRC_STOP, current_username, (rand() % 100) + 1); } | |||||
else if (strcmp(cmd, "dump") == 0) | |||||
{ | |||||
#ifndef NO_VULN_COMMANDS | |||||
ircmsg(creds.channel, "%s: All projects:", current_username); | |||||
msgswp = dump(); | |||||
ircmsg(creds.channel, msgswp); | |||||
#else | |||||
ircmsg(creds.channel, "%s: dump disabled", current_username); | |||||
#endif /* !NO_VULN_COMMANDS */ | |||||
} | |||||
else if (strcmp(cmd, "reroll") == 0) | |||||
{ | |||||
/* ircmsg(creds.channel, "%s: Rerolling...", current_username); */ | |||||
purge_assignments(current_username); | |||||
random_assign(current_username); | |||||
ircmsg(creds.channel, "%s: %s", current_username, remind(current_username)); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
/* some arguments */ | |||||
char const * const arg = cmd + i + 1; | |||||
if (strncmp(cmd, "raw", i) == 0) | |||||
{ | |||||
#ifndef NO_VULN_COMMANDS | |||||
/* ircmsg(creds.channel, "%s: Executing SQL `%s'.", current_username, arg); */ | |||||
msgswp = raw(arg); | |||||
ircmsg(creds.channel, msgswp); | |||||
#else | |||||
ircmsg(creds.channel, "%s: raw disabled", current_username); | |||||
#endif /* !NO_VULN_COMMANDS */ | |||||
} | |||||
else if (strncmp(cmd, "repo", i) == 0) | |||||
{ | |||||
/* ircmsg(creds.channel, "%s: Setting project repository...", current_username); */ | |||||
set_repo(creds.channel, arg); | |||||
msgswp = remind(creds.channel); | |||||
ircmsg(creds.channel, "%s: %s", current_username, msgswp); | |||||
} | |||||
} | |||||
free(msgswp); | |||||
} | |||||
/* Parses the format username[:password]@server[:port] */ | |||||
#define GENCOPY(dst,src,l) \ | |||||
do \ | |||||
{ \ | |||||
dst = malloc(sep + 1); \ | |||||
if (dst) \ | |||||
{ \ | |||||
strncpy(dst,src,l); \ | |||||
dst[len] = '\0'; \ | |||||
} \ | |||||
else \ | |||||
{ return 1; } \ | |||||
} while (0) | |||||
DECL int | |||||
parse_url(char const * url) | |||||
{ | |||||
size_t len = strlen(url); | |||||
size_t sep = 0, ls = 0, rs; | |||||
while (++sep < len && url[sep] != '@'); | |||||
while (++ls < len && url[ls] != ':') | |||||
{ | |||||
if (ls >= sep) | |||||
{ ls = 0; break; } | |||||
} | |||||
rs = sep; | |||||
while (++rs < len && url[rs] != ':'); | |||||
if (rs == len) | |||||
{ rs = 0; } | |||||
GENCOPY(creds.username, url, ls ? ls : sep); | |||||
if (ls) | |||||
{ | |||||
GENCOPY(creds.password, url + ls + 1, sep - ls - 1); | |||||
} | |||||
if (rs) | |||||
{ | |||||
GENCOPY(creds.server, url + sep + 1, rs - sep - 1); | |||||
creds.port = atoi(url + rs + 1); | |||||
} | |||||
else | |||||
{ | |||||
GENCOPY(creds.server, url + sep + 1, len - sep - 1); | |||||
} | |||||
return 0; | |||||
} | |||||
DECL void | |||||
creds_free(void) | |||||
{ | |||||
FULL_FREE(creds.username); | |||||
FULL_FREE(creds.password); | |||||
FULL_FREE(creds.channel); | |||||
FULL_FREE(creds.server); | |||||
} |
@@ -1,3 +1,5 @@ | |||||
/* stmt.c */ | |||||
VARDECL sqlite3_stmt * remind_stmt; | VARDECL sqlite3_stmt * remind_stmt; | ||||
VARDECL char const remind_stmt_template[] = | VARDECL char const remind_stmt_template[] = | ||||
"SELECT " | "SELECT " |
@@ -7,19 +7,16 @@ | |||||
#include <string.h> | #include <string.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <ctype.h> | |||||
#include <libircclient.h> | |||||
#include <sqlite3.h> | #include <sqlite3.h> | ||||
#include "api.h" | |||||
#include "error.h" | #include "error.h" | ||||
#include "free.h" | |||||
#include "help.h" | |||||
#include "irc.h" | |||||
#include "irccolors.h" | #include "irccolors.h" | ||||
#include "parse.h" | |||||
#include "config.h" | |||||
#include "sql_stmt.c" | |||||
#include "irc.c" | |||||
#include "parse.c" | |||||
#include "stmt.c" | |||||
#include "api.c" | #include "api.c" | ||||
#include "irc.c" | |||||
#include "main.c" | #include "main.c" |
@@ -1,7 +1,2 @@ | |||||
#!/bin/sh | #!/bin/sh | ||||
# doubles as a cleanup script | |||||
DIR=$(dirname $(readlink -f "$0")) | |||||
cd $DIR | |||||
TARGET=${TARGET-/opt/probotic} | |||||
userdel probotic | |||||
rm -rf $TARGET | |||||
userdel -rf probotic |