/* * Taken the code from ExitOneClient() for this and placed it here. * - avalon */ void remove_client_from_list(struct Client *cptr) { assert(cli_verify(cptr)); assert(con_verify(cli_connect(cptr))); assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr))); assert(!cli_next(cptr) || cli_verify(cli_next(cptr))); assert(!IsMe(cptr)); /* Only remove from the list if it actually IS in the list. * cli_next(cptr) cannot be NULL here if cptr is in the list, * only &me is at the end, and we never try to remove &me -GW */ if(cli_next(cptr)) { if (cli_prev(cptr)) cli_next(cli_prev(cptr)) = cli_next(cptr); else { GlobalClientList = cli_next(cptr); cli_prev(GlobalClientList) = 0; } cli_prev(cli_next(cptr)) = cli_prev(cptr); } cli_next(cptr) = cli_prev(cptr) = 0; if (IsUser(cptr) && cli_user(cptr)) { add_history(cptr, 0); off_history(cptr); } if (cli_user(cptr)) { free_user(cli_user(cptr)); cli_user(cptr) = 0; } if (cli_serv(cptr)) { if (cli_serv(cptr)->user) { free_user(cli_serv(cptr)->user); cli_serv(cptr)->user = 0; } if (cli_serv(cptr)->client_list) MyFree(cli_serv(cptr)->client_list); MyFree(cli_serv(cptr)->last_error_msg); MyFree(cli_serv(cptr)); #ifdef DEBUGMODE --servs.inuse; #endif } free_client(cptr); }
/** Remove \a cptr from lists that it is a member of. * Specifically, this delinks \a cptr from #GlobalClientList, updates * the whowas history list, frees its Client::cli_user and * Client::cli_serv fields, and finally calls free_client() on it. * @param[in] cptr Client to remove from lists and free. */ void remove_client_from_list(struct Client *cptr) { assert(cli_verify(cptr)); assert(con_verify(cli_connect(cptr))); assert(!cli_prev(cptr) || cli_verify(cli_prev(cptr))); assert(!cli_next(cptr) || cli_verify(cli_next(cptr))); assert(!IsMe(cptr)); /* Only try remove cptr from the list if it IS in the list. * cli_next(cptr) cannot be NULL here, as &me is always the end * the list, and we never remove &me. -GW */ if(cli_next(cptr)) { if (cli_prev(cptr)) cli_next(cli_prev(cptr)) = cli_next(cptr); else { GlobalClientList = cli_next(cptr); cli_prev(GlobalClientList) = 0; } cli_prev(cli_next(cptr)) = cli_prev(cptr); } cli_next(cptr) = cli_prev(cptr) = 0; if (IsUser(cptr) && cli_user(cptr)) { add_history(cptr, 0); off_history(cptr); } if (cli_user(cptr)) { free_user(cli_user(cptr)); cli_user(cptr) = 0; } if (cli_serv(cptr)) { if (cli_serv(cptr)->user) { free_user(cli_serv(cptr)->user); cli_serv(cptr)->user = 0; } if (cli_serv(cptr)->client_list) MyFree(cli_serv(cptr)->client_list); MyFree(cli_serv(cptr)->last_error_msg); MyFree(cli_serv(cptr)); --servs.inuse; --servs.alloc; } free_client(cptr); }
void m_svscloak(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; char *hostname, *target; if(parc < 3 || EmptyString(parv[2])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0]); return; } target = parv[1]; hostname = parv[2]; if ((target_p = find_person(client_p, target))) { if(MyClient(target_p) && irccmp(target_p->host, hostname) != 0) { sendto_one(target_p, ":%s NOTICE %s :Activating Cloak: %s", me.name, target_p->name, hostname); sendto_gnotice_flags(UMODE_ALL, L_ALL, me.name, &me, NULL, "Activating Cloak: %s -> %s for %s", target_p->host, hostname, target_p->name); } /* Send to all Servers but the one WE got the SVSCLOAK from */ sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s SVSCLOAK %s :%s", parv[0], parv[1], parv[2]); /* locally modify the clients structure */ if(target_p->realhost[0] == '\0') strncpy(target_p->realhost, target_p->host, HOSTLEN); if(IsUserHostIp(target_p)) { delete_user_host(target_p->username, target_p->host, !MyConnect(target_p)); add_user_host(target_p->username, hostname, !MyConnect(target_p)); } strncpy(target_p->host, hostname, HOSTLEN); off_history(target_p); } else { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, target); return; } return; }
void m_svscloak(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; char *hostname, *target; user_modes old; if(parc < 3 || EmptyString(parv[2])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0]); return; } target = parv[1]; hostname = parv[2]; if ((target_p= find_person(target))) { if(MyClient(target_p) && irccmp(target_p->virthost, hostname) != 0) { sendto_one(target_p, ":%s NOTICE %s :Activating Cloak: %s", me.name, target_p->name, hostname); } else sendto_server(client_p, NOCAPS, NOCAPS, ":%s SVSCLOAK %s :%s", parv[0], parv[1], parv[2]); strncpy(target_p->virthost, hostname, HOSTLEN); CopyUmodes(old, target_p->umodes); SetUmode(target_p, UMODE_CLOAK); send_umode_out(target_p, target_p, &old); target_p->flags |= FLAGS_USERCLOAK; /* set the usercloak flag so that in the * future, the server will burst the new vhost * in case of netsplit. * --nenolod */ off_history(target_p); } else { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, target); return; } return; }
/* ** 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, const char *comment) { Reg aClient *acptr; Reg int i; Reg Link *lp; invLink *ilp; /* ** For a server or user quitting, propagage the information to ** other servers (except to the one where is came from (cptr)) */ if (IsMe(sptr)) { sendto_flag(SCH_ERROR, "ERROR: tried to exit me! : %s", comment); return; /* ...must *never* exit self!! */ } else if (IsServer(sptr)) { /* ** Old sendto_serv_but_one() call removed because we now ** need to send different names to different servers ** (domain name matching) */ if (!IsMasked(sptr)) { istat.is_serv--; } if (!IsBursting(sptr)) { istat.is_eobservers--; } for (i = fdas.highest; i >= 0; i--) { if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) || acptr == cptr || IsMe(acptr)) { continue; } if (!(sptr->flags & FLAGS_SQUIT)) { /* Make sure we only send the last SQUIT ** to a 2.11. */ continue; } if ((acptr->flags & FLAGS_HIDDEN) && !IsMasked(sptr)) { /* We need a special SQUIT reason, so ** the remote server can send the ** right quit message. */ sendto_one(acptr, ":%s SQUIT %s :%s %s", sptr->serv->up->serv->sid, sptr->serv->sid, sptr->serv->up->name, sptr->name); } else { sendto_one(acptr, ":%s SQUIT %s :%s", sptr->serv->up->serv->sid, sptr->serv->sid, comment); } } #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_SQUIT, sptr->serv, sptr, ":%s SQUIT %s :%s", from->name, sptr->name, comment); #endif del_from_sid_hash_table(sptr->serv); remove_server_from_tree(sptr); /* remove server from svrtop */ unregister_server(sptr); } else if (!IsPerson(sptr) && !IsService(sptr)) { /* ...this test is *dubious*, would need ** some thougth.. but for now it plugs a ** nasty hole in the server... --msa */ ; /* Nothing */ } else if (sptr->name[0] && !IsService(sptr)) /* clean 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) { if ((sptr->flags & FLAGS_SPLIT) == 0) { sendto_serv_butone(cptr, ":%s QUIT :%s", sptr->user->uid, comment); #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_QUIT| SERVICE_WANT_RQUIT, (sptr->user) ? sptr->user->servp : NULL, cptr, ":%s QUIT :%s", sptr->name, comment); #endif } else { if (sptr->flags & FLAGS_HIDDEN) /* joys of hostmasking */ for (i = fdas.highest; i >= 0; i--) { if (!(acptr =local[fdas.fd[i]]) || acptr == cptr || IsMe(acptr)) continue; if (acptr->flags & FLAGS_HIDDEN) sendto_one(acptr, ":%s QUIT :%s", sptr->user->uid, comment); } #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_QUIT, (sptr->user) ? sptr->user->servp : NULL, cptr, ":%s QUIT :%s", sptr->name, comment); #endif } } #ifdef USE_SERVICES else { /* Send QUIT to services which desire such as well. ** Services with both _QUIT and _KILL will get both ** for now --jv */ check_services_butone(SERVICE_WANT_QUIT, (sptr->user) ? sptr->user->servp : NULL, cptr, ":%s QUIT :%s", sptr->name, comment); } #endif /* ** 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) { if (IsInvisible(sptr)) { istat.is_user[1]--; sptr->user->servp->usercnt[1]--; } else { istat.is_user[0]--; sptr->user->servp->usercnt[0]--; } if (IsAnOper(sptr)) { sptr->user->servp->usercnt[2]--; istat.is_oper--; } sendto_common_channels(sptr, ":%s QUIT :%s", sptr->name, comment); if (!(acptr = cptr ? cptr : sptr->from)) acptr = sptr; while ((lp = sptr->user->channel)) { /* ** Mark channels from where remote chop left, ** this will eventually lock the channel. ** close_connection() has already been called, ** it makes MyConnect == False - krys */ if (sptr != cptr) { if (*lp->value.chptr->chname == '!') { if (!(sptr->flags &FLAGS_QUIT)) lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT; } else if ( #ifndef BETTER_CDELAY !(sptr->flags & FLAGS_QUIT) && #endif is_chan_op(sptr, lp->value.chptr)) { lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT; } } if (IsAnonymous(lp->value.chptr) && !IsQuiet(lp->value.chptr)) { sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname); } remove_user_from_channel(sptr,lp->value.chptr); } /* Clean up invitefield */ while ((ilp = sptr->user->invited)) { del_invite(sptr, ilp->chptr); /* again, this is all that is needed */ } /* remove from uid hash table */ if (sptr->user) { del_from_uid_hash_table(sptr->user->uid, sptr); } /* Add user to history */ #ifndef BETTER_NDELAY add_history(sptr, (sptr->flags & FLAGS_QUIT) ? &me : NULL); #else add_history(sptr, (sptr == cptr) ? &me : NULL); #endif off_history(sptr); #ifdef USE_HOSTHASH del_from_hostname_hash_table(sptr->user->host, sptr->user); #endif #ifdef USE_IPHASH del_from_ip_hash_table(sptr->user->sip, sptr->user); #endif } } else if (sptr->name[0] && IsService(sptr)) { /* ** 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) { /* ** A service quitting is annoying, It has to be sent ** to connected servers depending on ** sptr->service->dist */ for (i = fdas.highest; i >= 0; i--) { if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) || acptr == cptr || IsMe(acptr)) { continue; } if (match(sptr->service->dist, acptr->name) && match(sptr->service->dist, acptr->serv->sid)) { continue; } sendto_one(acptr, ":%s QUIT :%s", sptr->name, comment); } } #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL, ":%s QUIT :%s", sptr->name, comment); #endif /* MyConnect(sptr) is always FALSE here */ if (cptr == sptr) { sendto_flag(SCH_NOTICE, "Service %s disconnected", get_client_name(sptr, TRUE)); } sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)", sptr->name, from->name, comment); istat.is_service--; } /* 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_client_from_list(sptr); return; }
/* ** 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); }