This commit is contained in:
anon 2023-08-07 16:09:38 +02:00
commit e1270c32ba
19 changed files with 322 additions and 524 deletions

View File

@ -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

View File

@ -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: $?"

View File

@ -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

1
include/config.mk.h Normal file
View File

@ -0,0 +1 @@
#define DBFILE "probotic_data.sqlite"

View File

@ -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

View File

@ -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

View File

@ -1,6 +0,0 @@
#ifndef HELP_H_
VARDECL char const * help_msg;
#define HELP_H_
#endif

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 # BUILD & BOOTSTRAP
[ ! -e $DIR/bootstrap/ ] && $DIR/bootstrap/bootstrap.sh || return 1 make -C $DIR DEBUG=0 NVULN=1 || exit 1
# generate directories and install $DIR/bootstrap/bootstrap.sh || exit 1
TARGET=${TARGET-/opt/probotic}
useradd probotic -r -s /sbin/nologin -d $TARGET # INSTALL
mkdir -p $TARGET mkdir -p $TARGET
install -g probotic -o probotic -m 744 \ useradd probotic -r -s /sbin/nologin -d $TARGET
$DIR/bootstrap/probotic_data.sqlite probotic -v $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

126
src/api.c
View File

@ -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) if(l != SQLITE_OK && l != SQLITE_ROW && l != SQLITE_DONE)
{ {
fprintf(stderr, fprintf(stderr,
"sqlite (%d): %s\n", "sqlite (%d): %s\n",
sqlite3_errcode(connection), sqlite3_errmsg(connection)); sqlite3_errcode(connection), sqlite3_errmsg(connection));
exit(DB_ERROR); 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(new_assignment_stmt));
DBERR(stmt_prepare(purge_assignments_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); /* repo = (char *) sqlite3_column_text(remind_stmt, 3); */
if (repo) { repo = strdup(repo); } else { repo = "<no link available>"; } /* if (repo) { repo = strdup(repo); } else { repo = "<no link available>"; } */
if (-1 == asprintf(&r, /* if (-1 == asprintf(&r, */
IRC_RED "%s: " IRC_YELLOW "%s" IRC_GREEN /* IRC_RED "%s: " IRC_YELLOW "%s" IRC_GREEN */
" (@" IRC_BLUE "%s" IRC_GREEN ")" IRC_STOP, /* " (@" IRC_BLUE "%s" IRC_GREEN ")" IRC_STOP, */
title, desc, repo)) /* 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); } r = strdup(IRC_RED "No memory!" IRC_STOP);
} }
else else
{ {
r = strdup(IRC_RED "No current assignment." IRC_STOP); r = strdup(IRC_RED "No current assignment." IRC_STOP);
} }
return r; }
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, "|"); strcat(*r, "|");
if(argv[i]){ if(argv[i]){
strcat(*r, argv[i]); strcat(*r, argv[i]);
} }
else else
{ {
strcat(*r, "NULL"); 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; int* count = (int*)data;
*count = atoi(argv[0]); *count = atoi(argv[0]);
return 0; return 0;
} }
DECL int DECL int
get_project_count() get_project_count(void)
{ {
int r = 0; int r = 0;
char const * sql = "SELECT COUNT(*) FROM project;";
char const * sql = "SELECT COUNT(*) FROM project;"; DBERR(sqlite3_exec(connection, sql, get_project_count_callback, &r, NULL));
DBERR(sqlite3_exec(connection, sql, get_project_count_callback, &r, NULL)); return r;
return r;
} }
DECL int DECL int
get_nth_id(const int i) get_nth_id(const int i)
{ {
int r; int r;
DBERR(sqlite3_reset(get_nth_id_stmt)); DBERR(sqlite3_reset(get_nth_id_stmt));
DBERR(sqlite3_bind_int(get_nth_id_stmt, 1, i)); DBERR(sqlite3_bind_int(get_nth_id_stmt, 1, i));
DBERR(sqlite3_step(get_nth_id_stmt)); DBERR(sqlite3_step(get_nth_id_stmt));
r = sqlite3_column_int(get_nth_id_stmt, 0); r = sqlite3_column_int(get_nth_id_stmt, 0);
return r; 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_reset(new_assignment_stmt));
DBERR(sqlite3_bind_text(new_assignment_stmt, 1, who, -1, SQLITE_STATIC)); DBERR(sqlite3_bind_text(new_assignment_stmt, 1, who, -1, SQLITE_STATIC));
DBERR(sqlite3_bind_int(new_assignment_stmt, 2, project)); DBERR(sqlite3_bind_int(new_assignment_stmt, 2, project));
DBERR(sqlite3_step(new_assignment_stmt)); 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);
} }

189
src/irc.c
View File

@ -1,18 +1,48 @@
/* irc.c - IRC interface /* irc.c - IRC interface */
Probotic is free software: you can redistribute it and/or modify #define FULL_FREE(obj) \
it under the terms of the GNU General Public License version 3 only as do \
published by the Free Software Foundation. { \
if ((obj)) \
{ \
memset((obj), '\0', strlen((obj))); \
free((obj)); \
(obj) = NULL; \
} \
} while (0)
Probotic is distributed in the hope that it will be useful, #define PREFIX_COMMAND_CHAR '!'
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 #define IRCMSG(msg) irc_cmd_msg(session, creds.channel, msg)
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 '!' DECL void parse_command(char const * cmd);
#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 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) if (*message == PREFIX_COMMAND_CHAR)
{ { current_username = get_username(origin); }
case PREFIX_CHANNEL_COMMAND_CHAR:
current_username = strdup(creds.channel);
break;
case PREFIX_COMMAND_CHAR:
current_username = get_username(origin);
break;
}
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;
} }
DECL int /* 'abc' SINGLE
init(void) 'def ' SINGLE
{ 'ghi jkl' MULTI */
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 DECL int
loop(void) has_arg(char const * cmd)
{ {
/* We should figure out how the failure happens so we can tell the user that. */ while (isalnum(*cmd))
if (irc_run(session) != 0) {
{ ERR(1, "Error running IRC session\nPossible issue: bad URL," if (*cmd == '\0')
" no network connection, bad port, refused connection."); } { break; }
++cmd;
}
while (*cmd != '\0')
{
if (!isspace(*(++cmd)))
{ return 1; }
}
return 0; return 0;
} }
DECL void
parse_command(char const * cmd)
{
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);
}

View File

@ -1,21 +1,106 @@
/* 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.
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 VERSION_STRING "1" #define VERSION_STRING "1"
/* 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;
}
#undef GENCOPY
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);

View File

@ -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);
}

View File

@ -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 "

View File

@ -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 "stmt.c"
#include "irc.c"
#include "parse.c"
#include "api.c" #include "api.c"
#include "irc.c"
#include "main.c" #include "main.c"

Binary file not shown.

View File

@ -1,7 +1,2 @@
#!/bin/sh #!/bin/sh
# doubles as a cleanup script userdel -rf probotic
DIR=$(dirname $(readlink -f "$0"))
cd $DIR
TARGET=${TARGET-/opt/probotic}
userdel probotic
rm -rf $TARGET