@@ -9,7 +9,9 @@ LDLIBS:=-lsqlite3 | |||
LIB:=./lib/libircclient/src/libircclient.o | |||
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) | |||
CFLAGS += -Og -ggdb | |||
@@ -30,18 +32,21 @@ ifeq (${ENABLE_SSL},1) | |||
CPPFLAGS += -DIRC_SSL_SUPPORT | |||
endif | |||
all: ${PROGN} | |||
all: include/config.h ${PROGN} | |||
${PROGN}: ${HDR} ${SRC} | |||
${LINK.c} -pipe ${LIB} src/unity.c -o $@ ${LDLIBS} | |||
# do nothing but update them... | |||
$(SRC) $(HDR): | |||
${SRC} ${HDR}: | |||
submodules: | |||
git submodule update --init --recursive | |||
include/config.h: config.mk.h | |||
cp -f $< $@ | |||
clean: | |||
-rm ${OBJ} | |||
.PHONY: submodules clean | |||
.PHONY: all submodules clean |
@@ -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) \ | |||
do { fputs(PROGN ": " msg "\n", stderr); return (ret); } while (0) | |||
@@ -17,6 +13,3 @@ | |||
#define DB_ERROR 100 | |||
#define IRC_ERROR 101 | |||
#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 | |||
#define IRC_BOLD "[B]" | |||
#define IRC_ITALIC "[I]" | |||
@@ -22,6 +20,3 @@ | |||
#define IRC_DARKGRAY "[COLOR=DARKGRAY]" | |||
#define IRC_LIGHTGRAY "[COLOR=LIGHTGRAY]" | |||
#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 | |||
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")) | |||
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 | |||
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 |
@@ -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) | |||
VARDECL char const * db = DBFILE; | |||
@@ -9,25 +9,25 @@ VARDECL sqlite3 * connection = NULL; | |||
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 | |||
api_init(void) | |||
{ | |||
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(set_repo_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)); | |||
return 0; | |||
} | |||
@@ -44,21 +44,13 @@ api_rope(void) | |||
sqlite3_close(connection); | |||
} | |||
DECL void | |||
rope(void) | |||
{ | |||
if (session) | |||
{ irc_destroy_session(session); } | |||
api_rope(); | |||
} | |||
DECL char * | |||
remind(char * who) | |||
{ | |||
char * r; | |||
char * title; | |||
char * desc; | |||
char * repo; | |||
/* char * repo; */ | |||
DBERR(sqlite3_reset(remind_stmt)); | |||
DBERR(sqlite3_bind_text(remind_stmt, 1, who, -1, SQLITE_STATIC)); | |||
const int i = sqlite3_step(remind_stmt); | |||
@@ -69,20 +61,24 @@ remind(char * who) | |||
title = strdup(title); | |||
desc = (char *) sqlite3_column_text(remind_stmt, 1); | |||
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 */ | |||
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 | |||
@@ -129,14 +125,14 @@ rtos(void * data, | |||
*r = (char *)calloc(data_len, sizeof(char)); | |||
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"); | |||
@@ -164,7 +160,7 @@ raw(char const * const sql) | |||
if (errmsg){ | |||
free(r); | |||
r = errmsg; | |||
r = errmsg; | |||
} else { strcat(r, "\00"); } | |||
return r; | |||
} | |||
@@ -176,40 +172,39 @@ get_project_count_callback(void* data, int argc, char** argv, char** colname) | |||
{ | |||
(void)argc; | |||
(void)colname; | |||
int* count = (int*)data; | |||
*count = atoi(argv[0]); | |||
return 0; | |||
int* count = (int*)data; | |||
*count = atoi(argv[0]); | |||
return 0; | |||
} | |||
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 | |||
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 | |||
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 | |||
@@ -233,9 +228,10 @@ purge_assignments(char const * const who) | |||
DECL int | |||
is_no_assignment(char const * const who) | |||
{ | |||
const int e; | |||
DBERR(sqlite3_reset(is_no_assignment_stmt)); | |||
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); | |||
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 = | |||
/* 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 "!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 * | |||
get_username(const char * origin) | |||
@@ -127,15 +149,8 @@ event_channel(irc_session_t * lsession, | |||
(void) message; | |||
(void) count; | |||
/* 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 || | |||
message[1] == '\0') | |||
{ return; } | |||
@@ -144,44 +159,88 @@ event_channel(irc_session_t * lsession, | |||
current_username = NULL; | |||
} | |||
/* 'abc' SINGLE | |||
'def ' SINGLE | |||
'ghi jkl' MULTI */ | |||
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; | |||
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 | |||
help(void) | |||
@@ -24,6 +109,8 @@ help(void) | |||
"-url URL - Sets the target URL\n" | |||
"-db DBFILE - Sets the database file (default: probotic_data.sqlite)\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"); | |||
} | |||
@@ -54,7 +141,7 @@ main (int argc, | |||
else if (strcmp(arg, "help") == 0) | |||
{ goto help; } | |||
if (argc < 2) | |||
{ goto nop; } | |||
{ goto help; } | |||
if (strcmp(arg, "db") == 0) | |||
{ db = argv[1]; } | |||
else if (strcmp(arg, "url") == 0) | |||
@@ -70,7 +157,7 @@ main (int argc, | |||
++argv; --argc; | |||
} | |||
else | |||
{ nop: ERRFMT(1, "Oprand without option '%s'", arg); } | |||
{ goto help; } | |||
} | |||
} | |||
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 char const remind_stmt_template[] = | |||
"SELECT " |
@@ -7,19 +7,16 @@ | |||
#include <string.h> | |||
#include <time.h> | |||
#include <stdlib.h> | |||
#include <ctype.h> | |||
#include <libircclient.h> | |||
#include <sqlite3.h> | |||
#include "api.h" | |||
#include "error.h" | |||
#include "free.h" | |||
#include "help.h" | |||
#include "irc.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 "irc.c" | |||
#include "main.c" |
@@ -1,7 +1,2 @@ | |||
#!/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 |