Here you have it.WIP-31-Mar-2021
@@ -1,6 +1,9 @@ | |||
#ifndef DATA_H | |||
#define DATA_H | |||
#include <sqlite3.h> | |||
#include <libircclient.h> | |||
/* | |||
* We store data in IRC session context. | |||
*/ | |||
@@ -9,6 +12,7 @@ struct irc_ctx_t { | |||
char *channel; | |||
char *nick; | |||
char *server; | |||
sqlite3 * db; | |||
}; | |||
/* | |||
@@ -21,15 +25,4 @@ struct spam_params_t { | |||
float timer; | |||
}; | |||
/* | |||
* Eventually I'd like to be able to do insert_struct with filled out info or similar. | |||
*/ | |||
struct quote_t { | |||
int rowid; | |||
const char *added_by; | |||
const char *channel; | |||
const char *subject; | |||
const char *words; | |||
}; | |||
#endif /* DATA_H */ |
@@ -5,57 +5,46 @@ | |||
#include <sqlite3.h> | |||
#include <stdio.h> /* size_t */ | |||
#include <stdlib.h> /* free */ | |||
#include "data.h" | |||
#include "io.h" | |||
#include "strings.h" | |||
#include "i18n.h" | |||
#include "unused.h" | |||
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: | |||
printf("%d ", sqlite3_column_int(pTableInfo, col)); | |||
break; | |||
case SQLITE_FLOAT: | |||
printf("%f ", sqlite3_column_double(pTableInfo, col)); | |||
break; | |||
case SQLITE_TEXT: | |||
printf("%s ", sqlite3_column_text(pTableInfo, col)); | |||
break; | |||
case SQLITE_BLOB: //printf("%s",sqlite3_column_blob(pTableInfo, col)); | |||
/* fprintf(stderr, "IN BLOB bytes %d\n", | |||
sqlite3_column_bytes(pTableInfo, col)); */ | |||
snprintf(outfile, 20, "outdata.%d.png", ct++); | |||
n = sqlite3_column_bytes(pTableInfo, col); | |||
if (n > 0) | |||
size = (size_t)n; | |||
else | |||
break; | |||
if ((rc = (int)file_write(outfile, sqlite3_column_blob(pTableInfo, col), size))) { | |||
assert(rc == (int)size); | |||
} | |||
break; | |||
case SQLITE_NULL: | |||
printf("(null)\n"); | |||
break; | |||
default: | |||
printf(" *Cannot determine SQLITE TYPE* col=%d\n", col); | |||
} | |||
return 0; | |||
} | |||
static int run_script_callback(void *NotUsed, int argc, char **argv, char **azColName) { | |||
#define FINISH_UP() \ | |||
rc = sqlite3_reset(stmt); \ | |||
if (SQLITE_OK != rc) { \ | |||
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db)); \ | |||
} \ | |||
rc = sqlite3_clear_bindings(stmt); \ | |||
if (SQLITE_OK != rc) { \ | |||
fprintf(stderr, string_errmsg_clear, sqlite3_errmsg(db)); \ | |||
} \ | |||
return sqlite3_finalize(stmt) | |||
static const char string_errmsg_bind[] = _("Error binding parameter: %s\n"); | |||
static const char string_errmsg_clear[] = _("Error clearing bindings: %s\n"); | |||
static const char string_errmsg_delete[] = _("Error deleting data: %s\n"); | |||
static const char string_errmsg_insert[] = _("Error inserting data: %s\n"); | |||
static const char string_errmsg_prepare[] = _("Error preparing data: %s\n"); | |||
static const char string_errmsg_readfile[] = _("Error reading file: %s\n"); | |||
static const char string_errmsg_reset[] = _("Error resetting statement: %s\n"); | |||
static const char string_errmsg_update[] = _("Error updating data: %s\n"); | |||
static const char string_null_msg[] = _("(null)\n"); | |||
static const char string_sqlite_version[] = _("SQLite version: %s\n"); | |||
static const char string_unmatched_comment[] = _("Unmatched comment: %d\n"); | |||
int run_script_callback(void *NotUsed, int argc, char **argv, char **azColName) { | |||
int i; | |||
UNUSED(NotUsed); | |||
for (i = 0; i < argc; i++) { | |||
printf(" => %s = %s\n", azColName[i], (argv[i] ? argv[i] : "NULL")); | |||
printf(" => %s = %s\n", azColName[i], (argv[i] ? argv[i] : string_null_msg)); | |||
} | |||
return 0; | |||
return SQLITE_OK; | |||
} | |||
int run_script(sqlite3 * db, const char *script_filename) { | |||
int j, rc; | |||
int run_script(sqlite3 * db, int (*callback)(void *, int, char **, char **), const char *script_filename) { | |||
int j, rc, incomment; | |||
char *statements, *zErrMsg; | |||
char *str1, *saveptr1, *token; | |||
zErrMsg = 0; | |||
@@ -63,123 +52,137 @@ int run_script(sqlite3 * db, const char *script_filename) { | |||
fprintf(stderr, string_errmsg_readfile, script_filename); | |||
return -1; | |||
} | |||
#if 0 | |||
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); | |||
} | |||
#else | |||
incomment = 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 */ | |||
if (strstr(token, "/*")) { | |||
incomment = 1; | |||
} | |||
if (strstr(token, "*/")) { | |||
if (!incomment) { | |||
fprintf(stderr, string_unmatched_comment, j); | |||
} | |||
incomment = 0; | |||
} | |||
if (incomment) | |||
continue; | |||
printf("%d: %s\n", j, token); | |||
rc = sqlite3_exec(db, token, run_script_callback, 0, &zErrMsg); | |||
rc = sqlite3_exec(db, token, callback, 0, &zErrMsg); | |||
if (SQLITE_OK != rc) { | |||
fprintf(stderr, " !! SQL error: %s\n", sqlite3_errmsg(db)); | |||
fprintf(stderr, "!! SQL error: %s\n", zErrMsg); | |||
sqlite3_free(zErrMsg); | |||
break; | |||
} | |||
} | |||
#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, string_errmsg_prepare, sqlite3_errmsg(db)); | |||
return SQLITE_ERROR; | |||
} | |||
while (SQLITE_ROW == (rc = sqlite3_step(stmt))) { | |||
n = sqlite3_column_count(stmt); | |||
for (i = 0; i < n; ++i) { | |||
printf(" => "); | |||
print_col(stmt, i); | |||
puts(""); | |||
} | |||
} | |||
if (SQLITE_DONE != rc) { | |||
fprintf(stderr, string_errmsg_update, sqlite3_errmsg(db)); | |||
} | |||
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) { | |||
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db)); | |||
} | |||
if (SQLITE_OK != (rc = sqlite3_clear_bindings(stmt))) { | |||
fprintf(stderr, string_errmsg_clear, sqlite3_errmsg(db)); | |||
int run_one(sqlite3 * db, int (*callback)(void *, int, char **, char **), const char *query) { | |||
int rc = SQLITE_ERROR; | |||
char *zErrMsg = NULL; | |||
if (SQLITE_OK != (rc = sqlite3_exec(db, query, callback, 0, &zErrMsg))) { | |||
fprintf(stderr, "!! SQL error: %s\n", zErrMsg); | |||
sqlite3_free(zErrMsg); | |||
} | |||
return sqlite3_finalize(stmt); | |||
return rc; | |||
} | |||
int update_one(sqlite3 * db, int rowid, const char *param1, const char *param2) { | |||
const char insert_stmt[] = "update quotedb set ? = ? where quote_id = ?"; | |||
int insert_new_definition(sqlite3 * db, const char *channel, const char *name, const char *word, const char *definition) { | |||
const char insert_stmt[] = "insert into dictionarydb (date_added , channel , added_by, word , definition ) 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))) { | |||
rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0); | |||
if (SQLITE_OK != rc) { | |||
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db)); | |||
return SQLITE_ERROR; | |||
goto _out; | |||
} | |||
#define S(x) if (SQLITE_OK != (rc = sqlite3_bind_text(stmt, ++n, x, (int)strnlen(x, maxlen), SQLITE_STATIC))) { \ | |||
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db)); \ | |||
return SQLITE_ERROR; \ | |||
} | |||
S(param1); | |||
S(param2); | |||
n = 0; | |||
#define S(x) \ | |||
rc = sqlite3_bind_text(stmt, ++n, x, (int)strnlen(x, 4096), SQLITE_STATIC); \ | |||
if (SQLITE_OK != rc) { \ | |||
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db)); \ | |||
goto _out; \ | |||
} | |||
S(channel); | |||
S(name); | |||
S(word); | |||
S(definition); | |||
#undef S | |||
sqlite3_bind_int(stmt, 3, rowid); | |||
if (SQLITE_DONE != (rc = sqlite3_step(stmt))) { | |||
fprintf(stderr, string_errmsg_update, sqlite3_errmsg(db)); | |||
} | |||
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) { | |||
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db)); | |||
fprintf(stderr, string_errmsg_insert, sqlite3_errmsg(db)); | |||
} | |||
return sqlite3_finalize(stmt); | |||
_out: | |||
FINISH_UP(); | |||
} | |||
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; | |||
int delete_from_table_by_rowid(sqlite3 * db, int rowid) { | |||
int rc; | |||
const char insert_stmt[] = "delete from dictionarydb where rowid = ?"; | |||
sqlite3_stmt *stmt = NULL; | |||
maxlen = 4096; | |||
n = 0; | |||
if (SQLITE_OK != (rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0))) { | |||
rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0); | |||
if (SQLITE_OK != rc) { | |||
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db)); | |||
return SQLITE_ERROR; | |||
goto _out; | |||
} | |||
#define S(x) if (SQLITE_OK != (rc = sqlite3_bind_text(stmt, ++n, x, (int)strnlen(x, maxlen), SQLITE_STATIC))) { \ | |||
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, string_errmsg_insert, sqlite3_errmsg(db)); | |||
rc = sqlite3_bind_int(stmt, 1, rowid); | |||
if (SQLITE_OK != rc) { | |||
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db)); | |||
goto _out; | |||
} | |||
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) { | |||
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db)); | |||
if (SQLITE_DONE != (rc = sqlite3_step(stmt))) { | |||
fprintf(stderr, string_errmsg_delete, sqlite3_errmsg(db)); | |||
} | |||
return sqlite3_finalize(stmt); | |||
_out: | |||
FINISH_UP(); | |||
} | |||
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))) { | |||
rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION()", -1, &stmt, 0); | |||
if (SQLITE_OK != rc) { | |||
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db)); | |||
return 1; | |||
goto _out; | |||
} | |||
while (SQLITE_ROW == (rc = sqlite3_step(stmt))) { | |||
printf(string_sqlite_version, sqlite3_column_text(stmt, 0)); | |||
} | |||
if (SQLITE_DONE != rc) { | |||
fprintf(stderr, string_errmsg_update, sqlite3_errmsg(db)); | |||
} | |||
if (SQLITE_ROW == (rc = sqlite3_step(stmt))) { | |||
printf("SQLite version: %s\n", sqlite3_column_text(stmt, 0)); | |||
_out: | |||
FINISH_UP(); | |||
} | |||
/* | |||
* table_exists(tbl) => | |||
* 0 => table does not exist | |||
* 1 => table exists | |||
*/ | |||
int table_exists(sqlite3 * db, int (*callback)(void *, int, char **, char **), const char *table) { | |||
int ret, rc; | |||
char buf[BUFSIZ]; | |||
const char table_exists_query[] = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '%s'"; | |||
char *zErrMsg; | |||
ret = 0; | |||
memset(buf, 0, BUFSIZ); | |||
sprintf(buf, table_exists_query, table); | |||
rc = sqlite3_exec(db, buf, callback, 0, &zErrMsg); | |||
if (SQLITE_OK == rc) { | |||
ret = 1; | |||
} | |||
return sqlite3_finalize(stmt); | |||
return ret; | |||
} |
@@ -3,10 +3,15 @@ | |||
#include <sqlite3.h> | |||
int insert_row(sqlite3 *, const char *, const char *, const char *, const char *); | |||
int run_one(sqlite3 *, const char *); | |||
int run_script(sqlite3 *, const char *); | |||
typedef int (*callback)(void *, int, char **, char **); | |||
int sqlite_version(sqlite3 *); | |||
int update_one(sqlite3 *, int, const char *, const char *); | |||
int run_one(sqlite3 *, callback, const char *); | |||
int run_script_callback(void *, int argc, char **, char **); | |||
int run_script(sqlite3 *, callback, const char *); | |||
int insert_new_definition(sqlite3 *, const char *, const char *, const char *, const char *); | |||
int delete_from_table_by_rowid(sqlite3 *, int); | |||
int table_exists(sqlite3 *, callback, const char *); | |||
#endif /* DB_H */ |
@@ -1,17 +1,34 @@ | |||
#include <string.h> | |||
#define _POSIX_C_SOURCE 200809L /* strnlen */ | |||
#include <string.h> /* strchr, strnlen */ | |||
#include <assert.h> /* assert */ | |||
#include <errno.h> | |||
#include <errno.h> /* strerror */ | |||
#include <stdio.h> /* size_t */ | |||
#include "libircclient.h" | |||
#include <libircclient.h> | |||
#include <sqlite3.h> | |||
#include "data.h" | |||
#include "db.h" | |||
#include "events.h" | |||
#include "strings.h" | |||
#include "i18n.h" | |||
#include "threads.h" | |||
#include "unused.h" | |||
char F_SPAM_THREADS = STOPPED; | |||
extern const char string_thread_failure[]; | |||
extern const char string_errmsg_reset[]; | |||
extern const char string_errmsg_prepare[]; | |||
extern const char string_errmsg_clear[]; | |||
static const char string_connect_success[] = _("Connected!\n Server: %s\n Port: %d\n Nick: %s\n Channel: %s\n"); | |||
static const char string_dcc_chat_closed[] = _("DCC %d: chat closed\n"); | |||
static const char string_dcc_chat_failure[] = _("DCC %d: error %s\n"); | |||
static const char string_dcc_chat_request[] = _("DCC chat [%d] requested from '%s' (%s)\n"); | |||
static const char string_dcc_chat_success[] = _("DCC %d: chat connected\n"); | |||
static const char string_dcc_send_file_failure[] = _("File sent error: %d\n"); | |||
static const char string_dcc_send_file_progress[] = _("File sent progress: %d\n"); | |||
static const char string_dcc_send_file_success[] = _("File sent successfully\n"); | |||
static const char string_dcc_send_request[] = _("DCC send [%d] requested from '%s' (%s): %s (%lu bytes)\n"); | |||
static const char string_spam_success[] = _("Spammer thread was started successfully.\n"); | |||
static char say_hi = 1; | |||
@@ -21,6 +38,17 @@ static const char *admins[] = { | |||
static int nadmins = 1; | |||
static int IsAdmin(const char *name) { | |||
int n, rc; | |||
rc = 0; | |||
for (n = 0; n < nadmins; n++) { | |||
rc = !strcmp(name, admins[n]); | |||
if (rc) | |||
break; | |||
} | |||
return rc; | |||
} | |||
THREAD_FUNCTION(gen_spam) { | |||
struct spam_params_t *sp = (struct spam_params_t *)arg; | |||
while (RUNNING == F_SPAM_THREADS) { | |||
@@ -32,8 +60,7 @@ THREAD_FUNCTION(gen_spam) { | |||
return 0; | |||
} | |||
/* XXX this is a nasty shortcut to copy the signature of the other functions | |||
* easily */ | |||
/* XXX this is a nasty shortcut to copy the signature of the other functions easily */ | |||
EVENT_GENERIC_SIGNATURE(start_spam) { | |||
struct irc_ctx_t *ctx; | |||
static struct spam_params_t spam1; | |||
@@ -64,23 +91,23 @@ EVENT_GENERIC_SIGNATURE(start_spam) { | |||
} | |||
EVENT_GENERIC_SIGNATURE(dump_event) { | |||
char buf[1024]; | |||
char buf[BUFSIZ]; | |||
unsigned int cnt; | |||
size_t bufsize, nwritten; | |||
size_t nwritten; | |||
UNUSED(session); | |||
bufsize = sizeof buf; | |||
memset(buf, 0, bufsize); | |||
memset(&buf, 0, BUFSIZ); | |||
nwritten = 0; | |||
cnt = 0; | |||
while (cnt < count && nwritten < (bufsize-1)) { | |||
do { | |||
if (cnt) | |||
nwritten += snprintf(buf + nwritten, 2, "|"); | |||
nwritten += snprintf(buf + nwritten, bufsize - nwritten - 1, "%s", params[cnt]); | |||
nwritten += snprintf(buf + nwritten, BUFSIZ - nwritten - 1, "%s", params[cnt]); | |||
cnt++; | |||
} | |||
buf[nwritten+1] = '\0'; | |||
while (cnt < count && nwritten < (BUFSIZ - 1)); | |||
buf[nwritten + 1] = '\0'; | |||
printf("[%s] %s : [%d] %s\n", event, origin ? origin : "(null)", cnt, buf); | |||
} | |||
@@ -111,20 +138,9 @@ EVENT_NUMERIC_SIGNATURE(irc_event_numeric) { | |||
} | |||
} | |||
int IsAdmin(const char *name) { | |||
int n, rc; | |||
rc = 0; | |||
for (n = 0; n < nadmins; n++) { | |||
rc = !strcmp(name, admins[n]); | |||
if (rc) | |||
break; | |||
} | |||
return rc; | |||
} | |||
EVENT_GENERIC_SIGNATURE(irc_event_channel) { | |||
struct irc_ctx_t *ctx; | |||
char nickbuf[128]; | |||
char buf[BUFSIZ], nickbuf[128]; | |||
UNUSED(event); | |||
UNUSED(params); | |||
@@ -142,7 +158,6 @@ EVENT_GENERIC_SIGNATURE(irc_event_channel) { | |||
} | |||
ctx = (struct irc_ctx_t *)irc_get_ctx(session); | |||
UNUSED(ctx); | |||
if (!strcmp(params[1], ".stop")) { | |||
irc_cmd_msg(session, params[0], ":x"); | |||
@@ -162,6 +177,66 @@ EVENT_GENERIC_SIGNATURE(irc_event_channel) { | |||
irc_cmd_quit(session, "Bye!"); | |||
} | |||
/* TODO sqlite3 .dump command */ | |||
if (!strcmp(params[1], ".dump")) { | |||
} | |||
/* | |||
* .define phrase with words | |||
* .define phrase with words => definition with words | |||
* First form performs a SELECT | |||
* Second form performs an INSERT | |||
*/ | |||
if (params[1] == strstr(params[1], ".define")) { | |||
char *firstword = NULL, *definition = NULL; | |||
firstword = strchr(params[1], ' '); | |||
definition = strstr(params[1], "=>"); | |||
if (NULL != firstword) | |||
firstword++; | |||
else | |||
return; | |||
if (NULL != definition) { | |||
*(definition-1) = '\0'; | |||
definition += 3; | |||
} | |||
else | |||
return; | |||
printf("new define: %s => %s\n", firstword, definition); | |||
if (NULL != firstword && *firstword && NULL != definition && *definition) { | |||
if (SQLITE_OK == insert_new_definition(ctx->db, params[0], nickbuf, firstword, definition)) { | |||
memset(buf, 0, sizeof buf); | |||
snprintf(buf, (sizeof buf) - 1, "Definition for %s added.", firstword); | |||
irc_cmd_msg(session, params[0], buf); | |||
} | |||
} else if (NULL != firstword && *firstword && NULL == definition) { | |||
/* Lookup */ | |||
if (SQLITE_OK == insert_new_definition(ctx->db, params[0], nickbuf, firstword, definition)) { | |||
memset(buf, 0, sizeof buf); | |||
snprintf(buf, (sizeof buf) - 1, "Definition for %s added.", firstword); | |||
irc_cmd_msg(session, params[0], buf); | |||
} | |||
} | |||
} | |||
if (params[1] == strstr(params[1], ".delete")) { | |||
int n; | |||
char *firstword = NULL; | |||
firstword = strchr(params[1], ' '); | |||
n = -1; | |||
if (firstword) { | |||
n = atoi(firstword); | |||
} | |||
if (n > 0 && SQLITE_OK == delete_from_table_by_rowid(ctx->db, n)) { | |||
memset(buf, 0, sizeof buf); | |||
snprintf(buf, (sizeof buf) - 1, "Deleted record %d.", n); | |||
irc_cmd_msg(session, params[0], buf); | |||
} | |||
} | |||
#if 0 | |||
if (ctx->insolents.find(nickbuf) == ctx->insolents.end()) | |||
ctx->insolents[nickbuf] | |||
@@ -248,6 +323,7 @@ EVENT_GENERIC_SIGNATURE(irc_event_nick) { | |||
#endif | |||
} | |||
DCC_RECV_SIGNATURE(dcc_recv_callback) { | |||
static int count = 1; | |||
char buf[12]; | |||
@@ -257,12 +333,12 @@ DCC_RECV_SIGNATURE(dcc_recv_callback) { | |||
switch (status) { | |||
case LIBIRC_ERR_CLOSED: | |||
printf("DCC %d: chat closed\n", id); | |||
printf(string_dcc_chat_closed, id); | |||
break; | |||
case 0: | |||
if (!data) { | |||
printf("DCC %d: chat connected\n", id); | |||
printf(string_dcc_chat_success, id); | |||
irc_dcc_msg(session, id, "Hehe"); | |||
} else { | |||
printf("DCC %d: %s\n", id, data); | |||
@@ -272,13 +348,13 @@ DCC_RECV_SIGNATURE(dcc_recv_callback) { | |||
break; | |||
default: | |||
printf("DCC %d: error %s\n", id, irc_strerror(status)); | |||
printf(string_dcc_chat_failure, id, irc_strerror(status)); | |||
break; | |||
} | |||
} | |||
EVENT_DCC_CHAT_SIGNATURE(irc_event_dcc_chat) { | |||
printf("DCC chat [%d] requested from '%s' (%s)\n", dccid, nick, addr); | |||
printf(string_dcc_chat_request, dccid, nick, addr); | |||
irc_dcc_accept(session, dccid, 0, dcc_recv_callback); | |||
} | |||
@@ -287,25 +363,23 @@ DCC_RECV_SIGNATURE(dcc_file_recv_callback) { | |||
UNUSED(session); | |||
UNUSED(id); | |||
if (status == 0 && length == 0) { | |||
printf("File sent successfully\n"); | |||
printf("%s", string_dcc_send_file_success); | |||
if (ctx) | |||
fclose((FILE *) ctx); | |||
} else if (status) { | |||
printf("File sent error: %d\n", status); | |||
printf(string_dcc_send_file_failure, status); | |||
if (ctx) | |||
fclose((FILE *) ctx); | |||
} else { | |||
if (ctx) | |||
fwrite(data, 1, length, (FILE *) ctx); | |||
printf("File sent progress: %d\n", length); | |||
printf(string_dcc_send_file_progress, length); | |||
} | |||
} | |||
EVENT_DCC_SEND_SIGNATURE(irc_event_dcc_send) { | |||
FILE *fp; | |||
printf("DCC send [%d] requested from '%s' (%s): %s (%lu bytes)\n", dccid, nick, addr, filename, size); | |||
printf(string_dcc_send_request, dccid, nick, addr, filename, size); | |||
if ((fp = fopen("file", "wb")) == 0) | |||
abort(); | |||
@@ -1,47 +1,23 @@ | |||
#ifndef EVENTS_H | |||
#define EVENTS_H | |||
#define DCC_RECV_SIGNATURE(event_name) \ | |||
void event_name (irc_session_t * session, irc_dcc_t id, int status, void * ctx, const char * data, unsigned int length) | |||
#define EVENT_DCC_CHAT_SIGNATURE(event_name) \ | |||
void event_name \ | |||
(irc_session_t * session, \ | |||
const char * nick, \ | |||
const char * addr, \ | |||
irc_dcc_t dccid) | |||
void event_name (irc_session_t * session, const char * nick, const char * addr, irc_dcc_t dccid) | |||
#define EVENT_DCC_SEND_SIGNATURE(event_name) \ | |||
void event_name \ | |||
(irc_session_t * session, \ | |||
const char * nick, \ | |||
const char * addr, \ | |||
const char * filename, \ | |||
unsigned long size, \ | |||
irc_dcc_t dccid) | |||
void event_name (irc_session_t * session, const char * nick, const char * addr, const char * filename, unsigned long size, irc_dcc_t dccid) | |||
#define EVENT_GENERIC_SIGNATURE(event_name) \ | |||
void event_name \ | |||
(irc_session_t * session, \ | |||
const char *event, \ | |||
const char *origin, \ | |||
const char **params, \ | |||
unsigned int count) | |||
void event_name (irc_session_t * session, const char *event, const char *origin, const char **params, unsigned int count) | |||
#define EVENT_NUMERIC_SIGNATURE(event_name) \ | |||
void event_name \ | |||
(irc_session_t * session, \ | |||
unsigned int event, \ | |||
const char *origin, \ | |||
const char **params, \ | |||
unsigned int count) | |||
#define DCC_RECV_SIGNATURE(event_name) \ | |||
void event_name \ | |||
(irc_session_t * session, \ | |||
irc_dcc_t id, \ | |||
int status, \ | |||
void * ctx, \ | |||
const char * data, \ | |||
unsigned int length) | |||
void event_name (irc_session_t * session, unsigned int event, const char *origin, const char **params, unsigned int count) | |||
DCC_RECV_SIGNATURE(dcc_file_recv_callback); | |||
DCC_RECV_SIGNATURE(dcc_recv_callback); | |||
EVENT_DCC_CHAT_SIGNATURE(irc_event_dcc_chat); | |||
EVENT_DCC_SEND_SIGNATURE(irc_event_dcc_send); | |||
EVENT_GENERIC_SIGNATURE(dump_event); | |||
@@ -0,0 +1,6 @@ | |||
#ifndef STRINGS_H | |||
#define STRINGS_H | |||
#define _(x) x | |||
#endif /* STRINGS_H */ |
@@ -59,7 +59,7 @@ 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) { | |||
size_t copy_file(const char *srcname, const char *dstname) { | |||
int rc; | |||
char *buf; | |||
size_t nread, nwrite; | |||
@@ -73,7 +73,7 @@ int copy_file(const char *srcname, const char *dstname) { | |||
} | |||
assert(nread == nwrite); | |||
free(buf); | |||
rc = 0; | |||
rc = nread; | |||
} | |||
return rc; | |||
} |
@@ -6,4 +6,4 @@ | |||
char *file_read(const char *filename, size_t *readSize); | |||
size_t file_write(const char *fileName, const void *data, const size_t size); | |||
#endif /* IO_H */ | |||
#endif /* IO_H */ |
@@ -1,5 +1,5 @@ | |||
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */ | |||
#include <string.h> | |||
#define _POSIX_C_SOURCE 200809L /* strnlen */ | |||
#include <string.h> /* memset */ | |||
#include <stdlib.h> /* malloc */ | |||
#include "levenshtein.h" | |||
@@ -35,7 +35,10 @@ int levenshtein(const char *s, const char *t) { | |||
int i, j, n; | |||
int ls = (int)strnlen(s, 128), lt = (int)strnlen(t, 128); | |||
int *d; | |||
d = (int*)malloc(sizeof(int) * (unsigned long)((ls + 1) * (lt + 1))); | |||
size_t size; | |||
size = sizeof(int) * (unsigned long)((ls + 1) * (lt + 1)); | |||
d = (int *)malloc(size); | |||
memset(d, 0, size); | |||
for (i = 0; i <= ls; i++) | |||
for (j = 0; j <= lt; j++) | |||
*(d + i * ls + j) = -1; | |||
@@ -3,4 +3,4 @@ | |||
int levenshtein(const char *s, const char *t); | |||
#endif /* LEVENSHTEIN_H */ | |||
#endif /* LEVENSHTEIN_H */ |
@@ -34,20 +34,20 @@ | |||
* | |||
* 0. You just DO WHAT THE FUCK YOU WANT TO. | |||
*/ | |||
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */ | |||
#include <string.h> | |||
#include <assert.h> /* assert */ | |||
#include <errno.h> | |||
#include <errno.h> /* strerror */ | |||
#include <getopt.h> /* getopt */ | |||
#include <libircclient.h> | |||
#include <stdio.h> /* size_t */ | |||
#include <string.h> /* memset */ | |||
#include <unistd.h> /* getopt */ | |||
#include "libircclient.h" | |||
#include "data.h" | |||
#include "db.h" | |||
#include "events.h" | |||
#include "levenshtein.h" | |||
#include "strings.h" | |||
#include "i18n.h" | |||
#include "threads.h" | |||
#include "unused.h" | |||
@@ -55,9 +55,20 @@ extern void install_signal_handler(void); | |||
char F_IRC_THREAD = STOPPED; | |||
char F_MAIN_THREAD = STOPPED; | |||
char F_SPAM_THREADS = STOPPED; | |||
char IsIPv6Enabled = 0; | |||
irc_session_t *irc_session = NULL; | |||
const char string_usage_fmt[] = | |||
_("Usage: %s [-46] [-q query] [-d sqlite db] [-h] [-p port] [-f script file] <[-s] server addr> [[-p] server port] <[-n] irc nick> <[-c] irc channel>\n"); | |||
const char string_connect_failure[] = _("Could not connect: %s\n"); | |||
const char string_ircthread_success[] = _("IRC thread was started successfully.\n"); | |||
const char string_opendb_failure[] = _("Can't open database: %s\n"); | |||
const char string_opendb_success[] = _("Open database successfully: %s\n"); | |||
const char string_thread_failure[] = _("CREATE_THREAD failed: %s\n"); | |||
THREAD_FUNCTION(IrcSessionThread) { | |||
int rc; | |||
const char *server; | |||
@@ -82,12 +93,13 @@ THREAD_FUNCTION(IrcSessionThread) { | |||
callbacks.event_numeric = irc_event_numeric; | |||
callbacks.event_privmsg = irc_event_privmsg; | |||
callbacks.event_channel_notice = dump_event; | |||
callbacks.event_ctcp_action = dump_event; | |||
callbacks.event_ctcp_rep = dump_event; | |||
callbacks.event_ctcp_req = dump_event; | |||
callbacks.event_invite = dump_event; | |||
callbacks.event_kick = dump_event; | |||
callbacks.event_mode = dump_event; | |||
callbacks.event_nick = dump_event; | |||
callbacks.event_notice = dump_event; | |||
callbacks.event_part = dump_event; | |||
callbacks.event_quit = dump_event; | |||
@@ -100,6 +112,7 @@ THREAD_FUNCTION(IrcSessionThread) { | |||
if (!irc_session) { | |||
fprintf(stderr, string_connect_failure, irc_strerror(irc_errno(irc_session))); | |||
F_IRC_THREAD = STOPPED; | |||
goto _out; | |||
} | |||
irc_set_ctx(irc_session, ctx); | |||
irc_option_set(irc_session, LIBIRC_OPTION_STRIPNICKS); | |||
@@ -125,12 +138,14 @@ THREAD_FUNCTION(IrcSessionThread) { | |||
if (rc) { | |||
fprintf(stderr, string_connect_failure, irc_strerror(irc_errno(irc_session))); | |||
F_IRC_THREAD = STOPPED; | |||
goto _out; | |||
} | |||
/* and run into forever loop, generating events */ | |||
if (irc_run(irc_session)) { | |||
fprintf(stderr, string_connect_failure, irc_strerror(irc_errno(irc_session))); | |||
F_IRC_THREAD = STOPPED; | |||
} | |||
_out: | |||
irc_destroy_session(irc_session); | |||
irc_session = NULL; | |||
} | |||
@@ -141,37 +156,29 @@ THREAD_FUNCTION(IrcSessionThread) { | |||
return NULL; | |||
#endif | |||
} | |||
int main(int argc, char *argv[]) { | |||
int c; | |||
int rc; | |||
int opt; | |||
const char *db_name; | |||
const char *query_str; | |||
const char *filename; | |||
sqlite3 *db; | |||
int c, opt, rc; | |||
const char *db_name, *filename, *query_str; | |||
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"; | |||
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:46")) != -1) { | |||
switch (opt) { | |||
case '4': | |||
IsIPv6Enabled = 0; | |||
break; | |||
case '6': | |||
IsIPv6Enabled = 1; | |||
break; | |||
case '4': | |||
IsIPv6Enabled = 0; | |||
break; | |||
case '6': | |||
IsIPv6Enabled = 1; | |||
break; | |||
case 'c': | |||
ctx.channel = optarg; | |||
break; | |||
@@ -200,57 +207,58 @@ int main(int argc, char *argv[]) { | |||
break; | |||
} | |||
} | |||
if (NULL != db_name) { | |||
if (SQLITE_OK == (rc = sqlite3_open(db_name, &db))) { | |||
printf("%s", string_opendb_success); | |||
sqlite_version(db); | |||
} | |||
} else { | |||
fprintf(stderr, string_opendb_failure, sqlite3_errmsg(db)); | |||
rc = sqlite3_open(db_name, &ctx.db); | |||
if (rc != SQLITE_OK) { | |||
fprintf(stderr, string_opendb_failure, sqlite3_errmsg(ctx.db)); | |||
return -1; | |||
} | |||
} else { | |||
printf(string_opendb_success, db_name); | |||
sqlite_version(ctx.db); | |||
/*run_one(db, create_db_query);*/ | |||
printf("%d\n", table_exists(ctx.db, run_script_callback, "dictionarydb")); | |||
if (NULL != query_str) { | |||
rc = run_one(db, query_str); | |||
} else if (NULL != filename) { | |||
rc = run_script(db, filename); | |||
} else if (argc == 4) { | |||
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) { | |||
if (NULL != query_str) { | |||
rc = run_one(ctx.db, run_script_callback, query_str); | |||
} else if (NULL != filename) { | |||
rc = run_script(ctx.db, run_script_callback, filename); | |||
} else if (optind < argc) { | |||
ctx.server = argv[optind++]; | |||
if (optind < argc) | |||
ctx.nick = argv[optind++]; | |||
if (optind < argc) | |||
ctx.channel = argv[optind++]; | |||
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_thread_failure, strerror(errno)); | |||
} else { | |||
printf("%s", string_ircthread_success); | |||
} | |||
while (RUNNING == F_MAIN_THREAD) { | |||
sleep(1); | |||
/* TODO separare thread to monitor input, I'd also like to be | |||
* able to restart / reconnect, I think that may happen in here */ | |||
c = getchar(); | |||
if ('q' == c) { | |||
if (irc_session) | |||
irc_cmd_quit(irc_session, "Bye!"); | |||
F_MAIN_THREAD = STOPPED; | |||
} | |||
} | |||
F_IRC_THREAD = STOPPED; | |||
F_SPAM_THREADS = STOPPED; | |||
rc = 0; | |||
} else { | |||
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_thread_failure, strerror(errno)); | |||
} else { | |||
printf("%s", string_ircthread_success); | |||
} | |||
while (RUNNING == F_MAIN_THREAD) { | |||
sleep(1); | |||
c = getchar(); | |||
if ('q' == c) { | |||
if (irc_session) | |||
irc_cmd_quit(irc_session, "Bye!"); | |||
F_MAIN_THREAD = STOPPED; | |||
} | |||
} | |||
F_IRC_THREAD = STOPPED; | |||
F_SPAM_THREADS = STOPPED; | |||
rc = 0; | |||
} else { | |||
fprintf(stderr, string_usage_fmt, argv[0]); | |||
return -1; | |||
} | |||
sqlite3_close(db); | |||
sqlite3_close(ctx.db); | |||
return rc; | |||
} |
@@ -16,17 +16,23 @@ OPT := -ggdb -O0 | |||
ifeq ($(O),1) | |||
OPT := -g -O1 | |||
else ifeq ($(O),2) | |||
OPT := -g0 -O2 | |||
else ifeq ($(O),s) | |||
OPT := -g0 -Os | |||
endif | |||
ifeq ($(O),2) | |||
OPT := -g0 -O2 | |||
ifeq ($(LTO),1) | |||
LDFLAGS += -funroll-loops -flto -fwhole-program | |||
endif | |||
ifeq ($(O),s) | |||
OPT := -g0 -Os | |||
ifeq ($(PROF),1) | |||
DEBUG += --coverage -pg | |||
LDFLAGS += -lgcov | |||
endif | |||
FLAGS := -D_FORTIFY_SOURCE=2 -fasynchronous-unwind-tables -fexceptions -fpie -Wl,-pie -fpic -fstack-clash-protection -fstack-protector-all -fstack-protector-strong -g -grecord-gcc-switches -fcf-protection -pipe -Wformat -Werror=format-security -Werror=implicit-function-declaration -Wl,-z,defs -Wl,-z,now -Wl,-z,relro | |||
F := -Wl,-z,defs -Wl,-z,now -Wl,-z,relro -fpie -Wl,-pie -fpic -fstack-clash-protection -fstack-protector-all -fstack-protector-strong | |||
FLAGS := -D_FORTIFY_SOURCE=2 -fasynchronous-unwind-tables -fexceptions -g -grecord-gcc-switches -fcf-protection -pipe -Wformat -Werror=format-security -Werror=implicit-function-declaration | |||
CFLAGS += $(FLAGS) | |||
LDFLAGS += $(FLAGS) | |||
@@ -1,12 +1,24 @@ | |||
#include <signal.h> /* signal */ | |||
#include <stdio.h> /* fprintf */ | |||
#include <string.h> /* memset */ | |||
#include "libircclient.h" | |||
#include <libircclient.h> | |||
#include "threads.h" /* F_* */ | |||
#include "strings.h" | |||
#include "i18n.h" | |||
#ifdef BUFSIZ | |||
#undef BUFSIZ | |||
#endif | |||
#define BUFSIZ 127 | |||
extern irc_session_t *irc_session; | |||
static const char string_signal_recv_fmt[] = _("Received %s, exiting.\n"); | |||
static const char string_signal_unknown_fmt[] = _("(Unknown Signal)"); | |||
static void SignalHandler(int sig) { | |||
char buf[512]; | |||
char buf[BUFSIZ+1]; | |||
const char *s = string_signal_unknown_fmt; | |||
#define CASE(x) case x: s = #x; break | |||
switch (sig) { | |||
@@ -21,16 +33,20 @@ static void SignalHandler(int sig) { | |||
break; | |||
} | |||
#undef CASE | |||
memset(&buf, 0, sizeof buf); | |||
snprintf(buf, (sizeof buf) - 1, string_signal_fmt, s); | |||
memset(&buf, 0, BUFSIZ+1); | |||
snprintf(buf, BUFSIZ, string_signal_recv_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); | |||
@@ -1,24 +0,0 @@ | |||
#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_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_usage_fmt[] = "Usage: %s [-46] [-q query] [-d sqlite db] [-h] [-p port] [-f script file] <[-s] server addr> [[-p] server port] <[-n] irc name> <[-c] irc channel>\n"; | |||
const char string_spam_success[] = "Spammer thread was started successfully.\n"; | |||
const char string_ircthread_success[] = "IRC thread was started successfully.\n"; | |||
const char string_thread_failure[] = "CREATE_THREAD failed: %s\n"; |
@@ -1,31 +0,0 @@ | |||
#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_usage_fmt[]; | |||
/* Threads */ | |||
extern const char string_spam_success[]; | |||
extern const char string_ircthread_success[]; | |||
/* Generic thread failure */ | |||
extern const char string_thread_failure[]; | |||
#endif /* STRINGS_H */ |