Files
bare-operating-system/packages/bare-os-coreutils/lib/irc-commands.js
T
Raven Scott 8bb8254c42
Release rolling / release (push) Canceled after 8m43s
IRC Commands
2026-08-13 00:33:57 -04:00

501 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Slash-command table for /bin/irc (modern client + common aliases). */
var BARE_IRC_FEATURED_ROOMS = [
{ name: '#libera', users: '', topic: 'Official Libera.Chat help' },
{ name: '#linux', users: '', topic: 'Linux discussion' },
{ name: '#programming', users: '', topic: 'Programming' },
{ name: '#javascript', users: '', topic: 'JavaScript' },
{ name: '#python', users: '', topic: 'Python' },
{ name: '#rust', users: '', topic: 'Rust' },
{ name: '#archlinux', users: '', topic: 'Arch Linux' },
{ name: '#debian', users: '', topic: 'Debian' },
{ name: '#ubuntu', users: '', topic: 'Ubuntu' },
{ name: '#vim', users: '', topic: 'Vim' },
{ name: '#emacs', users: '', topic: 'Emacs' },
{ name: '#git', users: '', topic: 'Git' }
]
function bareIrcNeedTarget(buf) {
return buf && buf.kind && buf.kind !== 'server' ? buf.name : ''
}
function bareIrcModeNicks(client, chan, flag, nicks) {
if (!chan || !nicks.length) return false
var i
for (i = 0; i < nicks.length; i++) {
client.sendRaw('MODE', [chan, flag, nicks[i]])
}
return true
}
function bareIrcRunSlash(client, rawLine, opts) {
opts = opts || {}
var buf = opts.buf || null
var ctx = opts.ctx
var line = String(rawLine || '').trim()
var out = {
ok: true,
help: false,
rooms: false,
roomsQuery: '',
quit: false,
close: false,
clear: false,
usage: '',
note: ''
}
if (!line || line.charAt(0) !== '/') {
out.ok = false
return out
}
var body = line.slice(1)
var sp = body.search(/\s/)
var cmd = (sp < 0 ? body : body.slice(0, sp)).toLowerCase()
var rest = sp < 0 ? '' : body.slice(sp + 1).trim()
var parts = rest ? rest.split(/\s+/) : []
var chan = bareIrcNeedTarget(buf)
if (cmd === 'help' || cmd === 'h' || cmd === '?') {
out.help = true
return out
}
if (cmd === 'quit' || cmd === 'exit') {
client.quit(rest || 'Leaving')
out.quit = true
return out
}
if (cmd === 'disconnect') {
client.quit(rest || 'Disconnect')
return out
}
if (cmd === 'reconnect') {
if (opts.reconnect) opts.reconnect()
else out.note = 'reconnect unavailable'
return out
}
if (cmd === 'join' || cmd === 'j') {
if (!parts[0]) {
out.usage = '/join #channel [key]'
return out
}
client.join(parts[0], parts[1])
return out
}
if (cmd === 'part' || cmd === 'leave') {
var pchan = parts[0] && parts[0].charAt(0) === '#' ? parts.shift() : chan
if (!pchan) {
out.usage = '/part [#channel] [reason]'
return out
}
client.part(pchan, parts.join(' '))
return out
}
if (cmd === 'cycle' || cmd === 'hop') {
var cchan = parts[0] || chan
if (!cchan) {
out.usage = '/cycle [#channel]'
return out
}
client.part(cchan, 'cycling')
client.join(cchan)
return out
}
if (cmd === 'query' || cmd === 'q') {
if (!parts[0]) {
out.usage = '/query NICK [text]'
return out
}
var qb = bareIrcEnsureBuffer(client.state, 'query', parts[0])
client.state.currentId = qb.id
if (parts.slice(1).join(' '))
client.sendPrivmsg(parts[0], parts.slice(1).join(' '))
return out
}
if (cmd === 'msg' || cmd === 'privmsg' || cmd === 'm') {
if (!parts[0] || !parts.slice(1).join(' ')) {
out.usage = '/msg TARGET text'
return out
}
client.sendPrivmsg(parts[0], parts.slice(1).join(' '))
return out
}
if (cmd === 'notice') {
if (!parts[0] || !parts.slice(1).join(' ')) {
out.usage = '/notice TARGET text'
return out
}
client.sendRaw('NOTICE', [parts[0], parts.slice(1).join(' ')])
return out
}
if (cmd === 'nick') {
if (!parts[0]) {
out.usage = '/nick NEWNICK'
return out
}
client.sendRaw('NICK', [parts[0]])
return out
}
if (cmd === 'whois') {
if (!parts[0]) {
out.usage = '/whois NICK'
return out
}
client.sendRaw(
'WHOIS',
parts.length > 1 ? [parts[0], parts[1]] : [parts[0]]
)
return out
}
if (cmd === 'whowas') {
if (!parts[0]) {
out.usage = '/whowas NICK'
return out
}
client.sendRaw('WHOWAS', [parts[0]])
return out
}
if (cmd === 'who') {
client.sendRaw('WHO', [parts[0] || chan || '*'])
return out
}
if (cmd === 'names') {
client.sendRaw('NAMES', [parts[0] || chan || ''].filter(Boolean))
return out
}
if (cmd === 'topic') {
var tchan = chan
var topic = rest
if (
parts[0] &&
(parts[0].charAt(0) === '#' || parts[0].charAt(0) === '&')
) {
tchan = parts[0]
topic = parts.slice(1).join(' ')
}
if (!tchan) {
out.usage = '/topic [#channel] [text]'
return out
}
if (topic) client.sendRaw('TOPIC', [tchan, topic])
else client.sendRaw('TOPIC', [tchan])
return out
}
if (cmd === 'me' || cmd === 'action') {
if (!rest || !chan) {
out.usage = '/me action text (in a channel or query)'
return out
}
client.sendPrivmsg(chan, '\x01ACTION ' + rest + '\x01')
return out
}
if (cmd === 'away') {
client.sendRaw('AWAY', rest ? [rest] : [])
return out
}
if (cmd === 'back') {
client.sendRaw('AWAY', [])
return out
}
if (cmd === 'quote' || cmd === 'raw') {
if (!rest) {
out.usage = '/quote COMMAND [params]'
return out
}
var qparts = rest.split(/\s+/)
client.sendRaw(qparts[0], qparts.slice(1))
return out
}
if (cmd === 'list' || cmd === 'rooms' || cmd === 'browse') {
out.rooms = true
out.roomsQuery = rest
return out
}
if (cmd === 'motd') {
client.sendRaw('MOTD', parts[0] ? [parts[0]] : [])
return out
}
if (cmd === 'lusers') {
client.sendRaw('LUSERS', parts)
return out
}
if (cmd === 'admin') {
client.sendRaw('ADMIN', parts[0] ? [parts[0]] : [])
return out
}
if (cmd === 'info') {
client.sendRaw('INFO', parts[0] ? [parts[0]] : [])
return out
}
if (cmd === 'time') {
client.sendRaw('TIME', parts[0] ? [parts[0]] : [])
return out
}
if (cmd === 'links') {
client.sendRaw('LINKS', parts)
return out
}
if (cmd === 'map') {
client.sendRaw('MAP', [])
return out
}
if (cmd === 'rules') {
client.sendRaw('RULES', [])
return out
}
if (cmd === 'stats') {
client.sendRaw('STATS', parts[0] ? parts : ['u'])
return out
}
if (cmd === 'version') {
if (parts[0] && parts[0].charAt(0) !== '#') {
client.sendRaw('PRIVMSG', [parts[0], '\x01VERSION\x01'])
return out
}
client.sendRaw('VERSION', parts[0] ? [parts[0]] : [])
return out
}
if (cmd === 'userhost') {
if (!parts[0]) {
out.usage = '/userhost NICK [NICK...]'
return out
}
client.sendRaw('USERHOST', parts.slice(0, 5))
return out
}
if (cmd === 'ison') {
if (!parts[0]) {
out.usage = '/ison NICK [NICK...]'
return out
}
client.sendRaw('ISON', parts)
return out
}
if (cmd === 'mode') {
if (!parts[0]) {
out.usage = '/mode TARGET [modes] [args]'
return out
}
client.sendRaw('MODE', parts)
return out
}
if (cmd === 'umode') {
client.sendRaw(
'MODE',
[client.state.nick].concat(parts.length ? parts : [])
)
return out
}
if (cmd === 'kick') {
var kchan = chan
var knick = parts[0]
var kreason = parts.slice(1).join(' ')
if (
parts[0] &&
(parts[0].charAt(0) === '#' || parts[0].charAt(0) === '&')
) {
kchan = parts[0]
knick = parts[1]
kreason = parts.slice(2).join(' ')
}
if (!kchan || !knick) {
out.usage = '/kick [channel] NICK [reason]'
return out
}
client.sendRaw('KICK', kreason ? [kchan, knick, kreason] : [kchan, knick])
return out
}
if (cmd === 'invite') {
if (!parts[0]) {
out.usage = '/invite NICK [#channel]'
return out
}
var ichan = parts[1] || chan
if (!ichan) {
out.usage = '/invite NICK #channel'
return out
}
client.sendRaw('INVITE', [parts[0], ichan])
return out
}
if (cmd === 'ban') {
if (!chan) {
out.usage = '/ban [mask] (in a channel)'
return out
}
if (!parts[0]) client.sendRaw('MODE', [chan, '+b'])
else client.sendRaw('MODE', [chan, '+b', parts[0]])
return out
}
if (cmd === 'unban') {
if (!chan || !parts[0]) {
out.usage = '/unban mask (in a channel)'
return out
}
client.sendRaw('MODE', [chan, '-b', parts[0]])
return out
}
if (cmd === 'op') {
if (!chan || !parts[0]) {
out.usage = '/op NICK [NICK...] (in a channel)'
return out
}
bareIrcModeNicks(client, chan, '+o', parts)
return out
}
if (cmd === 'deop') {
if (!chan || !parts[0]) {
out.usage = '/deop NICK [NICK...]'
return out
}
bareIrcModeNicks(client, chan, '-o', parts)
return out
}
if (cmd === 'voice') {
if (!chan || !parts[0]) {
out.usage = '/voice NICK [NICK...]'
return out
}
bareIrcModeNicks(client, chan, '+v', parts)
return out
}
if (cmd === 'devoice') {
if (!chan || !parts[0]) {
out.usage = '/devoice NICK [NICK...]'
return out
}
bareIrcModeNicks(client, chan, '-v', parts)
return out
}
if (cmd === 'knock') {
if (!parts[0]) {
out.usage = '/knock #channel [message]'
return out
}
client.sendRaw(
'KNOCK',
parts.slice(1).join(' ')
? [parts[0], parts.slice(1).join(' ')]
: [parts[0]]
)
return out
}
if (cmd === 'ctcp') {
if (!parts[0] || !parts[1]) {
out.usage = '/ctcp NICK CMD [args]'
return out
}
var ctcp =
parts[1].toUpperCase() +
(parts.slice(2).join(' ') ? ' ' + parts.slice(2).join(' ') : '')
client.sendRaw('PRIVMSG', [parts[0], '\x01' + ctcp + '\x01'])
return out
}
if (cmd === 'ping') {
if (parts[0]) {
client.sendRaw('PRIVMSG', [parts[0], '\x01PING ' + Date.now() + '\x01'])
} else {
client.sendRaw('PING', [client.state.nick || 'irc'])
}
return out
}
if (cmd === 'ignore') {
if (!parts[0]) {
var keys = Object.keys(client.state.ignore || {})
out.note = keys.length
? 'ignoring: ' + keys.join(', ')
: 'ignore list empty'
return out
}
if (!client.state.ignore) client.state.ignore = {}
client.state.ignore[
bareIrcCasemap(parts[0], bareIrcCasemapping(client.state.isupport))
] = parts[0]
out.note = 'ignoring ' + parts[0]
return out
}
if (cmd === 'unignore') {
if (!parts[0]) {
out.usage = '/unignore NICK'
return out
}
if (client.state.ignore) {
delete client.state.ignore[
bareIrcCasemap(parts[0], bareIrcCasemapping(client.state.isupport))
]
}
out.note = 'unignored ' + parts[0]
return out
}
if (cmd === 'clear') {
out.clear = true
return out
}
if (cmd === 'close' || cmd === 'wc') {
out.close = true
return out
}
if (cmd === 'win' || cmd === 'buffer' || cmd === 'window') {
var n = parseInt(parts[0], 10)
var list = bareIrcListBuffers(client.state)
if (n >= 1 && n <= list.length) client.state.currentId = list[n - 1].id
else out.usage = '/win N (1' + list.length + ')'
return out
}
if (cmd === 'p2p') {
if (parts[0] === 'open' && parts[1]) {
var name = String(parts[1])
if (name.indexOf('[p2p]') < 0) name = name + ' [p2p]'
var pb = bareIrcEnsureBuffer(client.state, 'p2p', name)
client.state.currentId = pb.id
bareIrcPushLine(client.state, pb, {
atMs: Date.now(),
kind: 'info',
text: 'Shadow room — not Libera. Messages stay on the swarm sideband.'
})
if (ctx && typeof ctx.bareOsIrcShadowOpen === 'function') {
try {
ctx.bareOsIrcShadowOpen(parts[1])
} catch (e) {
/* ignore */
}
}
return out
}
out.usage = '/p2p open #name'
return out
}
if (cmd === 'oper') {
if (parts.length < 2) {
out.usage = '/oper USER PASS'
return out
}
client.sendRaw('OPER', [parts[0], parts[1]])
return out
}
if (cmd === 'squery') {
if (!parts[0] || !parts.slice(1).join(' ')) {
out.usage = '/squery SERVICE text'
return out
}
client.sendRaw('SQUERY', [parts[0], parts.slice(1).join(' ')])
return out
}
if (cmd === 'set') {
out.note = 'config is ~/.irc/config.json (nick, autojoin, saslUser)'
return out
}
if (cmd === 'server') {
out.note =
(client.state.network || 'irc') +
' ' +
(client.opts.host || '') +
':' +
(client.opts.port || '')
return out
}
out.ok = false
out.usage = 'unknown command /' + cmd + ' try /help'
return out
}