Initial code commit.

It doesn't do anything useful.
This commit is contained in:
Bubblegumdrop 2021-03-08 16:59:27 -05:00
parent 2209d5d880
commit 60dbee40e3
8 changed files with 446 additions and 0 deletions

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# The (un)Official Lain's Diction Book
Quote / Definition / Pastebin bot
it takes text from irc and stores it in a database
13:56 <@kashire> We need to make our own dictionary.
13:56 <@kashire> The (un)Official Lain's Diction Book.

89
db.c Normal file
View File

@ -0,0 +1,89 @@
/* <https://gist.github.com/enile8/2424514> */
#include <assert.h> /* assert */
#include <sqlite3.h>
#include <stdio.h> /* size_t */
#include <stdlib.h> /* malloc */
#include <string.h> /* strdup */
/* TODO: libircclient for basic IRC functionality.
* Perhaps a database backend and a client frontend that's separate. */
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#include "io.c"
static int 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"));
}
return 0;
}
int test_db(char *script_filename) {
char *orig_statements;
char *saveptr1;
char *statements;
char *str1, *token;
char *zErrMsg;
const char *db_name;
int j;
int rc;
int nstatements;
sqlite3 *db;
nstatements = 0;
zErrMsg = 0;
orig_statements = file_read(script_filename);
if (orig_statements) {
statements = strndup(orig_statements, 4096);
} else {
fprintf(stderr, "Error reading file: %s\n", script_filename);
return -1;
}
db_name = "familyGuy.db";
rc = sqlite3_open(db_name, &db);
if (rc) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
} else {
fprintf(stderr, "Open database successfully\n");
}
for (j = 1, str1 = statements;; j++, str1 = NULL) {
token = strtok_r(str1, "\n", &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
rc = sqlite3_exec(db, token, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
sqlite3_free(zErrMsg);
break;
}
nstatements++; /* Number of successfully executed statements */
}
free(orig_statements);
free(statements);
sqlite3_close(db);
fprintf(stderr, "Bye!\n");
return 0;
}
#ifdef TEST_DB
int main(int argc, char **argv) {
char *script_filename;
if (argc > 1) {
script_filename = argv[1];
} else {
fprintf(stderr, "Usage: %s <script>\n", argv[0]);
return -1;
}
return test_db(script_filename);
}
#endif

53
io.c Normal file
View File

@ -0,0 +1,53 @@
#include <assert.h> /* assert */
#include <stdio.h> /* FILE* */
#include <stdlib.h> /* malloc, free */
/* <https://rosettacode.org/wiki/Read_entire_file#C> */
char *file_read(const char *filename) {
char *buffer;
FILE *fh;
long size;
size_t nread;
assert(filename != NULL);
buffer = NULL;
fh = fopen(filename, "rb");
if (fh != NULL) {
fseek(fh, 0L, SEEK_END);
size = ftell(fh);
rewind(fh);
buffer = malloc(size);
if (buffer != NULL) {
assert(buffer != NULL);
nread = fread(buffer, 1, size, fh);
fclose(fh);
fh = NULL;
if (size != (long)nread) {
free(buffer);
buffer = NULL;
}
assert(size == (long)nread);
}
if (fh != NULL)
fclose(fh);
}
return buffer;
}
/* <https://www.rosettacode.org/wiki/Write_entire_file#C> */
size_t file_write(const char *fileName, const void *data, const size_t size) {
size_t numberBytesWritten = 0;
FILE *file;
assert(fileName != NULL);
assert(data != NULL);
assert(size > 0);
if (fileName != NULL && *fileName != '\0') {
file = fopen(fileName, "wb");
if (file != NULL) {
if (data != NULL) {
numberBytesWritten = fwrite(data, 1, size, file);
}
fclose(file);
}
}
return numberBytesWritten;
}

14
makefile Normal file
View File

@ -0,0 +1,14 @@
CFLAGS += -ggdb -O0 -std=c89 -W -Wall -Wextra -pedantic
LDFLAGS += -lpthread -lircclient -lsqlite3
all: spammer
spammer: spammer.c
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
# TODO: client side / offline access
db: db.c
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) -DTEST_DB
clean:
$(RM) -rf spammer db a.out *.o *.db

10
script.sql Normal file
View File

@ -0,0 +1,10 @@
create table myTable (FirstName varchar(30), LastName varchar(30), Age smallint, Hometown varchar(30), Job varchar(30))
insert into myTable (FirstName, LastName, Age, Hometown, Job) values ('Peter', 'Griffin', 41, 'Quahog', 'Brewery')
insert into myTable (FirstName, LastName, Age, Hometown, Job) values ('Lois', 'Griffin', 40, 'Newport', 'Piano Teacher')
insert into myTable (FirstName, LastName, Age, Hometown, Job) values ('Joseph', 'Swanson', 39, 'Quahog', 'Police Officer')
insert into myTable (FirstName, LastName, Age, Hometown, Job) values ('Glenn', 'Quagmire', 41, 'Quahog', 'Pilot')
select * from myTable
delete from myTable
drop table myTable

9
script2.sql Normal file
View File

@ -0,0 +1,9 @@
create table if not exists quotedb (date_added text not null, added_by text not null, subject text not null, words text not null)
insert into quotedb (date_added, added_by , subject, words) values (datetime('now'), 'strike', 'Flisk', "<Flisk> yeah hate when hookers who give free blowjobs won't finger my asshole for free too")
insert into quotedb (date_added, added_by , subject, words) values (datetime('now'), 'oda', 'nimbius', ' * nimbius is no longer thinking about those beans')
select * from quotedb
delete from quotedb
drop table quotedb

250
spammer.c Normal file
View File

@ -0,0 +1,250 @@
/* 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
*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
* Copyright (C) 2021 Bubblegumdrop <Bubblegumdrop@lain.church>
*
* This example is free, and not covered by LGPL license. There is no
* restriction applied to their modification, redistribution, using and so on.
* You can study them, modify them, use them in your own program - either
* completely or partially. By using it you may give me some credits in your
* program, but you don't have to.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* Version 2, December 2004
*
* Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
* Copyright (C) 2021 Bubblegumdrop <Bubblegumdrop@lain.church>
*
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* Quote bot. WIP.
*/
#define _XOPEN_SOURCE 500 /* strdup */
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */
#include <string.h>
#include <assert.h> /* assert */
#include <errno.h>
#include <stdio.h> /* size_t */
#include <stdlib.h> /* malloc */
/* TODO: libircclient for basic IRC functionality.
* Perhaps a database backend and a client frontend that's separate. */
#if defined (_WIN32)
#include <windows.h>
#define CREATE_THREAD(id,func,param) (CreateThread(0, 0, func, param, 0, id) == 0)
#define THREAD_FUNCTION(funcname) static DWORD WINAPI funcname (LPVOID arg)
#define thread_id_t DWORD
#define sleep(a) Sleep (a*1000)
#else
#include <unistd.h>
#include <pthread.h>
#define CREATE_THREAD(id,func,param) (pthread_create (id, 0, func, (void *) param) != 0)
#define THREAD_FUNCTION(funcname) static void * funcname (void * arg)
#define thread_id_t pthread_t
#endif
#include "libircclient.h"
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
/*
* We store data in IRC session context.
*/
typedef struct {
char *channel;
char *nick;
} irc_ctx_t;
/*
* Params that we give to our threads.
*/
typedef struct {
irc_session_t *session;
const char *phrase;
const char *channel;
int timer;
} spam_params_t;
#include "db.c"
/* <https://rosettacode.org/wiki/Levenshtein_distance#C>
* TODO: use this for quote duplicate removal */
int dist(const char *s, const char *t, int *d, int ls, int lt, int i, int j) {
int x, y;
if (*(d + i * ls + j) >= 0)
return *(d + i * ls + j);
if (i == ls)
x = lt - j;
else if (j == lt)
x = ls - i;
else if (s[i] == t[j])
x = dist(s, t, d, ls, lt, i + 1, j + 1);
else {
x = dist(s, t, d, ls, lt, i + 1, j + 1);
if ((y = dist(s, t, d, ls, lt, i, j + 1)) < x)
x = y;
if ((y = dist(s, t, d, ls, lt, i + 1, j)) < x)
x = y;
x++;
}
return *(d + i * ls + j) = x;
}
int levenshtein(const char *s, const char *t) {
int i, j, n;
int ls = strnlen(s, 128), lt = strnlen(t, 128);
int *d;
d = malloc(sizeof(int) * ((ls + 1) * (lt + 1)));
for (i = 0; i <= ls; i++)
for (j = 0; j <= lt; j++)
*(d + i * ls + j) = -1;
n = dist(s, t, d, ls, lt, 0, 0);
free(d);
d = NULL;
return n;
}
THREAD_FUNCTION(gen_spam) {
spam_params_t *sp = (spam_params_t *) arg;
while (1) {
if (irc_cmd_msg(sp->session, sp->channel, sp->phrase))
break;
sleep(sp->timer);
}
return 0;
}
void event_join(irc_session_t * session, const char *event, const char *origin, const char **params, unsigned int count) {
irc_ctx_t *ctx;
UNUSED(count);
UNUSED(event);
if (!origin)
return;
ctx = (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);
}
}
void event_connect(irc_session_t * session, const char *event, const char *origin, const char **params, unsigned int count) {
irc_ctx_t *ctx;
UNUSED(event);
UNUSED(origin);
UNUSED(params);
UNUSED(count);
ctx = (irc_ctx_t *) irc_get_ctx(session);
irc_cmd_join(session, ctx->channel, 0);
}
void event_numeric(irc_session_t * session, unsigned int event, const char *origin, const char **params, unsigned int count) {
UNUSED(session);
UNUSED(origin);
UNUSED(params);
UNUSED(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 main(int argc, char **argv) {
char *script_filename;
irc_callbacks_t callbacks;
irc_ctx_t ctx;
irc_session_t *s;
unsigned short port = 6667;
const char *s1 = "rosettacode";
const char *s2 = "raisethysword";
printf("distance between `%s' and `%s': %d\n", s1, s2, levenshtein(s1, s2));
/* TODO: getopt */
if (argc == 2) {
script_filename = argv[1];
return test_db(script_filename);
} else {
if (argc != 4) {
printf("Usage: %s <server> <nick> <channel>\n", argv[0]);
return 1;
}
}
/* Initialize the callbacks */
memset(&callbacks, 0, sizeof(callbacks));
/* Set up the callbacks we will use */
callbacks.event_connect = event_connect;
callbacks.event_join = event_join;
callbacks.event_numeric = event_numeric;
ctx.channel = argv[3];
ctx.nick = argv[2];
/* And create the IRC session; 0 means error */
s = irc_create_session(&callbacks);
if (!s) {
printf("Could not create IRC session\n");
return 1;
}
irc_set_ctx(s, &ctx);
irc_option_set(s, LIBIRC_OPTION_STRIPNICKS);
/* If the port number is specified in the server string, use the port 0 so it gets parsed */
if (strchr(argv[1], ':') != 0)
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
*/
if (argv[1][0] == '#' && argv[1][1] == '#') {
/* Skip the first character as libircclient needs only one # for SSL support, i.e. #irc.freenode.net */
argv[1]++;
irc_option_set(s, LIBIRC_OPTION_SSL_NO_VERIFY);
}
/* Initiate the IRC server connection */
if (irc_connect(s, argv[1], port, 0, argv[2], 0, 0)) {
printf("Could not connect: %s\n", irc_strerror(irc_errno(s)));
return 1;
}
/* 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 1;
}
return 1;
}