2020-02-03 19:45:12 +00:00
|
|
|
/* global irc, twemoji, globalConfig */
|
2019-01-09 20:47:21 +00:00
|
|
|
/* eslint-disable no-useless-escape, no-control-regex */
|
2020-02-03 19:45:12 +00:00
|
|
|
|
|
|
|
import seedrandom from 'seedrandom'
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
import { el, span, sf, formatDate, removeStr, match, serialize, objectGetKey, rand, addClass, removeClass, toggleClass } from './utility'
|
|
|
|
import stylize from './colorparser'
|
2020-02-03 19:45:12 +00:00
|
|
|
import themes from './theme'
|
|
|
|
import { IRCConnection } from './irc'
|
2016-12-15 21:30:55 +00:00
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
const gcfg = Object.assign({}, globalConfig)
|
2016-09-23 09:47:12 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
window.irc = {
|
|
|
|
primaryFrame: null,
|
|
|
|
config: {
|
|
|
|
colors: true,
|
|
|
|
channelify: true,
|
|
|
|
sharedInput: false,
|
|
|
|
timestamps: true,
|
|
|
|
timestampFormat: 'HH:mm:ss',
|
|
|
|
colorNicknames: true,
|
|
|
|
colorNicklist: false,
|
|
|
|
scrollOnResize: true,
|
|
|
|
scrollOnFocus: true,
|
|
|
|
emoji: true,
|
|
|
|
theme: 'default'
|
|
|
|
},
|
|
|
|
serverData: {},
|
|
|
|
serverChatQueue: {},
|
|
|
|
chatType: 'simple',
|
2020-02-03 19:45:12 +00:00
|
|
|
documentTitle: 'TeemantIRC',
|
|
|
|
handler: null
|
|
|
|
}
|
|
|
|
|
|
|
|
const customCTCPs = {
|
|
|
|
VERSION: function (data, connection) {
|
|
|
|
return `TeemantIRC - ${gcfg.description} ver. ${gcfg.version} - https://teemant.icynet.eu/`
|
|
|
|
},
|
|
|
|
SOURCE: function (data, connection) {
|
|
|
|
return 'https://gitlab.icynet.eu/IcyNetwork/teemant'
|
2020-02-05 21:04:19 +00:00
|
|
|
},
|
|
|
|
TIME: function (data, connection) {
|
|
|
|
return new Date()
|
2020-02-03 19:45:12 +00:00
|
|
|
}
|
2016-09-24 16:09:03 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
const clientdom = { connector: {}, settings: {} }
|
2016-09-24 12:25:47 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
const colorizer = {
|
2020-02-05 21:04:19 +00:00
|
|
|
getRandomColor: function (nickname) {
|
2019-01-09 20:47:21 +00:00
|
|
|
let themefunc = themes.available[irc.config.theme].nick_pallete
|
|
|
|
|
|
|
|
let randgen = seedrandom(nickname)
|
|
|
|
let h = rand(randgen, themefunc.H[0], themefunc.H[1])
|
|
|
|
let s = rand(randgen, themefunc.S[0], themefunc.S[1])
|
|
|
|
let l = rand(randgen, themefunc.L[0], themefunc.L[1])
|
|
|
|
return 'hsl(' + h + ',' + s + '%,' + l + '%)'
|
|
|
|
},
|
|
|
|
strip: function (message) {
|
|
|
|
return message.replace(/(\x03\d{0,2}(,\d{0,2})?)/g, '').replace(/[\x0F\x02\x16\x1F]/g, '')
|
|
|
|
},
|
|
|
|
stylize: stylize
|
2016-09-24 12:25:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
// Utilities
|
2016-09-26 14:16:05 +00:00
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
const validators = {
|
|
|
|
iporhost: function (str) {
|
|
|
|
let valid = false
|
2019-01-09 20:47:21 +00:00
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
if (str.match(/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i)) {
|
|
|
|
valid = true
|
|
|
|
} else if (str.match(/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/i)) {
|
|
|
|
valid = true
|
|
|
|
}
|
2016-09-23 07:38:47 +00:00
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
return valid
|
|
|
|
},
|
|
|
|
nickname: function (str) {
|
|
|
|
if (str.match(/[a-z_\-\[\]\\^{}|`][a-z0-9_\-\[\]\\^{}|`]*/i)) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
},
|
|
|
|
escapeHTML: function (str) {
|
|
|
|
return str.replace(/</g, '<').replace(/>/, '>')
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
2016-09-23 07:38:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
const processors = {
|
2020-02-05 21:04:19 +00:00
|
|
|
inlineColor: function (text) {
|
2019-01-09 20:47:21 +00:00
|
|
|
const rgbRegex = /(.?)(rgba?\((?:\s*\d+\s*,){2}\s*\d+\s*(?:,\s*[\d.]+\s*)?\);?)/gmi
|
|
|
|
const substitute = '$1$2 <div class="color_sample" style="background-color:$2"></div>'
|
|
|
|
text = text.replace(rgbRegex, substitute)
|
|
|
|
return text
|
|
|
|
},
|
|
|
|
linkify (text) {
|
|
|
|
const re = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:''.,<>?«»“”‘’]))/gi
|
|
|
|
return text.replace(re, function (url) {
|
|
|
|
let href = url
|
|
|
|
if (url.indexOf('http') !== 0) {
|
|
|
|
href = 'http://' + url
|
|
|
|
}
|
|
|
|
return '<a href="' + href + '" target="_blank" rel="nofollow">' + url + '</a>'
|
|
|
|
})
|
|
|
|
},
|
|
|
|
channelify (text) {
|
|
|
|
if (!irc.config.channelify) return text
|
|
|
|
|
|
|
|
const channelRegex = /(^|[\s,.:;?!"'()+@-\~%])(#+[^\x00\x07\r\n\s,:]*[a-z][^\x00\x07\r\n\s,:]*)/gmi
|
|
|
|
const substitute = '$1<a onclick="irc.joinChannel(\'$2\');" class="channel">$2</a>'
|
|
|
|
|
|
|
|
return text.replace(channelRegex, substitute)
|
|
|
|
},
|
|
|
|
emojify (text) {
|
|
|
|
if (irc.config.emoji === true && window.twemoji !== undefined) {
|
|
|
|
// Emoji live in the D800-DFFF surrogate plane; only bother passing
|
|
|
|
// this range to CPU-expensive parse()
|
|
|
|
const emojiRegex = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g
|
|
|
|
if (emojiRegex.test(text)) {
|
|
|
|
return twemoji.parse(text)
|
|
|
|
} else {
|
|
|
|
return text
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return text
|
|
|
|
}
|
|
|
|
}
|
2016-09-23 15:42:59 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
function whoisMessage (whoisData, buffer) {
|
|
|
|
let messages = []
|
|
|
|
for (let key in whoisData) {
|
|
|
|
switch (key) {
|
|
|
|
case 'hostmask':
|
|
|
|
messages.push(span(whoisData[key], ['hostmask']) + ': ' + validators.escapeHTML(whoisData['realname']))
|
|
|
|
break
|
|
|
|
case 'idleSeconds':
|
|
|
|
let msgs = 'is idle for ' + whoisData[key] + ' seconds'
|
|
|
|
if (whoisData['signonTime']) {
|
|
|
|
msgs += ', signed on at ' + (new Date(parseInt(whoisData['signonTime']) * 1000))
|
|
|
|
}
|
|
|
|
messages.push(msgs)
|
|
|
|
break
|
|
|
|
case 'loggedIn':
|
|
|
|
case 'registered':
|
|
|
|
case 'connectingFrom':
|
|
|
|
case 'usingModes':
|
|
|
|
case 'title':
|
|
|
|
messages.push(validators.escapeHTML(whoisData[key]))
|
|
|
|
break
|
|
|
|
case 'channels':
|
|
|
|
messages.push(whoisData[key].join(' '))
|
|
|
|
break
|
|
|
|
case 'server':
|
|
|
|
let adfd = sf('is on %s', span(whoisData[key], ['server', 'nick']))
|
2020-02-05 21:04:19 +00:00
|
|
|
if (whoisData['serverName']) {
|
2019-01-09 20:47:21 +00:00
|
|
|
adfd += ' '
|
2020-02-05 21:04:19 +00:00
|
|
|
adfd += span(validators.escapeHTML(whoisData['serverName']), ['hostmask'])
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
messages.push(adfd)
|
|
|
|
break
|
|
|
|
case 'secure':
|
|
|
|
messages.push('is using a secure connection.')
|
|
|
|
break
|
|
|
|
case 'bot':
|
|
|
|
messages.push('is a bot on ' + irc.serverData[buffer.server].network)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i in messages) {
|
|
|
|
let mesg = sf('[%s] %s', span(whoisData.nickname, ['nick']), messages[i])
|
|
|
|
buffer.addMessage(mesg, null, 'whois')
|
|
|
|
}
|
2016-09-24 12:25:47 +00:00
|
|
|
}
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
const whoQueue = {}
|
|
|
|
/*
|
|
|
|
function queryChannelMembers (server, channel) {
|
|
|
|
whoQueue[channel] = true
|
|
|
|
sendToServer(server, { command: 'who', arguments: [channel] })
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function whoResponse (data, buffer) {
|
|
|
|
let srv = irc.chat.getChatBuffersByServer(data.from)
|
|
|
|
let channels = []
|
|
|
|
for (let i in srv) {
|
|
|
|
let j = srv[i]
|
|
|
|
if (j.type === 'channel' && j.name === data.target) {
|
|
|
|
channels.push(j)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channels.length > 0) {
|
|
|
|
for (let c in channels) {
|
|
|
|
let chan = channels[c]
|
|
|
|
if (!chan.nicklist) continue
|
|
|
|
for (let i in data.who) {
|
|
|
|
let who = data.who[i]
|
|
|
|
chan.nicklist.setModesFromString(who.modes, who.nickname)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send message to buffer
|
|
|
|
if (whoQueue[data.target]) {
|
|
|
|
delete whoQueue[data.target]
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let messages = []
|
|
|
|
for (let i in data.who) {
|
|
|
|
let dt = data.who[i]
|
|
|
|
messages.push(
|
|
|
|
sf('[%s] %s %s %s %s (%s)',
|
|
|
|
span(dt.channel, ['channel']),
|
|
|
|
span(dt.nickname, ['nick']),
|
|
|
|
span(dt.hostmask, ['hostmask']),
|
|
|
|
dt.modes,
|
|
|
|
dt.hopcount,
|
|
|
|
validators.escapeHTML(dt.realname)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
messages.push(sf('[%s] %s', span(data.target, [(data.target.indexOf('#') === 0 ? 'channel' : 'nick')]), data.message))
|
|
|
|
|
|
|
|
for (let i in messages) {
|
|
|
|
buffer.addMessage(messages[i], null, 'whois')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
const asterisk = span('ℹ', ['asterisk'])
|
|
|
|
const arrowout = span('⬅', ['arrowout'])
|
|
|
|
const arrowin = span('➡', ['arrowin'])
|
|
|
|
|
2016-09-23 14:26:31 +00:00
|
|
|
let composer = {
|
2019-01-09 20:47:21 +00:00
|
|
|
message: {
|
|
|
|
simple: function (time, sender, message, type, server) {
|
|
|
|
let element = document.createElement('div')
|
|
|
|
element.className = 'message type_simple m_' + type
|
|
|
|
|
|
|
|
if (irc.config.timestamps) {
|
|
|
|
element.innerHTML += span(formatDate(time, irc.config.timestampFormat), ['timestamp'])
|
|
|
|
element.innerHTML += ' '
|
|
|
|
}
|
|
|
|
|
|
|
|
if (irc.config.colors) {
|
|
|
|
message = colorizer.stylize(message)
|
|
|
|
} else {
|
|
|
|
message = colorizer.strip(message)
|
|
|
|
}
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
message = processors.inlineColor(message)
|
2019-01-09 20:47:21 +00:00
|
|
|
message = processors.channelify(message)
|
|
|
|
message = processors.linkify(message)
|
|
|
|
message = processors.emojify(message)
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case 'mode':
|
|
|
|
element.innerHTML += ' ' + span(sender, ['actionee', 'nick']) + ' '
|
|
|
|
element.innerHTML += span(message, ['content'])
|
|
|
|
break
|
|
|
|
case 'action':
|
|
|
|
element.innerHTML += asterisk + ' ' + span(sender, ['actionee', 'nick']) + ' '
|
|
|
|
element.innerHTML += span(message, ['content'])
|
|
|
|
break
|
|
|
|
case 'part':
|
|
|
|
case 'quit':
|
|
|
|
case 'kick':
|
|
|
|
element.innerHTML += arrowout + ' ' + span(span(sender, ['actionee', 'nick']) + ' ' + message, ['content'])
|
|
|
|
break
|
|
|
|
case 'join':
|
|
|
|
element.innerHTML += arrowin + ' ' + span(span(sender, ['actionee', 'nick']) + ' ' + message, ['content'])
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'ctcpResponse':
|
2019-01-09 20:47:21 +00:00
|
|
|
element.innerHTML += asterisk + ' CTCP response from ' + span(sender, ['actionee', 'nick']) + ' '
|
|
|
|
element.innerHTML += span(message, ['content'])
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'ctcpRequest':
|
2019-01-09 20:47:21 +00:00
|
|
|
element.innerHTML += asterisk + ' CTCP request to ' + span(sender, ['actionee', 'nick']) + ' '
|
|
|
|
element.innerHTML += span(message, ['content'])
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
if (sender) {
|
|
|
|
element.innerHTML += span(sender, ['sender']) + ' ' + span(message, ['content'])
|
|
|
|
} else {
|
|
|
|
element.innerHTML += span(message, ['content', 'no_sender'])
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if (irc.config.colorNicknames === true) {
|
|
|
|
if (sender) {
|
|
|
|
let sndr1 = element.querySelector('.sender')
|
|
|
|
if (sndr1) {
|
2020-02-05 21:04:19 +00:00
|
|
|
sndr1.style.color = colorizer.getRandomColor(sndr1.innerHTML)
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let sndr2 = element.querySelectorAll('.nick')
|
|
|
|
if (sndr2.length > 0) {
|
|
|
|
for (let a in sndr2) {
|
|
|
|
if (sndr2[a] && sndr2[a]['style']) {
|
2020-02-05 21:04:19 +00:00
|
|
|
sndr2[a].style.color = colorizer.getRandomColor(sndr2[a].innerHTML)
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return element
|
|
|
|
}
|
|
|
|
},
|
|
|
|
themeSelection: function (name, theme) {
|
|
|
|
let btn = document.createElement('div')
|
|
|
|
btn.className = 'theme_button theme_' + theme.type
|
|
|
|
let sampler = document.createElement('div')
|
|
|
|
sampler.className = 'sampler'
|
|
|
|
sampler.style['background-color'] = theme.colorSamples.background
|
|
|
|
let toolbar = document.createElement('span')
|
|
|
|
toolbar.className = 's_toolbar'
|
|
|
|
toolbar.style['background-color'] = theme.colorSamples.toolbar
|
|
|
|
let nameb = document.createElement('span')
|
|
|
|
nameb.className = 'name'
|
|
|
|
nameb.innerHTML = theme['name']
|
|
|
|
sampler.appendChild(toolbar)
|
|
|
|
btn.appendChild(sampler)
|
|
|
|
btn.appendChild(nameb)
|
|
|
|
btn.setAttribute('id', 'theme-' + name)
|
|
|
|
|
|
|
|
return btn
|
|
|
|
},
|
|
|
|
embedURL: function (server, port, defaultNick, useSSL, hideServerData, channels) {
|
|
|
|
let builder = window.location.origin + '/'
|
|
|
|
let params = {}
|
|
|
|
let finalChannels = []
|
|
|
|
|
|
|
|
if (server) builder += server + '/'
|
|
|
|
if (channels) channels = channels.trim()
|
|
|
|
if (defaultNick) params.nickname = defaultNick
|
|
|
|
if (port && port !== 6667) params.port = port
|
|
|
|
if (useSSL) params.secure = 1
|
2020-02-05 21:04:19 +00:00
|
|
|
if (hideServerData) params.extras = 0
|
2019-01-09 20:47:21 +00:00
|
|
|
if (Object.keys(params).length > 0) builder += '?' + serialize(params)
|
|
|
|
|
|
|
|
if (channels) {
|
|
|
|
if (channels.indexOf(',')) {
|
|
|
|
let tmp = channels.split(',')
|
|
|
|
for (let i in tmp) {
|
|
|
|
tmp[i] = tmp[i].trim()
|
|
|
|
|
|
|
|
if (tmp[i].indexOf('#') !== 0) {
|
|
|
|
tmp[i] = '#' + tmp[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
finalChannels.push(tmp[i])
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (channels.indexOf('#') !== 0) {
|
|
|
|
channels = '#' + channels
|
|
|
|
}
|
|
|
|
finalChannels.push(channels)
|
|
|
|
}
|
|
|
|
|
|
|
|
builder += finalChannels.join(',')
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder
|
|
|
|
}
|
|
|
|
}
|
2016-09-23 14:26:31 +00:00
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
function sendToServer (server, obj) {
|
|
|
|
let i = irc.handler.getClientByActualServer(server)
|
|
|
|
if (!i) throw new Error('Invalid connection ' + server)
|
2020-02-05 21:04:19 +00:00
|
|
|
i.emit('userInput', obj)
|
2020-02-03 19:45:12 +00:00
|
|
|
}
|
|
|
|
|
2016-12-17 15:14:41 +00:00
|
|
|
// onclick food
|
|
|
|
window.irc.joinChannel = (channel) => {
|
2019-01-09 20:47:21 +00:00
|
|
|
let buf = irc.chat.getActiveChatBuffer()
|
|
|
|
if (!buf || !buf.server) return
|
2016-12-17 15:14:41 +00:00
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buf.server, { command: 'join', message: '', arguments: [channel] })
|
2019-01-09 20:47:21 +00:00
|
|
|
return false
|
|
|
|
}
|
2016-12-17 15:14:41 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
// Client commands
|
2016-09-26 15:41:48 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
// commandName: { execute: function (buffer, handler, command, message, listargs) {}, description: ''}
|
2016-09-26 15:41:48 +00:00
|
|
|
let commands = {
|
2019-01-09 20:47:21 +00:00
|
|
|
embed: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
let data = irc.auther.getDataFromForm()
|
|
|
|
let url = 'Couldn\'t compose URL!'
|
|
|
|
|
|
|
|
if (data) {
|
2020-02-05 21:08:23 +00:00
|
|
|
url = composer.embedURL(data.server, data.port, data.nickname, data.secure, true, data.channels.join(','))
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer.addMessage(url, null, 'help')
|
|
|
|
},
|
|
|
|
description: '- Embed URL for the current connection'
|
|
|
|
},
|
|
|
|
|
|
|
|
join: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1]) {
|
|
|
|
if (!buffer.alive) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'join', message: '', arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
|
|
|
handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameters!')
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'join', message: '', arguments: [listargs[1]] })
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
description: '<channel> - Join a channel'
|
|
|
|
},
|
|
|
|
|
|
|
|
part: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1] && buffer.type === 'channel') {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'part', message: '', arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else if (buffer.type !== 'channel') {
|
|
|
|
handler.commandError(buffer, listargs[0].toUpperCase() + ': Buffer is not a channel.')
|
|
|
|
} else if (listargs[1]) {
|
|
|
|
if (listargs[1].indexOf('#') !== -1) {
|
|
|
|
let msg = ''
|
|
|
|
if (listargs[2]) {
|
|
|
|
msg = listargs.slice(2).join(' ')
|
|
|
|
}
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'part', message: msg, arguments: [listargs[1]] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
|
|
|
if (buffer.type === 'channel') {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'part', message: listargs.slice(1).join(' '), arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
|
|
|
handler.commandError(buffer, listargs[0].toUpperCase() + ': Buffer is not a channel.')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
description: '[<#channel>|<message>] [message] - Leave the channel. If no channel specified, leave the current buffer.',
|
|
|
|
aliases: ['leave']
|
|
|
|
},
|
|
|
|
|
|
|
|
topic: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1] && buffer.type === 'channel') {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'topic', message: '', arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else if (buffer.type !== 'channel') {
|
|
|
|
handler.commandError(buffer, listargs[0].toUpperCase() + ': Buffer is not a channel.')
|
|
|
|
} else if (listargs[1]) {
|
|
|
|
if (listargs[1].indexOf('#') !== -1) {
|
|
|
|
let msg = ''
|
|
|
|
if (listargs[2]) {
|
|
|
|
msg = listargs.slice(2).join(' ')
|
|
|
|
}
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'topic', message: msg, arguments: [listargs[1]] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
|
|
|
if (buffer.type === 'channel') {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'topic', message: listargs.slice(1).join(' '), arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
|
|
|
handler.commandError(buffer, listargs[0].toUpperCase() + ': Buffer is not a channel.')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
description: '[<#channel>|<topic>] [topic] - Sets/prints the current topic of the channel.',
|
|
|
|
aliases: ['t']
|
|
|
|
},
|
|
|
|
|
|
|
|
kick: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (buffer.type !== 'channel') {
|
|
|
|
return handler.commandError(buffer, listargs[0].toUpperCase() + ': Buffer is not a channel!')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!listargs[1]) {
|
|
|
|
return handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameter <user>!')
|
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, {
|
2019-01-09 20:47:21 +00:00
|
|
|
command: 'kick',
|
|
|
|
message: listargs.slice(2).join(' '),
|
|
|
|
arguments: [buffer.name, listargs[1]]
|
|
|
|
})
|
|
|
|
},
|
|
|
|
description: '<user> <message> - Kick the following user from the channel.'
|
|
|
|
},
|
|
|
|
|
|
|
|
quit: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'quit', message: listargs.slice(1).join(' '), arguments: [] })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '[<message>] - Quit the current server with message.',
|
|
|
|
aliases: ['exit']
|
|
|
|
},
|
|
|
|
|
|
|
|
mode: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'mode', message: listargs.slice(1).join(' '), arguments: [] })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '[target] [mode] - Set/remove mode of target.'
|
|
|
|
},
|
|
|
|
|
|
|
|
msg: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1] || !listargs[2]) {
|
|
|
|
return handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameters!')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (listargs[1] === '*') {
|
|
|
|
listargs[1] = buffer.name
|
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'privmsg', message: listargs.slice(2).join(' '), arguments: [listargs[1]] })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '<target> <message> - Sends a message to target.',
|
|
|
|
aliases: ['privmsg', 'q', 'query', 'say']
|
|
|
|
},
|
|
|
|
|
|
|
|
ctcp: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1] || !listargs[2]) {
|
|
|
|
return handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameters!')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (listargs[1] === '*') {
|
|
|
|
listargs[1] = buffer.name
|
|
|
|
}
|
|
|
|
|
|
|
|
listargs[2] = listargs[2].toUpperCase()
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'ctcp', message: listargs.slice(2).join(' '), arguments: listargs.slice(1) })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '<target> <type> [arguments] - Sends a CTCP request to target.'
|
|
|
|
},
|
|
|
|
|
|
|
|
notice: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1] || !listargs[2]) {
|
|
|
|
return handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameters!')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (listargs[1] === '*') {
|
|
|
|
listargs[1] = buffer.name
|
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, {
|
2019-01-09 20:47:21 +00:00
|
|
|
command: 'notice',
|
|
|
|
message: listargs.slice(2).join(' '),
|
|
|
|
arguments: [listargs[1]]
|
|
|
|
})
|
|
|
|
},
|
|
|
|
description: '<target> <message> - Sends a NOTICE to target.'
|
|
|
|
},
|
|
|
|
|
|
|
|
action: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, {
|
2019-01-09 20:47:21 +00:00
|
|
|
command: 'privmsg',
|
|
|
|
message: '\x01ACTION ' + message.substring(command.length + 2) + '\x01',
|
|
|
|
arguments: [buffer.name]
|
|
|
|
})
|
|
|
|
},
|
2020-02-05 21:04:19 +00:00
|
|
|
description: '<message> - Act as yourself. (CTCP ACTION)',
|
2019-01-09 20:47:21 +00:00
|
|
|
aliases: ['me']
|
|
|
|
},
|
|
|
|
|
|
|
|
list: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'list', message: '', arguments: listargs.splice(1) })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '- List all channels on the current server.'
|
|
|
|
},
|
|
|
|
|
|
|
|
nick: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1]) {
|
|
|
|
if (buffer.server !== '' && irc.serverData[buffer.server] != null) {
|
2020-02-05 21:04:19 +00:00
|
|
|
let mynick = irc.serverData[buffer.server].userNick
|
2019-01-09 20:47:21 +00:00
|
|
|
buffer.addMessage('Your nickname is: <span class="nick">' + mynick + '</span>', null, 'help')
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'nick', message: '', arguments: listargs.splice(1) })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
2020-02-05 21:04:19 +00:00
|
|
|
description: '[<nickname>] - Set/display your nickname.',
|
2019-01-09 20:47:21 +00:00
|
|
|
aliases: ['nickname']
|
|
|
|
},
|
|
|
|
|
|
|
|
names: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
let channel = ''
|
|
|
|
if (!listargs[1]) {
|
|
|
|
if (buffer.type === 'channel') {
|
|
|
|
channel = buffer.name
|
|
|
|
} else {
|
|
|
|
return handler.commandError(buffer, '/' + command.toUpperCase() + ': Buffer is not a channel!')
|
|
|
|
}
|
|
|
|
} else if (listargs[1].indexOf('#') === 0) {
|
|
|
|
channel = listargs[1]
|
|
|
|
} else {
|
|
|
|
return handler.commandError(buffer, '/' + command.toUpperCase() + ': Invalid channel name!')
|
|
|
|
}
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'names', message: '', arguments: [channel] })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '- List all users on the current channel.',
|
|
|
|
aliases: ['nicknames']
|
|
|
|
},
|
|
|
|
|
|
|
|
quote: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, {
|
2019-01-09 20:47:21 +00:00
|
|
|
command: listargs[1],
|
|
|
|
message: listargs.slice(2).join(' '),
|
|
|
|
arguments: listargs.splice(2)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
description: '<command> [args] - Send a raw command to the server.',
|
|
|
|
aliases: ['raw']
|
|
|
|
},
|
|
|
|
|
|
|
|
whois: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-08 13:31:01 +00:00
|
|
|
if (!listargs[1]) return handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameters!')
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'whois', message: '', arguments: [listargs[1]] })
|
2019-01-09 20:47:21 +00:00
|
|
|
},
|
|
|
|
description: '<nickname> - Display information about a user.'
|
|
|
|
},
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
who: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
if (!listargs[1]) listargs[1] = buffer.name
|
|
|
|
sendToServer(buffer.server, { command: 'who', arguments: [listargs[1]] })
|
|
|
|
},
|
|
|
|
description: '[<target>] - Display some information.'
|
|
|
|
},
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
connect: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
clientdom.connector.frame.style.display = 'block'
|
|
|
|
irc.auther.authMessage('Create a new connection', false)
|
|
|
|
irc.auther.canClose = true
|
|
|
|
},
|
|
|
|
description: '- Create a new connection.'
|
|
|
|
},
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
ping: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
let server = irc.handler.getClientByActualServer(buffer.server)
|
|
|
|
buffer.addMessage('Connection latency: ' + server.ping + 'ms', null, 'help')
|
|
|
|
},
|
|
|
|
aliases: ['latency', 'lag']
|
|
|
|
},
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
help: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
2020-02-08 13:31:01 +00:00
|
|
|
if (!listargs[1]) return handler.commandError(buffer, listargs[0].toUpperCase() + ': Missing parameters!')
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
let cmd = listargs[1].toLowerCase()
|
|
|
|
if (cmd.indexOf('/') === 0) {
|
|
|
|
cmd = cmd.substring(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd in commands) {
|
|
|
|
if ('description' in commands[cmd]) {
|
|
|
|
buffer.addMessage(span('/' + cmd.toUpperCase(), ['command']) + ' ' +
|
|
|
|
validators.escapeHTML(commands[cmd].description), null, 'help')
|
|
|
|
} else {
|
|
|
|
buffer.addMessage(span('/' + cmd.toUpperCase(), ['command']) + ' - No description provided', null, 'help')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let foundAliased = null
|
|
|
|
for (let cmd2 in commands) {
|
|
|
|
if (!commands[cmd2]['aliases']) continue
|
|
|
|
if (commands[cmd2].aliases.indexOf(cmd) !== -1) foundAliased = cmd2
|
|
|
|
}
|
|
|
|
if (foundAliased) {
|
|
|
|
if ('description' in commands[foundAliased]) {
|
|
|
|
buffer.addMessage(span('/' + cmd.toUpperCase(), ['command']) + ' ' +
|
|
|
|
validators.escapeHTML(commands[foundAliased].description), null, 'help')
|
|
|
|
} else {
|
|
|
|
buffer.addMessage(span('/' + cmd.toUpperCase(), ['command']) + ' - No description provided', null, 'help')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
handler.commandError(buffer, span('/' + cmd.toUpperCase(), ['command']) + ': Unknown command!')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
description: '<command> - Display help for command'
|
|
|
|
},
|
|
|
|
|
|
|
|
clear: {
|
|
|
|
execute: function (buffer, handler, command, message, listargs) {
|
|
|
|
buffer.clearMessages()
|
|
|
|
},
|
|
|
|
description: '- Clears the current buffer.'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Classes
|
2016-09-23 09:47:12 +00:00
|
|
|
|
2016-09-23 07:38:47 +00:00
|
|
|
class Nicklist {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor (buffer) {
|
|
|
|
this.buffer = buffer
|
|
|
|
this.nicks = []
|
|
|
|
this.simplifiedNicksList = []
|
|
|
|
}
|
|
|
|
|
|
|
|
sort () {
|
|
|
|
let spfx = irc.serverData[this.buffer.server].supportedPrefixes
|
|
|
|
this.nicks.sort(function (a, b) {
|
|
|
|
let rex = new RegExp('^[' + spfx + ']')
|
|
|
|
let nicks = [a.prefix.replace(rex, '').toLowerCase(), b.prefix.replace(rex, '').toLowerCase()]
|
|
|
|
let prefix = []
|
|
|
|
if (rex.test(a.prefix)) prefix.push(spfx.indexOf(a.prefix[0]))
|
|
|
|
else prefix.push(spfx.length + 1)
|
|
|
|
if (rex.test(b.prefix)) prefix.push(spfx.indexOf(b.prefix[0]))
|
|
|
|
else prefix.push(spfx.length + 1)
|
|
|
|
if (prefix[0] < prefix[1]) return -1
|
|
|
|
if (prefix[0] > prefix[1]) return 1
|
|
|
|
if (nicks[0] > nicks[1]) return 1
|
|
|
|
if (nicks[0] < nicks[1]) return -1
|
|
|
|
return 0
|
|
|
|
})
|
|
|
|
return this.nicks
|
|
|
|
}
|
|
|
|
|
|
|
|
appendToList (nick) {
|
|
|
|
if (!this.buffer.active) return
|
|
|
|
|
|
|
|
let str = document.createElement('div')
|
|
|
|
str.className = 'nick'
|
|
|
|
str.setAttribute('id', 'nick-' + nick.nickname)
|
|
|
|
let construct = ''
|
|
|
|
|
|
|
|
if (nick.prefix !== '') {
|
|
|
|
construct += span(nick.prefix, ['prefix'])
|
|
|
|
} else {
|
|
|
|
construct += span(' ', ['no-prefix'])
|
|
|
|
}
|
|
|
|
|
|
|
|
if (irc.config.colorNicklist) {
|
2020-02-05 21:04:19 +00:00
|
|
|
construct += '<span class="nickname" style="color: ' + colorizer.getRandomColor(nick.nickname) + ';">' + nick.nickname + '</span>'
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
|
|
|
construct += span(nick.nickname, ['nickname'])
|
|
|
|
}
|
|
|
|
|
|
|
|
str.innerHTML = construct
|
|
|
|
clientdom.nicklist.appendChild(str)
|
|
|
|
}
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
reset () {
|
|
|
|
this.nicks = []
|
|
|
|
this.simplifiedNicksList = []
|
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
render () {
|
|
|
|
if (!this.buffer.active) return
|
|
|
|
if (!irc.serverData[this.buffer.server]) return
|
|
|
|
|
|
|
|
clientdom.nicklist.innerHTML = ''
|
|
|
|
this.simplifiedNicksList = []
|
|
|
|
this.sort()
|
|
|
|
|
|
|
|
for (let n in this.nicks) {
|
|
|
|
let nick = this.nicks[n]
|
|
|
|
this.simplifiedNicksList.push(nick.nickname)
|
|
|
|
this.appendToList(nick)
|
|
|
|
}
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
irc.chat.inputHandler.searchNicknames = this.simplifiedNicksList
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nickAdd (nickname) {
|
|
|
|
let newbie = { nickname: nickname, prefix: '', modes: [] }
|
|
|
|
if (this.getNickIndex(nickname) != null) return
|
|
|
|
this.nicks.push(newbie)
|
|
|
|
this.render()
|
|
|
|
}
|
|
|
|
|
|
|
|
nickAddObject (obj) {
|
|
|
|
if (this.getNickIndex(obj.nickname) != null) return
|
|
|
|
this.nicks.push(obj)
|
|
|
|
}
|
|
|
|
|
|
|
|
nickRemove (nickname) {
|
|
|
|
let nickIndex = this.getNickIndex(nickname)
|
|
|
|
|
|
|
|
if (nickIndex != null) {
|
|
|
|
this.nicks.splice(nickIndex, 1)
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.buffer.active) return
|
|
|
|
let tt = clientdom.nicklist.querySelector('#nick-' + nickname)
|
|
|
|
if (tt) tt.remove()
|
|
|
|
removeStr(this.simplifiedNicksList, nickname)
|
|
|
|
}
|
|
|
|
|
|
|
|
nickChange (oldNickname, newNickname) {
|
|
|
|
let nickIndex = this.getNickIndex(oldNickname)
|
|
|
|
|
|
|
|
if (nickIndex != null) {
|
|
|
|
this.nicks[nickIndex].nickname = newNickname
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.render()
|
|
|
|
}
|
|
|
|
|
|
|
|
getNickIndex (nickname) {
|
|
|
|
let result = null
|
|
|
|
|
|
|
|
for (let n in this.nicks) {
|
|
|
|
if (this.nicks[n].nickname === nickname) result = n
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
highestPriorityMode (modes) {
|
|
|
|
let highest = null
|
|
|
|
let modeTranslations = irc.serverData[this.buffer.server].modeTranslation
|
|
|
|
|
|
|
|
for (let mode in modeTranslations) {
|
|
|
|
if (modes.indexOf(mode) !== -1) {
|
|
|
|
highest = mode
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return { highest, prefix: highest ? modeTranslations[highest] : null }
|
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
modeAdded (nickname, newMode) {
|
|
|
|
let nickIndex = this.getNickIndex(nickname)
|
|
|
|
let nick = null
|
|
|
|
|
|
|
|
if (nickIndex != null) {
|
|
|
|
nick = this.nicks[nickIndex]
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
// Add mode to nicks' modes list
|
2019-01-09 20:47:21 +00:00
|
|
|
nick.modes.push(newMode)
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
// Find the prefix to give to the nick
|
|
|
|
nick.prefix = this.highestPriorityMode(nick.modes).prefix || ''
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
this.render()
|
|
|
|
}
|
|
|
|
|
|
|
|
modeRemoved (nickname, oldMode) {
|
|
|
|
let nickIndex = this.getNickIndex(nickname)
|
|
|
|
let nick = null
|
|
|
|
|
|
|
|
if (nickIndex != null) {
|
|
|
|
nick = this.nicks[nickIndex]
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
// Remove mode from nicks' modes list
|
2019-01-09 20:47:21 +00:00
|
|
|
removeStr(nick.modes, oldMode)
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
// Find the prefix to give to the nick
|
|
|
|
nick.prefix = this.highestPriorityMode(nick.modes).prefix || ''
|
2019-01-09 20:47:21 +00:00
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
this.render()
|
|
|
|
}
|
|
|
|
|
|
|
|
setModesFromString (str, nickname) {
|
|
|
|
if (this.getNickIndex(nickname) === null) return
|
|
|
|
|
|
|
|
let spfx = irc.serverData[this.buffer.server].modeTranslation
|
|
|
|
let modes = []
|
|
|
|
let split = str.split('')
|
|
|
|
for (let i in split) {
|
|
|
|
let char = split[i]
|
|
|
|
if (char === 'H' || char === 'G' || char === '*' || char === 's') continue
|
|
|
|
for (let mode in spfx) {
|
|
|
|
let prefix = spfx[mode]
|
|
|
|
if (char === prefix) {
|
|
|
|
modes.push(mode)
|
|
|
|
break
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
let nick = this.nicks[this.getNickIndex(nickname)]
|
|
|
|
|
|
|
|
nick.modes = modes
|
|
|
|
nick.prefix = this.highestPriorityMode(nick.modes).prefix || ''
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
this.render()
|
|
|
|
}
|
2016-09-23 07:38:47 +00:00
|
|
|
}
|
|
|
|
|
2016-09-22 17:15:40 +00:00
|
|
|
class Tab {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor (buffer) {
|
|
|
|
this.buffer = buffer
|
|
|
|
this.element = null
|
|
|
|
this.closeRequested = false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a tab element
|
|
|
|
renderTab () {
|
|
|
|
let internals = span(this.buffer.title, null, 'title') + span('', ['none'], 'unread')
|
|
|
|
|
|
|
|
let ttt = document.createElement('div')
|
|
|
|
ttt.innerHTML = internals
|
|
|
|
ttt.className = 'tab'
|
|
|
|
ttt.setAttribute('id', 'tab-' + this.buffer.name)
|
|
|
|
clientdom.tabby.appendChild(ttt)
|
|
|
|
this.element = ttt
|
|
|
|
|
|
|
|
ttt.innerHTML += span('x', null, 'close')
|
|
|
|
ttt.querySelector('#close').addEventListener('click', () => {
|
|
|
|
this.close()
|
|
|
|
}, false)
|
|
|
|
|
|
|
|
ttt.addEventListener('click', () => {
|
|
|
|
if (this.closeRequested) return
|
|
|
|
if (this.buffer.active) return
|
|
|
|
|
|
|
|
irc.chat.render(this.buffer)
|
|
|
|
}, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
setActive (active) {
|
|
|
|
if (this.element) {
|
|
|
|
this.element.className = 'tab'
|
|
|
|
if (active) {
|
|
|
|
addClass(this.element, 'active')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setHot (hot) {
|
|
|
|
if (this.element) {
|
|
|
|
if (hot) {
|
|
|
|
addClass(this.element, 'hot')
|
|
|
|
} else {
|
|
|
|
removeClass(this.element, 'hot')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setUnreadCount (count) {
|
|
|
|
if (this.element) {
|
|
|
|
let counter = this.element.querySelector('#unread')
|
|
|
|
if (count === 0) {
|
|
|
|
counter.className = 'none'
|
|
|
|
} else {
|
|
|
|
counter.innerHTML = count
|
|
|
|
counter.className = ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setTitle (title) {
|
|
|
|
let titleEl = this.element.querySelector('#title')
|
|
|
|
if (titleEl) {
|
|
|
|
titleEl.innerHTML = title
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close () {
|
|
|
|
this.closeRequested = true
|
|
|
|
this.buffer.closeChatBuffer()
|
|
|
|
}
|
2016-09-22 17:15:40 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 21:30:55 +00:00
|
|
|
class ChatBuffer {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor (servername, buffername, tabname, type) {
|
|
|
|
this.messages = []
|
|
|
|
this.nicklist = null
|
|
|
|
this.topic = null
|
|
|
|
this.input = ''
|
|
|
|
this.lastscroll = 0
|
|
|
|
this.wasAtBottom = false
|
|
|
|
this.unreadCount = 0
|
|
|
|
|
|
|
|
this.server = servername
|
|
|
|
this.name = buffername
|
|
|
|
this.title = tabname
|
|
|
|
this.type = type
|
|
|
|
this.active = false
|
|
|
|
this.alive = true
|
|
|
|
this.hot = false
|
|
|
|
|
|
|
|
if (type !== 'applet') {
|
|
|
|
this.tab = new Tab(this)
|
|
|
|
this.tab.renderTab()
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'channel') {
|
|
|
|
this.nicklist = new Nicklist(this, clientdom.nicklist)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
this.active = true
|
|
|
|
this.tab.setActive(true)
|
|
|
|
this.unreadCount = 0
|
|
|
|
this.tab.setUnreadCount(0)
|
|
|
|
|
|
|
|
clientdom.chat.className = 'chatarea'
|
|
|
|
clientdom.nicklist.innerHTML = ''
|
|
|
|
clientdom.topicbar.innerHTML = ''
|
|
|
|
|
|
|
|
if (!irc.config.sharedInput) {
|
|
|
|
clientdom.input.value = this.input
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.nicklist) {
|
|
|
|
addClass(clientdom.chat, 'vnicks')
|
|
|
|
this.nicklist.render()
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.hot) {
|
|
|
|
this.setHotStatus(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.topic != null && this.topic !== '') {
|
|
|
|
addClass(clientdom.chat, 'vtopic')
|
|
|
|
if (irc.config.colors) {
|
2020-02-08 13:31:01 +00:00
|
|
|
clientdom.topicbar.innerHTML = processors.channelify(processors.linkify(colorizer.stylize(this.topic)))
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
2020-02-08 13:31:01 +00:00
|
|
|
clientdom.topicbar.innerHTML = processors.channelify(processors.linkify(colorizer.strip(this.topic)))
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.renderMessages()
|
|
|
|
if (this.wasAtBottom) {
|
|
|
|
clientdom.letterbox.scrollTop = clientdom.letterbox.scrollHeight
|
|
|
|
} else {
|
|
|
|
clientdom.letterbox.scrollTop = this.lastscroll
|
|
|
|
}
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
clientdom.currentNickname.innerHTML = irc.serverData[this.server] ? irc.serverData[this.server].userNick
|
2019-01-09 20:47:21 +00:00
|
|
|
: el('i', 'Disconnected')
|
|
|
|
|
|
|
|
irc.chat.changeTitle('TeemantIRC - ' + this.title)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderMessages () {
|
|
|
|
if (!this.active) return
|
|
|
|
|
|
|
|
clientdom.letterbox.innerHTML = ''
|
|
|
|
|
|
|
|
for (let t in this.messages) {
|
|
|
|
let mesg = this.messages[t]
|
|
|
|
this.appendMessage({ message: mesg.message, sender: mesg.sender, type: mesg.type, time: mesg.time })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clearMessages () {
|
|
|
|
this.messages = []
|
|
|
|
|
|
|
|
if (this.active) {
|
|
|
|
clientdom.letterbox.innerHTML = ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setHotStatus (hot) {
|
|
|
|
this.hot = hot
|
|
|
|
if (this.tab) {
|
|
|
|
this.tab.setHot(hot)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
appendMessage (meta) {
|
|
|
|
let mesgConstr = composer.message[irc.chatType](meta.time, meta.sender, meta.message, meta.type, this.server)
|
|
|
|
|
|
|
|
if (irc.serverData[this.server]) {
|
2020-02-05 21:04:19 +00:00
|
|
|
let mynick = irc.serverData[this.server].userNick
|
2019-01-09 20:47:21 +00:00
|
|
|
if ((meta.type === 'privmsg' || meta.type === 'notice' || meta.type === 'action') &&
|
|
|
|
meta.message.toLowerCase().indexOf(mynick.toLowerCase()) !== -1 && meta.sender !== mynick) {
|
|
|
|
addClass(mesgConstr, 'mentioned')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.letterbox.appendChild(mesgConstr)
|
|
|
|
|
|
|
|
let lFactor = clientdom.letterbox.offsetHeight + clientdom.letterbox.scrollTop
|
|
|
|
if (lFactor > clientdom.letterbox.scrollHeight - 100) {
|
|
|
|
clientdom.letterbox.scrollTop = clientdom.letterbox.scrollHeight
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
topicChange (topic) {
|
|
|
|
if (this.active) {
|
|
|
|
if (irc.config.colors) {
|
|
|
|
clientdom.topicbar.innerHTML = processors.linkify(colorizer.stylize(topic))
|
|
|
|
} else {
|
|
|
|
clientdom.topicbar.innerHTML = processors.linkify(colorizer.strip(topic))
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.topic == null) {
|
|
|
|
addClass(clientdom.chat, 'vtopic')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.topic = topic
|
|
|
|
}
|
|
|
|
|
|
|
|
addMessage (message, sender, type, time) {
|
|
|
|
let mesg = { message: message, sender: sender, type: type, time: time || new Date() }
|
|
|
|
this.messages.push(mesg)
|
|
|
|
|
|
|
|
if (this.active) {
|
|
|
|
this.appendMessage(mesg)
|
|
|
|
} else {
|
|
|
|
this.unreadCount += 1
|
|
|
|
if (irc.serverData[this.server]) {
|
2020-02-05 21:04:19 +00:00
|
|
|
let mynick = irc.serverData[this.server].userNick
|
2019-01-09 20:47:21 +00:00
|
|
|
if ((type === 'privmsg' || type === 'notice' || type === 'action') &&
|
|
|
|
message.toLowerCase().indexOf(mynick.toLowerCase()) !== -1 && sender !== mynick) {
|
|
|
|
// TODO: notify user of mentioned
|
|
|
|
|
|
|
|
if (!this.active) {
|
|
|
|
this.setHotStatus(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.tab.setUnreadCount(this.unreadCount)
|
|
|
|
}
|
|
|
|
|
|
|
|
switchOff () {
|
2020-02-05 21:04:19 +00:00
|
|
|
irc.chat.inputHandler.searchNicknames = []
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
let lFactor = clientdom.letterbox.offsetHeight + clientdom.letterbox.scrollTop
|
|
|
|
if (lFactor > clientdom.letterbox.scrollHeight - 100) {
|
|
|
|
this.wasAtBottom = true
|
|
|
|
} else {
|
|
|
|
this.wasAtBottom = false
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!irc.config.sharedInput) {
|
|
|
|
this.input = clientdom.input.value
|
|
|
|
}
|
|
|
|
|
|
|
|
this.tab.setActive(false)
|
|
|
|
this.lastscroll = clientdom.letterbox.scrollTop
|
|
|
|
this.active = false
|
|
|
|
}
|
|
|
|
|
|
|
|
setAliveStatus (status) {
|
|
|
|
this.alive = status
|
|
|
|
if (this.alive) {
|
|
|
|
this.tab.setTitle(this.title)
|
|
|
|
} else {
|
|
|
|
this.tab.setTitle(el('i', sf('(%s)', this.title)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
closeChatBuffer () {
|
|
|
|
irc.chat.closeChatBuffer(this)
|
|
|
|
}
|
2016-09-22 17:15:40 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 15:28:53 +00:00
|
|
|
class ThemeSelector {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor (settings, variable) {
|
|
|
|
this.settings = settings
|
|
|
|
this.variable = variable
|
|
|
|
}
|
|
|
|
|
|
|
|
setActiveSelection (name) {
|
|
|
|
let all = clientdom.settings.available_themes.querySelectorAll('.theme_button')
|
|
|
|
if (all.length > 0) {
|
|
|
|
for (let a in all) {
|
|
|
|
if (all[a] && all[a]['className']) {
|
|
|
|
let elem = all[a]
|
|
|
|
if (elem.getAttribute('id') === 'theme-' + name) {
|
|
|
|
addClass(elem, 'selected')
|
|
|
|
} else {
|
|
|
|
removeClass(elem, 'selected')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bindButton (button, theme) {
|
|
|
|
button.onclick = (e) => {
|
|
|
|
this.settings.themeSelection = theme
|
|
|
|
this.setActiveSelection(theme)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
clientdom.settings.available_themes.innerHTML = ''
|
|
|
|
|
|
|
|
for (let n in themes.available) {
|
|
|
|
let theme = themes.available[n]
|
|
|
|
let button = composer.themeSelection(n, theme)
|
|
|
|
|
|
|
|
clientdom.settings.available_themes.appendChild(button)
|
|
|
|
|
|
|
|
this.bindButton(button, n)
|
|
|
|
}
|
|
|
|
}
|
2016-10-01 15:28:53 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 21:30:55 +00:00
|
|
|
class AppletChatBuffer extends ChatBuffer {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor (appletName, title, frame) {
|
|
|
|
super('', appletName, title, 'applet')
|
|
|
|
this.tab = null
|
|
|
|
this.isOpen = false
|
|
|
|
this.timeout = null
|
|
|
|
this.frame = frame
|
|
|
|
}
|
|
|
|
|
|
|
|
closeChatBuffer () {
|
|
|
|
irc.chat.closeChatBuffer(this)
|
|
|
|
this.tab = null
|
|
|
|
this.isOpen = false
|
|
|
|
}
|
|
|
|
|
|
|
|
open () {
|
|
|
|
if (this.isOpen) {
|
|
|
|
irc.chat.render(this)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.tab = new Tab(this)
|
|
|
|
this.tab.renderTab()
|
|
|
|
irc.chat.buffers.push(this)
|
|
|
|
irc.chat.render(this)
|
|
|
|
this.isOpen = true
|
|
|
|
}
|
|
|
|
|
|
|
|
addMessage (message, sender, type, time) {
|
|
|
|
// Don't send messages to any applet buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
switchOff () {
|
|
|
|
this.active = false
|
|
|
|
this.tab.setActive(false)
|
|
|
|
this.frame.style.display = 'none'
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
this.active = true
|
|
|
|
this.tab.setActive(true)
|
|
|
|
this.frame.style.display = 'block'
|
|
|
|
}
|
2016-12-07 12:58:20 +00:00
|
|
|
}
|
|
|
|
|
2016-12-15 21:30:55 +00:00
|
|
|
class Settings extends AppletChatBuffer {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor () {
|
|
|
|
super('settings', 'Settings', clientdom.settings.frame)
|
|
|
|
|
|
|
|
this.themeSelection = ''
|
|
|
|
|
|
|
|
this.themeSelector = new ThemeSelector(this)
|
|
|
|
this.themeSelector.render()
|
|
|
|
|
|
|
|
clientdom.settings.save.onclick = (e) => {
|
|
|
|
this.saveSpecified()
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.settings.open.onclick = (e) => {
|
|
|
|
this.open()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switchTheme () {
|
|
|
|
if (this.themeSelection !== '') {
|
2020-02-05 21:04:19 +00:00
|
|
|
themes.changeTheme(this.themeSelection)
|
2019-01-09 20:47:21 +00:00
|
|
|
irc.config.theme = this.themeSelection
|
|
|
|
this.themeSelector.setActiveSelection(this.themeSelection)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
saveSpecified () {
|
2020-02-05 21:04:19 +00:00
|
|
|
if (this.timeout) clearTimeout(this.timeout)
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
this.switchTheme()
|
|
|
|
|
|
|
|
for (let key in irc.config) {
|
|
|
|
let value = irc.config[key]
|
|
|
|
let type = typeof value
|
|
|
|
|
|
|
|
if (clientdom.settings[key]) {
|
|
|
|
if (type === 'boolean') {
|
|
|
|
irc.config[key] = clientdom.settings[key].checked
|
|
|
|
} else {
|
|
|
|
irc.config[key] = clientdom.settings[key].value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clientdom.settings.saveStatus.innerHTML = span('Settings saved!', ['success'])
|
|
|
|
|
|
|
|
if ('localStorage' in window) {
|
|
|
|
window.localStorage['teemant_settings'] = JSON.stringify(irc.config)
|
|
|
|
}
|
|
|
|
|
|
|
|
this.timeout = setTimeout(function () {
|
|
|
|
clientdom.settings.saveStatus.innerHTML = ''
|
|
|
|
}, 3000)
|
|
|
|
}
|
|
|
|
|
|
|
|
setInitialValues () {
|
|
|
|
if ('localStorage' in window) {
|
|
|
|
if (window.localStorage['teemant_settings']) {
|
|
|
|
try {
|
|
|
|
let settings = JSON.parse(window.localStorage.teemant_settings)
|
|
|
|
for (let key in irc.config) {
|
|
|
|
let value = irc.config[key]
|
|
|
|
let type = typeof value
|
|
|
|
|
|
|
|
if (settings[key]) {
|
|
|
|
if (key === 'theme') {
|
|
|
|
this.themeSelection = settings[key]
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'boolean') {
|
|
|
|
clientdom.settings[key].checked = settings[key]
|
|
|
|
} else {
|
|
|
|
clientdom.settings[key].value = settings[key]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.saveSpecified()
|
|
|
|
return
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let key in irc.config) {
|
|
|
|
let value = irc.config[key]
|
|
|
|
let type = typeof value
|
|
|
|
|
|
|
|
if (clientdom.settings[key]) {
|
|
|
|
if (type === 'boolean') {
|
|
|
|
clientdom.settings[key].checked = value
|
|
|
|
} else {
|
|
|
|
clientdom.settings[key].value = value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
super.render()
|
|
|
|
clientdom.chat.className = 'chatarea'
|
|
|
|
clientdom.nicklist.innerHTML = ''
|
|
|
|
clientdom.topicbar.innerHTML = ''
|
|
|
|
clientdom.letterbox.innerHTML = ''
|
|
|
|
irc.chat.changeTitle('TeemantIRC - Settings')
|
|
|
|
}
|
2016-09-25 18:48:35 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
class ConnectionHandler {
|
|
|
|
constructor () {
|
|
|
|
this.clients = {}
|
|
|
|
}
|
|
|
|
|
|
|
|
getClientByActualServer (actual) {
|
|
|
|
for (let i in this.clients) {
|
|
|
|
let a = this.clients[i]
|
|
|
|
if (a.data.actualServer === actual) return a
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
createConnection (data) {
|
|
|
|
let client = new IRCConnection(data, gcfg, { ctcps: customCTCPs })
|
|
|
|
irc.auther.authMessage('Connecting to server...', false)
|
|
|
|
client.on('authenticated', () => {
|
|
|
|
irc.auther.authComplete()
|
|
|
|
|
|
|
|
this.clients[data.server] = client
|
|
|
|
this.bindAll(data.server, client)
|
|
|
|
|
|
|
|
irc.chat.newServerChatBuffer(client)
|
|
|
|
irc.chat.joinChannels(client.data.actualServer, data.channels)
|
|
|
|
})
|
2020-02-08 10:50:56 +00:00
|
|
|
client.once('connectionError', (e) => {
|
|
|
|
if (e.message.indexOf('IRCError') !== 0) return
|
|
|
|
irc.auther.authMessage(e.message, true)
|
|
|
|
})
|
2020-02-03 19:45:12 +00:00
|
|
|
client.connect().catch(e => {
|
|
|
|
console.error(e)
|
|
|
|
irc.auther.authMessage('Socket connection failed!', true)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
bindAll (srv, client) {
|
|
|
|
let server = client.data.actualServer
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
client.on('fromServer', (data) => {
|
2020-02-03 19:45:12 +00:00
|
|
|
switch (data.type) {
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'joinChannel':
|
|
|
|
if (data.user.nickname === irc.serverData[server].userNick) {
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.createChatBuffer(server, data.channel, 'channel', true)
|
|
|
|
}
|
|
|
|
irc.chat.handleJoin(server, data.user, data.channel)
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'kickedFromChannel':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.handleLeave(server, data.kickee, data.channel, data.reason, data.user)
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'partChannel':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.handleLeave(server, data.user, data.channel, data.reason)
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'quit':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.handleQuit(server, data.user, data.reason)
|
|
|
|
break
|
|
|
|
case 'message':
|
2020-02-05 21:04:19 +00:00
|
|
|
if (data.to === irc.serverData[server].userNick) {
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.messageChatBuffer(data.user.nickname, server, { message: data.message, type: data.messageType, from: data.user.nickname })
|
|
|
|
} else if (data.to == null) {
|
|
|
|
let atest = irc.chat.getActiveChatBuffer()
|
|
|
|
|
|
|
|
if (atest.server !== server) {
|
|
|
|
atest = irc.chat.getServerChatBuffer(server)
|
|
|
|
}
|
|
|
|
|
|
|
|
atest.addMessage(data.message, data.user.nickname, data.messageType)
|
|
|
|
} else {
|
|
|
|
irc.chat.messageChatBuffer(data.to, server, { message: data.message, type: data.messageType, from: data.user.nickname })
|
|
|
|
}
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'nicks':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.buildNicklist(data.channel, server, data.nicks)
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'topic':
|
|
|
|
if (data['topic'] && data['setBy']) {
|
|
|
|
irc.chat.topicChange(data.channel, server, data.topic, data['setBy'])
|
2020-02-03 19:45:12 +00:00
|
|
|
} else if (data['topic']) {
|
|
|
|
irc.chat.topicChange(data.channel, server, data.topic, null)
|
2020-02-05 21:04:19 +00:00
|
|
|
} else if (data['setBy']) {
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.messageChatBuffer(data.channel, server, {
|
2020-02-05 21:04:19 +00:00
|
|
|
message: 'Topic set by ' + data.setBy + ' on ' + (new Date(data.time * 1000)),
|
2020-02-03 19:45:12 +00:00
|
|
|
type: 'topic',
|
|
|
|
from: null
|
|
|
|
})
|
|
|
|
}
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'nick':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.nickChange(server, data.nick, data.newNick)
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'modeAdd':
|
|
|
|
case 'modeDel':
|
2020-02-03 19:45:12 +00:00
|
|
|
case 'mode':
|
|
|
|
irc.chat.handleMode(server, data)
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'serverMessage':
|
2020-02-03 19:45:12 +00:00
|
|
|
if (data['error']) data.messageType = 'error'
|
|
|
|
if (irc.chat.getServerChatBuffer(server) == null) {
|
|
|
|
if (!irc.serverChatQueue[server]) {
|
|
|
|
irc.serverChatQueue[server] = []
|
|
|
|
} else {
|
|
|
|
irc.serverChatQueue[server].push({ type: data.messageType, message: data.message, from: data.from || null, time: new Date() })
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
irc.chat.messageChatBuffer(server, server, { message: data.message, type: data.messageType, from: data.from || null })
|
|
|
|
}
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'connectMessage':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.auther.authMessage(data.message, data.error)
|
|
|
|
break
|
|
|
|
case 'whoisResponse':
|
|
|
|
whoisMessage(data.whois, irc.chat.getActiveChatBuffer())
|
|
|
|
break
|
2020-02-08 13:31:01 +00:00
|
|
|
case 'whoResponse':
|
|
|
|
whoResponse(data, irc.chat.getActiveChatBuffer())
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'listedChannel':
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.chat.messageChatBuffer(server, server,
|
|
|
|
{
|
|
|
|
message: span(data.channel, ['channel']) + ' ' +
|
|
|
|
span(data.users, ['usercount']) + ' ' +
|
|
|
|
span(data.topic, ['topic']),
|
|
|
|
type: 'listentry',
|
|
|
|
from: data.from
|
|
|
|
})
|
|
|
|
break
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
client.on('connectionClosed', () => {
|
2020-02-03 19:45:12 +00:00
|
|
|
let serverz = irc.chat.getChatBuffersByServer(server)
|
|
|
|
for (let a in serverz) {
|
|
|
|
let serv = serverz[a]
|
|
|
|
serv.addMessage('You are no longer talking on this server.', null, 'error')
|
|
|
|
serv.setAliveStatus(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (irc.serverData[server]) {
|
|
|
|
delete irc.serverData[server]
|
|
|
|
}
|
|
|
|
|
|
|
|
stopWarnings()
|
2020-02-05 21:04:19 +00:00
|
|
|
this.clients[srv] = null
|
2020-02-03 19:45:12 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 17:15:40 +00:00
|
|
|
class IRCConnector {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor () {
|
|
|
|
this.formLocked = false
|
|
|
|
this.canClose = false
|
|
|
|
this.defaults = {}
|
|
|
|
|
|
|
|
clientdom.connector.form.onsubmit = (e) => {
|
|
|
|
if (this.formLocked) {
|
|
|
|
e.preventDefault()
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
this.formLocked = true
|
|
|
|
|
|
|
|
this.validateForm(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.connector.onkeyup = (e) => {
|
|
|
|
let key = e.keyCode || e.which || e.charCode || 0
|
|
|
|
if (key === 27 && this.canClose) {
|
|
|
|
this.authComplete()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.connector.pwtrigger.onclick = (e) => {
|
|
|
|
this.togglePassword()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fillFormFromURI (urlParams) {
|
2020-02-08 10:50:56 +00:00
|
|
|
let skipServer = false
|
2019-01-09 20:47:21 +00:00
|
|
|
if (this.defaults.server) {
|
|
|
|
clientdom.connector.server.value = this.defaults.server
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.defaults.port) {
|
|
|
|
clientdom.connector.port.value = this.defaults.port
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.defaults.ssl) {
|
|
|
|
clientdom.connector.secure.checked = this.defaults.ssl
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let param in urlParams) {
|
|
|
|
let value = urlParams[param]
|
|
|
|
|
|
|
|
switch (param) {
|
|
|
|
case 'nick':
|
|
|
|
case 'nickname':
|
|
|
|
if (validators.nickname(value)) {
|
2020-02-03 19:45:12 +00:00
|
|
|
clientdom.connector.nickname.value = value.replace(/\?/g, rand(seedrandom(1), 10000, 99999))
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
case 'secure':
|
|
|
|
case 'ssl':
|
|
|
|
if (value === 'true' || value === '1') {
|
|
|
|
clientdom.connector.secure.checked = true
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 'password':
|
|
|
|
if (value === 'true' || value === '1') {
|
|
|
|
clientdom.connector.pwtrigger.checked = true
|
|
|
|
this.togglePassword()
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 'server':
|
|
|
|
case 'host':
|
|
|
|
if (validators.iporhost(value)) {
|
2020-02-08 10:50:56 +00:00
|
|
|
skipServer = true
|
2019-01-09 20:47:21 +00:00
|
|
|
clientdom.connector.server.value = value
|
|
|
|
}
|
|
|
|
break
|
2020-02-05 21:04:19 +00:00
|
|
|
case 'serverinfo':
|
2019-01-09 20:47:21 +00:00
|
|
|
case 'extra':
|
|
|
|
case 'extras':
|
|
|
|
case 'connection':
|
|
|
|
if (value === 'false' || value === '0') {
|
|
|
|
clientdom.connector.server_data.style.display = 'none'
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 'port':
|
|
|
|
try {
|
|
|
|
let ppp = parseInt(value)
|
|
|
|
clientdom.connector.port.value = ppp
|
|
|
|
} catch (e) {}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window.location.hash) {
|
|
|
|
clientdom.connector.channel.value = window.location.hash
|
|
|
|
}
|
|
|
|
|
2020-02-08 10:50:56 +00:00
|
|
|
if (window.location.pathname.length > 4 && !skipServer) {
|
2019-01-09 20:47:21 +00:00
|
|
|
let t1 = window.location.pathname.substring(1, window.location.pathname.length - 1)
|
|
|
|
let proposed = ''
|
|
|
|
|
|
|
|
if (t1.indexOf('/') !== -1) {
|
|
|
|
proposed = t1.split('/')
|
|
|
|
proposed = proposed[proposed.length - 1]
|
|
|
|
} else {
|
|
|
|
proposed = t1
|
|
|
|
}
|
|
|
|
|
|
|
|
if (validators.iporhost(proposed)) {
|
|
|
|
clientdom.connector.server.value = proposed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultTo (data) {
|
|
|
|
this.defaults = data
|
|
|
|
}
|
|
|
|
|
|
|
|
getDataFromForm () {
|
|
|
|
let nickname = clientdom.connector.nickname.value
|
|
|
|
let password = clientdom.connector.password.value
|
|
|
|
let channel = clientdom.connector.channel.value
|
|
|
|
let server = clientdom.connector.server.value
|
|
|
|
let port = clientdom.connector.port.value
|
|
|
|
|
|
|
|
if (!validators.nickname(nickname)) {
|
|
|
|
this.authMessage('Erroneous nickname!', true)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel.indexOf(',') !== -1) {
|
|
|
|
channel = channel.trim().split(',')
|
|
|
|
|
|
|
|
for (let t in channel) {
|
|
|
|
let chan = channel[t]
|
|
|
|
|
|
|
|
channel[t] = chan.trim()
|
|
|
|
|
|
|
|
if (chan.indexOf('#') !== 0) {
|
|
|
|
channel[t] = '#' + chan
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (channel !== '') {
|
|
|
|
channel = channel.trim()
|
|
|
|
if (channel.indexOf('#') !== 0) {
|
|
|
|
channel = '#' + channel
|
|
|
|
}
|
|
|
|
channel = [channel]
|
|
|
|
} else {
|
|
|
|
channel = []
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!validators.iporhost(server)) {
|
|
|
|
this.authMessage('Erroneous server address!', true)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
port = parseInt(port)
|
|
|
|
} catch (e) {
|
|
|
|
this.authMessage('Erroneous port!', true)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port < 10 || port > 65535) {
|
|
|
|
this.authMessage('Erroneous port!', true)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!clientdom.connector.pwtrigger.checked) {
|
|
|
|
password = ''
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
nickname: nickname,
|
2020-02-03 19:45:12 +00:00
|
|
|
channels: channel,
|
2019-01-09 20:47:21 +00:00
|
|
|
server: server,
|
|
|
|
port: port,
|
|
|
|
password: password,
|
|
|
|
secure: clientdom.connector.secure.checked
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
validateForm (event) {
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
let data = this.getDataFromForm()
|
|
|
|
if (!data) return
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.handler.createConnection(data)
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
authMessage (message, error) {
|
|
|
|
clientdom.connector.messenger.innerHTML = span(message, ['msg', (error ? 'error' : '')])
|
|
|
|
if (error) {
|
|
|
|
this.formLocked = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
togglePassword () {
|
|
|
|
if (clientdom.connector.pwtrigger.checked) {
|
|
|
|
clientdom.connector.pwbox.style.display = 'block'
|
|
|
|
} else {
|
|
|
|
clientdom.connector.pwbox.style.display = 'none'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
authComplete () {
|
|
|
|
clientdom.connector.frame.style.display = 'none'
|
|
|
|
this.formLocked = false
|
|
|
|
}
|
2016-09-22 17:15:40 +00:00
|
|
|
}
|
|
|
|
|
2016-09-23 14:26:31 +00:00
|
|
|
class InputHandler {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor () {
|
|
|
|
this.history = []
|
|
|
|
this.historyCaret = 0
|
|
|
|
this.searchNicknames = []
|
|
|
|
|
|
|
|
this.index = -1
|
|
|
|
this.words = []
|
|
|
|
this.last = ''
|
|
|
|
|
|
|
|
clientdom.input.onkeyup = (e) => {
|
|
|
|
let key = e.keyCode || e.which || e.charCode || 0
|
|
|
|
if (key === 13) {
|
|
|
|
this.handleInput()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.keyUpHandle(e, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.input.onkeydown = (e) => {
|
|
|
|
let key = e.keyCode || e.which || e.charCode || 0
|
|
|
|
if (e.ctrlKey || e.shiftKey || e.altKey) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.keyDownHandle(e, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.input.onfocus = (e) => {
|
|
|
|
if (irc.config.scrollOnFocus) {
|
|
|
|
clientdom.letterbox.scrollTop = clientdom.letterbox.scrollHeight
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.send.onclick = (e) => {
|
|
|
|
this.handleInput()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
keyUpHandle (e, key) {
|
|
|
|
if (key === 38 || key === 40) {
|
|
|
|
clientdom.input.selectionStart = clientdom.input.value.length
|
|
|
|
clientdom.input.selectionEnd = clientdom.input.value.length
|
|
|
|
} else if (key === 9) return
|
|
|
|
let input = clientdom.input.value
|
|
|
|
let word = input.split(/ |\n/).pop()
|
|
|
|
|
|
|
|
// Reset iteration.
|
|
|
|
this.tabCompleteReset()
|
|
|
|
|
|
|
|
// Check for matches if the current word is the last word.
|
|
|
|
if (clientdom.input.selectionStart === input.length && word.length) {
|
|
|
|
// Call the match() function to filter the words.
|
|
|
|
this.tabWords = match(word, this.searchNicknames)
|
|
|
|
if (input.indexOf(word) === 0) {
|
|
|
|
for (let n in this.tabWords) {
|
|
|
|
this.tabWords[n] += ': '
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
keyDownHandle (e, key) {
|
|
|
|
if (key === 38) {
|
|
|
|
if (this.historyCaret <= 0) {
|
|
|
|
this.historyCaret = 0
|
|
|
|
} else {
|
|
|
|
this.historyCaret -= 1
|
|
|
|
}
|
|
|
|
|
|
|
|
let selection = this.history[this.historyCaret]
|
|
|
|
|
|
|
|
if (selection) {
|
|
|
|
clientdom.input.value = selection
|
|
|
|
this.tabCompleteReset()
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
} else if (key === 40) {
|
|
|
|
if (this.historyCaret >= this.history.length) {
|
|
|
|
this.historyCaret = this.history.length
|
|
|
|
} else {
|
|
|
|
this.historyCaret += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
let selection = this.history[this.historyCaret]
|
|
|
|
|
|
|
|
if (!this.history[this.historyCaret]) selection = ''
|
|
|
|
|
|
|
|
clientdom.input.value = selection
|
|
|
|
this.tabCompleteReset()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key === 9) {
|
|
|
|
e.preventDefault()
|
|
|
|
|
|
|
|
this.index++
|
|
|
|
|
|
|
|
// Get next match.
|
|
|
|
let word = this.tabWords[this.index % this.tabWords.length]
|
|
|
|
if (!word) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let value = clientdom.input.value
|
|
|
|
this.lastWord = this.lastWord || value.split(/ |\n/).pop()
|
|
|
|
|
|
|
|
// Return if the 'minLength' requirement isn't met.
|
|
|
|
if (this.lastWord.length < 1) return
|
|
|
|
|
|
|
|
let text = value.substr(0, clientdom.input.selectionStart - this.lastWord.length) + word
|
|
|
|
clientdom.input.value = text
|
|
|
|
|
|
|
|
// Remember the word until next time.
|
|
|
|
this.lastWord = word
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tabCompleteReset () {
|
|
|
|
this.index = -1
|
|
|
|
this.lastWord = ''
|
|
|
|
this.tabWords = []
|
|
|
|
}
|
|
|
|
|
|
|
|
handleInput () {
|
|
|
|
let message = clientdom.input.value
|
|
|
|
let buffer = irc.chat.getActiveChatBuffer()
|
|
|
|
|
|
|
|
if (!buffer) return
|
|
|
|
if (message.trim() === '') return
|
|
|
|
|
|
|
|
let listargs = message.split(' ')
|
|
|
|
|
|
|
|
if (listargs[0].indexOf('/') === 0) {
|
|
|
|
let command = listargs[0].substring(1).toLowerCase()
|
|
|
|
if (command.toLowerCase() in commands) {
|
|
|
|
let cmd = commands[command]
|
|
|
|
if ('execute' in cmd) {
|
|
|
|
cmd.execute(buffer, this, command, message, listargs)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let foundAliased = null
|
|
|
|
for (let cmd in commands) {
|
|
|
|
if (!commands[cmd]['aliases']) continue
|
|
|
|
if (commands[cmd].aliases.indexOf(command) !== -1) foundAliased = commands[cmd]
|
|
|
|
}
|
|
|
|
if (foundAliased) {
|
|
|
|
foundAliased.execute(buffer, this, command, message, listargs)
|
|
|
|
} else {
|
|
|
|
this.commandError(buffer, listargs[0].toUpperCase() + ': Unknown command!')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'privmsg', message: message, arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.history.push(message)
|
|
|
|
this.historyCaret = this.history.length
|
|
|
|
clientdom.input.value = ''
|
|
|
|
}
|
|
|
|
|
|
|
|
commandError (buffer, message) {
|
|
|
|
buffer.addMessage(message, null, 'error')
|
|
|
|
return true
|
|
|
|
}
|
2016-09-23 14:26:31 +00:00
|
|
|
}
|
|
|
|
|
2016-09-22 17:15:40 +00:00
|
|
|
class IRCChatWindow {
|
2019-01-09 20:47:21 +00:00
|
|
|
constructor () {
|
|
|
|
this.buffers = []
|
|
|
|
this.firstServer = true
|
|
|
|
this.currentChatBuffer = null
|
2020-02-05 21:04:19 +00:00
|
|
|
this.inputHandler = new InputHandler()
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
clientdom.frame.style.display = 'none'
|
|
|
|
|
|
|
|
clientdom.smsctrig.onclick = (e) => {
|
|
|
|
toggleClass(clientdom.chat, 'vopentrig')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
destroyAllChatBuffers () {
|
|
|
|
// Wipe all server data
|
|
|
|
irc.serverData = {}
|
|
|
|
irc.serverChatQueue = {}
|
|
|
|
this.buffers = []
|
|
|
|
|
|
|
|
// Clear tabs
|
|
|
|
clientdom.tabby.innerHTML = ''
|
|
|
|
|
|
|
|
// Reset to the defaults
|
|
|
|
irc.auther.authMessage('Disconnected', true)
|
|
|
|
clientdom.frame.style.display = 'none'
|
|
|
|
this.firstServer = true
|
|
|
|
window.onbeforeunload = null
|
|
|
|
}
|
|
|
|
|
|
|
|
getChatBufferByName (buffername) {
|
|
|
|
let result = null
|
|
|
|
for (let t in this.buffers) {
|
|
|
|
let buf = this.buffers[t]
|
|
|
|
if (buf.name.toLowerCase() === buffername.toLowerCase()) {
|
|
|
|
result = buf
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
getActiveChatBuffer () {
|
|
|
|
let result = null
|
|
|
|
for (let t in this.buffers) {
|
|
|
|
let buf = this.buffers[t]
|
|
|
|
if (buf.active === true) {
|
|
|
|
result = buf
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
getServerChatBuffer (server) {
|
|
|
|
let result = null
|
|
|
|
for (let t in this.buffers) {
|
|
|
|
let buf = this.buffers[t]
|
|
|
|
if (buf.server === server) {
|
|
|
|
result = buf
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
getChatBuffersByServer (server) {
|
|
|
|
let result = []
|
|
|
|
for (let t in this.buffers) {
|
|
|
|
let buf = this.buffers[t]
|
|
|
|
if (buf.server === server) {
|
|
|
|
result.push(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
getChatBufferByServerName (server, channel) {
|
|
|
|
let result = null
|
|
|
|
for (let t in this.buffers) {
|
|
|
|
let buf = this.buffers[t]
|
|
|
|
if (buf.server === server && buf.name.toLowerCase() === channel.toLowerCase()) {
|
|
|
|
result = buf
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
getChatBuffersByType (type) {
|
|
|
|
let result = []
|
|
|
|
for (let t in this.buffers) {
|
|
|
|
let buf = this.buffers[t]
|
|
|
|
if (buf.type === type) {
|
|
|
|
result.push(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
newServerChatBuffer (serverinfo) {
|
|
|
|
if (this.firstServer) {
|
|
|
|
clientdom.frame.style.display = 'block'
|
|
|
|
window.onbeforeunload = function (e) {
|
2020-02-05 21:04:19 +00:00
|
|
|
return 'You will be disconnected from all the channels you\'re currently in.'
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let prefixes = ''
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
for (let v in serverinfo.data.supportedModes) {
|
|
|
|
prefixes += serverinfo.data.supportedModes[v]
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.serverData[serverinfo.data.actualServer] = {
|
|
|
|
modeTranslation: serverinfo.data.supportedModes,
|
2019-01-09 20:47:21 +00:00
|
|
|
supportedPrefixes: prefixes,
|
2020-02-03 19:45:12 +00:00
|
|
|
network: serverinfo.data.network,
|
2020-02-05 21:04:19 +00:00
|
|
|
userNick: serverinfo.config.nickname,
|
|
|
|
maxChannelLength: serverinfo.data.maxChannelLength
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
let newServer = new ChatBuffer(serverinfo.data.actualServer, serverinfo.data.actualServer, serverinfo.data.network, 'server')
|
2019-01-09 20:47:21 +00:00
|
|
|
this.buffers.push(newServer)
|
|
|
|
this.render(newServer)
|
|
|
|
this.firstServer = false
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
if (irc.serverChatQueue[serverinfo.data.actualServer]) {
|
|
|
|
for (let a in irc.serverChatQueue[serverinfo.data.actualServer]) {
|
|
|
|
let mesg = irc.serverChatQueue[serverinfo.data.actualServer][a]
|
2019-01-09 20:47:21 +00:00
|
|
|
newServer.addMessage(mesg.message, mesg.from, mesg.type, mesg.time)
|
|
|
|
}
|
2020-02-03 19:45:12 +00:00
|
|
|
delete irc.serverChatQueue[serverinfo.data.actualServer]
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
createChatBuffer (server, name, type, autoswitch) {
|
|
|
|
let buf = this.getChatBufferByServerName(server, name)
|
|
|
|
if (buf) {
|
|
|
|
if (autoswitch) {
|
|
|
|
this.render(buf)
|
|
|
|
}
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = new ChatBuffer(server, name, name, type)
|
|
|
|
this.buffers.push(buf)
|
|
|
|
|
|
|
|
if (autoswitch) {
|
|
|
|
this.render(buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
|
|
|
closeChatBuffer (buffer) {
|
|
|
|
if (buffer.type === 'server') {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'quit', message: 'Server tab closed', arguments: [] })
|
2019-01-09 20:47:21 +00:00
|
|
|
} else if (buffer.type === 'channel' && buffer.alive) {
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(buffer.server, { command: 'part', message: 'Tab closed', arguments: [buffer.name] })
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let bufIndex = this.buffers.indexOf(buffer)
|
|
|
|
|
|
|
|
if (buffer.active) {
|
|
|
|
if (bufIndex === 0) {
|
|
|
|
if (this.buffers[bufIndex + 1]) {
|
|
|
|
this.render(this.buffers[bufIndex + 1])
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.render(this.buffers[bufIndex - 1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.tab.element.remove()
|
|
|
|
this.buffers.splice(bufIndex, 1)
|
|
|
|
|
|
|
|
if (this.buffers.length === 0 || (this.buffers.length === 1 && this.buffers[0].type === 'applet')) {
|
|
|
|
irc.chat.destroyAllChatBuffers()
|
|
|
|
irc.auther.authMessage('Create a new connection', false)
|
|
|
|
irc.auther.canClose = false
|
|
|
|
clientdom.connector.frame.style.display = 'block'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
messageChatBuffer (name, server, message) {
|
|
|
|
let buf = this.getChatBufferByServerName(server, name)
|
|
|
|
|
|
|
|
if (buf == null) {
|
|
|
|
buf = this.createChatBuffer(server, name, 'message', false)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (message.type === 'privmsg' && message.message.indexOf('\x01ACTION') === 0) {
|
|
|
|
message.message = message.message.substring(8)
|
2020-02-03 20:32:40 +00:00
|
|
|
message.message = message.message.substring(0, message.message.length - 1)
|
2019-01-09 20:47:21 +00:00
|
|
|
message.type = 'action'
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.addMessage(message.message, message.from, message.type)
|
|
|
|
}
|
|
|
|
|
|
|
|
buildNicklist (channel, server, nicks) {
|
|
|
|
let buf = this.getChatBufferByServerName(server, channel)
|
|
|
|
|
|
|
|
if (buf == null) return
|
|
|
|
|
|
|
|
let channelSendNicks = []
|
|
|
|
|
2020-02-08 13:31:01 +00:00
|
|
|
buf.nicklist.reset()
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
for (let n in nicks) {
|
|
|
|
let nick = { nickname: '', prefix: '', modes: [] }
|
|
|
|
|
|
|
|
if (irc.serverData[buf.server].supportedPrefixes.split('').indexOf(nicks[n].substring(0, 1)) !== -1) {
|
|
|
|
nick.prefix = nicks[n].substring(0, 1)
|
|
|
|
nick.nickname = nicks[n].substring(1)
|
|
|
|
nick.modes = [objectGetKey(irc.serverData[buf.server].modeTranslation, nick.prefix)]
|
|
|
|
channelSendNicks.push(span(nick.prefix, ['prefix']) + span(nick.nickname, ['nick']))
|
|
|
|
} else {
|
|
|
|
nick.nickname = nicks[n]
|
|
|
|
channelSendNicks.push(span(nick.nickname, ['nick']))
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.nicklist.nickAddObject(nick)
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.addMessage(sf('Nicks %s: %s', span(channel, ['channel']), channelSendNicks.join(', ')), null, 'names')
|
|
|
|
|
|
|
|
if (buf.active) {
|
|
|
|
buf.nicklist.render()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nickChange (server, oldNick, newNick) {
|
|
|
|
let buffers = this.getChatBuffersByServer(server)
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
if (irc.serverData[server].userNick === oldNick) {
|
|
|
|
irc.serverData[server].userNick = newNick
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
let activeBuf = this.getActiveChatBuffer()
|
|
|
|
|
|
|
|
if (activeBuf.server === server) {
|
|
|
|
clientdom.currentNickname.innerHTML = newNick
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i in buffers) {
|
|
|
|
let buffer = buffers[i]
|
|
|
|
|
|
|
|
if (buffer.type !== 'channel') continue
|
|
|
|
if (buffer.nicklist.getNickIndex(oldNick) == null) continue
|
|
|
|
|
|
|
|
buffer.nicklist.nickChange(oldNick, newNick)
|
|
|
|
buffer.addMessage(sf('%s is now known as %s', oldNick, newNick), null, 'nick')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
topicChange (channel, server, topic, changer) {
|
|
|
|
let buf = this.getChatBufferByServerName(server, channel)
|
|
|
|
|
|
|
|
if (!buf) return
|
|
|
|
|
|
|
|
buf.topicChange(topic)
|
|
|
|
if (changer) {
|
|
|
|
buf.addMessage(sf('%s has changed the topic of %s to %s', span(changer, ['nick']), channel, topic),
|
|
|
|
null, 'topic')
|
|
|
|
} else {
|
|
|
|
buf.addMessage(sf('Topic of %s is \'%s\'', span(channel, ['channel']), topic), null, 'topic')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleQuit (server, user, reason) {
|
|
|
|
let buffers = this.getChatBuffersByServer(server)
|
|
|
|
|
|
|
|
for (let i in buffers) {
|
|
|
|
let buffer = buffers[i]
|
|
|
|
|
|
|
|
if (buffer.type !== 'channel') continue
|
|
|
|
if (buffer.nicklist.getNickIndex(user.nickname) == null) continue
|
|
|
|
|
|
|
|
buffer.nicklist.nickRemove(user.nickname)
|
|
|
|
buffer.addMessage(sf('%s has quit %s', span(sf('%s@%s', user.username, user.hostname), ['hostmask']), reason), user.nickname, 'quit')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleJoin (server, user, channel) {
|
|
|
|
let buffer = this.getChatBufferByServerName(server, channel)
|
|
|
|
|
|
|
|
if (!buffer) return
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
if (user.nickname === irc.serverData[server].userNick) {
|
2019-01-09 20:47:21 +00:00
|
|
|
buffer.setAliveStatus(true)
|
|
|
|
} else {
|
|
|
|
buffer.nicklist.nickAdd(user.nickname)
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.addMessage(sf('%s has joined %s', span(sf('%s@%s', user.username, user.hostname), ['hostmask']), channel), user.nickname, 'join')
|
|
|
|
}
|
|
|
|
|
|
|
|
handleLeave (server, user, channel, reason, kicker) {
|
|
|
|
let buffer = this.getChatBufferByServerName(server, channel)
|
|
|
|
|
|
|
|
if (!buffer) return
|
|
|
|
|
|
|
|
if (user['nickname']) {
|
2020-02-05 21:04:19 +00:00
|
|
|
if (irc.serverData[server] && user.nickname === irc.serverData[server].userNick) {
|
2019-01-09 20:47:21 +00:00
|
|
|
buffer.setAliveStatus(false)
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-05 21:04:19 +00:00
|
|
|
if (irc.serverData[server] && user === irc.serverData[server].userNick) {
|
2019-01-09 20:47:21 +00:00
|
|
|
buffer.setAliveStatus(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (kicker) {
|
|
|
|
buffer.addMessage(sf('has kicked %s %s', span(user, ['nick']), reason), kicker.nickname, 'part')
|
|
|
|
} else {
|
|
|
|
buffer.addMessage(sf('%s has left %s %s', span(sf('%s@%s', user.username, user.hostname), ['hostmask']), channel,
|
|
|
|
(reason != null ? span(reason, ['reason']) : '')), user.nickname, 'part')
|
|
|
|
}
|
|
|
|
if (kicker) {
|
|
|
|
buffer.nicklist.nickRemove(user)
|
|
|
|
} else {
|
|
|
|
buffer.nicklist.nickRemove(user.nickname)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
handleMode (server, data) {
|
2019-01-09 20:47:21 +00:00
|
|
|
let buf = null
|
2020-02-05 21:04:19 +00:00
|
|
|
if (data.target === irc.serverData[server].userNick) {
|
2020-02-03 19:45:12 +00:00
|
|
|
buf = this.getServerChatBuffer(server)
|
2019-01-09 20:47:21 +00:00
|
|
|
} else {
|
2020-02-03 19:45:12 +00:00
|
|
|
buf = this.getChatBufferByServerName(server, data.target)
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!buf) return
|
|
|
|
|
2020-02-05 21:04:19 +00:00
|
|
|
if (data.type === 'modeAdd') {
|
2019-01-09 20:47:21 +00:00
|
|
|
buf.nicklist.modeAdded(data.modeTarget, data.mode)
|
|
|
|
buf.addMessage('set mode ' + span(data.target, ['channel']) + ' ' + span(sf('+%s %s', data.mode, data.modeTarget), ['mode']),
|
|
|
|
data.user.nickname, 'mode')
|
2020-02-05 21:04:19 +00:00
|
|
|
} else if (data.type === 'modeDel') {
|
2019-01-09 20:47:21 +00:00
|
|
|
buf.nicklist.modeRemoved(data.modeTarget, data.mode)
|
|
|
|
buf.addMessage('set mode ' + span(data.target, ['channel']) + ' ' + span(sf('-%s %s', data.mode, data.modeTarget), ['mode']),
|
|
|
|
data.user.nickname, 'mode')
|
|
|
|
} else {
|
|
|
|
buf.addMessage('set mode ' + span(data.target, ['channel']) + ' ' + span(data.message, ['mode']),
|
|
|
|
data.user.nickname, 'mode')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
joinChannels (server, channel) {
|
2020-02-03 19:45:12 +00:00
|
|
|
if (typeof channel !== 'object') {
|
|
|
|
if (channel.indexOf(',') !== -1) {
|
|
|
|
channel = channel.trim().split(',')
|
2019-01-09 20:47:21 +00:00
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
for (let t in channel) {
|
|
|
|
let chan = channel[t]
|
2019-01-09 20:47:21 +00:00
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
channel[t] = chan.trim()
|
2019-01-09 20:47:21 +00:00
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
if (chan.indexOf('#') !== 0) {
|
|
|
|
channel[t] = '#' + chan
|
|
|
|
}
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
2020-02-03 19:45:12 +00:00
|
|
|
} else if (channel !== '') {
|
|
|
|
channel = channel.trim()
|
|
|
|
if (channel.indexOf('#') !== 0) {
|
|
|
|
channel = '#' + channel
|
|
|
|
}
|
|
|
|
channel = [channel]
|
|
|
|
} else {
|
|
|
|
channel = []
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
sendToServer(server, { command: 'join', message: '', arguments: channel })
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
changeTitle (title) {
|
|
|
|
// TODO: notify of hot buffers
|
|
|
|
document.title = title
|
|
|
|
irc.documentTitle = title
|
|
|
|
}
|
|
|
|
|
|
|
|
render (buffer) {
|
|
|
|
let activeNow = this.getActiveChatBuffer()
|
2020-02-05 21:04:19 +00:00
|
|
|
this.inputHandler.tabCompleteReset()
|
2019-01-09 20:47:21 +00:00
|
|
|
|
|
|
|
if (activeNow) {
|
|
|
|
activeNow.switchOff()
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.render()
|
|
|
|
}
|
2016-09-22 17:15:40 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
// Initialization
|
|
|
|
|
|
|
|
function parseURL () {
|
|
|
|
let match
|
|
|
|
let pl = /\+/g // Regex for replacing addition symbol with a space
|
|
|
|
let search = /([^&=]+)=?([^&]*)/g
|
|
|
|
let decode = (s) => { return decodeURIComponent(s.replace(pl, ' ')) }
|
|
|
|
let query = window.location.search.substring(1)
|
2016-09-23 09:47:12 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
let urlParams = {}
|
|
|
|
while ((match = search.exec(query)) != null) {
|
|
|
|
urlParams[decode(match[1])] = decode(match[2])
|
|
|
|
}
|
2016-09-25 15:21:28 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
irc.auther.fillFormFromURI(urlParams)
|
|
|
|
}
|
2016-09-25 15:21:28 +00:00
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
function stopWarnings () {
|
|
|
|
if (Object.keys(irc.serverData).length === 0) {
|
|
|
|
window.onbeforeunload = null
|
|
|
|
}
|
2016-09-25 15:21:28 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
window.onresize = function () {
|
|
|
|
if (irc.config.scrollOnResize) {
|
|
|
|
clientdom.letterbox.scrollTop = clientdom.letterbox.scrollHeight
|
|
|
|
}
|
2016-12-07 12:58:20 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 20:47:21 +00:00
|
|
|
window.onload = function () {
|
|
|
|
irc.primaryFrame = document.querySelector('.ircclient')
|
|
|
|
|
|
|
|
clientdom.settings['frame'] = irc.primaryFrame.querySelector('.settings')
|
|
|
|
|
|
|
|
for (let key in irc.config) {
|
|
|
|
clientdom.settings[key] = clientdom.settings.frame.querySelector('#s_' + key)
|
|
|
|
}
|
|
|
|
|
|
|
|
clientdom.settings['available_themes'] = clientdom.settings.frame.querySelector('.available_themes')
|
|
|
|
clientdom.settings['save'] = clientdom.settings.frame.querySelector('#save_settings')
|
|
|
|
clientdom.settings['saveStatus'] = clientdom.settings.frame.querySelector('#settings_status')
|
|
|
|
clientdom.connector['frame'] = irc.primaryFrame.querySelector('#authdialog')
|
|
|
|
clientdom.connector['server_data'] = clientdom.connector.frame.querySelector('.server_data')
|
|
|
|
clientdom.connector['messenger'] = clientdom.connector.frame.querySelector('#connmsg')
|
|
|
|
clientdom.connector['form'] = clientdom.connector.frame.querySelector('#IRCConnector')
|
|
|
|
clientdom.connector['nickname'] = clientdom.connector.form.querySelector('#nickname')
|
|
|
|
clientdom.connector['password'] = clientdom.connector.form.querySelector('#password')
|
|
|
|
clientdom.connector['pwtrigger'] = clientdom.connector.form.querySelector('#password_trig')
|
|
|
|
clientdom.connector['pwbox'] = clientdom.connector.form.querySelector('.password_box')
|
|
|
|
clientdom.connector['channel'] = clientdom.connector.form.querySelector('#channel')
|
|
|
|
clientdom.connector['server'] = clientdom.connector.form.querySelector('#server')
|
|
|
|
clientdom.connector['port'] = clientdom.connector.form.querySelector('#port')
|
|
|
|
clientdom.connector['secure'] = clientdom.connector.form.querySelector('#secure')
|
|
|
|
clientdom['tabby'] = irc.primaryFrame.querySelector('.tabby')
|
|
|
|
clientdom['frame'] = irc.primaryFrame.querySelector('#chat')
|
|
|
|
clientdom['letterbox'] = clientdom.frame.querySelector('.letterbox')
|
|
|
|
clientdom['nicklist'] = clientdom.frame.querySelector('.nicklist')
|
2020-02-05 21:08:23 +00:00
|
|
|
clientdom['currentNickname'] = clientdom.frame.querySelector('.my_nickname')
|
2019-01-09 20:47:21 +00:00
|
|
|
clientdom['input'] = clientdom.frame.querySelector('.userinput')
|
|
|
|
clientdom['send'] = clientdom.frame.querySelector('.sendbutton')
|
|
|
|
clientdom['chat'] = clientdom.frame.querySelector('.chatarea')
|
|
|
|
clientdom['topicbar'] = clientdom.chat.querySelector('.topicbar')
|
|
|
|
clientdom['smsctrig'] = clientdom.chat.querySelector('.smsc-nicklistbtn')
|
|
|
|
clientdom.settings['open'] = irc.primaryFrame.querySelector('.open_settings')
|
|
|
|
|
|
|
|
irc.settings = new Settings()
|
2020-02-05 21:04:19 +00:00
|
|
|
irc.settings.setInitialValues()
|
2020-02-03 19:45:12 +00:00
|
|
|
irc.handler = new ConnectionHandler()
|
2019-01-09 20:47:21 +00:00
|
|
|
irc.auther = new IRCConnector()
|
|
|
|
irc.chat = new IRCChatWindow()
|
|
|
|
|
2020-02-03 19:45:12 +00:00
|
|
|
parseURL()
|
|
|
|
window.onpopstate = parseURL
|
2019-01-09 20:47:21 +00:00
|
|
|
}
|