mirror of
https://github.com/pissnet/pissircd.git
synced 2025-07-27 05:22:24 +01:00
Move watch code from core to module
This commit is contained in:
parent
15ac841aea
commit
bcbcc10b9d
9 changed files with 463 additions and 346 deletions
|
@ -334,7 +334,6 @@ extern void del_queries(char *);
|
|||
/* Hash stuff */
|
||||
#define NICK_HASH_TABLE_SIZE 32768
|
||||
#define CHAN_HASH_TABLE_SIZE 32768
|
||||
#define WATCH_HASH_TABLE_SIZE 32768
|
||||
#define WHOWAS_HASH_TABLE_SIZE 32768
|
||||
#define THROTTLING_HASH_TABLE_SIZE 8192
|
||||
#define hash_find_channel find_channel
|
||||
|
@ -350,12 +349,6 @@ extern int add_to_id_hash_table(char *, Client *);
|
|||
extern int del_from_id_hash_table(char *, Client *);
|
||||
extern int add_to_channel_hash_table(char *, Channel *);
|
||||
extern void del_from_channel_hash_table(char *, Channel *);
|
||||
extern int add_to_watch_hash_table(char *, Client *, int);
|
||||
extern int del_from_watch_hash_table(char *, Client *);
|
||||
extern int hash_check_watch(Client *, int);
|
||||
extern int hash_del_watch_list(Client *);
|
||||
extern void count_watch_memory(int *, u_long *);
|
||||
extern Watch *hash_get_watch(char *);
|
||||
extern Channel *hash_get_chan_bucket(uint64_t);
|
||||
extern Client *hash_find_client(const char *, Client *);
|
||||
extern Client *hash_find_id(const char *, Client *);
|
||||
|
|
|
@ -1165,6 +1165,10 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, char *varshortname, long va
|
|||
#define HOOKTYPE_CONNECT_EXTINFO 104
|
||||
/** See hooktype_is_invited() */
|
||||
#define HOOKTYPE_IS_INVITED 105
|
||||
/** See hooktype_post_local_nickchange() */
|
||||
#define HOOKTYPE_POST_LOCAL_NICKCHANGE 106
|
||||
/** See hooktype_post_remote_nickchange() */
|
||||
#define HOOKTYPE_POST_REMOTE_NICKCHANGE 107
|
||||
/* Adding a new hook here?
|
||||
* 1) Add the #define HOOKTYPE_.... with a new number
|
||||
* 2) Add a hook prototype (see below)
|
||||
|
@ -1523,9 +1527,10 @@ int hooktype_modechar_add(Channel *channel, int modechar);
|
|||
* @param client The client
|
||||
* @param mtags Message tags associated with the event
|
||||
* @param reason The away reason, or NULL if away is unset.
|
||||
* @param already_as_away Set to 1 if the user only changed their away reason.
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_away(Client *client, MessageTag *mtags, char *reason);
|
||||
int hooktype_away(Client *client, MessageTag *mtags, char *reason, int already_as_away);
|
||||
|
||||
/** Called when a user wants to invite another user to a channel (function prototype for HOOKTYPE_PRE_INVITE).
|
||||
* @param client The client
|
||||
|
@ -2115,6 +2120,20 @@ int hooktype_connect_extinfo(Client *client, NameValuePrioList **list);
|
|||
*/
|
||||
int hooktype_is_invited(Client *client, Channel *channel, int *invited);
|
||||
|
||||
/** Called after a local user has changed the nick name (function prototype for HOOKTYPE_POST_LOCAL_NICKCHANGE).
|
||||
* @param client The client
|
||||
* @param mtags Message tags associated with the event
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_post_local_nickchange(Client *client, MessageTag *mtags);
|
||||
|
||||
/** Called after a remote user has changed the nick name (function prototype for HOOKTYPE_POST_REMOTE_NICKCHANGE).
|
||||
* @param client The client
|
||||
* @param mtags Message tags associated with the event
|
||||
* @return The return value is ignored (use return 0)
|
||||
*/
|
||||
int hooktype_post_remote_nickchange(Client *client, MessageTag *mtags);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef GCC_TYPECHECKING
|
||||
|
@ -2225,7 +2244,9 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
|
|||
((hooktype == HOOKTYPE_ACCOUNT_LOGIN) && !ValidateHook(hooktype_account_login, func)) || \
|
||||
((hooktype == HOOKTYPE_CLOSE_CONNECTION) && !ValidateHook(hooktype_close_connection, func)) || \
|
||||
((hooktype == HOOKTYPE_CONNECT_EXTINFO) && !ValidateHook(hooktype_connect_extinfo, func)) || \
|
||||
((hooktype == HOOKTYPE_IS_INVITED) && !ValidateHook(hooktype_is_invited, func)) ) \
|
||||
((hooktype == HOOKTYPE_IS_INVITED) && !ValidateHook(hooktype_is_invited, func)) || \
|
||||
((hooktype == HOOKTYPE_POST_LOCAL_NICKCHANGE) && !ValidateHook(hooktype_post_local_nickchange, func)) || \
|
||||
((hooktype == HOOKTYPE_POST_REMOTE_NICKCHANGE) && !ValidateHook(hooktype_post_remote_nickchange, func)) ) \
|
||||
_hook_error_incompatible();
|
||||
#endif /* GCC_TYPECHECKING */
|
||||
|
||||
|
|
|
@ -1323,8 +1323,6 @@ struct LocalClient {
|
|||
u_short sendB; /**< Statistics: counters to count upto 1-k lots of bytes */
|
||||
u_short receiveB; /**< Statistics: sent and received (???) */
|
||||
short lastsq; /**< # of 2k blocks when sendqueued called last */
|
||||
Link *watch; /**< Watch notification list (WATCH) for this user */
|
||||
u_short watches; /**< Number of entries in the watch list */
|
||||
ModData moddata[MODDATA_MAX_LOCAL_CLIENT]; /**< LocalClient attached module data, used by the ModData system */
|
||||
#ifdef DEBUGMODE
|
||||
time_t cputime; /**< Something with debugging (why is this a time_t? TODO) */
|
||||
|
|
306
src/hash.c
306
src/hash.c
|
@ -260,11 +260,9 @@ void siphash_generate_key(char *k)
|
|||
static struct list_head clientTable[NICK_HASH_TABLE_SIZE];
|
||||
static struct list_head idTable[NICK_HASH_TABLE_SIZE];
|
||||
static Channel *channelTable[CHAN_HASH_TABLE_SIZE];
|
||||
static Watch *watchTable[WATCH_HASH_TABLE_SIZE];
|
||||
|
||||
static char siphashkey_nick[SIPHASH_KEY_LENGTH];
|
||||
static char siphashkey_chan[SIPHASH_KEY_LENGTH];
|
||||
static char siphashkey_watch[SIPHASH_KEY_LENGTH];
|
||||
static char siphashkey_whowas[SIPHASH_KEY_LENGTH];
|
||||
static char siphashkey_throttling[SIPHASH_KEY_LENGTH];
|
||||
|
||||
|
@ -277,7 +275,6 @@ void init_hash(void)
|
|||
|
||||
siphash_generate_key(siphashkey_nick);
|
||||
siphash_generate_key(siphashkey_chan);
|
||||
siphash_generate_key(siphashkey_watch);
|
||||
siphash_generate_key(siphashkey_whowas);
|
||||
siphash_generate_key(siphashkey_throttling);
|
||||
|
||||
|
@ -288,7 +285,6 @@ void init_hash(void)
|
|||
INIT_LIST_HEAD(&idTable[i]);
|
||||
|
||||
memset(channelTable, 0, sizeof(channelTable));
|
||||
memset(watchTable, 0, sizeof(watchTable));
|
||||
|
||||
memset(ThrottlingHash, 0, sizeof(ThrottlingHash));
|
||||
/* do not call init_throttling() here, as
|
||||
|
@ -310,11 +306,6 @@ uint64_t hash_channel_name(const char *name)
|
|||
return siphash_nocase(name, siphashkey_chan) % CHAN_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
uint64_t hash_watch_nick_name(const char *name)
|
||||
{
|
||||
return siphash_nocase(name, siphashkey_watch) % WATCH_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
uint64_t hash_whowas_name(const char *name)
|
||||
{
|
||||
return siphash_nocase(name, siphashkey_whowas) % WHOWAS_HASH_TABLE_SIZE;
|
||||
|
@ -599,303 +590,6 @@ Channel *hash_get_chan_bucket(uint64_t hashv)
|
|||
return channelTable[hashv];
|
||||
}
|
||||
|
||||
void count_watch_memory(int *count, u_long *memory)
|
||||
{
|
||||
int i = WATCH_HASH_TABLE_SIZE;
|
||||
Watch *anptr;
|
||||
|
||||
while (i--)
|
||||
{
|
||||
anptr = watchTable[i];
|
||||
while (anptr)
|
||||
{
|
||||
(*count)++;
|
||||
(*memory) += sizeof(Watch)+strlen(anptr->nick);
|
||||
anptr = anptr->hnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* add_to_watch_hash_table
|
||||
*/
|
||||
int add_to_watch_hash_table(char *nick, Client *client, int awaynotify)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
Link *lp;
|
||||
|
||||
|
||||
/* Get the right bucket... */
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
/* Find the right nick (header) in the bucket, or NULL... */
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, nick))
|
||||
anptr = anptr->hnext;
|
||||
|
||||
/* If found NULL (no header for this nick), make one... */
|
||||
if (!anptr) {
|
||||
anptr = (Watch *)safe_alloc(sizeof(Watch)+strlen(nick));
|
||||
anptr->lasttime = timeofday;
|
||||
strcpy(anptr->nick, nick);
|
||||
|
||||
anptr->watch = NULL;
|
||||
|
||||
anptr->hnext = watchTable[hashv];
|
||||
watchTable[hashv] = anptr;
|
||||
}
|
||||
/* Is this client already on the watch-list? */
|
||||
if ((lp = anptr->watch))
|
||||
while (lp && (lp->value.client != client))
|
||||
lp = lp->next;
|
||||
|
||||
/* No it isn't, so add it in the bucket and client addint it */
|
||||
if (!lp) {
|
||||
lp = anptr->watch;
|
||||
anptr->watch = make_link();
|
||||
anptr->watch->value.client = client;
|
||||
anptr->watch->flags = awaynotify;
|
||||
anptr->watch->next = lp;
|
||||
|
||||
lp = make_link();
|
||||
lp->next = client->local->watch;
|
||||
lp->value.wptr = anptr;
|
||||
lp->flags = awaynotify;
|
||||
client->local->watch = lp;
|
||||
client->local->watches++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_check_watch
|
||||
*/
|
||||
int hash_check_watch(Client *client, int reply)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
Link *lp;
|
||||
int awaynotify = 0;
|
||||
|
||||
if ((reply == RPL_GONEAWAY) || (reply == RPL_NOTAWAY) || (reply == RPL_REAWAY))
|
||||
awaynotify = 1;
|
||||
|
||||
/* Get us the right bucket */
|
||||
hashv = hash_watch_nick_name(client->name);
|
||||
|
||||
/* Find the right header in this bucket */
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, client->name))
|
||||
anptr = anptr->hnext;
|
||||
if (!anptr)
|
||||
return 0; /* This nick isn't on watch */
|
||||
|
||||
/* Update the time of last change to item */
|
||||
anptr->lasttime = TStime();
|
||||
|
||||
/* Send notifies out to everybody on the list in header */
|
||||
for (lp = anptr->watch; lp; lp = lp->next)
|
||||
{
|
||||
if (!awaynotify)
|
||||
{
|
||||
sendnumeric(lp->value.client, reply,
|
||||
client->name,
|
||||
(IsUser(client) ? client->user->username : "<N/A>"),
|
||||
(IsUser(client) ?
|
||||
(IsHidden(client) ? client->user->virthost : client->
|
||||
user->realhost) : "<N/A>"), anptr->lasttime, client->info);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* AWAY or UNAWAY */
|
||||
if (!lp->flags)
|
||||
continue; /* skip away/unaway notification for users not interested in them */
|
||||
|
||||
if (reply == RPL_NOTAWAY)
|
||||
sendnumeric(lp->value.client, reply,
|
||||
client->name,
|
||||
(IsUser(client) ? client->user->username : "<N/A>"),
|
||||
(IsUser(client) ?
|
||||
(IsHidden(client) ? client->user->virthost : client->
|
||||
user->realhost) : "<N/A>"), client->user->lastaway);
|
||||
else /* RPL_GONEAWAY / RPL_REAWAY */
|
||||
sendnumeric(lp->value.client, reply,
|
||||
client->name,
|
||||
(IsUser(client) ? client->user->username : "<N/A>"),
|
||||
(IsUser(client) ?
|
||||
(IsHidden(client) ? client->user->virthost : client->
|
||||
user->realhost) : "<N/A>"), client->user->lastaway, client->user->away);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_get_watch
|
||||
*/
|
||||
Watch *hash_get_watch(char *nick)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, nick))
|
||||
anptr = anptr->hnext;
|
||||
|
||||
return anptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* del_from_watch_hash_table
|
||||
*/
|
||||
int del_from_watch_hash_table(char *nick, Client *client)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr, *nlast = NULL;
|
||||
Link *lp, *last = NULL;
|
||||
|
||||
/* Get the bucket for this nick... */
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
/* Find the right header, maintaining last-link pointer... */
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, nick)) {
|
||||
nlast = anptr;
|
||||
anptr = anptr->hnext;
|
||||
}
|
||||
if (!anptr)
|
||||
return 0; /* No such watch */
|
||||
|
||||
/* Find this client from the list of notifies... with last-ptr. */
|
||||
if ((lp = anptr->watch))
|
||||
while (lp && (lp->value.client != client)) {
|
||||
last = lp;
|
||||
lp = lp->next;
|
||||
}
|
||||
if (!lp)
|
||||
return 0; /* No such client to watch */
|
||||
|
||||
/* Fix the linked list under header, then remove the watch entry */
|
||||
if (!last)
|
||||
anptr->watch = lp->next;
|
||||
else
|
||||
last->next = lp->next;
|
||||
free_link(lp);
|
||||
|
||||
/* Do the same regarding the links in client-record... */
|
||||
last = NULL;
|
||||
if ((lp = client->local->watch))
|
||||
while (lp && (lp->value.wptr != anptr)) {
|
||||
last = lp;
|
||||
lp = lp->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give error on the odd case... probobly not even neccessary
|
||||
* No error checking in ircd is unneccessary ;) -Cabal95
|
||||
*/
|
||||
if (!lp)
|
||||
sendto_ops("WATCH debug error: del_from_watch_hash_table "
|
||||
"found a watch entry with no client "
|
||||
"counterpoint processing nick %s on client %p!",
|
||||
nick, client->user);
|
||||
else {
|
||||
if (!last) /* First one matched */
|
||||
client->local->watch = lp->next;
|
||||
else
|
||||
last->next = lp->next;
|
||||
free_link(lp);
|
||||
}
|
||||
/* In case this header is now empty of notices, remove it */
|
||||
if (!anptr->watch) {
|
||||
if (!nlast)
|
||||
watchTable[hashv] = anptr->hnext;
|
||||
else
|
||||
nlast->hnext = anptr->hnext;
|
||||
safe_free(anptr);
|
||||
}
|
||||
|
||||
/* Update count of notifies on nick */
|
||||
client->local->watches--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_del_watch_list
|
||||
*/
|
||||
int hash_del_watch_list(Client *client)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
Link *np, *lp, *last;
|
||||
|
||||
|
||||
if (!(np = client->local->watch))
|
||||
return 0; /* Nothing to do */
|
||||
|
||||
client->local->watch = NULL; /* Break the watch-list for client */
|
||||
while (np) {
|
||||
/* Find the watch-record from hash-table... */
|
||||
anptr = np->value.wptr;
|
||||
last = NULL;
|
||||
for (lp = anptr->watch; lp && (lp->value.client != client);
|
||||
lp = lp->next)
|
||||
last = lp;
|
||||
|
||||
/* Not found, another "worst case" debug error */
|
||||
if (!lp)
|
||||
sendto_ops("WATCH Debug error: hash_del_watch_list "
|
||||
"found a WATCH entry with no table "
|
||||
"counterpoint processing client %s!",
|
||||
client->name);
|
||||
else {
|
||||
/* Fix the watch-list and remove entry */
|
||||
if (!last)
|
||||
anptr->watch = lp->next;
|
||||
else
|
||||
last->next = lp->next;
|
||||
free_link(lp);
|
||||
|
||||
/*
|
||||
* If this leaves a header without notifies,
|
||||
* remove it. Need to find the last-pointer!
|
||||
*/
|
||||
if (!anptr->watch) {
|
||||
Watch *np2, *nl;
|
||||
|
||||
hashv = hash_watch_nick_name(anptr->nick);
|
||||
|
||||
nl = NULL;
|
||||
np2 = watchTable[hashv];
|
||||
while (np2 != anptr) {
|
||||
nl = np2;
|
||||
np2 = np2->hnext;
|
||||
}
|
||||
|
||||
if (nl)
|
||||
nl->hnext = anptr->hnext;
|
||||
else
|
||||
watchTable[hashv] = anptr->hnext;
|
||||
safe_free(anptr);
|
||||
}
|
||||
}
|
||||
|
||||
lp = np; /* Save last pointer processed */
|
||||
np = np->next; /* Jump to the next pointer */
|
||||
free_link(lp); /* Free the previous */
|
||||
}
|
||||
|
||||
client->local->watches = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Throttling - originally by Stskeeps */
|
||||
|
||||
/* Note that we call this set::anti-flood::connect-flood nowadays */
|
||||
|
|
|
@ -544,8 +544,6 @@ static void exit_one_client(Client *client, MessageTag *mtags_i, const char *com
|
|||
}
|
||||
if (*client->name)
|
||||
del_from_client_hash_table(client->name, client);
|
||||
if (IsUser(client))
|
||||
hash_check_watch(client, RPL_LOGOFF);
|
||||
if (remote_rehash_client == client)
|
||||
remote_rehash_client = NULL; /* client did a /REHASH and QUIT before rehash was complete */
|
||||
remove_client_from_list(client);
|
||||
|
@ -630,8 +628,6 @@ void exit_client_ex(Client *client, Client *origin, MessageTag *recv_mtags, char
|
|||
{
|
||||
RunHook3(HOOKTYPE_LOCAL_QUIT, client, recv_mtags, comment);
|
||||
sendto_connectnotice(client, 1, comment);
|
||||
/* Clean out list and watch structures -Donwulff */
|
||||
hash_del_watch_list(client);
|
||||
on_for = TStime() - client->local->firsttime;
|
||||
if (IsHidden(client))
|
||||
ircd_log(LOG_CLIENT, "Disconnect - (%lld:%lld:%lld) %s!%s@%s [%s] [vhost: %s] (%s)",
|
||||
|
|
|
@ -73,10 +73,9 @@ CMD_FUNC(cmd_away)
|
|||
|
||||
new_message(client, recv_mtags, &mtags);
|
||||
sendto_server(client, 0, 0, mtags, ":%s AWAY", client->name);
|
||||
hash_check_watch(client, RPL_NOTAWAY);
|
||||
sendto_local_common_channels(client, client, ClientCapabilityBit("away-notify"), mtags,
|
||||
":%s AWAY", client->name);
|
||||
RunHook3(HOOKTYPE_AWAY, client, mtags, NULL);
|
||||
RunHook4(HOOKTYPE_AWAY, client, mtags, NULL, 0);
|
||||
free_message_tags(mtags);
|
||||
}
|
||||
|
||||
|
@ -125,13 +124,11 @@ CMD_FUNC(cmd_away)
|
|||
if (MyConnect(client))
|
||||
sendnumeric(client, RPL_NOWAWAY);
|
||||
|
||||
hash_check_watch(client, already_as_away ? RPL_REAWAY : RPL_GONEAWAY);
|
||||
|
||||
sendto_local_common_channels(client, client,
|
||||
ClientCapabilityBit("away-notify"), mtags,
|
||||
":%s AWAY :%s", client->name, client->user->away);
|
||||
|
||||
RunHook3(HOOKTYPE_AWAY, client, mtags, client->user->away);
|
||||
RunHook4(HOOKTYPE_AWAY, client, mtags, client->user->away, already_as_away);
|
||||
|
||||
free_message_tags(mtags);
|
||||
|
||||
|
|
|
@ -227,12 +227,11 @@ CMD_FUNC(cmd_nick_remote)
|
|||
|
||||
/* Finally set new nick name. */
|
||||
del_from_client_hash_table(client->name, client);
|
||||
hash_check_watch(client, RPL_LOGOFF);
|
||||
|
||||
strcpy(client->name, nick);
|
||||
add_to_client_hash_table(nick, client);
|
||||
|
||||
hash_check_watch(client, RPL_LOGON);
|
||||
RunHook2(HOOKTYPE_POST_REMOTE_NICKCHANGE, client, mtags);
|
||||
}
|
||||
|
||||
CMD_FUNC(cmd_nick_local)
|
||||
|
@ -243,7 +242,8 @@ CMD_FUNC(cmd_nick_local)
|
|||
char nick[NICKLEN + 2], descbuf[BUFSIZE];
|
||||
Membership *mp;
|
||||
long lastnick = 0l;
|
||||
int differ = 1, update_watch = 1;
|
||||
int differ = 1;
|
||||
int newuser = 0;
|
||||
unsigned char removemoder = (client->umodes & UMODE_REGNICK) ? 1 : 0;
|
||||
Hook *h;
|
||||
int i = 0;
|
||||
|
@ -353,6 +353,8 @@ CMD_FUNC(cmd_nick_local)
|
|||
/* New local client? */
|
||||
if (!client->name[0])
|
||||
{
|
||||
newuser = 1;
|
||||
|
||||
if (iConf.ping_cookie)
|
||||
{
|
||||
/*
|
||||
|
@ -389,7 +391,6 @@ CMD_FUNC(cmd_nick_local)
|
|||
*/
|
||||
} else {
|
||||
/* New user! */
|
||||
update_watch = 0; /* already done in register_user() */
|
||||
strlcpy(nick, client->name, sizeof(nick)); /* don't ask, but I need this. do not remove! -- Syzop */
|
||||
}
|
||||
}
|
||||
|
@ -456,8 +457,6 @@ CMD_FUNC(cmd_nick_local)
|
|||
}
|
||||
|
||||
del_from_client_hash_table(client->name, client);
|
||||
if (update_watch && IsUser(client))
|
||||
hash_check_watch(client, RPL_LOGOFF);
|
||||
|
||||
strlcpy(client->name, nick, sizeof(client->name));
|
||||
add_to_client_hash_table(nick, client);
|
||||
|
@ -466,11 +465,11 @@ CMD_FUNC(cmd_nick_local)
|
|||
snprintf(descbuf, sizeof(descbuf), "Client: %s", nick);
|
||||
fd_desc(client->local->fd, descbuf);
|
||||
|
||||
if (update_watch && IsUser(client))
|
||||
hash_check_watch(client, RPL_LOGON);
|
||||
|
||||
if (removemoder && MyUser(client))
|
||||
sendto_one(client, NULL, ":%s MODE %s :-r", me.name, client->name);
|
||||
|
||||
if (MyUser(client) && !newuser)
|
||||
RunHook2(HOOKTYPE_POST_LOCAL_NICKCHANGE, client, recv_mtags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1106,7 +1105,6 @@ int _register_user(Client *client, char *nick, char *username, char *umode, char
|
|||
safe_strdup(client->user->virthost, virthost);
|
||||
}
|
||||
|
||||
hash_check_watch(client, RPL_LOGON); /* Uglier hack */
|
||||
build_umode_string(client, 0, SEND_UMODES|UMODE_SERVNOTICE, buf);
|
||||
|
||||
sendto_serv_butone_nickcmd(client->direction, client, (*buf == '\0' ? "+" : buf));
|
||||
|
|
|
@ -103,7 +103,6 @@ CMD_FUNC(cmd_svsnick)
|
|||
|
||||
add_history(acptr, 1);
|
||||
del_from_client_hash_table(acptr->name, acptr);
|
||||
hash_check_watch(acptr, RPL_LOGOFF);
|
||||
|
||||
sendto_snomask(SNO_NICKCHANGE,
|
||||
"*** %s (%s@%s) has been forced to change their nickname to %s",
|
||||
|
@ -111,5 +110,5 @@ CMD_FUNC(cmd_svsnick)
|
|||
|
||||
strlcpy(acptr->name, parv[2], sizeof acptr->name);
|
||||
add_to_client_hash_table(parv[2], acptr);
|
||||
hash_check_watch(acptr, RPL_LOGON);
|
||||
RunHook2(HOOKTYPE_POST_LOCAL_NICKCHANGE, acptr, mtags);
|
||||
}
|
||||
|
|
|
@ -22,9 +22,34 @@
|
|||
|
||||
#include "unrealircd.h"
|
||||
|
||||
CMD_FUNC(cmd_watch);
|
||||
#define MSG_WATCH "WATCH"
|
||||
#define WATCH_HASH_TABLE_SIZE 32768
|
||||
|
||||
#define MSG_WATCH "WATCH"
|
||||
#define WATCHES(client) (moddata_local_client(client, watchCounterMD).i)
|
||||
#define WATCH(client) (moddata_local_client(client, watchListMD).ptr)
|
||||
|
||||
ModDataInfo *watchCounterMD;
|
||||
ModDataInfo *watchListMD;
|
||||
static Watch *watchTable[WATCH_HASH_TABLE_SIZE];
|
||||
static int watch_initialized = 0;
|
||||
static char siphashkey_watch[SIPHASH_KEY_LENGTH];
|
||||
|
||||
CMD_FUNC(cmd_watch);
|
||||
void dummy_free(ModData *md);
|
||||
void watch_free(ModData *md);
|
||||
int watch_user_quit(Client *client, MessageTag *mtags, char *comment);
|
||||
int watch_away(Client *client, MessageTag *mtags, char *reason, int already_as_away);
|
||||
int watch_nickchange(Client *client, MessageTag *mtags, char *newnick);
|
||||
int watch_post_nickchange(Client *client, MessageTag *mtags);
|
||||
int watch_user_connect(Client *client);
|
||||
|
||||
int add_to_watch_hash_table(char *nick, Client *client, int awaynotify);
|
||||
int hash_check_watch(Client *client, int reply);
|
||||
Watch *hash_get_watch(char *nick);
|
||||
int del_from_watch_hash_table(char *nick, Client *client);
|
||||
int hash_del_watch_list(Client *client);
|
||||
uint64_t hash_watch_nick_name(const char *name);
|
||||
void count_watch_memory(int *count, u_long *memory);
|
||||
|
||||
ModuleHeader MOD_HEADER
|
||||
= {
|
||||
|
@ -36,9 +61,51 @@ ModuleHeader MOD_HEADER
|
|||
};
|
||||
|
||||
MOD_INIT()
|
||||
{
|
||||
CommandAdd(modinfo->handle, MSG_WATCH, cmd_watch, 1, CMD_USER);
|
||||
{
|
||||
ModDataInfo mreq;
|
||||
|
||||
MARK_AS_OFFICIAL_MODULE(modinfo);
|
||||
|
||||
if (!watch_initialized)
|
||||
{
|
||||
memset(watchTable, 0, sizeof(watchTable));
|
||||
siphash_generate_key(siphashkey_watch);
|
||||
watch_initialized = 1;
|
||||
}
|
||||
|
||||
CommandAdd(modinfo->handle, MSG_WATCH, cmd_watch, 1, CMD_USER);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, watch_user_quit);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_REMOTE_QUIT, 0, watch_user_quit);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_AWAY, 0, watch_away);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_LOCAL_NICKCHANGE, 0, watch_nickchange);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_REMOTE_NICKCHANGE, 0, watch_nickchange);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_POST_LOCAL_NICKCHANGE, 0, watch_post_nickchange);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_POST_REMOTE_NICKCHANGE, 0, watch_post_nickchange);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, watch_user_connect);
|
||||
HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, 0, watch_user_connect);
|
||||
|
||||
memset(&mreq, 0 , sizeof(mreq));
|
||||
mreq.type = MODDATATYPE_LOCAL_CLIENT;
|
||||
mreq.name = "watchCount",
|
||||
mreq.free = dummy_free;
|
||||
watchCounterMD = ModDataAdd(modinfo->handle, mreq);
|
||||
if (!watchCounterMD)
|
||||
{
|
||||
config_error("[%s] Failed to request user watchCount moddata: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
memset(&mreq, 0 , sizeof(mreq));
|
||||
mreq.type = MODDATATYPE_LOCAL_CLIENT;
|
||||
mreq.name = "watchList",
|
||||
mreq.free = watch_free;
|
||||
watchListMD = ModDataAdd(modinfo->handle, mreq);
|
||||
if (!watchListMD)
|
||||
{
|
||||
config_error("[%s] Failed to request user watchList moddata: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
|
||||
return MOD_FAILED;
|
||||
}
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -52,6 +119,14 @@ MOD_UNLOAD()
|
|||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
void dummy_free(ModData *md)
|
||||
{
|
||||
}
|
||||
|
||||
void watch_free(ModData *md)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* RPL_NOWON - Online at the moment (Successfully added to WATCH-list)
|
||||
* RPL_NOWOFF - Offline at the moement (Successfully added to WATCH-list)
|
||||
|
@ -127,7 +202,7 @@ CMD_FUNC(cmd_watch)
|
|||
continue;
|
||||
if (do_nick_name(s + 1))
|
||||
{
|
||||
if (client->local->watches >= MAXWATCH)
|
||||
if (WATCHES(client) >= MAXWATCH)
|
||||
{
|
||||
sendnumeric(client, ERR_TOOMANYWATCH, s + 1);
|
||||
continue;
|
||||
|
@ -187,13 +262,13 @@ CMD_FUNC(cmd_watch)
|
|||
for (lp = anptr->watch, count = 1;
|
||||
(lp = lp->next); count++)
|
||||
;
|
||||
sendnumeric(client, RPL_WATCHSTAT, client->local->watches, count);
|
||||
sendnumeric(client, RPL_WATCHSTAT, WATCHES(client), count);
|
||||
|
||||
/*
|
||||
* Send a list of everybody in their WATCH list. Be careful
|
||||
* not to buffer overflow.
|
||||
*/
|
||||
if ((lp = client->local->watch) == NULL)
|
||||
if ((lp = WATCH(client)) == NULL)
|
||||
{
|
||||
sendnumeric(client, RPL_ENDOFWATCHLIST, *s);
|
||||
continue;
|
||||
|
@ -229,7 +304,7 @@ CMD_FUNC(cmd_watch)
|
|||
*/
|
||||
if ((*s == 'L' || *s == 'l') && !did_l)
|
||||
{
|
||||
Link *lp = client->local->watch;
|
||||
Link *lp = WATCH(client);
|
||||
|
||||
did_l = 1;
|
||||
|
||||
|
@ -264,3 +339,349 @@ CMD_FUNC(cmd_watch)
|
|||
*/
|
||||
}
|
||||
}
|
||||
|
||||
int watch_user_quit(Client *client, MessageTag *mtags, char *comment)
|
||||
{
|
||||
if (IsUser(client))
|
||||
hash_check_watch(client, RPL_LOGOFF);
|
||||
|
||||
if (MyConnect(client))
|
||||
/* Clean out list and watch structures -Donwulff */
|
||||
hash_del_watch_list(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int watch_away(Client *client, MessageTag *mtags, char *reason, int already_as_away)
|
||||
{
|
||||
if (reason)
|
||||
hash_check_watch(client, already_as_away ? RPL_REAWAY : RPL_GONEAWAY);
|
||||
else
|
||||
hash_check_watch(client, RPL_NOTAWAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int watch_nickchange(Client *client, MessageTag *mtags, char *newnick)
|
||||
{
|
||||
hash_check_watch(client, RPL_LOGOFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int watch_post_nickchange(Client *client, MessageTag *mtags)
|
||||
{
|
||||
hash_check_watch(client, RPL_LOGON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int watch_user_connect(Client *client)
|
||||
{
|
||||
hash_check_watch(client, RPL_LOGON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* add_to_watch_hash_table
|
||||
*/
|
||||
int add_to_watch_hash_table(char *nick, Client *client, int awaynotify)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
Link *lp;
|
||||
|
||||
|
||||
/* Get the right bucket... */
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
/* Find the right nick (header) in the bucket, or NULL... */
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, nick))
|
||||
anptr = anptr->hnext;
|
||||
|
||||
/* If found NULL (no header for this nick), make one... */
|
||||
if (!anptr) {
|
||||
anptr = (Watch *)safe_alloc(sizeof(Watch)+strlen(nick));
|
||||
anptr->lasttime = timeofday;
|
||||
strcpy(anptr->nick, nick);
|
||||
|
||||
anptr->watch = NULL;
|
||||
|
||||
anptr->hnext = watchTable[hashv];
|
||||
watchTable[hashv] = anptr;
|
||||
}
|
||||
/* Is this client already on the watch-list? */
|
||||
if ((lp = anptr->watch))
|
||||
while (lp && (lp->value.client != client))
|
||||
lp = lp->next;
|
||||
|
||||
/* No it isn't, so add it in the bucket and client addint it */
|
||||
if (!lp) {
|
||||
lp = anptr->watch;
|
||||
anptr->watch = make_link();
|
||||
anptr->watch->value.client = client;
|
||||
anptr->watch->flags = awaynotify;
|
||||
anptr->watch->next = lp;
|
||||
|
||||
lp = make_link();
|
||||
lp->next = WATCH(client);
|
||||
lp->value.wptr = anptr;
|
||||
lp->flags = awaynotify;
|
||||
WATCH(client) = lp;
|
||||
WATCHES(client)++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_check_watch
|
||||
*/
|
||||
int hash_check_watch(Client *client, int reply)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
Link *lp;
|
||||
int awaynotify = 0;
|
||||
|
||||
if ((reply == RPL_GONEAWAY) || (reply == RPL_NOTAWAY) || (reply == RPL_REAWAY))
|
||||
awaynotify = 1;
|
||||
|
||||
/* Get us the right bucket */
|
||||
hashv = hash_watch_nick_name(client->name);
|
||||
|
||||
/* Find the right header in this bucket */
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, client->name))
|
||||
anptr = anptr->hnext;
|
||||
if (!anptr)
|
||||
return 0; /* This nick isn't on watch */
|
||||
|
||||
/* Update the time of last change to item */
|
||||
anptr->lasttime = TStime();
|
||||
|
||||
/* Send notifies out to everybody on the list in header */
|
||||
for (lp = anptr->watch; lp; lp = lp->next)
|
||||
{
|
||||
if (!awaynotify)
|
||||
{
|
||||
sendnumeric(lp->value.client, reply,
|
||||
client->name,
|
||||
(IsUser(client) ? client->user->username : "<N/A>"),
|
||||
(IsUser(client) ?
|
||||
(IsHidden(client) ? client->user->virthost : client->
|
||||
user->realhost) : "<N/A>"), anptr->lasttime, client->info);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* AWAY or UNAWAY */
|
||||
if (!lp->flags)
|
||||
continue; /* skip away/unaway notification for users not interested in them */
|
||||
|
||||
if (reply == RPL_NOTAWAY)
|
||||
sendnumeric(lp->value.client, reply,
|
||||
client->name,
|
||||
(IsUser(client) ? client->user->username : "<N/A>"),
|
||||
(IsUser(client) ?
|
||||
(IsHidden(client) ? client->user->virthost : client->
|
||||
user->realhost) : "<N/A>"), client->user->lastaway);
|
||||
else /* RPL_GONEAWAY / RPL_REAWAY */
|
||||
sendnumeric(lp->value.client, reply,
|
||||
client->name,
|
||||
(IsUser(client) ? client->user->username : "<N/A>"),
|
||||
(IsUser(client) ?
|
||||
(IsHidden(client) ? client->user->virthost : client->
|
||||
user->realhost) : "<N/A>"), client->user->lastaway, client->user->away);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_get_watch
|
||||
*/
|
||||
Watch *hash_get_watch(char *nick)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, nick))
|
||||
anptr = anptr->hnext;
|
||||
|
||||
return anptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* del_from_watch_hash_table
|
||||
*/
|
||||
int del_from_watch_hash_table(char *nick, Client *client)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr, *nlast = NULL;
|
||||
Link *lp, *last = NULL;
|
||||
|
||||
/* Get the bucket for this nick... */
|
||||
hashv = hash_watch_nick_name(nick);
|
||||
|
||||
/* Find the right header, maintaining last-link pointer... */
|
||||
if ((anptr = (Watch *)watchTable[hashv]))
|
||||
while (anptr && mycmp(anptr->nick, nick)) {
|
||||
nlast = anptr;
|
||||
anptr = anptr->hnext;
|
||||
}
|
||||
if (!anptr)
|
||||
return 0; /* No such watch */
|
||||
|
||||
/* Find this client from the list of notifies... with last-ptr. */
|
||||
if ((lp = anptr->watch))
|
||||
while (lp && (lp->value.client != client)) {
|
||||
last = lp;
|
||||
lp = lp->next;
|
||||
}
|
||||
if (!lp)
|
||||
return 0; /* No such client to watch */
|
||||
|
||||
/* Fix the linked list under header, then remove the watch entry */
|
||||
if (!last)
|
||||
anptr->watch = lp->next;
|
||||
else
|
||||
last->next = lp->next;
|
||||
free_link(lp);
|
||||
|
||||
/* Do the same regarding the links in client-record... */
|
||||
last = NULL;
|
||||
if ((lp = WATCH(client)))
|
||||
while (lp && (lp->value.wptr != anptr)) {
|
||||
last = lp;
|
||||
lp = lp->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give error on the odd case... probobly not even neccessary
|
||||
* No error checking in ircd is unneccessary ;) -Cabal95
|
||||
*/
|
||||
if (!lp)
|
||||
sendto_ops("WATCH debug error: del_from_watch_hash_table "
|
||||
"found a watch entry with no client "
|
||||
"counterpoint processing nick %s on client %p!",
|
||||
nick, client->user);
|
||||
else {
|
||||
if (!last) /* First one matched */
|
||||
WATCH(client) = lp->next;
|
||||
else
|
||||
last->next = lp->next;
|
||||
free_link(lp);
|
||||
}
|
||||
/* In case this header is now empty of notices, remove it */
|
||||
if (!anptr->watch) {
|
||||
if (!nlast)
|
||||
watchTable[hashv] = anptr->hnext;
|
||||
else
|
||||
nlast->hnext = anptr->hnext;
|
||||
safe_free(anptr);
|
||||
}
|
||||
|
||||
/* Update count of notifies on nick */
|
||||
WATCHES(client)--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hash_del_watch_list
|
||||
*/
|
||||
int hash_del_watch_list(Client *client)
|
||||
{
|
||||
unsigned int hashv;
|
||||
Watch *anptr;
|
||||
Link *np, *lp, *last;
|
||||
|
||||
|
||||
if (!(np = WATCH(client)))
|
||||
return 0; /* Nothing to do */
|
||||
|
||||
WATCH(client) = NULL; /* Break the watch-list for client */
|
||||
while (np) {
|
||||
/* Find the watch-record from hash-table... */
|
||||
anptr = np->value.wptr;
|
||||
last = NULL;
|
||||
for (lp = anptr->watch; lp && (lp->value.client != client);
|
||||
lp = lp->next)
|
||||
last = lp;
|
||||
|
||||
/* Not found, another "worst case" debug error */
|
||||
if (!lp)
|
||||
sendto_ops("WATCH Debug error: hash_del_watch_list "
|
||||
"found a WATCH entry with no table "
|
||||
"counterpoint processing client %s!",
|
||||
client->name);
|
||||
else {
|
||||
/* Fix the watch-list and remove entry */
|
||||
if (!last)
|
||||
anptr->watch = lp->next;
|
||||
else
|
||||
last->next = lp->next;
|
||||
free_link(lp);
|
||||
|
||||
/*
|
||||
* If this leaves a header without notifies,
|
||||
* remove it. Need to find the last-pointer!
|
||||
*/
|
||||
if (!anptr->watch) {
|
||||
Watch *np2, *nl;
|
||||
|
||||
hashv = hash_watch_nick_name(anptr->nick);
|
||||
|
||||
nl = NULL;
|
||||
np2 = watchTable[hashv];
|
||||
while (np2 != anptr) {
|
||||
nl = np2;
|
||||
np2 = np2->hnext;
|
||||
}
|
||||
|
||||
if (nl)
|
||||
nl->hnext = anptr->hnext;
|
||||
else
|
||||
watchTable[hashv] = anptr->hnext;
|
||||
safe_free(anptr);
|
||||
}
|
||||
}
|
||||
|
||||
lp = np; /* Save last pointer processed */
|
||||
np = np->next; /* Jump to the next pointer */
|
||||
free_link(lp); /* Free the previous */
|
||||
}
|
||||
|
||||
WATCHES(client) = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t hash_watch_nick_name(const char *name)
|
||||
{
|
||||
return siphash_nocase(name, siphashkey_watch) % WATCH_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
void count_watch_memory(int *count, u_long *memory)
|
||||
{
|
||||
int i = WATCH_HASH_TABLE_SIZE;
|
||||
Watch *anptr;
|
||||
|
||||
while (i--)
|
||||
{
|
||||
anptr = watchTable[i];
|
||||
while (anptr)
|
||||
{
|
||||
(*count)++;
|
||||
(*memory) += sizeof(Watch)+strlen(anptr->nick);
|
||||
anptr = anptr->hnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue