/*---------------------------------------------------------------------------------------- * Name: bs_gseen * Author: Jens 'DukePyrolator' Voss * * Version: 1.0.7 * * --------------------------------------------------------------------------------------- * Supported IRCd: Unreal3.2 * Requires: Anope1.7.8+ and MySQL *---------------------------------------------------------------------------------------- * * If you find bugs, please send me a Mail or contact me on irc.anope.org #anope * *--------------------------------------------------------------------------------------- * Credits * - special thanks to all the people in #anope :-) * *---------------------------------------------------------------------------------------- * Changelog: * * v1.0.7 15/04/2004 - removed a warning message * v1.0.6 21/03/2005 - fixed a segfault when botserv is kicked from chan .... * v1.0.5 13/03/2005 - fixed some small bugs * v1.0.4 11/03/2005 - added Italian language - thx to HAL9000 * v1.0.3 11/03/2005 - fixed a new crashbug :/ * v1.0.2 10/03/2005 - fixed 2 possible crashbugs * v1.0.1 09/03/2005 - fixed a stupid crashbug * v1.0.0 08/03/2005 - first release * *---------------------------------------------------------------------------------------- * * internal infos * * * fields: nick - nickname (char) * type - int * host - ident@host * vhost - ident@host (vhost) * chan - #chan * msg - quit/part/kick message * last - timestamp of last seen ( time() ) * spent - timestamp ( time() - last ) - not used at the moment * newnick - nickname char * * * type: 0 - undefined - should never be 0 ERROR * 1 - connect to network (new user) GS_NEW * 2 - nickchange to newnick GS_NICK_NEW * 3 - nickchange from oldnick GS_NICK_OLD * 4 - join chan GS_JOIN * 5 - part chan GS_PART * 6 - quit network GS_QUIT * 7 - kicked from chan GS_KICK * * example for type 2 and 3: * * DukePyrolator changes nick to DukeP|away * - oldnick "DukePyrolator" gets type 2 and in field newnick is "DukeP|away" written * - newnick "DukeP|away" gets type 3 and in field newnick is "DukePyrolator" written * *-------------------------------------------------------------------------------------------*/ #include "module.h" #include #define AUTHOR "DukePyrolator" #define VERSION "1.0.7" /* language definitions */ #define GS_BOT 0 #define GS_YOU 1 #define GS_CONNECT 2 #define GS_NICKCHANGE 3 #define GS_NICKCHANGE_FROM 4 #define GS_JOIN 5 #define GS_JOIN_SECRET 6 #define GS_PART 7 #define GS_PART_SECRET 8 #define GS_KICK 9 #define GS_KICK_SECRET 10 #define GS_QUIT 11 #define GS_FAILED 12 #define GS_ONLINE 13 #define GS_ONLINE_AS 14 #define GS_OFFLINE 15 #define GS_TIME_FULL 16 #define GS_TIME_HOURS 17 #define GS_TIME_MINUTES 18 #define GS_TIME_SECONDS 19 #define GS_NOT_SEEN 20 #define GS_IN_CHAN 21 /* ENGLISH */ #define BS_SEEN_EN {"You found me, %s!", /* BOT */ \ "You might see yourself in the mirror, %s...", /* YOU */ \ "%s (%s) was last seen connecting %s ago (%s)%s", /* ON CONNECT */ \ "%s (%s) was last seen changing nick to %s %s ago%s", /* NICKCHANGE TO */ \ "%s (%s) was last seen changing nick from %s to %s %s ago%s", /* NICKCHANGE FROM */ \ "%s (%s) was last seen joining %s %s ago%s", /* JOIN */ \ "%s (%s) was last seen joining a secret chan %s ago%s", /* JOIN SECRET */ \ "%s (%s) was last seen parting %s (\"%s\") %s ago%s", /* PART */ \ "%s (%s) was last seen parting a secret chan %s ago%s", /* PART SECRET */ \ "%s (%s) was kicked from %s (\"%s\") %s ago%s", /* KICK */ \ "%s (%s) was kicked from a secret chan %s ago%s", /* KICK SECRET */ \ "%s (%s) was last seen quitting (%s) %s ago (%s).", /* QUIT */ \ "Seen query failed.", /* FAILED */ \ " and is still online.", /* ONLINE */ \ ". %s is still online.", /* ONLINE AS */ \ " but %s mysteriously dematerialized.", /* OFFLINE */ \ "%i days, %i hours and %i minutes", /* TIME FULL */ \ "%i hours and %i minutes", /* TIME HOURS */ \ "%i minutes", /* TIME MINUTES */ \ "%i seconds", /* TIME SECONDS */ \ "Sorry, I have not seen %s.", /* NOT SEEN */ \ "%s is in the chan right now!"} /* IN CHAN */ /* /ENGLISH */ /* GERMAN */ #define BS_SEEN_DE {"Du hast mich gefunden, %s!", /* BOT */ \ "Schau in den Spiegel, %s...", /* YOU */ \ "%s (%s) ist vor %s in den IRC gekommen (%s) %s", /* ON CONNECT */ \ "%s (%s) wechselte seinen Nick zu %s vor %s%s", /* NICKCHANGE TO */ \ "%s (%s) wechselte den Nick von %s zu %s vor %s%s", /* NICKCHANGE FROM */ \ "%s (%s) betrat den Raum %s vor %s%s", /* JOIN */ \ "%s (%s) betrat vor %s einen streng geheimen Raum%s", /* JOIN SECRET */ \ "%s (%s) verlies den Raum %s (\"%s\") vor %s%s", /* PART */ \ "%s (%s) verlies vor %s einen streng geheimen Raum%s", /* PART SECRET */ \ "%s (%s) wurde vor %s aus %s (\"%s\") gekickt%s", /* KICK */ \ "%s (%s) wurde vor %s aus einem streng geheimen Raum gekickt%s", /* KICK SECRET */ \ "%s (%s) verlies den IRC (%s) vor %s (%s).", /* QUIT */ \ "Seen Anfrage fehlgeschlagen.", /* FAILED */ \ " und ist immernoch online.", /* ONLINE */ \ ". %s ist immernoch online.", /* ONLINE AS */ \ " aber %s ist auf mysteriöse Weise verschwunden.", /* OFFLINE */ \ "%i Tagen, %i Stunden und %i Minuten", /* TIME FULL */ \ "%i Stunden und %i Minuten", /* TIME SHORT */ \ "%i Minuten", /* TIME MINUTES */ \ "%i Sekunden", /* TIME SECONDS */ \ "Ich habe %s leider nicht gesehen.", /* NOT SEEN */ \ "%s ist doch im Raum!"} /* /GERMAN */ /* ITALIAN */ #define BS_SEEN_IT {"%s, mi hai trovato!", /* BOT */ \ "%s, hai una doppia personalità?", /* YOU */ \ "Ho visto %s (%s) collegarsi %s fa (%s)%s", /* ON CONNECT */ \ "Ho visto %s (%s) cambiare il suo nick in %s %s fa%s", /* NICKCHANGE TO */ \ "Ho visto %s (%s) cambiare il suo nick da %s a %s %s fa%s", /* NICKCHANGE FROM */ \ "Ho visto %s (%s) entrare in %s %s fa%s", /* JOIN */ \ "Ho visto %s (%s) entrare in un canale segreto %s fa%s", /* JOIN SECRET */ \ "Ho visto %s (%s) uscire da %s (\"%s\") %s fa%s", /* PART */ \ "Ho visto %s (%s) uscire da un canale segreto %s fa%s", /* PART SECRET */ \ "Ho visto %s (%s) venire espulso da %s (\"%s\") %s fa%s", /* KICK */ \ "Ho visto %s (%s) venire espulso da un canale segreto %s fa%s", /* KICK SECRET */ \ "Ho visto %s (%s) scollegarsi (%s) %s fa (%s).", /* QUIT */ \ "Spiacente, non sono in grado di elaborare la richiesta.", /* FAILED */ \ " ed è tutt'ora online.", /* ONLINE */ \ ". %s è tutt'ora online.", /* ONLINE AS */ \ " ma %s si è misteriosamente dematerializzato.", /* OFFLINE */ \ "%i giorni, %i ore e %i minuti", /* TIME FULL */ \ "%i ore e %i minuti", /* TIME HOURS */ \ "%i minuti", /* TIME MINUTES */ \ "%i secondi", /* TIME SECONDS */ \ "Spiacente, non ricordo di aver visto %s.", /* NOT SEEN */ \ "%s si trova in canale in questo momento!"} /* IN CHAN */ /* /ITALIAN */ #define BS_NUM_LANGS 16 #define BS_NUM_STRINGS 22 char *langtable[BS_NUM_LANGS][BS_NUM_STRINGS] = { BS_SEEN_EN, /* LANG_EN_US * 0 * English (US) */ BS_SEEN_EN, /* LANG_JA_JIS * 1 * Japanese (JIS) */ BS_SEEN_EN, /* LANG_JA_EUC * 2 * Japanese (EUC) */ BS_SEEN_EN, /* LANG_JA_SJIS * 3 * Japanese (SJIS) */ BS_SEEN_EN, /* LANG_ES * 4 * Spanish */ BS_SEEN_EN, /* LANG_PT * 5 * Portugese */ BS_SEEN_EN, /* LANG_FR * 6 * French */ BS_SEEN_EN, /* LANG_TR * 7 * Turkish */ BS_SEEN_IT, /* LANG_IT * 8 * Italian */ BS_SEEN_DE, /* LANG_DE * 9 * German */ BS_SEEN_EN, /* LANG_CAT * 10 * Catalan */ BS_SEEN_EN, /* LANG_GR * 11 * Greek */ BS_SEEN_EN, /* LANG_NL * 12 * Dutch */ BS_SEEN_EN, /* LANG_RU * 13 * Russian */ BS_SEEN_EN, /* LANG_HU * 14 * Hungarian */ BS_SEEN_EN};/* LANG_PL * 15 * Polish */ /* /LANGSTUFF */ extern int debug; int do_on_part(char *source, int ac, char **av); int do_on_kick(char *source, int ac, char **av); int do_first_join(char *source, int ac, char **av); int do_on_join(char *source, int ac, char **av); int do_on_quit(char *source, int ac, char **av); int do_on_nick(char *source, int ac, char **av); int do_on_privmsg(char *source, int ac, char **av); void do_seen(User *u, Channel *c, char *target); void add_user_join(Channel *c, User *u); /* language */ char *lang_get_string(uint16 lang, uint16 string); /* mysql */ static MYSQL *mysql; static MYSQL_RES *res; static MYSQL_ROW row; int mydb_init(void); int do_query(char *query); char *quote(char *arg); char query[MAX_SQL_BUF]; char avbuf[512]; /***********************************************************************************/ int AnopeInit(int argc, char **argv) { Message *m; // #if !(defined(IRC_UNREAL) || defined(IRC_UNREAL32)) // alog("[bs_gseen] This module requires UnrealIRCd"); // alog("[bs_gseen] Module not loaded."); // return MOD_STOP; // #endif #ifndef USE_MYSQL alog("[bs_gseen] MYSQL is not enabled. This module requires MYSQL !"); alog("[bs_gseen] Module not loaded."); return MOD_STOP; #endif /* activate mysql connection and stop if failed */ if (mydb_init()) return MOD_STOP; m = createMessage("SJOIN", do_first_join); moduleAddMessage(m, MOD_HEAD); m = createMessage("SJOIN", do_on_join); moduleAddMessage(m, MOD_TAIL); m = createMessage("JOIN", do_on_join); moduleAddMessage(m, MOD_TAIL); m = createMessage("PART", do_on_part); moduleAddMessage(m, MOD_TAIL); m = createMessage("NICK", do_on_nick); moduleAddMessage(m, MOD_TAIL); m = createMessage("QUIT", do_on_quit); moduleAddMessage(m, MOD_HEAD); m = createMessage("KICK", do_on_kick); moduleAddMessage(m, MOD_TAIL); m = createMessage("PRIVMSG", do_on_privmsg); moduleAddMessage(m, MOD_HEAD); if (UseTokens) { m = createMessage("~", do_first_join); /* sjoin */ moduleAddMessage(m, MOD_HEAD); m = createMessage("~", do_on_join); /* sjoin */ moduleAddMessage(m, MOD_TAIL); m = createMessage("C", do_on_join); /* join */ moduleAddMessage(m, MOD_TAIL); m = createMessage("D", do_on_part); /* part */ moduleAddMessage(m, MOD_TAIL); m = createMessage("&", do_on_nick); moduleAddMessage(m, MOD_TAIL); m = createMessage(",", do_on_quit); moduleAddMessage(m, MOD_HEAD); m = createMessage("H", do_on_kick); moduleAddMessage(m, MOD_TAIL); m = createMessage("!", do_on_privmsg); moduleAddMessage(m, MOD_HEAD); } moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); return MOD_CONT; } /***************************************************************************************/ void do_seen(User *u, Channel *c, char *target) { User *u2 = NULL; Channel *targetchan = NULL; char outbuf[BUFSIZE], timebuf[BUFSIZE], timebuf2[BUFSIZE], onlinebuf[BUFSIZE]; struct u_chanlist *uc; int type = 0, is_online = 0; char *chan, *vhost, *msg, *newnick,*buf; time_t now = time(NULL); struct tm *lastbuf; long int tbuf, last; int days_, hours_, minutes_, seconds_; uint16 lang; res = NULL; if (u && u->na && u->na->nc) { lang = u->na->nc->language; } else { lang = NSDefLanguage; } if (!target) return; if (strlen(target) > 30) { send_cmd(c->ci->bi->nick, "NOTICE %s :Nick too long, maxlength is 30 chars", u->nick); return; } if (stricmp(target, c->ci->bi->nick)==0) { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_BOT), u->nick); send_cmd(c->ci->bi->nick, "PRIVMSG %s :%s", c->name, outbuf); return; } if (stricmp(target, u->nick)==0) { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_YOU), u->nick); send_cmd(c->ci->bi->nick, "PRIVMSG %s :%s", c->name, outbuf); return; } if (u2 = finduser(target)) { snprintf(onlinebuf, BUFSIZE, lang_get_string(lang,GS_ONLINE)); } else { snprintf(onlinebuf, BUFSIZE, lang_get_string(lang,GS_OFFLINE), target); } if (u2) { for (uc = u2->chans; uc; uc = uc->next) { if ((c == uc->chan)) { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_IN_CHAN), target); send_cmd(c->ci->bi->nick, "PRIVMSG %s :%s", c->name, outbuf); return; } } } buf = quote(target); snprintf(query,MAX_SQL_BUF,"SELECT * FROM `bs_gseen` WHERE `nick` = '%s';", buf); do_query(query); free(buf); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { row = mysql_fetch_row(res); type = atoi(row[1]); vhost = row[3]; chan = row[4]; msg = row[5]; newnick = row[8]; last = atol(row[6]); tbuf = now - last; days_ = (tbuf/86400); hours_ = (tbuf/3600) % 24; minutes_ = (tbuf/60) % 60; seconds_ = (tbuf) % 60; lastbuf = localtime(&last); strftime_lang(timebuf2, BUFSIZE, u, STRFTIME_DATE_TIME_FORMAT, lastbuf); if (days_) { snprintf(timebuf, BUFSIZE, lang_get_string(lang, GS_TIME_FULL), days_, hours_, minutes_); } else if (hours_) { snprintf(timebuf, BUFSIZE, lang_get_string(lang, GS_TIME_HOURS), hours_, minutes_); } else if (minutes_) { snprintf(timebuf, BUFSIZE, lang_get_string(lang, GS_TIME_MINUTES), minutes_); } else { snprintf(timebuf, BUFSIZE, lang_get_string(lang, GS_TIME_SECONDS), seconds_); } if (type == 1) { /* connect */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_CONNECT), target, vhost, timebuf, timebuf2, onlinebuf); } else if (type == 2) { /* nickchange to */ if (u2 = finduser(newnick)) { snprintf(onlinebuf, BUFSIZE, lang_get_string(lang,GS_ONLINE_AS), newnick); } else { snprintf(onlinebuf, BUFSIZE, lang_get_string(lang,GS_OFFLINE), newnick); } snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_NICKCHANGE), target, vhost, newnick, timebuf, onlinebuf); } else if (type == 3) { /* nickchange from */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_NICKCHANGE_FROM), target, vhost, newnick, target, timebuf, onlinebuf); } else if (type == 4) { /* join */ targetchan=findchan(chan); if ((stricmp(c->name,chan)!=0) && ((targetchan) && (targetchan->mode & anope_get_secret_mode()))) { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_JOIN_SECRET), target, vhost, timebuf, onlinebuf); } else { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_JOIN), target, vhost, chan, timebuf, onlinebuf); } } else if (type == 5) { /* part */ targetchan=findchan(chan); if ((stricmp(c->name,chan)!=0) && ((targetchan) && (targetchan->mode & anope_get_secret_mode()))) { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_PART_SECRET), target, vhost, timebuf, onlinebuf); } else { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_PART), target, vhost, chan, msg, timebuf, onlinebuf); } } else if (type == 6) { /* quit */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_QUIT), target, vhost, msg, timebuf, timebuf2); } else if (type == 7) { /* kick */ targetchan=findchan(chan); if ((stricmp(c->name,chan)!=0) && ((targetchan) && (targetchan->mode & anope_get_secret_mode()))) { snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_KICK_SECRET), target, vhost, timebuf, onlinebuf); } else { if (lang == 9) { /* german language has an different grammar */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_KICK), target, vhost, timebuf, chan, msg, onlinebuf); } else { /* english or other languages */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_KICK), target, vhost, chan, msg, timebuf, onlinebuf); } } } else { /* error */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_FAILED)); } } else { /* (mysql_num_rows(res) */ /* not found */ snprintf(outbuf, BUFSIZE, lang_get_string(lang, GS_NOT_SEEN), target); } send_cmd(c->ci->bi->nick, "PRIVMSG %s :%s", c->name, outbuf); if (res) mysql_free_result(res); } /***************************************************************************************/ int do_on_privmsg(char *source, int ac, char **av) { User *u = finduser(source); Channel *c; char *cmd, *target, *target_; if (*av[0] == '#') { /* channel msg ? */ if (!av[1]) return MOD_CONT; cmd = myStrGetToken(av[1],' ',0); target = myStrGetToken(av[1],' ',1); if (cmd && target && !stricmp(cmd,"!seen")) { if (s_BotServ && (c = findchan(av[0]))) { if (!(c->ci->flags & CI_VERBOTEN) && c->ci->c && c->ci->bi) { /* Some paranoia checks */ target_ = normalizeBuffer(target); do_seen(u, c, target_); free(target_); } } free(cmd);free(target); return MOD_STOP; } free(cmd);free(target); } return MOD_CONT; } /***************************************************************************************/ int do_on_kick(char *source, int ac, char **av) { User *u; time_t now = time(NULL); char *victim, *host, *vhost, *vident, *channel = quote(av[0]), *msg = av[2] ? quote(av[2]) : quote(""); int len; u = finduser(av[1]); source = quote(source); victim = quote(av[1]); if (!u) return MOD_CONT; /* do not free(), only prevent segfault */ if (u->vident) vident = u->vident; else vident = u->username; len = strlen(u->host)+strlen(u->username)+2; host = malloc(len); snprintf(host,len,"%s@%s", u->username, u->host); len = strlen(u->vhost)+strlen(vident)+2; vhost = malloc(len); snprintf(vhost,len,"%s@%s", vident, u->vhost ? u->vhost : u->host); snprintf(query,MAX_SQL_BUF,"SELECT `nick` FROM `bs_gseen` WHERE `nick` = '%s';", victim); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='7', `host`='%s', `vhost`='%s', `last`='%lu', `chan`='%s', `msg`='%s', `newnick`='%s' WHERE `nick`='%s';", host, vhost, now, channel, msg, source, victim); } else { snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`, `chan`, `msg`, `newnick`) " "VALUES ('%s', 7, '%s', '%s', '%lu', '%s', '%s', '%s');", victim, host, vhost, now, channel, msg, source); } mysql_free_result(res); do_query(query); MODCONT: free(msg); free(source); free(victim); free(vhost); free(host); return MOD_CONT; } /***************************************************************************************/ int do_on_quit(char *source, int ac, char **av) { User *u; time_t now = time(NULL); char *host, *vhost, *vident, *msg = quote(av[0]); int len; u = finduser(source); source = quote(source); if (!u) return MOD_STOP; /* do not free(), only prevent segfault */ if (u->vident) vident = u->vident; else vident = u->username; len = strlen(u->host)+strlen(u->username)+2; host = malloc(len); snprintf(host,len,"%s@%s", u->username, u->host); len = strlen(u->vhost)+strlen(vident)+2; vhost = malloc(len); snprintf(vhost,len,"%s@%s", vident, u->vhost ? u->vhost : u->host); snprintf(query,MAX_SQL_BUF,"SELECT `nick` FROM `bs_gseen` WHERE `nick` = '%s';", source); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='6', `host`='%s', `vhost`='%s', `last`='%lu', `msg`='%s' WHERE `nick`='%s';", host, vhost, now, msg, source); } else { snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`, `msg`) " "VALUES ('%s', 6, '%s', '%s', '%lu', '%s');", source, host, vhost, now, msg); } mysql_free_result(res); do_query(query); MODCONT: if (msg) free(msg); if (source) free(source); if (vhost) free(vhost); if (host) free(host); return MOD_CONT; } /***************************************************************************************/ int do_on_part(char *source, int ac, char **av) { User *u; time_t now = time(NULL); char *host, *vhost, *vident, *channel = quote(av[0]), *msg = av[1] ? quote(av[1]) : quote(""); int len; u = finduser(source); source = quote(source); if (!u) return MOD_CONT; /* do not free(), only prevent segfault */ if (u->vident) vident = u->vident; else vident = u->username; len = strlen(u->host)+strlen(u->username)+2; host = malloc(len); snprintf(host,len,"%s@%s", u->username, u->host); len = strlen(u->vhost)+strlen(vident)+2; vhost = malloc(len); snprintf(vhost,len,"%s@%s", vident, u->vhost ? u->vhost : u->host); snprintf(query,MAX_SQL_BUF,"SELECT `nick` FROM `bs_gseen` WHERE `nick` = '%s';", source); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='5', `host`='%s', `vhost`='%s', `last`='%lu', `chan`='%s', `msg`='%s' WHERE `nick`='%s';", host, vhost, now, channel, msg, source); } else { snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`, `chan`, `msg`) " "VALUES ('%s', 5, '%s', '%s', '%lu', '%s', '%s');", source, host, vhost, now, channel, msg); } mysql_free_result(res); do_query(query); MODCONT: if (msg) free(msg); if (source) free(source); if (vhost) free(vhost); if (host) free(host); return MOD_CONT; } /***************************************************************************************/ /* short workaround for an anope bug */ int do_first_join(char *source, int ac, char **av) { strcpy(avbuf, av[ac-1]); return MOD_CONT; } /***************************************************************************************/ /* Unreal SJOIN On Services connect there is SJOIN (time 0) (chan 1) (mode 2) (extras 3) :(users and modes 4) SJOIN !11LkOb #ircops +nt :@Trystan &*!*@*.aol.com "*@*.home.com 0 1 2 3 4 SJOIN (!11kIfW) (#anope) (+ntrSTf) (test [7c#C15]:15) (:@~Gormak @*DukePyrolator &*!*@*.aol.com "*!*@localhost) av[0] = time stamp (base64) av[1] = channel av[2] = modes av[3] = users + bans + exceptions On Channel Creation or a User joins an existing Luna.NomadIrc.Net SJOIN !11LkW9 #akill :@Trystan Luna.NomadIrc.Net SJOIN !11LkW9 #akill :Trystan` av[0] = time stamp (base64) av[1] = channel av[2] = users */ int do_on_join(char *source, int ac, char **av) { User *u; time_t now = time(NULL); char *s, *end, cubuf[7], *end2, *cumodes[6]; Channel *c = NULL; av[ac-1] = avbuf; c = findchan(av[1]); if (!c) { return MOD_STOP; } /* should only happens after a netsplit or if services are connecting*/ /* needs testing !! */ if (ac >= 4) { cubuf[0] = '+'; cumodes[0] = cubuf; s = av[ac - 1]; while (*s) { end = strchr(s, ' '); if (end) *end = 0; end2 = cubuf + 1; /* if a ban -> do nothing */ if (ircd->sjoinbanchar) { if (*s == ircd->sjoinbanchar) { if (!end) break; s = end + 1; continue; } } /* if an exception -> do nothing */ if (ircd->sjoinexchar) { if (*s == ircd->sjoinexchar) { if (!end) break; s = end + 1; continue; } } if (*s == '\'') { if (!end) break; s = end + 1; continue; } while (csmodes[(int) *s] != 0) { *end2++ = csmodes[(int) *s++]; } *end2 = 0; u = finduser(s); if (!u) continue; add_user_join(c,u); if (!end) break; s = end + 1; } /* end of "while(*s)" */ /* end of "if (ac >= 4 && ac <= 6) " */ } else if (ac == 3) { /* for unrealircd */ cubuf[0] = '+'; cumodes[0] = cubuf; s = av[2]; while (*s) { end = strchr(s, ' '); if (end) *end = 0; end2 = cubuf + 1; while (csmodes[(int) *s] != 0) *end2++ = csmodes[(int) *s++]; *end2 = 0; u = finduser(s); if (!u) continue; add_user_join(c,u); if (!end) break; s = end + 1; } /* end of while */ /* end of " else if (ac == 3) " */ } else if (ac == 2) { /* normal join ? */ u = finduser(source); if (!u) return MOD_CONT; add_user_join(c,u); } return MOD_CONT; } /* end of do_on_join */ /*******************************************************************************************/ void add_user_join(Channel *c, User *u) { time_t now = time(NULL); char *host, *vhost, *vident, *channel, *nick; int len; channel = quote(c->name); nick = quote(u->nick); if (u->vident) vident = u->vident; else vident = u->username; len = strlen(u->host)+strlen(u->username)+2; host = malloc(len); snprintf(host,len,"%s@%s", u->username, u->host); len = strlen(u->vhost)+strlen(vident)+2; vhost = malloc(len); snprintf(vhost,len,"%s@%s", vident, u->vhost ? u->vhost : u->host); snprintf(query,MAX_SQL_BUF,"SELECT `nick` FROM `bs_gseen` WHERE `nick` = '%s';", nick); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='4', `host`='%s', `vhost`='%s', `last`='%lu', `chan`='%s' WHERE `nick`='%s';", host, vhost, now, channel, nick); } else { snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`, `chan`) " "VALUES ('%s', 1, '%s', '%s', '%lu', '%s');", nick, host, vhost, now, channel); } mysql_free_result(res); do_query(query); free(channel); free(nick); free(vhost); free(host); } /***************************************************************************************/ int do_on_nick(char *source, int ac, char **av) { User *u; int len; time_t now = time(NULL); char *nick, *oldnick, *vident, *vhost, *host; if ((ac == 10) || (ac ==11)) { /* new user */ u = finduser(av[0]); if (!u) return MOD_CONT; nick = quote(av[0]); if (u->vident) vident = u->vident; else vident = u->username; len = strlen(u->host)+strlen(u->username)+2; host = malloc(len); snprintf(host,len,"%s@%s", u->username, u->host); len = strlen(u->vhost)+strlen(vident)+2; vhost = malloc(len); snprintf(vhost,len,"%s@%s", vident, u->vhost ? u->vhost : u->host); snprintf(query,MAX_SQL_BUF,"SELECT `nick` FROM `bs_gseen` WHERE `nick` = '%s';", nick); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='1', `host`='%s', `vhost`='%s', `last`='%lu' WHERE `nick`='%s';", host, vhost, now, nick); } else { snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`) " "VALUES ('%s', 1, '%s', '%s', '%lu');", nick, host, vhost, now); } mysql_free_result(res); do_query(query); goto MODCONT; } else if (ac == 2) { /* nickchange */ u = finduser(av[0]); if (!u) return MOD_CONT; nick = quote(av[0]); oldnick = quote(source); if (u->vident) vident = u->vident; else vident = u->username; len = strlen(u->host)+strlen(u->username)+2; host = malloc(len); snprintf(host,len,"%s@%s", u->username, u->host); len = strlen(u->vhost)+strlen(vident)+2; vhost = malloc(len); snprintf(vhost,len,"%s@%s", vident, u->vhost ? u->vhost : u->host); /* update old nick */ snprintf(query,MAX_SQL_BUF,"SELECT `nick`, `last` FROM `bs_gseen` WHERE `nick` = '%s';", oldnick); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ row = mysql_fetch_row(res); snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='2', `host`='%s', `vhost`='%s', `last`='%lu', `spent`=%lu - %s, `newnick`='%s' " "WHERE `nick`='%s';", host, vhost, now, now, row[1], nick, oldnick); } else { /* should only be true if module loaded and services are already connected */ snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`, `spent`, `newnick`) " "VALUES ('%s', 2, '%s', '%s', '%lu', '0', '%s');", oldnick, host, vhost, now, nick); } mysql_free_result(res); do_query(query); /* update new nick */ snprintf(query,MAX_SQL_BUF,"SELECT `nick` FROM `bs_gseen` WHERE `nick` = '%s';", nick); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) > 0) { /* exists this nick already in the database? */ snprintf(query, MAX_SQL_BUF,"UPDATE `bs_gseen` SET " "`type`='3', `host`='%s', `vhost`='%s', `last`='%lu', `spent`='0', `newnick`='%s' " "WHERE `nick`='%s';", host, vhost, now, oldnick, nick); } else { snprintf(query, MAX_SQL_BUF,"INSERT INTO `bs_gseen` " "(`nick`, `type`, `host`, `vhost`, `last`, `spent`, `newnick`) " "VALUES ('%s', 3, '%s', '%s', '%lu', '0', '%s');", nick, host, vhost, now, oldnick); } mysql_free_result(res); do_query(query); if(oldnick) free(oldnick); goto MODCONT; } else { /* strange error */ alog("[bs_gseen] some strange error occured. Please report it. (ac=%i)", ac); return MOD_STOP; } MODCONT: free(nick); free(vhost); free(host); return MOD_CONT; }; /***************************************************************************************/ void AnopeFini(void) { mysql_close(mysql); } /****************************************************************************************/ int mydb_init(void) { mysql = mysql_init(NULL); if (MysqlSock) { if ((!mysql_real_connect(mysql, MysqlHost, MysqlUser, MysqlPass, MysqlName, MysqlPort, MysqlSock, 0))) { alog("[bs_gseen] Cant connect to MySQL: %s\n", mysql_error(mysql)); alog("bs_gseen.so: unloading..."); return MOD_STOP; } } else { if ((!mysql_real_connect(mysql, MysqlHost, MysqlUser, MysqlPass, MysqlName, MysqlPort, NULL, 0))) { alog("[bs_gseen] Cant connect to MySQL: %s\n", mysql_error(mysql)); alog("bs_gseen.so: unloading..."); return MOD_STOP; } } if (mysql_select_db(mysql, MysqlName)) { alog("[bs_gseen] Cant connect to MySQL: %s\n", mysql_error(mysql)); alog("bs_gseen.so: unloading..."); return MOD_STOP; } /* checking for table and create it, if not found */ snprintf(query,MAX_SQL_BUF,"SHOW TABLES LIKE 'bs_gseen';"); do_query(query); res = mysql_store_result(mysql); if (mysql_num_rows(res) == 0) { /* dont change the order of the fields or you break some other stuff */ /* add new fields only to the end */ snprintf(query, MAX_SQL_BUF, "CREATE TABLE bs_gseen (" "nick VARCHAR(32) NOT NULL, PRIMARY KEY (nick), " "type INT, " "host TEXT, " "vhost TEXT, " "chan VARCHAR(32), " "msg TEXT, " "last BIGINT(14), " "spent INT, " "newnick VARCHAR(32));" ); if (do_query(query)) { alog("[bs_gseen] failed to create table"); alog("bs_gseen.so: unloading..."); mysql_free_result(res); return 1; } alog("[bs_gseen] Created table bs_gseen"); } mysql_free_result(res); return 0; } /*************************************************************************************************/ char *quote(char *arg) { int slen; char *buf; if (!arg) return 0; slen = strlen(arg); buf = malloc((1 + (slen * 2)) * sizeof(char)); mysql_real_escape_string(mysql,buf, arg, slen); return buf; } /*************************************************************************************************/ char *lang_get_string(uint16 lang, uint16 string) { if (lang >= BS_NUM_LANGS) lang = 0; if (string >= BS_NUM_STRINGS) string = GS_FAILED; return langtable[lang][string]; } /*************************************************************************************************/ int do_query(char *query) { int result; if (debug) alog("***Debug*** %s", query); mysql_ping(mysql); /* checks for mysql connection and reconnect */ result = mysql_query(mysql, query); if (result) { log_perror(mysql_error(mysql)); return result; } return 0; } /******************************************************************************************************/