more fixes

This commit is contained in:
zefie
2025-06-16 13:54:15 -04:00
parent 1c3cec5f3a
commit 672877698b

View File

@@ -39,6 +39,8 @@ class WTVIRC {
this.clients = []; this.clients = [];
this.usernames = new Map(); // nickname -> username this.usernames = new Map(); // nickname -> username
this.channels = new Map(); this.channels = new Map();
this.channelkeys = new Map(); // channel -> password
this.channellimits = new Map(); // channel -> limit of users
this.channeltimestamps = new Map(); // channel -> timestamp of creation this.channeltimestamps = new Map(); // channel -> timestamp of creation
this.channelops = new Map(); // channel -> Set of operators this.channelops = new Map(); // channel -> Set of operators
this.channelhalfops = new Map(); // channel -> Set of half-operators this.channelhalfops = new Map(); // channel -> Set of half-operators
@@ -779,29 +781,33 @@ class WTVIRC {
} else if (flags[i] === '+l' || flags[i] === '-l') { } else if (flags[i] === '+l' || flags[i] === '-l') {
// Check if 'l' mode is already present, if not, add it with the limit // Check if 'l' mode is already present, if not, add it with the limit
let chan_modes = this.channelmodes.get(targetUniqueId) || []; let chan_modes = this.channelmodes.get(targetUniqueId) || [];
if (!chan_modes.some(m => /^l\d+$/.test(m))) { if (chan_modes === true) {
// Remove any old l modes, then update if it exists, else add new chan_modes = [];
const limitValue = target; }
const existingIndex = chan_modes.findIndex(m => /^l\d+$/.test(m)); // Check if 'l' mode is already present
if (existingIndex !== -1) { if (flags[i] === '+l') {
chan_modes[existingIndex] = `l${limitValue}`; if (!chan_modes.includes('l')) {
} else { chan_modes.push('l');
chan_modes.push(`l${limitValue}`); this.channelmodes.set(targetUniqueId, chan_modes);
this.channellimits.set(targetUniqueId, target);
} }
this.channelmodes.set(targetUniqueId, chan_modes); } else {
chan_modes = chan_modes.filter(mode => mode !== 'l');
this.channellimits.delete(targetUniqueId);
} }
} else if (flags[i] === '+k' || flags[i] === '-k') { } else if (flags[i] === '+k' || flags[i] === '-k') {
let chan_modes = this.channelmodes.get(targetUniqueId) || []; let chan_modes = this.channelmodes.get(targetUniqueId) || [];
if (!chan_modes || chan_modes === true) { if (!chan_modes || chan_modes === true) {
chan_modes = []; chan_modes = [];
} }
const keyModeIndex = chan_modes.findIndex(m => typeof m === 'string' && m.startsWith('k ')); if (flags[i] === '+k') {
if (keyModeIndex !== -1) { if (!chan_modes.includes('k')) {
// Update existing key chan_modes.push('k');
chan_modes[keyModeIndex] = `k ${target}`; this.channelkeys.set(targetUniqueId, target);
}
} else { } else {
// Add new key mode chan_modes = chan_modes.filter(mode => mode !== 'k');
chan_modes.push(`k ${target}`); this.channelkeys.delete(targetUniqueId);
} }
this.channelmodes.set(targetUniqueId, chan_modes); this.channelmodes.set(targetUniqueId, chan_modes);
} }
@@ -1270,16 +1276,28 @@ class WTVIRC {
return mode; return mode;
}); });
if (chan_modes.length > 0) { if (chan_modes.length > 0) {
var params2 = [];
// Batch all modes into a single 324 reply // Batch all modes into a single 324 reply
const modeString = chan_modes var modeString = chan_modes
.map(m => { .map(m => {
// For modes with parameters (like k <key> or l<limit>) // For modes with parameters (like k <key> or l<limit>)
if (typeof m === 'string' && (m.startsWith('k ') || /^l\d+$/.test(m))) { console.log(m);
return m; if (typeof m === 'string' && (m === '+k' || m === '+l')) {
if (m === '+l') {
params2.push(this.channellimits.get(channel));
} else if (m === '+k') {
params2.push(this.channelkeys.get(channel));
}
return m.replace(/^\+/, '');
} }
return m; return m.replace(/^\+/, ''); // Remove leading '+' for other modes
}) })
.join('').replace(/\+/g, ''); .join('');
params2.forEach(param => {
if (param) {
modeString += ` ${param}`;
}
});
socket.write(`:${this.servername} 324 ${socket.nickname} ${channel} +${modeString}\r\n`); socket.write(`:${this.servername} 324 ${socket.nickname} ${channel} +${modeString}\r\n`);
} else { } else {
socket.write(`:${this.servername} 324 ${socket.nickname} ${channel}\r\n`); socket.write(`:${this.servername} 324 ${socket.nickname} ${channel}\r\n`);
@@ -1453,9 +1471,8 @@ class WTVIRC {
continue; // Skip if no modes are set continue; // Skip if no modes are set
} }
// Check if the user is in too many channels // Check if the user is in too many channels
const keyMode = modes.find(m => typeof m === 'string' && m.startsWith('k ')); if (this.channelmodes.has(ch) && this.channelmodes.get(ch).includes('k')) {
if (keyMode) { const channelKey = this.channelkeys.get(ch);
const channelKey = keyMode.split(' ')[1];
// The key must be provided as the second parameter in the JOIN command // The key must be provided as the second parameter in the JOIN command
// params[1] is the key for the first channel, params[2] for the second, etc. // params[1] is the key for the first channel, params[2] for the second, etc.
// For simplicity, assume only one channel per JOIN or the key is always params[1] // For simplicity, assume only one channel per JOIN or the key is always params[1]
@@ -1465,6 +1482,14 @@ class WTVIRC {
continue; // Skip joining this channel continue; // Skip joining this channel
} }
} }
if (this.channelmodes.has(ch) && this.channelmodes.get(ch).includes('l')) {
// Channel has a user limit (+l)
const limit = this.channellimits.get(ch) || null;
if (limit !== null && this.channels.get(ch).size >= limit) {
socket.write(`:${this.servername} 471 ${socket.nickname} ${ch} :Cannot join channel (+l)\r\n`);
continue; // Skip joining this channel
}
}
if (this.channelmodes.has(ch) && this.channelmodes.get(ch).includes('i')) { if (this.channelmodes.has(ch) && this.channelmodes.get(ch).includes('i')) {
// Channel is invite-only (+i) // Channel is invite-only (+i)
// For simplicity, let's assume you have an invited list per channel (not implemented yet) // For simplicity, let's assume you have an invited list per channel (not implemented yet)
@@ -1501,17 +1526,7 @@ class WTVIRC {
} }
} }
} }
// Check if the channel user limit has been reached
if (this.channelmodes.has(ch) && this.channelmodes.get(ch).includes('l')) {
const limitMatch = this.channelmodes.get(ch).match(/l(\d+)/);
if (limitMatch) {
const limit = parseInt(limitMatch[1], 10);
if (this.channels.has(ch) && this.channels.get(ch).size >= limit) {
socket.write(`:${this.servername} 471 ${socket.nickname} ${ch} :Cannot join channel (+l)\r\n`);
continue; // Skip joining this channel
}
}
}
// If we reach here, the user can join the channel // If we reach here, the user can join the channel
// Reuse the JOIN logic for each channel // Reuse the JOIN logic for each channel
// Only run the code after $PLACEHOLDER$ for each channel // Only run the code after $PLACEHOLDER$ for each channel
@@ -2678,9 +2693,8 @@ class WTVIRC {
if (!chan_modes || chan_modes === true) { if (!chan_modes || chan_modes === true) {
chan_modes = []; chan_modes = [];
} }
// replace limit mode if it exists this.channellimits.set(channel, limit);
chan_modes = chan_modes.filter(m => !/^l\d+$/.test(m)); this.channelmodes.set(channel, [...chan_modes, 'l']);
this.channelmodes.set(channel, [...chan_modes, `l${limit}`]);
this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} +l ${limit}\r\n`); this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} +l ${limit}\r\n`);
return; return;
} else if (mode.startsWith('-l')) { } else if (mode.startsWith('-l')) {
@@ -2692,7 +2706,8 @@ class WTVIRC {
if (!chan_modes || chan_modes === true) { if (!chan_modes || chan_modes === true) {
chan_modes = []; chan_modes = [];
} }
this.channelmodes.set(channel, (chan_modes).filter(m => !/^l\d+$/.test(m))); this.channellimits.delete(channel);
this.channelmodes.set(channel, (chan_modes).filter(m => m !== 'l'));
this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} -l\r\n`); this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} -l\r\n`);
return; return;
} else if (mode.startsWith('+k')) { } else if (mode.startsWith('+k')) {
@@ -2709,7 +2724,9 @@ class WTVIRC {
if (!chan_modes || chan_modes === true) { if (!chan_modes || chan_modes === true) {
chan_modes = []; chan_modes = [];
} }
this.channelmodes.set(channel, [...chan_modes, `k ${key}`]); // replace key mode if it exists
this.channelkeys.set(channel, key);
this.channelmodes.set(channel, [...chan_modes, 'k']);
this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} +k ${key}\r\n`); this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} +k ${key}\r\n`);
return; return;
} else if (mode.startsWith('-k')) { } else if (mode.startsWith('-k')) {
@@ -2717,7 +2734,8 @@ class WTVIRC {
if (!chan_modes || chan_modes === true) { if (!chan_modes || chan_modes === true) {
chan_modes = []; chan_modes = [];
} }
this.channelmodes.set(channel, (chan_modes).filter(m => !/^k.*$/.test(m))); this.channelkeys.delete(channel);
this.channelmodes.set(channel, (chan_modes).filter(m => m !== 'k'));
this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} -k\r\n`); this.broadcastChannel(channel, `:${nickname}!${username}@${socket.host} MODE ${channel} -k\r\n`);
return; return;
} else if (mode.startsWith('+i')) { } else if (mode.startsWith('+i')) {