Compare commits
7 Commits
master
...
WIP-11-Mar
Author | SHA1 | Date | |
---|---|---|---|
|
856d8132b5 | ||
|
90f6bdbb7a | ||
|
542e8395ef | ||
|
823330dde9 | ||
|
eb77e1ac0e | ||
|
61ba8a692f | ||
|
60dbee40e3 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
spammer
|
||||
*.o
|
||||
sqlite3*
|
||||
*.sqlite3
|
13
LICENSE
Normal file
13
LICENSE
Normal 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.
|
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# 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.
|
||||
|
||||
# TODO
|
||||
|
||||
- Perhaps a database backend and a client frontend that's separate.
|
||||
- SQL schema
|
||||
- SQL interface
|
||||
- Option arguments w/ getopt
|
||||
- Exit codes
|
||||
|
||||
# Extras
|
||||
|
||||
You can unzip the SQLite amalgamation right into here to use it,
|
||||
otherwise, provide INLINE_SQLITE=0:
|
||||
|
||||
make INLINE_SQLITE=1
|
36
data.h
Normal file
36
data.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef DATA_H
|
||||
#define DATA_H
|
||||
|
||||
/*
|
||||
* We store data in IRC session context.
|
||||
*/
|
||||
struct irc_ctx_t {
|
||||
unsigned short port;
|
||||
char *channel;
|
||||
char *nick;
|
||||
char *server;
|
||||
};
|
||||
|
||||
/*
|
||||
* Params that we give to our threads.
|
||||
*/
|
||||
struct spam_params_t {
|
||||
irc_session_t *session;
|
||||
const char *phrase;
|
||||
const char *channel;
|
||||
int timer;
|
||||
int unused;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
188
db.c
Normal file
188
db.c
Normal file
@ -0,0 +1,188 @@
|
||||
/* <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> /* free */
|
||||
#include "io.h"
|
||||
#include "strings.h"
|
||||
#include "unused.h"
|
||||
|
||||
struct params {
|
||||
int type;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
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) {
|
||||
int i;
|
||||
UNUSED(NotUsed);
|
||||
for (i = 0; i < argc; i++) {
|
||||
printf(" => %s = %s\n", azColName[i], (argv[i] ? argv[i] : "NULL"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int run_script(sqlite3 * db, const char *script_filename) {
|
||||
int rc;
|
||||
char *statements, *zErrMsg;
|
||||
zErrMsg = 0;
|
||||
if (!(statements = file_read(script_filename, NULL))) {
|
||||
fprintf(stderr, string_errmsg_readfile, script_filename);
|
||||
return -1;
|
||||
}
|
||||
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, run_script_callback, 0, &zErrMsg);
|
||||
if (SQLITE_OK != rc) {
|
||||
fprintf(stderr, " !! SQL error: %s\n", sqlite3_errmsg(db));
|
||||
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));
|
||||
}
|
||||
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;
|
||||
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, 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, 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, string_errmsg_update, sqlite3_errmsg(db));
|
||||
}
|
||||
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) {
|
||||
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, 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, 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));
|
||||
}
|
||||
if (SQLITE_OK != (rc = sqlite3_reset(stmt))) {
|
||||
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, 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));
|
||||
}
|
||||
return sqlite3_finalize(stmt);
|
||||
}
|
12
db.h
Normal file
12
db.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#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 *);
|
||||
int sqlite_version(sqlite3 *);
|
||||
int update_one(sqlite3 *, int, const char *, const char *);
|
||||
|
||||
#endif /* DB_H */
|
8
dictionary.sql
Normal file
8
dictionary.sql
Normal 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
|
235
events.c
Normal file
235
events.c
Normal file
@ -0,0 +1,235 @@
|
||||
#include <string.h>
|
||||
#include <assert.h> /* assert */
|
||||
#include <errno.h>
|
||||
#include <stdio.h> /* size_t */
|
||||
|
||||
#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) {
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
struct irc_ctx_t *ctx;
|
||||
|
||||
UNUSED(event);
|
||||
UNUSED(origin);
|
||||
UNUSED(params);
|
||||
UNUSED(count);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
struct irc_ctx_t *ctx;
|
||||
char nickbuf[128];
|
||||
|
||||
UNUSED(event);
|
||||
UNUSED(params);
|
||||
UNUSED(count);
|
||||
|
||||
dump_event(session, event, origin, params, count);
|
||||
|
||||
if (NULL == origin || count < 2)
|
||||
return;
|
||||
|
||||
irc_target_get_nick(origin, nickbuf, sizeof(nickbuf));
|
||||
|
||||
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]
|
||||
= 0;
|
||||
|
||||
ctx->insolents[nickbuf]++;
|
||||
|
||||
printf("'%s' swears in the channel '%s' %d times\n", nickbuf, params[1], ctx->insolents[nickbuf]);
|
||||
|
||||
switch (ctx->insolents[nickbuf]) {
|
||||
case 1:
|
||||
// Send a private message
|
||||
sprintf(text, "%s, please do not swear in this channel.", nickbuf);
|
||||
irc_cmd_msg(session, nickbuf, text);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Send a channel message
|
||||
sprintf(text, "%s, do not swear in this channel, or you'll leave it.", nickbuf);
|
||||
irc_cmd_msg(session, params[0], text);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Send a channel notice, and kick the insolent
|
||||
sprintf(text, "kicked %s from %s for swearing.", nickbuf, params[0]);
|
||||
irc_cmd_me(session, params[0], text);
|
||||
irc_cmd_kick(session, nickbuf, params[0], "swearing");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EVENT_SIGNATURE(event_join) {
|
||||
char buf[128];
|
||||
struct irc_ctx_t *ctx;
|
||||
|
||||
UNUSED(count);
|
||||
UNUSED(event);
|
||||
|
||||
if (!origin)
|
||||
return;
|
||||
|
||||
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)) {
|
||||
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];
|
||||
struct irc_ctx_t *ctx;
|
||||
|
||||
UNUSED(event);
|
||||
UNUSED(params);
|
||||
|
||||
if (!origin || count != 1)
|
||||
return;
|
||||
|
||||
irc_target_get_nick(origin, nickbuf, sizeof(nickbuf));
|
||||
ctx = (struct irc_ctx_t *)irc_get_ctx(session);
|
||||
UNUSED(ctx);
|
||||
|
||||
#if 0
|
||||
if (ctx->insolents.find(nickbuf) != ctx->insolents.end()) {
|
||||
printf("%s has changed its nick to %s to prevent penalties - no way!\n", nickbuf, params[0]);
|
||||
ctx->insolents[params[0]] = ctx->insolents[nickbuf];
|
||||
ctx->insolents.erase(nickbuf);
|
||||
}
|
||||
#endif
|
||||
}
|
27
events.h
Normal file
27
events.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef EVENTS_H
|
||||
#define EVENTS_H
|
||||
|
||||
#define EVENT_SIGNATURE(event_name) \
|
||||
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)
|
||||
|
||||
|
||||
EVENT_NUMERIC_SIGNATURE(event_numeric);
|
||||
EVENT_SIGNATURE(event_channel);
|
||||
EVENT_SIGNATURE(event_connect);
|
||||
EVENT_SIGNATURE(event_join);
|
||||
EVENT_SIGNATURE(event_nick);
|
||||
|
||||
#endif /* EVENTS_H */
|
79
io.c
Normal file
79
io.c
Normal file
@ -0,0 +1,79 @@
|
||||
#include <assert.h> /* assert */
|
||||
#include <stdio.h> /* FILE* */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <unistd.h> /* unlink */
|
||||
|
||||
#include "io.h"
|
||||
|
||||
/* <https://rosettacode.org/wiki/Read_entire_file#C> */
|
||||
char *file_read(const char *filename, size_t *readSize) {
|
||||
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);
|
||||
if (size > 0)
|
||||
buffer = (char *)malloc((size_t)size);
|
||||
if (buffer != NULL) {
|
||||
assert(buffer != NULL);
|
||||
nread = fread(buffer, 1, (size_t)size, fh);
|
||||
fclose(fh);
|
||||
fh = NULL;
|
||||
if (size != (long)nread) {
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
assert(size == (long)nread);
|
||||
if (NULL != readSize) {
|
||||
*readSize = 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
9
io.h
Normal file
9
io.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef IO_H
|
||||
#define IO_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
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 */
|
46
levenshtein.c
Normal file
46
levenshtein.c
Normal file
@ -0,0 +1,46 @@
|
||||
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* malloc */
|
||||
|
||||
#include "levenshtein.h"
|
||||
|
||||
/* <https://rosettacode.org/wiki/Levenshtein_distance#C>
|
||||
* TODO: use this for quote duplicate removal */
|
||||
static int levenshtein_dist(const char *s, const char *t, int *d, int ls, int lt, int i, int j) {
|
||||
int x, y;
|
||||
int *n = d + i * ls + j;
|
||||
|
||||
if (*n >= 0)
|
||||
return *n;
|
||||
|
||||
if (i == ls)
|
||||
x = lt - j;
|
||||
else if (j == lt)
|
||||
x = ls - i;
|
||||
else if (s[i] == t[j])
|
||||
x = levenshtein_dist(s, t, d, ls, lt, i + 1, j + 1);
|
||||
else {
|
||||
x = levenshtein_dist(s, t, d, ls, lt, i + 1, j + 1);
|
||||
|
||||
if ((y = levenshtein_dist(s, t, d, ls, lt, i, j + 1)) < x)
|
||||
x = y;
|
||||
if ((y = levenshtein_dist(s, t, d, ls, lt, i + 1, j)) < x)
|
||||
x = y;
|
||||
x++;
|
||||
}
|
||||
return *n = x;
|
||||
}
|
||||
|
||||
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)));
|
||||
for (i = 0; i <= ls; i++)
|
||||
for (j = 0; j <= lt; j++)
|
||||
*(d + i * ls + j) = -1;
|
||||
n = levenshtein_dist(s, t, d, ls, lt, 0, 0);
|
||||
free(d);
|
||||
d = NULL;
|
||||
return n;
|
||||
}
|
6
levenshtein.h
Normal file
6
levenshtein.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef LEVENSHTEIN_H
|
||||
#define LEVENSHTEIN_H
|
||||
|
||||
int levenshtein(const char *s, const char *t);
|
||||
|
||||
#endif /* LEVENSHTEIN_H */
|
217
main.c
Normal file
217
main.c
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#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 "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;
|
||||
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;
|
||||
struct irc_ctx_t *ctx;
|
||||
irc_callbacks_t callbacks;
|
||||
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));
|
||||
/* Set up the callbacks we will use */
|
||||
callbacks.event_channel = event_channel;
|
||||
callbacks.event_connect = event_connect;
|
||||
callbacks.event_join = event_join;
|
||||
callbacks.event_nick = event_nick;
|
||||
callbacks.event_numeric = event_numeric;
|
||||
/* And create the IRC session; 0 means error */
|
||||
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(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)
|
||||
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
|
||||
*/
|
||||
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(irc_session, LIBIRC_OPTION_SSL_NO_VERIFY);
|
||||
}
|
||||
/* Initiate the IRC server connection */
|
||||
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(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;
|
||||
}
|
||||
F_MAIN_THREAD = STOPPED;
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
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";
|
||||
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':
|
||||
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':
|
||||
ctx.server = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
fprintf(stderr, string_usage_fmt, argv[0]);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL != db_name) {
|
||||
if (SQLITE_OK == (rc = sqlite3_open(db_name, &db))) {
|
||||
printf(string_opendb_success);
|
||||
sqlite_version(db);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, string_opendb_failure, sqlite3_errmsg(db));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*run_one(db, create_db_query);*/
|
||||
|
||||
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) {
|
||||
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 {
|
||||
fprintf(stderr, string_usage_fmt, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
return rc;
|
||||
}
|
43
makefile
Normal file
43
makefile
Normal file
@ -0,0 +1,43 @@
|
||||
INLINE_SQLITE ?= 0
|
||||
WARN := -W -Wall -Wextra -pedantic -pedantic-errors
|
||||
|
||||
CC ?= gcc
|
||||
|
||||
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
|
||||
$(CC) -c $< -o $@ $(LDFLAGS)
|
||||
|
||||
spammer: $(OBJ)
|
||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) -rf spammer db a.out *.o *.db *.sqlite3 *.exe *.dll
|
10
script.sql
Normal file
10
script.sql
Normal 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
|
13
script2.sql
Normal file
13
script2.sql
Normal file
@ -0,0 +1,13 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
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)
|
||||
|
||||
insert into quotedb (date_added, channel, added_by, subject, words) values (datetime('now'), '#lainchan', 'strike', 'Flisk', "<Flisk> yeah hate when hookers who give free blowjobs won't finger my asshole for free too")
|
||||
insert into quotedb (date_added, channel, added_by, subject, words) values (datetime('now'), '#lainchan', 'oda', 'nimbius', '* nimbius is no longer thinking about those beans')
|
||||
|
||||
select * from quotedb
|
||||
|
||||
COMMIT;
|
||||
|
||||
--delete from quotedb
|
||||
--drop table quotedb
|
42
signal.c
Normal file
42
signal.c
Normal 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
25
strings.c
Normal 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
28
strings.h
Normal 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 */
|
27
threads.h
Normal file
27
threads.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef THREADS_H
|
||||
#define THREADS_H
|
||||
|
||||
#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
|
||||
|
||||
enum {
|
||||
RUNNING,
|
||||
STOPPED,
|
||||
};
|
||||
|
||||
extern char F_IRC_THREAD;
|
||||
extern char F_MAIN_THREAD;
|
||||
extern char F_SPAM_THREADS;
|
||||
|
||||
#endif /* THREADS_H */
|
Loading…
Reference in New Issue
Block a user