ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/client.c
(Generate patch)

Comparing:
ircd-hybrid-8/src/client.c (file contents), Revision 1158 by michael, Wed Aug 10 19:46:00 2011 UTC vs.
ircd-hybrid/trunk/src/client.c (file contents), Revision 4428 by michael, Thu Aug 7 17:46:02 2014 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  client.c: Controls clients.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2002 by the past and present ircd coders, and others.
4 > *  Copyright (c) 1997-2014 ircd-hybrid development team
5   *
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
# Line 18 | Line 17
17   *  along with this program; if not, write to the Free Software
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
19   *  USA
20 < *
21 < *  $Id$
20 > */
21 >
22 > /*! \file client.c
23 > * \brief Controls clients.
24 > * \version $Id$
25   */
26  
27   #include "stdinc.h"
28   #include "list.h"
29   #include "client.h"
28 #include "channel_mode.h"
29 #include "common.h"
30   #include "event.h"
31 #include "fdlist.h"
31   #include "hash.h"
32   #include "irc_string.h"
33   #include "ircd.h"
35 #include "s_gline.h"
34   #include "numeric.h"
35 < #include "packet.h"
38 < #include "s_auth.h"
35 > #include "auth.h"
36   #include "s_bsd.h"
37 < #include "s_conf.h"
38 < #include "s_log.h"
39 < #include "s_misc.h"
40 < #include "s_serv.h"
37 > #include "conf.h"
38 > #include "log.h"
39 > #include "misc.h"
40 > #include "server.h"
41   #include "send.h"
42   #include "whowas.h"
43 < #include "s_user.h"
47 < #include "dbuf.h"
43 > #include "user.h"
44   #include "memory.h"
45 + #include "mempool.h"
46   #include "hostmask.h"
50 #include "balloc.h"
47   #include "listener.h"
52 #include "irc_res.h"
48   #include "userhost.h"
49   #include "watch.h"
50 + #include "rng_mt.h"
51 + #include "parse.h"
52 + #include "ipcache.h"
53  
56 dlink_list listing_client_list = { NULL, NULL, 0 };
57 /* Pointer to beginning of Client list */
58 dlink_list global_client_list = {NULL, NULL, 0};
59 /* unknown/client pointer lists */
60 dlink_list unknown_list = {NULL, NULL, 0};
61 dlink_list local_client_list = {NULL, NULL, 0};
62 dlink_list serv_list = {NULL, NULL, 0};
63 dlink_list global_serv_list = {NULL, NULL, 0};
64 dlink_list oper_list = {NULL, NULL, 0};
65
66 static EVH check_pings;
54  
55 < static BlockHeap *client_heap  = NULL;
56 < static BlockHeap *lclient_heap = NULL;
57 <
58 < static dlink_list dead_list  = { NULL, NULL, 0};
59 < static dlink_list abort_list = { NULL, NULL, 0};
55 > dlink_list listing_client_list;
56 > dlink_list unknown_list;
57 > dlink_list local_client_list;
58 > dlink_list local_server_list;
59 > dlink_list global_client_list;
60 > dlink_list global_server_list;
61 > dlink_list oper_list;
62  
63 + static mp_pool_t *client_pool, *lclient_pool;
64 + static dlink_list dead_list, abort_list;
65   static dlink_node *eac_next;  /* next aborted client to exit */
66  
76 static void check_pings_list(dlink_list *);
77 static void check_unknowns_list(void);
78 static void ban_them(struct Client *, struct ConfItem *);
79
80
81 /* init_client()
82 *
83 * inputs       - NONE
84 * output       - NONE
85 * side effects - initialize client free memory
86 */
87 void
88 init_client(void)
89 {
90  /* start off the check ping event ..  -- adrian
91   * Every 30 seconds is plenty -- db
92   */
93  client_heap = BlockHeapCreate("client", sizeof(struct Client), CLIENT_HEAP_SIZE);
94  lclient_heap = BlockHeapCreate("local client", sizeof(struct LocalUser), LCLIENT_HEAP_SIZE);
95  eventAdd("check_pings", check_pings, NULL, 5);
96 }
67  
68   /*
69   * make_client - create a new Client struct and set it to initial state.
# Line 113 | Line 83 | init_client(void)
83   struct Client *
84   make_client(struct Client *from)
85   {
86 <  struct Client *client_p = BlockHeapAlloc(client_heap);
86 >  struct Client *client_p = mp_pool_get(client_pool);
87  
88 <  if (from == NULL)
88 >  if (!from)
89    {
90 <    client_p->from  = client_p; /* 'from' of local client is self! */
91 <    client_p->since = client_p->lasttime = client_p->firsttime = CurrentTime;
92 <
93 <    client_p->localClient = BlockHeapAlloc(lclient_heap);
90 >    client_p->from                      = client_p; /* 'from' of local client is self! */
91 >    client_p->localClient               = mp_pool_get(lclient_pool);
92 >    client_p->localClient->since        = CurrentTime;
93 >    client_p->localClient->lasttime     = CurrentTime;
94 >    client_p->localClient->firsttime    = CurrentTime;
95      client_p->localClient->registration = REG_INIT;
96 +
97      /* as good a place as any... */
98      dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
99    }
100    else
101      client_p->from = from; /* 'from' of local client is self! */
102  
103 +  client_p->idhnext = client_p;
104    client_p->hnext  = client_p;
105 <  client_p->status = STAT_UNKNOWN;
105 >  SetUnknown(client_p);
106    strcpy(client_p->username, "unknown");
107 +  strcpy(client_p->svid, "0");
108  
109    return client_p;
110   }
# Line 145 | Line 119 | make_client(struct Client *from)
119   static void
120   free_client(struct Client *client_p)
121   {
122 <  assert(client_p != NULL);
122 >  assert(client_p);
123    assert(client_p != &me);
124    assert(client_p->hnext == client_p);
125 +  assert(client_p->idhnext == client_p);
126    assert(client_p->channel.head == NULL);
127    assert(dlink_list_length(&client_p->channel) == 0);
128 +  assert(dlink_list_length(&client_p->whowas) == 0);
129 +  assert(!IsServer(client_p) || client_p->serv);
130  
154  MyFree(client_p->away);
131    MyFree(client_p->serv);
132 +  MyFree(client_p->certfp);
133  
134    if (MyConnect(client_p))
135    {
136      assert(client_p->localClient->invited.head == NULL);
137      assert(dlink_list_length(&client_p->localClient->invited) == 0);
138 +    assert(dlink_list_length(&client_p->localClient->watches) == 0);
139      assert(IsClosing(client_p) && IsDead(client_p));
140  
141      MyFree(client_p->localClient->response);
# Line 168 | Line 146 | free_client(struct Client *client_p)
146       */
147      if (client_p->localClient->listener)
148      {
149 <      assert(0 < client_p->localClient->listener->ref_count);
150 <      if (0 == --client_p->localClient->listener->ref_count &&
173 <          !client_p->localClient->listener->active)
174 <        free_listener(client_p->localClient->listener);
149 >      listener_release(client_p->localClient->listener);
150 >      client_p->localClient->listener = NULL;
151      }
152  
153      dbuf_clear(&client_p->localClient->buf_recvq);
154      dbuf_clear(&client_p->localClient->buf_sendq);
155  
156 <    BlockHeapFree(lclient_heap, client_p->localClient);
156 >    mp_pool_release(client_p->localClient);
157    }
158  
159 <  BlockHeapFree(client_heap, client_p);
184 < }
185 <
186 < /*
187 < * check_pings - go through the local client list and check activity
188 < * kill off stuff that should die
189 < *
190 < * inputs       - NOT USED (from event)
191 < * output       - next time_t when check_pings() should be called again
192 < * side effects -
193 < *
194 < *
195 < * A PING can be sent to clients as necessary.
196 < *
197 < * Client/Server ping outs are handled.
198 < */
199 <
200 < /*
201 < * Addon from adrian. We used to call this after nextping seconds,
202 < * however I've changed it to run once a second. This is only for
203 < * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
204 < * run once a second makes life a lot easier - when a new client connects
205 < * and they need a ping in 4 seconds, if nextping was set to 20 seconds
206 < * we end up waiting 20 seconds. This is stupid. :-)
207 < * I will optimise (hah!) check_pings() once I've finished working on
208 < * tidying up other network IO evilnesses.
209 < *     -- adrian
210 < */
211 <
212 < static void
213 < check_pings(void *notused)
214 < {              
215 <  check_pings_list(&local_client_list);
216 <  check_pings_list(&serv_list);
217 <  check_unknowns_list();
159 >  mp_pool_release(client_p);
160   }
161  
162   /* check_pings_list()
163   *
164   * inputs       - pointer to list to check
165   * output       - NONE
166 < * side effects -
166 > * side effects -
167   */
168   static void
169   check_pings_list(dlink_list *list)
170   {
171 <  char scratch[32];        /* way too generous but... */
172 <  struct Client *client_p; /* current local client_p being examined */
173 <  int ping, pingwarn;      /* ping time value from client */
232 <  dlink_node *ptr, *next_ptr;
171 >  char buf[IRCD_BUFSIZE] = "";
172 >  int ping = 0;      /* ping time value from client */
173 >  dlink_node *ptr = NULL, *ptr_next = NULL;
174  
175 <  DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
175 >  DLINK_FOREACH_SAFE(ptr, ptr_next, list->head)
176    {
177 <    client_p = ptr->data;
177 >    struct Client *client_p = ptr->data;
178  
238    /*
239    ** Note: No need to notify opers here. It's
240    ** already done when "FLAGS_DEADSOCKET" is set.
241    */
179      if (IsDead(client_p))
180 <    {
244 <      /* Ignore it, its been exited already */
245 <      continue;
246 <    }
247 <
248 <    if (client_p->localClient->reject_delay > 0)
249 <    {
250 <      if (client_p->localClient->reject_delay <= CurrentTime)
251 <        exit_client(client_p, &me, "Rejected");
252 <      continue;
253 <    }
254 <
255 <    if (GlobalSetOptions.idletime && IsClient(client_p))
256 <    {
257 <      if (!IsExemptKline(client_p) && !IsOper(client_p) &&
258 <          !IsIdlelined(client_p) &&
259 <          ((CurrentTime - client_p->localClient->last) > GlobalSetOptions.idletime))
260 <      {
261 <        struct ConfItem *conf;
262 <        struct AccessItem *aconf;
263 <
264 <        conf = make_conf_item(KLINE_TYPE);
265 <        aconf = map_to_conf(conf);
266 <
267 <        DupString(aconf->host, client_p->host);
268 <        DupString(aconf->reason, "idle exceeder");
269 <        DupString(aconf->user, client_p->username);
270 <        aconf->hold = CurrentTime + 60;
271 <        add_temp_line(conf);
272 <
273 <        sendto_realops_flags(UMODE_ALL, L_ALL,
274 <                             "Idle time limit exceeded for %s - temp k-lining",
275 <                             get_client_name(client_p, HIDE_IP));
276 <        exit_client(client_p, &me, aconf->reason);
277 <        continue;
278 <      }
279 <    }
180 >      continue;  /* Ignore it, its been exited already */
181  
182      if (!IsRegistered(client_p))
183 <      ping = CONNECTTIMEOUT, pingwarn = 0;
183 >      ping = CONNECTTIMEOUT;
184      else
185 <      ping = get_client_ping(client_p, &pingwarn);
185 >      ping = get_client_ping(&client_p->localClient->confs);
186  
187 <    if (ping < CurrentTime - client_p->lasttime)
187 >    if (ping < CurrentTime - client_p->localClient->lasttime)
188      {
189        if (!IsPingSent(client_p))
190        {
191 <        /*
192 <         * if we havent PINGed the connection and we havent
193 <         * heard from it in a while, PING it to make sure
194 <         * it is still alive.
195 <         */
196 <        SetPingSent(client_p);
197 <        ClearPingWarning(client_p);
198 <        client_p->lasttime = CurrentTime - ping;
298 <        sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
191 >        /*
192 >         * If we haven't PINGed the connection and we haven't
193 >         * heard from it in a while, PING it to make sure
194 >         * it is still alive.
195 >         */
196 >        SetPingSent(client_p);
197 >        client_p->localClient->lasttime = CurrentTime - ping;
198 >        sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
199        }
200        else
201        {
202 <        if (CurrentTime - client_p->lasttime >= 2 * ping)
202 >        if (CurrentTime - client_p->localClient->lasttime >= 2 * ping)
203          {
204            /*
205             * If the client/server hasn't talked to us in 2*ping seconds
206             * and it has a ping time, then close its connection.
207             */
208            if (IsServer(client_p) || IsHandshake(client_p))
209 <          {
210 <            sendto_realops_flags(UMODE_ALL, L_ADMIN,
211 <                                 "No response from %s, closing link",
212 <                                 get_client_name(client_p, HIDE_IP));
213 <            sendto_realops_flags(UMODE_ALL, L_OPER,
214 <                                 "No response from %s, closing link",
215 <                                 get_client_name(client_p, MASK_IP));
216 <            ilog(L_NOTICE, "No response from %s, closing link",
217 <                 get_client_name(client_p, HIDE_IP));
218 <          }
219 <
220 <          snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
221 <                   (int)(CurrentTime - client_p->lasttime));
222 <          exit_client(client_p, &me, scratch);
323 <        }
324 <        else if (!IsPingWarning(client_p) && pingwarn > 0 &&
325 <                 (IsServer(client_p) || IsHandshake(client_p)) &&
326 <                 CurrentTime - client_p->lasttime >= ping + pingwarn)
327 <        {
328 <          /*
329 <           * If the server hasn't replied in pingwarn seconds after sending
330 <           * the PING, notify the opers so that they are aware of the problem.
331 <           */
332 <          SetPingWarning(client_p);
333 <          sendto_realops_flags(UMODE_ALL, L_ADMIN,
334 <                               "Warning, no response from %s in %d seconds",
335 <                               get_client_name(client_p, HIDE_IP), pingwarn);
336 <          sendto_realops_flags(UMODE_ALL, L_OPER,
337 <                               "Warning, no response from %s in %d seconds",
338 <                               get_client_name(client_p, MASK_IP), pingwarn);
339 <          ilog(L_NOTICE, "No response from %s in %d seconds",
340 <               get_client_name(client_p, HIDE_IP), pingwarn);
209 >          {
210 >            sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
211 >                                 "No response from %s, closing link",
212 >                                 get_client_name(client_p, HIDE_IP));
213 >            sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
214 >                                 "No response from %s, closing link",
215 >                                 get_client_name(client_p, MASK_IP));
216 >            ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
217 >                 get_client_name(client_p, HIDE_IP));
218 >          }
219 >
220 >          snprintf(buf, sizeof(buf), "Ping timeout: %d seconds",
221 >                   (int)(CurrentTime - client_p->localClient->lasttime));
222 >          exit_client(client_p, buf);
223          }
224        }
225      }
# Line 353 | Line 235 | check_pings_list(dlink_list *list)
235   static void
236   check_unknowns_list(void)
237   {
238 <  dlink_node *ptr, *next_ptr;
238 >  dlink_node *ptr = NULL, *ptr_next = NULL;
239  
240 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
240 >  DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
241    {
242      struct Client *client_p = ptr->data;
243  
362    if (client_p->localClient->reject_delay > 0)
363    {
364      if (client_p->localClient->reject_delay <= CurrentTime)
365        exit_client(client_p, &me, "Rejected");
366      continue;
367    }
368
244      /*
245       * Check UNKNOWN connections - if they have been in this state
246       * for > 30s, close them.
247       */
248 <    if (IsAuthFinished(client_p) && (CurrentTime - client_p->firsttime) > 30)
249 <      exit_client(client_p, &me, "Registration timed out");
248 >    if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
249 >      exit_client(client_p, "Registration timed out");
250    }
251   }
252  
253 + /*
254 + * check_pings - go through the local client list and check activity
255 + * kill off stuff that should die
256 + *
257 + * inputs       - NOT USED (from event)
258 + * output       - next time_t when check_pings() should be called again
259 + * side effects -
260 + *
261 + *
262 + * A PING can be sent to clients as necessary.
263 + *
264 + * Client/Server ping outs are handled.
265 + */
266 +
267 + /*
268 + * Addon from adrian. We used to call this after nextping seconds,
269 + * however I've changed it to run once a second. This is only for
270 + * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
271 + * run once a second makes life a lot easier - when a new client connects
272 + * and they need a ping in 4 seconds, if nextping was set to 20 seconds
273 + * we end up waiting 20 seconds. This is stupid. :-)
274 + * I will optimise (hah!) check_pings() once I've finished working on
275 + * tidying up other network IO evilnesses.
276 + *     -- adrian
277 + */
278 +
279 + static void
280 + check_pings(void *notused)
281 + {
282 +  check_pings_list(&local_client_list);
283 +  check_pings_list(&local_server_list);
284 +  check_unknowns_list();
285 + }
286 +
287   /* check_conf_klines()
288   *
289   * inputs       - NONE
# Line 382 | Line 291 | check_unknowns_list(void)
291   * side effects - Check all connections for a pending kline against the
292   *                client, exit the client if a kline matches.
293   */
294 < void
294 > void
295   check_conf_klines(void)
296 < {              
297 <  struct Client *client_p = NULL;       /* current local client_p being examined */
298 <  struct AccessItem *aconf = NULL;
390 <  struct ConfItem *conf = NULL;
391 <  dlink_node *ptr, *next_ptr;
296 > {
297 >  struct MaskItem *conf = NULL;
298 >  dlink_node *ptr = NULL, *ptr_next = NULL;
299  
300 <  DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
300 >  DLINK_FOREACH_SAFE(ptr, ptr_next, local_client_list.head)
301    {
302 <    client_p = ptr->data;
302 >    struct Client *client_p = ptr->data;
303  
304      /* If a client is already being exited
305       */
306      if (IsDead(client_p) || !IsClient(client_p))
307        continue;
308  
309 <    /* if there is a returned struct ConfItem then kill it */
310 <    if ((aconf = find_dline_conf(&client_p->localClient->ip,
404 <                                  client_p->localClient->aftype)) != NULL)
309 >    if ((conf = find_conf_by_address(NULL, &client_p->localClient->ip, CONF_DLINE,
310 >                                     client_p->localClient->aftype, NULL, NULL, 1)))
311      {
312 <      if (aconf->status & CONF_EXEMPTDLINE)
407 <        continue;
408 <
409 <      conf = unmap_conf_item(aconf);
410 <      ban_them(client_p, conf);
312 >      conf_try_ban(client_p, conf);
313        continue; /* and go examine next fd/client_p */
314      }
315  
316 <    if (ConfigFileEntry.glines && (aconf = find_gline(client_p)))
316 >    if (ConfigGeneral.glines)
317      {
318 <      if (IsExemptKline(client_p) ||
319 <          IsExemptGline(client_p))
318 >      if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
319 >                                       CONF_GLINE, client_p->localClient->aftype,
320 >                                       client_p->username, NULL, 1)))
321        {
322 <        sendto_realops_flags(UMODE_ALL, L_ALL,
323 <                             "GLINE over-ruled for %s, client is %sline_exempt",
421 <                             get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
322 >        conf_try_ban(client_p, conf);
323 >        /* and go examine next fd/client_p */
324          continue;
325        }
326 +    }
327  
328 <      conf = unmap_conf_item(aconf);
329 <      ban_them(client_p, conf);
330 <      /* and go examine next fd/client_p */    
428 <      continue;
429 <    }
430 <
431 <    if ((aconf = find_kill(client_p)) != NULL)
328 >    if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
329 >                                     CONF_KLINE, client_p->localClient->aftype,
330 >                                     client_p->username, NULL, 1)))
331      {
332 <
333 <      /* if there is a returned struct AccessItem.. then kill it */
435 <      if (IsExemptKline(client_p))
436 <      {
437 <        sendto_realops_flags(UMODE_ALL, L_ALL,
438 <                             "KLINE over-ruled for %s, client is kline_exempt",
439 <                             get_client_name(client_p, HIDE_IP));
440 <        continue;
441 <      }
442 <
443 <      conf = unmap_conf_item(aconf);
444 <      ban_them(client_p, conf);
445 <      continue;
332 >      conf_try_ban(client_p, conf);
333 >      continue;
334      }
335  
336 <    /* if there is a returned struct MatchItem then kill it */
337 <    if ((conf = find_matching_name_conf(XLINE_TYPE,  client_p->info,
450 <                                        NULL, NULL, 0)) != NULL ||
451 <        (conf = find_matching_name_conf(RXLINE_TYPE, client_p->info,
452 <                                        NULL, NULL, 0)) != NULL)
336 >    if ((conf = find_matching_name_conf(CONF_XLINE,  client_p->info,
337 >                                        NULL, NULL, 0)))
338      {
339 <      ban_them(client_p, conf);
339 >      conf_try_ban(client_p, conf);
340        continue;
341      }
342    }
343  
344    /* also check the unknowns list for new dlines */
345 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
345 >  DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
346    {
347 <    client_p = ptr->data;
347 >    struct Client *client_p = ptr->data;
348  
349 <    if ((aconf = find_dline_conf(&client_p->localClient->ip,
350 <                                  client_p->localClient->aftype)))
349 >    if ((conf = find_conf_by_address(NULL, &client_p->localClient->ip, CONF_DLINE,
350 >                                     client_p->localClient->aftype, NULL, NULL, 1)))
351      {
352 <      if (aconf->status & CONF_EXEMPTDLINE)
353 <        continue;
469 <
470 <      exit_client(client_p, &me, "D-lined");
352 >      conf_try_ban(client_p, conf);
353 >      continue; /* and go examine next fd/client_p */
354      }
355    }
356   }
357  
358   /*
359 < * ban_them
359 > * conf_try_ban
360   *
361   * inputs       - pointer to client to ban
362 < *              - pointer to ConfItem
362 > *              - pointer to MaskItem
363   * output       - NONE
364   * side effects - given client_p is banned
365   */
366 < static void
367 < ban_them(struct Client *client_p, struct ConfItem *conf)
366 > void
367 > conf_try_ban(struct Client *client_p, struct MaskItem *conf)
368   {
369 <  const char *user_reason = NULL;       /* What is sent to user */
487 <  const char *channel_reason = NULL;    /* What is sent to channel */
488 <  struct AccessItem *aconf = NULL;
489 <  struct MatchItem *xconf = NULL;
369 >  const char *user_reason = NULL;  /* What is sent to user */
370    const char *type_string = NULL;
371    const char dline_string[] = "D-line";
372    const char kline_string[] = "K-line";
# Line 495 | Line 375 | ban_them(struct Client *client_p, struct
375  
376    switch (conf->type)
377    {
378 <    case RKLINE_TYPE:
379 <    case KLINE_TYPE:
378 >    case CONF_KLINE:
379 >      if (IsExemptKline(client_p))
380 >      {
381 >        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
382 >                             "KLINE over-ruled for %s, client is kline_exempt",
383 >                             get_client_name(client_p, HIDE_IP));
384 >        return;
385 >      }
386 >
387        type_string = kline_string;
501      aconf = map_to_conf(conf);
388        break;
389 <    case DLINE_TYPE:
389 >    case CONF_DLINE:
390 >      if (find_conf_by_address(NULL, &client_p->localClient->ip, CONF_EXEMPT,
391 >                               client_p->localClient->aftype, NULL, NULL, 1))
392 >        return;
393        type_string = dline_string;
505      aconf = map_to_conf(conf);
394        break;
395 <    case GLINE_TYPE:
395 >    case CONF_GLINE:
396 >      if (IsExemptKline(client_p) ||
397 >          IsExemptGline(client_p))
398 >      {
399 >        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
400 >                             "GLINE over-ruled for %s, client is %sline_exempt",
401 >                             get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
402 >        return;
403 >      }
404 >
405        type_string = gline_string;
509      aconf = map_to_conf(conf);
406        break;
407 <    case RXLINE_TYPE:
512 <    case XLINE_TYPE:
407 >    case CONF_XLINE:
408        type_string = xline_string;
409 <      xconf = map_to_conf(conf);
515 <      ++xconf->count;
409 >      ++conf->count;
410        break;
411      default:
412        assert(0);
413        break;
414    }
415  
416 <  if (ConfigFileEntry.kline_with_reason)
523 <  {
524 <    if (aconf != NULL)
525 <      user_reason = aconf->reason ? aconf->reason : type_string;
526 <    if (xconf != NULL)
527 <      user_reason = xconf->reason ? xconf->reason : type_string;
528 <  }
529 <  else
530 <    user_reason = type_string;
416 >  user_reason = conf->reason ? conf->reason : type_string;
417  
418 <  if (ConfigFileEntry.kline_reason != NULL)
533 <    channel_reason = ConfigFileEntry.kline_reason;
534 <  else
535 <    channel_reason = user_reason;
536 <
537 <  sendto_realops_flags(UMODE_ALL, L_ALL, "%s active for %s",
418 >  sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s active for %s",
419                         type_string, get_client_name(client_p, HIDE_IP));
420  
421    if (IsClient(client_p))
422 <    sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
542 <               me.name, client_p->name, user_reason);
422 >    sendto_one_numeric(client_p, &me, ERR_YOUREBANNEDCREEP, user_reason);
423  
424 <  exit_client(client_p, &me, channel_reason);
424 >  exit_client(client_p, user_reason);
425   }
426  
427   /* update_client_exit_stats()
428   *
429   * input        - pointer to client
430   * output       - NONE
431 < * side effects -
431 > * side effects -
432   */
433   static void
434   update_client_exit_stats(struct Client *client_p)
# Line 557 | Line 437 | update_client_exit_stats(struct Client *
437    {
438      assert(Count.total > 0);
439      --Count.total;
440 <    if (IsOper(client_p))
440 >    if (HasUMode(client_p, UMODE_OPER))
441        --Count.oper;
442 <    if (IsInvisible(client_p))
442 >    if (HasUMode(client_p, UMODE_INVISIBLE))
443        --Count.invisi;
444    }
445    else if (IsServer(client_p))
446 <    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, "Server %s split from %s",
446 >    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
447 >                         "Server %s split from %s",
448                           client_p->name, client_p->servptr->name);
449  
450    if (splitchecking && !splitmode)
# Line 576 | Line 457 | update_client_exit_stats(struct Client *
457   * output       - return client pointer
458   * side effects - find person by (nick)name
459   */
579 /* XXX - ugly wrapper */
460   struct Client *
461 < find_person(const struct Client *client_p, const char *name)
461 > find_person(const struct Client *const source_p, const char *name)
462   {
463 <  struct Client *c2ptr;
463 >  struct Client *target_p = NULL;
464  
465    if (IsDigit(*name))
466    {
467 <    if ((c2ptr = hash_find_id(name)) != NULL)
468 <    {
589 <      /* invisible users shall not be found by UID guessing */
590 <      if (IsInvisible(c2ptr) && !IsServer(client_p))
591 <        c2ptr = NULL;
592 <    }
467 >    if (IsServer(source_p->from))
468 >      target_p = hash_find_id(name);
469    }
470    else
471 <    c2ptr = find_client(name);
471 >    target_p = hash_find_client(name);
472  
473 <  return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL);
473 >  return (target_p && IsClient(target_p)) ? target_p : NULL;
474   }
475  
476   /*
477 < * find_chasing - find the client structure for a nick name (user)
478 < *      using history mechanism if necessary. If the client is not found,
479 < *      an error message (NO SUCH NICK) is generated. If the client was found
604 < *      through the history, chasing will be 1 and otherwise 0.
477 > * find_chasing - find the client structure for a nick name (name)
478 > *      using history mechanism if necessary. If the client is not found,
479 > *      an error message (NO SUCH NICK) is generated.
480   */
481   struct Client *
482 < find_chasing(struct Client *client_p, struct Client *source_p, const char *user, int *chasing)
482 > find_chasing(struct Client *source_p, const char *name)
483   {
484 <  struct Client *who = find_person(client_p, user);
610 <
611 <  if (chasing)
612 <    *chasing = 0;
484 >  struct Client *who = find_person(source_p, name);
485  
486    if (who)
487 <    return(who);
487 >    return who;
488  
489 <  if (IsDigit(*user))
490 <    return(NULL);
489 >  if (IsDigit(*name))
490 >    return NULL;
491  
492 <  if ((who = get_history(user,
493 <                        (time_t)ConfigFileEntry.kill_chase_time_limit))
494 <                         == NULL)
492 >  if ((who = whowas_get_history(name,
493 >                         (time_t)ConfigGeneral.kill_chase_time_limit))
494 >                         == NULL)
495    {
496 <    sendto_one(source_p, form_str(ERR_NOSUCHNICK),
497 <               me.name, source_p->name, user);
626 <    return(NULL);
496 >    sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name);
497 >    return NULL;
498    }
499  
500 <  if (chasing)
630 <    *chasing = 1;
631 <
632 <  return(who);
500 >  return who;
501   }
502  
503   /*
# Line 641 | Line 509 | find_chasing(struct Client *client_p, st
509   *        But, this can be used to any client structure.
510   *
511   * NOTE 1:
512 < *        Watch out the allocation of "nbuf", if either source_p->name
512 > *        Watch out the allocation of "buf", if either source_p->name
513   *        or source_p->sockhost gets changed into pointers instead of
514   *        directly allocated within the structure...
515   *
516   * NOTE 2:
517   *        Function return either a pointer to the structure (source_p) or
518 < *        to internal buffer (nbuf). *NEVER* use the returned pointer
518 > *        to internal buffer (buf). *NEVER* use the returned pointer
519   *        to modify what it points!!!
520   */
521   const char *
522 < get_client_name(const struct Client *client, int showip)
522 > get_client_name(const struct Client *client_p, enum addr_mask_type type)
523   {
524 <  static char nbuf[HOSTLEN * 2 + USERLEN + 5];
524 >  static char buf[HOSTLEN * 2 + USERLEN + 5];
525  
526 <  assert(client != NULL);
526 >  assert(client_p);
527  
528 <  if (irccmp(client->name, client->host) == 0)
529 <    return client->name;
528 >  if (!MyConnect(client_p))
529 >    return client_p->name;
530  
531 <  if (ConfigServerHide.hide_server_ips)
532 <    if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
533 <      showip = MASK_IP;
531 >  if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
532 >  {
533 >    if (!irccmp(client_p->name, client_p->host))
534 >      return client_p->name;
535 >    else if (ConfigServerHide.hide_server_ips)
536 >      type = MASK_IP;
537 >  }
538  
539 <  if (ConfigFileEntry.hide_spoof_ips)
540 <    if (showip == SHOW_IP && IsIPSpoof(client))
541 <      showip = MASK_IP;
539 >  if (ConfigGeneral.hide_spoof_ips)
540 >    if (IsIPSpoof(client_p) && type == SHOW_IP)
541 >      type = MASK_IP;
542  
543    /* And finally, let's get the host information, ip or name */
544 <  switch (showip)
544 >  switch (type)
545    {
546      case SHOW_IP:
547 <      if (MyConnect(client))
548 <      {
549 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
550 <                 client->name,
679 <                 client->username, client->sockhost);
680 <        break;
681 <      }
547 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
548 >               client_p->name,
549 >               client_p->username, client_p->sockhost);
550 >      break;
551      case MASK_IP:
552 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
553 <               client->name, client->username);
552 >      if (client_p->localClient->aftype == AF_INET)
553 >        snprintf(buf, sizeof(buf), "%s[%s@255.255.255.255]",
554 >                 client_p->name, client_p->username);
555 >      else
556 >        snprintf(buf, sizeof(buf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
557 >                 client_p->name, client_p->username);
558        break;
559      default:
560 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
561 <               client->name,
562 <               client->username, client->host);
560 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
561 >               client_p->name,
562 >               client_p->username, client_p->host);
563    }
564  
565 <  return nbuf;
565 >  return buf;
566   }
567  
568   void
569   free_exited_clients(void)
570   {
571    dlink_node *ptr = NULL, *next = NULL;
572 <  
572 >
573    DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
574    {
575      free_client(ptr->data);
# Line 712 | Line 585 | free_exited_clients(void)
585   * The only messages generated are QUITs on channels.
586   */
587   static void
588 < exit_one_client(struct Client *source_p, const char *quitmsg)
588 > exit_one_client(struct Client *source_p, const char *comment)
589   {
590 <  dlink_node *lp = NULL, *next_lp = NULL;
590 >  dlink_node *ptr = NULL, *ptr_next = NULL;
591  
592    assert(!IsMe(source_p));
593 +  assert(source_p != &me);
594  
595    if (IsClient(source_p))
596    {
597 <    if (source_p->servptr->serv != NULL)
598 <      dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
597 >    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
598 >    dlinkDelete(&source_p->node, &global_client_list);
599  
600      /*
601       * If a person is on a channel, send a QUIT notice
# Line 729 | Line 603 | exit_one_client(struct Client *source_p,
603       * that the client can show the "**signoff" message).
604       * (Note: The notice is to the local clients *only*)
605       */
606 <    sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
606 >    sendto_common_channels_local(source_p, 0, 0, ":%s!%s@%s QUIT :%s",
607                                   source_p->name, source_p->username,
608 <                                 source_p->host, quitmsg);
609 <    DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
610 <      remove_user_from_channel(lp->data);
608 >                                 source_p->host, comment);
609 >    DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
610 >      remove_user_from_channel(ptr->data);
611  
612 <    add_history(source_p, 0);
613 <    off_history(source_p);
612 >    whowas_add_history(source_p, 0);
613 >    whowas_off_history(source_p);
614  
615      watch_check_hash(source_p, RPL_LOGOFF);
616  
617      if (MyConnect(source_p))
618      {
619        /* Clean up invitefield */
620 <      DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
621 <        del_invite(lp->data, source_p);
620 >      DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->localClient->invited.head)
621 >        del_invite(ptr->data, source_p);
622  
623        del_all_accepts(source_p);
624      }
# Line 752 | Line 626 | exit_one_client(struct Client *source_p,
626    else if (IsServer(source_p))
627    {
628      dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
629 +    dlinkDelete(&source_p->node, &global_client_list);
630  
631 <    if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
632 <      free_dlink_node(lp);
631 >    if ((ptr = dlinkFindDelete(&global_server_list, source_p)))
632 >      free_dlink_node(ptr);
633    }
634  
635    /* Remove source_p from the client lists */
636 <  if (HasID(source_p))
636 >  if (source_p->id[0])
637      hash_del_id(source_p);
638    if (source_p->name[0])
639      hash_del_client(source_p);
# Line 766 | Line 641 | exit_one_client(struct Client *source_p,
641    if (IsUserHostIp(source_p))
642      delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
643  
769  /* remove from global client list
770   * NOTE: source_p->node.next cannot be NULL if the client is added
771   *       to global_client_list (there is always &me at its end)
772   */
773  if (source_p != NULL && source_p->node.next != NULL)
774    dlinkDelete(&source_p->node, &global_client_list);
775
644    update_client_exit_stats(source_p);
645  
646    /* Check to see if the client isn't already on the dead list */
# Line 783 | Line 651 | exit_one_client(struct Client *source_p,
651    dlinkAdd(source_p, make_dlink_node(), &dead_list);
652   }
653  
654 < /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
787 < * and servers to those servers that need them.  A server needs the client
788 < * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
789 < * isn't getting the SQUIT because of @#(*&@)# hostmasking.  With TS4, once
790 < * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
791 < * on that one -orabidoo
792 < *
793 < * This is now called on each local server -adx
794 < */
795 < static void
796 < recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
797 <                   struct Client *from, struct Client *to, const char *comment,
798 <                   const char *splitstr)
799 < {
800 <  dlink_node *ptr, *next;
801 <  struct Client *target_p;
802 <  int hidden = match(me.name, source_p->name); /* XXX */
803 <
804 <  assert(to != source_p);  /* should be already removed from serv_list */
805 <
806 <  /* If this server can handle quit storm (QS) removal
807 <   * of dependents, just send the SQUIT
808 <   *
809 <   * Always check *all* dependent servers if some of them are
810 <   * hidden behind fakename. If so, send out the QUITs -adx
811 <   */
812 <  if (hidden || !IsCapable(to, CAP_QS))
813 <    DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
814 <    {
815 <      target_p = ptr->data;
816 <      sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
817 <    }
818 <
819 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
820 <    recurse_send_quits(original_source_p, ptr->data, from, to,
821 <                       comment, splitstr);
822 <
823 <  if (!hidden && ((source_p == original_source_p && to != from) ||
824 <                  !IsCapable(to, CAP_QS)))
825 <  {
826 <    /* don't use a prefix here - we have to be 100% sure the message
827 <     * will be accepted without Unknown prefix etc.. */
828 <    sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
829 <  }
830 < }
831 <
832 < /*
654 > /*
655   * Remove all clients that depend on source_p; assumes all (S)QUITs have
656 < * already been sent.  we make sure to exit a server's dependent clients
657 < * and servers before the server itself; exit_one_client takes care of
656 > * already been sent.  we make sure to exit a server's dependent clients
657 > * and servers before the server itself; exit_one_client takes care of
658   * actually removing things off llists.   tweaked from +CSr31  -orabidoo
659   */
660   static void
661 < recurse_remove_clients(struct Client *source_p, const char *quitmsg)
661 > recurse_remove_clients(struct Client *source_p, const char *comment)
662   {
663 <  dlink_node *ptr, *next;
663 >  dlink_node *ptr = NULL, *ptr_next = NULL;
664  
665 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
666 <    exit_one_client(ptr->data, quitmsg);
665 >  DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->client_list.head)
666 >    exit_one_client(ptr->data, comment);
667  
668 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
668 >  DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->server_list.head)
669    {
670 <    recurse_remove_clients(ptr->data, quitmsg);
671 <    exit_one_client(ptr->data, quitmsg);
670 >    recurse_remove_clients(ptr->data, comment);
671 >    exit_one_client(ptr->data, comment);
672    }
673   }
674  
675   /*
854 ** Remove *everything* that depends on source_p, from all lists, and sending
855 ** all necessary QUITs and SQUITs.  source_p itself is still on the lists,
856 ** and its SQUITs have been sent except for the upstream one  -orabidoo
857 */
858 static void
859 remove_dependents(struct Client *source_p, struct Client *from,
860                  const char *comment, const char *splitstr)
861 {
862  dlink_node *ptr = NULL;
863
864  DLINK_FOREACH(ptr, serv_list.head)
865    recurse_send_quits(source_p, source_p, from, ptr->data,
866                       comment, splitstr);
867
868  recurse_remove_clients(source_p, splitstr);
869 }
870
871 /*
676   * exit_client - exit a client of any type. Generally, you can use
677   * this on any struct Client, regardless of its state.
678   *
679   * Note, you shouldn't exit remote _users_ without first doing
680 < * SetKilled and propagating a kill or similar message. However,
681 < * it is perfectly correct to call exit_client to force a _server_
680 > * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
681 > *
682 > * However, it is perfectly correct to call exit_client to force a _server_
683   * quit (either local or remote one).
684   *
685 + *
686   * inputs:       - a client pointer that is going to be exited
881 *               - for servers, the second argument is a pointer to who
882 *                 is firing the server. This side won't get any generated
883 *                 messages. NEVER NULL!
687   * output:       none
688   * side effects: the client is delinked from all lists, disconnected,
689   *               and the rest of IRC network is notified of the exit.
690   *               Client memory is scheduled to be freed
691   */
692   void
693 < exit_client(struct Client *source_p, struct Client *from, const char *comment)
693 > exit_client(struct Client *source_p, const char *comment)
694   {
695    dlink_node *m = NULL;
696  
697 +  assert(!IsMe(source_p));
698 +  assert(source_p != &me);
699 +
700    if (MyConnect(source_p))
701    {
702      /* DO NOT REMOVE. exit_client can be called twice after a failed
# Line 901 | Line 707 | exit_client(struct Client *source_p, str
707  
708      SetClosing(source_p);
709  
710 <    if (IsIpHash(source_p))
905 <      remove_one_ip(&source_p->localClient->ip);
906 <
907 <    if (source_p->localClient->auth)
710 >    if (HasFlag(source_p, FLAGS_IPHASH))
711      {
712 <      delete_auth(source_p->localClient->auth);
713 <      source_p->localClient->auth = NULL;
712 >      DelFlag(source_p, FLAGS_IPHASH);
713 >      ipcache_remove_address(&source_p->localClient->ip);
714      }
715  
716 <    /* This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
716 >    delete_auth(&source_p->localClient->auth);
717 >
718 >    /*
719 >     * This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
720       * STAT_HANDSHAKE or STAT_UNKNOWN
721       * all of which are lumped together into unknown_list
722       *
# Line 924 | Line 730 | exit_client(struct Client *source_p, str
730      }
731      else if (IsClient(source_p))
732      {
733 +      time_t on_for = CurrentTime - source_p->localClient->firsttime;
734        assert(Count.local > 0);
735        Count.local--;
736  
737 <      if (IsOper(source_p))
738 <      {
932 <        if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
737 >      if (HasUMode(source_p, UMODE_OPER))
738 >        if ((m = dlinkFindDelete(&oper_list, source_p)))
739            free_dlink_node(m);
934      }
740  
741        assert(dlinkFind(&local_client_list, source_p));
742        dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
743  
744 <      if (source_p->localClient->list_task != NULL)
745 <        free_list_task(source_p->localClient->list_task, source_p);
744 >      if (source_p->localClient->list_task)
745 >        free_list_task(source_p);
746  
747        watch_del_watch_list(source_p);
748 <      sendto_realops_flags(UMODE_CCONN, L_ALL, "Client exiting: %s (%s@%s) [%s] [%s]",
748 >      sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
749 >                           "Client exiting: %s (%s@%s) [%s] [%s]",
750                             source_p->name, source_p->username, source_p->host, comment,
751 <                           ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
751 >                           ConfigGeneral.hide_spoof_ips && IsIPSpoof(source_p) ?
752                             "255.255.255.255" : source_p->sockhost);
753 <      sendto_realops_flags(UMODE_CCONN_FULL, L_ALL, "CLIEXIT: %s %s %s %s 0 %s",
754 <                           source_p->name,
755 <                           source_p->username,
756 <                           source_p->host,
757 <
758 <                           ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
953 <                           "255.255.255.255" : source_p->sockhost,
954 <                           comment);
753 >      ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
754 >           myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
755 >           (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
756 >           source_p->name, source_p->username, source_p->host,
757 >           source_p->localClient->send.bytes>>10,
758 >           source_p->localClient->recv.bytes>>10);
759      }
760 <
957 <    /* As soon as a client is known to be a server of some sort
958 <     * it has to be put on the serv_list, or SJOIN's to this new server
959 <     * from the connect burst will not be seen.
960 <     */
961 <    if (IsServer(source_p) || IsConnecting(source_p) ||
962 <        IsHandshake(source_p))
760 >    else if (IsServer(source_p))
761      {
762 <      if ((m = dlinkFindDelete(&serv_list, source_p)) != NULL)
763 <      {
966 <        free_dlink_node(m);
967 <        unset_chcap_usage_counts(source_p);
968 <      }
762 >      assert(Count.myserver > 0);
763 >      --Count.myserver;
764  
765 <      if (IsServer(source_p))
766 <        Count.myserver--;
765 >      assert(dlinkFind(&local_server_list, source_p));
766 >      dlinkDelete(&source_p->localClient->lclient_node, &local_server_list);
767      }
768  
974    log_user_exit(source_p);
975
769      if (!IsDead(source_p))
770      {
771        if (IsServer(source_p))
772        {
773 <        /* for them, we are exiting the network */
774 <        sendto_one(source_p, ":%s SQUIT %s :%s",
775 <                   ID_or_name(from, source_p), me.name, comment);
773 >        if (!HasFlag(source_p, FLAGS_SQUIT))
774 >        {
775 >          /* for them, we are exiting the network */
776 >          sendto_one(source_p, ":%s SQUIT %s :%s",
777 >                     me.id, me.id, comment);
778 >        }
779        }
780  
781        sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
782                   source_p->host, comment);
783      }
784  
989    /*
990    ** Currently only server connections can have
991    ** depending remote clients here, but it does no
992    ** harm to check for all local clients. In
993    ** future some other clients than servers might
994    ** have remotes too...
995    **
996    ** Close the Client connection first and mark it
997    ** so that no messages are attempted to send to it.
998    ** Remember it makes source_p->from == NULL.
999    */
785      close_connection(source_p);
786    }
787 +  else if (IsClient(source_p) && HasFlag(source_p->servptr, FLAGS_EOB))
788 +    sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
789 +                         "Client exiting at %s: %s (%s@%s) [%s]",
790 +                         source_p->servptr->name, source_p->name,
791 +                         source_p->username, source_p->host, comment);
792  
793    if (IsServer(source_p))
794    {
795 <    char splitstr[HOSTLEN + HOSTLEN + 2];
795 >    char splitstr[HOSTLEN + HOSTLEN + 2] = "";
796  
797      /* This shouldn't ever happen */
798 <    assert(source_p->serv != NULL && source_p->servptr != NULL);
798 >    assert(source_p->serv && source_p->servptr);
799  
800      if (ConfigServerHide.hide_servers)
801        /*
802 <       * Set netsplit message to "*.net *.split" to still show
802 >       * Set netsplit message to "*.net *.split" to still show
803         * that its a split, but hide the servers splitting
804         */
805 <      strcpy(splitstr, "*.net *.split");
805 >      strlcpy(splitstr, "*.net *.split", sizeof(splitstr));
806      else
807        snprintf(splitstr, sizeof(splitstr), "%s %s",
808                 source_p->servptr->name, source_p->name);
809  
810 <    remove_dependents(source_p, from->from, comment, splitstr);
810 >    /* Send SQUIT for source_p in every direction. source_p is already off of local_server_list here */
811 >    if (!HasFlag(source_p, FLAGS_SQUIT))
812 >      sendto_server(NULL, NOCAPS, NOCAPS, "SQUIT %s :%s", source_p->id, comment);
813 >
814 >    /* Now exit the clients internally */
815 >    recurse_remove_clients(source_p, splitstr);
816  
817 <    if (source_p->servptr == &me)
817 >    if (MyConnect(source_p))
818      {
819 <      sendto_realops_flags(UMODE_ALL, L_ALL,
819 >      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
820                             "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
821 <                           source_p->name, (int)(CurrentTime - source_p->firsttime),
821 >                           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
822                             source_p->localClient->send.bytes >> 10,
823                             source_p->localClient->recv.bytes >> 10);
824 <      ilog(L_NOTICE, "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
825 <           source_p->name, (int)(CurrentTime - source_p->firsttime),
824 >      ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
825 >           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
826             source_p->localClient->send.bytes >> 10,
827             source_p->localClient->recv.bytes >> 10);
828      }
829    }
830 <  else if (IsClient(source_p) && !IsKilled(source_p))
831 <  {
832 <    sendto_server(from->from, NULL, CAP_TS6, NOCAPS,
1038 <                  ":%s QUIT :%s", ID(source_p), comment);
1039 <    sendto_server(from->from, NULL, NOCAPS, CAP_TS6,
1040 <                  ":%s QUIT :%s", source_p->name, comment);
1041 <  }
830 >  else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
831 >    sendto_server(source_p->from, NOCAPS, NOCAPS, ":%s QUIT :%s",
832 >                  source_p->id, comment);
833  
834    /* The client *better* be off all of the lists */
835    assert(dlinkFind(&unknown_list, source_p) == NULL);
836    assert(dlinkFind(&local_client_list, source_p) == NULL);
837 <  assert(dlinkFind(&serv_list, source_p) == NULL);
837 >  assert(dlinkFind(&local_server_list, source_p) == NULL);
838    assert(dlinkFind(&oper_list, source_p) == NULL);
839  
840    exit_one_client(source_p, comment);
# Line 1082 | Line 873 | dead_link_on_write(struct Client *client
873   void
874   dead_link_on_read(struct Client *client_p, int error)
875   {
876 <  char errmsg[255];
876 >  char errmsg[IRCD_BUFSIZE];
877    int current_error;
878  
879    if (IsDefunct(client_p))
# Line 1095 | Line 886 | dead_link_on_read(struct Client *client_
886  
887    if (IsServer(client_p) || IsHandshake(client_p))
888    {
889 <    int connected = CurrentTime - client_p->firsttime;
890 <      
889 >    int connected = CurrentTime - client_p->localClient->firsttime;
890 >
891      if (error == 0)
892      {
893        /* Admins get the real IP */
894 <      sendto_realops_flags(UMODE_ALL, L_ADMIN,
895 <                           "Server %s closed the connection",
896 <                           get_client_name(client_p, SHOW_IP));
894 >      sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
895 >                           "Server %s closed the connection",
896 >                           get_client_name(client_p, SHOW_IP));
897  
898        /* Opers get a masked IP */
899 <      sendto_realops_flags(UMODE_ALL, L_OPER,
900 <                           "Server %s closed the connection",
901 <                           get_client_name(client_p, MASK_IP));
899 >      sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
900 >                           "Server %s closed the connection",
901 >                           get_client_name(client_p, MASK_IP));
902  
903 <      ilog(L_NOTICE, "Server %s closed the connection",
904 <           get_client_name(client_p, SHOW_IP));
903 >      ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
904 >           get_client_name(client_p, SHOW_IP));
905      }
906      else
907      {
908        report_error(L_ADMIN, "Lost connection to %s: %s",
909 <                   get_client_name(client_p, SHOW_IP), current_error);
909 >                   get_client_name(client_p, SHOW_IP), current_error);
910        report_error(L_OPER, "Lost connection to %s: %s",
911 <                   get_client_name(client_p, MASK_IP), current_error);
911 >                   get_client_name(client_p, MASK_IP), current_error);
912      }
913  
914 <    sendto_realops_flags(UMODE_ALL, L_ALL,
915 <                         "%s had been connected for %d day%s, %2d:%02d:%02d",
916 <                         client_p->name, connected/86400,
917 <                         (connected/86400 == 1) ? "" : "s",
918 <                         (connected % 86400) / 3600, (connected % 3600) / 60,
919 <                         connected % 60);
914 >    sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
915 >                         "%s had been connected for %d day%s, %2d:%02d:%02d",
916 >                         client_p->name, connected/86400,
917 >                         (connected/86400 == 1) ? "" : "s",
918 >                         (connected % 86400) / 3600, (connected % 3600) / 60,
919 >                         connected % 60);
920    }
921  
922    if (error == 0)
# Line 1135 | Line 926 | dead_link_on_read(struct Client *client_
926      snprintf(errmsg, sizeof(errmsg), "Read error: %s",
927               strerror(current_error));
928  
929 <  exit_client(client_p, &me, errmsg);
929 >  exit_client(client_p, errmsg);
930   }
931  
932   void
# Line 1152 | Line 943 | exit_aborted_clients(void)
943  
944      if (target_p == NULL)
945      {
946 <      sendto_realops_flags(UMODE_ALL, L_ALL,
946 >      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
947                             "Warning: null client on abort_list!");
948        dlinkDelete(ptr, &abort_list);
949        free_dlink_node(ptr);
# Line 1166 | Line 957 | exit_aborted_clients(void)
957      else
958        notice = "Write error: connection closed";
959  
960 <    exit_client(target_p, &me, notice);  
960 >    exit_client(target_p, notice);
961      free_dlink_node(ptr);
962    }
963   }
# Line 1194 | Line 985 | del_accept(struct split_nuh_item *accept
985  
986   struct split_nuh_item *
987   find_accept(const char *nick, const char *user,
988 <            const char *host, struct Client *client_p, int do_match)
988 >            const char *host, struct Client *client_p,
989 >            int (*cmpfunc)(const char *, const char *))
990   {
991    dlink_node *ptr = NULL;
1200  /* XXX We wouldn't need that if match() would return 0 on match */
1201  int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp;
992  
993    DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
994    {
995      struct split_nuh_item *accept_p = ptr->data;
996  
997 <    if (cmpfunc(accept_p->nickptr, nick) == do_match &&
998 <        cmpfunc(accept_p->userptr, user) == do_match &&
999 <        cmpfunc(accept_p->hostptr, host) == do_match)
997 >    if (!cmpfunc(accept_p->nickptr, nick) &&
998 >        !cmpfunc(accept_p->userptr, user) &&
999 >        !cmpfunc(accept_p->hostptr, host))
1000        return accept_p;
1001    }
1002  
# Line 1227 | Line 1017 | accept_message(struct Client *source,
1017    dlink_node *ptr = NULL;
1018  
1019    if (source == target || find_accept(source->name, source->username,
1020 <                                      source->host, target, 1))
1020 >                                      source->host, target, match))
1021      return 1;
1022  
1023 <  if (IsSoftCallerId(target))
1023 >  if (HasUMode(target, UMODE_SOFTCALLERID))
1024      DLINK_FOREACH(ptr, target->channel.head)
1025        if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1026          return 1;
# Line 1247 | Line 1037 | accept_message(struct Client *source,
1037   void
1038   del_all_accepts(struct Client *client_p)
1039   {
1040 <  dlink_node *ptr = NULL, *next_ptr = NULL;
1040 >  dlink_node *ptr = NULL, *ptr_next = NULL;
1041  
1042 <  DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1042 >  DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->localClient->acceptlist.head)
1043      del_accept(ptr->data, client_p);
1044   }
1045  
1046 < /* change_local_nick()
1047 < *
1258 < * inputs       - pointer to server
1259 < *              - pointer to client
1260 < *              - nick
1261 < * output       -
1262 < * side effects - changes nick of a LOCAL user
1263 < */
1264 < void
1265 < change_local_nick(struct Client *client_p, struct Client *source_p, const char *nick)
1046 > unsigned int
1047 > idle_time_get(const struct Client *source_p, const struct Client *target_p)
1048   {
1049 <  int samenick = 0;
1049 >  unsigned int idle = 0;
1050 >  unsigned int min_idle = 0;
1051 >  unsigned int max_idle = 0;
1052 >  const struct ClassItem *class = get_class_ptr(&target_p->localClient->confs);
1053 >
1054 >  if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1055 >    return CurrentTime - target_p->localClient->last_privmsg;
1056 >  if (HasUMode(source_p, UMODE_OPER) &&
1057 >      !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1058 >    return CurrentTime - target_p->localClient->last_privmsg;
1059  
1060 <  assert(source_p->name[0] && !EmptyString(nick));
1060 >  min_idle = class->min_idle;
1061 >  max_idle = class->max_idle;
1062  
1063 <  /*
1064 <   * Client just changing his/her nick. If he/she is
1273 <   * on a channel, send note of change to all clients
1274 <   * on that channel. Propagate notice to other servers.
1275 <   */
1276 <  if ((source_p->localClient->last_nick_change +
1277 <       ConfigFileEntry.max_nick_time) < CurrentTime)
1278 <    source_p->localClient->number_of_nick_changes = 0;
1279 <  source_p->localClient->last_nick_change = CurrentTime;
1280 <  source_p->localClient->number_of_nick_changes++;
1281 <
1282 <  if ((ConfigFileEntry.anti_nick_flood &&
1283 <      (source_p->localClient->number_of_nick_changes
1284 <       <= ConfigFileEntry.max_nick_changes)) ||
1285 <     !ConfigFileEntry.anti_nick_flood ||
1286 <     (IsOper(source_p) && ConfigFileEntry.no_oper_flood))
1287 <  {
1288 <    samenick = !irccmp(source_p->name, nick);
1063 >  if (min_idle == max_idle)
1064 >    return min_idle;
1065  
1066 <    if (!samenick)
1067 <    {
1068 <      source_p->tsinfo = CurrentTime;
1069 <      clear_ban_cache_client(source_p);
1294 <      watch_check_hash(source_p, RPL_LOGOFF);
1295 <
1296 <      if (HasUMode(source_p, UMODE_REGISTERED))
1297 <      {
1298 <        unsigned int oldmodes = source_p->umodes;
1299 <        char modebuf[IRCD_BUFSIZE] = { '\0' };
1300 <
1301 <        DelUMode(source_p, UMODE_REGISTERED);
1302 <        send_umode(source_p, source_p, oldmodes, 0xffffffff, modebuf);
1303 <      }
1304 <    }
1305 <
1306 <    /* XXX - the format of this notice should eventually be changed
1307 <     * to either %s[%s@%s], or even better would be get_client_name() -bill
1308 <     */
1309 <    sendto_realops_flags(UMODE_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]",
1310 <                         source_p->name, nick, source_p->username, source_p->host);
1311 <    sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
1312 <                                 source_p->name, source_p->username,
1313 <                                 source_p->host, nick);
1314 <    add_history(source_p, 1);
1066 >  if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1067 >    idle = genrand_int32();
1068 >  else
1069 >    idle = CurrentTime - target_p->localClient->last_privmsg;
1070  
1071 <    sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
1072 <                  ":%s NICK %s :%lu",
1073 <                  ID(source_p), nick, (unsigned long)source_p->tsinfo);
1074 <    sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
1320 <                  ":%s NICK %s :%lu",
1321 <                  source_p->name, nick, (unsigned long)source_p->tsinfo);
1071 >  if (!max_idle)
1072 >    idle = 0;
1073 >  else
1074 >    idle %= max_idle;
1075  
1076 <    hash_del_client(source_p);
1077 <    strcpy(source_p->name, nick);
1325 <    hash_add_client(source_p);
1076 >  if (idle < min_idle)
1077 >    idle = min_idle + (idle % (max_idle - min_idle));
1078  
1079 <    if (!samenick)
1080 <      watch_check_hash(source_p, RPL_LOGON);
1079 >  return idle;
1080 > }
1081  
1082 <    /* fd_desc is long enough */
1083 <    fd_note(&client_p->localClient->fd, "Nick: %s", nick);
1084 <  }
1085 <  else
1086 <    sendto_one(source_p, form_str(ERR_NICKTOOFAST),
1087 <               me.name, source_p->name, source_p->name,
1088 <               nick, ConfigFileEntry.max_nick_time);
1082 > /* client_init()
1083 > *
1084 > * inputs       - NONE
1085 > * output       - NONE
1086 > * side effects - initialize client free memory
1087 > */
1088 > void
1089 > client_init(void)
1090 > {
1091 >  static struct event event_ping =
1092 >  {
1093 >    .name = "check_pings",
1094 >    .handler = check_pings,
1095 >    .when = 5
1096 >  };
1097 >
1098 >  client_pool = mp_pool_new(sizeof(struct Client), MP_CHUNK_SIZE_CLIENT);
1099 >  lclient_pool = mp_pool_new(sizeof(struct LocalUser), MP_CHUNK_SIZE_LCLIENT);
1100 >  event_add(&event_ping, NULL);
1101   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)