This commit is contained in:
Stephen Bennett 2009-12-08 19:23:32 +00:00
commit 4606e8fc6c
19 changed files with 58 additions and 396 deletions

View File

@ -92,10 +92,10 @@ struct User
{
rb_dlink_list channel; /* chain of channel pointer blocks */
rb_dlink_list invited; /* chain of invite pointer blocks */
char *away; /* pointer to away message */
int refcnt; /* Number of times this block is referenced */
char suser[NICKLEN+1];
struct Dictionary *metadata;
};
struct Server
@ -119,12 +119,6 @@ struct ZipStats
double out_ratio;
};
struct MetadataEntry
{
char key[METADATAKEYLEN];
char value[METADATAVALUELEN];
};
struct Client
{
rb_dlink_node node;
@ -456,7 +450,6 @@ struct ListClient
#define CLICAP_MULTI_PREFIX 0x0001
#define CLICAP_SASL 0x0002
#define CLICAP_PRESENCE 0x0004
/*
* flags macros.
@ -614,8 +607,4 @@ extern char *generate_uid(void);
void allocate_away(struct Client *);
void free_away(struct Client *);
const char *get_metadata(struct Client *, const char *);
void set_metadata(struct Client *, const char *, const char *);
void delete_metadata(struct Client *, const char *);
#endif /* INCLUDED_client_h */

View File

@ -111,18 +111,13 @@
#define BANREASONLEN 390 /* kline/dline */
#define AWAYLEN TOPICLEN
#define KILLLEN 200 /* with Killed (nick ()) added this should fit in quit */
#define METADATAKEYLEN 31
/* :012345678901234567890123456789012345678901234567890123456789123 792 * 012345678901234567890123456789 012345678901234567890123456789 :
* takes at most 137 bytes
* :123456789 ENCAP * PRESENCE 012345678901234567890123456789 :
* takes at most 63 bytes
* */
#define METADATAVALUELEN 300
/* 23+1 for \0 */
#define KEYLEN 24
#define BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */
#define OPERNICKLEN (NICKLEN*2) /* Length of OPERNICKs. */
#define MAXRECIPIENTS 20
#define MAXBANLENGTH 1024
#define OPERNICKLEN NICKLEN*2 /* Length of OPERNICKs. */
#define USERHOST_REPLYLEN (NICKLEN+HOSTLEN+USERLEN+5)
#define MAX_DATE_STRING 32 /* maximum string length for a date string */

View File

@ -359,11 +359,6 @@ extern const char *form_str(int);
#define RPL_SCANMATCHED 750
#define RPL_SCANUMODES 751
#define RPL_METADATASET 790
#define RPL_METADATAREM 791
#define RPL_METADATACHG 792
#define RPL_WHOISMETADATA 793
#define RPL_LOGGEDIN 900
#define RPL_LOGGEDOUT 901
#define ERR_NICKLOCKED 902

View File

@ -64,9 +64,7 @@ extern void sendto_channel_opmod(struct Client *one, struct Client *source_p,
extern void sendto_channel_local(int type, struct Channel *, const char *, ...) AFP(3, 4);
extern void sendto_channel_local_butone(struct Client *, int type, struct Channel *, const char *, ...) AFP(4, 5);
extern void sendto_common_channels_local(struct Client *, const char *, ...) AFP(2, 3);
extern void sendto_common_channels_local_with_capability(struct Client *, int, const char *, ...) AFP(3, 4);
extern void sendto_common_channels_local_butone(struct Client *, const char *, ...) AFP(2, 3);
extern void sendto_common_channels_local_with_capability_butone(struct Client *, int, const char *, ...) AFP(3, 4);
extern void sendto_match_butone(struct Client *, struct Client *,

View File

@ -26,7 +26,6 @@
#include "ratbox_lib.h"
#include "config.h" /* Gotta pull in the autoconf stuff */
#include "ircd_defs.h" /* Needed for some reasons here -- dwr */
#include "irc_dictionary.h"
/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__

View File

@ -83,7 +83,6 @@ TSRCS = \
m_ping.c \
m_pong.c \
m_post.c \
m_presence.c \
m_privs.c \
m_rehash.c \
m_restart.c \

View File

@ -744,7 +744,6 @@ static void
msg_client(int p_or_n, const char *command,
struct Client *source_p, struct Client *target_p, const char *text)
{
const char *awaymsg;
int do_floodcount = 0;
if(MyClient(source_p))
@ -789,9 +788,9 @@ msg_client(int p_or_n, const char *command,
return;
}
if(MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && (awaymsg = get_metadata(target_p, "away")) != NULL)
if(MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && target_p->user->away)
sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
target_p->name, awaymsg);
target_p->name, target_p->user->away);
if(MyClient(target_p))
{

View File

@ -78,22 +78,30 @@ m_away(struct Client *client_p, struct Client *source_p, int parc, const char *p
if(parc < 2 || EmptyString(parv[1]))
{
/* Marking as not away */
if(get_metadata(source_p, "away") != NULL)
if(source_p->user->away != NULL)
{
/* we now send this only if they were away before --is */
sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
":%s AWAY", use_id(source_p));
delete_metadata(source_p, "away");
free_away(source_p);
}
if(MyConnect(source_p))
sendto_one_numeric(source_p, RPL_UNAWAY, form_str(RPL_UNAWAY));
return 0;
}
set_metadata(source_p, "away", parv[1]);
sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
":%s AWAY :%s", use_id(source_p), parv[1]);
if(source_p->user->away == NULL)
{
allocate_away(source_p);
rb_strlcpy(source_p->user->away, parv[1], AWAYLEN);
sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
":%s AWAY :%s", use_id(source_p), source_p->user->away);
} else {
rb_strlcpy(source_p->user->away, parv[1], AWAYLEN);
}
if(MyConnect(source_p))
sendto_one_numeric(source_p, RPL_NOWAWAY, form_str(RPL_NOWAWAY));

View File

@ -69,8 +69,7 @@ static struct clicap
int namelen;
} clicap_list[] = {
_CLICAP("multi-prefix", CLICAP_MULTI_PREFIX, 0, 0),
_CLICAP("sasl", CLICAP_SASL, 0, 0),
_CLICAP("presence", CLICAP_PRESENCE, 0, 0)
_CLICAP("sasl", CLICAP_SASL, 0, 0)
};
#define CLICAP_LIST_LEN (sizeof(clicap_list) / sizeof(struct clicap))

View File

@ -58,7 +58,6 @@ static void add_invite(struct Channel *, struct Client *);
static int
m_invite(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
const char *awaymsg;
struct Client *target_p;
struct Channel *chptr;
struct membership *msptr;
@ -166,9 +165,9 @@ m_invite(struct Client *client_p, struct Client *source_p, int parc, const char
sendto_one(source_p, form_str(RPL_INVITING),
me.name, source_p->name,
target_p->name, parv[2]);
if((awaymsg = get_metadata(target_p, "away")) != NULL)
if(target_p->user->away)
sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
target_p->name, awaymsg);
target_p->name, target_p->user->away);
}
/* invite timestamp */
else if(parc > 3 && !EmptyString(parv[3]))

View File

@ -1,141 +0,0 @@
/*
* charybdis: an advanced ircd.
* m_presence.c: IRC presence protocol implementation
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
* Copyright (c) 2009 William Pitcock <nenolod@dereferenced.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: m_away.c 3370 2007-04-03 10:15:39Z nenolod $
*/
#include "stdinc.h"
#include "client.h"
#include "match.h"
#include "ircd.h"
#include "numeric.h"
#include "send.h"
#include "msg.h"
#include "parse.h"
#include "modules.h"
#include "s_conf.h"
#include "s_serv.h"
#include "packet.h"
static int m_presence(struct Client *, struct Client *, int, const char **);
static int me_presence(struct Client *, struct Client *, int, const char **);
struct Message presence_msgtab = {
"PRESENCE", 0, 0, 0, MFLG_SLOW,
{mg_unreg, {m_presence, 2}, {m_presence, 2}, mg_ignore, {me_presence, 2}, {m_presence, 2}}
};
mapi_clist_av1 presence_clist[] = { &presence_msgtab, NULL };
DECLARE_MODULE_AV1(presence, NULL, NULL, presence_clist, NULL, NULL, "$Revision$");
/*
** m_presence
** parv[1] = key
** parv[2] = setting
*/
static int
m_presence(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
const char *val;
if(MyClient(source_p) && !IsFloodDone(source_p))
flood_endgrace(source_p);
if(!IsClient(source_p))
return 0;
if (!irccmp(parv[1], "away"))
{
sendto_one_notice(source_p, ":Please use /AWAY to change your away status");
return 0;
}
if((parc < 3 || EmptyString(parv[2])) && !EmptyString(parv[1]))
{
if ((val = get_metadata(source_p, parv[1])) != NULL)
{
delete_metadata(source_p, parv[1]);
sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
":%s ENCAP * PRESENCE %s", use_id(source_p), parv[1]);
}
if (MyConnect(source_p))
sendto_one_numeric(source_p, RPL_METADATAREM, form_str(RPL_METADATAREM), parv[1]);
return 0;
}
if (strlen(parv[1]) >= METADATAKEYLEN)
{
sendto_one_notice(source_p, ":Metadata key too long");
return 0;
}
if ((val = get_metadata(source_p, parv[1])) != NULL)
{
if (!strcmp(parv[2], val))
return 0;
}
set_metadata(source_p, parv[1], parv[2]);
sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
":%s ENCAP * PRESENCE %s :%s", use_id(source_p), parv[1], parv[2]);
if(MyConnect(source_p))
sendto_one_numeric(source_p, RPL_METADATASET, form_str(RPL_METADATASET), parv[1]);
return 0;
}
/*
** me_presence
** parv[1] = key
** parv[2] = setting
*/
static int
me_presence(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
const char *val;
if(!IsClient(source_p))
return 0;
if((parc < 3 || EmptyString(parv[2])) && !EmptyString(parv[1]))
{
delete_metadata(source_p, parv[1]);
return 0;
}
if (strlen(parv[1]) >= METADATAKEYLEN)
return 0;
if ((val = get_metadata(source_p, parv[1])) != NULL)
{
if (!strcmp(parv[2], val))
return 0;
}
set_metadata(source_p, parv[1], parv[2]);
return 0;
}

View File

@ -704,7 +704,7 @@ stats_operedup (struct Client *source_p)
if(IsOperInvis(target_p) && !IsOper(source_p))
continue;
if(get_metadata(target_p, "away"))
if(target_p->user->away)
continue;
count++;
@ -1137,6 +1137,7 @@ stats_memory (struct Client *source_p)
int conf_count = 0; /* conf lines */
int users_invited_count = 0; /* users invited */
int user_channels = 0; /* users in channels */
int aways_counted = 0;
size_t number_servers_cached; /* number of servers cached by scache */
size_t channel_memory = 0;
@ -1145,6 +1146,7 @@ stats_memory (struct Client *source_p)
size_t channel_invex_memory = 0;
size_t channel_quiet_memory = 0;
size_t away_memory = 0; /* memory used by aways */
size_t ww = 0; /* whowas array count */
size_t wwm = 0; /* whowas array memory used */
size_t conf_memory = 0; /* memory used by conf lines */
@ -1179,6 +1181,11 @@ stats_memory (struct Client *source_p)
users_counted++;
users_invited_count += rb_dlink_list_length(&target_p->user->invited);
user_channels += rb_dlink_list_length(&target_p->user->channel);
if(target_p->user->away)
{
aways_counted++;
away_memory += (strlen(target_p->user->away) + 1);
}
}
}
@ -1239,9 +1246,10 @@ stats_memory (struct Client *source_p)
(unsigned long) users_invited_count * sizeof(rb_dlink_node));
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"z :User channels %u(%lu)",
"z :User channels %u(%lu) Aways %u(%d)",
user_channels,
(unsigned long) user_channels * sizeof(rb_dlink_node));
(unsigned long) user_channels * sizeof(rb_dlink_node),
aways_counted, (int) away_memory);
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"z :Attached confs %u(%lu)",

View File

@ -84,7 +84,7 @@ m_userhost(struct Client *client_p, struct Client *source_p, int parc, const cha
rl = rb_sprintf(response, "%s%s=%c%s@%s ",
target_p->name,
IsOper(target_p) ? "*" : "",
(get_metadata(target_p, "away") != NULL) ? '-' : '+',
(target_p->user->away) ? '-' : '+',
target_p->username,
target_p->sockhost);
}
@ -93,7 +93,7 @@ m_userhost(struct Client *client_p, struct Client *source_p, int parc, const cha
rl = rb_sprintf(response, "%s%s=%c%s@%s ",
target_p->name,
IsOper(target_p) ? "*" : "",
(get_metadata(target_p, "away") != NULL) ? '-' : '+',
(target_p->user->away) ? '-' : '+',
target_p->username, target_p->host);
}

View File

@ -467,7 +467,7 @@ do_who(struct Client *source_p, struct Client *target_p, struct membership *mspt
const char *q;
rb_sprintf(status, "%c%s%s",
(get_metadata(target_p, "away") != NULL) ? 'G' : 'H', IsOper(target_p) ? "*" : "", msptr ? find_channel_status(msptr, fmt->fields || IsCapable(source_p, CLICAP_MULTI_PREFIX)) : "");
target_p->user->away ? 'G' : 'H', IsOper(target_p) ? "*" : "", msptr ? find_channel_status(msptr, fmt->fields || IsCapable(source_p, CLICAP_MULTI_PREFIX)) : "");
if (fmt->fields == 0)
sendto_one(source_p, form_str(RPL_WHOREPLY), me.name,

View File

@ -228,7 +228,6 @@ do_whois(struct Client *client_p, struct Client *source_p, int parc, const char
static void
single_whois(struct Client *source_p, struct Client *target_p, int operspy)
{
const char *awaymsg;
char buf[BUFSIZE];
rb_dlink_node *ptr;
struct membership *msptr;
@ -240,8 +239,6 @@ single_whois(struct Client *source_p, struct Client *target_p, int operspy)
hook_data_client hdata;
int visible;
int extra_space = 0;
struct DictionaryIter iter;
struct MetadataEntry *md;
if(target_p->user == NULL)
{
@ -307,9 +304,9 @@ single_whois(struct Client *source_p, struct Client *target_p, int operspy)
target_p->name, target_p->servptr->name,
target_p->servptr->info);
if((awaymsg = get_metadata(target_p, "away")) != NULL)
if(target_p->user->away)
sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
target_p->name, awaymsg);
target_p->name, target_p->user->away);
if(IsOper(target_p))
{
@ -369,17 +366,6 @@ single_whois(struct Client *source_p, struct Client *target_p, int operspy)
}
}
DICTIONARY_FOREACH(md, &iter, target_p->user->metadata)
{
/* XXX: hack around "away" for legacy clients. --nenolod */
if (!irccmp(md->key, "away"))
continue;
sendto_one_numeric(source_p, RPL_WHOISMETADATA,
form_str(RPL_WHOISMETADATA),
target_p->name, md->key, md->value);
}
hdata.client = source_p;
hdata.target = target_p;

View File

@ -76,7 +76,7 @@ static rb_bh *client_heap = NULL;
static rb_bh *lclient_heap = NULL;
static rb_bh *pclient_heap = NULL;
static rb_bh *user_heap = NULL;
static rb_bh *metadata_heap = NULL;
static rb_bh *away_heap = NULL;
static char current_uid[IDLEN];
struct Dictionary *nd_dict = NULL;
@ -120,7 +120,7 @@ init_client(void)
lclient_heap = rb_bh_create(sizeof(struct LocalUser), LCLIENT_HEAP_SIZE, "lclient_heap");
pclient_heap = rb_bh_create(sizeof(struct PreClient), PCLIENT_HEAP_SIZE, "pclient_heap");
user_heap = rb_bh_create(sizeof(struct User), USER_HEAP_SIZE, "user_heap");
metadata_heap = rb_bh_create(sizeof(struct MetadataEntry), USER_HEAP_SIZE, "metadata_heap");
away_heap = rb_bh_create(AWAYLEN, AWAY_HEAP_SIZE, "away_heap");
rb_event_addish("check_pings", check_pings, NULL, 30);
rb_event_addish("free_exited_clients", &free_exited_clients, NULL, 4);
@ -1657,10 +1657,8 @@ make_user(struct Client *client_p)
{
user = (struct User *) rb_bh_alloc(user_heap);
user->refcnt = 1;
user->metadata = irc_dictionary_create(irccmp);
client_p->user = user;
}
return user;
}
@ -1697,8 +1695,12 @@ make_server(struct Client *client_p)
void
free_user(struct User *user, struct Client *client_p)
{
free_away(client_p);
if(--user->refcnt <= 0)
{
if(user->away)
rb_free((char *) user->away);
/*
* sanity check
*/
@ -1725,63 +1727,21 @@ free_user(struct User *user, struct Client *client_p)
}
}
const char *
get_metadata(struct Client *client_p, const char *key)
void
allocate_away(struct Client *client_p)
{
struct MetadataEntry *md;
if (client_p->user != NULL)
{
md = irc_dictionary_retrieve(client_p->user->metadata, key);
if (md == NULL)
return NULL;
return md->value;
}
return NULL;
if(client_p->user->away == NULL)
client_p->user->away = rb_bh_alloc(away_heap);
}
void
set_metadata(struct Client *client_p, const char *key, const char *value)
{
struct MetadataEntry *md;
if(client_p->user != NULL)
{
md = irc_dictionary_retrieve(client_p->user->metadata, key);
if (md == NULL)
{
md = rb_bh_alloc(metadata_heap);
rb_strlcpy(md->key, key, sizeof md->key);
irc_dictionary_add(client_p->user->metadata, md->key, md);
}
else if (!strcmp(md->key, key) && !strcmp(md->value, value))
return;
else
rb_strlcpy(md->key, key, sizeof md->key);
rb_strlcpy(md->value, value, sizeof md->value);
}
sendto_common_channels_local_with_capability(client_p, CLICAP_PRESENCE, form_str(RPL_METADATACHG), me.name, client_p->name, key, value);
}
void
delete_metadata(struct Client *client_p, const char *key)
free_away(struct Client *client_p)
{
struct MetadataEntry *md;
if(client_p->user != NULL)
{
md = irc_dictionary_delete(client_p->user->metadata, key);
if (md == NULL)
return;
rb_bh_free(metadata_heap, md);
if(client_p->user != NULL && client_p->user->away != NULL) {
rb_bh_free(away_heap, client_p->user->away);
client_p->user->away = NULL;
}
sendto_common_channels_local_with_capability(client_p, CLICAP_PRESENCE, form_str(RPL_METADATACHG), me.name, client_p->name, key, "");
}
void

View File

@ -811,10 +811,10 @@ static const char * replies[] = {
/* 787 */ NULL,
/* 788 */ NULL,
/* 789 */ NULL,
/* 790 RPL_METADATASET */ "%s :Metadata set",
/* 791 RPL_METADATAREM */ "%s :Metadata removed",
/* 792 RPL_METADATACHG */ ":%s 792 * %s %s :%s",
/* 793 RPL_WHOISMETADATA */ "%s %s :%s",
/* 790 */ NULL,
/* 791 */ NULL,
/* 792 */ NULL,
/* 793 */ NULL,
/* 794 */ NULL,
/* 795 */ NULL,
/* 796 */ NULL,

View File

@ -474,8 +474,6 @@ burst_TS6(struct Client *client_p)
RB_DLINK_FOREACH(ptr, global_client_list.head)
{
const char *awaymsg = NULL;
target_p = ptr->data;
if(!IsPerson(target_p))
@ -518,10 +516,10 @@ burst_TS6(struct Client *client_p)
use_id(target_p), target_p->user->suser);
}
if(ConfigFileEntry.burst_away && (awaymsg = get_metadata(target_p, "away")) != NULL)
if(ConfigFileEntry.burst_away && !EmptyString(target_p->user->away))
sendto_one(client_p, ":%s AWAY :%s",
use_id(target_p),
awaymsg);
target_p->user->away);
hclientinfo.target = target_p;
call_hook(h_burst_client, &hclientinfo);

View File

@ -760,69 +760,6 @@ sendto_common_channels_local(struct Client *user, const char *pattern, ...)
rb_linebuf_donebuf(&linebuf);
}
/*
* sendto_common_channels_local_with_capability()
*
* inputs - pointer to client
* - capability
* - pattern to send
* output - NONE
* side effects - Sends a message to all people on local server who are
* in same channel with user.
* used by m_nick.c and exit_one_client.
*/
void
sendto_common_channels_local_with_capability(struct Client *user, int capability, const char *pattern, ...)
{
va_list args;
rb_dlink_node *ptr;
rb_dlink_node *next_ptr;
rb_dlink_node *uptr;
rb_dlink_node *next_uptr;
struct Channel *chptr;
struct Client *target_p;
struct membership *msptr;
struct membership *mscptr;
buf_head_t linebuf;
rb_linebuf_newbuf(&linebuf);
va_start(args, pattern);
rb_linebuf_putmsg(&linebuf, pattern, &args, NULL);
va_end(args);
++current_serial;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, user->user->channel.head)
{
mscptr = ptr->data;
chptr = mscptr->chptr;
RB_DLINK_FOREACH_SAFE(uptr, next_uptr, chptr->locmembers.head)
{
msptr = uptr->data;
target_p = msptr->client_p;
if(!IsCapable(target_p, capability))
continue;
if(IsIOError(target_p) ||
target_p->serial == current_serial)
continue;
target_p->serial = current_serial;
send_linebuf(target_p, &linebuf);
}
}
/* this can happen when the user isnt in any channels, but we still
* need to send them the data, ie a nick change
*/
if(MyConnect(user) && (user->serial != current_serial) && IsCapable(user, capability))
send_linebuf(user, &linebuf);
rb_linebuf_donebuf(&linebuf);
}
/*
* sendto_common_channels_local_butone()
*
@ -877,72 +814,6 @@ sendto_common_channels_local_butone(struct Client *user, const char *pattern, ..
rb_linebuf_donebuf(&linebuf);
}
/*
* sendto_common_channels_local_with_capability_butone()
*
* inputs - pointer to client
* - capability
* - pattern to send
* output - NONE
* side effects - Sends a message to all people on local server who are
* in same channel with user, except the user themselves.
* used by m_nick.c and exit_one_client.
*/
void
sendto_common_channels_local_with_capability_butone(struct Client *user, int capability, const char *pattern, ...)
{
va_list args;
rb_dlink_node *ptr;
rb_dlink_node *next_ptr;
rb_dlink_node *uptr;
rb_dlink_node *next_uptr;
struct Channel *chptr;
struct Client *target_p;
struct membership *msptr;
struct membership *mscptr;
buf_head_t linebuf;
rb_linebuf_newbuf(&linebuf);
va_start(args, pattern);
rb_linebuf_putmsg(&linebuf, pattern, &args, NULL);
va_end(args);
++current_serial;
/* Skip them -- jilles */
user->serial = current_serial;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, user->user->channel.head)
{
mscptr = ptr->data;
chptr = mscptr->chptr;
RB_DLINK_FOREACH_SAFE(uptr, next_uptr, chptr->locmembers.head)
{
msptr = uptr->data;
target_p = msptr->client_p;
if(!IsCapable(target_p, capability))
continue;
if(IsIOError(target_p) ||
target_p->serial == current_serial)
continue;
target_p->serial = current_serial;
send_linebuf(target_p, &linebuf);
}
}
/* this can happen when the user isnt in any channels, but we still
* need to send them the data, ie a nick change
*/
if(MyConnect(user) && (user->serial != current_serial) && IsCapable(user, capability))
send_linebuf(user, &linebuf);
rb_linebuf_donebuf(&linebuf);
}
/* sendto_match_butone()
*
* inputs - server not to send to, source, mask, type of mask, va_args