2 * IRC - Internet Relay Chat, ircd/list.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Finland
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
44 static struct liststats {
46 } cloc, crem, users, servs, links, classs, aconfs;
54 memset(&cloc, 0, sizeof(cloc));
55 memset(&crem, 0, sizeof(crem));
56 memset(&users, 0, sizeof(users));
57 memset(&servs, 0, sizeof(servs));
58 memset(&links, 0, sizeof(links));
59 memset(&classs, 0, sizeof(classs));
60 memset(&aconfs, 0, sizeof(aconfs));
64 void outofmemory(void)
66 Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
67 restart("Out of Memory");
71 * Create a new aClient structure and set it to initial state.
73 * from == NULL, create local client (a client connected to a socket).
75 * from != NULL, create remote client (behind a socket associated with
76 * the client defined by 'from').
77 * ('from' is a local client!!).
79 aClient *make_client(aClient *from, int status)
81 Reg1 aClient *cptr = NULL;
82 Reg2 size_t size = CLIENT_REMOTE_SIZE;
85 * Check freelists first to see if we can grab a client without
86 * having to call malloc.
89 size = CLIENT_LOCAL_SIZE;
91 if (!(cptr = (aClient *)RunMalloc(size)))
93 memset(cptr, 0, size); /* All variables are 0 by default */
96 if (size == CLIENT_LOCAL_SIZE)
102 /* Note: structure is zero (memset) */
103 cptr->from = from ? from : cptr; /* 'from' of local client is self! */
105 cptr->status = status;
106 strcpy(cptr->username, "unknown");
107 if (size == CLIENT_LOCAL_SIZE)
109 cptr->since = cptr->lasttime = cptr->firsttime = now;
110 cptr->lastnick = TStime();
111 cptr->nextnick = now - NICK_DELAY;
112 cptr->nexttarget = now - (TARGET_DELAY * (STARTTARGETS - 1));
118 void free_client(aClient *cptr)
124 * 'make_user' add's an User information block to a client
125 * if it was not previously allocated.
127 anUser *make_user(aClient *cptr)
134 if (!(user = (anUser *)RunMalloc(sizeof(anUser))))
136 memset(user, 0, sizeof(anUser)); /* All variables are 0 by default */
147 aServer *make_server(aClient *cptr)
149 Reg1 aServer *serv = cptr->serv;
153 if (!(serv = (aServer *)RunMalloc(sizeof(aServer))))
155 memset(serv, 0, sizeof(aServer)); /* All variables are 0 by default */
161 DupString(serv->last_error_msg, "<>"); /* String must be non-empty */
169 * Decrease user reference count by one and realease block, if count reaches 0.
171 void free_user(anUser *user, aClient *cptr)
173 if (--user->refcnt == 0)
180 if (user->joined || user->invited || user->channel)
182 dumpcore("%p user (%s!%s@%s) %p %p %p %d %d",
183 cptr, cptr ? cptr->name : "<noname>",
184 user->username, user->host, user,
185 user->invited, user->channel, user->joined, user->refcnt);
187 sendto_ops("* %p user (%s!%s@%s) %p %p %p %d %d *",
188 cptr, cptr ? cptr->name : "<noname>",
189 user->username, user->host, user,
190 user->invited, user->channel, user->joined, user->refcnt);
200 * Taken the code from ExitOneClient() for this and placed it here.
203 void remove_client_from_list(aClient *cptr)
207 cptr->prev->next = cptr->next;
214 cptr->next->prev = cptr->prev;
215 if (IsUser(cptr) && cptr->user)
217 add_history(cptr, 0);
221 free_user(cptr->user, cptr);
224 if (cptr->serv->user)
225 free_user(cptr->serv->user, cptr);
226 if (cptr->serv->client_list)
227 RunFree(cptr->serv->client_list);
228 RunFree(cptr->serv->last_error_msg);
245 * Although only a small routine, it appears in a number of places
246 * as a collection of a few lines...functions like this *should* be
247 * in this file, shouldnt they ? after all, this is list.c, isn't it ?
250 void add_client_to_list(aClient *cptr)
253 * Since we always insert new clients to the top of the list,
254 * this should mean the "me" is the bottom most item in the list.
259 cptr->next->prev = cptr;
264 * Look for ptr in the linked listed pointed to by link.
266 Link *find_user_link(Link *lp, aClient *ptr)
271 if (lp->value.cptr == ptr)
278 Link *make_link(void)
282 lp = (Link *)RunMalloc(sizeof(Link));
289 void free_link(Link *lp)
297 Dlink *add_dlink(Dlink **lpp, aClient *cp)
300 lp = (Dlink *)RunMalloc(sizeof(Dlink));
303 if ((lp->next = *lpp))
309 void remove_dlink(Dlink **lpp, Dlink *lp)
313 if ((lp->prev->next = lp->next))
314 lp->next->prev = lp->prev;
316 else if ((*lpp = lp->next))
317 lp->next->prev = NULL;
321 aConfClass *make_class(void)
323 Reg1 aConfClass *tmp;
325 tmp = (aConfClass *) RunMalloc(sizeof(aConfClass));
332 void free_class(aConfClass * tmp)
340 aConfItem *make_conf(void)
342 Reg1 aConfItem *aconf;
344 aconf = (struct ConfItem *)RunMalloc(sizeof(aConfItem));
348 memset(&aconf->ipnum, 0, sizeof(struct in_addr));
350 aconf->host = aconf->passwd = aconf->name = NULL;
351 aconf->status = CONF_ILLEGAL;
355 aconf->confClass = NULL;
359 void delist_conf(aConfItem *aconf)
367 for (bconf = conf; aconf != bconf->next; bconf = bconf->next);
368 bconf->next = aconf->next;
373 void free_conf(aConfItem *aconf)
375 del_queries((char *)aconf);
376 RunFree(aconf->host);
378 memset(aconf->passwd, 0, strlen(aconf->passwd));
379 RunFree(aconf->passwd);
380 RunFree(aconf->name);
388 aGline *make_gline(int is_ipmask, char *host, char *reason,
389 char *name, time_t expire)
394 if(*host == '#' || *host == '&' || *host == '+')
395 gtype=1; /* BAD CHANNEL GLINE */
398 agline = (struct Gline *)RunMalloc(sizeof(aGline)); /* alloc memory */
399 DupString(agline->host, host); /* copy vital information */
400 DupString(agline->reason, reason);
401 DupString(agline->name, name);
402 agline->expire = expire;
403 agline->gflags = GLINE_ACTIVE; /* gline is active */
405 SetGlineIsIpMask(agline);
409 { agline->next = badchan; /* link it into the list */
410 return (badchan = agline);
413 agline->next = gline; /* link it into the list */
414 return (gline = agline);
417 aGline *find_gline(aClient *cptr, aGline **pgline)
419 Reg3 aGline *agline = gline, *a2gline = NULL;
422 { /* look through all glines */
423 if (agline->expire <= TStime())
424 { /* handle expired glines */
425 free_gline(agline, a2gline);
426 agline = a2gline ? a2gline->next : gline;
428 break; /* agline == NULL means gline == NULL */
432 /* Does gline match? */
433 /* Added a check against the user's IP address as well -Kev */
434 if ((GlineIsIpMask(agline) ?
435 match(agline->host, inetntoa(cptr->ip)) :
436 match(agline->host, cptr->sockhost)) == 0 &&
437 match(agline->name, cptr->user->username) == 0)
440 *pgline = a2gline; /* If they need it, give them the previous gline
441 entry (probably for free_gline, below) */
446 agline = agline->next;
449 return NULL; /* found no glines */
452 void free_gline(aGline *agline, aGline *pgline)
455 pgline->next = agline->next; /* squeeze agline out */
459 if(*agline->host =='#' || *agline->host == '&' || *agline->host == '+')
461 badchan = agline->next;
465 gline = agline->next;
468 RunFree(agline->host); /* and free up the memory */
469 RunFree(agline->reason);
470 RunFree(agline->name);
475 int bad_channel(char *name)
481 if ((agline->gflags&GLINE_ACTIVE) && (agline->expire >TStime()) &&
482 !mmatch(agline->host,name))
492 void send_listinfo(aClient *cptr, char *name)
494 int inuse = 0, mem = 0, tmp = 0;
496 sendto_one(cptr, ":%s %d %s :Local: inuse: %d(%d)",
497 me.name, RPL_STATSDEBUG, name, inuse += cloc.inuse,
498 tmp = cloc.inuse * CLIENT_LOCAL_SIZE);
500 sendto_one(cptr, ":%s %d %s :Remote: inuse: %d(%d)",
501 me.name, RPL_STATSDEBUG, name,
502 crem.inuse, tmp = crem.inuse * CLIENT_REMOTE_SIZE);
505 sendto_one(cptr, ":%s %d %s :Users: inuse: %d(%d)",
506 me.name, RPL_STATSDEBUG, name, users.inuse,
507 tmp = users.inuse * sizeof(anUser));
509 inuse += users.inuse,
510 sendto_one(cptr, ":%s %d %s :Servs: inuse: %d(%d)",
511 me.name, RPL_STATSDEBUG, name, servs.inuse,
512 tmp = servs.inuse * sizeof(aServer));
514 inuse += servs.inuse,
515 sendto_one(cptr, ":%s %d %s :Links: inuse: %d(%d)",
516 me.name, RPL_STATSDEBUG, name, links.inuse,
517 tmp = links.inuse * sizeof(Link));
519 inuse += links.inuse,
520 sendto_one(cptr, ":%s %d %s :Classes: inuse: %d(%d)",
521 me.name, RPL_STATSDEBUG, name, classs.inuse,
522 tmp = classs.inuse * sizeof(aConfClass));
524 inuse += classs.inuse,
525 sendto_one(cptr, ":%s %d %s :Confs: inuse: %d(%d)",
526 me.name, RPL_STATSDEBUG, name, aconfs.inuse,
527 tmp = aconfs.inuse * sizeof(aConfItem));
529 inuse += aconfs.inuse,
530 sendto_one(cptr, ":%s %d %s :Totals: inuse %d %d",
531 me.name, RPL_STATSDEBUG, name, inuse, mem);