/* * bot.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 #include #include #include #include #include #include #include #include #include "bottypes.h" #include "settings.h" #include "globals.h" #include "modules/irchandlers/servtab.h" int nextcheck; int lines = 0; int rejoint = 0; int reloadmsgmod = 0; int reloadircmod = 0; short connectarms = 1; #ifdef SAFEHOME #ifdef MAIN int nextsecure; #endif char homekey[KEYLEN]; #endif char compiledate[] = __DATE__ " " __TIME__; MYSQL mysql, *sock; MYSQL_RES *res; MYSQL_ROW row; MYSQL logmysql, *logsock; MYSQL_RES *logres; MYSQL_ROW logrow; /* Global mutexes */ pthread_mutex_t mysqlmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t logmysqlmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalusermutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalchannelmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalchanusermutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalacumutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalmodmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalarmmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalbanmutex=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t globalmutex=PTHREAD_MUTEX_INITIALIZER; /* * The heads and tails of the linked lists used for all the databases. */ struct arm *lastarm = NULL; struct arm *firstarm = NULL; struct module *firstmodule = NULL; struct module *lastmodule = NULL; struct activeuser *lastauser = NULL; struct activeuser *firstauser = NULL; struct channel *firstchan = NULL; struct channel *lastchan = NULL; struct chanuser *firstchanuser = NULL; struct chanuser *lastchanuser = NULL; struct activechanuser *firstacu = NULL; struct activechanuser *lastacu = NULL; void cquit(int); void seg(int); void sigusr1(int); void stresstest(int); /* * OK, Useful functions. */ char *STR_replace_c (char *source, char *old, char *new, char *dest) { int i=0, j=0; int lold, lnew, lsource; int tempwork=0; int templen=1024; char *tempdest; /* create a temp work area if source = dest */ if (source == dest) { tempwork = 1; tempdest = calloc(templen, sizeof(char)); } else { /* since dest is different from source, do work in dest */ tempdest = dest; } lold = strlen(old); lnew = strlen(new); lsource = strlen (source); while (i < (lsource - lold + 1)) { /* if temparea used and too small, increase its size */ if (tempwork && ((j + lnew) >= templen)) { templen += 256; tempdest = realloc(tempdest, templen * sizeof(char)); } if (strncmp (&source[i], old, lold)) { tempdest[j++] = source[i++]; } else { strcpy (&tempdest[j], new); j = j + lnew; i = i + lold; } } /* if temp work area used and too small, increase its size */ if (tempwork && ((j + strlen(&source[i])) >= templen)) { templen += 256; tempdest = realloc(tempdest, templen * sizeof(char)); } tempdest[j] = 0; strcat (&tempdest[j], &source[i]); /* if a temp work area was used, copy to final dest */ if (tempwork && ((j + strlen(&source[i])) >= templen)) { templen += 256; tempdest = realloc(tempdest, templen * sizeof(char)); } tempdest[j] = 0; strcat (&tempdest[j], &source[i]); /* if a temp work area was used, copy to final dest */ if (tempwork) { strcpy(dest, tempdest); free(tempdest); } return (dest); } int regex_match(char *regex, char *string) { pcre *re; const char *error; int erroffset; int rc; /* Compile the regular expression in the first argument */ re = pcre_compile(regex, 0, &error, &erroffset, NULL); /* Compilation failed: print the error message and exit */ if (re == NULL) { printf("PCRE compilation failed at offset %d: %s\n", erroffset, error); return 0; } /* Compilation succeeded: match the subject in the second argument */ rc = pcre_exec(re, NULL, string, (int)strlen(string), 0, 0, NULL, 0); if (rc < 0) return 0; return 1; } void dbconnect (void) { if (!(sock = mysql_real_connect(&mysql,MYSQL_SERVER,MYSQL_USER,MYSQL_PASS,MYSQL_DB,MYSQL_PORT,NULL,0))) { fprintf(stderr,"Couldn't connect to MySQL server!\n%s\n\n", mysql_error(&mysql)); perror(""); exit(1); } } void logdbconnect (void) { if (!(logsock = mysql_real_connect(&logmysql,MYSQL_LOGSERVER,MYSQL_LOGUSER,MYSQL_LOGPASS,MYSQL_LOGDB,LOGMYSQL_PORT,NULL,0))) { fprintf(stderr,"Couldn't connect to Log-MySQL server!\n%s\n\n", mysql_error(&logmysql)); perror(""); exit(1); } } void dbquery (char *query) { char tmp[512]= ""; pthread_mutex_lock(&mysqlmutex); // Lock mutex if(mysql_query(sock, query)) { #ifdef DEBUG printf("Query failed (%s)\n", mysql_error(sock)); #endif snprintf(tmp, 512, "%c4Warning:%c Query failed (%s). Query: %s", COLORS, COLORS, mysql_error(sock), query); privmsg(HOMECHAN, tmp); if(strcmp(mysql_error(sock), "MySQL server has gone away") == 0 || strcmp(mysql_error(sock), "Lost connection to MySQL server during query") == 0) { dbconnect(); usleep(200); mysql_query(sock, query); if(!mysql_query(sock, query)) res = mysql_store_result(sock); } } else res = mysql_store_result(sock); } void logdbquery (char *query) { char tmp[512]= ""; pthread_mutex_lock(&logmysqlmutex); // Lock mutex if(mysql_query(logsock, query)) { #ifdef DEBUG printf("Query failed (%s)\n", mysql_error(logsock)); #endif snprintf(tmp, 512, "%c4Warning:%c Query failed (%s). Query: %s", COLORS, COLORS, mysql_error(logsock), query); privmsg(HOMECHAN, tmp); if(strcmp(mysql_error(logsock), "MySQL server has gone away") == 0 || strcmp(mysql_error(logsock), "Lost connection to MySQL server during query") == 0) { logdbconnect(); usleep(200); mysql_query(logsock, query); if(!mysql_query(logsock, query)) logres = mysql_store_result(logsock); } } else logres = mysql_store_result(logsock); } char *escapequery (char *query) { char *escaped = malloc(2*strlen(query)); mysql_real_escape_string(&mysql, escaped, query, strlen(query)); return escaped; } void loadmodulesinconf (void) { char path[100]; FILE *pFile; pFile = fopen ("modules.conf","r"); if(pFile == NULL) { printf("Could not open modules.conf, Natasha aborting.\n"); exit(0); } while (fscanf (pFile, "%s\n", path) != EOF) if(path[0] != '#' && path[0] != '\0') loadmodule(path, 1); // while (fgets(path, 100, pFile) != EOF) if(path[0] != '#' && path[0] != '\0') loadmodule(path, 1); fclose (pFile); } char *loaddatafromfile (char *file) { FILE *pFile; static char buffer[513]; pFile = fopen (file,"r"); if(pFile == NULL) { printf("Could not open: %s.\n", file); return &(buffer[1]); } fgets (buffer , 512 , pFile); fclose (pFile); return &(buffer[0]); } int writedatatofile (char *file, char *data) { FILE *pFile; pFile = fopen (file, "w"); if(pFile == NULL) { printf("Could not open: %s.\n", file); return 0; } fputs (data, pFile); fclose (pFile); return 1; } #ifdef MAIN #ifdef SAFEHOME void securehome (void) { char msg[512]; char newkey[KEYLEN]; srand (time(NULL)); /* Init random number generator */ snprintf(msg, 512, "MODE " HOMECHAN " -k %s\n\r", homekey); /* Remove old key */ putserver(msg, firstarm); snprintf(newkey, KEYLEN, "SE%iE", rand()); /* Generate new key */ snprintf(msg, 512, "MODE " HOMECHAN " +k %s\n\r", newkey); /* Set new key */ putserver(msg, firstarm); printf("Home channel secured, new key set to: %s\n", newkey); } #endif #endif int countargs(char *string) { int i = 0; int args = 0; for(i = 0; string[i] != '\0'; ++i) { if(args == 0) args = 1; else if(string[i] == ' ') ++args; } return args; } int checkargs(int numargs, int type, char *string, struct arm *a) { struct module *m; void (*cmd)(); /* Type 0: Exact 1: More 2: Less */ if((type == 0 && countargs(string) != numargs) || (type == 1 && countargs(string) < numargs) || (type == 2 && countargs(string) > numargs)) { say(a->parsevars->sender, "Wrong number of arguments.", a); m = findmodule("MSGHandlers"); if(m != NULL) { cmd = dlsym(m->fl, "m_help"); cmd(a->parsevars->command, a); } return 0; } else return 1; } void add (struct activeuser *u) { /* Make a whois and add the user */ char whois[10+NICKLEN] = ""; #ifdef Q if(strcasecmp(u->nick, Q_NICK) == 0) return; #ifdef L if(strcasecmp(u->nick, L_NICK) == 0) return; #endif #endif sprintf(whois, "WHOIS %s\n\r", u->nick); putserver (whois, bestarm()); return; } void violation (char *sender, char action[256], char *channel) { char msg[512]; char tmstr[100]; time_t tim; struct tm *tmstruct; tim = time(NULL); tmstruct = localtime(&tim); strftime(tmstr, 9, "%H:%M:%S", tmstruct); sprintf(msg, "%c4Violation:%c %c%s%c %s %c%s%c (%c%s%c)", COLORS, COLORS, BOLD, sender, BOLD, action, BOLD, channel, BOLD, BOLD, tmstr, BOLD); privmsg(HOMECHAN, msg); } void cquit(int unused) { quit("Killed by console"); } void sigusr1(int unused) { pthread_mutex_unlock(&mysqlmutex); // UnLock mutex pthread_mutex_unlock(&globalmutex); // UnLock mutex printf("Recieved SIGUSR1, unlocking MySQL mutex and globalmutex.\n"); } void seg(int unused) { #ifdef DEBUG system("xmms --stop && echo \"Natasha sefmentation fault\" | festival --tts &"); #else system("sleep 10 && ./natasha &"); #endif printf("Segmentation fault\n"); exit(1); } void quit (char reason[]) { struct arm *a; char msg[512]; #ifdef MAIN #ifdef SAFEHOME snprintf(msg, 512, "MODE " HOMECHAN " -k %s\n\r", homekey); /* Remove key */ puttoserver(msg, firstarm); #endif #endif sprintf(msg, "QUIT :%s\n\r", reason); a = firstarm; while (a != NULL) { if(a->status == 1) { puttoserver(msg, a); close(a->fd); usleep(100); } a = a->next; } flushlog(); printf("Quiting: %s\n", reason); mysql_close(sock); mysql_close(logsock); exit(0); } /* Utility functions that actually do read/writes from the server. */ void puttoserver (char *text, struct arm *a) { int l, j; l = strlen (text); a->datasent += l; /* some sleep time */ if(a->datasent > 300) (a == firstarm) ? (a->nextsend = time(NULL) + a->datasent/100 + 2) : (a->nextsend = time(NULL) + a->datasent/100); j = write (a->fd, text, l); #ifdef DEBUG write (1, text, l); #endif if (j != l) { perror ("write:"); linkbreak(a); } } char *getline (struct arm *a) { static char buffer[513]; /* one more than defined maximum length */ int i = 0, j; i = 1; buffer[i] = 0; while ((buffer[i - 1] != '\n') && (i < 512)) { j = read (a->fd, &(buffer[i]), 1); if (j <= 0) { perror ("read"); linkbreak(a); buffer[i]=0; return &(buffer[i]); } if (j == 0) { linkbreak(a); buffer[i] = 0; return &(buffer[i]); } i++; } buffer[i] = 0; // printf("buffer(%i): %s\n", aid, &(buffer[1])); return &(buffer[1]); } void linkbreak (struct arm *a) { char query[512]; struct activechanuser *acu; printf("Link break for: %s\n", a->nick); if(a->fd) close(a->fd); a->fd = 0; a->status = 0; a->nextsend = time(NULL) + RECONFREQ; sprintf(query, "UPDATE `arms` SET `status` = '0' WHERE `id` = '%i'", a->id); dbquery(query); EndDbQuery(); if(a->channels != 0) { acu = firstacu; while (acu != NULL) { if(acu->channel->arm == a) { acu->channel->ison = 0; delachanuser(acu->user->nick, acu->channel->name); } acu = acu->next; } a->channels = 0; } } void startlink (struct arm *a) { struct hostent *server = NULL; struct sockaddr_in server_addr; char line[512]; char send[512]; #ifdef OUTGOING_VHOST struct hostent *vhost = NULL; struct sockaddr_in local_addr; #endif a->status = 1; while (a->firstsendqueue != NULL) delsendqueue(a); if (a->fd) { close (a->fd); } printf("Connecting arm: %s\n", a->nick); server = gethostbyname(SERVER); if(server == NULL) { printf("Looking up server hostname failed.\n"); a->status = 0; return; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(IRCPORT); memcpy (&(server_addr.sin_addr.s_addr), server->h_addr, server->h_length); a->fd = socket (AF_INET, SOCK_STREAM, 0); #ifdef OUTGOING_VHOST vhost = gethostbyname(a->vhost); if(vhost == NULL) { printf("Looking up vhost failed.\n"); a->status = 0; return; } memset(&local_addr, 0, sizeof(struct sockaddr_in)); local_addr.sin_family = AF_INET; memcpy (&(local_addr.sin_addr.s_addr), vhost->h_addr, vhost->h_length); if(bind(a->fd, (struct sockaddr *) &local_addr, sizeof(struct sockaddr_in))) { perror ("bind"); a->status = 0; return; } #endif if (connect (a->fd, (struct sockaddr *) &server_addr, sizeof (server_addr))) { perror ("connect"); a->status = 0; return; } a->nextsend = 0; sprintf(send, "UPDATE `arms` SET `status` = '1' WHERE `id` = '%i'", a->id); dbquery(send); EndDbQuery(); /* Establish a client connection. */ sprintf(send, "USER %s +iw %s :Natasha service owned by: %s\n\r", USERNAME, a->nick, BOTHOUSE); puttoserver(send, a); sprintf(send, "Nick %s\n\r", a->nick); puttoserver(send, a); while (strstr(line, " 255 ") == NULL) { strcpy(line, getline(a)); if(a->status == 0) return; // Return if connection goes down if(strstr(line, " 433 ") != NULL) { printf("Warning: Nick %s is stolen.\n", a->nick); sprintf(send, "%c4Warning:%c Nick %c%s%c is stolen.", COLORS, COLORS, BOLD, a->nick, BOLD); privmsg(HOMECHAN, send); puttoserver("QUIT :Nick stolen\n\r", a); usleep(200); linkbreak(a); return; } if (strstr(line, " 001 ") != NULL) { sscanf(line, ":%s 001 ", a->server); #ifdef DEBUG printf("Server name set to: %s\n", a->server); #endif } if (strstr(line, "PING :") != NULL) { #ifdef DEBUG printf("Ping<>Pong\n"); #endif serverpong(strstr(line, "PING"), a); } #ifdef DEBUG #ifdef SKIPMOTD if(strstr(line, " 372 ") == NULL && strstr(line, " 375 ") == NULL && strstr(line, " 376 ") == NULL) #endif printf("Server: %s\n", line); #endif } #ifdef DEBUG printf("Connected.\n"); #endif #ifdef Q /* Q auth stuff */ sprintf(line, "%s@%s", Q_NICK, Q_HOST); sprintf(send, "AUTH %s %s", a->nick, Q_PASS); exprivmsg(line, send, a); #ifdef DEBUG printf("Q AUTH'd.\n"); #endif #endif rejoinchannel(HOMECHAN, a); } void parse (char *buffer, struct arm *a) { int i, j; char msg[512] = ""; char host[HOSTLEN] = ""; char username[USERLEN] = ""; struct activeuser *u; #ifdef DEBUG // printf("Buffer: %s", buffer); #endif for (i = 0; i < MAX_ARGS; i++) strncpy(a->parsevars->args[i], "", 512); a->parsevars->argcount = 0; a->parsevars->sender[0] = 0; a->parsevars->command[0] = 0; /* Skip over any leading spaces. */ for (i = 0; buffer[i] && (buffer[i] == ' '); i++); /* * "i" had better increase monatomically from here on, or we're in * a lot of trouble. :) */ /* Check to see who sent it. */ if (buffer[i] == ':') { j = 0; for (i++; buffer[i] && (buffer[i] != '!' && buffer[i] != ' '); i++) { a->parsevars->sender[j] = buffer[i]; j++; } a->parsevars->sender[j] = 0; if(buffer[i] == '!') { ++i; for(j = 0; buffer[i] != '@'; ++i) { username[j] = buffer[i]; ++j; } ++i; for(j = 0; buffer[i] != ' '; ++i) { host[j] = buffer[i]; ++j; } j = 0; a->parsevars->isserver = 0; } else a->parsevars->isserver = 1; } if (!buffer[i]) { return; } /* Skip over leading spaces */ while (buffer[i] && (buffer[i] == ' ')) i++; j = 0; while ((buffer[i + j]) && !isspace (buffer[i + j]) && j < 512) j++; memcpy(a->parsevars->command, buffer + i, j); a->parsevars->command[j] = 0; /* * Good news, we got the command and the sender (probably). * Now all we need is the parameters and we're in business. :) */ i = i + j; while ((buffer[i]) && (buffer[i] != '\n') && (buffer[i] != '\r')) { while (buffer[i] == ' ') i++; /* Again, do a standard spaces-skip job. */ j = 0; if (buffer[i] == ':') { i++; /* Skip over the : */ while ((buffer[i] != 0) && (buffer[i] != '\n') && (buffer[i] != '\r')) { a->parsevars->args[a->parsevars->argcount][j] = buffer[i]; i++; /* Next char in both the source */ j++; /* and the destination strings */ } a->parsevars->args[a->parsevars->argcount][j] = 0; } else { while ((buffer[i] != 0) && (buffer[i] != '\n') && (buffer[i] != '\r') && (buffer[i] != ' ')) { a->parsevars->args[a->parsevars->argcount][j] = buffer[i]; i++; j++; } a->parsevars->args[a->parsevars->argcount][j] = 0; } a->parsevars->argcount++; } for (j = 0; servtab[j].func != NULL; j++) { if (!strcmp (a->parsevars->command, servtab[j].msg)) { u = findauser(a->parsevars->sender); if(u == NULL && (strcmp(a->parsevars->command, "NICK") == 0 || strcmp(a->parsevars->command, "QUIT") == 0)) return; if(u == NULL && a->parsevars->isserver == 0 && strcmp("", a->parsevars->sender) != 0) { #ifdef DEBUG printf("New active user: %s host: %s username: %s command: %s\n", a->parsevars->sender, host, username, a->parsevars->command); #endif u = addauser(a->parsevars->sender, username, host); #ifdef DEBUG printf("- Doing whois\n"); #endif #ifdef Q_AUTOAUTH add(u); #endif } if(u != NULL) u->lastseen = time(NULL); i = 1; while(i < MAX_ARGS && a->parsevars->args[i][0] != '\x0') { if(strcmp(a->parsevars->command, "PRIVMSG") != 0 && i != 1) strcat(msg, " "); strcat(msg, a->parsevars->args[i]); ++i; } if(u != NULL || a->parsevars->isserver == 1 || strcmp(a->parsevars->command, "PING") == 0) { /* First we log */ #ifdef DEBUG printf("- Logging\n"); #endif addlog(a->parsevars->sender, a->parsevars->args[0], a->parsevars->command, msg); #ifdef DEBUG printf("- Exec: %s\n", a->parsevars->command); #endif amodfunc("IRCHandlers", servtab[j].func, a); #ifdef DEBUG printf("- End\n"); #endif } return; } } } /* A main function to handle the reads/sends for each arm */ void *armthread (void* ptr) { struct arm *a = (struct arm*)ptr; struct timeval tm; int rc; startlink(a); if(a->status == 0) return NULL; joinchannels(a); while(a->status == 1) { /* First we send data in queue */ if(time(NULL) >= a->lastreset+EXCESSRESET) { a->datasent = 0; a->nextsend = 0; a->lastreset = time(NULL); } if((a->nextsend < time(NULL)) && (a->firstsendqueue->data != NULL)) { puttoserver(a->firstsendqueue->data, a); delsendqueue(a); } /* Now we read */ tm.tv_usec=50000; tm.tv_sec=0; FD_ZERO (&a->r); FD_SET (a->fd, &a->r); rc = select (a->fd + 1, &a->r, NULL, NULL, &tm); if (rc==-1) { if (errno!=EINTR) { perror("select!=EINTR"); } else { perror("select==EINTR"); } } else if (rc>0) { if (FD_ISSET(a->fd,&a->r)) { if(!pthread_mutex_trylock(&globalmutex)) { parse(getline(a), a); pthread_mutex_unlock(&globalmutex); } else usleep(500000); } else { fprintf(stderr,"FD_ISSET unknown.\n"); } } } return NULL; } int main (int argc, char **argv) { char tmp[512]; int lastmysql, i; struct arm *a; signal(SIGINT, cquit); signal(SIGSEGV, seg); signal(SIGUSR1, sigusr1); signal(SIGUSR2, stresstest); printf("%s\n\nConnecting to MySQL database.\n", CTCP_VERSION_REPLY); mysql_init(&mysql); mysql_init(&logmysql); dbconnect(); logdbconnect(); printf("Loading database.\n"); loadarms(); loadchannellist(); printf("Loading modules.\n"); loadmodulesinconf(); #ifdef SAFEHOME strncpy(homekey, loaddatafromfile("homekey"), KEYLEN); #endif i = time(NULL); a = firstarm; while (a != NULL) { a->nextsend = i; i += RECONFREQ; a = a->next; } nextcheck = time(NULL); lastmysql = time(NULL); rejoint = time(NULL) + 180; #ifdef MAIN #ifdef SAFEHOME nextsecure = time(NULL) + 60; #endif #endif printf("Initiating main loop.\n\n"); /* Main loop */ while (1) { /* Here we check for some "timeouts" */ if(time(NULL) >= nextcheck) { #ifdef DEBUG printf("Processing scheduled tasks.\n"); #endif /* Reload MSGHandlers or IRCHandlers if requested */ if(reloadmsgmod == 1) { strncpy(tmp, findmodule("MSGHandlers")->path, 100); unloadmodule("MSGHandlers"); loadmodule(tmp, 0); reloadmsgmod = 0; } if(reloadircmod == 1) { strncpy(tmp, findmodule("IRCHandlers")->path, 100); unloadmodule("IRCHandlers"); loadmodule(tmp, 1); reloadircmod = 0; } modfunc("Graph", "graphmain"); // The graphs modfunc("Request", "spewchan"); // Spew request data to public channe #ifdef MAIN #ifdef SAFEHOME /* Home channel security */ if(nextsecure < time(NULL)) { securehome(); nextsecure = time(NULL) + SECURETIME; } #endif #endif /* MySQL keepalive */ if(lastmysql+10000 < time(NULL)) { #ifdef DEBUG printf("Reconnect MySQL\n"); #endif pthread_mutex_lock(&mysqlmutex); // Lock mutex mysql_close(sock); dbconnect(); pthread_mutex_unlock(&mysqlmutex); // UnLock mutex pthread_mutex_lock(&logmysqlmutex); // Lock mutex mysql_close(logsock); logdbconnect(); pthread_mutex_unlock(&logmysqlmutex); // UnLock mutex lastmysql = time(NULL); } // Join dead threads pthread_mutex_lock(&globalmutex); // Lock MuteX a = firstarm; while (a != NULL) { if(a->status == 0 && a->activethread == 1) { if(pthread_join(a->thread, NULL)) printf("Error joining thread for %s.", a->nick); a->activethread = 0; } a = a->next; } pthread_mutex_unlock(&globalmutex); // UnLock MuteX // Create threads for disconnected arms if(connectarms == 1) { pthread_mutex_lock(&globalmutex); // Lock MuteX a = firstarm; while (a != NULL) { if(a->status == 0 && a->activethread == 0 && a->nextsend <= time(NULL) && a->connect == 1) { if(pthread_create(&a->thread, NULL, armthread, a)) printf("Error creating thread for %s.", a->nick); a->activethread = 1; a = NULL; } else a = a->next; } pthread_mutex_unlock(&globalmutex); // UnLock MuteX } #ifdef DEBUG printf("Timer User Loop.\n"); #endif // Clear old activeusers and bans TimerUserLoop(); #ifdef DEBUG printf("Timer Channel Loop\n"); #endif TimerChannelLoop(); CleanUpOldBadChans(); #ifdef DEBUG printf("End Of Loops\n"); #endif // Set new nextcheck nextcheck = time(NULL) + CHECK_TIME; } usleep(500000); } return 0; } /* Stresstest code */ void stresstest(int unused) { struct arm *a; a = findarm("Natasha-dev"); pthread_mutex_lock(&globalmutex); // Lock MuteX printf("Stresstest begin\n"); while(1) parse(":barrysworld1.uk.quakenet.org 330 Natasha-dev BteEst SkalMan :is authed as\n\r", a); }