/** 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 }