mirror of
https://github.com/EnergyMech/energymech.git
synced 2025-12-29 16:14:43 +00:00
1114 lines
21 KiB
C
1114 lines
21 KiB
C
/*
|
|
|
|
EnergyMech, IRC bot software
|
|
Copyright (c) 2000-2018 proton
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
#define TOYBOX_C
|
|
#include "config.h"
|
|
|
|
#ifdef TOYBOX
|
|
#include "defines.h"
|
|
#include "structs.h"
|
|
#include "global.h"
|
|
#include "h.h"
|
|
#include "text.h"
|
|
#include "mcmd.h"
|
|
|
|
#ifdef TRIVIA
|
|
|
|
#define TRIV_WAIT_QUESTION 0
|
|
#define TRIV_HINT_TWO 1
|
|
#define TRIV_HINT_THREE 2
|
|
#define TRIV_NO_ANSWER 3
|
|
|
|
#define TRIV_HINT_DELAY 15
|
|
|
|
#define TRIV_HINT_DELAY_STR1 "15"
|
|
#define TRIV_HINT_DELAY_STR2 "30"
|
|
|
|
#define TRIV_METACHARS " .,-'%&/?!:;\""
|
|
|
|
#define DAY_IN_SECONDS (24*60*60)
|
|
#define WEEK_IN_SECONDS (7*24*60*60)
|
|
|
|
LS TrivScore *lastwinner;
|
|
LS Chan *triv_chan = NULL;
|
|
LS Strp *triv_answers = NULL;
|
|
LS time_t triv_ask_time;
|
|
LS time_t triv_next_time = 0;
|
|
LS time_t triv_weektop10;
|
|
LS int triv_mode;
|
|
LS int triv_score;
|
|
LS int triv_streak;
|
|
LS int triv_halt_flag;
|
|
|
|
#endif /* TRIVIA */
|
|
|
|
#define BIGSAY_DEFAULTFONT "default"
|
|
#define FONT_EXTENSION ".bigchars"
|
|
|
|
BigC *newchar;
|
|
BigC *orig_fontlist = NULL;
|
|
int orig_charlines;
|
|
int orig_charheight;
|
|
int orig_spacewidth;
|
|
int orig_kerning;
|
|
|
|
int read_charset_callback(char *rest)
|
|
{
|
|
char *opt;
|
|
int *n,sz;
|
|
|
|
if (charlines)
|
|
{
|
|
charlines--;
|
|
if (stringcmp("-blank-",rest) == 0)
|
|
rest = "";
|
|
else
|
|
{
|
|
sz = strlen(rest);
|
|
if (sz > newchar->width)
|
|
newchar->width = sz;
|
|
}
|
|
append_strp(&newchar->data,rest);
|
|
return(FALSE);
|
|
}
|
|
|
|
opt = chop(&rest);
|
|
n = NULL;
|
|
|
|
if (!stringcasecmp(opt,"chars") && charheight)
|
|
{
|
|
charlines = charheight;
|
|
opt = chop(&rest);
|
|
|
|
#ifdef DEBUG
|
|
debug("(read_charset_callback) New character definition: %s\n",opt);
|
|
#endif /* DEBUG */
|
|
set_mallocdoer(read_charset_callback);
|
|
newchar = (BigC*)Calloc(sizeof(BigC) + strlen(opt));
|
|
|
|
newchar->next = fontlist;
|
|
fontlist = newchar;
|
|
stringcpy(newchar->chars,opt);
|
|
}
|
|
else
|
|
if (!stringcasecmp(opt,"spacewidth"))
|
|
{
|
|
n = &spacewidth;
|
|
}
|
|
else
|
|
if (!stringcasecmp(opt,"charheight"))
|
|
{
|
|
n = &charheight;
|
|
}
|
|
else
|
|
if (!stringcasecmp(opt,"kerning"))
|
|
{
|
|
n = &kerning;
|
|
}
|
|
else
|
|
if (!stringcasecmp(opt,"fontname"))
|
|
{
|
|
opt = chop(&rest);
|
|
if (fontname && !stringcasecmp(fontname,opt))
|
|
{
|
|
fontlist = orig_fontlist;
|
|
charlines = orig_charlines;
|
|
charheight = orig_charheight;
|
|
spacewidth = orig_spacewidth;
|
|
kerning = orig_kerning;
|
|
orig_fontlist = NULL;
|
|
return(TRUE);
|
|
}
|
|
Free((char**)&fontname);
|
|
set_mallocdoer(read_charset_callback);
|
|
fontname = stringdup(opt);
|
|
}
|
|
|
|
if (n)
|
|
{
|
|
*n = asc2int(rest);
|
|
if (errno) *n = 0;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
int read_bigcharset(char *fname)
|
|
{
|
|
BigC *bigc;
|
|
int fd;
|
|
|
|
if ((fd = open(fname,O_RDONLY)) < 0)
|
|
{
|
|
stringcat(fname,FONT_EXTENSION);
|
|
if ((fd = open(fname,O_RDONLY)) < 0)
|
|
return(-1);
|
|
}
|
|
|
|
orig_fontlist = fontlist;
|
|
orig_charlines = charlines;
|
|
orig_charheight = charheight;
|
|
orig_spacewidth = spacewidth;
|
|
orig_kerning = kerning;
|
|
|
|
fontlist = NULL;
|
|
charlines = 0;
|
|
spacewidth = 0;
|
|
charheight = 0;
|
|
kerning = 0;
|
|
|
|
readline(fd,&read_charset_callback); /* readline closes fd */
|
|
|
|
/*
|
|
* free the old font if there is one
|
|
*/
|
|
#ifdef DEBUG
|
|
debug("(read_bigcharset) purge old charset, if there is one. orig = %p\n",orig_fontlist);
|
|
#endif
|
|
while(orig_fontlist)
|
|
{
|
|
bigc = orig_fontlist;
|
|
orig_fontlist = bigc->next;
|
|
if (bigc->data)
|
|
purge_linklist((void**)&bigc->data);
|
|
Free((char**)&bigc);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int read_ascii(char *rest)
|
|
{
|
|
to_user_q(global_from,FMT_PLAIN,rest);
|
|
}
|
|
|
|
#ifdef TRIVIA
|
|
|
|
/*
|
|
*
|
|
* trivia scorings
|
|
*
|
|
*/
|
|
|
|
void trivia_week_toppers(void)
|
|
{
|
|
char triv_str[MSGLEN];
|
|
TrivScore *chosen[10];
|
|
TrivScore *su;
|
|
char *p;
|
|
int week;
|
|
int i,x;
|
|
|
|
chosen[0] = NULL;
|
|
week = (now + (3 * DAY_IN_SECONDS)) / WEEK_IN_SECONDS;
|
|
|
|
for(su=scorelist;su;su=su->next)
|
|
{
|
|
if (su->week_nr != week)
|
|
continue;
|
|
for(i=0;i<10;i++)
|
|
{
|
|
if (!chosen[i] || (chosen[i]->score_wk < su->score_wk))
|
|
{
|
|
for(x=8;x>=i;x--)
|
|
chosen[x+1] = chosen[x];
|
|
chosen[i] = su;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chosen[0])
|
|
{
|
|
p = triv_str;
|
|
for(i=0;i<10;i++)
|
|
{
|
|
if (!chosen[i])
|
|
break;
|
|
if (i)
|
|
{
|
|
*(p++) = ' ';
|
|
*(p++) = ' ';
|
|
}
|
|
sprintf(p,"#%i: %s (%ipts)",i+1,chosen[i]->nick,chosen[i]->score_wk);
|
|
p = STREND(p);
|
|
}
|
|
to_server("PRIVMSG %s :This Weeks Top 10: %s\n",triv_chan->name,triv_str);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
void hint_one(void)
|
|
{
|
|
char triv_str[MSGLEN];
|
|
char *src,*dst;
|
|
|
|
sprintf(triv_str,"PRIVMSG %s :1st hint: ",triv_chan->name);
|
|
dst = STREND(triv_str);
|
|
src = triv_answers->p;
|
|
while(*src)
|
|
{
|
|
if (STRCHR(TRIV_METACHARS,*src))
|
|
*(dst++) = *src;
|
|
else
|
|
*(dst++) = triv_qchar;
|
|
src++;
|
|
}
|
|
*dst = 0;
|
|
to_server("%s Question score: %i points\n",triv_str,triv_score);
|
|
}
|
|
|
|
void hint_two(void)
|
|
{
|
|
char triv_str[MSGLEN];
|
|
char *src,*dst;
|
|
int n;
|
|
|
|
sprintf(triv_str,"PRIVMSG %s :2nd hint: ",triv_chan->name);
|
|
dst = STREND(triv_str);
|
|
src = triv_answers->p;
|
|
|
|
n = asc2int(src);
|
|
if (!errno)
|
|
{
|
|
if (n > 99 && *src) *(dst++) = *(src++);
|
|
if (n > 999 && *src) *(dst++) = *(src++);
|
|
if (n > 9999 && *src) *(dst++) = *(src++);
|
|
}
|
|
else
|
|
{
|
|
n = strlen(src);
|
|
if (n > 2 && *src) *(dst++) = *(src++);
|
|
if (n > 4 && *src) *(dst++) = *(src++);
|
|
if (n > 6 && *src) *(dst++) = *(src++);
|
|
}
|
|
|
|
while(*src)
|
|
{
|
|
if (STRCHR(TRIV_METACHARS,*src))
|
|
*(dst++) = *src;
|
|
else
|
|
*(dst++) = triv_qchar;
|
|
src++;
|
|
}
|
|
*dst = 0;
|
|
to_server("%s " TRIV_HINT_DELAY_STR2 " seconds remaining.\n",triv_str);
|
|
}
|
|
|
|
void hint_three(void)
|
|
{
|
|
char triv_str[MSGLEN];
|
|
char *src,*dst;
|
|
int n;
|
|
|
|
sprintf(triv_str,"PRIVMSG %s :3rd hint: ",triv_chan->name);
|
|
dst = STREND(triv_str);
|
|
src = triv_answers->p;
|
|
|
|
n = asc2int(src);
|
|
if (!errno)
|
|
{
|
|
if (n > 9 && *src) *(dst++) = *(src++);
|
|
if (n > 99 && *src) *(dst++) = *(src++);
|
|
if (n > 999 && *src) *(dst++) = *(src++);
|
|
}
|
|
else
|
|
{
|
|
n = strlen(src);
|
|
if (n > 1 && *src) *(dst++) = *(src++);
|
|
if (n > 3 && *src) *(dst++) = *(src++);
|
|
if (n > 4 && *src) *(dst++) = *(src++);
|
|
}
|
|
|
|
while(*src)
|
|
{
|
|
if (STRCHR(TRIV_METACHARS "aeiouyAEIOUY",*src))
|
|
*(dst++) = *src;
|
|
else
|
|
*(dst++) = triv_qchar;
|
|
src++;
|
|
}
|
|
*dst = 0;
|
|
to_server("%s " TRIV_HINT_DELAY_STR1 " seconds remaining.\n",triv_str);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
void trivia_cleanup(void)
|
|
{
|
|
Strp *ans;
|
|
|
|
triv_mode = TRIV_WAIT_QUESTION;
|
|
triv_next_time = now + triv_qdelay;
|
|
while((ans = triv_answers))
|
|
{
|
|
triv_answers = ans->next;
|
|
Free((char**)&ans);
|
|
}
|
|
}
|
|
|
|
void trivia_check(Chan *chan, char *rest)
|
|
{
|
|
TrivScore *su;
|
|
Strp *ans;
|
|
int week;
|
|
|
|
if (chan != triv_chan)
|
|
return;
|
|
|
|
for(ans=triv_answers;ans;ans=ans->next)
|
|
{
|
|
if (!stringcasecmp(ans->p,rest))
|
|
goto have_answer;
|
|
}
|
|
return;
|
|
|
|
have_answer:
|
|
week = (now + (3 * DAY_IN_SECONDS)) / WEEK_IN_SECONDS;
|
|
|
|
for(su=scorelist;su;su=su->next)
|
|
{
|
|
if (!nickcmp(su->nick,CurrentNick))
|
|
{
|
|
su->score_mo += triv_score;
|
|
|
|
if (su->week_nr == week)
|
|
su->score_wk += triv_score;
|
|
else
|
|
{
|
|
if (su->week_nr == (week - 1))
|
|
su->score_last_wk = su->score_wk;
|
|
else
|
|
su->score_last_wk = 0;
|
|
su->week_nr = week;
|
|
su->score_wk = triv_score;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!su)
|
|
{
|
|
set_mallocdoer(trivia_check);
|
|
su = (TrivScore*)Calloc(sizeof(TrivScore) + strlen(CurrentNick));
|
|
su->next = scorelist;
|
|
scorelist = su;
|
|
su->score_wk = su->score_mo = triv_score;
|
|
su->week_nr = week;
|
|
/* su->month_nr = 0; * fix this */
|
|
stringcpy(su->nick,CurrentNick);
|
|
}
|
|
|
|
to_server("PRIVMSG %s :Yes, %s! got the answer -> %s <- in %i seconds, and gets %i points!\n",
|
|
triv_chan->name,CurrentNick,triv_answers->p,
|
|
(int)(now - triv_ask_time),triv_score);
|
|
|
|
if (su == lastwinner)
|
|
{
|
|
triv_streak++;
|
|
if (su->score_wk == su->score_mo)
|
|
{
|
|
to_server("PRIVMSG %s :%s has won %i in a row! Total score this Week: %i points\n",
|
|
triv_chan->name,CurrentNick,triv_streak,su->score_wk);
|
|
}
|
|
else
|
|
{
|
|
to_server("PRIVMSG %s :%s has won %i in a row! Total score this Week: %i points, and this Month: %i points\n",
|
|
triv_chan->name,CurrentNick,triv_streak,su->score_wk,su->score_mo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lastwinner = su;
|
|
triv_streak = 1;
|
|
if (su->score_wk == su->score_mo)
|
|
{
|
|
to_server("PRIVMSG %s :%s has won the question! Total score this Week: %i points\n",
|
|
triv_chan->name,CurrentNick,su->score_wk);
|
|
}
|
|
else
|
|
{
|
|
to_server("PRIVMSG %s :%s has won the question! Total score this Week: %i points, and this Month: %i points\n",
|
|
triv_chan->name,CurrentNick,su->score_wk,su->score_mo);
|
|
}
|
|
}
|
|
|
|
trivia_cleanup();
|
|
}
|
|
|
|
void trivia_no_answer(void)
|
|
{
|
|
to_server("PRIVMSG %s :Time's up! The answer was -> %s <-\n",
|
|
triv_chan->name,triv_answers->p);
|
|
|
|
trivia_cleanup();
|
|
}
|
|
|
|
char *random_question(char *triv_rand)
|
|
{
|
|
char *p,tmpname[120];
|
|
off_t sz;
|
|
int fd,ifd;
|
|
int n;
|
|
struct
|
|
{
|
|
int off;
|
|
int sz;
|
|
|
|
} entry;
|
|
|
|
if (STRCHR(triv_qfile,'/') || strlen(triv_qfile) > 100) /* really bad filenames... */
|
|
return(NULL);
|
|
|
|
stringcat(stringcpy(tmpname,"trivia/"),triv_qfile);
|
|
|
|
if ((fd = open(tmpname,O_RDONLY)) < 0)
|
|
#ifdef DEBUG
|
|
{
|
|
debug("(random_question) %s: %s\n",tmpname,strerror(errno));
|
|
return(NULL);
|
|
}
|
|
#else
|
|
return(NULL);
|
|
#endif /* DEBUG */
|
|
|
|
stringcpy(triv_rand,tmpname);
|
|
if ((p = STRCHR(triv_rand,'.')) == NULL)
|
|
p = STREND(triv_rand);
|
|
stringcpy(p,".index");
|
|
|
|
if ((ifd = open(triv_rand,O_RDONLY)) < 0)
|
|
return(NULL);
|
|
|
|
sz = lseek(ifd,0,SEEK_END);
|
|
sz = sz / sizeof(entry);
|
|
n = RANDOM(1,sz);
|
|
n--;
|
|
|
|
lseek(ifd,(n * sizeof(entry)),SEEK_SET);
|
|
if (read(ifd,&entry,sizeof(entry)) == -1)
|
|
return(NULL);
|
|
|
|
lseek(fd,entry.off,SEEK_SET);
|
|
if (read(fd,triv_rand,entry.sz) == -1)
|
|
return(NULL);
|
|
|
|
triv_rand[entry.sz] = 0;
|
|
|
|
close(fd);
|
|
close(ifd);
|
|
|
|
return(triv_rand);
|
|
}
|
|
|
|
void trivia_question(void)
|
|
{
|
|
char buffer[MSGLEN];
|
|
char *question,*answer,*rest;
|
|
|
|
if (triv_halt_flag)
|
|
{
|
|
to_server("PRIVMSG %s :Trivia has been stopped!\n",triv_chan->name);
|
|
goto stop_trivia;
|
|
}
|
|
|
|
if ((rest = random_question(buffer)) == NULL)
|
|
{
|
|
bad_question:
|
|
to_server("PRIVMSG %s :Bad Question File\n",triv_chan->name);
|
|
stop_trivia:
|
|
trivia_cleanup();
|
|
triv_chan = NULL;
|
|
triv_next_time = 0;
|
|
triv_halt_flag = FALSE;
|
|
short_tv &= ~TV_TRIVIA;
|
|
return;
|
|
}
|
|
|
|
question = get_token(&rest,MATCH_ALL);
|
|
|
|
while((answer = get_token(&rest,MATCH_ALL)))
|
|
append_strp(&triv_answers,answer);
|
|
|
|
if (triv_answers == NULL)
|
|
goto bad_question;
|
|
|
|
triv_score = (RANDOM(2,9) + RANDOM(2,10) + RANDOM(2,10)) / 3;
|
|
triv_ask_time = now;
|
|
|
|
if (now > (triv_weektop10 + 1200))
|
|
{
|
|
trivia_week_toppers();
|
|
triv_weektop10 = now;
|
|
}
|
|
|
|
to_server("PRIVMSG %s :%s\n",triv_chan->name,question);
|
|
hint_one();
|
|
}
|
|
|
|
void trivia_tick(void)
|
|
{
|
|
Chan *chan;
|
|
Mech *bot;
|
|
|
|
if (triv_next_time && (now >= triv_next_time))
|
|
{
|
|
for(bot=botlist;bot;bot=bot->next)
|
|
{
|
|
for(chan=bot->chanlist;chan;chan=chan->next)
|
|
{
|
|
if (triv_chan == chan)
|
|
{
|
|
current = bot;
|
|
triv_next_time = now + TRIV_HINT_DELAY;
|
|
switch(triv_mode)
|
|
{
|
|
case TRIV_WAIT_QUESTION:
|
|
trivia_question();
|
|
break;
|
|
case TRIV_HINT_TWO:
|
|
hint_two();
|
|
break;
|
|
case TRIV_HINT_THREE:
|
|
hint_three();
|
|
break;
|
|
case TRIV_NO_ANSWER:
|
|
trivia_no_answer();
|
|
return; /* dont increment with triv_mode */
|
|
}
|
|
triv_mode++;
|
|
#ifdef DEBUG
|
|
current = NULL;
|
|
#endif /* DEBUG */
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* File operations
|
|
*
|
|
*/
|
|
|
|
void write_triviascore(void)
|
|
{
|
|
TrivScore *su;
|
|
int fd;
|
|
|
|
if (scorelist)
|
|
{
|
|
if ((fd = open(TRIVIASCOREFILE,O_WRONLY|O_TRUNC|O_CREAT,NEWFILEMODE)) < 0)
|
|
return;
|
|
to_file(fd,COMMENT_STRCHR " nick score_wk score_mo score_last_wk score_last_mo\n");
|
|
for(su=scorelist;su;su=su->next)
|
|
{
|
|
to_file(fd,"%s %i %i %i %i %i %i\n",su->nick,su->score_wk,su->score_mo,
|
|
su->score_last_wk,su->score_last_mo,su->week_nr,su->month_nr);
|
|
}
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
int trivia_score_callback(char *rest)
|
|
{
|
|
TrivScore *su;
|
|
char *nick,*wk,*mo,*lwk,*lmo,*wnr,*mnr;
|
|
int score_wk,score_mo,score_last_wk,score_last_mo;
|
|
int week_nr,month_nr;
|
|
int err;
|
|
|
|
if (*rest != COMMENT_CHAR)
|
|
{
|
|
nick = chop(&rest);
|
|
wk = chop(&rest);
|
|
mo = chop(&rest);
|
|
lwk = chop(&rest);
|
|
lmo = chop(&rest);
|
|
wnr = chop(&rest);
|
|
mnr = chop(&rest);
|
|
|
|
if (mnr)
|
|
{
|
|
score_wk = asc2int(wk);
|
|
err = errno;
|
|
score_mo = asc2int(mo);
|
|
err += errno;
|
|
score_last_wk = asc2int(lwk);
|
|
err += errno;
|
|
score_last_mo = asc2int(lmo);
|
|
err += errno;
|
|
week_nr = asc2int(wnr);
|
|
err += errno;
|
|
month_nr = asc2int(mnr);
|
|
err += errno;
|
|
|
|
if (!err)
|
|
{
|
|
set_mallocdoer(trivia_score_callback);
|
|
su = (TrivScore*)Calloc(sizeof(TrivScore) + strlen(nick));
|
|
su->next = scorelist;
|
|
scorelist = su;
|
|
su->score_wk = score_wk;
|
|
su->score_mo = score_mo;
|
|
su->score_last_wk = score_last_wk;
|
|
su->score_last_mo = score_last_mo;
|
|
su->week_nr = week_nr;
|
|
su->month_nr = month_nr;
|
|
stringcpy(su->nick,nick);
|
|
}
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
void read_triviascore(void)
|
|
{
|
|
TrivScore *su;
|
|
int fd;
|
|
|
|
if ((fd = open(TRIVIASCOREFILE,O_RDONLY)) < 0)
|
|
return;
|
|
|
|
while(scorelist)
|
|
{
|
|
su = scorelist;
|
|
scorelist = su->next;
|
|
Free((char**)&su);
|
|
}
|
|
|
|
readline(fd,&trivia_score_callback); /* readline closes fd */
|
|
}
|
|
|
|
#endif /* TRIVIA */
|
|
|
|
/*
|
|
-+=====================================================================================================================+-
|
|
toybox.c commands
|
|
-+=====================================================================================================================+-
|
|
*/
|
|
|
|
void do_bigsay(COMMAND_ARGS)
|
|
{
|
|
#define OEND (output + MSGLEN - 1)
|
|
/*
|
|
* on_msg checks CARGS + CAXS
|
|
*/
|
|
BigC *bigc;
|
|
Strp *sp;
|
|
char output[MSGLEN];
|
|
char *pt,*tail,*temp,*temp2;
|
|
int i,x;
|
|
|
|
if (fontname && *rest != '-')
|
|
goto reuse_font;
|
|
|
|
stringcat(stringcpy(output,COMMONDIR),BIGSAY_DEFAULTFONT);
|
|
|
|
if (rest[0] == '-')
|
|
{
|
|
temp = chop(&rest);
|
|
if (temp[1] == '-')
|
|
; /* allow .bigsay -- -dash- */
|
|
else
|
|
if (STRCHR(temp,'/') == NULL) /* no filesystem perversions... */
|
|
{
|
|
stringcat(stringcat(stringcpy(output,COMMONDIR),temp+1),".bigchars"); /* temp+1 = skip initial '-' */
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
debug("(do_bigsay) fontfile %s, text = \"%s\"\n",output,rest);
|
|
#endif /* DEBUG */
|
|
|
|
if (read_bigcharset(output) < 0)
|
|
{
|
|
to_user(from,ERR_FILEOPEN,output);
|
|
return;
|
|
}
|
|
|
|
reuse_font:
|
|
for(i=0;i<charheight;i++)
|
|
{
|
|
*output = 0;
|
|
tail = output;
|
|
for(pt=rest;*pt;pt++)
|
|
{
|
|
/* find a matching character */
|
|
if (*pt == ' ')
|
|
{
|
|
x = spacewidth;
|
|
while(x-- && tail < OEND)
|
|
*(tail++) = ' ';
|
|
*tail = 0;
|
|
continue;
|
|
}
|
|
for(bigc=fontlist;bigc;bigc=bigc->next)
|
|
{
|
|
if (STRCHR(bigc->chars,*pt))
|
|
{
|
|
sp = bigc->data;
|
|
for(x=0;x<i;x++)
|
|
if (sp) sp = sp->next;
|
|
temp = (sp) ? sp->p : "";
|
|
temp2 = tail;
|
|
while(*temp && tail < OEND)
|
|
*(tail++) = *(temp++);
|
|
while(tail < (temp2 + bigc->width) && tail < OEND)
|
|
*(tail++) = ' ';
|
|
if (pt[1])
|
|
{
|
|
x = kerning;
|
|
while(x-- && tail < OEND)
|
|
*(tail++) = ' ';
|
|
}
|
|
*tail = 0;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (bigc == NULL)
|
|
{
|
|
debug("(do_bigsay) no matching character found for '%c'\n",*pt);
|
|
}
|
|
#endif /* DEBUG */
|
|
}
|
|
temp = NULL;
|
|
for(tail=output;*tail;tail++)
|
|
{
|
|
if (!temp && *tail == ' ')
|
|
temp = tail;
|
|
if (*tail != ' ')
|
|
temp = NULL;
|
|
}
|
|
if (temp)
|
|
{
|
|
if (temp == output)
|
|
temp++;
|
|
*temp = 0;
|
|
}
|
|
to_user_q(from,FMT_PLAIN,output);
|
|
}
|
|
}
|
|
|
|
void do_random_msg(COMMAND_ARGS)
|
|
{
|
|
const char *filename;
|
|
const char *message;
|
|
|
|
filename = CurrentCmd->cmdarg;
|
|
|
|
if (*rest)
|
|
{
|
|
to = chop(&rest);
|
|
if (ischannel(to) && (get_authaccess(from,to) < cmdaccess))
|
|
return;
|
|
}
|
|
else
|
|
if (!ischannel(to))
|
|
{
|
|
usage(from); /* usage for CurrentCmd->name */
|
|
return;
|
|
}
|
|
|
|
if ((message = randstring(filename)) == NULL)
|
|
{
|
|
to_user(from,ERR_FILEOPEN,filename);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* send message to target nick/channel
|
|
*/
|
|
to_server("PRIVMSG %s :%s\n",to,message);
|
|
/*
|
|
* if its not a channel we send a copy to the user who did the command also
|
|
*/
|
|
if (!ischannel(to))
|
|
{
|
|
to_user(from,"(%s) %s",to,message);
|
|
}
|
|
}
|
|
|
|
void do_randtopic(COMMAND_ARGS)
|
|
{
|
|
/*
|
|
* on_msg checks CAXS
|
|
*/
|
|
Chan *chan = CurrentChan;
|
|
char *topic;
|
|
|
|
/*
|
|
* the bot can set a random topic if chanmode is -t
|
|
*/
|
|
if (chan->bot_is_op || chan->topprot == FALSE)
|
|
{
|
|
if ((topic = randstring(RANDTOPICSFILE)) == NULL)
|
|
{
|
|
to_user(from,ERR_FILEOPEN,RANDTOPICSFILE);
|
|
return;
|
|
}
|
|
to_server("TOPIC %s :%s\n",to,topic);
|
|
to_user(from,TEXT_TOPICCHANGED,to);
|
|
return;
|
|
}
|
|
to_user(from,ERR_NOTOPPED,to);
|
|
}
|
|
|
|
void do_8ball(COMMAND_ARGS)
|
|
{
|
|
char *message;
|
|
|
|
if ((message = randstring(RAND8BALLFILE)) == NULL)
|
|
{
|
|
to_user_q(from,ERR_FILEOPEN,RAND8BALLFILE);
|
|
return;
|
|
}
|
|
|
|
to_user_q(from,FMT_PLAIN,message);
|
|
}
|
|
|
|
void do_ascii(COMMAND_ARGS)
|
|
{
|
|
char fname[MSGLEN];
|
|
int fd;
|
|
|
|
#ifdef DEBUG
|
|
if (STRCHR(rest,'/'))
|
|
{
|
|
debug("(do_ascii) '/' not permitted in filename\n");
|
|
ascii_badfile:
|
|
to_user_q(from,"%s","Bad filename or file does not exist");
|
|
return;
|
|
}
|
|
stringcat(stringcpy(fname,"ascii/"),rest);
|
|
debug("(do_ascii) file = \"%s\"\n",fname);
|
|
if (is_safepath(fname,FILE_MUST_EXIST) != FILE_IS_SAFE)
|
|
{
|
|
debug("(do_ascii) is_safepath() not safe\n");
|
|
goto ascii_badfile;
|
|
}
|
|
if ((fd = open(fname,O_RDONLY)) < 0)
|
|
{
|
|
debug("(do_ascii) open(%s): %s\n",fname,strerror(errno));
|
|
goto ascii_badfile;
|
|
}
|
|
#else
|
|
if (STRCHR(rest,'/'))
|
|
{
|
|
ascii_badfile:
|
|
to_user_q(from,"%s","Bad filename or file does not exist");
|
|
return;
|
|
}
|
|
stringcat(stringcpy(fname,"ascii/"),rest);
|
|
if (is_safepath(fname,FILE_MUST_EXIST) != FILE_IS_SAFE)
|
|
goto ascii_badfile;
|
|
if ((fd = open(fname,O_RDONLY)) < 0)
|
|
goto ascii_badfile;
|
|
#endif
|
|
|
|
global_from = from;
|
|
readline(fd,&read_ascii); /* readline closes fd */
|
|
}
|
|
|
|
/*
|
|
help:RAND:[[min[-| ]]max|"nick"|"luser"]
|
|
|
|
Tell the user a random number or channel nick.
|
|
|
|
Valid forms:
|
|
|
|
RAND Number between 1 and 100 (incl. 1 and 100)
|
|
RAND 10 Number between 1 and 10 (incl. 1 and 10)
|
|
RAND 0 10 Number between 0 and 10 (incl. 0 and 10)
|
|
RAND 0-10 Same
|
|
RAND nick Random channel non-bot user
|
|
RAND luser Random channel user with no bot access
|
|
|
|
By default, the bot picks a number between 1 and 100 (incl. 1 and 100)
|
|
|
|
If the command ``RAND nick'' is issued in a channel, the bot picks a random channel
|
|
user (after eliminating all known bots) and says the nick in the channel.
|
|
|
|
If the command ``RAND luser'' is issued in a channel, the bot picks a random channel
|
|
user that has no access in the bots userlist and says the nick in the channel.
|
|
|
|
*/
|
|
void do_rand(COMMAND_ARGS)
|
|
{
|
|
const char *opt;
|
|
const ChanUser *cu;
|
|
int r,min = 1,max = 100,maxaccess = -1;
|
|
|
|
if (!rest || *rest == 0)
|
|
goto pick_randnum;
|
|
|
|
if (attrtab[(uchar)*rest] & NUM)
|
|
{
|
|
max = 0;
|
|
while(attrtab[(uchar)*rest] & NUM)
|
|
max = 10 * max + (*(rest++) - '0');
|
|
if (*rest == '-' || *rest == ' ')
|
|
rest++;
|
|
if ((attrtab[(uchar)*rest] & NUM) == 0)
|
|
goto pick_randnum;
|
|
min = max;
|
|
max = 0;
|
|
while(attrtab[(uchar)*rest] & NUM)
|
|
max = 10 * max + (*(rest++) - '0');
|
|
goto pick_randnum;
|
|
}
|
|
opt = chop(&rest);
|
|
if (stringcasecmp(opt,"nick") == 0)
|
|
maxaccess = OWNERLEVEL;
|
|
if (stringcasecmp(opt,"luser") == 0)
|
|
maxaccess = 0;
|
|
if (maxaccess >= 0 && CurrentChan)
|
|
{
|
|
max = 0;
|
|
for(cu=CurrentChan->users;cu;cu=cu->next)
|
|
{
|
|
if (get_useraccess(get_nuh(cu),to) <= maxaccess)
|
|
max++;
|
|
}
|
|
if (max < 2)
|
|
{
|
|
to_user_q(from,"Unable to pick at random, too few choices");
|
|
return;
|
|
}
|
|
r = RANDOM(0,max);
|
|
#ifdef DEBUG
|
|
debug("(do_rand) pick a rand user: max = %i, r = %i\n",max,r);
|
|
#endif
|
|
max = 0;
|
|
for(cu=CurrentChan->users;cu;cu=cu->next)
|
|
{
|
|
if (get_useraccess(get_nuh(cu),to) <= maxaccess)
|
|
{
|
|
if (r == max)
|
|
{
|
|
to_user_q(from,"Random %suser: %s",(maxaccess == 0) ? "l" : "",cu->nick);
|
|
return;
|
|
}
|
|
max++;
|
|
}
|
|
}
|
|
to_user_q(from,"Unable to pick at random...");
|
|
return;
|
|
}
|
|
pick_randnum:
|
|
if (max == 0 || max < min)
|
|
max = 100;
|
|
if (min < 0 || min > max)
|
|
min = 1;
|
|
r = RANDOM(min,max);
|
|
#ifdef DEBUG
|
|
debug("(do_rand) pick a rand number: min = %i, max = %i, r = %i\n",min,max,r);
|
|
#endif
|
|
to_user_q(from,"Random number: %i",r);
|
|
}
|
|
|
|
#endif /* TOYBOX */
|
|
|
|
#ifdef TRIVIA
|
|
|
|
void do_trivia(COMMAND_ARGS)
|
|
{
|
|
/*
|
|
* on_msg checks CAXS + CARGS
|
|
*/
|
|
Chan *chan;
|
|
int uaccess;
|
|
|
|
uaccess = get_maxaccess(from);
|
|
|
|
if ((chan = find_channel_ac(to)) == NULL)
|
|
{
|
|
if (uaccess) to_user(from,ERR_CHAN,to);
|
|
return;
|
|
}
|
|
|
|
if (!stringcasecmp(rest,"start"))
|
|
{
|
|
if (triv_chan)
|
|
{
|
|
if (triv_chan == chan)
|
|
{
|
|
triv_halt_flag = FALSE;
|
|
return;
|
|
}
|
|
if (uaccess) to_user(from,"trivia is already activated on %s!",
|
|
(get_useraccess(from,triv_chan->name)) ? triv_chan->name : "another channel");
|
|
return;
|
|
}
|
|
to_server("PRIVMSG %s :Trivia starting! Get ready...\n",chan->name);
|
|
triv_chan = chan;
|
|
triv_mode = TRIV_WAIT_QUESTION;
|
|
triv_next_time = now + triv_qdelay;
|
|
triv_weektop10 = now;
|
|
lastwinner = NULL;
|
|
short_tv |= TV_TRIVIA;
|
|
if (!scorelist)
|
|
{
|
|
read_triviascore();
|
|
}
|
|
}
|
|
else
|
|
if (!stringcasecmp(rest,"stop"))
|
|
{
|
|
if (chan == triv_chan)
|
|
{
|
|
if (chan == triv_chan)
|
|
to_server("PRIVMSG %s :Trivia shutting down...\n",chan->name);
|
|
triv_halt_flag = TRUE;
|
|
}
|
|
}
|
|
else
|
|
if (!stringcasecmp(rest,"top10"))
|
|
{
|
|
int n;
|
|
|
|
if (triv_chan)
|
|
{
|
|
uaccess = get_authaccess(from,triv_chan->name);
|
|
if (now > (triv_weektop10 + 300))
|
|
n = 1;
|
|
else
|
|
n = uaccess;
|
|
|
|
if (n)
|
|
{
|
|
trivia_week_toppers();
|
|
if (!uaccess) triv_weektop10 = now;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* TRIVIA */
|