/* * memory.c * (C) Peter Salanki 2004 * 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" struct activeuser *addauser (char *nick, char *username, char *hostname) { struct activeuser *newuser; newuser = (struct activeuser *) Malloc (sizeof (struct activeuser)); if (newuser == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return newuser; } memset (newuser, 0, sizeof (struct activeuser)); // printf("Debug: Space allocated for %s.\n", nick); strncpy (newuser->nick, nick, NICKLEN); newuser->username = DupString(username); newuser->hostname = DupString(hostname); newuser->auth = 0; newuser->userid = 0; newuser->lastseen = time(NULL); newuser->isinhome = 0; newuser->requestok = 0; #ifdef Q_AUTOAUTH newuser->check = 0; #endif #ifdef UMODE_x /* Need to be recoded to more efficient code */ if(strstr(newuser->hostname, UMODE_x_hostappend) != NULL) add(newuser); #endif newuser->firstlink = NULL; newuser->lastlink = NULL; newuser->last = lastauser; newuser->next = NULL; if (lastauser != NULL) { lastauser->next = newuser; } else { /* * No final user yet defined, so this one must be the * very first one. */ firstauser = newuser; } lastauser = newuser; #ifdef Q if(strcasecmp(nick, Q_NICK) == 0) Qu = newuser; #ifdef L else if(strcasecmp(nick, L_NICK) == 0) Lu = newuser; #endif #endif return newuser; } struct aculink *addaculink (struct activeuser *u, struct activechanuser *acu) { struct aculink *newaculink; newaculink = (struct aculink *) Malloc (sizeof (struct aculink)); if (newaculink == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return newaculink; } memset (newaculink, 0, sizeof (struct aculink)); newaculink->link = acu; newaculink->last = u->lastlink; newaculink->next = NULL; if (u->lastlink != NULL) { u->lastlink->next = newaculink; } else { u->firstlink = newaculink; } u->lastlink = newaculink; return newaculink; } /* Add an arm */ void addarm (char *nick, char *auth, int aid, int type) { struct arm *newarm; if (findarm(nick) == NULL) { newarm = (struct arm *) Malloc (sizeof (struct arm)); if (newarm == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return; } memset (newarm, 0, sizeof (struct arm)); #ifdef DEBUG printf("Debug: Space allocated for arm: %s.\n", nick); #endif strncpy (newarm->nick, nick, NICKLEN); strncpy (newarm->auth, auth, NICKLEN); strncpy (newarm->server, SERVER, 50); #ifdef OUTGOING_VHOST strncpy (newarm->vhost, DEFAULT_VHOST, 150); #endif newarm->id = aid; newarm->fd = -1; newarm->datasent = 0; newarm->datainbuff = 0; newarm->lastreset = 0; newarm->nextsend = 0; newarm->status = 0; newarm->channels = 0; newarm->type = type; newarm->connect = 1; /* Parsevar Malloc() */ newarm->parsevars = (struct parsevars *) Malloc (sizeof (struct parsevars)); ++armcount; /* Increase global arm counter */ newarm->last = lastarm; newarm->next = NULL; if (lastarm != NULL) { lastarm->next = newarm; } else { /* * No final user yet defined, so this one must be the * very first one. */ firstarm = newarm; } lastarm = newarm; } } /* Loadmodule */ struct module *loadmodule (char *path, short fatal) { struct module *newmodule = NULL; const char *err; char msg[512]; void (*cmd)(struct module *m); if (findmodulebypath(path) == NULL) { newmodule = (struct module *) Malloc (sizeof (struct module)); if (newmodule == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return NULL; } memset(newmodule, 0, sizeof (struct module)); strncpy(newmodule->path, path, 100); newmodule->fl = dlopen(path, RTLD_NOW); err = dlerror(); if(err) { printf("Error loading module: %s.\n", err); snprintf(msg, 512, "%c4Warning:%c Module load failed (%c%s%c). Error: %s", COLORS, COLORS, BOLD, path, BOLD, err); privmsg(HOMECHAN, msg); Free(newmodule); if(fatal == 1) exit(1); return NULL; } else { strncpy(newmodule->name, "UnNamed", 20); } newmodule->last = lastmodule; newmodule->next = NULL; if (lastmodule != NULL) { lastmodule->next = newmodule; } else { /* * No final user yet defined, so this one must be the * very first one. */ firstmodule = newmodule; } lastmodule = newmodule; } cmd = dlsym(newmodule->fl, "_module_init"); err = dlerror(); if(err) { snprintf(msg, 512, "%c4Error:%c Init function does not exist in module. Module load aborted.", COLORS, COLORS); privmsg(HOMECHAN, msg); unloadmodule("UnNamed"); return NULL; } cmd(newmodule); printf("Successfully loaded: %s version: %0.2f\n", newmodule->name, newmodule->version); return newmodule; } void unloadmodule (char *name) { struct module *m; const char *err; void (*cmd)(struct module *m); m = findmodule(name); if (m == NULL) return; cmd = dlsym(m->fl, "_module_destroy"); err = dlerror(); if(err) printf("Warning: destroy function in module: %s is missing\n", name); else cmd(m); dlclose(m->fl); if (m->last != NULL) { m->last->next = m->next; /* Reset the next pointer */ } else { firstmodule = m->next; } if (m->next != NULL) { m->next->last = m->last; /* and the last pointer */ } else { lastmodule = m->last; } Free(m); /* And remove the module from memory. */ } /* Add an active channel user */ struct activechanuser *addachanuser (struct activeuser *u, struct channel *c) { struct activechanuser *newactivechanuser; if(c == NULL || u == NULL) { if(u != NULL && c == NULL) { u->isinhome = 1; return NULL; } return NULL; } if(findachanuser(u, c) != NULL) return NULL; newactivechanuser = (struct activechanuser *) Malloc (sizeof (struct activechanuser)); if (newactivechanuser == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return NULL; } memset (newactivechanuser, 0, sizeof (struct activechanuser)); #ifdef DEBUG printf("Debug: Space allocated for active channel user %s.\n", u->nick); // Debugging code #endif newactivechanuser->channel = c; newactivechanuser->user = u; newactivechanuser->op = 0; newactivechanuser->voice = 0; newactivechanuser->warned = 0; newactivechanuser->lastreset = time(NULL); newactivechanuser->rows = 0; newactivechanuser->last = lastacu; newactivechanuser->next = NULL; if (lastacu != NULL) { lastacu->next = newactivechanuser; } else { /* * No final user yet defined, so this one must be the * very first one. */ firstacu = newactivechanuser; } lastacu = newactivechanuser; addaculink(u, newactivechanuser); return newactivechanuser; } /* Add a ban on a channel */ int addban (struct channel *c, char *host, char *reason, int setby, int expire, struct activeuser *u, char *kickreason, int uid, short mysql) { struct banlist *newban; char msg[CHANNELLEN+10+BANLEN]; char query[MAX_QUERY]; char *eshost, *esreason; if(c == NULL || findban(host, c) != NULL) return 0; newban = (struct banlist *) Malloc (sizeof (struct banlist)); if (newban == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return 0; } memset (newban, 0, sizeof (struct banlist)); strcpy(newban->host, host); strcpy(newban->reason, reason); newban->setby = setby; newban->expire = expire; newban->uid = uid; newban->channel = c; newban->last = c->lastbanlist; newban->next = NULL; if (c->lastbanlist != NULL) { c->lastbanlist->next = newban; } else { /* * No final user yet defined, so this one must be the * very first one. */ c->firstbanlist = newban; } c->lastbanlist = newban; if(mysql) { esreason = escapequery(newban->reason); eshost = escapequery(newban->host); snprintf(query, MAX_QUERY, "INSERT INTO `bans` (`cid`, `uid`, `host`, `setby`, `reason`, `expire`, `sid`) VALUES ('%i', '%i', '%s', '%i', '%s', '%i', '" SID "')", c->id, newban->uid, eshost, newban->setby, esreason, newban->expire); dbquery(query); EndDbQuery(); if(esreason != NULL) Free(esreason); if(eshost != NULL) Free(eshost); } /* We ban on channel */ if(findachanuser(u, c) != NULL) { sprintf(msg, "MODE %s +b %s\n\r", c->name, host); putserver(msg, c->arm); kick(c->name, u->nick, kickreason); return 1; } else return 0; } /* Add a row to sendqueue */ void putserver (char *data, struct arm *a) { struct sendqueue *newsendqueue; if(a == NULL) { printf("FATAL: arm == NULL in putserver()\n"); return; } a->datainbuff = a->datainbuff + strlen(data); newsendqueue = (struct sendqueue *) Malloc (sizeof (struct sendqueue)); if (newsendqueue == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return; } memset (newsendqueue, 0, sizeof (struct sendqueue)); strcpy(newsendqueue->data, data); newsendqueue->last = a->lastsendqueue; newsendqueue->next = NULL; if (a->lastsendqueue != NULL) { a->lastsendqueue->next = newsendqueue; } else { /* * No final user yet defined, so this one must be the * very first one. */ a->firstsendqueue = newsendqueue; } a->lastsendqueue = newsendqueue; } /* Add a channel */ void addchannel (char *channel, int id, char *modes, char *key, short autoop, short autovoice, short bitch, short ftopic, char *mvoice, short advertise, char *flood, short peak, short greet, short tv, short vote, short infobot, short stats, struct arm *arm, char *onjoin, char service, short suspended, short quotes) { struct channel *newchan; if(findchannel(channel) != NULL || arm == NULL) return; newchan = (struct channel *) Malloc (sizeof (struct channel)); if (newchan == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return; } memset (newchan, 0, sizeof (struct channel)); #ifdef DEBUG printf("Debug: Space allocated for channel %s.\n", channel); #endif newchan->id = id; newchan->isop = 1; // Assume we have ops newchan->ison = 0; // Assume we are not on the channel #ifdef SPAMSCAN newchan->nextspam = time(NULL); #endif strncpy(newchan->topic, "", TOPICLEN); strcpy(newchan->name, channel); strcpy(newchan->modes, modes); strcpy(newchan->key, key); newchan->autoop = autoop; newchan->autovoice = autovoice; newchan->bitch = bitch; newchan->ftopic = ftopic; strcpy(newchan->mvoice, mvoice); strcpy(newchan->onjoin, onjoin); newchan->advertise = advertise; sscanf(flood, "%i:%i", &newchan->floodrep, &newchan->floodtime); newchan->peak = peak; newchan->greet = greet; newchan->tv = tv; newchan->vote = vote; newchan->infobot = infobot; newchan->stats = stats; newchan->service = service; newchan->suspended = suspended; newchan->quotes = quotes; newchan->votestruct = NULL; newchan->arm = arm; newchan->firstbanlist = NULL; newchan->lastbanlist = NULL; newchan->last = lastchan; newchan->next = NULL; if (lastchan != NULL) { lastchan->next = newchan; } else { /* * No final channel yet defined, so this one must be the * very first one. */ firstchan = newchan; } lastchan = newchan; } /* Add a channel user */ void addchanuser (struct channel *channel, int uid, int level, char *greet) { struct chanuser *newchanuser; newchanuser = (struct chanuser *) Malloc (sizeof (struct chanuser)); if (newchanuser == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return; } memset (newchanuser, 0, sizeof (struct chanuser)); #ifdef DEBUG printf("Debug: Space allocated for channel user %d.\n", uid); // Debugging code #endif newchanuser->channel = channel; newchanuser->uid = uid; newchanuser->level = level; /* Greet */ if(greet[0] != '\0') newchanuser->greet = DupString(greet); else newchanuser->greet = NULL; newchanuser->last = lastchanuser; newchanuser->next = NULL; if (lastchanuser != NULL) { lastchanuser->next = newchanuser; } else { /* * No final user yet defined, so this one must be the * very first one. */ firstchanuser = newchanuser; } lastchanuser = newchanuser; } struct arm *findarm (char *nick) { struct arm *a; for(a = firstarm; (a != NULL) && (strcasecmp(a->nick, nick) != 0); a = a->next); return a; } struct module *findmodule (char *name) { struct module *m; m = firstmodule; while ((m != NULL) && (strcasecmp (m->name, name) != 0)) { m = m->next; } return m; } struct module *findmodulebypath (char path[100]) { struct module *m; m = firstmodule; while ((m != NULL) && (strcasecmp (m->path, path) != 0)) { m = m->next; } return m; } struct arm *findarmbyid (int id) { struct arm *a; a = firstarm; while (a != NULL && a->id != id) { a = a->next; } return a; } struct arm *findarmbytype (int type) { struct arm *a; a = firstarm; while (a != NULL && a->type != type) { a = a->next; } return a; } /* * Find active user by nick. Handy for deleting them, checking authentication * and so on. */ struct activeuser *findauser (char *nick) { struct activeuser *u; for(u = firstauser; (u != NULL) && (irc_strcmp (u->nick, nick) != 0); u = u->next); return u; } /* Use with caution, there may be more than one client with that userid */ struct activeuser *findauserbyid (int id) { struct activeuser *u; for(u = firstauser; (u != NULL) && (u->userid != id); u = u->next); return u; } /* Find a channel by name */ struct channel *findchannel (char *name) { struct channel *c; for(c = firstchan; (c != NULL) && (irc_strcmp (c->name, name) != 0); c = c->next); return c; } struct channel *findchannelbyid (int id) { struct channel *c; for(c = firstchan; (c != NULL) && (id != c->id); c = c->next); return c; } /* Find a channel user by uid */ struct chanuser *findchanuser (int uid, struct channel *c) { struct chanuser *cu; for(cu = firstchanuser; cu != NULL; cu = cu->next) if(cu->channel == c && cu->uid == uid) return cu; return NULL; } struct activechanuser *findachanuser (struct activeuser *u, struct channel *c) { struct aculink *aculink; if(u == NULL || c == NULL) return NULL; for(aculink = u->firstlink; aculink != NULL; aculink = aculink->next) if(aculink->link->channel == c) return aculink->link; return NULL; } struct banlist *findban (char *host, struct channel *c) { struct banlist *ban; ban = c->firstbanlist; for(ban = c->firstbanlist; ban != NULL && strcasecmp(ban->host, host) != 0; ban = ban->next); return ban; } void delarm (char *arm) { struct arm *a; a = findarm (arm); if (a == NULL) { return; } else { if(a->status == 1) { puttoserver("QUIT :This ARM is being removed\n\r", a); linkbreak(a); } /* Free parsevars */ Free(a->parsevars); /* Flush sendqueue */ if(a->firstsendqueue->data != NULL) delsendqueue(a); /* Remove all channels that the arm was on */ PartAllArmChannels(a); --armcount; /* Decrease global arm counter */ } if (a->last != NULL) { a->last->next = a->next; /* Reset the next pointer */ } else { firstarm = a->next; } if (a->next != NULL) { a->next->last = a->last; /* and the last pointer */ } else { lastarm = a->last; } Free(a); /* And remove the user from memory. */ } void deluser (struct activeuser *u) { if (u == NULL) { /* printf("Debug: Failed to find user %s.\n",nick); */ return; } assert(u->firstlink == NULL); if (u->last != NULL) { u->last->next = u->next; /* Reset the next pointer */ } else { firstauser = u->next; } if (u->next != NULL) { u->next->last = u->last; /* and the last pointer */ } else { lastauser = u->last; } Free(u->username); /* Free suballocs */ Free(u->hostname); #ifdef Q if(Qu == u) Qu = NULL; #ifdef L else if(Lu == u) Lu = NULL; #endif #endif Free(u); /* And remove the user from memory. */ } void delaculink (struct activeuser *u, struct activechanuser *acu) { struct aculink *aculink; short done = 0; if (u == NULL) { /* printf("Debug: Failed to find user %s.\n",nick); */ return; } aculink = u->firstlink; while (aculink != NULL && done == 0) { if(aculink->link == acu) done = 1; else aculink = aculink->next; } if (aculink->last != NULL) { aculink->last->next = aculink->next; /* Reset the next pointer */ } else { u->firstlink = aculink->next; } if (aculink->next != NULL) { aculink->next->last = aculink->last; /* and the last pointer */ } else { u->lastlink = aculink->last; } Free(aculink); /* And remove the user from memory. */ } /* Delete user on channel */ int delachanuser (struct activechanuser *acu, struct activeuser *u) { if (acu == NULL) { if(u != NULL && acu == NULL) { u->isinhome = 0; // if(u->auth > SERVICE_FRIEND) InActiveStaff(u); } #ifdef DEBUG else printf("Debug: Failed to find user for acudel %s.\n", u->nick); #endif } else { // printf ("Debug: Deleting active channel user nick %s\n", nick); delaculink(u, acu); // Delete the link if (acu->last != NULL) { acu->last->next = acu->next; /* Reset the next pointer */ } else { firstacu = acu->next; } if (acu->next != NULL) { acu->next->last = acu->last; /* and the last pointer */ } else { lastacu = acu->last; } Free(acu); /* And remove the user from memory. */ } /* Check if user is on any chans now */ if(u != NULL && u->auth == UNAUTHED) { if(u->firstlink == NULL && u->isinhome == 0) { #ifdef DEBUG printf("User: %s not seen on any channel, deleted. (parted)\n", u->nick); #endif deluser(u); return 1; } } return 0; } /* Delete ban from channel */ void delban (struct banlist *ban) { char msg[CHANNELLEN+10+BANLEN]; char query[MAX_QUERY]; if (ban != NULL) { snprintf(query, MAX_QUERY, "DELETE FROM `bans` WHERE `cid` = '%i' AND `uid` = '%i' AND `host` = '%s' AND `expire` = '%i'", ban->channel->id, ban->uid, ban->host, ban->expire); dbquery(query); EndDbQuery(); sprintf(msg, "MODE %s -b %s\n\r", ban->channel->name, ban->host); putserver(msg, ban->channel->arm); if (ban->last != NULL) { ban->last->next = ban->next; /* Reset the next pointer */ } else { ban->channel->firstbanlist = ban->next; } if (ban->next != NULL) { ban->next->last = ban->last; /* and the last pointer */ } else { ban->channel->lastbanlist = ban->last; } Free(ban); /* And remove the user from memory. */ } } /* Delete first sendqueue row from arm */ void delsendqueue (struct arm *a) { struct sendqueue *sendqueue; sendqueue = a->firstsendqueue; a->datainbuff = a->datainbuff - strlen(sendqueue->data); // while (sendqueue != NULL) sendqueue = sendqueue->next; This is wrong, we need to start sending the queue from back to front if (sendqueue != NULL) { if (sendqueue->last != NULL) { //sendqueue->last->next = sendqueue->next; /* Reset the next pointer */ This should never be true printf("BUG BUG BUG BUG!!!!!!!!\n"); } else { a->firstsendqueue = sendqueue->next; } if (sendqueue->next != NULL) { sendqueue->next->last = sendqueue->last; /* and the last pointer */ } else { a->lastsendqueue = sendqueue->last; } Free(sendqueue); /* And remove the sendqueue from memory. */ } } /* Delete channel */ void delchannel (struct channel *c) { struct banlist *ban, *next; /* Remove all channel bans */ ban = c->firstbanlist; while(ban != NULL) { next = ban->next; delban(ban); ban = next; } DelAllChanUsersForChannel(c); /* Delete all channel users in memory */ if (c->last != NULL) { c->last->next = c->next; /* Reset the next pointer */ } else { firstchan = c->next; } if (c->next != NULL) { c->next->last = c->last; /* and the last pointer */ } else { lastchan = c->last; } Free(c); /* And remove the channel from memory. */ } /* Delete channel user */ void delchanuser (struct chanuser *cu) { if (cu->last != NULL) { cu->last->next = cu->next; /* Reset the next pointer */ } else { firstchanuser = cu->next; } if (cu->next != NULL) { cu->next->last = cu->last; /* and the last pointer */ } else { lastchanuser = cu->last; } if(cu->greet != NULL) Free(cu->greet); Free(cu); /* And remove the channel from memory. */ } void DelAllChanUsersForChannel(struct channel *c) { struct chanuser *cu, *next; cu = firstchanuser; while (cu != NULL) { next = cu->next; if(cu->channel == c) delchanuser(cu); cu = next; } } struct vote *AllocateVote(struct channel *c) { struct vote *newvote; if(c->votestruct != NULL) return NULL; // Vote already running newvote = (struct vote *) Malloc (sizeof (struct vote)); if (newvote == NULL) { printf ("Debug: Malloc() FAILED!\a\n"); return NULL; } memset (newvote, 0, sizeof (struct vote)); newvote->yes = 0; newvote->no = 0; newvote->lastvid = 0; c->votestruct = newvote; return newvote; } int FreeVote (struct channel *c) { if(c->votestruct == NULL) return 0; /* No vote on channel */ Free(c->votestruct); c->votestruct = NULL; return 1; }