chmode +a and chmod +O in progress. sendto_* updates

This commit is contained in:
fishwaldo 2002-08-14 16:52:02 +00:00
parent 881b9a01ce
commit c02c237503
13 changed files with 380 additions and 191 deletions

View file

@ -19,3 +19,7 @@ Symbols are:
user removes -x then, vhost is set to real host.
(F) - Added Setulined to conf file for locally linked servers.
(HP) - Added Patch to fix race condition in dead_link
(F) - Added Channel Admins (+a)
(F) - Moved AnonOps Mode char to +A
(F) - Only allow channel admins to set +A (anonops)
(F) - Channel Mode +O (opers only)

124
TODO
View file

@ -1,122 +1,4 @@
$Id: TODO,v 1.2 2002/08/13 14:44:59 fishwaldo Exp $
- add more stderr debugging (ircd -s)... one for every place we syslog()
- ircd -s doesn't work through a restart
- re-implement first param in m_lusers()
- trie' channel name list
- finish RFC'ing m_message.c
----
is-'s TODO list
- umode +R for registered nick
- TBURST
- change nick instead of kill on nick collide
- dynamically extensible parser for modules
- modularize channel, network code etc (not just commands)
we can use override_function() or similar for this
- username/passwords (iauth ?)
- channel modes to allow/prevent talking on channel
by hostmasks.
-----------------------------------------------------------------------------
madmax's TODO
- Make stats p just notice opers, rather than return a list, when
server_hide is on (#13)
- Client UIDs (ts4 style?) for cookies (later for persistent nicks)
- Definable server region or 'global' (open I) for /links output (#20)
-----------------------------------------------------------------------------
Adrian's TODO list
* make the reserved FD limit run-time tunable, esp from comm_open()
This involves making fd_table[] a dynamically growing/(don't bother with
shrinking) list.. have the max fd list configurable in the conf file..
* Fix the anti-client flood code to not be so anal when people connect -
I've counted all lines from a client as being a flood, so if a client
connects and issues JOIN's to a whole bunch of channels the flood
protection stops everything coming through at once .. (not that I mind.. :)
* PLEASE redo all dlink_list management with the stuff in src/tools.c
* In the server outbound connection code, make the sendto_realops()
logging more sane. Ie, if there's an error, also log the errno string.
* look at the old Listener code in s_bsd.c before I chopped it. Notice
the anti-flood code in there. Make sure the same load-checking stuff
is in listener.c
* get send_message(), replace comm_setselect() with send_queued_write(), see
if the optimization works
* remove aconf->ipnum, since we're doing a DNS lookup each time we
connect. If people don't like this, they can (should!) be running
a name cache locally!
db-->>ummm aconf->ipnum is used for IP based klines only, not for DNS
* Add the IRCnet(?) split logic for nick collisions - on a nick collision,
change to "%d-%s", random, nick
* Hrm. Since Diane changed the user->channel code to use dlink_lists,
she's made some things faster (deopping lists of people in a net.join,
finding an op, etc) but some things slower (deleting from the channel,
change_channel_membership(), etc.) What needs to happen is that for
each channel a user is on, a flag needs to be set tracking which list
they're on so we don't have to search the lists when we want to change
their status. This could become a slow-CPU sticking point.
db-->> Actually, the old code was just as slow at doing that, since
it was a link list of SLink's with a flag denoting whether client
on channel was an op or not... With a channel of 100 clients and
thats 100 link SLink's
------------------------------------------------------------------------------
Little things to be done given enough time and initiative -Hwy
. The 3 logging path settings are NOOP in the conf (logpath, oper_log,
gline_log)
. Fix convertconf more
. 2 pass conf parser (grab classes before anything that uses them)
. Re-add the ability to set usermodes from the conf (oldconf field after the
O: line class)
. <Riedel> walter : have you implemented the motd= thing in the auth block ?
. Fix topic bursting to LL servers (broke lately for some reason)
--> Unknown status
. A FAQ
--> Dracus is working on this, I will try to put something together too
. Major cleanup of example.conf, it's a disgrace
--> Still a disgrace
. chkconf
--> SCARY!!!
. More translations!
-- Rodder's list
. Add scalable database-based authentication. Probably part of Iauth.
Also add support for server-side notify with the list stored in the
auth database. This would make ircd an awesome instant messaging
back-end.
-- jdc's list
* Re-write m_stats.c to be table-based, similar to m_set. Also change
to support funtion exit code values (int), so that STATS output can
be "successful" or "unsuccessful" (eg. "STATS i requested by <nick>
[unsuccessful]" vs. "STATS i requested by <nick>").
--> Table part I know is done, what about the success status?
* Re-write proper startup procedure for daemon; procedure should be
done in stages, similar to boot0/1/2 stages in FreeBSD.
* Write secure cryptlink protocol with help from Sean.
-- Diane's list
* add logging to ircd.log of possible channel floods
* add code to log a minute worth of flooding if the ircd gets n possible
flood messages on a channel in t seconds.. This log would be available
to hand to authorities if requested.
$Id: TODO,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
invites and exception list (and invite exception lists) should
override a oper only channel :)

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: channel.h,v 1.2 2002/08/13 14:45:10 fishwaldo Exp $
* $Id: channel.h,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#ifndef INCLUDED_channel_h
@ -66,7 +66,7 @@ struct Channel
struct Channel *root_chptr; /* pointer back to root if vchan */
dlink_list vchan_list; /* vchan sublist */
#endif
dlink_list chanadmins; /* list of Channel Admins */
dlink_list chanops; /* lists of chanops etc. */
#ifdef REQUIRE_OANDV
dlink_list chanops_voiced; /* UGH I'm sorry */
@ -77,7 +77,8 @@ struct Channel
dlink_list voiced;
dlink_list peons; /* non ops, just members */
dlink_list deopped; /* users deopped on sjoin */
dlink_list locchanadmins; /* local versions of the above */
dlink_list locchanops; /* local versions of the above */
#ifdef REQUIRE_OANDV
dlink_list locchanops_voiced; /* UGH I'm sorry */
@ -114,6 +115,7 @@ extern int is_banned (struct Channel *chptr, struct Client *who);
extern int can_join(struct Client *source_p, struct Channel *chptr,
char *key);
extern int is_chan_op (struct Channel *chptr,struct Client *who);
extern int is_chan_admin (struct Channel *chptr, struct Client *who);
extern int is_any_op (struct Channel *chptr,struct Client *who);
#ifdef HALFOPS
extern int is_half_op (struct Channel *chptr,struct Client *who);
@ -171,9 +173,9 @@ struct Ban /* also used for exceptions -orabidoo */
#define MAX_VCHAN_TIME (60*60)
/* Number of chanops, peon, voiced, halfops sublists */
#ifdef REQUIRE_OANDV
#define NUMLISTS 5
#define NUMLISTS 6
#else
#define NUMLISTS 4
#define NUMLISTS 5
#endif
#ifdef INTENSIVE_DEBUG

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: channel_mode.h,v 1.2 2002/08/13 14:45:10 fishwaldo Exp $
* $Id: channel_mode.h,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
@ -80,6 +80,7 @@ extern void unset_chcap_usage_counts(struct Client *serv_p);
#define CHFL_BAN 0x0010 /* ban channel flag */
#define CHFL_EXCEPTION 0x0020 /* exception to ban channel flag */
#define CHFL_INVEX 0x0080
#define CHFL_ADMIN 0x0100 /* channel admins */
/* Channel Visibility macros */
@ -88,6 +89,7 @@ extern void unset_chcap_usage_counts(struct Client *serv_p);
#define MODE_VOICE CHFL_VOICE
#define MODE_HALFOP CHFL_HALFOP
#define MODE_DEOPPED CHFL_DEOPPED
#define MODE_ADMIN CHFL_ADMIN
/* channel modes ONLY */
#define MODE_PRIVATE 0x0008
@ -100,6 +102,7 @@ extern void unset_chcap_usage_counts(struct Client *serv_p);
#define MODE_EXCEPTION 0x0800
#define MODE_INVEX 0x2000
#define MODE_HIDEOPS 0x4000
#define MODE_OPERSONLY 0x8000
/*
* mode flags which take another parameter (With PARAmeterS)
@ -143,6 +146,7 @@ struct ChCapCombo
int cap_no;
};
#define CHACCESS_ADMIN 4
#define CHACCESS_CHANOP 3
#define CHACCESS_HALFOP 2
#define CHACCESS_VOICED 1

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: client.h,v 1.2 2002/08/13 14:45:10 fishwaldo Exp $
* $Id: client.h,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#ifndef INCLUDED_client_h
@ -629,5 +629,6 @@ extern int change_local_nick(struct Client *client_p, struct Client *source_p,
char *nick);
extern void dead_link(struct Client *client_p);
extern void exit_aborted_clients(void);
extern char *make_virthost(char *curr, char *new, int mode);
#endif /* INCLUDED_client_h */

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: send.h,v 1.2 2002/08/13 14:45:11 fishwaldo Exp $
* $Id: send.h,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#ifndef INCLUDED_send_h
@ -107,6 +107,7 @@ kill_client_ll_serv_butone(struct Client *one, struct Client *source_p,
#define ONLY_CHANOPS_HALFOPS 3
#define ONLY_CHANOPS 4
#define ONLY_SERVERS 5 /* for channel_mode.c */
#define ONLY_CHANADMIN 6
#define L_ALL 0
#define L_OPER 1

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: m_invite.c,v 1.2 2002/08/13 14:45:11 fishwaldo Exp $
* $Id: m_invite.c,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
@ -62,7 +62,7 @@ _moddeinit(void)
mod_del_cmd(&invite_msgtab);
}
const char *_version = "$Revision: 1.2 $";
const char *_version = "$Revision: 1.3 $";
#endif
/*
@ -174,7 +174,7 @@ m_invite(struct Client *client_p,
return;
}
chop = is_chan_op(chptr, source_p);
chop = is_chan_op(chptr, source_p) || is_chan_admin(chptr, source_p);
if (chptr && (vchan->mode.mode & MODE_INVITEONLY))
{
@ -187,6 +187,7 @@ m_invite(struct Client *client_p,
}
}
else
if (!(vchan->mode.mode * MODE_OPERSONLY))
/* Don't save invite even if from an op otherwise... */
chop = 0;

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: m_join.c,v 1.2 2002/08/13 14:45:11 fishwaldo Exp $
* $Id: m_join.c,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
@ -65,7 +65,7 @@ _moddeinit(void)
{
mod_del_cmd(&join_msgtab);
}
const char *_version = "$Revision: 1.2 $";
const char *_version = "$Revision: 1.3 $";
#endif
static void do_join_0(struct Client *client_p, struct Client *source_p);
@ -216,7 +216,7 @@ m_join(struct Client *client_p,
}
if (chptr->users == 0)
flags = CHFL_CHANOP;
flags = CHFL_ADMIN;
else
flags = 0;
}
@ -230,7 +230,7 @@ m_join(struct Client *client_p,
continue;
}
flags = CHFL_CHANOP;
flags = CHFL_ADMIN;
if(!ServerInfo.hub)
{
/* LazyLinks */
@ -312,7 +312,7 @@ m_join(struct Client *client_p,
** Set timestamp if appropriate, and propagate
*/
if (flags & CHFL_CHANOP)
if (flags & CHFL_ADMIN)
{
chptr->channelts = CurrentTime;
@ -374,7 +374,7 @@ m_join(struct Client *client_p,
source_p->vhost,
root_chptr->chname);
if( flags & CHFL_CHANOP )
if( flags & CHFL_ADMIN )
{
chptr->mode.mode |= MODE_TOPICLIMIT;
chptr->mode.mode |= MODE_NOPRIVMSGS;
@ -399,7 +399,7 @@ m_join(struct Client *client_p,
parv[0], root_chptr->chname, chptr->topic);
if (!(chptr->mode.mode & MODE_HIDEOPS) ||
(flags & CHFL_CHANOP) || (flags & CHFL_HALFOP))
(flags & CHFL_CHANOP) || (flags & CHFL_HALFOP) || (flags & CHFL_ADMIN))
{
sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
me.name, parv[0], root_chptr->chname,

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: m_who.c,v 1.2 2002/08/13 14:45:12 fishwaldo Exp $
* $Id: m_who.c,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
#include "tools.h"
@ -61,7 +61,7 @@ _moddeinit(void)
{
mod_del_cmd(&who_msgtab);
}
const char *_version = "$Revision: 1.2 $";
const char *_version = "$Revision: 1.3 $";
#endif
static void do_who_on_channel(struct Client *source_p,
struct Channel *chptr, char *real_name,
@ -75,10 +75,12 @@ static void do_who_list(struct Client *source_p, struct Channel *chptr,
#ifdef HALFOPS
dlink_list *halfops_list,
#endif
dlink_list *chanadmins_list,
dlink_list *voiced_list,
char *chanop_flag,
char *halfop_flag,
char *voiced_flag,
char *chanadmin_flag,
char *chname, int member);
static void who_global(struct Client *source_p, char *mask, int server_oper);
@ -255,6 +257,8 @@ static void m_who(struct Client *client_p,
#endif
else if(is_voiced(chptr,target_p))
do_who(source_p, target_p, chname, flags[2]);
else if(is_chan_admin(chptr, target_p))
do_who(source_p, target_p, chname, flags[5]);
else
do_who(source_p, target_p, chname, "");
}
@ -416,7 +420,6 @@ static void do_who_on_channel(struct Client *source_p,
/* jdc -- Check is_any_op() for +o > +h > +v priorities */
set_channel_mode_flags( flags, chptr, source_p );
do_who_list(source_p, chptr,
&chptr->peons,
&chptr->chanops,
@ -426,10 +429,12 @@ static void do_who_on_channel(struct Client *source_p,
#ifdef HALFOPS
&chptr->halfops,
#endif
&chptr->chanadmins,
&chptr->voiced,
flags[0],
flags[1],
flags[2],
flags[5],
chname, member);
}
@ -443,10 +448,12 @@ static void do_who_list(struct Client *source_p, struct Channel *chptr,
#ifdef HALFOPS
dlink_list *halfops_list,
#endif
dlink_list *chanadmins_list,
dlink_list *voiced_list,
char *chanop_flag,
char *halfop_flag,
char *voiced_flag,
char *admins_flag,
char *chname, int member)
{
struct Client *target_p;
@ -461,6 +468,7 @@ static void do_who_list(struct Client *source_p, struct Channel *chptr,
#ifdef HALFOPS
dlink_node *halfops_ptr;
#endif
dlink_node *chanadmins_ptr;
int done=0;
peons_ptr = peons_list->head;
@ -472,6 +480,7 @@ static void do_who_list(struct Client *source_p, struct Channel *chptr,
#ifdef REQUIRE_OANDV
chanops_voiced_ptr = chanops_voiced_list->head;
#endif
chanadmins_ptr = chanadmins_list->head;
while (done != NUMLISTS)
{
@ -498,6 +507,16 @@ static void do_who_list(struct Client *source_p, struct Channel *chptr,
}
else
done++;
ilog(1, "chanadmin1 %s", admins_flag);
if(chanadmins_ptr != NULL)
{
target_p = chanadmins_ptr->data;
if(member || !IsInvisible(target_p))
do_who(source_p, target_p, chname, admins_flag);
chanadmins_ptr = chanadmins_ptr->next;
}
else
done++;
#ifdef HALFOPS
if(halfops_ptr != NULL)
@ -572,6 +591,13 @@ static void do_who_list(struct Client *source_p, struct Channel *chptr,
do_who(source_p, target_p, chname, chanop_flag);
}
#endif
for(ptr = chanadmins_list->head; ptr; ptr = ptr->next)
{
target_p = ptr->data;
ilog(1, "doadmin %s", admins_flag);
if(member || !IsInvisible(target_p))
do_who(source_p, target_p, chname, admins_flag);
}
for(ptr = chanops_list->head; ptr; ptr = ptr->next)
{
@ -600,7 +626,6 @@ static void do_who(struct Client *source_p,
char *op_flags)
{
char status[5];
ircsprintf(status,"%c%s%s",
target_p->user->away ? 'G' : 'H',
IsOper(target_p) ? "*" : "", op_flags );

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: channel.c,v 1.2 2002/08/13 14:45:12 fishwaldo Exp $
* $Id: channel.c,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
@ -152,6 +152,11 @@ add_user_to_channel(struct Channel *chptr, struct Client *who, int flags)
dlinkAdd(who, lptr, &chptr->locchanops);
break;
#endif
case MODE_ADMIN:
dlinkAdd(who, ptr, &chptr->chanadmins);
if (MyClient(who))
dlinkAdd(who, lptr, &chptr->locchanadmins);
break;
}
if(flags & MODE_DEOPPED)
@ -209,6 +214,8 @@ remove_user_from_channel(struct Channel *chptr, struct Client *who)
else if ((ptr = find_user_link(&chptr->halfops, who)))
dlinkDelete(ptr, &chptr->halfops);
#endif
else if ((ptr = find_user_link(&chptr->chanadmins, who)))
dlinkDelete(ptr, &chptr->chanadmins);
else {
assert(0 == 1); /* This ain't supposed to happen */
}
@ -237,6 +244,8 @@ remove_user_from_channel(struct Channel *chptr, struct Client *who)
else if ((ptr = find_user_link(&chptr->locchanops_voiced, who)))
dlinkDelete(ptr, &chptr->locchanops_voiced);
#endif
else if ((ptr = find_user_link(&chptr->locchanadmins, who)))
dlinkDelete(ptr, &chptr->locchanadmins);
else
assert(1 == 0);
@ -371,7 +380,7 @@ send_channel_modes(struct Client *client_p, struct Channel *chptr)
send_members(client_p, modebuf, parabuf, chptr, &chptr->halfops, "@");
}
#endif
send_members(client_p, modebuf, parabuf, chptr, &chptr->chanadmins, "*");
send_members(client_p, modebuf, parabuf, chptr, &chptr->voiced, "+");
send_members(client_p, modebuf, parabuf, chptr, &chptr->peons, "");
@ -642,7 +651,7 @@ destroy_channel(struct Channel *chptr)
* persistent channels. In the case of a LL the channel need not
* be empty, it only has to be empty of local users.
*/
delete_members(chptr, &chptr->chanadmins);
delete_members(chptr, &chptr->chanops);
#ifdef REQUIRE_OANDV
delete_members(chptr, &chptr->chanops_voiced);
@ -653,6 +662,7 @@ destroy_channel(struct Channel *chptr)
delete_members(chptr, &chptr->halfops);
#endif
delete_members(chptr, &chptr->locchanadmins);
delete_members(chptr, &chptr->locchanops);
#ifdef REQUIRE_OANDV
delete_members(chptr, &chptr->locchanops_voiced);
@ -801,7 +811,11 @@ channel_member_names(struct Client *source_p,
members_ptr[3] = chptr->peons.head;
#ifdef REQUIRE_OANDV
members_ptr[4] = chptr->chanops_voiced.head;
#else
members_ptr[4] = NULL;
#endif
members_ptr[5] = chptr->chanadmins.head;
is_member = IsMember(source_p, chptr);
/* Note: This code will show one chanop followed by one voiced followed
@ -889,7 +903,10 @@ channel_member_names(struct Client *source_p,
ptr_list[3] = chptr->peons.head;
#ifdef REQUIRE_OANDV
ptr_list[4] = chptr->chanops_voiced.head;
#else
ptr_list[4] = NULL;
#endif
ptr_list[5] = chptr->chanadmins.head;
set_channel_mode_flags(ptr_flags, chptr, source_p);
@ -1056,6 +1073,8 @@ channel_chanop_or_voice(struct Channel *chptr, struct Client *target_p)
else if (find_user_link(&chptr->chanops_voiced, target_p))
return ("@+");
#endif
else if (find_user_link(&chptr->chanadmins, target_p))
return ("*");
return ("");
}
@ -1181,7 +1200,7 @@ can_join(struct Client *source_p, struct Channel *chptr, char *key)
for (ptr = chptr->invexlist.head; ptr; ptr = ptr->next)
{
invex = ptr->data;
if (match(invex->banstr, src_host) || match(invex->banstr, src_iphost))
if (match(invex->banstr, src_host) || match(invex->banstr, src_iphost) || match(invex->banstr, src_vhost))
break;
}
if (ptr == NULL)
@ -1195,6 +1214,30 @@ can_join(struct Client *source_p, struct Channel *chptr, char *key)
if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
return (ERR_CHANNELISFULL);
if ((chptr->mode.mode & MODE_OPERSONLY) && !IsOper(source_p)) {
for (lp = source_p->user->invited.head; lp; lp = lp->next) {
if (lp->data == chptr)
break;
}
if (!lp)
{
if (!ConfigChannel.use_invex)
return (ERR_NOPRIVILEGES);
for (ptr = chptr->invexlist.head; ptr; ptr = ptr->next)
{
invex = ptr->data;
if (match(invex->banstr, src_host) || match(invex->banstr, src_iphost) || match(invex->banstr, src_vhost))
break;
}
if (ptr == NULL)
return (ERR_NOPRIVILEGES);
else
return 0;
} else {
return 0;
}
return (ERR_NOPRIVILEGES);
}
return 0;
}
@ -1221,10 +1264,30 @@ is_chan_op(struct Channel *chptr, struct Client *who)
return 0;
}
/*
* is_chan_admin
*
* inputs - Pointer to channel to check chanadmin on
* - pointer to client struct being checked
* output - yes if chanadmin, no if not
* side effects -
*/
int
is_chan_admin(struct Channel *chptr, struct Client *who)
{
if (chptr)
{
if (find_user_link(&chptr->chanadmins, who) != NULL)
return 1;
}
return 0;
}
/*
* is_any_op
*
* inputs - pointer to channel to check for chanop or halfops on
* inputs - pointer to channel to check for chanop or halfops or chanadmin on
* - pointer to client struct being checked
* output - yes if anyop no if not
* side effects -
@ -1240,6 +1303,8 @@ is_any_op(struct Channel *chptr, struct Client *who)
if (find_user_link(&chptr->halfops, who) != NULL)
return 1;
#endif
if (find_user_link(&chptr->chanadmins, who) != NULL)
return 1;
#ifdef REQUIRE_OANDV
if (find_user_link(&chptr->chanops_voiced, who) != NULL)
return 1;

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: channel_mode.c,v 1.2 2002/08/13 14:45:12 fishwaldo Exp $
* $Id: channel_mode.c,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
@ -88,6 +88,10 @@ static void chm_op(struct Client *, struct Client *, struct Channel *, int,
int *, char **, int *, int, int, char, void *,
const char *chname);
static void chm_admin(struct Client *, struct Client *, struct Channel *, int,
int *, char **, int *, int, int, char, void *,
const char *chnamd);
#ifdef HALFOPS
static void chm_halfop(struct Client *, struct Client *, struct Channel *,
int, int *, char **, int *, int, int, char, void *,
@ -123,7 +127,7 @@ static void send_mode_changes(struct Client *, struct Client *,
struct Channel *, char *chname);
static void mode_get_status(struct Channel *, struct Client *, int *, int *,
int *, int);
int *, int *, int);
static void update_channel_info(struct Channel *);
@ -397,6 +401,14 @@ change_channel_membership(struct Channel *chptr,
}
}
#endif
else if ((ptr = find_user_link(&chptr->locchanadmins, who)))
{
if (loc_to_list != &chptr->locchanadmins)
{
dlinkDelete(ptr, &chptr->locchanadmins);
dlinkAdd(who, ptr, loc_to_list);
}
}
else
ok = 0;
}
@ -444,6 +456,14 @@ change_channel_membership(struct Channel *chptr,
dlinkAdd(who, ptr, to_list);
}
}
else if ((ptr = find_user_link(&chptr->chanadmins, who)))
{
if (to_list != &chptr->chanadmins)
{
dlinkDelete(ptr, &chptr->chanadmins);
dlinkAdd(who, ptr, to_list);
}
}
#endif
else
ok = 0;
@ -487,9 +507,11 @@ channel_modes(struct Channel *chptr, struct Client *client_p,
*mbuf++ = 'i';
if (chptr->mode.mode & MODE_NOPRIVMSGS)
*mbuf++ = 'n';
if (chptr->mode.mode & MODE_OPERSONLY)
*mbuf++ = 'O';
#ifdef ANONOPS
if (chptr->mode.mode & MODE_HIDEOPS)
*mbuf++ = 'a';
*mbuf++ = 'A';
#endif
if (chptr->mode.limit)
{
@ -790,11 +812,14 @@ chm_simple(struct Client *client_p, struct Client *source_p,
mode_type = (long)d;
/* dont allow halfops to set +-p, as this controls whether they can set
* +-h or not.. all other simple modes are ok
/* dont allow chanops/halfops to set +-p, as this controls whether they can set
* +-h or +-o .. all other simple modes are ok
*/
/* we also dont allow anyone but Admins to set +A (anonops) or +O (opers only) */
if((alev < CHACCESS_HALFOP) ||
((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
((mode_type == MODE_PRIVATE) && (alev < CHACCESS_ADMIN)) ||
((mode_type == MODE_HIDEOPS) && (alev < CHACCESS_ADMIN)) ||
((mode_type == MODE_OPERSONLY) && (alev < CHACCESS_ADMIN)))
{
if (!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name,
@ -802,7 +827,9 @@ chm_simple(struct Client *client_p, struct Client *source_p,
*errors |= SM_ERR_NOOPS;
return;
}
/* don't allow
/* setting + */
if ((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
{
@ -848,6 +875,8 @@ chm_simple(struct Client *client_p, struct Client *source_p,
}
}
/* anonops slightly changed with NeoIRCd. We only allow channel admins to set or remove it. */
#ifdef ANONOPS
static void
chm_hideops(struct Client *client_p, struct Client *source_p,
@ -861,10 +890,14 @@ chm_hideops(struct Client *client_p, struct Client *source_p,
* have the capab if we support it, so we should never get
* here for a remote server if we dont support it..
*/
if(!ConfigChannel.use_anonops)
if(!ConfigChannel.use_anonops) {
if (*errors & SM_ERR_UNKNOWN)
return;
*errors |= SM_ERR_UNKNOWN;
sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
return;
if (alev < CHACCESS_HALFOP)
}
if (alev < CHACCESS_ADMIN)
{
if (!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name,
@ -1286,6 +1319,136 @@ chm_invex(struct Client *client_p, struct Client *source_p,
}
}
static void
chm_admin(struct Client *client_p, struct Client *source_p,
struct Channel *chptr, int parc, int *parn,
char **parv, int *errors, int alev, int dir, char c, void *d,
const char *chname)
{
int i, wasnt_voiced = 0, t_voice, t_op, t_hop, t_admin;
char *opnick;
struct Client *targ_p;
/* we only allow other chan admins to set +a */
if (alev < CHACCESS_ADMIN)
{
if (!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name,
source_p->name, chname);
*errors |= SM_ERR_NOOPS;
return;
}
if ((dir == MODE_QUERY) || parc <= *parn)
return;
if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
return;
opnick = parv[(*parn)++];
if ((targ_p = find_client(opnick)) == NULL)
{
if (!(*errors & SM_ERR_NOTONCHANNEL))
sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name,
source_p->name, opnick);
*errors |= SM_ERR_NOTONCHANNEL;
return;
}
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, &t_admin, 1);
if (!IsMember(targ_p, chptr))
{
if (!(*errors & SM_ERR_NOTONCHANNEL))
sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), me.name,
source_p->name, chname, opnick);
*errors |= SM_ERR_NOTONCHANNEL;
return;
}
if (((dir == MODE_ADD) && (t_hop || t_op)) ||
((dir == MODE_DEL) && !t_hop))
return;
/* Cancel out all other mode changes... */
for (i = 0; i < mode_count_plus; i++)
if ((mode_changes_plus[i].letter == 'v' || mode_changes_plus[i].letter == 'o' ||
mode_changes_plus[i].letter == 'h')
&& mode_changes_plus[i].client == targ_p)
{
if (mode_changes_plus[i].letter == 'a')
{
mode_changes_plus[i].letter = 0;
return;
}
mode_changes_plus[i].letter = 0;
wasnt_voiced = 1;
}
if (dir == MODE_ADD)
{
for (i = 0; i < mode_count_minus; i++)
if (mode_changes_minus[i].letter == 'a'
&& mode_changes_minus[i].client == targ_p)
{
mode_changes_minus[i].letter = 0;
return;
}
if (!wasnt_voiced && t_voice)
{
mode_changes_minus[mode_count_minus].letter = 'v';
mode_changes_minus[mode_count_minus].caps = 0;
mode_changes_minus[mode_count_minus].nocaps = 0;
mode_changes_minus[mode_count_minus].mems = ONLY_CHANOPS_HALFOPS;
mode_changes_minus[mode_count_minus].id = targ_p->user->id;
mode_changes_minus[mode_count_minus].arg = targ_p->name;
mode_changes_minus[mode_count_minus++].client = targ_p;
}
if (!wasnt_voiced && t_op)
{
mode_changes_minus[mode_count_minus].letter = 'o';
mode_changes_minus[mode_count_minus].caps = 0;
mode_changes_minus[mode_count_minus].nocaps = 0;
mode_changes_minus[mode_count_minus].mems = ONLY_CHANOPS_HALFOPS;
mode_changes_minus[mode_count_minus].id = targ_p->user->id;
mode_changes_minus[mode_count_minus].arg = targ_p->name;
mode_changes_minus[mode_count_minus++].client = targ_p;
}
if (!wasnt_voiced && t_hop)
{
mode_changes_minus[mode_count_minus].letter = 'v';
mode_changes_minus[mode_count_minus].caps = 0;
mode_changes_minus[mode_count_minus].nocaps = 0;
mode_changes_minus[mode_count_minus].mems = ONLY_CHANOPS_HALFOPS;
mode_changes_minus[mode_count_minus].id = targ_p->user->id;
mode_changes_minus[mode_count_minus].arg = targ_p->name;
mode_changes_minus[mode_count_minus++].client = targ_p;
}
mode_changes_plus[mode_count_plus].letter = c;
mode_changes_plus[mode_count_plus].caps = CAP_HOPS;
mode_changes_plus[mode_count_plus].nocaps = 0;
mode_changes_plus[mode_count_plus].mems = ONLY_CHANOPS_HALFOPS;
mode_changes_plus[mode_count_plus].id = targ_p->user->id;
mode_changes_plus[mode_count_plus].arg = targ_p->name;
mode_changes_plus[mode_count_plus++].client = targ_p;
}
else
{ /* MODE_DEL */
mode_changes_minus[mode_count_minus].letter = 'a';
mode_changes_minus[mode_count_minus].caps = CAP_HOPS;
mode_changes_minus[mode_count_minus].nocaps = 0;
mode_changes_minus[mode_count_minus].mems = ONLY_CHANOPS_HALFOPS;
mode_changes_minus[mode_count_minus].id = targ_p->user->id;
mode_changes_minus[mode_count_minus].arg = targ_p->name;
mode_changes_minus[mode_count_minus++].client = targ_p;
}
}
static void
chm_op(struct Client *client_p, struct Client *source_p,
struct Channel *chptr, int parc, int *parn,
@ -1305,14 +1468,17 @@ chm_op(struct Client *client_p, struct Client *source_p,
* -A1kmm.
*/
int wasnt_voiced = 0, t_op, t_hop, t_voice;
int wasnt_voiced = 0, t_op, t_hop, t_voice, t_admin;
char *opnick;
struct Client *targ_p;
#ifdef HALFOPS
int wasnt_hopped = 0;
#endif
if (alev < CHACCESS_CHANOP)
if (alev <
((chptr->mode.mode & MODE_PRIVATE) ?
CHACCESS_ADMIN : CHACCESS_CHANOP))
{
if (!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name,
@ -1355,7 +1521,7 @@ chm_op(struct Client *client_p, struct Client *source_p,
return;
}
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, 1);
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, &t_admin, 1);
if (((dir == MODE_ADD) && t_op) ||
((dir == MODE_DEL) && !t_op
@ -1497,7 +1663,7 @@ chm_halfop(struct Client *client_p, struct Client *source_p,
char **parv, int *errors, int alev, int dir, char c, void *d,
const char *chname)
{
int i, wasnt_voiced = 0, t_voice, t_op, t_hop;
int i, wasnt_voiced = 0, t_voice, t_op, t_hop, t_admin;
char *opnick;
struct Client *targ_p;
@ -1549,7 +1715,7 @@ chm_halfop(struct Client *client_p, struct Client *source_p,
return;
}
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, 1);
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, &t_admin, 1);
if (!IsMember(targ_p, chptr))
{
@ -1667,7 +1833,7 @@ chm_voice(struct Client *client_p, struct Client *source_p,
char **parv, int *errors, int alev, int dir, char c, void *d,
const char *chname)
{
int i, t_op, t_hop, t_voice;
int i, t_op, t_hop, t_voice, t_admin;
char *opnick;
struct Client *targ_p;
@ -1703,8 +1869,8 @@ chm_voice(struct Client *client_p, struct Client *source_p,
return;
}
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, 1);
mode_get_status(chptr, targ_p, &t_op, &t_hop, &t_voice, &t_admin, 1);
if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
return;
@ -1914,7 +2080,7 @@ struct ChannelMode
static struct ChannelMode ModeTable[255] =
{
{chm_nosuch, NULL},
{chm_nosuch, NULL}, /* A */
{chm_hideops, NULL}, /* A */
{chm_nosuch, NULL}, /* B */
{chm_nosuch, NULL}, /* C */
{chm_nosuch, NULL}, /* D */
@ -1928,7 +2094,7 @@ static struct ChannelMode ModeTable[255] =
{chm_nosuch, NULL}, /* L */
{chm_nosuch, NULL}, /* M */
{chm_nosuch, NULL}, /* N */
{chm_nosuch, NULL}, /* O */
{chm_simple, (void *) MODE_OPERSONLY}, /* O */
{chm_nosuch, NULL}, /* P */
{chm_nosuch, NULL}, /* Q */
{chm_nosuch, NULL}, /* R */
@ -1946,11 +2112,7 @@ static struct ChannelMode ModeTable[255] =
{chm_nosuch, NULL},
{chm_nosuch, NULL},
{chm_nosuch, NULL},
#ifdef ANONOPS
{chm_hideops, NULL}, /* a */
#else
{chm_nosuch, NULL}, /* a */
#endif
{chm_admin, NULL}, /* a */
{chm_ban, NULL}, /* b */
{chm_nosuch, NULL}, /* c */
{chm_nosuch, NULL}, /* d */
@ -1998,6 +2160,9 @@ get_channel_access(struct Client *source_p, struct Channel *chptr)
if (!MyClient(source_p))
return CHACCESS_CHANOP;
if (is_chan_admin(chptr, source_p))
return CHACCESS_ADMIN;
if (is_chan_op(chptr, source_p))
return CHACCESS_CHANOP;
@ -2615,6 +2780,9 @@ set_channel_mode_flags(char flags_ptr[NUMLISTS][2], struct Channel *chptr,
flags_ptr[3][0] = '\0';
#ifdef REQUIRE_OANDV
flags_ptr[4][0] = '\0';
flags_ptr[5][0] = '\0';
#else
flags_ptr[4][0] = '\0';
#endif
}
else
@ -2631,13 +2799,15 @@ set_channel_mode_flags(char flags_ptr[NUMLISTS][2], struct Channel *chptr,
#ifdef REQUIRE_OANDV
flags_ptr[4][0] = '@';
#endif
flags_ptr[5][0] = '*';
flags_ptr[0][1] = '\0';
flags_ptr[1][1] = '\0';
flags_ptr[2][1] = '\0';
#ifdef REQUIRE_OANDV
flags_ptr[4][1] = '\0';
#endif
#endif
flags_ptr[5][1] = '\0';
}
}
@ -2667,6 +2837,7 @@ sync_oplists(struct Channel *chptr, struct Client *target_p,
#ifdef REQUIRE_OANDV
send_oplist(name, target_p, &chptr->chanops_voiced, "v", dir);
#endif
send_oplist(name, target_p, &chptr->chanadmins, "a", dir);
}
static void
@ -2739,7 +2910,7 @@ sync_channel_oplists(struct Channel *chptr, int dir)
& is_voiced. Since member status is now changed *after* processing all
modes, we need a special tool to keep track of who is opped, voiced etc. */
static void mode_get_status(struct Channel *chptr, struct Client *target_p,
int *t_op, int *t_hop, int *t_voice, int need_check)
int *t_op, int *t_hop, int *t_voice, int *t_admin, int need_check)
{
int i;
@ -2752,6 +2923,7 @@ static void mode_get_status(struct Channel *chptr, struct Client *target_p,
*t_hop = 0; /* shouldn't be necessary, but... */
#endif
*t_voice = is_voiced(chptr, target_p);
*t_admin = is_chan_admin(chptr, target_p);
}
else {
*t_op = 0;
@ -2772,6 +2944,9 @@ static void mode_get_status(struct Channel *chptr, struct Client *target_p,
#endif
else if (mode_changes_minus[i].letter == 'v')
*t_voice = 0;
else if (mode_changes_minus[i].letter == 'a')
*t_admin = 0;
}
for (i = 0; i < mode_count_plus; i++)
@ -2788,6 +2963,9 @@ static void mode_get_status(struct Channel *chptr, struct Client *target_p,
#endif
else if (mode_changes_plus[i].letter == 'v')
*t_voice = 1;
else if (mode_changes_plus[i].letter == 'a')
*t_admin = 1;
}
}
@ -2795,7 +2973,7 @@ static void update_channel_info(struct Channel *chptr)
{
int i;
#ifdef ANONOPS
int t_voice, t_hop, t_op;
int t_voice, t_hop, t_op, t_admin;
dlink_node *ptr, *ptr_next;
if (hideops_changed == -1)
@ -2808,15 +2986,15 @@ static void update_channel_info(struct Channel *chptr)
for (ptr = chptr->locpeons.head; ptr != NULL && ptr->data != NULL;
ptr = ptr->next)
{
mode_get_status(chptr, ptr->data, &t_op, &t_hop, &t_voice, 0);
if (!t_hop && !t_op)
mode_get_status(chptr, ptr->data, &t_op, &t_hop, &t_voice, &t_admin, 0);
if (!t_hop && !t_op && t_admin)
sync_oplists(chptr, ptr->data, MODE_DEL, RootChan(chptr)->chname);
}
for (ptr = chptr->locvoiced.head; ptr != NULL && ptr->data != NULL;
ptr = ptr->next)
{
mode_get_status(chptr, ptr->data, &t_op, &t_hop, &t_voice, 0);
if (!t_hop && !t_op)
mode_get_status(chptr, ptr->data, &t_op, &t_hop, &t_voice, &t_admin, 0);
if (!t_hop && !t_op && t_admin)
sync_oplists(chptr, ptr->data, MODE_DEL, RootChan(chptr)->chname);
}
@ -2829,7 +3007,7 @@ static void update_channel_info(struct Channel *chptr)
dlink_list deopped = {NULL, NULL};
for (i = 0; i < mode_count_minus; i++)
if ((mode_changes_minus[i].letter == 'o' ||
if ((mode_changes_minus[i].letter == 'o' || mode_changes_minus[i].letter == 'a' ||
mode_changes_minus[i].letter == 'h') &&
MyConnect(mode_changes_minus[i].client))
{
@ -2838,7 +3016,7 @@ static void update_channel_info(struct Channel *chptr)
}
for (i = 0; i < mode_count_plus; i++)
if ((mode_changes_plus[i].letter == 'o' ||
if ((mode_changes_plus[i].letter == 'o' || mode_changes_minus[i].letter == 'a' ||
mode_changes_plus[i].letter == 'h') &&
MyConnect(mode_changes_plus[i].client))
{
@ -2892,6 +3070,15 @@ static void update_channel_info(struct Channel *chptr)
change_channel_membership(chptr, &chptr->peons, &chptr->locpeons,
mode_changes_minus[i].client);
}
else if (mode_changes_minus[i].letter == 'a')
{
if (is_chan_admin(chptr, mode_changes_minus[i].client))
change_channel_membership(chptr, &chptr->chanadmins, &chptr->locchanadmins,
mode_changes_minus[i].client);
else
change_channel_membership(chptr, &chptr->peons, &chptr->locpeons,
mode_changes_minus[i].client);
}
for (i = 0; i < mode_count_plus; i++)
if (mode_changes_plus[i].letter == 'o')
@ -2921,6 +3108,15 @@ static void update_channel_info(struct Channel *chptr)
change_channel_membership(chptr, &chptr->voiced, &chptr->locvoiced,
mode_changes_plus[i].client);
}
else if (mode_changes_plus[i].letter == 'a')
{
if (is_chan_admin(chptr, mode_changes_plus[i].client))
change_channel_membership(chptr, &chptr->chanadmins,
&chptr->locchanadmins, mode_changes_plus[i].client);
else
change_channel_membership(chptr, &chptr->voiced, &chptr->locchanadmins,
mode_changes_plus[i].client);
}
}
#ifdef INTENSIVE_DEBUG

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: client.c,v 1.3 2002/08/14 03:14:27 fishwaldo Exp $
* $Id: client.c,v 1.4 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
#include "config.h"
@ -1159,7 +1159,7 @@ void dead_link(struct Client *client_p)
/* Mark it dead before sending out any notices, just in case this ever goes
* global */
Debug((DEBUG_ERROR, "Closing link to %s: %s", get_client_name(to, HIDE_IP),
Debug((DEBUG_ERROR, "Closing link to %s: %s", get_client_name(client_p, HIDE_IP),
notice));
assert(dlinkFind(&abort_list, client_p) == NULL);
m = make_dlink_node();

View file

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: send.c,v 1.2 2002/08/13 14:45:13 fishwaldo Exp $
* $Id: send.c,v 1.3 2002/08/14 16:52:02 fishwaldo Exp $
*/
#include "stdinc.h"
@ -233,14 +233,14 @@ send_linebuf_remote(struct Client *to, struct Client *from,
sendto_server(NULL, to, NULL, NOCAPS, NOCAPS, NOFLAGS,
":%s KILL %s :%s (%s[%s@%s] Ghosted %s)",
me.name, to->name, me.name, to->name,
to->username, to->host, to->from->name);
to->username, to->vhost, to->from->name);
to->flags |= FLAGS_KILLED;
if (IsPerson(from))
sendto_one(from, form_str(ERR_GHOSTEDCLIENT),
me.name, from->name, to->name, to->username,
to->host, to->from);
to->vhost, to->from);
exit_client(NULL, to, &me, "Ghosted client");
@ -516,7 +516,7 @@ sendto_channel_butone(struct Client *one, struct Client *from,
from->name, command, RootChan(chptr)->chname);
else
linebuf_putmsg(&local_linebuf, pattern, &args, ":%s!%s@%s %s %s ",
from->name, from->username, from->host,
from->name, from->username, from->vhost,
command, RootChan(chptr)->chname);
linebuf_putmsg(&remote_linebuf, pattern, &args, ":%s %s %s ",
@ -548,6 +548,9 @@ sendto_channel_butone(struct Client *one, struct Client *from,
sendto_list_anywhere(one, from, &chptr->peons,
&local_linebuf, &remote_linebuf, &uid_linebuf);
sendto_list_anywhere(one, from, &chptr->chanadmins,
&local_linebuf, &remote_linebuf, &uid_linebuf);
linebuf_donebuf(&local_linebuf);
linebuf_donebuf(&remote_linebuf);
linebuf_donebuf(&uid_linebuf);
@ -747,6 +750,7 @@ sendto_common_channels_local(struct Client *user, const char *pattern, ...)
#endif
sendto_list_local(&chptr->locvoiced, &linebuf);
sendto_list_local(&chptr->locpeons, &linebuf);
sendto_list_local(&chptr->locchanadmins, &linebuf);
}
if (MyConnect(user) && (user->serial != current_serial))
@ -804,6 +808,8 @@ sendto_channel_local(int type,
#ifdef REQUIRE_OANDV
sendto_list_local(&chptr->locchanops_voiced, &linebuf);
#endif
case ONLY_CHANADMIN:
sendto_list_local(&chptr->locchanadmins, &linebuf);
}
linebuf_donebuf(&linebuf);
} /* sendto_channel_local() */
@ -861,6 +867,8 @@ sendto_channel_remote(struct Client *one,
sendto_list_remote(one, from, &chptr->chanops_voiced, caps, nocaps,
&linebuf);
#endif
case ONLY_CHANADMIN:
sendto_list_remote(one, from, &chptr->chanadmins, caps, nocaps, &linebuf);
}
linebuf_donebuf(&linebuf);
} /* sendto_channel_remote() */
@ -1004,7 +1012,7 @@ sendto_match_butone(struct Client *one, struct Client *from,
linebuf_putmsg(&remote_linebuf, pattern, &args, ":%s ", from->name);
linebuf_putmsg(&local_linebuf, pattern, &args, ":%s!%s@%s ", from->name,
from->username, from->host);
from->username, from->vhost);
va_end(args);
@ -1091,7 +1099,7 @@ sendto_anywhere(struct Client *to, struct Client *from,
linebuf_putmsg(&linebuf, pattern, &args, ":%s ", from->name);
else
linebuf_putmsg(&linebuf, pattern, &args, ":%s!%s@%s ", from->name,
from->username, from->host);
from->username, from->vhost);
}
else {
if(IsCapable(to->from, CAP_UID))
@ -1187,7 +1195,7 @@ sendto_wallops_flags(int flags, struct Client *source_p,
if(IsPerson(source_p))
linebuf_putmsg(&linebuf, pattern, &args, ":%s!%s@%s WALLOPS :",
source_p->name, source_p->username, source_p->host);
source_p->name, source_p->username, source_p->vhost);
else
linebuf_putmsg(&linebuf, pattern, &args, ":%s WALLOPS :", source_p->name);