Compare commits

...

2 Commits

Author SHA1 Message Date
Bubblegumdrop
856d8132b5 Strings... 2021-03-11 20:48:32 -05:00
Bubblegumdrop
90f6bdbb7a IRC functionality in place: .start .stop spam and .quit 2021-03-11 17:23:43 -05:00
12 changed files with 422 additions and 214 deletions

13
data.h
View File

@ -4,32 +4,33 @@
/*
* We store data in IRC session context.
*/
typedef struct {
struct irc_ctx_t {
unsigned short port;
char *channel;
char *nick;
char *server;
} irc_ctx_t;
};
/*
* Params that we give to our threads.
*/
typedef struct {
struct spam_params_t {
irc_session_t *session;
const char *phrase;
const char *channel;
int timer;
int unused;
} spam_params_t;
};
/*
* Eventually I'd like to be able to do insert_struct with filled out info or similar.
*/
typedef struct {
struct quote_t {
int rowid;
const char *added_by;
const char *channel;
const char *subject;
const char *words;
} quote_t;
};
#endif /* DATA_H */

106
db.c
View File

@ -1,32 +1,24 @@
/* <https://gist.github.com/enile8/2424514> */
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */
#include <string.h>
#include <assert.h> /* assert */
#include <sqlite3.h>
#include <stdio.h> /* size_t */
#include <stdlib.h> /* malloc */
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#include <stdlib.h> /* free */
#include "io.h"
#include "strings.h"
#include "unused.h"
const char errmsg_bind[] = "Error binding parameter: %s\n";
const char errmsg_clear[] = "Error clearing bindings: %s\n";
const char errmsg_insert[] = "Error inserting data: %s\n";
const char errmsg_prepare[] = "Error preparing data: %s\n";
const char errmsg_readfile[] = "Error reading file: %s\n";
const char errmsg_reset[] = "Error resetting statement: %s\n";
const char errmsg_update[] = "Error updating data: %s\n";
struct params {
int type;
void *arg;
};
int print_col(sqlite3_stmt * pTableInfo, int col) {
static int print_col(sqlite3_stmt * pTableInfo, int col) {
int n, rc;
static int ct = 0;
char outfile[50];
size_t size;
printf("%s: ", sqlite3_column_name(pTableInfo, col));
switch (sqlite3_column_type(pTableInfo, col)) {
case SQLITE_INTEGER:
@ -52,16 +44,14 @@ int print_col(sqlite3_stmt * pTableInfo, int col) {
}
break;
case SQLITE_NULL:
printf("Null ");
printf("(null)\n");
break;
default:
printf(" *Cannot determine SQLITE TYPE* col=%d ", col);
printf(" *Cannot determine SQLITE TYPE* col=%d\n", col);
}
return 0;
}
static int callback_run_script(void *NotUsed, int argc, char **argv, char **azColName) {
static int run_script_callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
UNUSED(NotUsed);
for (i = 0; i < argc; i++) {
@ -69,49 +59,45 @@ static int callback_run_script(void *NotUsed, int argc, char **argv, char **azCo
}
return 0;
}
int run_script(sqlite3 * db, const char *script_filename) {
int j, rc;
char *copy_statements, *orig_statements, *saveptr1, *str1, *token, *zErrMsg;
int rc;
char *statements, *zErrMsg;
zErrMsg = 0;
orig_statements = file_read(script_filename, 0);
if (orig_statements) {
copy_statements = strndup(orig_statements, 4096);
} else {
fprintf(stderr, errmsg_readfile, script_filename);
if (!(statements = file_read(script_filename, NULL))) {
fprintf(stderr, string_errmsg_readfile, script_filename);
return -1;
}
for (j = 1, str1 = copy_statements;; j++, str1 = NULL) {
rc = sqlite3_exec(db, statements, run_script_callback, 0, &zErrMsg);
if (SQLITE_OK != rc) {
fprintf(stderr, " !! SQL error: %s\n", sqlite3_errmsg(db));
sqlite3_free(zErrMsg);
}
#if 0
for (j = 1, str1 = statements;; j++, str1 = NULL) {
token = strtok_r(str1, "\n", &saveptr1);
if (token == NULL)
break;
if (strlen(token) > 2 && token[0] == '-' && token[1] == '-')
continue; /* Comment line; TODO multiline comment */
printf("%d: %s\n", j, token);
rc = sqlite3_exec(db, token, callback_run_script, 0, &zErrMsg);
rc = sqlite3_exec(db, token, run_script_callback, 0, &zErrMsg);
if (SQLITE_OK != rc) {
fprintf(stderr, " !! SQL error: %s\n", sqlite3_errmsg(db));
sqlite3_free(zErrMsg);
break;
}
}
free(copy_statements);
free(orig_statements);
#endif
free(statements);
fprintf(stderr, "Bye!\n");
return SQLITE_OK;
}
int run_one(sqlite3 * db, const char *query) {
int i, n, rc;
sqlite3_stmt *stmt = NULL;
printf("> %s\n", query);
if (SQLITE_OK != (rc = sqlite3_prepare_v2(db, query, -1, &stmt, 0))) {
fprintf(stderr, errmsg_prepare, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
return SQLITE_ERROR;
}
while (SQLITE_ROW == (rc = sqlite3_step(stmt))) {
@ -123,17 +109,16 @@ int run_one(sqlite3 * db, const char *query) {
}
}
if (SQLITE_DONE != rc) {
fprintf(stderr, errmsg_update, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_update, sqlite3_errmsg(db));
}
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) {
fprintf(stderr, errmsg_reset, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db));
}
if (SQLITE_OK != (rc = sqlite3_clear_bindings(stmt))) {
fprintf(stderr, errmsg_clear, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_clear, sqlite3_errmsg(db));
}
return sqlite3_finalize(stmt);
}
int update_one(sqlite3 * db, int rowid, const char *param1, const char *param2) {
const char insert_stmt[] = "update quotedb set ? = ? where quote_id = ?";
int n, rc;
@ -142,75 +127,62 @@ int update_one(sqlite3 * db, int rowid, const char *param1, const char *param2)
maxlen = 4096;
n = 0;
if (SQLITE_OK != (rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0))) {
fprintf(stderr, errmsg_prepare, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
return SQLITE_ERROR;
}
#define S(x) if (SQLITE_OK != (rc = sqlite3_bind_text(stmt, ++n, x, (int)strnlen(x, maxlen), SQLITE_STATIC))) { \
fprintf(stderr, errmsg_bind, sqlite3_errmsg(db)); \
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db)); \
return SQLITE_ERROR; \
}
S(param1);
S(param2);
#undef S
sqlite3_bind_int(stmt, 3, rowid);
if (SQLITE_DONE != (rc = sqlite3_step(stmt))) {
fprintf(stderr, errmsg_update, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_update, sqlite3_errmsg(db));
}
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) {
fprintf(stderr, errmsg_reset, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db));
}
return sqlite3_finalize(stmt);
}
int insert_row(sqlite3 * db, const char *channel, const char *added_by, const char *subject, const char *words) {
const char insert_stmt[] = "insert into quotedb (date_added, channel, added_by, subject, words) values (datetime('now'), ?, ?, ?, ?)";
int n, rc;
size_t maxlen;
sqlite3_stmt *stmt = NULL;
maxlen = 4096;
n = 0;
if (SQLITE_OK != (rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0))) {
fprintf(stderr, errmsg_prepare, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
return SQLITE_ERROR;
}
#define S(x) if (SQLITE_OK != (rc = sqlite3_bind_text(stmt, ++n, x, (int)strnlen(x, maxlen), SQLITE_STATIC))) { \
fprintf(stderr, errmsg_bind, sqlite3_errmsg(db)); \
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db)); \
return SQLITE_ERROR; \
}
S(channel);
S(added_by);
S(subject);
S(words);
#undef S
if (SQLITE_DONE != (rc = sqlite3_step(stmt))) {
fprintf(stderr, errmsg_insert, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_insert, sqlite3_errmsg(db));
}
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) {
fprintf(stderr, errmsg_reset, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db));
}
return sqlite3_finalize(stmt);
}
int sqlite_version(sqlite3 * db) {
int rc;
sqlite3_stmt *stmt = NULL;
if (SQLITE_OK != (rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION()", -1, &stmt, 0))) {
fprintf(stderr, errmsg_prepare, sqlite3_errmsg(db));
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
return 1;
}
if (SQLITE_ROW == (rc = sqlite3_step(stmt))) {
printf("SQLite version: %s\n", sqlite3_column_text(stmt, 0));
}
sqlite3_finalize(stmt);
return 0;
return sqlite3_finalize(stmt);
}

8
dictionary.sql Normal file
View File

@ -0,0 +1,8 @@
BEGIN TRANSACTION;
create table if not exists dictionarydb (date_added text not null, added_by text not null, channel text not null, word text not null, definition text not null)
COMMIT;
--delete from quotedb
--drop table quotedb

165
events.c
View File

@ -2,68 +2,152 @@
#include <assert.h> /* assert */
#include <errno.h>
#include <stdio.h> /* size_t */
#include <stdlib.h> /* malloc */
#include "libircclient.h"
#include "data.h"
#include "events.h"
#include "strings.h"
#include "threads.h"
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
char F_SPAM_THREADS = STOPPED;
char say_hi = 1;
THREAD_FUNCTION(gen_spam) {
spam_params_t *sp = (spam_params_t *) arg;
while (1) {
struct spam_params_t *sp = (struct spam_params_t *)arg;
while (RUNNING == F_SPAM_THREADS) {
if (irc_cmd_msg(sp->session, sp->channel, sp->phrase))
break;
if (sp->timer > 0)
sleep((unsigned int)
sp->timer);
sleep((unsigned int)sp->timer);
}
return 0;
}
EVENT_SIGNATURE(start_spam) {
struct irc_ctx_t *ctx;
static struct spam_params_t spam1;
static struct spam_params_t spam2;
static struct spam_params_t spam3;
thread_id_t tid;
UNUSED(count);
UNUSED(event);
UNUSED(origin);
UNUSED(params);
ctx = (struct irc_ctx_t *)irc_get_ctx(session);
spam1.session = spam2.session = spam3.session = session;
spam1.channel = spam2.channel = spam3.channel = ctx->channel;
spam1.phrase = "HEHE";
spam2.phrase = "HAHA";
spam3.phrase = "HUHU";
spam1.timer = 2;
spam2.timer = 3;
spam3.timer = 4;
F_SPAM_THREADS = RUNNING;
if (CREATE_THREAD(&tid, gen_spam, &spam1)
|| CREATE_THREAD(&tid, gen_spam, &spam2)
|| CREATE_THREAD(&tid, gen_spam, &spam3))
printf("CREATE_THREAD failed: %s\n", strerror(errno));
else
printf(string_spam_success);
}
void dump_event(irc_session_t * session, const char *event, const char *origin, const char **params, unsigned int count) {
char buf[1024];
unsigned int cnt;
UNUSED(session);
buf[0] = '\0';
memset(buf, 0, sizeof buf);
for (cnt = 0; cnt < count; cnt++) {
if (cnt)
strcat(buf, "|");
strcat(buf, params[cnt]);
}
printf("[%s] %s : [%d] %s\n", event, origin ? origin : "(null)", cnt, buf);
}
EVENT_SIGNATURE(event_connect) {
irc_ctx_t *ctx;
struct irc_ctx_t *ctx;
UNUSED(event);
UNUSED(origin);
UNUSED(params);
UNUSED(count);
ctx = (irc_ctx_t *)
irc_get_ctx(session);
ctx = (struct irc_ctx_t *)irc_get_ctx(session);
printf(string_connect_success, ctx->server, ctx->port, ctx->nick, ctx->channel);
irc_cmd_join(session, ctx->channel, 0);
}
EVENT_NUMERIC_SIGNATURE(event_numeric) {
UNUSED(session);
UNUSED(origin);
UNUSED(params);
UNUSED(count);
char buf[24];
snprintf(buf, sizeof buf, "%d", event);
dump_event(session, buf, origin, params, count);
if (event > 400) {
printf("ERROR %d: %s: %s %s %s %s\n", event, origin ? origin : "unknown", params[0], count > 1 ? params[1] : "", count > 2 ? params[2] : "", count > 3 ? params[3] : "");
}
}
int IsAdmin(const char *name) {
return !strcmp(name, "Bubblegumdrop");
}
EVENT_SIGNATURE(event_channel) {
irc_ctx_t *ctx;
struct irc_ctx_t *ctx;
char nickbuf[128];
UNUSED(event);
UNUSED(params);
UNUSED(count);
if (!origin || count != 2)
return;
dump_event(session, event, origin, params, count);
if (strstr(params[1], "fuck") == 0)
if (NULL == origin || count < 2)
return;
irc_target_get_nick(origin, nickbuf, sizeof(nickbuf));
ctx = (irc_ctx_t *) irc_get_ctx(session);
if (!IsAdmin(nickbuf)) {
return;
}
ctx = (struct irc_ctx_t *)irc_get_ctx(session);
UNUSED(ctx);
if (!strcmp(params[1], ".stop")) {
irc_cmd_msg(session, params[0], ":x");
F_SPAM_THREADS = STOPPED;
}
if (!strcmp(params[1], ".start")) {
irc_cmd_msg(session, params[0], ":v");
F_SPAM_THREADS = RUNNING;
start_spam(session, ctx->nick, origin, params, count);
}
if (!strcmp(params[1], ".quit")) {
F_MAIN_THREAD = STOPPED;
F_IRC_THREAD = STOPPED;
F_MAIN_THREAD = STOPPED;
irc_cmd_quit(session, "Bye!");
}
#if 0
if (ctx->insolents.find(nickbuf) == ctx->insolents.end())
ctx->insolents[nickbuf]
@ -97,48 +181,39 @@ EVENT_SIGNATURE(event_channel) {
}
EVENT_SIGNATURE(event_join) {
irc_ctx_t *ctx;
char buf[128];
struct irc_ctx_t *ctx;
UNUSED(count);
UNUSED(event);
if (!origin)
return;
ctx = (irc_ctx_t *)
irc_get_ctx(session);
ctx = (struct irc_ctx_t *)irc_get_ctx(session);
/*
* We need to know whether WE are joining the channel, or someone else.
* To do this, we compare the origin with our nick.
* Note that we have set LIBIRC_OPTION_STRIPNICKS to obtain 'parsed' nicks.
*/
if (!strcmp(origin, ctx->nick)) {
static spam_params_t spam1;
static spam_params_t spam2;
static spam_params_t spam3;
thread_id_t tid;
spam1.session = spam2.session = spam3.session = session;
spam1.channel = spam2.channel = spam3.channel = ctx->channel;
spam1.phrase = "HEHE";
spam2.phrase = "HAHA";
spam3.phrase = "HUHU";
spam1.timer = 2;
spam2.timer = 3;
spam3.timer = 4;
printf("We just joined the channel %s; starting the spam threads\n", params[1]);
if (CREATE_THREAD(&tid, gen_spam, &spam1)
|| CREATE_THREAD(&tid, gen_spam, &spam2)
|| CREATE_THREAD(&tid, gen_spam, &spam3))
printf("CREATE_THREAD failed: %s\n", strerror(errno));
else
printf("Spammer thread was started successfully.\n");
} else {
char textbuf[168];
sprintf(textbuf, "Hey, %s, hi!", origin);
irc_cmd_msg(session, params[0], textbuf);
if (say_hi)
irc_cmd_msg(session, params[0], "Hi");
/*
printf("We just joined the channel %s; starting the spam threads\n", params[0]);
start_spam (session, ctx->nick, origin, params, count);
*/
} else if (say_hi) {
memset(&buf, 0, sizeof buf);
snprintf(buf, (sizeof buf) - 1, "Hey, %s, hi!", origin);
irc_cmd_msg(session, params[0], buf);
}
}
EVENT_SIGNATURE(event_nick) {
char nickbuf[128];
irc_ctx_t *ctx;
struct irc_ctx_t *ctx;
UNUSED(event);
UNUSED(params);
@ -147,7 +222,7 @@ EVENT_SIGNATURE(event_nick) {
return;
irc_target_get_nick(origin, nickbuf, sizeof(nickbuf));
ctx = (irc_ctx_t *) irc_get_ctx(session);
ctx = (struct irc_ctx_t *)irc_get_ctx(session);
UNUSED(ctx);
#if 0

22
io.c
View File

@ -1,6 +1,7 @@
#include <assert.h> /* assert */
#include <stdio.h> /* FILE* */
#include <stdlib.h> /* malloc, free */
#include <unistd.h> /* unlink */
#include "io.h"
@ -18,7 +19,7 @@ char *file_read(const char *filename, size_t *readSize) {
size = ftell(fh);
rewind(fh);
if (size > 0)
buffer = (char*)malloc((size_t)size);
buffer = (char *)malloc((size_t)size);
if (buffer != NULL) {
assert(buffer != NULL);
nread = fread(buffer, 1, (size_t)size, fh);
@ -57,3 +58,22 @@ size_t file_write(const char *fileName, const void *data, const size_t size) {
}
return numberBytesWritten;
}
int copy_file(const char *srcname, const char *dstname) {
int rc;
char *buf;
size_t nread, nwrite;
rc = -1;
buf = file_read(srcname, &nread);
if (buf) {
nwrite = file_write(dstname, buf, nread);
if (nread != nwrite) {
fprintf(stderr, "Incorrect write size (%ld != %ld)\n", nread, nwrite);
unlink(dstname);
}
assert(nread == nwrite);
free(buf);
rc = 0;
}
return rc;
}

166
main.c
View File

@ -1,10 +1,15 @@
/*
* code adapted from:
* Dictionary bot.
*
* Code adapted from:
*
* <https://gist.github.com/enile8/2424514>
* <https://www.rosettacode.org/wiki/Write_entire_file#C>
* <https://rosettacode.org/wiki/Read_entire_file#C>
* libircclient-1.10/examples/spammer.c
*
* And surely others.
*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
* Copyright (C) 2021 Bubblegumdrop <Bubblegumdrop@lain.church>
*
@ -28,46 +33,39 @@
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* Quote bot. WIP.
*/
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */
#include <string.h>
#include <assert.h> /* assert */
#include <errno.h>
#include <getopt.h> /* getopt */
#include <stdio.h> /* size_t */
#include <unistd.h> /* getopt */
#include <getopt.h> /* getopt */
#include "libircclient.h"
#include "data.h"
#include "db.h"
#include "events.h"
#include "levenshtein.h"
#include "strings.h"
#include "threads.h"
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
extern void install_signal_handler(void);
char F_IRC_THREAD = STOPPED;
char F_MAIN_THREAD = STOPPED;
THREAD_FUNCTION(irc_thread) {
irc_session_t *irc_session = NULL;
const char create_db_query[] = "create table if not exists quotedb (date_added text not null, added_by text not null, channel text not null, subject text not null, words text not null)";
THREAD_FUNCTION(IrcSessionThread) {
const char *server;
unsigned short port = 6667;
struct irc_ctx_t *ctx;
irc_callbacks_t callbacks;
irc_session_t *s;
irc_ctx_t *ctx;
ctx = (irc_ctx_t *) arg;
ctx = (struct irc_ctx_t *)arg;
assert(NULL != ctx);
server = ctx->server;
assert(NULL != server);
assert(NULL != ctx->nick);
assert(NULL != ctx->channel);
while (RUNNING == F_IRC_THREAD) {
/* Initialize the callbacks */
memset(&callbacks, 0, sizeof(callbacks));
@ -78,16 +76,16 @@ THREAD_FUNCTION(irc_thread) {
callbacks.event_nick = event_nick;
callbacks.event_numeric = event_numeric;
/* And create the IRC session; 0 means error */
s = irc_create_session(&callbacks);
if (!s) {
printf("Could not create IRC session\n");
return (void *)-1;
irc_session = irc_create_session(&callbacks);
if (!irc_session) {
fprintf(stderr, string_connect_failure, irc_strerror(irc_errno(irc_session)));
F_IRC_THREAD = STOPPED;
}
irc_set_ctx(s, &ctx);
irc_option_set(s, LIBIRC_OPTION_STRIPNICKS);
irc_set_ctx(irc_session, ctx);
irc_option_set(irc_session, LIBIRC_OPTION_STRIPNICKS);
/* If the port number is specified in the server string, use the port 0 so it gets parsed */
if (strchr(server, ':') != 0)
port = 0;
ctx->port = 0;
/*
* To handle the "SSL certificate verify failed" from command line we allow passing ## in front
* of the server name, and in this case tell libircclient not to verify the cert
@ -95,93 +93,125 @@ THREAD_FUNCTION(irc_thread) {
if (server[0] == '#' && server[0] == '#') {
/* Skip the first character as libircclient needs only one # for SSL support, i.e. #irc.freenode.net */
server++;
irc_option_set(s, LIBIRC_OPTION_SSL_NO_VERIFY);
irc_option_set(irc_session, LIBIRC_OPTION_SSL_NO_VERIFY);
}
/* Initiate the IRC server connection */
if (irc_connect(s, server, port, 0, ctx->nick, 0, 0)) {
printf("Could not connect: %s\n", irc_strerror(irc_errno(s)));
return (void *)-1;
if (irc_connect(irc_session, server, ctx->port, 0, ctx->nick, 0, 0)) {
fprintf(stderr, string_connect_failure, irc_strerror(irc_errno(irc_session)));
F_IRC_THREAD = STOPPED;
}
/* and run into forever loop, generating events */
if (irc_run(s)) {
printf("Could not connect or I/O error: %s\n", irc_strerror(irc_errno(s)));
return (void *)-1;
if (irc_run(irc_session)) {
fprintf(stderr, string_connect_failure, irc_strerror(irc_errno(irc_session)));
F_IRC_THREAD = STOPPED;
}
irc_destroy_session(irc_session);
irc_session = NULL;
}
return (void *)0;
F_MAIN_THREAD = STOPPED;
#ifdef _WIN32
return 0;
#else
return NULL;
#endif
}
int main(int argc, char **argv) {
int rc, opt;
const char *db_name = NULL;
const char *script_filename = NULL;
const char *query_str = NULL;
irc_ctx_t ctx;
sqlite3 *db = NULL;
int main(int argc, char *argv[]) {
int rc;
int opt;
const char *db_name;
const char *query_str;
const char *filename;
sqlite3 *db;
struct irc_ctx_t ctx;
thread_id_t tid;
#if 0
const char *s1 = "rosettacode";
const char *s2 = "raisethysword";
printf("distance between `%s' and `%s': %d\n", s1, s2, levenshtein(s1, s2));
#endif
install_signal_handler();
db_name = "familyGuy.sqlite3";
while ((opt = getopt(argc, argv, "c:d:s:h")) != -1) {
query_str = NULL;
filename = NULL;
rc = -1;
db = NULL;
memset(&ctx, 0, sizeof(struct irc_ctx_t));
ctx.port = 6667;
while ((opt = getopt(argc, argv, "c:d:f:hn:p:q:s:")) != -1) {
switch (opt) {
case 'c':
query_str = optarg;
ctx.channel = optarg;
break;
case 'd':
db_name = optarg;
break;
case 'f':
filename = optarg;
break;
case 'n':
ctx.nick = optarg;
break;
case 'p':
ctx.port = atoi(optarg);
break;
case 'q':
query_str = optarg;
break;
case 's':
script_filename = optarg;
ctx.server = optarg;
break;
case 'h':
default:
fprintf(stderr, "Usage: %s [-h]\n", argv[0]);
fprintf(stderr, string_usage_fmt, argv[0]);
return -1;
break;
}
}
if (NULL != db_name) {
if (SQLITE_OK == (rc = sqlite3_open(db_name, &db))) {
printf("Open database successfully: ");
printf(string_opendb_success);
sqlite_version(db);
}
} else {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
fprintf(stderr, string_opendb_failure, sqlite3_errmsg(db));
return -1;
}
run_one(db, "create table if not exists quotedb (date_added text not null, added_by text not null, channel text not null, subject text not null, words text not null)");
/*run_one(db, create_db_query);*/
if (query_str) {
run_one(db, query_str);
} else if (script_filename) {
run_script(db, script_filename);
if (NULL != query_str) {
rc = run_one(db, query_str);
} else if (NULL != filename) {
rc = run_script(db, filename);
} else if (argc == 4) {
ctx.server = argv[1];
ctx.nick = argv[2];
ctx.channel = argv[3];
F_IRC_THREAD = F_MAIN_THREAD = RUNNING;
if (CREATE_THREAD(&tid, irc_thread, &ctx)) {
printf("CREATE_THREAD failed: %s\n", strerror(errno));
} else {
printf("IRC thread was started successfully.\n");
if (argc > 1)
ctx.server = argv[1];
if (argc > 2)
ctx.nick = argv[2];
if (argc > 3)
ctx.channel = argv[3];
if (!ctx.server || !ctx.nick || !ctx.channel) {
fprintf(stderr, string_usage_fmt, argv[0]);
return -1;
}
F_IRC_THREAD = RUNNING;
F_MAIN_THREAD = RUNNING;
if (CREATE_THREAD(&tid, IrcSessionThread, &ctx)) {
printf(string_ircthread_failure, strerror(errno));
} else {
printf(string_ircthread_success);
}
while (RUNNING == F_MAIN_THREAD) {
sleep(1);
}
F_IRC_THREAD = STOPPED;
F_SPAM_THREADS = STOPPED;
rc = 0;
} else {
printf("Usage: %s <server> <nick> <channel>\n", argv[0]);
fprintf(stderr, string_usage_fmt, argv[0]);
return -1;
}
F_IRC_THREAD = STOPPED;
sqlite3_close(db);
return 0;
return rc;
}

View File

@ -1,39 +1,36 @@
INLINE_SQLITE ?= 0
WARN := -W -Wall -Wextra -pedantic -pedantic-errors
CC ?= gcc
WARN := -W -Wall -Wextra -pedantic -pedantic-errors \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security \
-Wformat-y2k \
-Wimport -Winit-self -Winline \
-Winvalid-pch \
-Wmissing-field-initializers -Wmissing-format-attribute \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings
#-Wpacked -Wpadded
CFLAGS += -ggdb -O0 -std=c99 $(WARN)
CFLAGS += -I.
LDFLAGS += -lpthread -lircclient -ldl
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
ifeq ($(INLINE_SQLITE),0)
TMP := $(OBJ)
OBJ := $(filter-out sqlite3.o,$(TMP))
LDFLAGS += -lsqlite3
endif
OPT := -ggdb -O0
ifeq ($(O),1)
OPT := -g -O1
endif
ifeq ($(O),2)
OPT := -g0 -O2
endif
ifeq ($(O),s)
OPT := -g0 -Os
endif
CFLAGS += $(OPT) -std=c99 $(WARN)
CFLAGS += -I.
LDFLAGS += -lircclient -lpthread
all: spammer
sqlite3.o: sqlite3.c
@ -43,4 +40,4 @@ spammer: $(OBJ)
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
clean:
$(RM) -rf spammer db a.out *.o *.db *.sqlite3
$(RM) -rf spammer db a.out *.o *.db *.sqlite3 *.exe *.dll

42
signal.c Normal file
View File

@ -0,0 +1,42 @@
#include <signal.h> /* signal */
#include <stdio.h> /* fprintf */
#include <string.h> /* memset */
#include "libircclient.h"
#include "threads.h" /* F_* */
#include "strings.h"
extern irc_session_t *irc_session;
static void SignalHandler(int sig) {
char buf[512];
const char *s = string_signal_unknown_fmt;
#define CASE(x) case x: s = #x; break
switch (sig) {
CASE(SIGTERM);
CASE(SIGINT);
#ifndef _WIN32
CASE(SIGQUIT);
CASE(SIGKILL);
CASE(SIGHUP);
#endif
default:
break;
}
#undef CASE
memset(&buf, 0, sizeof buf);
snprintf(buf, (sizeof buf) - 1, string_signal_fmt, s);
fprintf(stderr, "%s", buf);
F_IRC_THREAD = STOPPED;
F_MAIN_THREAD = STOPPED;
F_SPAM_THREADS = STOPPED;
if (NULL != irc_session)
irc_cmd_quit(irc_session, buf);
/* TODO: clean exit */
}
void install_signal_handler(void) {
signal(SIGTERM, SignalHandler);
signal(SIGINT, SignalHandler);
#ifndef _WIN32
signal(SIGQUIT, SignalHandler);
signal(SIGKILL, SignalHandler);
signal(SIGHUP, SignalHandler);
#endif
}

25
strings.c Normal file
View File

@ -0,0 +1,25 @@
#include "strings.h"
const char string_connect_failure[] = "Could not connect: %s\n";
const char string_connect_success[] = "Connected!\n Server: %s\n Port: %d\n Nick: %s\n Channel: %s\n";
const char string_errmsg_bind[] = "Error binding parameter: %s\n";
const char string_errmsg_clear[] = "Error clearing bindings: %s\n";
const char string_errmsg_insert[] = "Error inserting data: %s\n";
const char string_errmsg_prepare[] = "Error preparing data: %s\n";
const char string_errmsg_readfile[] = "Error reading file: %s\n";
const char string_errmsg_reset[] = "Error resetting statement: %s\n";
const char string_errmsg_update[] = "Error updating data: %s\n";
const char string_ircthread_success[] = "IRC thread was started successfully.\n";
const char string_ircthread_failure[] = "CREATE_THREAD failed: %s\n";
const char string_opendb_failure[] = "Can't open database: %s\n";
const char string_opendb_success[] = "Open database successfully\n";
const char string_signal_fmt[] = "Received %s, exiting.\n";
const char string_signal_unknown_fmt[] = "(Unknown Signal)";
const char string_spam_success[] = "Spammer thread was started successfully.\n";
const char string_usage_fmt[] = "Usage: %s [-q query] [-d sqlite db] [-h] [-p port] [-f script file]\n";

28
strings.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef STRINGS_H
#define STRINGS_H
extern const char string_connect_failure[];
extern const char string_connect_success[];
extern const char string_errmsg_bind[];
extern const char string_errmsg_clear[];
extern const char string_errmsg_insert[];
extern const char string_errmsg_prepare[];
extern const char string_errmsg_readfile[];
extern const char string_errmsg_reset[];
extern const char string_errmsg_update[];
extern const char string_opendb_failure[];
extern const char string_opendb_success[];
extern const char string_signal_fmt[];
extern const char string_signal_unknown_fmt[];
extern const char string_spam_success[];
extern const char string_usage_fmt[];
extern const char string_ircthread_success[];
extern const char string_ircthread_failure[];
#endif /* STRINGS_H */

View File

@ -21,5 +21,7 @@ enum {
};
extern char F_IRC_THREAD;
extern char F_MAIN_THREAD;
extern char F_SPAM_THREADS;
#endif /* THREADS_H */
#endif /* THREADS_H */

8
unused.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef UNUSED_H
#define UNUSED_H
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#endif /* UNUSED_H */