/* * database.c * (C) Peter Salanki 2002 * This program is copyright, and covered by the Gnu Public License. * The Natasha bot. * sorcer@linux.se */ #include #include #include #include #include #include #include #include #include #include #include "globals.h" #include "irc_chattr.h" int curtime; int userlevel (struct activeuser *u) { if (u != NULL) { return (u->auth); } else { return 0; } } int chanuserlevel (struct activeuser *u, struct channel *c) { struct chanuser *cu; if(u == NULL) return CHAN_OWNER; /* Server */ #ifdef Q if(u == Qu) return CHAN_OWNER; #ifdef L else if(u == Lu) return CHAN_OWNER; #endif #endif if (u != NULL && u->auth >= NORMAL) { if (c != NULL) { cu = findchanuser(u->userid, c); if(cu != NULL) return (cu->level); else return 0; } else return 0; } else { return 0; } } char *chanusergreet (struct activeuser *u, struct channel *c) { struct chanuser *cu; if (u != NULL && u->auth >= NORMAL) { if (c != NULL) { cu = findchanuser(u->userid, c); if(cu != NULL && cu->greet != NULL) return cu->greet; else return NULL; } else return NULL; } else { return NULL; } } char *authtotext(int auth) { char *text = Malloc(18); if(auth == UNAUTHED) strcpy(text, "Not logged in"); else if(auth == NORMAL) strcpy(text, "Normal user"); else if(auth == SERVICE_FRIEND) strcpy(text, "Service friend"); else if(auth == HELPER) strcpy(text, "Helper"); else if(auth == QUEUE_WORKER) strcpy(text, "Queue worker"); else if(auth == TECHNICIAN) strcpy(text, "Technician"); else if(auth == MASTER_TECHNICIAN) strcpy(text, "Master Technician"); else if(auth == IRC_OPERATOR) strcpy(text, "IRC Operator"); else if(auth == BOT_NORMAL) strcpy(text, "Bot"); else if(auth == BOT_PRIVATE) strcpy(text, "Private Bot"); else if(auth == BOT_CHECK) strcpy(text, "Checker Service"); else strcpy(text, "Undefined"); return text; } void chanlevtotext(int level, char *text) { if(level == CHAN_NOACCESS) strcpy(text, "No access"); else if(level == CHAN_FRIEND) strcpy(text, "Friend"); else if(level == CHAN_VOICE) strcpy(text, "Voice"); else if(level == CHAN_OP) strcpy(text, "Operator"); else if(level == CHAN_MASTER) strcpy(text, "Master"); else if(level == CHAN_OWNER) strcpy(text, "Owner"); else strcpy(text, "Undefined"); } int texttochanlev(char *text) { if(strcasecmp(text, "No") == 0) return CHAN_NOACCESS; else if(strcasecmp(text, "Friend") == 0) return CHAN_FRIEND; else if(strcasecmp(text, "Voice") == 0) return CHAN_VOICE; else if(strcasecmp(text, "Op") == 0) return CHAN_OP; else if(strcasecmp(text, "Master") == 0) return CHAN_MASTER; else if(strcasecmp(text, "Owner") == 0) return CHAN_OWNER; else return 99; // Level doesen't exist } int modfunc(char *module, char *function) { char msg[512]; struct module *m; void (*cmd)(); const char *err; m = findmodule(module); if(m != NULL) { cmd = dlsym(m->fl, function); err = dlerror(); if(err) { snprintf(msg, 512, "%c4Warning:%c Call for function failed (%c%s%c in module %c%s%c). Error: %s", COLORS, COLORS, BOLD, function, BOLD, BOLD, module, BOLD, err); privmsg(HOMECHAN, msg); return 0; } cmd(); return 1; } return 0; } int amodfunc(char *module, char *function, struct arm *arm) { char msg[512]; struct module *m; void (*cmd)(struct arm *arm); const char *err; m = findmodule(module); if(m != NULL) { cmd = dlsym(m->fl, function); err = dlerror(); if(err) { snprintf(msg, 512, "%c4Warning:%c Call for function failed (%c%s%c in module %c%s%c). Error: %s", COLORS, COLORS, BOLD, function, BOLD, BOLD, module, BOLD, err); privmsg(HOMECHAN, msg); return 0; } cmd(arm); return 1; } return 0; } /* Generate a random string */ char *RandString(int length) { char *po = Malloc(length); int i; srand(time(NULL)); for(i = 0; i < length; ++i) po[i] = (char)(0x61+(rand()&15)); return po; } /* * irc_strcmp - case insensitive comparison of 2 strings * NOTE: see ircd_chattr.h for notes on case mapping. * NOTE: This function is a direct ripoff from the the Undernet IRCd. */ int irc_strcmp(const char *a, const char *b) { const char* ra = a; const char* rb = b; while (ToLower(*ra) == ToLower(*rb)) { if (!*ra++) return 0; else ++rb; } return (*ra - *rb); } void TimerUserLoop(void) { /* This loop handles all timer based actions to the user structure */ struct activeuser *u; struct activeuser *next; if(htm) return; // Skip if in HTM curtime = time(NULL); u = firstauser; while (u != NULL) { if((next = DelOld(u)) == NULL) { #ifdef Q_AUTOAUTH ReCheckAuth(u); #endif u = u->next; } else u = next; } } #ifdef Q_AUTOAUTH int ReCheckAuth(struct activeuser *u) { /* Check if an unauthed user needs to be auth-checked again */ if(u->auth == UNAUTHED && u->check != 0 && curtime >= u->check) { add(u); u->check = 0; return 1; } else return 0; } #endif struct activeuser *DelOld(struct activeuser *u) { /* This function checks if a user is on any channels, and his idle time. If he isn't seen on any channels, and has exceeded the maximum idle time, he will be deleted from memory */ struct activeuser *NextUser = NULL; if(u->lastseen+UEXPIRE <= curtime && u->auth < BOT_NORMAL && u->firstlink == NULL && u->isinhome == 0) { #ifdef DEBUG printf("User: %s not seen on any channel, deleted. (expire)\n", u->nick); #endif NextUser = u->next; deluser(u); return NextUser; /* } else if(u->auth > SERVICE_FRIEND && u->lastseen+MAXACTIVEIDLE <= curtime && u->auth < IRC_OPERATOR) { InActiveStaff(u); return NULL; */ } else return NULL; } void TimerChannelLoop(void) { /* This loop handles all timer based actions to the user structure */ struct channel *c; int rejoin; int dohourly; if(htm) return; // Skip if in HTM curtime = time(NULL); /* Rejoin timer */ if(curtime >= rejoint) { rejoin = 1; rejoint = time(NULL) + REJOINFREQ; } else rejoin = 0; /* Hourly timer */ if(curtime >= hourly) { dohourly = 1; hourly = time(NULL) + 3600; } else dohourly = 0; /* Loop */ c = firstchan; while (c != NULL) { if(c->arm->status == 1 && c->suspended == 0) { DelOldChannelBans(c); /* Delete old channel bans */ CloseEndedVote(c); /* Close votes that have ended */ if(rejoin) ReJoinChannelCheck(c); /* Try to rejoin channels if rejoint(time variable) is exceeded */ #ifdef Q if(dohourly) ChannelServiceCheck(c); /* Check for change of channel service */ #endif if(dohourly) ChannelBanEnforce(c); } c = c->next; } } void ReJoinChannelCheck(struct channel *c) { /* Check if the bot is not on a channel and rejoin if TRUE and channel is not suspended. */ if(c->ison == 0) { #ifdef DEBUG printf("Rejoining: %s\n", c->name); #endif rejoinchannel(c->name, c->arm); } } void DelOldChannelBans(struct channel *c) { /* This function will remove bans from channels that have expired */ struct banlist *ban; ban = c->firstbanlist; while (ban != NULL) { if(ban->expire <= curtime) delban(ban); ban = ban->next; } } void CloseEndedVote(struct channel *c) { /* This function will close a vote for a channel if it has expired */ char tmp[512]; if(c->votestruct != NULL && c->votestruct->expiretime <= curtime) { if(c->votestruct->yes > c->votestruct->no) snprintf(tmp, 512, "Vote has ended. %cYes%c won with %c%i%c votes against %c%i%c.", BOLD, BOLD, BOLD, c->votestruct->yes, BOLD, BOLD, c->votestruct->no, BOLD); else if(c->votestruct->no > c->votestruct->yes) snprintf(tmp, 512, "Vote has ended. %cNo%c won with %c%i%c votes against %c%i%c.", BOLD, BOLD, BOLD, c->votestruct->no, BOLD, BOLD, c->votestruct->yes, BOLD); else if(c->votestruct->no == c->votestruct->yes) snprintf(tmp, 512, "Vote has ended. Vote ended in tie with %c%i%c yes and no votes.", BOLD, c->votestruct->yes, BOLD); privmsg(c->name, tmp); FreeVote(c); } } #ifdef Q int ChannelServiceCheck(struct channel *c) { /* Check channel for service */ if(c->ison == 0) return 0; if(findachanuser(Qu, c) != NULL) { if(c->service != 'Q') { c->service = 'Q'; dbchanmode(c->id, "service", "Q"); #ifdef DEBUG printf("New service set for channel: %s. Service: Q (hourly)\n", c->name); #endif } } #ifdef L else if(findachanuser(Lu, c) != NULL) { if(c->service != 'L') { c->service = 'L'; dbchanmode(c->id, "service", "L"); #ifdef DEBUG printf("New service set for channel: %s. Service: L (hourly)\n", c->name); #endif } } #endif else { if(c->service != '\0') { c->service = '\0'; dbchanmode(c->id, "service", ""); #ifdef DEBUG printf("New service set for channel: %s. Service: None (hourly)\n", c->name); #endif } } return 1; } #endif int ChannelBanEnforce(struct channel *c) { /* Channel ban enforcement */ struct activeuser *u; if(c->ison == 0 || c->isop == 0) return 0; u = firstauser; while (u != NULL) { if(findachanuser(u, c) != NULL) BannedUser(c, u); u = u->next; } return 1; } struct arm *bestarm(void) { struct arm *a; int leastdatainbuf = 999999999; struct arm *bestarm = NULL; int randarm, carm; randarm = rand()%armcount; a = firstarm; for(carm = 0; carm <= randarm && a != NULL; ++carm) { if((a->datainbuff <= leastdatainbuf) && a->status == 1) { bestarm = a; leastdatainbuf = a->datainbuff; } a = a->next; } if(bestarm == NULL) { a = firstarm; while(a != NULL) { if((a->datainbuff <= leastdatainbuf) && a->status == 1) { bestarm = a; leastdatainbuf = a->datainbuff; if(leastdatainbuf == 0) a = lastarm; } a = a->next; } } assert(bestarm != NULL); if(bestarm->datainbuff != 0) { a = firstarm; while(a != NULL) { if((a->datainbuff <= leastdatainbuf) && a->status == 1) { bestarm = a; leastdatainbuf = a->datainbuff; if(leastdatainbuf == 0) a = lastarm; } a = a->next; } } return bestarm; } void delallachanusers (struct channel *c) { struct activechanuser *acu; /* Delete all active channel users */ acu = firstacu; while (acu != NULL) { if(acu->channel == c) delachanuser(acu, acu->user); acu = acu->next; } #ifdef DEBUG printf("All active channel users for channel: %s deleted\n", c->name); #endif } int delallauserchans (struct activeuser *u) { struct aculink *aculink; struct aculink *next; #ifdef DEBUG printf("Deleting all active channels for user: %s\n", u->nick); #endif aculink = u->firstlink; while (aculink != NULL) { next = aculink->next; if(delachanuser(aculink->link, u)) return 1; aculink = next; } return 0; } void loadarms () { dbquery("UPDATE `arms` SET `status` = 0, `channels` = 1 WHERE `sid` = " SID ""); EndDbQuery(); dbquery("SELECT `id`, `nick`, `type`,`auth` FROM `arms` WHERE `sid` = " SID " ORDER BY `id`"); while((row = mysql_fetch_row(res))) { addarm (row[1], row[3], atoi(row[0]), atoi(row[2])); } EndDbQuery(); } void loadchannellist () { char service = '\0'; dbquery("SELECT * FROM `channels` WHERE `sid` = " SID ""); while((row = mysql_fetch_row(res))) { sscanf(row[18], "%c", &service); addchannel (row[1], atoi(row[0]), row[2], row[3], atoi(row[4]), atoi(row[5]), atoi(row[6]), atoi(row[7]), row[8], atoi(row[9]), row[10], atoi(row[11]), atoi(row[12]), atoi(row[13]), atoi(row[14]), atoi(row[15]), atoi(row[16]), findarmbyid(atoi(row[21])), row[17], service, atoi(row[19]), atoi(row[20])); } EndDbQuery(); dbquery("SELECT * FROM `chanusers` WHERE `sid` = " SID " "); while((row = mysql_fetch_row(res))) { addchanuser (findchannelbyid(atoi(row[0])), atoi(row[1]), atoi(row[2]), row[3]); } EndDbQuery(); dbquery("SELECT `cid`, `uid`, `host`, `setby`, `reason`, `expire` FROM `bans` WHERE `sid` = " SID ""); while((row = mysql_fetch_row(res))) { addban(findchannelbyid(atoi(row[0])), row[2], row[4], atoi(row[3]), atoi(row[5]), NULL, "", atoi(row[1]), 0); } EndDbQuery(); } void loadchannel (char *channame) { char query[MAX_QUERY], service = '\0'; sprintf(query, "SELECT * FROM `channels` WHERE `name` = '%s'", channame); dbquery(query); if((row = mysql_fetch_row(res))) { sscanf(row[18], "%c", &service); addchannel (row[1], atoi(row[0]), row[2], row[3], atoi(row[4]), atoi(row[5]), atoi(row[6]), atoi(row[7]), row[8], atoi(row[9]), row[10], atoi(row[11]), atoi(row[12]), atoi(row[13]), atoi(row[14]), atoi(row[15]), atoi(row[16]), findarmbyid(atoi(row[21])), row[17], service, atoi(row[19]), atoi(row[20])); } else printf("Something relly strange heappened, the channel (%s) I tried to load doesen't exist.\n", channame); EndDbQuery(); } void ReloadChannel(struct channel *c) { if(c == NULL) return; // Just to be safe char query[MAX_QUERY], service = '\0'; sprintf(query, "SELECT * FROM `channels` WHERE `id` = %i", c->id); dbquery(query); if((row = mysql_fetch_row(res))) { sscanf(row[18], "%c", &service); c->stats = atoi(row[16]); } else printf("Something relly strange heappened, the channel (%s) I tried to load doesen't exist.\n", c->name); EndDbQuery(); } void joinchannels (struct arm *a) { char msg[4096], query[MAX_QUERY]; struct channel *c; strncpy(msg, "JOIN ", 4096); c = firstchan; while (c != NULL && strlen(msg) < 4096-CHANNELLEN) { if(c->arm == a) { if(c->suspended == 0) { strcat(msg, c->name); strcat(msg, ","); c->ison = 0; // Assume we are NOT on the channel } ++a->channels; } c = c->next; } sprintf(query, "UPDATE `arms` SET `channels` = '%i' WHERE `id` = '%i'", a->channels, a->id); dbquery(query); EndDbQuery(); strcat(msg,"\n\r"); putserver(msg, a); } void adddbchannel (char *channame, struct arm *a) { char query[MAX_QUERY]; sprintf(query, "INSERT INTO channels (name, arm, sid) VALUES ('%s','%i','%i')", channame, a->id, atoi(SID)); dbquery(query); EndDbQuery(); } void deldbarm (char *arm) { struct arm *a; char query[MAX_QUERY]; a = findarm(arm); sprintf(query, "DELETE FROM channels WHERE arm = '%i'", a->id); dbquery(query); EndDbQuery(); sprintf(query, "DELETE FROM arms WHERE id = '%i'", a->id); dbquery(query); EndDbQuery(); } void deldbchannel (char *channame) { struct channel *c; char query[MAX_QUERY]; c = findchannel(channame); sprintf(query, "DELETE FROM channels WHERE id = '%i'", c->id); dbquery(query); EndDbQuery(); if(c->arm->type != BOT_CHECK) { sprintf(query, "DELETE FROM chanusers WHERE cid = '%i'", c->id); dbquery(query); EndDbQuery(); sprintf(query, "DELETE FROM log WHERE cid = '%d'", c->id); dbquery(query); EndDbQuery(); sprintf(query, "DELETE FROM quotes WHERE cid = '%d'", c->id); dbquery(query); EndDbQuery(); } } void dbchanmode (int id, char *option, char *value) { char query[MAX_QUERY]; char *esvalue; esvalue = escapequery(value); sprintf(query, "UPDATE `channels` SET `%s` = '%s' WHERE id = '%d'", option, esvalue, id); Free(esvalue); dbquery(query); EndDbQuery(); } void addlog(char *nick, char *channame, char *action, char *msg, struct arm *arm) { char tmp[512]; char *esnick, *esusername, *eshost, *esmsg; arm->parsevars->c = findchannel(channame); #ifdef LOGALL if(arm->parsevars->c != NULL && arm->parsevars->u != NULL) fprintf(fLogAll, "%s\t%s!%s@%s\t%s\t%i\t%i\t%s\n", channame, nick, arm->parsevars->u->username, arm->parsevars->u->hostname, action, arm->id, (int) time(NULL), msg); /* Add to the LogAll */ #endif // printf("Starting to log for: %s channel: %s action: %s msg: %s\n", nick, channame, action, msg); if((arm->parsevars->c == NULL || (arm->parsevars->c != NULL && arm->parsevars->c->stats == 0) || arm->parsevars->u == NULL) && strcasecmp(action, "QUIT") != 0 && strcasecmp(action, "NICK") != 0) return; if(lines != 0) strcat(LogQueryBuffer, ", "); if(strcasecmp(action, "QUIT") != 0 && strcasecmp(action, "NICK") != 0) { esmsg = escapequery(msg); snprintf(tmp, 512, "('%i', '%s'", arm->parsevars->c->id, esmsg); strcat(LogQueryBuffer, tmp); } else { esmsg = escapequery(channame); snprintf(tmp, 512, "('0', '%s'", esmsg); strcat(LogQueryBuffer, tmp); } if(esmsg != NULL) Free(esmsg); esnick = escapequery(nick); snprintf(tmp, 512, ", '%s', '%s', '%i'", action, esnick, (int) time(NULL)); strcat(LogQueryBuffer, tmp); if(esnick != NULL) Free(esnick); if(arm->parsevars->u != NULL) { esusername = escapequery(arm->parsevars->u->username); eshost = escapequery(arm->parsevars->u->hostname); snprintf(tmp, 512, ", '%s', '%s', '%i')", esusername, eshost, arm->parsevars->u->userid); strcat(LogQueryBuffer, tmp); if(esusername != NULL) Free(esusername); if(eshost != NULL) Free(eshost); } else { strcat(LogQueryBuffer, ", ', '', '0')"); } if(lines != LINESBEFORESAVE) ++lines; else flushlog(); } void flushlog() { printf("Flushing logs...\n"); logdbquery(LogQueryBuffer); EndLogDbQuery(); Free(LogQueryBuffer); LogQueryInit(); lines = 0; } void LogQueryInit(void) { /* Init the LogQueryBuffer pointer */ LogQueryBuffer = Malloc(LINESBEFORESAVE*512); strcpy(LogQueryBuffer, "INSERT DELAYED INTO `log` (`cid`, `msg`, `action`, `nick`, `time`, `username`, `host`, `uid`) VALUES "); } int isOpLessChan(struct channel *c) { /* This function checks if a channel is opless */ struct activechanuser *acu; if(c->isop == 1 || c->ison == 0) return 0; // We are op, so the channel can't be opless, or we are not on the channel so we suspect that there are ops there. acu = firstacu; while (acu != NULL) { if(acu->channel == c && acu->op == 1) return 0; // Found a guy that has op, so, why go on? acu = acu->next; } return 1; } int ServiceChannelCount(void) { /* This function returns the total number of channels that the service is on */ int channels; dbquery("SELECT COUNT(*) FROM `channels` WHERE `sid` = '" SID "'"); row = mysql_fetch_row(res); channels = atoi(row[0]); EndDbQuery(); return channels; } int UsersOnChannelCount(struct channel *c) { /* Count total number of users on a channel */ struct activechanuser *acu; int i = 0; for(acu = firstacu; acu != NULL; acu = acu->next) if(acu->channel == c) ++i; return i; } int OnJoinVoteMsg(struct channel *c, struct activeuser *u) { char ret[512]; if(c == NULL || c->votestruct == NULL) return 0; else { snprintf(ret, 512, "There is currently a vote going on in this channel. The question is: %c%s%c See more status and help with %c!vote status%c", BOLD, c->votestruct->question, BOLD, BOLD, BOLD); #ifdef CNOTICE cnotice(u->nick, ret); #else say(u->nick, ret, say); #endif return 1; } } time_t UnixtimeFromDate(char *date) { struct tm tmstruct; int year, month, day, hour, min; sscanf(date, "%d-%d-%d %d:%d", &year, &month, &day, &hour, &min); if((year < 2003 || year > 2004) || (month < 1 || month > 12) || (day < 1 || day > 31) || (hour < 0 || hour > 24) || (min < 0 || min > 60)) return -2; tmstruct.tm_sec = 0; tmstruct.tm_min = min; tmstruct.tm_hour = hour; tmstruct.tm_mday = day; tmstruct.tm_mon = month-1; tmstruct.tm_year = year-1900; return mktime(&tmstruct); } int StrDurationToSeconds(char *duration) { /* Parse a string with duration and return duration in seconds */ char msg[512]; int expire; if (strstr(duration, "h") != NULL) { STR_replace_c (duration, "h", "", msg); expire = time(NULL) + atoi(msg)*3600; } else if (strstr(duration, "m") != NULL) { STR_replace_c (duration, "m", "", msg); expire = time(NULL) + atoi(msg)*60; } else if (strstr(duration, "d") != NULL) { STR_replace_c (duration, "d", "", msg); expire = time(NULL) + atoi(msg)*86400; } else { return -1; // Should be handled with something like: say(arm->parsevars->sender, "Wrong duration, duration can be day(d), hour(h), minute(m). I.e: 2h (two hours)", arm); } return expire; } #ifdef Q_AUTOAUTH int SyncChannel (struct channel *c) { /* This sends an auth check on all users on a channel */ struct activechanuser *acu; acu = firstacu; while (acu != NULL) { if (acu->channel == c && acu->user->auth == UNAUTHED) add(acu->user); acu = acu->next; } return 1; } #endif int dbCount (char *query) { int count; dbquery(query); row = mysql_fetch_row(res); count = atoi(row[0]); EndDbQuery(); return count; } int AddRegexBadChan (char *regex, char *reason, int finalduration, int adder) { /* Ban a regex from request, using regular expressions */ char query[MAX_QUERY]; char *esregex, *esreason; snprintf(query, MAX_QUERY, "SELECT COUNT(*) FROM `badchan` WHERE `channel` = '%s' AND `active` = '1'", regex); if(dbCount(query) > 0) return 0; esregex = escapequery(regex); esreason = escapequery(reason); sprintf(query, "INSERT INTO `badchan` (`channel`,`adder`,`reason`,`time`, `expire`) VALUES ('%s', '%i', '%s', UNIX_TIMESTAMP(), '%i')", esregex, adder, esreason, finalduration); Free(esregex); Free(esreason); dbquery(query); EndDbQuery(); return 1; } int AddBadChan (char *channel, char *reason, int finalduration, int adder) { /* Ban a channel from request, apply regexp */ char regex[CHANNELLEN+2]; snprintf(regex, CHANNELLEN+2, "^%s$", channel); return AddRegexBadChan (regex, reason, finalduration, adder); } int DelBadChan (char *regex) { /* Remove regex from badchan */ char query[MAX_QUERY]; char *esregex; esregex = escapequery(regex); snprintf(query, MAX_QUERY, "SELECT COUNT(*) FROM `badchan` WHERE `channel` = '%s' AND `active` = '1'", esregex); if(dbCount(query) == 0) return 0; sprintf(query, "UPDATE `badchan` SET `active` = 0 WHERE `channel` = '%s' AND `active` = '1'", esregex); Free(esregex); dbquery(query); EndDbQuery(); return 1; } void CleanUpOldBadChans (void) { /* Remove old badchans from database */ dbquery("UPDATE `badchan` SET `active` = 0 WHERE `expire` < UNIX_TIMESTAMP() AND `active` = '1'"); EndDbQuery(); } #ifdef SPAMSCAN int SOnChannel(struct channel *c) { /* Will check if SpamScan is on a channel and return 1 if it is */ if(findachanuser(findauser(SPAMSCANNICK), c) == NULL) return 0; else return 1; } int SpamChannel(struct channel *c) { /* Returns 1 if it is ok to spam into the channel */ if(c->nextspam <= time(NULL)) return 1; else return 0; } int SpamChannelWait(struct channel *c) { /* Adds SPAMWAIT to nextspam */ c->nextspam = time(NULL) + SPAMWAIT; return 1; } #endif void EndDbQuery(void) { /* Unlock the mutex and cleanup used resources */ if(res != NULL) mysql_free_result(res); pthread_mutex_unlock(&mysqlmutex); // UnLock mutex } void EndLogDbQuery(void) { /* Unlock the mutex and cleanup used resources */ if(res != NULL) mysql_free_result(logres); pthread_mutex_unlock(&logmysqlmutex); // UnLock mutex } void OutOfChannel(struct channel *c) { /* Execute this when the bot is out from a channel, i.e a kick or a cycle */ c->ison = 0; delallachanusers(c); } struct generalinfo GetGeneralInfo (short _arminfo, short _channels, short _totalusers, short _percentused, short _usersonline, short _staffinfo, short _queueinfo) { /* Get some general information, return generalinfo struct */ struct generalinfo gistruct; float capacity, fchannels; struct activeuser *u; /* Init to zero */ gistruct.arms = gistruct.connectedarms = gistruct.channels = gistruct.totalusers = gistruct.percentused = gistruct.usersonline = gistruct.usersauthed = gistruct.helpersonline = gistruct.queueworkersonline = gistruct.techsonline = gistruct.mtechsonline = gistruct.queuestatus = 0; /* Info about ARMs */ if(_arminfo) { dbquery("SELECT `status` FROM `arms`"); while((row = mysql_fetch_row(res))) { ++gistruct.arms; if(atoi(row[0]) == 1) ++gistruct.connectedarms; } EndDbQuery(); } /* Channel info */ if(_channels) { /* Number of channels */ dbquery("SELECT count(*) FROM `channels`"); row = mysql_fetch_row(res); gistruct.channels = atoi(row[0]); EndDbQuery(); /* Total percent of capacity used */ if(_percentused) { fchannels = gistruct.channels; capacity = ((fchannels + gistruct.arms)/(MAXCHANS * gistruct.arms)) * 100; gistruct.percentused = capacity; } } /* Total users in database */ if(_totalusers) { dbquery("SELECT COUNT(*) FROM users"); if((row = mysql_fetch_row(res))) gistruct.totalusers = atoi(row[0]); EndDbQuery(); } /* Number of users online atm */ if(_usersonline) { u = firstauser; while (u != NULL) { ++gistruct.usersonline; if(u->auth >= NORMAL && u->auth < BOT_NORMAL) { ++gistruct.usersauthed; if(_staffinfo) { if(u->auth == HELPER) ++gistruct.helpersonline; else if(u->auth == QUEUE_WORKER) ++gistruct.queueworkersonline; else if(u->auth == TECHNICIAN) ++gistruct.techsonline; else if(u->auth == MASTER_TECHNICIAN) ++gistruct.mtechsonline; } } u = u->next; } } /* Items in queue */ if(_queueinfo) gistruct.queuestatus = ItemsInQueue(); return gistruct; } int ItemsInQueue (void) { /* Get number of request items in queue */ int i; dbquery("SELECT count(*) FROM `request` WHERE status = '0'"); row = mysql_fetch_row(res); i = atoi(row[0]); EndDbQuery(); return i; } int SendEmail (char *to, char *subject, char *body) { /* Send an E-Mail using sendmail */ char *run; int size; size = strlen(body) + strlen(to) + strlen(subject) + 512; run = Malloc(size); snprintf(run, size, "/bin/echo 'To: %s\r\nFrom: " BOTHOUSE " <" FROMEMAIL ">\r\nSubject: %s\r\nX-Mailer: Natasha\r\n%s' | /usr/sbin/sendmail %s", to, subject, body, to); system(run); Free(run); return 1; } int GetUserEmail (int userid, char *ret) { /* Get a users E-Mail address from the useremails table */ char query[MAX_QUERY]; snprintf(query, MAX_QUERY, "SELECT `email` FROM `useremails` WHERE `userid` = '%i'", userid); dbquery(query); if((row = mysql_fetch_row(res))) { /* E-Mail address found */ strncpy(ret, row[0], EMAILLEN); EndDbQuery(); return 1; } else { /* No E-Mail address found */ EndDbQuery(); return 0; } } int UserHasEmailSet (int userid) { /* Check if a user has his E-Mail set */ char query[MAX_QUERY]; snprintf(query, MAX_QUERY, "SELECT COUNT(*) FROM `useremails` WHERE `userid` = '%i'", userid); if(dbCount(query) == 0) return 0; else return 1; } int SetUserEmail (int userid, char *email) { /* Set a user email */ char query[MAX_QUERY]; if(UserHasEmailSet(userid)) { /* User already has E-Mail set, so we need to update */ snprintf(query, MAX_QUERY, "UPDATE `useremails` SET `email` = '%s' WHERE `userid` = '%i'", email, userid); dbquery(query); EndDbQuery(); return 1; } else { /* User doesen't have E-Mail set, so we need to insert a new record */ snprintf(query, MAX_QUERY, "INSERT INTO `useremails` (`userid`, `email`) VALUES ('%i', '%s')", userid, email); dbquery(query); EndDbQuery(); return 1; } } /* * HostMatch - match a hostmask against a string, returns 0 on match. * NOTE: This function is a direct ripoff from the the Undernet IRCd. */ int HostMatch(const char *mask, const char *string) { const char *m = mask, *s = string; char ch; const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */ /* Process the "head" of the mask, if any */ while ((ch = *m++) && (ch != '*')) switch (ch) { case '\\': if (*m == '?' || *m == '*') ch = *m++; default: if (ToLower(*s) != ToLower(ch)) return 1; case '?': if (!*s++) return 1; }; if (!ch) return *s; /* We got a star: quickly find if/where we match the next char */ got_star: bm = m; /* Next try rollback here */ while ((ch = *m++)) switch (ch) { case '?': if (!*s++) return 1; case '*': bm = m; continue; /* while */ case '\\': if (*m == '?' || *m == '*') ch = *m++; default: goto break_while; /* C is structured ? */ }; break_while: if (!ch) return 0; /* mask ends with '*', we got it */ ch = ToLower(ch); while (ToLower(*s++) != ch) if (!*s) return 1; bs = s; /* Next try start from here */ /* Check the rest of the "chunk" */ while ((ch = *m++)) { switch (ch) { case '*': goto got_star; case '\\': if (*m == '?' || *m == '*') ch = *m++; default: if (ToLower(*s) != ToLower(ch)) { m = bm; s = bs; goto got_star; }; case '?': if (!*s++) return 1; }; }; if (*s) { m = bm; s = bs; goto got_star; }; return 0; } int BannedUser(struct channel *c, struct activeuser *u) { char hostmask[HOSTLEN+NICKLEN+USERLEN+10], kickreason[512], realbanhost[HOSTLEN+NICKLEN+USERLEN+10]; struct banlist *ban; if(c == NULL || u == NULL) return 0; snprintf(hostmask, HOSTLEN+NICKLEN+USERLEN+10, "%s!%s@%s", u->nick, u->username, u->hostname); ban = c->firstbanlist; while(ban != NULL) { if(strstr(ban->host, "!") == NULL) snprintf(realbanhost, HOSTLEN+NICKLEN+USERLEN+10, "*!%s", ban->host); else strncpy(realbanhost, ban->host, HOSTLEN+NICKLEN+USERLEN+10); if((u->userid != 0 && u->userid == ban->uid) || (!HostMatch(realbanhost, hostmask))) { /* We ban on channel */ sprintf(kickreason, "MODE %s +b %s\n\r", c->name, hostmask); putserver(kickreason, c->arm); snprintf(kickreason, 512, "Banned, reason: %c%s%c", BOLD, ban->reason, BOLD); kick(c->name, u->nick, kickreason); return 1; } ban = ban->next; } return 0; } #ifdef L void CheckLWhoaamiRow(struct arm *arm, char *row) { char channel[CHANNELLEN]; char modes[5]; char msg[512]; struct channel *c; sscanf(row, "%" STRCHANNELLEN "s %s", channel, modes); c = findchannel(channel); if(irc_strcmp(channel, HOMECHAN) != 0 && (c == NULL || c->arm != arm)) { snprintf(msg, 512, "Channel: %s removed from L", channel); exprivmsg(HOMECHAN, msg, firstarm); snprintf(msg, 512, "chanlev %s %s -%s", channel, arm->nick, modes); exprivmsg(L_NICK, msg, arm); } } #endif #ifdef Q_AUTOAUTH /* Auth a user by supplying Q auth and user pointer */ void AuthUser(struct activeuser *u, char *auth) { char query[MAX_QUERY]; char *esauth; char *textauth; struct aculink *aculink; #ifdef DEBUG printf("QQ\n"); #endif esauth = escapequery(auth); snprintf(query, MAX_QUERY, "SELECT `id`,`auth` FROM `users` WHERE `handle` = '%s'", esauth); #ifdef DEBUG printf("db\n"); #endif dbquery(query); #ifdef DEBUG printf("here\n"); #endif if(!(row = mysql_fetch_row(res))) { EndDbQuery(); sprintf(query, "INSERT INTO `users` (`handle`) VALUES ('%s')", esauth); dbquery(query); EndDbQuery(); #ifdef DEBUG printf("here\n"); #endif sprintf(query, "SELECT `id`,`auth` FROM `users` WHERE handle = '%s'", esauth); dbquery(query); #ifdef DEBUG printf("here\n"); #endif if(!(row = mysql_fetch_row(res))) { privmsgf(HOMECHAN, "ERROR: Fatal error, check user database. (%s)", esauth); EndDbQuery(); Free(esauth); return; } } #ifdef DEBUG printf("afterdb\n"); #endif u->userid = atoi(row[0]); if(u->auth != IRC_OPERATOR) u->auth = atoi(row[1]); EndDbQuery(); if(u->auth > NORMAL && u->auth != IRC_OPERATOR && u->isinhome == 0) { textauth = authtotext(u->auth); #ifdef SAFEHOME #ifdef MAIN snprintf(query, 512, "INVITE %s " HOMECHAN "\n\r", u->nick); if(u->auth >= LEASTINHOME) putserver (query, firstarm); /* if(u->auth >= LEASTINHOME) { snprintf(query, MAX_QUERY, "Welcome %c%s%c, the current access key to %c%s%c is %c%s%c", BOLD, textauth, BOLD, BOLD, HOMECHAN, BOLD, BOLD, homekey, BOLD); privmsg(u->nick, query); } */ #endif #endif setrightmode(NULL, u); sprintf(query, "%s logged in: %s (%s)", textauth, u->nick, auth); Free(textauth); privmsg(HOMECHAN, query); } strncpy(u->hand, auth, NICKLEN); #ifdef DEBUG printf("setrightmode\n"); #endif aculink = u->firstlink; while (aculink != NULL) { setrightmode(aculink->link, aculink->link->user); aculink = aculink->next; } snprintf(query, MAX_QUERY, "UPDATE `users` SET `lastseen` = UNIX_TIMESTAMP() WHERE id = '%d'", u->userid); dbquery(query); EndDbQuery(); Free(esauth); #ifdef DEBUG printf("End of AuthUser\n"); #endif } #endif int ActiveStaff(struct activeuser *u) { /* Activate a staff member, returns: 1: Done, 0: Not a staff member -1: Not authed -2: Already active */ char query[MAX_QUERY]; char *textauth; if(u->auth == UNAUTHED) { u->check = time(NULL); return -1; // Not authed } else if(u->auth > SERVICE_FRIEND) return -2; // Already active else { snprintf(query, MAX_QUERY, "SELECT `auth` FROM `users` WHERE `id` = '%i'", u->userid); dbquery(query); row = mysql_fetch_row(res); if(atoi(row[0]) > SERVICE_FRIEND) u->auth = atoi(row[0]); else { EndDbQuery(); return 0; // Not a staff member } EndDbQuery(); SetCorrectStaffChannelMode(u); textauth = authtotext(u->auth); sprintf(query, "%c%s%c is now active as a %c%s%c", BOLD,u->nick, BOLD, BOLD, textauth, BOLD); Free(textauth); privmsg(HOMECHAN, query); return 1; } } int InActiveStaff(struct activeuser *u) { /* InActivate a staff member, returns: 1: Done, 0: Not active */ char msg[256]; if(u->auth <= NORMAL || u->auth >= IRC_OPERATOR) return 0; else { u->auth = 1; SetCorrectStaffChannelMode(u); sprintf(msg, "%c%s%c is now inactive", BOLD, u->nick, BOLD); privmsg(HOMECHAN, msg); return 1; } } #ifdef MAIN int SetCorrectStaffChannelMode(struct activeuser *u) { /* Sets correct modes for staff member on channels where the main bot is */ /* struct channel *c; char modechange[256]; c = firstchan; while(c != NULL) { if(c->arm == firstarm) { if(u->auth <= NORMAL) snprintf(modechange, 256, "MODE %s -o+v %s %s\n\r", c->name, u->nick, u->nick); else snprintf(modechange, 256, "MODE %s -v+o %s %s\n\r", c->name, u->nick, u->nick); putserver(modechange, firstarm); } c = c->next; } if(u->auth <= NORMAL) snprintf(modechange, 256, "MODE " HOMECHAN " -o+v %s %s\n\r", u->nick, u->nick); else snprintf(modechange, 256, "MODE " HOMECHAN " -v+o %s %s\n\r", u->nick, u->nick); putserver(modechange, firstarm); */ return 1; } #endif