Skip to content
Draft
1 change: 1 addition & 0 deletions include/capab.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum Capab {
_CAP(AWAYNOTIFY, 0, "away-notify", 0),
_CAP(ACCNOTIFY, 0, "account-notify", 0),
_CAP(SASL, 0, "sasl", 0),
_CAP(DRAFT_CHANRENAME, 0, "draft/channel-rename", 0),
#ifdef USE_SSL
_CAP(TLS, 0, "tls", 0),
#endif
Expand Down
10 changes: 10 additions & 0 deletions include/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,16 @@ extern int IsInvited(struct Client* cptr, const void* chptr);
extern void send_channel_modes(struct Client *cptr, struct Channel *chptr);
extern char *pretty_mask(char *mask);
extern char *pretty_extmask(char *mask);
extern int rename_channel(struct Channel **chptr_p, const char *newname);

/* Pending channel-rename requests (defined in m_rename.c; consumed by the
* ACCOUNT A/D reply path in m_account.c and client exit in s_misc.c). */
struct PendingRename;
extern struct PendingRename *pending_rename_find(unsigned int cookie);
extern void pending_rename_complete(struct PendingRename *pr);
extern void pending_rename_deny(struct PendingRename *pr, const char *reason);
extern void pending_rename_client_exit(struct Client *cptr);

extern void del_invite(struct Client *cptr, struct Channel *chptr);
extern void list_set_default(void); /* this belongs elsewhere! */

Expand Down
5 changes: 5 additions & 0 deletions include/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ enum Flag
FLAG_IPV6, /**< server understands P10 IPv6 addrs */
FLAG_SERVICE, /**< server is a service */
FLAG_OPLEVELS, /**< server has oplevels support */
FLAG_RENAME_CAPABLE, /**< server applies and relays RENAME */
FLAG_GOTID, /**< successful ident lookup achieved */
FLAG_DOID, /**< I-lines say must use ident return */
FLAG_NONL, /**< No \n in buffer */
Expand Down Expand Up @@ -735,6 +736,8 @@ struct Client {
#define IsService(x) HasFlag(x, FLAG_SERVICE)
/** Return non-zero if the client has oplevels support. */
#define IsOpLevels(x) HasFlag(x, FLAG_OPLEVELS)
/** Return non-zero if the client applies and relays RENAME. */
#define IsRenameCapable(x) HasFlag(x, FLAG_RENAME_CAPABLE)
/** Return non-zero if the client has an account stamp. */
#define IsAccount(x) HasFlag(x, FLAG_ACCOUNT)
/** Return non-zero if the client has set mode +x (hidden host). */
Expand Down Expand Up @@ -855,6 +858,8 @@ struct Client {
#define SetService(x) SetFlag(x, FLAG_SERVICE)
/** Mark a client as having oplevels support. */
#define SetOpLevels(x) SetFlag(x, FLAG_OPLEVELS)
/** Mark a client as applying and relaying RENAME. */
#define SetRenameCapable(x) SetFlag(x, FLAG_RENAME_CAPABLE)
/** Mark a client as having an account stamp. */
#define SetAccount(x) SetFlag(x, FLAG_ACCOUNT)
/** Mark a client as having mode +x (hidden host). */
Expand Down
2 changes: 2 additions & 0 deletions include/handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ extern int m_protoctl(struct Client*, struct Client*, int, char*[]);
extern int m_pseudo(struct Client*, struct Client*, int, char*[]);
extern int m_quit(struct Client*, struct Client*, int, char*[]);
extern int m_registered(struct Client*, struct Client*, int, char*[]);
extern int m_rename(struct Client*, struct Client*, int, char*[]);
extern int m_rules(struct Client*, struct Client*, int, char*[]);
extern int m_sethost(struct Client*, struct Client*, int, char*[]);
extern int m_shun(struct Client*, struct Client*, int, char*[]);
Expand Down Expand Up @@ -237,6 +238,7 @@ extern int ms_privs(struct Client*, struct Client*, int, char*[]);
extern int ms_quit(struct Client*, struct Client*, int, char*[]);
extern int ms_rehash(struct Client*, struct Client*, int, char*[]);
extern int ms_remove(struct Client*, struct Client*, int, char*[]);
extern int ms_rename(struct Client*, struct Client*, int, char*[]);
extern int ms_rping(struct Client*, struct Client*, int, char*[]);
extern int ms_rpong(struct Client*, struct Client*, int, char*[]);
extern int ms_rules(struct Client*, struct Client*, int, char*[]);
Expand Down
1 change: 1 addition & 0 deletions include/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ extern int hAddWatch(struct Watch *wptr);
extern int hRemClient(struct Client *cptr);
extern int hChangeClient(struct Client *cptr, const char *newname);
extern int hRemChannel(struct Channel *chptr);
extern int hChangeChannel(struct Channel *chptr, const char *newname);
extern int hRemWatch(struct Watch *wptr);
extern struct Client *hSeekClient(const char *name, int TMask);
extern struct Channel *hSeekChannel(const char *name);
Expand Down
2 changes: 2 additions & 0 deletions include/ircd_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ enum Feature {
FEAT_CAP_away_notify,
FEAT_CAP_account_notify,
FEAT_CAP_sasl,
FEAT_CAP_draft_channel_rename,
FEAT_RENAME_SERVICES,
#ifdef USE_SSL
FEAT_CAP_tls,
#endif
Expand Down
4 changes: 4 additions & 0 deletions include/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ struct Client;
#define TOK_ACCOUNT "AC"
#define CMD_ACCOUNT MSG_ACCOUNT, TOK_ACCOUNT

#define MSG_RENAME "RENAME" /* RENA */
#define TOK_RENAME "RN"
#define CMD_RENAME MSG_RENAME, TOK_RENAME

#define MSG_ASLL "ASLL" /* ASLL */
#define TOK_ASLL "LL"
#define CMD_ASLL MSG_ASLL, TOK_ASLL
Expand Down
4 changes: 4 additions & 0 deletions include/send.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,8 @@ extern void sendto_mode_butone(struct Client *one, struct Client *from, const ch
extern void vsendto_mode_butone(struct Client *one, struct Client *from, const char *mode,
const char *pattern, va_list vl);

/* IRCv3 standard-replies FAIL line (tag-free minimal form) */
extern void send_fail(struct Client *to, const char *command, const char *code,
const char *context, const char *description);

#endif /* INCLUDED_send_h */
8 changes: 8 additions & 0 deletions ircd/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ IRCD_SRC = \
m_quit.c \
m_rehash.c \
m_remove.c \
m_rename.c \
m_reset.c \
m_restart.c \
m_rping.c \
Expand Down Expand Up @@ -888,6 +889,13 @@ m_remove.o: m_remove.c ../config.h ../include/client.h ../include/gline.h \
../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
../include/numeric.h ../include/numnicks.h ../include/send.h \
../include/shun.h ../include/zline.h
m_rename.o: m_rename.c ../config.h ../include/channel.h \
../include/client.h ../include/hash.h ../include/ircd.h \
../include/ircd_events.h ../include/ircd_features.h ../include/ircd_log.h \
../include/ircd_reply.h ../include/ircd_snprintf.h ../include/ircd_string.h \
../include/ircd_alloc.h ../include/list.h ../include/msg.h \
../include/numeric.h ../include/numnicks.h ../include/s_user.h \
../include/send.h
m_reset.o: m_reset.c ../config.h ../include/client.h ../include/hash.h \
../include/ircd.h ../include/ircd_features.h ../include/ircd_log.h \
../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \
Expand Down
89 changes: 89 additions & 0 deletions ircd/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,95 @@ struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType fl
return chptr;
}

/** Rename a channel.
* Updates the channel name in the hash table and channel structure.
* Reallocates the channel structure if the new name is longer.
*
* @param[in,out] chptr_p Pointer to channel pointer. Updated if reallocation occurs.
* @param[in] newname New name for the channel.
* @return 0 on success, -1 if invalid params, -2 if new name exists.
*/
int rename_channel(struct Channel **chptr_p, const char *newname)
{
struct Channel *chptr;
size_t oldlen, newlen;
struct Channel *newchptr;
struct Membership *member;
struct SLink *link;

if (!chptr_p || !*chptr_p || !newname || !*newname)
return -1;

chptr = *chptr_p;

newlen = strlen(newname);
if (newlen > CHANNELLEN)
return -1;

/* Check if new name already exists */
if (FindChannel(newname))
return -2;

oldlen = strlen(chptr->chname);

/* If new name fits in existing allocation, just update in place */
if (newlen <= oldlen) {
hChangeChannel(chptr, newname);
strcpy(chptr->chname, newname);
return 0;
}

/* New name is longer - need to reallocate */
newchptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + newlen);
if (!newchptr)
return -1;

/* Copy all data from old to new */
memcpy(newchptr, chptr, sizeof(struct Channel));
strcpy(newchptr->chname, newname);

/* Update hash table */
hRemChannel(chptr);
hAddChannel(newchptr);

/* Update global linked list */
if (chptr->prev)
chptr->prev->next = newchptr;
else
GlobalChannelList = newchptr;
if (chptr->next)
chptr->next->prev = newchptr;

/* Update all membership pointers */
for (member = newchptr->members; member; member = member->next_member)
member->channel = newchptr;

/* Update user invite lists that point to this channel */
for (link = newchptr->invites; link; link = link->next) {
struct Client *cptr = link->value.cptr;
struct SLink *inv;
/* Find and update user's invite pointer to this channel */
for (inv = cli_user(cptr)->invited; inv; inv = inv->next) {
if (inv->value.chptr == chptr) {
inv->value.chptr = newchptr;
break;
}
}
}

/* Update destruct event if pending */
if (newchptr->destruct_event)
newchptr->destruct_event->chptr = newchptr;

/* Free old channel structure */
MyFree(chptr);

/* Update caller's pointer */
*chptr_p = newchptr;

return 0;
}

/** invite a user to a channel.
*
* Adds an invite for a user to a channel. Limits the number of invites
Expand Down
17 changes: 17 additions & 0 deletions ircd/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,23 @@ int hRemChannel(struct Channel *chptr)
return -1;
}

/** Rename a channel in the hash table.
* @param[in] chptr Channel whose name is changing.
* @param[in] newname New name for channel.
* @return Zero on success.
*/
int hChangeChannel(struct Channel *chptr, const char *newname)
{
HASHREGS newhash = strhash(newname);

assert(0 != chptr);
hRemChannel(chptr);

chptr->hnext = channelTable[newhash];
channelTable[newhash] = chptr;
return 0;
}

/** Find a client by name, filtered by status mask.
* If a client is found, it is moved to the top of its hash bucket.
* @param[in] name Client name to search for.
Expand Down
4 changes: 4 additions & 0 deletions ircd/ircd.c
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,10 @@ int main(int argc, char **argv) {

hAddClient(&me);
SetIPv6(&me);
/* We advertise the 'r' (rename-capable) SERVER flag on our own SERVER
* lines; mirror it locally so scans over GlobalClientList (which
* includes &me) see this server as rename-capable too. */
SetRenameCapable(&me);

write_pidfile();
init_counters();
Expand Down
6 changes: 6 additions & 0 deletions ircd/ircd_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,12 @@ static struct FeatureDesc {
F_B(CAP_away_notify, 0, 1, 0),
F_B(CAP_account_notify, 0, 1, 0),
F_B(CAP_sasl, 0, 1, 0),
F_B(CAP_draft_channel_rename, 0, 0, 0),
/* Off by default: only a services build that disambiguates RENAME
* requests from account-stamp notifications on the AC 'R' subcommand
* (see the protocol-history comment in m_rename.c) should have this
* enabled. */
F_B(RENAME_SERVICES, 0, 0, 0),
#ifdef USE_SSL
F_B(CAP_tls, 0, 1, 0),
#endif
Expand Down
37 changes: 33 additions & 4 deletions ircd/m_account.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
*/
#include "config.h"

#include "channel.h"
#include "client.h"
#include "ircd.h"
#include "ircd_alloc.h"
Expand Down Expand Up @@ -241,12 +242,40 @@ int ms_account(struct Client* cptr, struct Client* sptr, int parc,
parv[1], parv[2], parv[3], parv[4], parv[5]);
return 0;
} else if (type == 'A' || type == 'D') {
/* LOC Replies (A=accept, D=deny) */
if (parc < 4)
/* LOC Replies (A=accept, D=deny) or Rename Permission Replies */
if (parc < 3)
return need_more_params(sptr, "ACCOUNT");

if (!(acptr = FindNServer(parv[1])))
return 0; /* target not online, ignore */
/* Rename reply carries the explicit RENAME discriminator (parv[3]);
* route by cookie without FindNServer so a decimal cookie can't
* alias a server numeric (F2). */
if (parc > 3 && !ircd_strcmp(parv[3], "RENAME")) {
unsigned int cookie = atoi(parv[1]);
struct PendingRename *pr = pending_rename_find(cookie);

if (pr) {
if (type == 'A') {
Debug((DEBUG_DEBUG, "ACCOUNT rename allow cookie=%u", cookie));
pending_rename_complete(pr);
} else {
/* Deny response: parv[4] contains the reason (trailing param) */
const char *reason = (parc > 4) ? parv[4] : "Permission denied";
Debug((DEBUG_DEBUG, "ACCOUNT rename deny cookie=%u reason=%s", cookie, reason));
pending_rename_deny(pr, reason);
}
}
return 0;
}

/* First check if this is a server numeric (LOC reply) */
acptr = FindNServer(parv[1]);

if (!acptr)
return 0; /* unknown numeric - ignore */

/* LOC reply - need at least 4 params */
if (parc < 4)
return need_more_params(sptr, "ACCOUNT");

if (!IsMe(acptr)) {
/* in-transit message, forward it */
Expand Down
1 change: 1 addition & 0 deletions ircd/m_cap.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static struct capabilities {
_CAP(AWAYNOTIFY, 0, "away-notify", FEAT_CAP_away_notify),
_CAP(ACCNOTIFY, 0, "account-notify", FEAT_CAP_account_notify),
_CAP(SASL, 0, "sasl", FEAT_CAP_sasl),
_CAP(DRAFT_CHANRENAME, 0, "draft/channel-rename", FEAT_CAP_draft_channel_rename),
#ifdef USE_SSL
_CAP(TLS, 0, "tls", FEAT_CAP_tls),
#endif
Expand Down
Loading