serverless-ircd 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +6 -1
- package/.gitmodules +3 -0
- package/CHANGELOG.md +214 -0
- package/README.md +110 -23
- package/apps/aws-stack/package.json +1 -1
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-worker/package.json +1 -1
- package/apps/cf-worker/src/origin-allowlist.ts +99 -0
- package/apps/cf-worker/src/worker.ts +89 -9
- package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
- package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
- package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
- package/apps/cf-worker/tests/smoke.test.ts +28 -2
- package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
- package/apps/cf-worker/wrangler.test.toml +23 -0
- package/apps/cf-worker/wrangler.toml +54 -0
- package/apps/local-cli/package.json +1 -1
- package/apps/web/landing/index.html +217 -0
- package/apps/web/package.json +28 -0
- package/apps/web/scripts/build.mjs +125 -0
- package/apps/web/src/build-env.ts +43 -0
- package/apps/web/src/config-schema.ts +138 -0
- package/apps/web/static/config.json +28 -0
- package/apps/web/static/config.prod.json +28 -0
- package/apps/web/static/config.staging.json +28 -0
- package/apps/web/tests/build-env.test.ts +63 -0
- package/apps/web/tests/build-smoke.test.ts +103 -0
- package/apps/web/tests/config-schema.test.ts +432 -0
- package/apps/web/tests/workspace.test.ts +12 -0
- package/apps/web/tsconfig.json +10 -0
- package/apps/web/upstream/.browserslistrc +3 -0
- package/apps/web/upstream/.editorconfig +9 -0
- package/apps/web/upstream/.eslintignore +3 -0
- package/apps/web/upstream/.eslintrc.js +90 -0
- package/apps/web/upstream/.github/FUNDING.yml +12 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/apps/web/upstream/.github/workflows/push.yml +26 -0
- package/apps/web/upstream/.github/workflows/release.yml +33 -0
- package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
- package/apps/web/upstream/.prettierrc.js +9 -0
- package/apps/web/upstream/.stylelintignore +5 -0
- package/apps/web/upstream/.stylelintrc.js +21 -0
- package/apps/web/upstream/LICENSE +201 -0
- package/apps/web/upstream/README.md +76 -0
- package/apps/web/upstream/babel.config.js +25 -0
- package/apps/web/upstream/crowdin.yml +3 -0
- package/apps/web/upstream/index.html +35 -0
- package/apps/web/upstream/jest.config.js +7 -0
- package/apps/web/upstream/jsdoc.json +22 -0
- package/apps/web/upstream/package.json +80 -0
- package/apps/web/upstream/scripts/pre-commit +43 -0
- package/apps/web/upstream/src/components/App.vue +516 -0
- package/apps/web/upstream/src/components/AppSettings.vue +587 -0
- package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
- package/apps/web/upstream/src/components/Avatar.vue +105 -0
- package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
- package/apps/web/upstream/src/components/BufferKey.vue +121 -0
- package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
- package/apps/web/upstream/src/components/Captcha.vue +85 -0
- package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
- package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
- package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
- package/apps/web/upstream/src/components/ChannelList.vue +345 -0
- package/apps/web/upstream/src/components/Container.vue +401 -0
- package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
- package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
- package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
- package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
- package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
- package/apps/web/upstream/src/components/MessageList.vue +1028 -0
- package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
- package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
- package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
- package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
- package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
- package/apps/web/upstream/src/components/Nicklist.vue +309 -0
- package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
- package/apps/web/upstream/src/components/NotConnected.vue +271 -0
- package/apps/web/upstream/src/components/SelfUser.vue +283 -0
- package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
- package/apps/web/upstream/src/components/ServerView.vue +126 -0
- package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
- package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
- package/apps/web/upstream/src/components/Sidebar.vue +429 -0
- package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
- package/apps/web/upstream/src/components/SidebarState.vue +145 -0
- package/apps/web/upstream/src/components/StartupError.vue +35 -0
- package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
- package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
- package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
- package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
- package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
- package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
- package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
- package/apps/web/upstream/src/components/UserBox.vue +728 -0
- package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
- package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
- package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
- package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
- package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
- package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
- package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
- package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
- package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
- package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
- package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
- package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
- package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
- package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
- package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
- package/apps/web/upstream/src/helpers/Colours.js +128 -0
- package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
- package/apps/web/upstream/src/helpers/Md5.js +193 -0
- package/apps/web/upstream/src/helpers/Misc.js +401 -0
- package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
- package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
- package/apps/web/upstream/src/libs/AudioManager.js +60 -0
- package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
- package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
- package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
- package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
- package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
- package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
- package/apps/web/upstream/src/libs/IPC.js +51 -0
- package/apps/web/upstream/src/libs/InputHandler.js +921 -0
- package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
- package/apps/web/upstream/src/libs/Logger.js +71 -0
- package/apps/web/upstream/src/libs/Message.js +169 -0
- package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
- package/apps/web/upstream/src/libs/MessageParser.js +249 -0
- package/apps/web/upstream/src/libs/Notifications.js +78 -0
- package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
- package/apps/web/upstream/src/libs/ServerSession.js +102 -0
- package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
- package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
- package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
- package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
- package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
- package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
- package/apps/web/upstream/src/libs/bufferTools.js +177 -0
- package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
- package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
- package/apps/web/upstream/src/libs/settingTools.js +31 -0
- package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
- package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
- package/apps/web/upstream/src/libs/state/UserState.js +89 -0
- package/apps/web/upstream/src/libs/state/common.js +26 -0
- package/apps/web/upstream/src/libs/state.js +961 -0
- package/apps/web/upstream/src/libs/storage/Local.js +51 -0
- package/apps/web/upstream/src/main.js +566 -0
- package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
- package/apps/web/upstream/src/res/configTemplates.js +373 -0
- package/apps/web/upstream/src/res/globalStyle.css +277 -0
- package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
- package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
- package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
- package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
- package/apps/web/upstream/src/res/localesList.json +27 -0
- package/apps/web/upstream/src/res/logo.png +0 -0
- package/apps/web/upstream/src/thirdparty/about.html +43 -0
- package/apps/web/upstream/src/thirdparty/index.js +5 -0
- package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
- package/apps/web/upstream/static/config.json +28 -0
- package/apps/web/upstream/static/emoticons/smile.png +0 -0
- package/apps/web/upstream/static/favicon.png +0 -0
- package/apps/web/upstream/static/highlight.mp3 +0 -0
- package/apps/web/upstream/static/highlight.ogg +0 -0
- package/apps/web/upstream/static/locales/.gitignore +2 -0
- package/apps/web/upstream/static/plugins/customise.html.example +10 -0
- package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
- package/apps/web/upstream/static/themes/common/base.css +1064 -0
- package/apps/web/upstream/static/themes/dark/theme.css +196 -0
- package/apps/web/upstream/static/themes/default/theme.css +92 -0
- package/apps/web/upstream/static/themes/elite/theme.css +248 -0
- package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
- package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
- package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
- package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
- package/apps/web/upstream/static/themes/sky/theme.css +107 -0
- package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
- package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
- package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
- package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
- package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
- package/apps/web/upstream/vue.config.js +150 -0
- package/apps/web/upstream/yarn.lock +9767 -0
- package/apps/web/vitest.config.ts +13 -0
- package/biome.json +1 -0
- package/docs/Home.md +1 -0
- package/docs/WebClientGuide.md +535 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/cf-adapter/package.json +1 -1
- package/packages/cf-adapter/tests/cf-harness.ts +12 -1
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/irc-core/package.json +1 -1
- package/packages/irc-core/reports/mutation/mutation.html +342 -0
- package/packages/irc-core/tests/batch.test.ts +15 -0
- package/packages/irc-core/tests/numerics.test.ts +13 -0
- package/packages/irc-core/tests/parser.test.ts +109 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/scenarios.ts +24 -2
- package/tools/ci-hardening/package.json +1 -1
- package/tools/load-test/package.json +1 -1
- package/tools/tcp-ws-forwarder/package.json +1 -1
|
@@ -0,0 +1,921 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
|
|
5
|
+
import * as TextFormatting from '@/helpers/TextFormatting';
|
|
6
|
+
import * as Misc from '@/helpers/Misc';
|
|
7
|
+
import AliasRewriter from './AliasRewriter';
|
|
8
|
+
|
|
9
|
+
// Map of commandName=commandHandlerFn
|
|
10
|
+
const inputCommands = {};
|
|
11
|
+
|
|
12
|
+
export default class InputHandler {
|
|
13
|
+
constructor(state) {
|
|
14
|
+
this.state = state;
|
|
15
|
+
this.aliasRewriter = new AliasRewriter();
|
|
16
|
+
|
|
17
|
+
// Load the aliases from general settings
|
|
18
|
+
this.aliasRewriter.importFromString(state.setting('aliases'));
|
|
19
|
+
|
|
20
|
+
// Only watch the user setting changes in order to reload them
|
|
21
|
+
state.$watch('user_settings.aliases', (newVal) => {
|
|
22
|
+
this.aliasRewriter.importFromString(state.setting('aliases'));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
this.listenForInput();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
defaultContext() {
|
|
29
|
+
return {
|
|
30
|
+
network: this.state.getActiveNetwork(),
|
|
31
|
+
buffer: this.state.getActiveBuffer(),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
validateContext(context) {
|
|
36
|
+
if (
|
|
37
|
+
typeof context !== 'object' ||
|
|
38
|
+
!Object.prototype.hasOwnProperty.call(context, 'buffer') ||
|
|
39
|
+
!Object.prototype.hasOwnProperty.call(context, 'network') ||
|
|
40
|
+
typeof context.buffer !== 'object' ||
|
|
41
|
+
typeof context.network !== 'object'
|
|
42
|
+
) {
|
|
43
|
+
throw new TypeError('context must contain both network and buffer properties');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
listenForInput() {
|
|
48
|
+
this.state.$on('input.raw', (input, context = this.defaultContext()) => {
|
|
49
|
+
let lines = input.split('\n');
|
|
50
|
+
lines.forEach((line) => this.processLine(line, context));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
processLine(rawLine, context = this.defaultContext()) {
|
|
55
|
+
this.validateContext(context);
|
|
56
|
+
const { network, buffer } = context;
|
|
57
|
+
let line = rawLine;
|
|
58
|
+
let stylesStrippedLine = Misc.stripStyles(line);
|
|
59
|
+
|
|
60
|
+
// If no command specified, server buffers = send raw, channels/queries = send message
|
|
61
|
+
let escapedCommand = stylesStrippedLine.substr(0, 2) === '//';
|
|
62
|
+
if (stylesStrippedLine[0] !== '/' || escapedCommand) {
|
|
63
|
+
if (escapedCommand) {
|
|
64
|
+
line = line.substr(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (buffer.isServer()) {
|
|
68
|
+
line = '/quote ' + line;
|
|
69
|
+
} else {
|
|
70
|
+
line = '/msg ' + buffer.name + ' ' + line;
|
|
71
|
+
}
|
|
72
|
+
} else if (stylesStrippedLine[0] === '/' && line[0] !== '/') {
|
|
73
|
+
// If attempting to send a /command but it has a colour code in front, use the
|
|
74
|
+
// style stripped version of the line
|
|
75
|
+
line = stylesStrippedLine;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let aliasVars = {
|
|
79
|
+
network: network.name,
|
|
80
|
+
server: network.connection.server,
|
|
81
|
+
channel: network.isChannelName(buffer.name) ? buffer.name : '',
|
|
82
|
+
query: network.isChannelName(buffer.name) ? '' : buffer.name,
|
|
83
|
+
destination: buffer.name,
|
|
84
|
+
nick: network.nick,
|
|
85
|
+
};
|
|
86
|
+
line = this.aliasRewriter.process(line, aliasVars);
|
|
87
|
+
|
|
88
|
+
// An alias rewrite may have cancelled out the input
|
|
89
|
+
if (!line) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Remove the / from the start of the line
|
|
94
|
+
line = line.substr(1);
|
|
95
|
+
|
|
96
|
+
let spaceIdx = line.indexOf(' ');
|
|
97
|
+
if (spaceIdx === -1) spaceIdx = line.length;
|
|
98
|
+
|
|
99
|
+
let command = line.substr(0, spaceIdx);
|
|
100
|
+
let params = line.substr(spaceIdx + 1);
|
|
101
|
+
|
|
102
|
+
let eventObj = {
|
|
103
|
+
handled: false,
|
|
104
|
+
raw: rawLine,
|
|
105
|
+
command: command,
|
|
106
|
+
params: params,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Plugins may tap into this event to handle a command themselves
|
|
110
|
+
this.state.$emit('input.command.' + command, eventObj, command, params);
|
|
111
|
+
if (eventObj.handled) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (inputCommands[command.toLowerCase()]) {
|
|
116
|
+
inputCommands[command.toLowerCase()].call(this, eventObj, command, params);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!eventObj.handled) {
|
|
120
|
+
network.ircClient.raw(line);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The actual handler functions for commands. Called in context of the InputHandler instance
|
|
127
|
+
* inputCommand['the /command name'] = function(){};
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
// /lines allows aliases to send multiple commands, separated by |
|
|
131
|
+
inputCommands.lines = function inputCommandLines(event, command, line) {
|
|
132
|
+
event.handled = true;
|
|
133
|
+
|
|
134
|
+
line.split('|').forEach((subLine) => {
|
|
135
|
+
this.processLine(subLine.trim());
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function handleMessage(type, event, command, line) {
|
|
140
|
+
event.handled = true;
|
|
141
|
+
|
|
142
|
+
let network = this.state.getActiveNetwork();
|
|
143
|
+
|
|
144
|
+
let spaceIdx = line.indexOf(' ');
|
|
145
|
+
if (spaceIdx === -1) spaceIdx = line.length;
|
|
146
|
+
|
|
147
|
+
let bufferName = line.substr(0, spaceIdx);
|
|
148
|
+
let message = line.substr(spaceIdx + 1);
|
|
149
|
+
|
|
150
|
+
// Only trim whitespace from the end if we have existing content. Some people enjoy sending
|
|
151
|
+
// pure whitespace messages which we don't want to interfere with
|
|
152
|
+
if (message.replace(/\s+/g, '') !== '') {
|
|
153
|
+
message = message.trimEnd();
|
|
154
|
+
} else {
|
|
155
|
+
// Windows uses \r\n for new lines as we split on \n trim \r from the end
|
|
156
|
+
message = message.replace(/[\r]+$/, '');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Make sure we have some text to actually send
|
|
160
|
+
if (!message) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let localBuffer = bufferName;
|
|
165
|
+
let extractedTarget = network.ircClient.network.extractTargetGroup(bufferName);
|
|
166
|
+
if (extractedTarget) {
|
|
167
|
+
localBuffer = extractedTarget.target;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let buffer = localBuffer.length && this.state.getOrAddBufferByName(network.id, localBuffer);
|
|
171
|
+
if (buffer) {
|
|
172
|
+
let textFormatType = 'privmsg';
|
|
173
|
+
if (type === 'action') {
|
|
174
|
+
textFormatType = 'action';
|
|
175
|
+
} else if (type === 'notice') {
|
|
176
|
+
textFormatType = 'notice';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let messageBody = TextFormatting.formatText(textFormatType, {
|
|
180
|
+
nick: network.nick,
|
|
181
|
+
text: message,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
let newMessage = {
|
|
185
|
+
time: Date.now(),
|
|
186
|
+
nick: network.nick,
|
|
187
|
+
message: messageBody,
|
|
188
|
+
type: type,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
this.state.addMessage(buffer, newMessage);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let fnNames = {
|
|
195
|
+
privmsg: 'say',
|
|
196
|
+
action: 'action',
|
|
197
|
+
notice: 'notice',
|
|
198
|
+
};
|
|
199
|
+
let fnName = fnNames[type] || 'say';
|
|
200
|
+
network.ircClient[fnName](bufferName, message);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
inputCommands.msg = function inputCommandMsg(event, command, line) {
|
|
204
|
+
handleMessage.call(this, 'privmsg', event, command, line);
|
|
205
|
+
};
|
|
206
|
+
inputCommands.action = function inputCommandMsg(event, command, line) {
|
|
207
|
+
handleMessage.call(this, 'action', event, command, line);
|
|
208
|
+
};
|
|
209
|
+
inputCommands.notice = function inputCommandMsg(event, command, line) {
|
|
210
|
+
handleMessage.call(this, 'notice', event, command, line);
|
|
211
|
+
};
|
|
212
|
+
inputCommands.dice = function inputCommandDice(event, command, line) {
|
|
213
|
+
// /dice 100
|
|
214
|
+
|
|
215
|
+
event.handled = true;
|
|
216
|
+
let buffer = this.state.getActiveBuffer();
|
|
217
|
+
let network = this.state.getActiveNetwork();
|
|
218
|
+
|
|
219
|
+
let sides = line.replace(/\D/g, '');
|
|
220
|
+
sides = parseInt(sides || '0', 10);
|
|
221
|
+
if (sides <= 0) {
|
|
222
|
+
sides = 6;
|
|
223
|
+
}
|
|
224
|
+
let rndNumber = Math.floor(Math.random() * sides) + 1;
|
|
225
|
+
|
|
226
|
+
let msg = TextFormatting.t('dice_roll', {
|
|
227
|
+
sides: TextFormatting.formatNumber(sides),
|
|
228
|
+
number: TextFormatting.formatNumber(rndNumber),
|
|
229
|
+
});
|
|
230
|
+
network.ircClient.action(buffer.name, msg);
|
|
231
|
+
this.state.addMessage(buffer, {
|
|
232
|
+
nick: network.nick,
|
|
233
|
+
message: msg,
|
|
234
|
+
type: 'action',
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
inputCommands.ctcp = function inputCommandCtcp(event, command, line) {
|
|
239
|
+
event.handled = true;
|
|
240
|
+
|
|
241
|
+
let params = line.split(' ');
|
|
242
|
+
let target = params.shift();
|
|
243
|
+
let ctcpType = params.shift();
|
|
244
|
+
|
|
245
|
+
if (!ctcpType || !target) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
let network = this.state.getActiveNetwork();
|
|
250
|
+
network.ircClient.ctcpRequest(...[target, ctcpType].concat(params));
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
inputCommands.join = function inputCommandJoin(event, command, line) {
|
|
254
|
+
event.handled = true;
|
|
255
|
+
|
|
256
|
+
let network = this.state.getActiveNetwork();
|
|
257
|
+
let bufferObjs = Misc.extractBuffers(line);
|
|
258
|
+
|
|
259
|
+
// handle join without any buffers specified
|
|
260
|
+
if (bufferObjs.length === 0) {
|
|
261
|
+
let buffer = this.state.getActiveBuffer();
|
|
262
|
+
|
|
263
|
+
// join the active channel if its not joined
|
|
264
|
+
if (buffer.isChannel() && !buffer.joined) {
|
|
265
|
+
network.ircClient.join(buffer.name, buffer.key);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// report an error if the user tries to join without specifying the channel
|
|
270
|
+
this.state.addMessage(buffer, {
|
|
271
|
+
nick: '*',
|
|
272
|
+
message: TextFormatting.t('error_no_channel_join'),
|
|
273
|
+
type: 'error',
|
|
274
|
+
});
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Only switch to the first channel we join if multiple are being joined
|
|
279
|
+
let hasSwitchedActiveBuffer = false;
|
|
280
|
+
bufferObjs.forEach((bufferObj, idx) => {
|
|
281
|
+
// /join 0 parts all channels and is only ever used to troll IRC newbies.
|
|
282
|
+
// Just disable it entirely.
|
|
283
|
+
if (bufferObj.name === '0') {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Prepend a # channel prefix if not specified already
|
|
288
|
+
let chanName = network.isChannelName(bufferObj.name) ?
|
|
289
|
+
bufferObj.name :
|
|
290
|
+
'#' + bufferObj.name;
|
|
291
|
+
|
|
292
|
+
let newBuffer = this.state.addBuffer(network.id, chanName);
|
|
293
|
+
|
|
294
|
+
if (newBuffer && !hasSwitchedActiveBuffer) {
|
|
295
|
+
this.state.setActiveBuffer(network.id, newBuffer.name);
|
|
296
|
+
hasSwitchedActiveBuffer = true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (bufferObj.key) {
|
|
300
|
+
newBuffer.key = bufferObj.key;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
network.ircClient.join(chanName, bufferObj.key);
|
|
304
|
+
});
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
inputCommands.part = function inputCommandPart(event, command, line) {
|
|
308
|
+
event.handled = true;
|
|
309
|
+
|
|
310
|
+
let network = this.state.getActiveNetwork();
|
|
311
|
+
let bufferNames = [];
|
|
312
|
+
let message = '';
|
|
313
|
+
|
|
314
|
+
if (line === '') {
|
|
315
|
+
// /part
|
|
316
|
+
bufferNames = [this.state.getActiveBuffer().name];
|
|
317
|
+
} else {
|
|
318
|
+
let lineParts = line.split(' ');
|
|
319
|
+
if (network.isChannelName(lineParts[0])) {
|
|
320
|
+
// /part #channel,#possible_channel possible part message
|
|
321
|
+
bufferNames = _.compact(lineParts[0].split(','));
|
|
322
|
+
message = lineParts.slice(1).join(' ');
|
|
323
|
+
} else {
|
|
324
|
+
// /part possible part message
|
|
325
|
+
bufferNames = [this.state.getActiveBuffer().name];
|
|
326
|
+
message = line;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
bufferNames.forEach((bufferName) => {
|
|
331
|
+
network.ircClient.part(bufferName, message);
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
inputCommands.quit = function inputCommandQuit(event, command, line) {
|
|
336
|
+
event.handled = true;
|
|
337
|
+
|
|
338
|
+
let network = this.state.getActiveNetwork();
|
|
339
|
+
network.ircClient.quit(line);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
inputCommands.topic = function inputCommandTopic(event, command, line) {
|
|
343
|
+
event.handled = true;
|
|
344
|
+
|
|
345
|
+
let network = this.state.getActiveNetwork();
|
|
346
|
+
let bufferName = '';
|
|
347
|
+
let newTopic = '';
|
|
348
|
+
|
|
349
|
+
if (line === '') {
|
|
350
|
+
// /topic
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
let lineParts = line.split(' ');
|
|
355
|
+
if (network.isChannelName(lineParts[0])) {
|
|
356
|
+
// /topic #channel a topic
|
|
357
|
+
bufferName = lineParts[0];
|
|
358
|
+
newTopic = lineParts.slice(1).join(' ');
|
|
359
|
+
} else {
|
|
360
|
+
// /topic a topic
|
|
361
|
+
bufferName = this.state.getActiveBuffer().name;
|
|
362
|
+
newTopic = line;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
network.ircClient.setTopic(bufferName, newTopic);
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
inputCommands.kick = function inputCommandKick(event, command, line) {
|
|
369
|
+
event.handled = true;
|
|
370
|
+
|
|
371
|
+
let network = this.state.getActiveNetwork();
|
|
372
|
+
let toKick = '';
|
|
373
|
+
let bufferName = '';
|
|
374
|
+
let kickReason = '';
|
|
375
|
+
|
|
376
|
+
if (line === '') {
|
|
377
|
+
// No params given
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let lineParts = line.split(' ');
|
|
382
|
+
|
|
383
|
+
if (network.isChannelName(lineParts[0])) {
|
|
384
|
+
bufferName = lineParts.shift();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
toKick = lineParts.shift();
|
|
388
|
+
kickReason = lineParts.join(' ');
|
|
389
|
+
|
|
390
|
+
if (!bufferName) {
|
|
391
|
+
bufferName = this.state.getActiveBuffer().name;
|
|
392
|
+
}
|
|
393
|
+
if (!toKick) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
network.ircClient.raw('KICK', bufferName, toKick, kickReason);
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
inputCommands.ignore = function inputCommandIgnore(event, command, line) {
|
|
401
|
+
event.handled = true;
|
|
402
|
+
|
|
403
|
+
let network = this.state.getActiveNetwork();
|
|
404
|
+
let toIgnore = line.split(' ').shift();
|
|
405
|
+
|
|
406
|
+
if (!toIgnore) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
let user = this.state.getUser(network.id, toIgnore);
|
|
411
|
+
if (user) {
|
|
412
|
+
user.ignore = true;
|
|
413
|
+
let buffer = this.state.getActiveBuffer();
|
|
414
|
+
this.state.addMessage(buffer, {
|
|
415
|
+
nick: '*',
|
|
416
|
+
message: 'Ignoring ' + user.nick,
|
|
417
|
+
type: 'message',
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
inputCommands.unignore = function inputCommandUnignore(event, command, line) {
|
|
423
|
+
event.handled = true;
|
|
424
|
+
|
|
425
|
+
let network = this.state.getActiveNetwork();
|
|
426
|
+
let toUnignore = line.split(' ').shift();
|
|
427
|
+
|
|
428
|
+
if (!toUnignore) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
let user = this.state.getUser(network.id, toUnignore);
|
|
433
|
+
if (user) {
|
|
434
|
+
user.ignore = false;
|
|
435
|
+
let buffer = this.state.getActiveBuffer();
|
|
436
|
+
this.state.addMessage(buffer, {
|
|
437
|
+
nick: '*',
|
|
438
|
+
message: 'No longer ignoring ' + user.nick,
|
|
439
|
+
type: 'message',
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
inputCommands.close = function inputCommandClose(event, command, line) {
|
|
445
|
+
event.handled = true;
|
|
446
|
+
|
|
447
|
+
let network = this.state.getActiveNetwork();
|
|
448
|
+
let bufferNames = _.compact(line.split(/[, ]/));
|
|
449
|
+
if (bufferNames.length === 0) {
|
|
450
|
+
bufferNames = [this.state.getActiveBuffer().name];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
bufferNames.forEach((bufferName) => {
|
|
454
|
+
let buffer = network.bufferByName(bufferName);
|
|
455
|
+
if (!buffer) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
this.state.removeBuffer(buffer);
|
|
460
|
+
});
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
inputCommands.query = function inputCommandQuery(event, command, line) {
|
|
464
|
+
event.handled = true;
|
|
465
|
+
|
|
466
|
+
let pos = line.indexOf(' ');
|
|
467
|
+
if (pos === -1) {
|
|
468
|
+
pos = line.length;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
let nick = line.substr(0, pos);
|
|
472
|
+
let message = line.substr(pos + 1);
|
|
473
|
+
|
|
474
|
+
let network = this.state.getActiveNetwork();
|
|
475
|
+
let buffer = this.state.getOrAddBufferByName(network.id, nick);
|
|
476
|
+
|
|
477
|
+
this.state.setActiveBuffer(network.id, buffer.name);
|
|
478
|
+
|
|
479
|
+
if (message) {
|
|
480
|
+
this.state.$emit('input.raw', '/msg ' + buffer.name + ' ' + message);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
inputCommands.invite = function inputCommandInvite(event, command, line) {
|
|
485
|
+
event.handled = true;
|
|
486
|
+
|
|
487
|
+
let network = this.state.getActiveNetwork();
|
|
488
|
+
let buffer = this.state.getActiveBuffer();
|
|
489
|
+
|
|
490
|
+
let lineParts = line.split(' ');
|
|
491
|
+
let nick = lineParts.shift();
|
|
492
|
+
let channel = lineParts.shift();
|
|
493
|
+
|
|
494
|
+
if (!channel) {
|
|
495
|
+
channel = buffer.name;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (!network.isChannelName(channel)) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
network.ircClient.raw('INVITE', nick, channel);
|
|
503
|
+
this.state.addMessage(buffer, {
|
|
504
|
+
nick: '*',
|
|
505
|
+
message: `Invited ${nick} to ${channel}`,
|
|
506
|
+
type: 'message',
|
|
507
|
+
});
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
inputCommands.nick = function inputCommandNick(event, command, line) {
|
|
511
|
+
event.handled = true;
|
|
512
|
+
|
|
513
|
+
let spaceIdx = line.indexOf(' ');
|
|
514
|
+
if (spaceIdx === -1) spaceIdx = line.length;
|
|
515
|
+
|
|
516
|
+
let newNick = line.substr(0, spaceIdx);
|
|
517
|
+
let network = this.state.getActiveNetwork();
|
|
518
|
+
network.ircClient.changeNick(newNick);
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
inputCommands.away = function inputCommandAway(event, command, line) {
|
|
522
|
+
event.handled = true;
|
|
523
|
+
|
|
524
|
+
let network = this.state.getActiveNetwork();
|
|
525
|
+
network.ircClient.raw('AWAY', line || 'Currently away');
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
inputCommands.back = function inputCommandAway(event, command, line) {
|
|
529
|
+
event.handled = true;
|
|
530
|
+
|
|
531
|
+
let network = this.state.getActiveNetwork();
|
|
532
|
+
network.ircClient.raw('AWAY');
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
inputCommands.quote = function inputCommandQuote(event, command, line) {
|
|
536
|
+
event.handled = true;
|
|
537
|
+
|
|
538
|
+
let network = this.state.getActiveNetwork();
|
|
539
|
+
|
|
540
|
+
// Sending a manual CAP command triggers raw CAPs to be shown in the server tab
|
|
541
|
+
if (line.split(' ')[0].toLowerCase() === 'cap') {
|
|
542
|
+
network.setting('show_raw_caps', true);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
let buffer = this.state.getActiveBuffer();
|
|
546
|
+
if (buffer.isServer()) {
|
|
547
|
+
this.state.addMessage(buffer, {
|
|
548
|
+
time: Date.now(),
|
|
549
|
+
nick: '',
|
|
550
|
+
message: line,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
network.ircClient.raw(line);
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
inputCommands.whois = function inputCommandWhois(event, command, line) {
|
|
558
|
+
event.handled = true;
|
|
559
|
+
|
|
560
|
+
let parts = line.split(' ');
|
|
561
|
+
let network = this.state.getActiveNetwork();
|
|
562
|
+
let buffer = this.state.getActiveBuffer();
|
|
563
|
+
|
|
564
|
+
network.ircClient.whois(parts[0], parts[0], (whoisData) => {
|
|
565
|
+
if (whoisData.error) {
|
|
566
|
+
let messageBody = TextFormatting.formatText('whois_error', {
|
|
567
|
+
nick: whoisData.nick,
|
|
568
|
+
text: whoisData.error,
|
|
569
|
+
});
|
|
570
|
+
this.state.addMessage(buffer, {
|
|
571
|
+
time: Date.now(),
|
|
572
|
+
nick: '',
|
|
573
|
+
message: messageBody,
|
|
574
|
+
type: 'error',
|
|
575
|
+
});
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
let out = [];
|
|
580
|
+
let display = (message) => {
|
|
581
|
+
if (!message) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
out.push(message);
|
|
586
|
+
};
|
|
587
|
+
let formats = {
|
|
588
|
+
mask: 'is {{nick}}!{{user}}@{{host}} * ({{real_name}})',
|
|
589
|
+
from: 'is connecting from {{actual_hostname}} {{actual_ip}}',
|
|
590
|
+
channels: 'is on {{channels}}',
|
|
591
|
+
server: 'is using {{server}} ({{server_info}})',
|
|
592
|
+
operator: '{{operator}}',
|
|
593
|
+
modes: '{{modes}}',
|
|
594
|
+
account: 'is logged in as {{account}}',
|
|
595
|
+
registered_nick: '{{registered_nick}}',
|
|
596
|
+
secure: 'is using a secure connection',
|
|
597
|
+
idle: 'has been idle for {{idle}}',
|
|
598
|
+
country: '{{country}}',
|
|
599
|
+
certfp: '{{certfp}}',
|
|
600
|
+
logon: 'connected on {{logon}}',
|
|
601
|
+
|
|
602
|
+
// The following entries will be ignored from whoisData as display() ignores
|
|
603
|
+
// empty lines.
|
|
604
|
+
nick: '',
|
|
605
|
+
user: '',
|
|
606
|
+
ident: '',
|
|
607
|
+
hostname: '',
|
|
608
|
+
real_name: '',
|
|
609
|
+
actual_ip: '',
|
|
610
|
+
server_info: '',
|
|
611
|
+
actual_hostname: '',
|
|
612
|
+
country_code: '',
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
// Display a select few entries first to keep a consistent order, and then
|
|
616
|
+
// show any extra information at the end
|
|
617
|
+
if (whoisData.nick && whoisData.hostname) {
|
|
618
|
+
display(formats.mask
|
|
619
|
+
.replace('{{nick}}', whoisData.nick)
|
|
620
|
+
.replace('{{user}}', whoisData.ident)
|
|
621
|
+
.replace('{{host}}', whoisData.hostname)
|
|
622
|
+
.replace('{{real_name}}', whoisData.real_name));
|
|
623
|
+
}
|
|
624
|
+
if (whoisData.actual_hostname && whoisData.actual_ip) {
|
|
625
|
+
display(formats.from
|
|
626
|
+
.replace('{{actual_hostname}}', whoisData.actual_hostname)
|
|
627
|
+
.replace('{{actual_ip}}', whoisData.actual_ip));
|
|
628
|
+
}
|
|
629
|
+
if (whoisData.country) {
|
|
630
|
+
display(formats.country.replace('{{country}}', whoisData.country));
|
|
631
|
+
}
|
|
632
|
+
if (whoisData.channels) {
|
|
633
|
+
display(formats.channels.replace('{{channels}}', whoisData.channels));
|
|
634
|
+
}
|
|
635
|
+
if (whoisData.server) {
|
|
636
|
+
display(formats.server
|
|
637
|
+
.replace('{{server}}', whoisData.server)
|
|
638
|
+
.replace('{{server_info}}', whoisData.server_info));
|
|
639
|
+
}
|
|
640
|
+
if (whoisData.operator) {
|
|
641
|
+
display(formats.operator.replace('{{operator}}', whoisData.operator));
|
|
642
|
+
}
|
|
643
|
+
if (whoisData.modes) {
|
|
644
|
+
display(formats.modes.replace('{{modes}}', whoisData.modes));
|
|
645
|
+
}
|
|
646
|
+
if (whoisData.account) {
|
|
647
|
+
display(formats.account.replace('{{account}}', whoisData.account));
|
|
648
|
+
}
|
|
649
|
+
if (whoisData.registered_nick) {
|
|
650
|
+
display(formats.registered_nick.replace('{{registered_nick}}', whoisData.registered_nick));
|
|
651
|
+
}
|
|
652
|
+
if (whoisData.secure) {
|
|
653
|
+
display(formats.secure);
|
|
654
|
+
}
|
|
655
|
+
if (whoisData.certfp) {
|
|
656
|
+
display(formats.certfp.replace('{{certfp}}', whoisData.certfp));
|
|
657
|
+
}
|
|
658
|
+
if (whoisData.idle) {
|
|
659
|
+
let idleSeconds = Math.floor(parseInt(whoisData.idle, 10));
|
|
660
|
+
display(formats.idle.replace('{{idle}}', TextFormatting.formatDuration(idleSeconds)));
|
|
661
|
+
}
|
|
662
|
+
if (whoisData.logon) {
|
|
663
|
+
let logonTime = parseInt(whoisData.logon, 10);
|
|
664
|
+
if (!Number.isNaN(logonTime)) {
|
|
665
|
+
let logonDate = new Date(logonTime * 1000);
|
|
666
|
+
display(formats.logon.replace('{{logon}}', logonDate));
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
_.each(whoisData, (val, key) => {
|
|
671
|
+
// Only include lines we haven't already used
|
|
672
|
+
if (typeof formats[key] === 'undefined') {
|
|
673
|
+
// Some keys such as `special` are arrays of values
|
|
674
|
+
if (_.isArray(val)) {
|
|
675
|
+
val.forEach((v) => display(`${key}: ${v}`));
|
|
676
|
+
} else {
|
|
677
|
+
display(`${key}: ${val}`);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
out.forEach((l) => {
|
|
683
|
+
this.state.addMessage(buffer, {
|
|
684
|
+
nick: parts[0],
|
|
685
|
+
message: l,
|
|
686
|
+
type: 'whois',
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
inputCommands.whowas = function inputCommandWhowas(event, command, line) {
|
|
693
|
+
event.handled = true;
|
|
694
|
+
|
|
695
|
+
let parts = line.split(' ');
|
|
696
|
+
let network = this.state.getActiveNetwork();
|
|
697
|
+
let buffer = this.state.getActiveBuffer();
|
|
698
|
+
|
|
699
|
+
network.ircClient.whowas(parts[0], parts[0], (whowasData) => {
|
|
700
|
+
if (whowasData.error) {
|
|
701
|
+
let messageBody = TextFormatting.formatText('whowas_error', {
|
|
702
|
+
nick: whowasData.nick,
|
|
703
|
+
text: whowasData.error,
|
|
704
|
+
});
|
|
705
|
+
this.state.addMessage(buffer, {
|
|
706
|
+
time: Date.now(),
|
|
707
|
+
nick: '',
|
|
708
|
+
message: messageBody,
|
|
709
|
+
type: 'whowas',
|
|
710
|
+
});
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
['whowas_ident', 'whowas_server'].forEach((prop) => {
|
|
715
|
+
let messageBody = TextFormatting.formatText(prop, {
|
|
716
|
+
nick: whowasData.nick,
|
|
717
|
+
ident: whowasData.ident,
|
|
718
|
+
host: whowasData.hostname,
|
|
719
|
+
name: whowasData.real_name,
|
|
720
|
+
server: whowasData.server,
|
|
721
|
+
info: whowasData.server_info,
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
this.state.addMessage(buffer, {
|
|
725
|
+
time: Date.now(),
|
|
726
|
+
nick: whowasData.nick,
|
|
727
|
+
message: messageBody,
|
|
728
|
+
type: 'whowas',
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
});
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
inputCommands.mode = function inputCommandMode(event, command, line) {
|
|
735
|
+
event.handled = true;
|
|
736
|
+
|
|
737
|
+
// /mode [target] [+-modes]
|
|
738
|
+
|
|
739
|
+
let network = this.state.getActiveNetwork();
|
|
740
|
+
let buffer = this.state.getActiveBuffer();
|
|
741
|
+
let target = buffer.isChannel() ?
|
|
742
|
+
buffer.name :
|
|
743
|
+
network.nick;
|
|
744
|
+
|
|
745
|
+
let parts = _.compact(line.split(' '));
|
|
746
|
+
|
|
747
|
+
if (line && line[0] !== '+' && line[0] !== '-') {
|
|
748
|
+
target = parts.shift();
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if (parts[0]) {
|
|
752
|
+
// parts[0] = the mode(s)
|
|
753
|
+
// parts[1] = optional mode arguments
|
|
754
|
+
|
|
755
|
+
// If we're asking for a ban list, show the response in the active channel
|
|
756
|
+
if (parts[0] === '+b' && !parts[1]) {
|
|
757
|
+
buffer.flags.requested_banlist = true;
|
|
758
|
+
// An IRCd may fuck up and simply not reply to a MODE command. Give a few seconds
|
|
759
|
+
// for it to reply and if not, ignore our request was sent
|
|
760
|
+
setTimeout(() => {
|
|
761
|
+
buffer.flags.requested_banlist = false;
|
|
762
|
+
}, 4000);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
network.ircClient.mode(target, parts[0], parts.splice(1));
|
|
766
|
+
} else {
|
|
767
|
+
// No modes specified will request the modes for the target
|
|
768
|
+
network.ircClient.mode(target);
|
|
769
|
+
|
|
770
|
+
if (target === buffer.name) {
|
|
771
|
+
// If we have requested modes for the active channel then flag it to show
|
|
772
|
+
// the response in the buffer itself. Wait a few seconds before removing
|
|
773
|
+
// the flag as there is no way to determine that everything has been received.
|
|
774
|
+
buffer.flags.requested_modes = true;
|
|
775
|
+
setTimeout(() => {
|
|
776
|
+
buffer.flags.requested_modes = false;
|
|
777
|
+
}, 4000);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
inputCommands.names = function inputCommandNames(event, command, line) {
|
|
783
|
+
event.handled = true;
|
|
784
|
+
|
|
785
|
+
// /names [#channel]
|
|
786
|
+
|
|
787
|
+
let network = this.state.getActiveNetwork();
|
|
788
|
+
let args = line;
|
|
789
|
+
|
|
790
|
+
if (!args) {
|
|
791
|
+
args = this.state.getActiveBuffer().name;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
network.ircClient.raw('NAMES ' + args);
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
inputCommands.inject = function inputCommandInject(event, command, line) {
|
|
798
|
+
event.handled = true;
|
|
799
|
+
|
|
800
|
+
let network = this.state.getActiveNetwork();
|
|
801
|
+
let connection = network.ircClient.connection;
|
|
802
|
+
connection.addReadBuffer(line);
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
inputCommands.clear = function inputCommandClear(event, command, line) {
|
|
806
|
+
event.handled = true;
|
|
807
|
+
|
|
808
|
+
let buffer = this.state.getActiveBuffer();
|
|
809
|
+
buffer.clearMessages();
|
|
810
|
+
|
|
811
|
+
this.state.addMessage(buffer, {
|
|
812
|
+
nick: '*',
|
|
813
|
+
message: 'Scrollback cleared',
|
|
814
|
+
});
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
inputCommands.echo = function inputCommandEcho(event, command, line) {
|
|
818
|
+
event.handled = true;
|
|
819
|
+
|
|
820
|
+
let buffer = this.state.getActiveBuffer();
|
|
821
|
+
|
|
822
|
+
this.state.addMessage(buffer, {
|
|
823
|
+
nick: '*',
|
|
824
|
+
message: line,
|
|
825
|
+
});
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
inputCommands.set = function inputCommandEcho(event, command, line) {
|
|
829
|
+
event.handled = true;
|
|
830
|
+
|
|
831
|
+
let buffer = this.state.getActiveBuffer();
|
|
832
|
+
|
|
833
|
+
let setting = '';
|
|
834
|
+
let spacePos = line.indexOf(' ');
|
|
835
|
+
|
|
836
|
+
if (spacePos > -1) {
|
|
837
|
+
// Anything after the space becomes the new setting value
|
|
838
|
+
// false = boolean false
|
|
839
|
+
// true = boolean true
|
|
840
|
+
// off = boolean false
|
|
841
|
+
// on = boolean true
|
|
842
|
+
// "false" = string false
|
|
843
|
+
// "true" = string true
|
|
844
|
+
setting = line.substr(0, spacePos);
|
|
845
|
+
let value = line.substr(spacePos + 1).trim();
|
|
846
|
+
switch (value.toLowerCase().trim()) {
|
|
847
|
+
case 'true':
|
|
848
|
+
case 'on':
|
|
849
|
+
value = true;
|
|
850
|
+
break;
|
|
851
|
+
case 'false':
|
|
852
|
+
case 'off':
|
|
853
|
+
value = false;
|
|
854
|
+
break;
|
|
855
|
+
default:
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Unquote any quoted values
|
|
859
|
+
// ie. "true" should jsut be the string true
|
|
860
|
+
if (value[0] === '"' && value[value.length - 1] === '"') {
|
|
861
|
+
value = value.substr(1, value.length - 2);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
this.state.setting(setting, value);
|
|
865
|
+
} else {
|
|
866
|
+
setting = line;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
this.state.addMessage(buffer, {
|
|
870
|
+
nick: '*',
|
|
871
|
+
message: `${setting} = ${this.state.setting(setting)}`,
|
|
872
|
+
});
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
inputCommands.list = function inputCommandList(event, command, line) {
|
|
876
|
+
event.handled = true;
|
|
877
|
+
|
|
878
|
+
let network = this.state.getActiveNetwork();
|
|
879
|
+
if (!network.channel_list.length && network.channel_list_state !== 'updating') {
|
|
880
|
+
network.channel_list_state = 'updating';
|
|
881
|
+
network.ircClient.raw('LIST ' + line);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
network.showServerBuffer('channels');
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
inputCommands.server = function inputCommandServer(event, command, line) {
|
|
888
|
+
event.handled = true;
|
|
889
|
+
|
|
890
|
+
let parts = line.split(' ');
|
|
891
|
+
let serverAddr = parts[0];
|
|
892
|
+
let serverPort = parts[1] || 6667;
|
|
893
|
+
let serverTls = false;
|
|
894
|
+
let serverPassword = parts[2];
|
|
895
|
+
let nick = parts[3] || 'ircuser';
|
|
896
|
+
|
|
897
|
+
if (serverPort[0] === '+') {
|
|
898
|
+
serverTls = true;
|
|
899
|
+
serverPort = parseInt(serverPort.substr(1), 10);
|
|
900
|
+
} else {
|
|
901
|
+
serverTls = false;
|
|
902
|
+
serverPort = parseInt(serverPort, 10);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
this.state.addNetwork(serverAddr, nick, {
|
|
906
|
+
server: serverAddr,
|
|
907
|
+
port: serverPort,
|
|
908
|
+
tls: serverTls,
|
|
909
|
+
password: serverPassword,
|
|
910
|
+
});
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
inputCommands.beep = function inputCommandBeep(event, command, line) {
|
|
914
|
+
event.handled = true;
|
|
915
|
+
this.state.$emit('audio.bleep');
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
inputCommands.notify = function inputCommandNotify(event, command, line) {
|
|
919
|
+
event.handled = true;
|
|
920
|
+
this.state.$emit('notification.show', line);
|
|
921
|
+
};
|