mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-09-06 21:24:37 +08:00
added basic support for MODE, TOPIC
This commit is contained in:
parent
05deaab46e
commit
e9923ebe12
2 changed files with 207 additions and 10 deletions
32
indexes.yaml
32
indexes.yaml
|
@ -369,19 +369,47 @@ indexes:
|
|||
|
||||
# Indexes for IRC
|
||||
|
||||
- collection: chat
|
||||
index:
|
||||
name: ns_nicks
|
||||
key:
|
||||
_id: 1
|
||||
rcpt: 1
|
||||
|
||||
- collection: nicks
|
||||
index:
|
||||
name: irc_nicks
|
||||
name: ns_nicks
|
||||
unique: true
|
||||
key:
|
||||
ns: 1
|
||||
nickview: 1
|
||||
|
||||
- collection: nicks
|
||||
index:
|
||||
name: user_nick
|
||||
key:
|
||||
user: 1
|
||||
|
||||
- collection: channels
|
||||
index:
|
||||
name: irc_channels
|
||||
name: ns_channels
|
||||
unique: true
|
||||
key:
|
||||
ns: 1
|
||||
channelview: 1
|
||||
|
||||
- collection: channels
|
||||
index:
|
||||
name: channel_members
|
||||
unique: true
|
||||
key:
|
||||
ns: 1
|
||||
channelview: 1
|
||||
members: 1
|
||||
|
||||
- collection: channels
|
||||
index:
|
||||
name: user_channel
|
||||
unique: true
|
||||
key:
|
||||
members: 1
|
||||
|
|
|
@ -122,6 +122,11 @@ class IRCConnection extends EventEmitter {
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'topic': {
|
||||
this.send({ time: data.topicTime, source: data.topicAuthor, verb: 'TOPIC', target: data.channel, message: data.topic });
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -228,8 +233,8 @@ class IRCConnection extends EventEmitter {
|
|||
}
|
||||
this.lastFetchedItem = message._id;
|
||||
|
||||
if (message.channel && message.session.toString() === this.session.id.toString()) {
|
||||
// ignore messages from self
|
||||
if (message.channel && message.session.toString() === this.session.id.toString() && !this.capEnabled.has('echo-message')) {
|
||||
// ignore messages from self unless echo-message
|
||||
return setImmediate(processNext);
|
||||
}
|
||||
|
||||
|
@ -334,7 +339,7 @@ class IRCConnection extends EventEmitter {
|
|||
message = message.concat(payload.params || []);
|
||||
}
|
||||
|
||||
if (payload.message) {
|
||||
if (payload.message || typeof payload.message === 'string') {
|
||||
message.push(':' + payload.message);
|
||||
}
|
||||
|
||||
|
@ -542,7 +547,7 @@ class IRCConnection extends EventEmitter {
|
|||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter(arg => arg);
|
||||
if (data) {
|
||||
if (data || typeof data === 'string') {
|
||||
params.push(data);
|
||||
}
|
||||
|
||||
|
@ -618,6 +623,12 @@ class IRCConnection extends EventEmitter {
|
|||
|
||||
this.send({ source: this.getFormattedName(), verb: 'JOIN', target: false, message: channelData.channel });
|
||||
|
||||
if (channelData.topic) {
|
||||
let topicTime = Math.round((channelData.topicTime || new Date()).getTime() / 1000);
|
||||
this.send({ verb: 'RPL_TOPIC', params: channelData.channel, message: channelData.topic });
|
||||
this.send({ verb: 'RPL_TOPICWHOTIME', params: [channelData.channel, channelData.topicAuthor, topicTime] });
|
||||
}
|
||||
|
||||
lines.forEach(line => {
|
||||
this.send({ verb: 'RPL_NAMREPLY', params: ['=', channelData.channel], message: line.members.join(' ') });
|
||||
});
|
||||
|
@ -700,7 +711,10 @@ class IRCConnection extends EventEmitter {
|
|||
.project({
|
||||
_id: true,
|
||||
channel: true,
|
||||
members: true
|
||||
members: true,
|
||||
topic: true,
|
||||
topicTime: true,
|
||||
topicAuthor: true
|
||||
})
|
||||
.toArray((err, channels) => {
|
||||
if (err) {
|
||||
|
@ -1124,7 +1138,10 @@ class IRCConnection extends EventEmitter {
|
|||
}, {
|
||||
fields: {
|
||||
_id: true,
|
||||
channel: true
|
||||
channel: true,
|
||||
topic: true,
|
||||
topicTime: true,
|
||||
topicAuthor: true
|
||||
}
|
||||
}, (err, channelData) => {
|
||||
if (err) {
|
||||
|
@ -1166,6 +1183,7 @@ class IRCConnection extends EventEmitter {
|
|||
});
|
||||
}
|
||||
|
||||
let time = new Date();
|
||||
channelData = {
|
||||
_id: new ObjectID(),
|
||||
channel,
|
||||
|
@ -1173,7 +1191,11 @@ class IRCConnection extends EventEmitter {
|
|||
ns: this.session.ns,
|
||||
mode: [],
|
||||
owner: this.session.auth.id,
|
||||
members: [this.session.auth.id]
|
||||
members: [this.session.auth.id],
|
||||
time,
|
||||
topic: '',
|
||||
topicTime: time,
|
||||
topicAuthor: ''
|
||||
};
|
||||
|
||||
db.database.collection('channels').insertOne(channelData, err => {
|
||||
|
@ -1397,7 +1419,7 @@ class IRCConnection extends EventEmitter {
|
|||
return next();
|
||||
}
|
||||
|
||||
let allowed = ['sasl', 'server-time', 'znc.in/server-time'];
|
||||
let allowed = ['sasl', 'server-time', 'znc.in/server-time', 'echo-message'];
|
||||
|
||||
this.capStarted = true;
|
||||
let subcommand = params
|
||||
|
@ -1587,6 +1609,153 @@ class IRCConnection extends EventEmitter {
|
|||
|
||||
return next();
|
||||
}
|
||||
|
||||
command_MODE(tags, prefix, params, next) {
|
||||
if (!this.session.user || !this.session.nick) {
|
||||
this.send({ verb: 'ERR_NOTREGISTERED', params: 'JOIN', message: 'You have not registered' });
|
||||
return next();
|
||||
}
|
||||
|
||||
let channel = params[0].trim();
|
||||
if (channel.length < 2 || !/^[#&]/.test(channel) || /[#&\s]/.test(channel.substr(1))) {
|
||||
this.send({ verb: 'ERR_NOSUCHCHANNEL', params: channel, message: 'No such channel' });
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!this.checkAuth()) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (params.length > 1) {
|
||||
this.send({ verb: 'ERR_CHANOPRIVSNEEDED', params: channel, message: 'You are not channel operator' });
|
||||
return next();
|
||||
}
|
||||
|
||||
db.database.collection('channels').findOne({
|
||||
ns: this.session.ns,
|
||||
channelview: channel.toLowerCase().replace(/\./g, '')
|
||||
}, {
|
||||
fields: {
|
||||
_id: true,
|
||||
mode: true,
|
||||
time: true
|
||||
}
|
||||
}, (err, channelData) => {
|
||||
if (err) {
|
||||
this.send({ verb: 'ERR_FILEERROR', params: channel, message: err.message });
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!channelData) {
|
||||
this.send({ verb: 'ERR_NOSUCHCHANNEL', params: channel, message: 'No such channel' });
|
||||
return next();
|
||||
}
|
||||
|
||||
let channelTime = Math.round((channelData.time || new Date()).getTime() / 1000);
|
||||
|
||||
this.send({ verb: 'RPL_CHANNELMODEIS', params: [channel, '+'] });
|
||||
this.send({ verb: 'RPL_CREATIONTIME', params: [channel, channelTime] });
|
||||
|
||||
return next();
|
||||
});
|
||||
}
|
||||
|
||||
command_TOPIC(tags, prefix, params, next) {
|
||||
if (!this.session.user || !this.session.nick) {
|
||||
this.send({ verb: 'ERR_NOTREGISTERED', params: 'JOIN', message: 'You have not registered' });
|
||||
return next();
|
||||
}
|
||||
|
||||
let channel = params[0].trim();
|
||||
if (channel.length < 2 || !/^[#&]/.test(channel) || /[#&\s]/.test(channel.substr(1))) {
|
||||
this.send({ verb: 'ERR_NOSUCHCHANNEL', params: channel, message: 'No such channel' });
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!this.checkAuth()) {
|
||||
return next();
|
||||
}
|
||||
|
||||
let newTopic = params
|
||||
.slice(1)
|
||||
.join(' ')
|
||||
.trim();
|
||||
|
||||
if (params.length < 2) {
|
||||
db.database.collection('channels').findOne({
|
||||
ns: this.session.ns,
|
||||
channelview: channel.toLowerCase().replace(/\./g, '')
|
||||
}, {
|
||||
fields: {
|
||||
_id: true,
|
||||
topic: true,
|
||||
topicTime: true,
|
||||
topicAuthor: true
|
||||
}
|
||||
}, (err, channelData) => {
|
||||
if (err) {
|
||||
this.send({ verb: 'ERR_FILEERROR', params: channel, message: err.message });
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!channelData) {
|
||||
this.send({ verb: 'ERR_NOSUCHCHANNEL', params: channel, message: 'No such channel' });
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!channelData.topic) {
|
||||
this.send({ verb: 'RPL_NOTOPIC', params: channel, message: 'No topic is set' });
|
||||
return next();
|
||||
}
|
||||
|
||||
let topicTime = Math.round((channelData.topicTime || new Date()).getTime() / 1000);
|
||||
|
||||
this.send({ verb: 'RPL_TOPIC', params: channel, message: channelData.topic });
|
||||
this.send({ verb: 'RPL_TOPICWHOTIME', params: [channel, channelData.topicAuthor, topicTime] });
|
||||
|
||||
return next();
|
||||
});
|
||||
} else {
|
||||
let topicTime = new Date();
|
||||
let topicAuthor = this.getFormattedName();
|
||||
|
||||
return db.database.collection('channels').findOneAndUpdate({
|
||||
ns: this.session.ns,
|
||||
channelview: channel.toLowerCase().replace(/\./g, '')
|
||||
}, {
|
||||
$set: {
|
||||
topic: newTopic,
|
||||
topicAuthor,
|
||||
topicTime
|
||||
}
|
||||
}, {
|
||||
returnOriginal: false
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
this.send({ verb: 'ERR_FILEERROR', params: channel, message: err.message });
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!result || !result.value) {
|
||||
this.send({ verb: 'ERR_NOSUCHCHANNEL', params: channel, message: 'Could not open channel' });
|
||||
return next();
|
||||
}
|
||||
|
||||
let channelData = result.value;
|
||||
|
||||
this.publish([this.session.ns, '#', channelData._id].join('.'), {
|
||||
action: 'topic',
|
||||
channel: channelData.channel,
|
||||
session: this.session.id.toString(),
|
||||
channelId: channelData._id.toString(),
|
||||
topic: newTopic,
|
||||
topicAuthor,
|
||||
topicTime
|
||||
});
|
||||
next();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IRCConnection;
|
||||
|
|
Loading…
Add table
Reference in a new issue