/* Rewritten by Run - 24 sept 94 */
static void exit_one_client(struct Client* bcptr, const char* comment)
{
  struct SLink *lp;
  struct Ban *bp;

  if (cli_serv(bcptr) && cli_serv(bcptr)->client_list)  /* Was SetServerYXX called ? */
    ClearServerYXX(bcptr);      /* Removes server from server_list[] */
  if (IsUser(bcptr)) {
    /*
     * clear out uping requests
     */
    if (IsUPing(bcptr))
      uping_cancel(bcptr, 0);
    /*
     * Stop a running /LIST clean
     */
    if (MyUser(bcptr) && cli_listing(bcptr)) {
      MyFree(cli_listing(bcptr));
      cli_listing(bcptr) = NULL;
    }
    /*
     * If a person is on a channel, send a QUIT notice
     * to every client (person) on the same channel (so
     * that the client can show the "**signoff" message).
     * (Note: The notice is to the local clients *only*)
     */
    sendcmdto_common_channels_butone(bcptr, CMD_QUIT, NULL, ":%s", comment);

    remove_user_from_all_channels(bcptr);

    /* Clean up invitefield */
    while ((lp = cli_user(bcptr)->invited))
      del_invite(bcptr, lp->value.chptr);

    /* Clean up silencefield */
    while ((bp = cli_user(bcptr)->silence)) {
      cli_user(bcptr)->silence = bp->next;
      free_ban(bp);
    }

    /* Clean up snotice lists */
    if (MyUser(bcptr))
      set_snomask(bcptr, ~0, SNO_DEL);

    if (IsInvisible(bcptr)) {
      assert(UserStats.inv_clients > 0);
      --UserStats.inv_clients;
    }
    if (IsOper(bcptr)) {
      assert(UserStats.opers > 0);
      --UserStats.opers;
    }
    if (MyConnect(bcptr))
      Count_clientdisconnects(bcptr, UserStats);
    else
      Count_remoteclientquits(UserStats, bcptr);
  }
  else if (IsServer(bcptr))
  {
    /* Remove downlink list node of uplink */
    remove_dlink(&(cli_serv(cli_serv(bcptr)->up))->down, cli_serv(bcptr)->updown);
    cli_serv(bcptr)->updown = 0;

    if (MyConnect(bcptr))
      Count_serverdisconnects(UserStats);
    else
      Count_remoteserverquits(UserStats);
  }
  else if (IsMe(bcptr))
  {
    sendto_opmask_butone(0, SNO_OLDSNO, "ERROR: tried to exit me! : %s",
			 comment);
    return;                     /* ...must *never* exit self! */
  }
  else if (IsUnknown(bcptr) || IsConnecting(bcptr) || IsHandshake(bcptr))
    Count_unknowndisconnects(UserStats);

  /*
   * Update IPregistry
   */
  if (IsIPChecked(bcptr))
    IPcheck_disconnect(bcptr);

  /* 
   * Remove from serv->client_list
   * NOTE: user is *always* NULL if this is a server
   */
  if (cli_user(bcptr)) {
    assert(!IsServer(bcptr));
    /* bcptr->user->server->serv->client_list[IndexYXX(bcptr)] = NULL; */
    RemoveYXXClient(cli_user(bcptr)->server, cli_yxx(bcptr));
  }

  /* Remove bcptr from the client list */
#ifdef DEBUGMODE
  if (hRemClient(bcptr) != 0)
    Debug((DEBUG_ERROR, "%p !in tab %s[%s] %p %p %p %d %d %p",
          bcptr, cli_name(bcptr), cli_from(bcptr) ? cli_sockhost(cli_from(bcptr)) : "??host",
          cli_from(bcptr), cli_next(bcptr), cli_prev(bcptr), cli_fd(bcptr),
          cli_status(bcptr), cli_user(bcptr)));
#else
  hRemClient(bcptr);
#endif
  remove_client_from_list(bcptr);
}
Example #2
0
/*
 * Exit one client, local or remote. Assuming all dependants have
 * been already removed, and socket closed for local client.
 */
static void 
exit_one_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
{
    Link   *lp;
    
    /*
     * For a server or user quitting, propogate the information to
     * other servers (except to the one where is came from (cptr))
     */
    if (IsMe(sptr))
    {
        sendto_ops("ERROR: tried to exit me! : %s", comment);
        return;                 /* ...must *never* exit self!! */
    }
    else if (IsServer(sptr))
    {
#ifdef ALWAYS_SEND_DURING_SPLIT
        currently_processing_netsplit = YES;
#endif

        exit_server(cptr, sptr, from, comment);
        
#ifdef ALWAYS_SEND_DURING_SPLIT
        currently_processing_netsplit = NO;
#endif
        return;
    }
    else if (!(IsPerson(sptr)))
        /*
         * ...this test is *dubious*, would need * some thought.. but for
         * now it plugs a * nasty hole in the server... --msa
         */
        ;                               /* Nothing */
    else if (sptr->name[0])
    {   
        /* ...just clean all others with QUIT... */
        /*
         * If this exit is generated from "m_kill", then there is no
         * sense in sending the QUIT--KILL's have been sent instead.
         */
        if ((sptr->flags & FLAGS_KILLED) == 0) 
        {
            sendto_serv_butone(cptr, ":%s QUIT :%s",
                               sptr->name, comment);
        }
        /*
         * * If a person is on a channel, send a QUIT notice * to every
         * client (person) on the same channel (so * that the client can
         * show the "**signoff" message). * (Note: The notice is to the
         * local clients *only*)
         */
        if (sptr->user)
        {
            send_part_to_common_channels(sptr, comment);
            send_quit_to_common_channels(sptr, comment);
            while ((lp = sptr->user->channel))
                remove_user_from_channel(sptr, lp->value.chptr);

	    clones_remove(sptr);

#ifdef RWHO_PROBABILITY
            probability_remove(sptr);
#endif
            
            /* Clean up invitefield */
            while ((lp = sptr->user->invited))
                del_invite(sptr, lp->value.chptr);
            /* Clean up silences */
            while ((lp = sptr->user->silence)) 
                del_silence(sptr, lp->value.cp);
            remove_dcc_references(sptr);
            /* again, this is all that is needed */
        }
    }

    /* Remove sptr from the client list */
    if (del_from_client_hash_table(sptr->name, sptr) != 1) 
    {
        Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
               sptr, sptr->name,
               sptr->from ? sptr->from->sockhost : "??host",
               sptr->from, sptr->next, sptr->prev, sptr->fd,
               sptr->status, sptr->user));
    }
    /* remove user from watchlists */
    if(IsRegistered(sptr))
        hash_check_watch(sptr, RPL_LOGOFF);
    remove_client_from_list(sptr);
    return;
}
Example #3
0
/*
** Exit one client, local or remote. Assuming all dependents have
** been already removed, and socket closed for local client.
*/
static void exit_one_client(struct Client *client_p,
                            struct Client *source_p,
                            struct Client *from, const char *comment)
{
  struct Client* target_p;
  dlink_node *lp;
  dlink_node *next_lp;

  if (IsServer(source_p))
    {
      if (source_p->servptr && source_p->servptr->serv)
        del_client_from_llist(&(source_p->servptr->serv->servers),
                                    source_p);
      else
        ts_warn("server %s without servptr!", source_p->name);

      if(!IsMe(source_p))
        remove_server_from_list(source_p);
    }
  else if (source_p->servptr && source_p->servptr->serv)
    {
      del_client_from_llist(&(source_p->servptr->serv->users), source_p);
    }
  /* there are clients w/o a servptr: unregistered ones */

  /*
  **  For a server or user quitting, propogate the information to
  **  other servers (except to the one where is came from (client_p))
  */
  if (IsMe(source_p))
    {
      sendto_realops_flags(FLAGS_ALL, L_ALL,
			   "ERROR: tried to exit me! : %s", comment);
      return;        /* ...must *never* exit self!! */
    }
  else if (IsServer(source_p))
    {
      /*
      ** Old sendto_serv_but_one() call removed because we now
      ** need to send different names to different servers
      ** (domain name matching)
      */
      /*
      ** The bulk of this is done in remove_dependents now, all
      ** we have left to do is send the SQUIT upstream.  -orabidoo
      */
      if (source_p->localClient)
      {
	if(source_p->localClient->ctrlfd > -1)
	{
          fd_close(source_p->localClient->ctrlfd);
	  source_p->localClient->ctrlfd = -1;

#ifndef HAVE_SOCKETPAIR
          fd_close(source_p->localClient->ctrlfd_r);
	  fd_close(source_p->localClient->fd_r);
	  
	  source_p->localClient->ctrlfd_r = -1;
	  source_p->localClient->fd_r = -1;
#endif
	}
      }

      target_p = source_p->from;
      if (target_p && IsServer(target_p) && target_p != client_p && !IsMe(target_p) &&
          (source_p->flags & FLAGS_KILLED) == 0)
        sendto_one(target_p, ":%s SQUIT %s :%s", from->name, source_p->name, comment);
    }
  else if (source_p->name[0]) /* ...just clean all others with QUIT... */
    {
      /*
      ** If this exit is generated from "m_kill", then there
      ** is no sense in sending the QUIT--KILL's have been
      ** sent instead.
      */
      if ((source_p->flags & FLAGS_KILLED) == 0)
        {
          sendto_server(client_p, source_p, NULL, NOCAPS, NOCAPS,
                        NOFLAGS, ":%s QUIT :%s", source_p->name, comment);
        }
      /*
      ** If a person is on a channel, send a QUIT notice
      ** to every client (person) on the same channel (so
      ** that the client can show the "**signoff" message).
      ** (Note: The notice is to the local clients *only*)
      */
      if (source_p->user)
        {
          sendto_common_channels_local(source_p, ":%s!%s@%s QUIT :%s",
				       source_p->name,
				       source_p->username,
				       source_p->host,
				       comment);

          for (lp = source_p->user->channel.head; lp; lp = next_lp)
	    {
	      next_lp = lp->next;
	      remove_user_from_channel(lp->data, source_p);
	    }
          /* Should not be in any channels now */
          assert(source_p->user->channel.head == NULL);
          
          /* Clean up invitefield */
          for (lp = source_p->user->invited.head; lp; lp = next_lp)
           {
              next_lp = lp->next;
              del_invite(lp->data, source_p);
           }

          /* Clean up allow lists */
          del_all_accepts(source_p);

	  add_history(source_p, 0);
	  off_history(source_p);

	  if (HasID(source_p))
	    del_from_id_hash_table(source_p->user->id, source_p);
  
          /* again, this is all that is needed */
        }
    }
  
  /* 
   * Remove source_p from the client lists
   */
  del_from_client_hash_table(source_p->name, source_p);

  /* remove from global client list */
  remove_client_from_list(source_p);

  /* Check to see if the client isn't already on the dead list */
  assert(dlinkFind(&dead_list, source_p) == NULL);
  /* add to dead client dlist */
  lp = make_dlink_node();
  SetDead(source_p);
  dlinkAdd(source_p, lp, &dead_list);
}
Example #4
0
void 
exit_one_server(aClient *cptr, aClient *dead, aClient *from, 
                aClient *lcptr, char *spinfo, char *comment)
{
    aClient *acptr, *next;
    DLink *lp;

    /* okay, this is annoying.
     * first off, we need two loops.
     * one: to remove all the clients.
     * two: to remove all the servers.
     * HOWEVER! removing a server may cause removal of more servers 
     * and more clients.
     * and this may make our pointer to next bad. therefore, we have to restart
     *  the server loop each time we find a server.
     * We _NEED_ two different loops: all clients must be removed "
     * before the server is
     *  removed. Otherwise, bad things (tm) can happen.
     */

    Debug((DEBUG_NOTICE, "server noquit: %s", cptr->name));

    for (acptr = client; acptr; acptr = next) 
    {
        next = acptr->next; /* we might destroy this client record 
                             * in the loop. */
        
        if(acptr->uplink != cptr || !IsPerson(acptr)) 
            continue;

        exit_one_client_in_split(acptr, dead, spinfo);
    }

    for (acptr = client; acptr; acptr = next) 
    {
        next = acptr->next; /* we might destroy this client record in 
                             * the loop. */

        if(acptr->uplink != cptr || !IsServer(acptr)) 
            continue;

        exit_one_server(acptr, dead, from, lcptr, spinfo, comment);
        next = client; /* restart the loop */
    }

    Debug((DEBUG_NOTICE, "done exiting server: %s", cptr->name));

    for (lp = server_list; lp; lp = lp->next)
    {
        acptr = lp->value.cptr;

        if (acptr == cptr || IsMe(acptr) ||
            acptr == dead || acptr == lcptr)
            continue;

        /* if the server is noquit, we only want to send it
         *  information about 'dead'
         * if it's not, this server gets split information for ALL
         * dead servers.
         */

#ifdef NOQUIT
        if(IsNoquit(acptr))
#endif
        if(cptr != dead)
            continue;

        if (cptr->from == acptr) /* "upstream" squit */
            sendto_one(acptr, ":%s SQUIT %s :%s", from->name, cptr->name,
                       comment);
        else 
            sendto_one(acptr, "SQUIT %s :%s", cptr->name, comment);
    }

    del_from_client_hash_table(cptr->name, cptr); 
    hash_check_watch(cptr, RPL_LOGOFF);
    remove_client_from_list(cptr);
}