/* * users.C: User management. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Rights to this code are documented in doc/pod/license.pod. * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) */ static char const rcsid[] = "$Id: users.C,v 1.7 2007/09/22 14:27:30 pippijn Exp $"; #include "atheme.h" #include #include "servers.h" #include #include #include user_t::map_type user_t::map; typedef std::map uid_map; static uid_map uidlist; user_t::callbacks user_t::callback; /* * init_users() * * Initializes the users heap and DTree. * * Inputs: * - none * * Outputs: * - none * * Side Effects: * - the users heap and DTree are initialized. */ void init_users (void) { #if 0 user_heap = BlockHeapCreate (sizeof (user_t), HEAP_USER); #endif } /* * user_add(char const * const nick, char const * const user, char const * const host, char const * const vhost, char const * const ip, * char const * const uid, char const * const gecos, server_t *server, time_t ts); * * User object factory. * * Inputs: * - nickname of new user * - username of new user * - hostname of new user * - virtual hostname of new user if applicable otherwise NULL * - ip of user if applicable otherwise NULL * - unique identifier (UID) of user if appliable otherwise NULL * - gecos of new user * - pointer to server new user is on * - user's timestamp * * Outputs: * - on success, a new user * - on failure, NULL * * Side Effects: * - if successful, a user is created and added to the users DTree. * * Bugs: * - this function does not check if a user object by this name already exists */ user_t * user_add (char const * const nick, char const * const user, char const * const host, char const * const vhost, char const * const ip, char const * const uid, char const * const gecos, server_t *server, time_t ts) { user_t *u; slog (LG_DEBUG, "user_add(): %s (%s@%s) -> %s", nick, user, host, server->name); u = new user_t; if (uid != NULL) { strlcpy (u->uid, uid, IDLEN); uidlist[u->uid] = u; } strlcpy (u->nick, nick, NICKLEN); strlcpy (u->user, user, USERLEN); strlcpy (u->host, host, HOSTLEN); strlcpy (u->gecos, gecos, GECOSLEN); if (vhost) strlcpy (u->vhost, vhost, HOSTLEN); else strlcpy (u->vhost, host, HOSTLEN); if (ip && strcmp (ip, "0") && strcmp (ip, "0.0.0.0") && strcmp (ip, "255.255.255.255")) strlcpy (u->ip, ip, HOSTIPLEN); u->server = server; u->server->users++; node_add (u, node_create (), &u->server->userlist); if (ts) u->ts = ts; else u->ts = NOW; user_t::map[u->nick] = u; cnt.user++; u->callback.add (u); return u; } /* * user_delete(user_t *u) * * Destroys a user object and deletes the object from the users DTree. * * Inputs: * - user object to delete * * Outputs: * - nothing * * Side Effects: * - on success, a user is deleted from the users DTree. */ void user_delete (user_t *u) { node_t *n, *tn; chanuser_t *cu; mynick_t *mn; if (!u) { slog (LG_DEBUG, "user_delete(): called for NULL user"); return; } slog (LG_DEBUG, "user_delete(): removing user: %s -> %s", u->nick, u->server->name); u->callback.remove (u); u->server->users--; if (is_ircop (u)) u->server->opers--; if (u->flags & UF_INVIS) u->server->invis--; /* remove the user from each channel */ LIST_FOREACH_SAFE (n, tn, u->channels.head) { cu = (chanuser_t *) n->data; chanuser_delete (cu->chan, u); } user_t::map.erase (u->nick); if (*u->uid) uidlist.erase (u->uid); n = node_find (u, &u->server->userlist); node_del (n, &u->server->userlist); node_free (n); if (u->myuser) { u->myuser->logins.erase (u); u->myuser->lastlogin = NOW; if ((mn = mynick_t::find (u->nick)) != NULL && mn->owner == u->myuser) mn->lastseen = NOW; u->myuser = NULL; } delete u; cnt.user--; } /* * user_find(char const * const nick) * * Finds a user by UID or nickname. * * Inputs: * - nickname or UID to look up * * Outputs: * - on success, the user object that was requested * - on failure, NULL * * Side Effects: * - none */ user_t * user_find (char const * const nick) { user_t::map_type::iterator it; uid_map::iterator idit; if (nick == NULL) return NULL; if (ircd->uses_uid == true) { idit = uidlist.find (nick); if (idit != uidlist.end ()) return idit->second; } it = user_t::map.find (nick); if (it != user_t::map.end ()) { if (ircd->uses_p10) wallops (_("user_find(): found user %s by nick!"), nick); return it->second; } return NULL; } /* * user_find_named(char const * const nick) * * Finds a user by nickname. Prevents chasing users by their UID. * * Inputs: * - nickname to look up * * Outputs: * - on success, the user object that was requested * - on failure, NULL * * Side Effects: * - none */ user_t * user_find_named (char const * const nick) { user_t::map_type::iterator it = user_t::map.find (nick); if (it != user_t::map.end ()) return it->second; return NULL; } /* * user_changeuid(user_t *u, char const * const uid) * * Changes a user object's UID. * * Inputs: * - user object to change UID * - new UID * * Outputs: * - nothing * * Side Effects: * - a user object's UID is changed. */ void user_changeuid (user_t *u, char const * const uid) { if (*u->uid) uidlist.erase (u->uid); strlcpy (u->uid, uid ? uid : "", IDLEN); if (*u->uid) uidlist[u->uid] = u; } /* * user_changenick(user_t *u, char const * const uid) * * Changes a user object's nick and TS. * * Inputs: * - user object to change * - new nick * - new TS * * Outputs: * - nothing * * Side Effects: * - a user object's nick and TS is changed. */ void user_changenick (user_t *u, char const * const nick, time_t ts) { mynick_t *mn; if (u->myuser != NULL && (mn = mynick_t::find (u->nick)) != NULL && mn->owner == u->myuser) mn->lastseen = NOW; user_t::map.erase (u->nick); strlcpy (u->nick, nick, NICKLEN); u->ts = ts; user_t::map[u->nick] = u; } /* * user_mode(user_t *user, char *modes) * * Changes a user object's modes. * * Inputs: * - user object to change modes on * - modestring describing the usermode change * * Outputs: * - nothing * * Side Effects: * - on success, a user's modes are adjusted. * * Bugs: * - this routine only tracks +i and +o usermode changes. */ void user_mode (user_t *u, char const * const modes) { int dir = MTYPE_ADD; char const *modestring = modes; if (!u) { slog (LG_DEBUG, "user_mode(): called for nonexistant user"); return; } while (*modestring != '\0') { switch (*modestring) { case '+': dir = MTYPE_ADD; break; case '-': dir = MTYPE_DEL; break; case 'i': if (dir == MTYPE_ADD) { if (!(u->flags & UF_INVIS)) u->server->invis++; u->flags |= UF_INVIS; } else if ((dir = MTYPE_DEL)) { if (u->flags & UF_INVIS) u->server->invis--; u->flags &= ~UF_INVIS; } break; case 'o': if (dir == MTYPE_ADD) { if (!is_ircop (u)) { u->flags |= UF_IRCOP; slog (LG_DEBUG, "user_mode(): %s is now an IRCop", u->nick); snoop ("OPER: %s (%s)", u->nick, u->server->name); u->server->opers++; u->callback.oper (u); } } else if ((dir = MTYPE_DEL)) { if (is_ircop (u)) { u->flags &= ~UF_IRCOP; slog (LG_DEBUG, "user_mode(): %s is no longer an IRCop", u->nick); snoop ("DEOPER: %s (%s)", u->nick, u->server->name); u->server->opers--; u->callback.deoper (u); } } default: break; } modestring++; } }