Merge branch 'master' of https://git.lain.church/emil/probotic
This commit is contained in:
commit
e1270c32ba
13
Makefile
13
Makefile
@ -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
|
||||||
|
30
build.sh
30
build.sh
@ -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
|
|
1
include/config.mk.h
Normal file
1
include/config.mk.h
Normal file
@ -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
|
|
23
install.sh
23
install.sh
@ -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
|
||||||
|
40
src/api.c
40
src/api.c
@ -1,4 +1,4 @@
|
|||||||
#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)
|
||||||
@ -22,7 +22,7 @@ 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));
|
||||||
@ -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,19 +61,23 @@ 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, */
|
||||||
|
/* IRC_RED "%s: " IRC_YELLOW "%s" IRC_GREEN */
|
||||||
|
/* " (@" IRC_BLUE "%s" IRC_GREEN ")" IRC_STOP, */
|
||||||
|
/* title, desc, repo)) */
|
||||||
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,
|
title, desc))
|
||||||
title, desc, repo))
|
|
||||||
{ /* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,13 +178,11 @@ get_project_count_callback(void* data, int argc, char** argv, char** colname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +198,8 @@ get_nth_id(const int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
@ -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
189
src/irc.c
@ -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);
|
||||||
|
}
|
||||||
|
121
src/main.c
121
src/main.c
@ -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);
|
||||||
|
223
src/parse.c
223
src/parse.c
@ -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 "
|
13
src/unity.c
13
src/unity.c
@ -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"
|
||||||
|
BIN
src/unity.o
BIN
src/unity.o
Binary file not shown.
@ -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
|
|
||||||
|
Reference in New Issue
Block a user