#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <avl.h>
#include "interface.h"
#include "lang.h"
#include "larts.h"
#include "mt19937ar.h"
#include "spreek.h"
#include "string.h"
#include "tab.h"
#include "worker.h"
struct apprecidata {
struct db *db;
presence_t p;
const char *perp;
const char *victim;
const char *iemand;
const char *anders;
};
static void recurse_appreciate(format_t *f, splitbuf_t *q, const char *app, void *userdata) {
char *message;
struct apprecidata *ap = userdata;
if(db_larts_appreciate(ap->db, ap->perp, ap->victim, app, language, &message)) {
if(message && *message)
format_print(f, q, message);
}
}
static void recurse_fallback(format_t *f, splitbuf_t *q, const char *app, void *userdata) {
struct apprecidata *ap = userdata;
const char *str = NULL;
const char *fallback = NULL;
presence_t p = ap->p;
if(!app)
return;
switch(*app) {
case 'u':
str = p.nick
? p.nick->fullname ?: p.nick->user ? p.nick->user->name
: p.nick->name : NULL,
fallback = "iemand";
break;
case 'r':
str = ap->iemand;
fallback = "iemand";
break;
case 'R':
str = ap->anders;
fallback = "iemand_anders";
break;
case 'S':
if(p.chan) {
if(!stricmp(ap->victim, f00fnick))
fallback = "zichzelf";
} else {
if(!stricmp(ap->victim, p.nick->name))
fallback = "je";
}
if(!fallback)
str = ap->victim;
break;
}
if(str)
qstrcat(q, str);
else if(fallback)
recurse_appreciate(f, q, fallback, ap);
}
static void hook_bereken(struct formatitem *fi, splitbuf_t *q, const char *app, void *_) {
echt_t r;
r = bereken(app);
if(!isfout(r))
spreek_echt(q, r);
}
static void appreciate_zoekrandomlui(struct apprecidata *ap) {
unsigned int n, r;
nick_t *f, *k, *s;
chan_t *c;
presence_t p = ap->p;
f = getnick(f00fnick);
s = getnick(ap->victim);
c = p.chan;
n = avl_count(&c->nicks);
if(n) {
// random persoon in kanaal (maar niet f00f):
r = 0;
if(f && avl_search(&c->nicks, f))
r++;
k = avl_at(&c->nicks, mt_genrand32_bounded(0, n - r))->item;
if(k == f)
k = c->nicks.tail->item;
ap->iemand = k->name;
// random persoon in kanaal (maar niet f00f of slachtoffer):
if(s && s != f && avl_search(&c->nicks, s))
r++;
k = avl_at(&c->nicks, mt_genrand32_bounded(0, n - r))->item;
if(r >= 1 && (k == f || k == s))
k = c->nicks.tail->item;
if(r == 2 && (k == f || k == s))
k = c->nicks.tail->prev->item;
ap->anders = k->name;
}
}
static splitbuf_t *getappreciate(const char *nick, presence_t p, const char *arg, const char *app, format_t *fmt) {
const char *perp;
splitbuf_t *q;
struct apprecidata ap = {0};
format_recurse_t f_a, r_a = format_recurse_0;
arg = arg ? fixnick(arg) : p.nick->name;
perp = p.nick->user ? p.nick->user->name : p.nick->name;
ap.p = p;
ap.perp = perp;
ap.victim = arg;
if(p.chan)
appreciate_zoekrandomlui(&ap);
ap.db = db_begin(tmp);
if(!ap.db)
return NULL;
r_a.format = fmt;
r_a.hook = recurse_appreciate;
r_a.userdata = ≈
f_a = r_a;
f_a.hook = recurse_fallback;
format_provide_str(fmt,
's', arg, // slachtoffer
't', target(p), // target van message
'a', p.nick->name, // aanroeper
'f', nick, // nick van f00f
'U', perp,
'B', "\002",
'C', "\003",
'G', "\007",
'O', "\017",
'_', "\037",
0);
format_provide_recurse(fmt,
'(', &r_a, // recursive appreciate
'r', &f_a, // random persoon in kanaal (maar niet f00f)
'R', &f_a, // random persoon in kanaal (maar niet f00f of slachtoffer)
'S', &f_a, // slachtoffer (of "zichzelf" indien f00f)
'u', &f_a, // username van aanroeper
0);
format_provide_hook(fmt, '[', hook_bereken, 0, 0);
q = qnew();
recurse_appreciate(fmt, q, app, &ap);
splitbuf_finish(q);
return db_commit(ap.db) && q->lines.head ? q : NULL;
}
bool ventrilofeedback(const char *nick, presence_t p, const char *arg, const char *app, format_t *fmt) {
format_t fmt0 = format_0;
splitbuf_t *q;
if(!fmt)
fmt = &fmt0;
if(!nick)
nick = opper();
q = getappreciate(nick, p, arg, app, fmt);
if(q)
return ventriloquateq(nick, p, q), true;
return false;
}
bool feedback(presence_t p, const char *arg, const char *app, format_t *fmt) {
format_t fmt0 = format_0;
splitbuf_t *q;
if(!fmt)
fmt = &fmt0;
q = getappreciate(f00fnick, p, arg, app, fmt);
if(q)
return sayq(p, q), true;
return false;
}
bool ventrilofeedback_str(const char *nick, presence_t p, const char *arg, const char *app, ...) {
format_t fmt = format_0;
va_list ap;
va_start(ap, app);
format_vadd_str(&fmt, ap);
va_end(ap);
return ventrilofeedback(nick, p, arg, app, &fmt);
}
bool feedback_str(presence_t p, const char *arg, const char *app, ...) {
format_t fmt = format_0;
va_list ap;
va_start(ap, app);
format_vadd_str(&fmt, ap);
va_end(ap);
return feedback(p, arg, app, &fmt);
}
bool ventrilopreciate(const char *nick, presence_t p, const char *arg, const char *app) {
return ventrilofeedback(nick, p, arg, app, NULL);
}
bool appreciate(presence_t p, const char *arg, const char *app) {
return feedback(p, arg, app, NULL);
}
bool rate(presence_t p, const char *word, int adjust) {
bool done;
if(!adjust)
return true;
if(!db_larts_rate(txn, word, p.nick->user ? p.nick->user->name : p.nick->name, adjust, &done))
return false;
return done;
}
static bool f00fstat(presence_t p, char *arg) {
char *word, *dude;
char **users;
unsigned int *cools, *larts;
int i, total;
splitbuf_t b;
if(!db_larts_stat(txn, arg, &word, &users, &cools, &larts))
return false;
if(!word)
return say(p, _("Ik heb nog nooit van \xe2\x80\x98%s\xe2\x80\x99 gehoord."), arg), false;
if(!*users)
return say(p, _("Niemand heeft een mening over \xe2\x80\x98%s\xe2\x80\x99."), word), false;
splitbuf_init(&b);
qprintf(&b, "[\002%s\002] ", word);
total = 0;
for(i = 0; dude = users[i], dude; i++) {
if(i)
qprintf(&b, ", ");
qprintf(&b, "%s: ", dude);
if(cools[i])
qprintf(&b, "+%u", cools[i]);
if(larts[i])
qprintf(&b, "-%u", larts[i]);
total += cools[i];
total -= larts[i];
}
qprintf(&b, _(" \002totaal\002: %+d"), total);
sayq(p, &b);
splitbuf_clean(&b);
return true;
}
static bool f00frevstat(presence_t p, char *who) {
char *nick;
unsigned int cools, larts;
int total;
splitbuf_t q;
if(!db_larts_revstat(txn, who, &nick, &cools, &larts))
return false;
if(!nick) {
say(p, _("Ik heb nog nooit van \xe2\x80\x98%s\xe2\x80\x99 gehoord."), who);
return false;
}
if(!cools && !larts) {
say(p, "%s heeft nergens een mening over.", nick);
} else {
splitbuf_init(&q);
qprintf(&q, "%s heeft ", nick);
if(cools)
qprintf(&q, "%u positieve ", cools);
if(cools && larts)
qprintf(&q, "en ");
if(larts)
qprintf(&q, "%u negatieve ", larts);
total = cools - larts;
qprintf(&q, "waarderingen gegeven. (totaal %+d)", total);
sayq(p, &q);
splitbuf_clean(&q);
}
return true;
}
static void f00f_STAT(presence_t p, char *arg) {
f00fstat(p, arg ?: p.nick->name);
}
static void f00f_REVSTAT(presence_t p, char *arg) {
f00frevstat(p, arg ?: p.nick->name);
}
static void f00f_DUIM(presence_t p, char *arg) {
appreciate(p, arg, "duim1");
appreciate(p, arg, "duim2");
}
static void f00f_THUMB(presence_t p, char *arg) {
appreciate(p, arg, "thumb1");
appreciate(p, arg, "thumb2");
}
static void f00f_BONK(presence_t p, char *arg) {
appreciate(p, arg, "bonk");
if(arg && p.chan && (!strcasecmp(arg, f00fnick) || !strcasecmp(arg, _("zichzelf"))))
say(p, "oif.");
else
db_kosmische_balans(txn, 1, NULL);
}
static void f00f_OIF(presence_t p, char *arg) {
db_kosmische_balans(txn, -1, NULL);
}
static void grep_OIF(presence_t p, int argc, char **argv) {
db_kosmische_balans(txn, -1, NULL);
}
static void grep_NAGIOS(presence_t p, int argc, char **argv) {
appreciate(p, argv[1], "paniek");
}
static void f00f_BRFD(presence_t p, char *arg) {
rate(p, "brfd", +1);
appreciate(p, arg, "brfd");
}
static const char * const vraagwoorden[] = {
"wie",
"welke",
"welk",
"wat",
"waarom",
"waar",
"wanneer",
"hoezo", /* jaja */
"hoeveel",
"hoe",
NULL
};
static void f00f_EIGHTBALL(presence_t p, char *arg) {
int i = -1;
if(arg) {
for(i = 0; vraagwoorden[i]; i++) {
if(!strncasecmp(vraagwoorden[i], arg, strlen(vraagwoorden[i]))) {
appreciate(p, arg, vraagwoorden[i]);
break;
}
}
}
if(i == -1 || !vraagwoorden[i]) {
appreciate(p, NULL, "eightball");
}
}
static void f00f_DRIE(presence_t p, char *arg) {
appreciate(p, NULL, "drie");
}
static void oi(presence_t p, char *arg) {
struct tm tm;
time_t tt;
if(!p.chan)
return;
time(&tt);
localtime_r(&tt, &tm);
say(p, "Emitting broadcast-\002oi\002 at \037%02d:%02d\037!"
" Please respond to handshake signal!",
tm.tm_hour, tm.tm_min);
db_oi_set(txn, p.chan->name, p.nick->name, tm.tm_hour, tm.tm_min);
}
static void f00f_OI(presence_t p, char *arg) {
if(p.chan && !arg)
oi(p, arg);
else
appreciate(p, arg, "oi");
}
void lart(presence_t p) {
presence_t me = {0};
if(!p.nick)
return;
me.nick = getnick(f00fnick);
me.chan = p.chan;
appreciate(me, p.nick->name, "lart");
}
static void grep_LART(presence_t p, int argc, char **argv) {
if(argc < 2)
return;
appreciate(p, argv[1], "lart");
}
static void grep_COOL(presence_t p, int argc, char **argv) {
if(argc < 2)
return;
appreciate(p, argv[1], "cool");
}
static void f00f_DOOD(presence_t p, char *arg) {
if(!arg)
say(p, "%s quits (dood!)", f00fnick);
else
appreciate(p, arg, "dood");
}
static void f00f_RECENTAPPRECIATIONS(presence_t p, char *arg) {
unsigned int u;
splitbuf_t q;
char **apps;
if(!db_recentappreciations(txn, &apps))
return;
splitbuf_init(&q);
qprintf(&q, _("Recent bijgewerkte appreciations:"));
for(u = 0; apps[u]; u++)
qprintf(&q, "%s %s", u ? "," : "", apps[u]);
sayq(p, &q);
splitbuf_clean(&q);
}
static void f00f_FANCLUB(presence_t p, char *arg) {
char *word;
int i;
splitbuf_t q;
char **dudes;
if(!db_fanclub(txn, arg ?: p.nick->name, &word, &dudes))
return;
if(!word) {
if(arg)
say(p, _("Wat is een %s?"), arg);
else
say(p, _("%s: En wie ben jij dan?"), p.nick->name);
return;
}
splitbuf_init(&q);
qprintf(&q, _("De fanclub van %s bestaat uit: "), word);
for(i = 0; dudes[i]; i++) {
if(i)
qstrcat(&q, ", ");
qstrcat(&q, dudes[i]);
}
if(!i)
say(p, _(arg ? "…niemand." : "…niemand, loser! Hahaha."));
sayq(p, &q);
splitbuf_clean(&q);
}
static void f00f_ZEIKERDS(presence_t p, char *arg) {
char *word;
int i;
splitbuf_t q;
char **dudes;
if(!db_zeikerds(txn, arg ?: p.nick->name, &word, &dudes))
return;
if(!word) {
if(arg)
say(p, _("Wat is een %s?"), arg);
else
say(p, _("%s: En wie ben jij dan?"), p.nick->name);
return;
}
splitbuf_init(&q);
qprintf(&q, _("Degenen die zeiken over %s zijn: "), word);
for(i = 0; dudes[i]; i++) {
if(i)
qstrcat(&q, ", ");
qstrcat(&q, dudes[i]);
}
if(!i)
say(p, _(arg ? "…niemand." : "…niemand, bofkont!"));
sayq(p, &q);
splitbuf_clean(&q);
}
static uint64_t f00f_AI(uint64_t max) {
return (uint64_t)mt_genrand32_bounded(0, max);
}
static void f00f_RANDOMLART(presence_t p, char *arg) {
char *lart;
if(!db_larts_random_app(txn, f00f_AI, &lart))
return;
if(lart)
appreciate(p, arg, lart);
}
static void f00f_HOMER(presence_t p, char *arg) {
ventrilopreciate("Homer", p, arg, "homer");
}
static tab_entry_t regex_tab_entries[] = {
{"^(\\+*[^+ ]+\\+*)\\+\\+$", grep_COOL},
{"^(-*[^- ]+-*)--$", grep_LART},
{"^\003[0-9]*\\*\\*\017 \003[0-9]*PROBLEM\017: ([^/]+)/.*\003[0-9]*DOWN\017 \003[0-9]*\\*\\*\017", grep_NAGIOS},
{"^oif\\b", grep_OIF},
};
TAB_REGISTER(regex);
static tab_entry_t command_tab_entries[] = {
{"STAT", f00f_STAT},
{"REVSTAT", f00f_REVSTAT},
{"BRFD", f00f_BRFD},
{"DUIM", f00f_DUIM},
{"THUMB", f00f_THUMB},
{"BONK", f00f_BONK},
{"OIF", f00f_OIF},
{"8BALL", f00f_EIGHTBALL},
{"EIGHTBALL", f00f_EIGHTBALL},
{"DRIE", f00f_DRIE},
{"OI", f00f_OI},
{"DOOD", f00f_DOOD},
{"RECENTAPPRECIATIONS", f00f_RECENTAPPRECIATIONS},
{"RECENTAPPS", f00f_RECENTAPPRECIATIONS},
{"RLART", f00f_RANDOMLART},
{"RANDOMLART", f00f_RANDOMLART},
{"HOMER", f00f_HOMER},
{"FANCLUB", f00f_FANCLUB},
{"ZEIKERDS", f00f_ZEIKERDS},
{"HATERS", f00f_ZEIKERDS},
};
TAB_REGISTER(command);