/** * mychan.C: Registered channels * * 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) */ #include "atheme.h" #include #include #include #include mychan_t::map_type mychan_t::map; mychan_t::callbacks mychan_t::callback; /*************** * M Y C H A N * ***************/ /* private destructor for mychan_t. */ void mychan_t::_destroy () { node_t *n, *tn; return_if_fail (this != NULL); if (!(runflags & RF_STARTING)) slog (LG_DEBUG, "mychan_delete(): %s", name); /* remove the chanacs shiz */ LIST_FOREACH_SAFE (n, tn, chanacs.head) { object_unref (n->data); } /* delete the metadata */ clear_metadata (); mychan_t::map.erase (name); delete this; cnt.mychan--; } mychan_t * mychan_t::create (char const * const name) { mychan_t *mc; return_val_if_fail ((mc = mychan_t::find (name)) == NULL, mc); if (!(runflags & RF_STARTING)) slog (LG_DEBUG, "mychan_t::create(): %s", name); mc = new mychan_t; strlcpy (mc->name, name, CHANNELLEN); mc->registered = NOW; mc->chan = channel_find (name); mychan_t::map[mc->name] = mc; cnt.mychan++; return mc; } mychan_t * mychan_t::find (char const * const name) { mychan_t::map_type::iterator it = mychan_t::map.find (name); if (it == mychan_t::map.end ()) return NULL; return it->second; } /* Check if there is anyone on the channel fulfilling the conditions. * Fairly expensive, but this is sometimes necessary to avoid * inappropriate drops. -- jilles */ bool mychan_t::isused () { node_t *n; channel_t *c; chanuser_t *cu; if (chan == NULL) return false; LIST_FOREACH (n, c->members.head) { cu = static_cast (n->data); if (chanacs_user_flags (this, cu->user) & CA_USEDUPDATE) return true; } return false; } unsigned mychan_t::num_founders () { node_t *n; chanacs_t *ca; int count = 0; LIST_FOREACH (n, chanacs.head) { ca = static_cast (n->data); if (ca->myuser != NULL && ca->level & CA_FOUNDER) count++; } return count; } char const * const mychan_t::founder_names () { node_t *n; chanacs_t *ca; static char names[512]; names[0] = '\0'; LIST_FOREACH (n, chanacs.head) { ca = static_cast (n->data); if (ca->myuser != NULL && ca->level & CA_FOUNDER) { if (names[0] != '\0') strlcat (names, ", ", sizeof names); strlcat (names, ca->myuser->name, sizeof names); } } return names; } /* Find a user fulfilling the conditions who can take another channel */ myuser_t * mychan_t::pick_candidate (unsigned int minlevel, int maxtime) { node_t *n; chanacs_t *ca; myuser_t *mu; LIST_FOREACH (n, chanacs.head) { ca = static_cast (n->data); if (ca->level & CA_AKICK) continue; mu = ca->myuser; if (mu == NULL || ca->level & CA_FOUNDER) continue; if ((ca->level & minlevel) == minlevel && (maxtime == 0 || !mu->logins.empty () || NOW - mu->lastlogin < maxtime)) { if (has_priv_myuser (mu, PRIV_REG_NOLIMIT)) return mu; if (mu->num_channels () < me.maxchans) return mu; } } return NULL; } /* Pick a suitable successor * Note: please do not make this dependent on currently being in * the channel or on IRC; this would give an unfair advantage to * 24*7 clients and bots. * -- jilles */ myuser_t * mychan_t::pick_successor () { myuser_t *mu; /* full privs? */ mu = pick_candidate (CA_FOUNDER_0 & ca_all & ~CA_FOUNDER, 7 * 86400); if (mu != NULL) return mu; mu = pick_candidate (CA_FOUNDER_0 & ca_all & ~CA_FOUNDER, 0); if (mu != NULL) return mu; /* someone with +R then? (old successor has this, but not sop) */ mu = pick_candidate (CA_RECOVER, 7 * 86400); if (mu != NULL) return mu; mu = pick_candidate (CA_RECOVER, 0); if (mu != NULL) return mu; /* an op perhaps? */ mu = pick_candidate (CA_OP, 7 * 86400); if (mu != NULL) return mu; mu = pick_candidate (CA_OP, 0); if (mu != NULL) return mu; /* just an active user with access */ mu = pick_candidate (0, 7 * 86400); if (mu != NULL) return mu; /* ok you can't say we didn't try */ return pick_candidate (0, 0); } // frees memory used by channels on shutdown void mychan_t::cleanup () { #if 0 mychan_t::map_type::iterator it = mychan_t::map.begin (); mychan_t::map_type::iterator et = mychan_t::map.end (); while (it != et) { delete it->second; ++it; } #endif }