From 8bd8c74613651370d144e375f2061d6d86b66379 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sun, 1 Sep 2019 14:14:25 +0200 Subject: [PATCH] Some updates --- build_declarations.sh | 2 +- modules/renderer/audio/AudioPlayer.ts | 4 +- modules/renderer/audio/AudioRecorder.ts | 33 +- modules/renderer/connection/FileTransfer.ts | 89 + .../renderer/connection/ServerConnection.ts | 2 + .../imports/.copy_imports_shared.d.ts | 2237 +++++++++-------- native/CMakeLists.txt | 2 +- .../src/audio/AudioMerger.cpp | 6 +- .../src/audio/AudioOutput.cpp | 10 +- .../serverconnection/src/audio/AudioOutput.h | 3 +- .../src/audio/codec/OpusConverter.cpp | 6 + .../src/audio/js/AudioOutputStream.cpp | 2 +- .../src/connection/ServerConnection.cpp | 1 + .../src/connection/audio/AudioSender.cpp | 39 +- .../src/connection/audio/VoiceClient.cpp | 138 +- .../src/connection/audio/VoiceClient.h | 9 + .../src/connection/audio/VoiceConnection.cpp | 14 +- .../src/connection/ft/FileTransferObject.cpp | 10 + .../src/connection/ft/FileTransferObject.h | 2 +- package.json | 2 +- 20 files changed, 1567 insertions(+), 1044 deletions(-) diff --git a/build_declarations.sh b/build_declarations.sh index 803e4c0..f57c21a 100755 --- a/build_declarations.sh +++ b/build_declarations.sh @@ -11,7 +11,7 @@ file_paths=( #TODO Windows path ) files=( - "exports.d.ts;imports_shared.d.ts" + "exports_app.d.ts;imports_shared.d.ts" # "exports_loader.d.ts;imports_shared_loader.d.ts" ) diff --git a/modules/renderer/audio/AudioPlayer.ts b/modules/renderer/audio/AudioPlayer.ts index dbbe9bd..9aeb886 100644 --- a/modules/renderer/audio/AudioPlayer.ts +++ b/modules/renderer/audio/AudioPlayer.ts @@ -45,7 +45,7 @@ namespace audio.player { export function initialize() { _output_stream = naudio.playback.create_stream(); - _output_stream.set_buffer_max_latency(0.08); + _output_stream.set_buffer_max_latency(0.4); _output_stream.set_buffer_latency(0.02); _output_stream.callback_overflow = () => { @@ -57,7 +57,7 @@ namespace audio.player { }; _audioContext = new AudioContext(); - _processor = _audioContext.createScriptProcessor(1024, _output_stream.channels, _output_stream.channels); + _processor = _audioContext.createScriptProcessor(1024 * 8, _output_stream.channels, _output_stream.channels); _processor.onaudioprocess = function(event) { const buffer = event.inputBuffer; diff --git a/modules/renderer/audio/AudioRecorder.ts b/modules/renderer/audio/AudioRecorder.ts index 16b3594..c4ef943 100644 --- a/modules/renderer/audio/AudioRecorder.ts +++ b/modules/renderer/audio/AudioRecorder.ts @@ -250,6 +250,25 @@ export namespace _audio.recorder { constructor() { this.handle = naudio.record.create_recorder(); + + this.consumer = this.handle.create_consumer(); + this.consumer.callback_ended = () => { + if(this._current_state !== audio.recorder.InputState.RECORDING) + return; + + this._current_state = audio.recorder.InputState.DRY; + if(this.callback_end) + this.callback_end(); + }; + this.consumer.callback_started = () => { + if(this._current_state !== audio.recorder.InputState.DRY) + return; + + this._current_state = audio.recorder.InputState.RECORDING; + if(this.callback_begin) + this.callback_begin(); + }; + this._current_state = audio.recorder.InputState.PAUSED; } @@ -370,20 +389,6 @@ export namespace _audio.recorder { this._current_state = audio.recorder.InputState.DRY; try { - if(!this.consumer) { - this.consumer = this.handle.create_consumer(); - this.consumer.callback_ended = () => { - this._current_state = audio.recorder.InputState.RECORDING; - if(this.callback_end) - this.callback_end(); - }; - this.consumer.callback_started = () => { - this._current_state = audio.recorder.InputState.DRY; - if(this.callback_begin) - this.callback_begin(); - }; - } - await new Promise((resolve, reject) => { this.handle.start(flag => { if(flag) diff --git a/modules/renderer/connection/FileTransfer.ts b/modules/renderer/connection/FileTransfer.ts index c3c658f..449695c 100644 --- a/modules/renderer/connection/FileTransfer.ts +++ b/modules/renderer/connection/FileTransfer.ts @@ -88,10 +88,99 @@ namespace _transfer { } } + class NativeFileUpload implements RequestFileUpload { + readonly transfer_key: transfer.UploadKey; + private _handle: native.ft.NativeFileTransfer; + + private _result: Promise; + + private _result_success: () => any; + private _result_error: (error: any) => any; + + constructor(key: transfer.UploadKey) { + this.transfer_key = key; + } + + + async put_data(data: BlobPart | File) : Promise { + if(this._result) { + await this._result; + return; + } + + let buffer: native.ft.FileTransferSource; + + if(data instanceof File) { + if(data.size != this.transfer_key.total_size) + throw "invalid size"; + + throw "files arent yet supported"; + } else if(typeof(data) === "string") { + if(data.length != this.transfer_key.total_size) + throw "invalid size"; + + buffer = native.ft.upload_transfer_object_from_buffer(str2ab8(data)); + } else { + let buf = data; + if(buf.byteLength != this.transfer_key.total_size) + throw "invalid size"; + + if(ArrayBuffer.isView(buf)) + buf = buf.buffer.slice(buf.byteOffset); + + buffer = native.ft.upload_transfer_object_from_buffer(buf); + } + + this._handle = native.ft.spawn_connection({ + client_transfer_id: this.transfer_key.client_transfer_id, + server_transfer_id: this.transfer_key.server_transfer_id, + + remote_address: this.transfer_key.peer.hosts[0], + remote_port: this.transfer_key.peer.port, + + transfer_key: this.transfer_key.key, + + object: buffer + }); + + await (this._result = new Promise((resolve, reject) => { + this._result_error = (error) => { + this._result_error = undefined; + this._result_success = undefined; + reject(error); + }; + this._result_success = () => { + this._result_error = undefined; + this._result_success = undefined; + resolve(); + }; + + this._handle.callback_failed = this._result_error; + this._handle.callback_finished = aborted => { + if(aborted) + this._result_error("aborted"); + else + this._result_success(); + }; + + this._handle.start(); + })); + } + + private try_put(data: FormData, url: string): Promise { + throw "what the hell?"; + } + } + export function spawn_download_transfer(key: transfer.DownloadKey) : transfer.DownloadTransfer { return new NativeFileDownload(key); } + + + export function spawn_upload_transfer(key: transfer.UploadKey) : transfer.NativeFileUpload { + return new NativeFileUpload(key); + } } Object.assign(window["transfer"] || (window["transfer"] = {}), _transfer); \ No newline at end of file diff --git a/modules/renderer/connection/ServerConnection.ts b/modules/renderer/connection/ServerConnection.ts index d6ee3b2..0466680 100644 --- a/modules/renderer/connection/ServerConnection.ts +++ b/modules/renderer/connection/ServerConnection.ts @@ -184,6 +184,8 @@ export namespace _connection { callback: error => { if(error != 0) { + /* required to notify the handle, just a promise reject does not work */ + this.client.handleDisconnect(DisconnectReason.CONNECT_FAILURE, error); reject(this._native_handle.error_message(error)); return; } else { diff --git a/modules/renderer/imports/.copy_imports_shared.d.ts b/modules/renderer/imports/.copy_imports_shared.d.ts index f3ac1d9..246e5c7 100644 --- a/modules/renderer/imports/.copy_imports_shared.d.ts +++ b/modules/renderer/imports/.copy_imports_shared.d.ts @@ -1,15 +1,16 @@ -/* File: shared/js/audio/audio.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/audio/audio.ts */ declare namespace audio { export namespace player { export interface Device { device_id: string; + driver: string; name: string; } } } -/* File: shared/js/bookmarks.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/bookmarks.ts */ declare namespace bookmarks { export const boorkmak_connect; export interface ServerProperties { @@ -24,6 +25,7 @@ declare namespace bookmarks { } export interface Bookmark { type: BookmarkType; + /* readonly */ parent: DirectoryBookmark; server_properties: ServerProperties; display_name: string; unique_id: string; @@ -36,6 +38,7 @@ declare namespace bookmarks { } export interface DirectoryBookmark { type: BookmarkType; + /* readonly */ parent: DirectoryBookmark; readonly content: (Bookmark | DirectoryBookmark)[]; unique_id: string; display_name: string; @@ -46,13 +49,14 @@ declare namespace bookmarks { export function parent_bookmark(bookmark: Bookmark): DirectoryBookmark; export function create_bookmark(display_name: string, directory: DirectoryBookmark, server_properties: ServerProperties, nickname: string): Bookmark; export function create_bookmark_directory(parent: DirectoryBookmark, name: string): DirectoryBookmark; + //TODO test if the new parent is within the old bookmark export function change_directory(parent: DirectoryBookmark, bookmark: Bookmark | DirectoryBookmark); export function save_bookmark(bookmark?: Bookmark | DirectoryBookmark); export function delete_bookmark(bookmark: Bookmark | DirectoryBookmark); export function add_current_server(); } -/* File: shared/js/BrowserIPC.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/BrowserIPC.ts */ declare interface Window { BroadcastChannel: BroadcastChannel; } @@ -175,7 +179,7 @@ declare namespace bipc { export function supported(); } -/* File: shared/js/connection/CommandHandler.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/CommandHandler.ts */ declare namespace connection { export class ServerConnectionCommandBoss extends AbstractCommandHandlerBoss { constructor(connection: AbstractServerConnection); @@ -190,6 +194,8 @@ declare namespace connection { unset_handler(command: string, handler?: any); handleCommandResult(json); handleCommandServerInit(json); + handleNotifyServerConnectionInfo(json); + handleNotifyConnectionInfo(json); private createChannelFromJson(json, ignoreOrder?: boolean); handleCommandChannelList(json); handleCommandChannelListFinished(json); @@ -203,22 +209,27 @@ declare namespace connection { handleNotifyChannelMoved(json); handleNotifyChannelEdited(json); handleNotifyTextMessage(json); + notifyClientChatComposing(json); handleNotifyClientChatClosed(json); handleNotifyClientUpdated(json); handleNotifyServerEdited(json); handleNotifyServerUpdated(json); handleNotifyMusicPlayerInfo(json); handleNotifyClientPoke(json); + //TODO server chat message handleNotifyServerGroupClientAdd(json); + //TODO server chat message handleNotifyServerGroupClientRemove(json); + //TODO server chat message handleNotifyClientChannelGroupChanged(json); handleNotifyChannelSubscribed(json); handleNotifyChannelUnsubscribed(json); handleNotifyConversationHistory(json: any[]); + handleNotifyConversationMessageDelete(json: any[]); } } -/* File: shared/js/connection/CommandHelper.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/CommandHelper.ts */ declare namespace connection { export class CommandHelper extends AbstractCommandHandler { private _who_am_i: any; @@ -227,6 +238,7 @@ declare namespace connection { }; constructor(connection); initialize(); + destroy(); handle_command(command: connection.ServerCommand): boolean; joinChannel(channel: ChannelEntry, password?: string): Promise; sendMessage(message: string, type: ChatType, target?: ChannelEntry | ClientEntry): Promise; @@ -238,16 +250,21 @@ declare namespace connection { request_playlist_songs(playlist_id: number): Promise; request_clients_by_server_group(group_id: number): Promise; request_playlist_info(playlist_id: number): Promise; + /** + * @deprecated + * Its just a workaround for the query management. + * There is no garante that the whoami trick will work forever + */ current_virtual_server_id(): Promise; } } -/* File: shared/js/connection/ConnectionBase.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/ConnectionBase.ts */ declare namespace connection { export interface CommandOptions { flagset?: string[]; process_result?: boolean; - timeout?: number; + timeout?: number /* default: 1000 */; } export const CommandOptionDefaults: CommandOptions; export type ConnectionStateListener = (old_state: ConnectionState, new_state: ConnectionState) => any; @@ -255,6 +272,7 @@ declare namespace connection { readonly client: ConnectionHandler; readonly command_helper: CommandHelper; protected constructor(client: ConnectionHandler); + /* resolved as soon a connection has been established. This does not means that the authentication had yet been done! */ abstract connect(address: ServerAddress, handshake: HandshakeHandler, timeout?: number): Promise; abstract connected(): boolean; abstract disconnect(reason?: string): Promise; @@ -314,19 +332,25 @@ declare namespace connection { volatile_handler_boss: boolean; ignore_consumed: boolean; protected constructor(connection: AbstractServerConnection); + /** + * @return If the command should be consumed + */ abstract handle_command(command: ServerCommand): boolean; } export interface SingleCommandHandler { name?: string; command?: string; timeout?: number; + /* if the return is true then the command handler will be removed */ function: (command: ServerCommand) => boolean; } export abstract class AbstractCommandHandlerBoss { readonly connection: AbstractServerConnection; protected command_handlers: AbstractCommandHandler[]; + /* TODO: Timeout */ protected single_command_handler: SingleCommandHandler[]; protected constructor(connection: AbstractServerConnection); + destroy(); register_handler(handler: AbstractCommandHandler); unregister_handler(handler: AbstractCommandHandler); register_single_handler(handler: SingleCommandHandler); @@ -336,7 +360,7 @@ declare namespace connection { } } -/* File: shared/js/connection/HandshakeHandler.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/HandshakeHandler.ts */ declare namespace connection { export interface HandshakeIdentityHandler { connection: AbstractServerConnection; @@ -360,14 +384,16 @@ declare namespace connection { } } -/* File: shared/js/connection/ServerConnectionDeclaration.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/connection/ServerConnectionDeclaration.ts */ declare enum ErrorID { - PERMISSION_ERROR, - EMPTY_RESULT, - PLAYLIST_IS_IN_USE, - FILE_ALREADY_EXISTS, - CLIENT_INVALID_ID, - CONVERSATION_MORE_DATA + PERMISSION_ERROR = 2568, + EMPTY_RESULT = 0x0501, + PLAYLIST_IS_IN_USE = 0x2103, + FILE_ALREADY_EXISTS = 2050, + CLIENT_INVALID_ID = 0x0200, + CONVERSATION_INVALID_ID = 0x2200, + CONVERSATION_MORE_DATA = 0x2201, + CONVERSATION_IS_PRIVATE = 0x2202 } declare class CommandResult { success: boolean; @@ -378,6 +404,7 @@ declare class CommandResult { constructor(json); } declare interface ClientNameInfo { + //cluid=tYzKUryn\/\/Y8VBMf8PHUT6B1eiE= name=Exp clname=Exp cldbid=9 client_unique_id: string; client_nickname: string; client_database_id: number; @@ -438,7 +465,7 @@ declare interface PlaylistSong { song_metadata: string; } -/* File: shared/js/ConnectionHandler.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ConnectionHandler.ts */ declare enum DisconnectReason { HANDLER_DESTROYED, REQUESTED, @@ -454,6 +481,7 @@ declare enum DisconnectReason { HANDSHAKE_BANNED, SERVER_CLOSED, SERVER_REQUIRES_PASSWORD, + SERVER_HOSTMESSAGE, IDENTITY_TOO_LOW, UNKNOWN } @@ -465,18 +493,18 @@ declare enum ConnectionState { DISCONNECTING } declare enum ViewReasonId { - VREASON_USER_ACTION, - VREASON_MOVED, - VREASON_SYSTEM, - VREASON_TIMEOUT, - VREASON_CHANNEL_KICK, - VREASON_SERVER_KICK, - VREASON_BAN, - VREASON_SERVER_STOPPED, - VREASON_SERVER_LEFT, - VREASON_CHANNEL_UPDATED, - VREASON_EDITED, - VREASON_SERVER_SHUTDOWN + VREASON_USER_ACTION = 0, + VREASON_MOVED = 1, + VREASON_SYSTEM = 2, + VREASON_TIMEOUT = 3, + VREASON_CHANNEL_KICK = 4, + VREASON_SERVER_KICK = 5, + VREASON_BAN = 6, + VREASON_SERVER_STOPPED = 7, + VREASON_SERVER_LEFT = 8, + VREASON_CHANNEL_UPDATED = 9, + VREASON_EDITED = 10, + VREASON_SERVER_SHUTDOWN = 11 } declare interface VoiceStatus { input_hardware: boolean; @@ -509,12 +537,10 @@ declare class ConnectionHandler { permissions: PermissionManager; groups: GroupManager; side_bar: chat.Frame; - select_info: InfoBar; - chat: ChatBox; settings: ServerSettings; sound: sound.SoundManager; - readonly hostbanner: Hostbanner; - readonly tag_connection_handler: JQuery; + hostbanner: Hostbanner; + tag_connection_handler: JQuery; private _clientId: number; private _local_client: LocalClientEntry; private _reconnect_timer: NodeJS.Timer; @@ -534,6 +560,9 @@ declare class ConnectionHandler { // @ts-ignore get clientId(); getServerConnection(): connection.AbstractServerConnection; + /** + * LISTENER + */ onConnected(); private initialize_server_settings(); // @ts-ignore @@ -541,7 +570,7 @@ declare class ConnectionHandler { private generate_ssl_certificate_accept(): JQuery; private _certificate_modal: Modal; handleDisconnect(type: DisconnectReason, data?: any); - cancel_reconnect(); + cancel_reconnect(log_event: boolean); private on_connection_state_changed(); update_voice_status(targetChannel?: ChannelEntry); sync_status_with_server(); @@ -550,9 +579,10 @@ declare class ConnectionHandler { acquire_recorder(voice_recoder: RecorderProfile, update_control_bar: boolean); reconnect_properties(profile?: profiles.ConnectionProfile): ConnectParameters; update_avatar(); + destroy(); } -/* File: shared/js/crypto/asn1.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/asn1.ts */ declare namespace asn1 { export class Int10 { constructor(value?: any); @@ -581,39 +611,39 @@ declare namespace asn1 { parseOID(start, end, maxLength); } export enum TagClass { - UNIVERSAL, - APPLICATION, - CONTEXT, - PRIVATE + UNIVERSAL = 0x00, + APPLICATION = 0x01, + CONTEXT = 0x02, + PRIVATE = 0x03 } export enum TagType { - EOC, - BOOLEAN, - INTEGER, - BIT_STRING, - OCTET_STRING, - NULL, - OBJECT_IDENTIFIER, - ObjectDescriptor, - EXTERNAL, - REAL, - ENUMERATED, - EMBEDDED_PDV, - UTF8String, - SEQUENCE, - SET, - NumericString, - PrintableString, - TeletextString, - VideotexString, - IA5String, - UTCTime, - GeneralizedTime, - GraphicString, - VisibleString, - GeneralString, - UniversalString, - BMPString + EOC = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL = 0x05, + OBJECT_IDENTIFIER = 0x06, + ObjectDescriptor = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0A, + EMBEDDED_PDV = 0x0B, + UTF8String = 0x0C, + SEQUENCE = 0x10, + SET = 0x11, + NumericString = 0x12, + PrintableString = 0x13, + TeletextString = 0x14, + VideotexString = 0x15, + IA5String = 0x16, + UTCTime = 0x17, + GeneralizedTime = 0x18, + GraphicString = 0x19, + VisibleString = 0x1A, + GeneralString = 0x1B, + UniversalString = 0x1C, + BMPString = 0x1E } export class ASN1Tag { tagClass: TagClass; @@ -644,7 +674,7 @@ declare namespace asn1 { export function decode(stream: string | ArrayBuffer); } -/* File: shared/js/crypto/crc32.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/crc32.ts */ declare class Crc32 { private static readonly lookup; private crc: number; @@ -653,12 +683,12 @@ declare class Crc32 { digest(radix: number); } -/* File: shared/js/crypto/hex.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/hex.ts */ declare namespace hex { export function encode(buffer); } -/* File: shared/js/crypto/sha.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/crypto/sha.ts */ declare function define($); declare function unescape(string: string): string; declare class _sha1 { @@ -669,7 +699,7 @@ declare namespace sha { export function sha1(message: string | ArrayBuffer): PromiseLike; } -/* File: shared/js/dns.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/dns.ts */ declare namespace dns { export interface AddressTarget { target_ip: string; @@ -690,12 +720,12 @@ declare namespace dns { export function resolve_address(address: string, options?: ResolveOptions): Promise; } -/* File: shared/js/events.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/events.ts */ declare namespace event { namespace global { } } -/* File: shared/js/FileManager.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/FileManager.ts */ declare class FileEntry { name: string; datetime: number; @@ -759,10 +789,14 @@ declare class FileManager extends connection.AbstractCommandHandler { private pending_upload_requests: transfer.UploadKey[]; private transfer_counter: number; constructor(client: ConnectionHandler); + destroy(); handle_command(command: connection.ServerCommand): boolean; + /******************************** File list ********************************/ + //TODO multiple requests (same path) requestFileList(path: string, channel?: ChannelEntry, password?: string): Promise; private notifyFileList(json); private notifyFileListFinished(json); + /******************************** File download/upload ********************************/ download_file(path: string, file: string, channel?: ChannelEntry, password?: string): Promise; upload_file(options: transfer.UploadOptions): Promise; private notifyStartDownload(json); @@ -800,6 +834,7 @@ declare class CacheManager { put_cache(key: string, value: Response, type?: string, headers?: { [key: string]: string; }); + delete(key: string); } declare class IconManager { private static cache: CacheManager; @@ -811,6 +846,7 @@ declare class IconManager { [id: number]: Promise; }; constructor(handle: FileManager); + destroy(); clear_cache(); delete_icon(id: number): Promise; iconList(): Promise; @@ -850,12 +886,15 @@ declare class AvatarManager { [response_avatar_id: number]: Promise; }; constructor(handle: FileManager); + destroy(); private _response_url(response: Response, type: ImageType): Promise; - resolved_cached?(client_avatar_id: string, avatar_id?: string): Promise; + resolved_cached?(client_avatar_id: string, avatar_version?: string): Promise; create_avatar_download(client_avatar_id: string): Promise; - private _load_avatar(client_avatar_id: string, avatar_id: string); - loadAvatar(client_avatar_id: string, avatar_id: string): Promise; + private _load_avatar(client_avatar_id: string, avatar_version: string); + /* loads an avatar by the avatar id and optional with the avatar version */ + load_avatar(client_avatar_id: string, avatar_version: string): Promise; generate_client_tag(client: ClientEntry): JQuery; + update_cache(client_avatar_id: string, avatar_id: string); generate_tag(client_avatar_id: string, avatar_id?: string, options?: { callback_image?: (tag: JQuery) => any; callback_avatar?: (avatar: Avatar) => any; @@ -868,12 +907,12 @@ declare class AvatarManager { }, client_unique_id: string, callback_loaded?: (successfully: boolean, error?: any) => any): JQuery; } -/* File: shared/js/i18n/country.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/i18n/country.ts */ declare namespace i18n { export function country_name(alpha_code: string, fallback?: string); } -/* File: shared/js/i18n/localize.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/i18n/localize.ts */ declare function guid(); declare namespace i18n { export interface TranslationKey { @@ -943,84 +982,22 @@ declare namespace i18n { declare const tr: typeof i18n.tr; declare const tra: typeof i18n.tra; -/* File: shared/js/load.ts */ -declare namespace app { - export enum Type { - UNKNOWN, - CLIENT_RELEASE, - CLIENT_DEBUG, - WEB_DEBUG, - WEB_RELEASE - } - export let type: Type; - export function is_web(); -} -declare namespace loader { - export type Task = { - name: string; - priority: number; - function: () => Promise; - }; - export enum Stage { - INITIALIZING, - SETUP, - STYLE, - JAVASCRIPT, - TEMPLATES, - JAVASCRIPT_INITIALIZING, - FINALIZING, - LOADED, - DONE - } - export let cache_tag: string | undefined; - export function finished(); - export function register_task(stage: Stage, task: Task); - export function execute(): Promise; - type DependSource = { - url: string; - depends: string[]; - }; - type SourcePath = string | DependSource | string[]; - export class SyntaxError { - source: any; - constructor(source: any); - } - export function load_script(path: SourcePath): Promise; - export function load_scripts(paths: SourcePath[]): Promise; - export function load_style(path: SourcePath): Promise; - export function load_styles(paths: SourcePath[]): Promise; -} -declare let _critical_triggered; -declare const display_critical_load; -declare const loader_impl_display_critical_error; -declare interface Window { - impl_display_critical_error: (_: string) => any; -} -declare function displayCriticalError(message: string); -declare const loader_javascript; -declare const loader_webassembly; -declare const loader_style; -declare function load_templates(): Promise; -declare function check_updates(): Promise; -declare interface Window { - $: JQuery; -} -declare let _fadeout_warned; -declare function fadeoutLoader(duration?, minAge?, ignoreAge?); - -/* File: shared/js/log.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/log.ts */ declare enum LogCategory { CHANNEL, CHANNEL_PROPERTIES, CLIENT, + BOOKMARKS, SERVER, PERMISSIONS, GENERAL, NETWORKING, VOICE, + AUDIO, I18N, IPC, - IDENTITIES + IDENTITIES, + STATISTICS } declare namespace log { export enum LogType { @@ -1031,11 +1008,16 @@ declare namespace log { ERROR } export let enabled_mapping; + //Values will be overridden by initialize() + export let level_mapping; export enum GroupMode { NATIVE, PREFIX } - export function initialize(); + //Category Example: ?log.i18n.enabled=0 + //Level Example A: ?log.level.trace.enabled=0 + //Level Example B: ?log.level=0 + export function initialize(default_level: LogType); export function log(type: LogType, category: LogCategory, message: string, ...optionalParams: any[]); export function trace(category: LogCategory, message: string, ...optionalParams: any[]); export function debug(category: LogCategory, message: string, ...optionalParams: any[]); @@ -1043,7 +1025,7 @@ declare namespace log { export function warn(category: LogCategory, message: string, ...optionalParams: any[]); export function error(category: LogCategory, message: string, ...optionalParams: any[]); export function group(level: LogType, category: LogCategory, name: string, ...optionalParams: any[]): Group; - export function table(title: string, arguments: any); + export function table(level: LogType, category: LogCategory, title: string, arguments: any); export class Group { readonly mode: GroupMode; readonly level: LogType; @@ -1067,11 +1049,10 @@ declare namespace log { } } -/* File: shared/js/main.ts */ -declare let settings: Settings; +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/main.ts */ declare const js_render; declare const native_client; -declare function getUserMediaFunction(): (constraints: MediaStreamConstraints, success: (stream: MediaStream) => any, fail: (error: any) => any) => any; +declare function getUserMediaFunctionPromise(): (constraints: MediaStreamConstraints) => Promise; declare interface Window { open_connected_question: () => Promise; } @@ -1080,17 +1061,14 @@ declare function moment(...arguments): any; declare function setup_jsrender(): boolean; declare function initialize(): Promise; declare function initialize_app(): Promise; -declare function ab2str(buf); declare function str2ab8(str); declare function arrayBufferBase64(base64: string); -declare function base64ArrayBuffer(arrayBuffer); -declare function Base64EncodeUrl(str); -declare function Base64DecodeUrl(str: string, pad?: boolean); +declare function base64_encode_ab(source: ArrayBufferLike); declare function main(); declare const task_teaweb_starter: loader.Task; declare const task_certificate_callback: loader.Task; -/* File: shared/js/permission/GroupManager.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/permission/GroupManager.ts */ declare enum GroupType { QUERY, TEMPLATE, @@ -1129,6 +1107,7 @@ declare class GroupManager extends connection.AbstractCommandHandler { channelGroups: Group[]; private requests_group_permissions: GroupPermissionRequest[]; constructor(client: ConnectionHandler); + destroy(); handle_command(command: connection.ServerCommand): boolean; requestGroups(); static sorter(): (a: Group, b: Group) => number; @@ -1139,347 +1118,347 @@ declare class GroupManager extends connection.AbstractCommandHandler { private handle_group_permission_list(json: any[]); } -/* File: shared/js/permission/PermissionManager.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/permission/PermissionManager.ts */ declare enum PermissionType { - B_SERVERINSTANCE_HELP_VIEW, - B_SERVERINSTANCE_VERSION_VIEW, - B_SERVERINSTANCE_INFO_VIEW, - B_SERVERINSTANCE_VIRTUALSERVER_LIST, - B_SERVERINSTANCE_BINDING_LIST, - B_SERVERINSTANCE_PERMISSION_LIST, - B_SERVERINSTANCE_PERMISSION_FIND, - B_VIRTUALSERVER_CREATE, - B_VIRTUALSERVER_DELETE, - B_VIRTUALSERVER_START_ANY, - B_VIRTUALSERVER_STOP_ANY, - B_VIRTUALSERVER_CHANGE_MACHINE_ID, - B_VIRTUALSERVER_CHANGE_TEMPLATE, - B_SERVERQUERY_LOGIN, - B_SERVERINSTANCE_TEXTMESSAGE_SEND, - B_SERVERINSTANCE_LOG_VIEW, - B_SERVERINSTANCE_LOG_ADD, - B_SERVERINSTANCE_STOP, - B_SERVERINSTANCE_MODIFY_SETTINGS, - B_SERVERINSTANCE_MODIFY_QUERYGROUP, - B_SERVERINSTANCE_MODIFY_TEMPLATES, - B_VIRTUALSERVER_SELECT, - B_VIRTUALSERVER_SELECT_GODMODE, - B_VIRTUALSERVER_INFO_VIEW, - B_VIRTUALSERVER_CONNECTIONINFO_VIEW, - B_VIRTUALSERVER_CHANNEL_LIST, - B_VIRTUALSERVER_CHANNEL_SEARCH, - B_VIRTUALSERVER_CLIENT_LIST, - B_VIRTUALSERVER_CLIENT_SEARCH, - B_VIRTUALSERVER_CLIENT_DBLIST, - B_VIRTUALSERVER_CLIENT_DBSEARCH, - B_VIRTUALSERVER_CLIENT_DBINFO, - B_VIRTUALSERVER_PERMISSION_FIND, - B_VIRTUALSERVER_CUSTOM_SEARCH, - B_VIRTUALSERVER_START, - B_VIRTUALSERVER_STOP, - B_VIRTUALSERVER_TOKEN_LIST, - B_VIRTUALSERVER_TOKEN_ADD, - B_VIRTUALSERVER_TOKEN_USE, - B_VIRTUALSERVER_TOKEN_DELETE, - B_VIRTUALSERVER_LOG_VIEW, - B_VIRTUALSERVER_LOG_ADD, - B_VIRTUALSERVER_JOIN_IGNORE_PASSWORD, - B_VIRTUALSERVER_NOTIFY_REGISTER, - B_VIRTUALSERVER_NOTIFY_UNREGISTER, - B_VIRTUALSERVER_SNAPSHOT_CREATE, - B_VIRTUALSERVER_SNAPSHOT_DEPLOY, - B_VIRTUALSERVER_PERMISSION_RESET, - B_VIRTUALSERVER_MODIFY_NAME, - B_VIRTUALSERVER_MODIFY_WELCOMEMESSAGE, - B_VIRTUALSERVER_MODIFY_MAXCLIENTS, - B_VIRTUALSERVER_MODIFY_RESERVED_SLOTS, - B_VIRTUALSERVER_MODIFY_PASSWORD, - B_VIRTUALSERVER_MODIFY_DEFAULT_SERVERGROUP, - B_VIRTUALSERVER_MODIFY_DEFAULT_MUSICGROUP, - B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELGROUP, - B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELADMINGROUP, - B_VIRTUALSERVER_MODIFY_CHANNEL_FORCED_SILENCE, - B_VIRTUALSERVER_MODIFY_COMPLAIN, - B_VIRTUALSERVER_MODIFY_ANTIFLOOD, - B_VIRTUALSERVER_MODIFY_FT_SETTINGS, - B_VIRTUALSERVER_MODIFY_FT_QUOTAS, - B_VIRTUALSERVER_MODIFY_HOSTMESSAGE, - B_VIRTUALSERVER_MODIFY_HOSTBANNER, - B_VIRTUALSERVER_MODIFY_HOSTBUTTON, - B_VIRTUALSERVER_MODIFY_PORT, - B_VIRTUALSERVER_MODIFY_HOST, - B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES, - B_VIRTUALSERVER_MODIFY_AUTOSTART, - B_VIRTUALSERVER_MODIFY_NEEDED_IDENTITY_SECURITY_LEVEL, - B_VIRTUALSERVER_MODIFY_PRIORITY_SPEAKER_DIMM_MODIFICATOR, - B_VIRTUALSERVER_MODIFY_LOG_SETTINGS, - B_VIRTUALSERVER_MODIFY_MIN_CLIENT_VERSION, - B_VIRTUALSERVER_MODIFY_ICON_ID, - B_VIRTUALSERVER_MODIFY_WEBLIST, - B_VIRTUALSERVER_MODIFY_CODEC_ENCRYPTION_MODE, - B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS, - B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS_OWN, - B_VIRTUALSERVER_MODIFY_CHANNEL_TEMP_DELETE_DELAY_DEFAULT, - B_VIRTUALSERVER_MODIFY_MUSIC_BOT_LIMIT, - I_CHANNEL_MIN_DEPTH, - I_CHANNEL_MAX_DEPTH, - B_CHANNEL_GROUP_INHERITANCE_END, - I_CHANNEL_PERMISSION_MODIFY_POWER, - I_CHANNEL_NEEDED_PERMISSION_MODIFY_POWER, - B_CHANNEL_INFO_VIEW, - B_CHANNEL_CREATE_CHILD, - B_CHANNEL_CREATE_PERMANENT, - B_CHANNEL_CREATE_SEMI_PERMANENT, - B_CHANNEL_CREATE_TEMPORARY, - B_CHANNEL_CREATE_PRIVATE, - B_CHANNEL_CREATE_WITH_TOPIC, - B_CHANNEL_CREATE_WITH_DESCRIPTION, - B_CHANNEL_CREATE_WITH_PASSWORD, - B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX8, - B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX16, - B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX32, - B_CHANNEL_CREATE_MODIFY_WITH_CODEC_CELTMONO48, - B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE, - B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC, - I_CHANNEL_CREATE_MODIFY_WITH_CODEC_MAXQUALITY, - I_CHANNEL_CREATE_MODIFY_WITH_CODEC_LATENCY_FACTOR_MIN, - B_CHANNEL_CREATE_WITH_MAXCLIENTS, - B_CHANNEL_CREATE_WITH_MAXFAMILYCLIENTS, - B_CHANNEL_CREATE_WITH_SORTORDER, - B_CHANNEL_CREATE_WITH_DEFAULT, - B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER, - B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD, - I_CHANNEL_CREATE_MODIFY_WITH_TEMP_DELETE_DELAY, - B_CHANNEL_MODIFY_PARENT, - B_CHANNEL_MODIFY_MAKE_DEFAULT, - B_CHANNEL_MODIFY_MAKE_PERMANENT, - B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT, - B_CHANNEL_MODIFY_MAKE_TEMPORARY, - B_CHANNEL_MODIFY_NAME, - B_CHANNEL_MODIFY_TOPIC, - B_CHANNEL_MODIFY_DESCRIPTION, - B_CHANNEL_MODIFY_PASSWORD, - B_CHANNEL_MODIFY_CODEC, - B_CHANNEL_MODIFY_CODEC_QUALITY, - B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR, - B_CHANNEL_MODIFY_MAXCLIENTS, - B_CHANNEL_MODIFY_MAXFAMILYCLIENTS, - B_CHANNEL_MODIFY_SORTORDER, - B_CHANNEL_MODIFY_NEEDED_TALK_POWER, - I_CHANNEL_MODIFY_POWER, - I_CHANNEL_NEEDED_MODIFY_POWER, - B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED, - B_CHANNEL_MODIFY_TEMP_DELETE_DELAY, - B_CHANNEL_DELETE_PERMANENT, - B_CHANNEL_DELETE_SEMI_PERMANENT, - B_CHANNEL_DELETE_TEMPORARY, - B_CHANNEL_DELETE_FLAG_FORCE, - I_CHANNEL_DELETE_POWER, - I_CHANNEL_NEEDED_DELETE_POWER, - B_CHANNEL_JOIN_PERMANENT, - B_CHANNEL_JOIN_SEMI_PERMANENT, - B_CHANNEL_JOIN_TEMPORARY, - B_CHANNEL_JOIN_IGNORE_PASSWORD, - B_CHANNEL_JOIN_IGNORE_MAXCLIENTS, - B_CHANNEL_IGNORE_VIEW_POWER, - I_CHANNEL_JOIN_POWER, - I_CHANNEL_NEEDED_JOIN_POWER, - B_CHANNEL_IGNORE_JOIN_POWER, - I_CHANNEL_VIEW_POWER, - I_CHANNEL_NEEDED_VIEW_POWER, - I_CHANNEL_SUBSCRIBE_POWER, - I_CHANNEL_NEEDED_SUBSCRIBE_POWER, - I_CHANNEL_DESCRIPTION_VIEW_POWER, - I_CHANNEL_NEEDED_DESCRIPTION_VIEW_POWER, - I_ICON_ID, - I_MAX_ICON_FILESIZE, - B_ICON_MANAGE, - B_GROUP_IS_PERMANENT, - I_GROUP_AUTO_UPDATE_TYPE, - I_GROUP_AUTO_UPDATE_MAX_VALUE, - I_GROUP_SORT_ID, - I_GROUP_SHOW_NAME_IN_TREE, - B_VIRTUALSERVER_SERVERGROUP_CREATE, - B_VIRTUALSERVER_SERVERGROUP_LIST, - B_VIRTUALSERVER_SERVERGROUP_PERMISSION_LIST, - B_VIRTUALSERVER_SERVERGROUP_CLIENT_LIST, - B_VIRTUALSERVER_CHANNELGROUP_CREATE, - B_VIRTUALSERVER_CHANNELGROUP_LIST, - B_VIRTUALSERVER_CHANNELGROUP_PERMISSION_LIST, - B_VIRTUALSERVER_CHANNELGROUP_CLIENT_LIST, - B_VIRTUALSERVER_CLIENT_PERMISSION_LIST, - B_VIRTUALSERVER_CHANNEL_PERMISSION_LIST, - B_VIRTUALSERVER_CHANNELCLIENT_PERMISSION_LIST, - B_VIRTUALSERVER_PLAYLIST_PERMISSION_LIST, - I_SERVER_GROUP_MODIFY_POWER, - I_SERVER_GROUP_NEEDED_MODIFY_POWER, - I_SERVER_GROUP_MEMBER_ADD_POWER, - I_SERVER_GROUP_SELF_ADD_POWER, - I_SERVER_GROUP_NEEDED_MEMBER_ADD_POWER, - I_SERVER_GROUP_MEMBER_REMOVE_POWER, - I_SERVER_GROUP_SELF_REMOVE_POWER, - I_SERVER_GROUP_NEEDED_MEMBER_REMOVE_POWER, - I_CHANNEL_GROUP_MODIFY_POWER, - I_CHANNEL_GROUP_NEEDED_MODIFY_POWER, - I_CHANNEL_GROUP_MEMBER_ADD_POWER, - I_CHANNEL_GROUP_SELF_ADD_POWER, - I_CHANNEL_GROUP_NEEDED_MEMBER_ADD_POWER, - I_CHANNEL_GROUP_MEMBER_REMOVE_POWER, - I_CHANNEL_GROUP_SELF_REMOVE_POWER, - I_CHANNEL_GROUP_NEEDED_MEMBER_REMOVE_POWER, - I_GROUP_MEMBER_ADD_POWER, - I_GROUP_NEEDED_MEMBER_ADD_POWER, - I_GROUP_MEMBER_REMOVE_POWER, - I_GROUP_NEEDED_MEMBER_REMOVE_POWER, - I_GROUP_MODIFY_POWER, - I_GROUP_NEEDED_MODIFY_POWER, - I_PERMISSION_MODIFY_POWER, - B_PERMISSION_MODIFY_POWER_IGNORE, - B_VIRTUALSERVER_SERVERGROUP_DELETE, - B_VIRTUALSERVER_CHANNELGROUP_DELETE, - I_CLIENT_PERMISSION_MODIFY_POWER, - I_CLIENT_NEEDED_PERMISSION_MODIFY_POWER, - I_CLIENT_MAX_CLONES_UID, - I_CLIENT_MAX_CLONES_IP, - I_CLIENT_MAX_CLONES_HWID, - I_CLIENT_MAX_IDLETIME, - I_CLIENT_MAX_AVATAR_FILESIZE, - I_CLIENT_MAX_CHANNEL_SUBSCRIPTIONS, - I_CLIENT_MAX_CHANNELS, - I_CLIENT_MAX_TEMPORARY_CHANNELS, - I_CLIENT_MAX_SEMI_CHANNELS, - I_CLIENT_MAX_PERMANENT_CHANNELS, - B_CLIENT_USE_PRIORITY_SPEAKER, - B_CLIENT_SKIP_CHANNELGROUP_PERMISSIONS, - B_CLIENT_FORCE_PUSH_TO_TALK, - B_CLIENT_IGNORE_BANS, - B_CLIENT_IGNORE_VPN, - B_CLIENT_IGNORE_ANTIFLOOD, - B_CLIENT_ENFORCE_VALID_HWID, - B_CLIENT_ALLOW_INVALID_PACKET, - B_CLIENT_ALLOW_INVALID_BADGES, - B_CLIENT_ISSUE_CLIENT_QUERY_COMMAND, - B_CLIENT_USE_RESERVED_SLOT, - B_CLIENT_USE_CHANNEL_COMMANDER, - B_CLIENT_REQUEST_TALKER, - B_CLIENT_AVATAR_DELETE_OTHER, - B_CLIENT_IS_STICKY, - B_CLIENT_IGNORE_STICKY, - B_CLIENT_MUSIC_CREATE_PERMANENT, - B_CLIENT_MUSIC_CREATE_SEMI_PERMANENT, - B_CLIENT_MUSIC_CREATE_TEMPORARY, - B_CLIENT_MUSIC_MODIFY_PERMANENT, - B_CLIENT_MUSIC_MODIFY_SEMI_PERMANENT, - B_CLIENT_MUSIC_MODIFY_TEMPORARY, - I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME, - I_CLIENT_MUSIC_LIMIT, - I_CLIENT_MUSIC_NEEDED_DELETE_POWER, - I_CLIENT_MUSIC_DELETE_POWER, - I_CLIENT_MUSIC_PLAY_POWER, - I_CLIENT_MUSIC_NEEDED_PLAY_POWER, - I_CLIENT_MUSIC_MODIFY_POWER, - I_CLIENT_MUSIC_NEEDED_MODIFY_POWER, - I_CLIENT_MUSIC_RENAME_POWER, - I_CLIENT_MUSIC_NEEDED_RENAME_POWER, - B_PLAYLIST_CREATE, - I_PLAYLIST_VIEW_POWER, - I_PLAYLIST_NEEDED_VIEW_POWER, - I_PLAYLIST_MODIFY_POWER, - I_PLAYLIST_NEEDED_MODIFY_POWER, - I_PLAYLIST_PERMISSION_MODIFY_POWER, - I_PLAYLIST_NEEDED_PERMISSION_MODIFY_POWER, - I_PLAYLIST_DELETE_POWER, - I_PLAYLIST_NEEDED_DELETE_POWER, - I_PLAYLIST_SONG_ADD_POWER, - I_PLAYLIST_SONG_NEEDED_ADD_POWER, - I_PLAYLIST_SONG_REMOVE_POWER, - I_PLAYLIST_SONG_NEEDED_REMOVE_POWER, - B_CLIENT_INFO_VIEW, - B_CLIENT_PERMISSIONOVERVIEW_VIEW, - B_CLIENT_PERMISSIONOVERVIEW_OWN, - B_CLIENT_REMOTEADDRESS_VIEW, - I_CLIENT_SERVERQUERY_VIEW_POWER, - I_CLIENT_NEEDED_SERVERQUERY_VIEW_POWER, - B_CLIENT_CUSTOM_INFO_VIEW, - B_CLIENT_MUSIC_CHANNEL_LIST, - B_CLIENT_MUSIC_SERVER_LIST, - I_CLIENT_MUSIC_INFO, - I_CLIENT_MUSIC_NEEDED_INFO, - I_CLIENT_KICK_FROM_SERVER_POWER, - I_CLIENT_NEEDED_KICK_FROM_SERVER_POWER, - I_CLIENT_KICK_FROM_CHANNEL_POWER, - I_CLIENT_NEEDED_KICK_FROM_CHANNEL_POWER, - I_CLIENT_BAN_POWER, - I_CLIENT_NEEDED_BAN_POWER, - I_CLIENT_MOVE_POWER, - I_CLIENT_NEEDED_MOVE_POWER, - I_CLIENT_COMPLAIN_POWER, - I_CLIENT_NEEDED_COMPLAIN_POWER, - B_CLIENT_COMPLAIN_LIST, - B_CLIENT_COMPLAIN_DELETE_OWN, - B_CLIENT_COMPLAIN_DELETE, - B_CLIENT_BAN_LIST, - B_CLIENT_BAN_LIST_GLOBAL, - B_CLIENT_BAN_TRIGGER_LIST, - B_CLIENT_BAN_CREATE, - B_CLIENT_BAN_CREATE_GLOBAL, - B_CLIENT_BAN_NAME, - B_CLIENT_BAN_IP, - B_CLIENT_BAN_HWID, - B_CLIENT_BAN_EDIT, - B_CLIENT_BAN_EDIT_GLOBAL, - B_CLIENT_BAN_DELETE_OWN, - B_CLIENT_BAN_DELETE, - B_CLIENT_BAN_DELETE_OWN_GLOBAL, - B_CLIENT_BAN_DELETE_GLOBAL, - I_CLIENT_BAN_MAX_BANTIME, - I_CLIENT_PRIVATE_TEXTMESSAGE_POWER, - I_CLIENT_NEEDED_PRIVATE_TEXTMESSAGE_POWER, - B_CLIENT_EVEN_TEXTMESSAGE_SEND, - B_CLIENT_SERVER_TEXTMESSAGE_SEND, - B_CLIENT_CHANNEL_TEXTMESSAGE_SEND, - B_CLIENT_OFFLINE_TEXTMESSAGE_SEND, - I_CLIENT_TALK_POWER, - I_CLIENT_NEEDED_TALK_POWER, - I_CLIENT_POKE_POWER, - I_CLIENT_NEEDED_POKE_POWER, - B_CLIENT_SET_FLAG_TALKER, - I_CLIENT_WHISPER_POWER, - I_CLIENT_NEEDED_WHISPER_POWER, - B_CLIENT_MODIFY_DESCRIPTION, - B_CLIENT_MODIFY_OWN_DESCRIPTION, - B_CLIENT_USE_BBCODE_ANY, - B_CLIENT_USE_BBCODE_URL, - B_CLIENT_USE_BBCODE_IMAGE, - B_CLIENT_MODIFY_DBPROPERTIES, - B_CLIENT_DELETE_DBPROPERTIES, - B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN, - B_CLIENT_QUERY_CREATE, - B_CLIENT_QUERY_LIST, - B_CLIENT_QUERY_LIST_OWN, - B_CLIENT_QUERY_RENAME, - B_CLIENT_QUERY_RENAME_OWN, - B_CLIENT_QUERY_CHANGE_PASSWORD, - B_CLIENT_QUERY_CHANGE_OWN_PASSWORD, - B_CLIENT_QUERY_CHANGE_PASSWORD_GLOBAL, - B_CLIENT_QUERY_DELETE, - B_CLIENT_QUERY_DELETE_OWN, - B_FT_IGNORE_PASSWORD, - B_FT_TRANSFER_LIST, - I_FT_FILE_UPLOAD_POWER, - I_FT_NEEDED_FILE_UPLOAD_POWER, - I_FT_FILE_DOWNLOAD_POWER, - I_FT_NEEDED_FILE_DOWNLOAD_POWER, - I_FT_FILE_DELETE_POWER, - I_FT_NEEDED_FILE_DELETE_POWER, - I_FT_FILE_RENAME_POWER, - I_FT_NEEDED_FILE_RENAME_POWER, - I_FT_FILE_BROWSE_POWER, - I_FT_NEEDED_FILE_BROWSE_POWER, - I_FT_DIRECTORY_CREATE_POWER, - I_FT_NEEDED_DIRECTORY_CREATE_POWER, - I_FT_QUOTA_MB_DOWNLOAD_PER_CLIENT, - I_FT_QUOTA_MB_UPLOAD_PER_CLIENT + B_SERVERINSTANCE_HELP_VIEW = "b_serverinstance_help_view", + B_SERVERINSTANCE_VERSION_VIEW = "b_serverinstance_version_view", + B_SERVERINSTANCE_INFO_VIEW = "b_serverinstance_info_view", + B_SERVERINSTANCE_VIRTUALSERVER_LIST = "b_serverinstance_virtualserver_list", + B_SERVERINSTANCE_BINDING_LIST = "b_serverinstance_binding_list", + B_SERVERINSTANCE_PERMISSION_LIST = "b_serverinstance_permission_list", + B_SERVERINSTANCE_PERMISSION_FIND = "b_serverinstance_permission_find", + B_VIRTUALSERVER_CREATE = "b_virtualserver_create", + B_VIRTUALSERVER_DELETE = "b_virtualserver_delete", + B_VIRTUALSERVER_START_ANY = "b_virtualserver_start_any", + B_VIRTUALSERVER_STOP_ANY = "b_virtualserver_stop_any", + B_VIRTUALSERVER_CHANGE_MACHINE_ID = "b_virtualserver_change_machine_id", + B_VIRTUALSERVER_CHANGE_TEMPLATE = "b_virtualserver_change_template", + B_SERVERQUERY_LOGIN = "b_serverquery_login", + B_SERVERINSTANCE_TEXTMESSAGE_SEND = "b_serverinstance_textmessage_send", + B_SERVERINSTANCE_LOG_VIEW = "b_serverinstance_log_view", + B_SERVERINSTANCE_LOG_ADD = "b_serverinstance_log_add", + B_SERVERINSTANCE_STOP = "b_serverinstance_stop", + B_SERVERINSTANCE_MODIFY_SETTINGS = "b_serverinstance_modify_settings", + B_SERVERINSTANCE_MODIFY_QUERYGROUP = "b_serverinstance_modify_querygroup", + B_SERVERINSTANCE_MODIFY_TEMPLATES = "b_serverinstance_modify_templates", + B_VIRTUALSERVER_SELECT = "b_virtualserver_select", + B_VIRTUALSERVER_SELECT_GODMODE = "b_virtualserver_select_godmode", + B_VIRTUALSERVER_INFO_VIEW = "b_virtualserver_info_view", + B_VIRTUALSERVER_CONNECTIONINFO_VIEW = "b_virtualserver_connectioninfo_view", + B_VIRTUALSERVER_CHANNEL_LIST = "b_virtualserver_channel_list", + B_VIRTUALSERVER_CHANNEL_SEARCH = "b_virtualserver_channel_search", + B_VIRTUALSERVER_CLIENT_LIST = "b_virtualserver_client_list", + B_VIRTUALSERVER_CLIENT_SEARCH = "b_virtualserver_client_search", + B_VIRTUALSERVER_CLIENT_DBLIST = "b_virtualserver_client_dblist", + B_VIRTUALSERVER_CLIENT_DBSEARCH = "b_virtualserver_client_dbsearch", + B_VIRTUALSERVER_CLIENT_DBINFO = "b_virtualserver_client_dbinfo", + B_VIRTUALSERVER_PERMISSION_FIND = "b_virtualserver_permission_find", + B_VIRTUALSERVER_CUSTOM_SEARCH = "b_virtualserver_custom_search", + B_VIRTUALSERVER_START = "b_virtualserver_start", + B_VIRTUALSERVER_STOP = "b_virtualserver_stop", + B_VIRTUALSERVER_TOKEN_LIST = "b_virtualserver_token_list", + B_VIRTUALSERVER_TOKEN_ADD = "b_virtualserver_token_add", + B_VIRTUALSERVER_TOKEN_USE = "b_virtualserver_token_use", + B_VIRTUALSERVER_TOKEN_DELETE = "b_virtualserver_token_delete", + B_VIRTUALSERVER_LOG_VIEW = "b_virtualserver_log_view", + B_VIRTUALSERVER_LOG_ADD = "b_virtualserver_log_add", + B_VIRTUALSERVER_JOIN_IGNORE_PASSWORD = "b_virtualserver_join_ignore_password", + B_VIRTUALSERVER_NOTIFY_REGISTER = "b_virtualserver_notify_register", + B_VIRTUALSERVER_NOTIFY_UNREGISTER = "b_virtualserver_notify_unregister", + B_VIRTUALSERVER_SNAPSHOT_CREATE = "b_virtualserver_snapshot_create", + B_VIRTUALSERVER_SNAPSHOT_DEPLOY = "b_virtualserver_snapshot_deploy", + B_VIRTUALSERVER_PERMISSION_RESET = "b_virtualserver_permission_reset", + B_VIRTUALSERVER_MODIFY_NAME = "b_virtualserver_modify_name", + B_VIRTUALSERVER_MODIFY_WELCOMEMESSAGE = "b_virtualserver_modify_welcomemessage", + B_VIRTUALSERVER_MODIFY_MAXCLIENTS = "b_virtualserver_modify_maxclients", + B_VIRTUALSERVER_MODIFY_RESERVED_SLOTS = "b_virtualserver_modify_reserved_slots", + B_VIRTUALSERVER_MODIFY_PASSWORD = "b_virtualserver_modify_password", + B_VIRTUALSERVER_MODIFY_DEFAULT_SERVERGROUP = "b_virtualserver_modify_default_servergroup", + B_VIRTUALSERVER_MODIFY_DEFAULT_MUSICGROUP = "b_virtualserver_modify_default_musicgroup", + B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELGROUP = "b_virtualserver_modify_default_channelgroup", + B_VIRTUALSERVER_MODIFY_DEFAULT_CHANNELADMINGROUP = "b_virtualserver_modify_default_channeladmingroup", + B_VIRTUALSERVER_MODIFY_CHANNEL_FORCED_SILENCE = "b_virtualserver_modify_channel_forced_silence", + B_VIRTUALSERVER_MODIFY_COMPLAIN = "b_virtualserver_modify_complain", + B_VIRTUALSERVER_MODIFY_ANTIFLOOD = "b_virtualserver_modify_antiflood", + B_VIRTUALSERVER_MODIFY_FT_SETTINGS = "b_virtualserver_modify_ft_settings", + B_VIRTUALSERVER_MODIFY_FT_QUOTAS = "b_virtualserver_modify_ft_quotas", + B_VIRTUALSERVER_MODIFY_HOSTMESSAGE = "b_virtualserver_modify_hostmessage", + B_VIRTUALSERVER_MODIFY_HOSTBANNER = "b_virtualserver_modify_hostbanner", + B_VIRTUALSERVER_MODIFY_HOSTBUTTON = "b_virtualserver_modify_hostbutton", + B_VIRTUALSERVER_MODIFY_PORT = "b_virtualserver_modify_port", + B_VIRTUALSERVER_MODIFY_HOST = "b_virtualserver_modify_host", + B_VIRTUALSERVER_MODIFY_DEFAULT_MESSAGES = "b_virtualserver_modify_default_messages", + B_VIRTUALSERVER_MODIFY_AUTOSTART = "b_virtualserver_modify_autostart", + B_VIRTUALSERVER_MODIFY_NEEDED_IDENTITY_SECURITY_LEVEL = "b_virtualserver_modify_needed_identity_security_level", + B_VIRTUALSERVER_MODIFY_PRIORITY_SPEAKER_DIMM_MODIFICATOR = "b_virtualserver_modify_priority_speaker_dimm_modificator", + B_VIRTUALSERVER_MODIFY_LOG_SETTINGS = "b_virtualserver_modify_log_settings", + B_VIRTUALSERVER_MODIFY_MIN_CLIENT_VERSION = "b_virtualserver_modify_min_client_version", + B_VIRTUALSERVER_MODIFY_ICON_ID = "b_virtualserver_modify_icon_id", + B_VIRTUALSERVER_MODIFY_WEBLIST = "b_virtualserver_modify_weblist", + B_VIRTUALSERVER_MODIFY_CODEC_ENCRYPTION_MODE = "b_virtualserver_modify_codec_encryption_mode", + B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS = "b_virtualserver_modify_temporary_passwords", + B_VIRTUALSERVER_MODIFY_TEMPORARY_PASSWORDS_OWN = "b_virtualserver_modify_temporary_passwords_own", + B_VIRTUALSERVER_MODIFY_CHANNEL_TEMP_DELETE_DELAY_DEFAULT = "b_virtualserver_modify_channel_temp_delete_delay_default", + B_VIRTUALSERVER_MODIFY_MUSIC_BOT_LIMIT = "b_virtualserver_modify_music_bot_limit", + I_CHANNEL_MIN_DEPTH = "i_channel_min_depth", + I_CHANNEL_MAX_DEPTH = "i_channel_max_depth", + B_CHANNEL_GROUP_INHERITANCE_END = "b_channel_group_inheritance_end", + I_CHANNEL_PERMISSION_MODIFY_POWER = "i_channel_permission_modify_power", + I_CHANNEL_NEEDED_PERMISSION_MODIFY_POWER = "i_channel_needed_permission_modify_power", + B_CHANNEL_INFO_VIEW = "b_channel_info_view", + B_CHANNEL_CREATE_CHILD = "b_channel_create_child", + B_CHANNEL_CREATE_PERMANENT = "b_channel_create_permanent", + B_CHANNEL_CREATE_SEMI_PERMANENT = "b_channel_create_semi_permanent", + B_CHANNEL_CREATE_TEMPORARY = "b_channel_create_temporary", + B_CHANNEL_CREATE_PRIVATE = "b_channel_create_private", + B_CHANNEL_CREATE_WITH_TOPIC = "b_channel_create_with_topic", + B_CHANNEL_CREATE_WITH_DESCRIPTION = "b_channel_create_with_description", + B_CHANNEL_CREATE_WITH_PASSWORD = "b_channel_create_with_password", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX8 = "b_channel_create_modify_with_codec_speex8", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX16 = "b_channel_create_modify_with_codec_speex16", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_SPEEX32 = "b_channel_create_modify_with_codec_speex32", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_CELTMONO48 = "b_channel_create_modify_with_codec_celtmono48", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSVOICE = "b_channel_create_modify_with_codec_opusvoice", + B_CHANNEL_CREATE_MODIFY_WITH_CODEC_OPUSMUSIC = "b_channel_create_modify_with_codec_opusmusic", + I_CHANNEL_CREATE_MODIFY_WITH_CODEC_MAXQUALITY = "i_channel_create_modify_with_codec_maxquality", + I_CHANNEL_CREATE_MODIFY_WITH_CODEC_LATENCY_FACTOR_MIN = "i_channel_create_modify_with_codec_latency_factor_min", + B_CHANNEL_CREATE_WITH_MAXCLIENTS = "b_channel_create_with_maxclients", + B_CHANNEL_CREATE_WITH_MAXFAMILYCLIENTS = "b_channel_create_with_maxfamilyclients", + B_CHANNEL_CREATE_WITH_SORTORDER = "b_channel_create_with_sortorder", + B_CHANNEL_CREATE_WITH_DEFAULT = "b_channel_create_with_default", + B_CHANNEL_CREATE_WITH_NEEDED_TALK_POWER = "b_channel_create_with_needed_talk_power", + B_CHANNEL_CREATE_MODIFY_WITH_FORCE_PASSWORD = "b_channel_create_modify_with_force_password", + I_CHANNEL_CREATE_MODIFY_WITH_TEMP_DELETE_DELAY = "i_channel_create_modify_with_temp_delete_delay", + B_CHANNEL_MODIFY_PARENT = "b_channel_modify_parent", + B_CHANNEL_MODIFY_MAKE_DEFAULT = "b_channel_modify_make_default", + B_CHANNEL_MODIFY_MAKE_PERMANENT = "b_channel_modify_make_permanent", + B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT = "b_channel_modify_make_semi_permanent", + B_CHANNEL_MODIFY_MAKE_TEMPORARY = "b_channel_modify_make_temporary", + B_CHANNEL_MODIFY_NAME = "b_channel_modify_name", + B_CHANNEL_MODIFY_TOPIC = "b_channel_modify_topic", + B_CHANNEL_MODIFY_DESCRIPTION = "b_channel_modify_description", + B_CHANNEL_MODIFY_PASSWORD = "b_channel_modify_password", + B_CHANNEL_MODIFY_CODEC = "b_channel_modify_codec", + B_CHANNEL_MODIFY_CODEC_QUALITY = "b_channel_modify_codec_quality", + B_CHANNEL_MODIFY_CODEC_LATENCY_FACTOR = "b_channel_modify_codec_latency_factor", + B_CHANNEL_MODIFY_MAXCLIENTS = "b_channel_modify_maxclients", + B_CHANNEL_MODIFY_MAXFAMILYCLIENTS = "b_channel_modify_maxfamilyclients", + B_CHANNEL_MODIFY_SORTORDER = "b_channel_modify_sortorder", + B_CHANNEL_MODIFY_NEEDED_TALK_POWER = "b_channel_modify_needed_talk_power", + I_CHANNEL_MODIFY_POWER = "i_channel_modify_power", + I_CHANNEL_NEEDED_MODIFY_POWER = "i_channel_needed_modify_power", + B_CHANNEL_MODIFY_MAKE_CODEC_ENCRYPTED = "b_channel_modify_make_codec_encrypted", + B_CHANNEL_MODIFY_TEMP_DELETE_DELAY = "b_channel_modify_temp_delete_delay", + B_CHANNEL_DELETE_PERMANENT = "b_channel_delete_permanent", + B_CHANNEL_DELETE_SEMI_PERMANENT = "b_channel_delete_semi_permanent", + B_CHANNEL_DELETE_TEMPORARY = "b_channel_delete_temporary", + B_CHANNEL_DELETE_FLAG_FORCE = "b_channel_delete_flag_force", + I_CHANNEL_DELETE_POWER = "i_channel_delete_power", + I_CHANNEL_NEEDED_DELETE_POWER = "i_channel_needed_delete_power", + B_CHANNEL_JOIN_PERMANENT = "b_channel_join_permanent", + B_CHANNEL_JOIN_SEMI_PERMANENT = "b_channel_join_semi_permanent", + B_CHANNEL_JOIN_TEMPORARY = "b_channel_join_temporary", + B_CHANNEL_JOIN_IGNORE_PASSWORD = "b_channel_join_ignore_password", + B_CHANNEL_JOIN_IGNORE_MAXCLIENTS = "b_channel_join_ignore_maxclients", + B_CHANNEL_IGNORE_VIEW_POWER = "b_channel_ignore_view_power", + I_CHANNEL_JOIN_POWER = "i_channel_join_power", + I_CHANNEL_NEEDED_JOIN_POWER = "i_channel_needed_join_power", + B_CHANNEL_IGNORE_JOIN_POWER = "b_channel_ignore_join_power", + I_CHANNEL_VIEW_POWER = "i_channel_view_power", + I_CHANNEL_NEEDED_VIEW_POWER = "i_channel_needed_view_power", + I_CHANNEL_SUBSCRIBE_POWER = "i_channel_subscribe_power", + I_CHANNEL_NEEDED_SUBSCRIBE_POWER = "i_channel_needed_subscribe_power", + I_CHANNEL_DESCRIPTION_VIEW_POWER = "i_channel_description_view_power", + I_CHANNEL_NEEDED_DESCRIPTION_VIEW_POWER = "i_channel_needed_description_view_power", + I_ICON_ID = "i_icon_id", + I_MAX_ICON_FILESIZE = "i_max_icon_filesize", + B_ICON_MANAGE = "b_icon_manage", + B_GROUP_IS_PERMANENT = "b_group_is_permanent", + I_GROUP_AUTO_UPDATE_TYPE = "i_group_auto_update_type", + I_GROUP_AUTO_UPDATE_MAX_VALUE = "i_group_auto_update_max_value", + I_GROUP_SORT_ID = "i_group_sort_id", + I_GROUP_SHOW_NAME_IN_TREE = "i_group_show_name_in_tree", + B_VIRTUALSERVER_SERVERGROUP_CREATE = "b_virtualserver_servergroup_create", + B_VIRTUALSERVER_SERVERGROUP_LIST = "b_virtualserver_servergroup_list", + B_VIRTUALSERVER_SERVERGROUP_PERMISSION_LIST = "b_virtualserver_servergroup_permission_list", + B_VIRTUALSERVER_SERVERGROUP_CLIENT_LIST = "b_virtualserver_servergroup_client_list", + B_VIRTUALSERVER_CHANNELGROUP_CREATE = "b_virtualserver_channelgroup_create", + B_VIRTUALSERVER_CHANNELGROUP_LIST = "b_virtualserver_channelgroup_list", + B_VIRTUALSERVER_CHANNELGROUP_PERMISSION_LIST = "b_virtualserver_channelgroup_permission_list", + B_VIRTUALSERVER_CHANNELGROUP_CLIENT_LIST = "b_virtualserver_channelgroup_client_list", + B_VIRTUALSERVER_CLIENT_PERMISSION_LIST = "b_virtualserver_client_permission_list", + B_VIRTUALSERVER_CHANNEL_PERMISSION_LIST = "b_virtualserver_channel_permission_list", + B_VIRTUALSERVER_CHANNELCLIENT_PERMISSION_LIST = "b_virtualserver_channelclient_permission_list", + B_VIRTUALSERVER_PLAYLIST_PERMISSION_LIST = "b_virtualserver_playlist_permission_list", + I_SERVER_GROUP_MODIFY_POWER = "i_server_group_modify_power", + I_SERVER_GROUP_NEEDED_MODIFY_POWER = "i_server_group_needed_modify_power", + I_SERVER_GROUP_MEMBER_ADD_POWER = "i_server_group_member_add_power", + I_SERVER_GROUP_SELF_ADD_POWER = "i_server_group_self_add_power", + I_SERVER_GROUP_NEEDED_MEMBER_ADD_POWER = "i_server_group_needed_member_add_power", + I_SERVER_GROUP_MEMBER_REMOVE_POWER = "i_server_group_member_remove_power", + I_SERVER_GROUP_SELF_REMOVE_POWER = "i_server_group_self_remove_power", + I_SERVER_GROUP_NEEDED_MEMBER_REMOVE_POWER = "i_server_group_needed_member_remove_power", + I_CHANNEL_GROUP_MODIFY_POWER = "i_channel_group_modify_power", + I_CHANNEL_GROUP_NEEDED_MODIFY_POWER = "i_channel_group_needed_modify_power", + I_CHANNEL_GROUP_MEMBER_ADD_POWER = "i_channel_group_member_add_power", + I_CHANNEL_GROUP_SELF_ADD_POWER = "i_channel_group_self_add_power", + I_CHANNEL_GROUP_NEEDED_MEMBER_ADD_POWER = "i_channel_group_needed_member_add_power", + I_CHANNEL_GROUP_MEMBER_REMOVE_POWER = "i_channel_group_member_remove_power", + I_CHANNEL_GROUP_SELF_REMOVE_POWER = "i_channel_group_self_remove_power", + I_CHANNEL_GROUP_NEEDED_MEMBER_REMOVE_POWER = "i_channel_group_needed_member_remove_power", + I_GROUP_MEMBER_ADD_POWER = "i_group_member_add_power", + I_GROUP_NEEDED_MEMBER_ADD_POWER = "i_group_needed_member_add_power", + I_GROUP_MEMBER_REMOVE_POWER = "i_group_member_remove_power", + I_GROUP_NEEDED_MEMBER_REMOVE_POWER = "i_group_needed_member_remove_power", + I_GROUP_MODIFY_POWER = "i_group_modify_power", + I_GROUP_NEEDED_MODIFY_POWER = "i_group_needed_modify_power", + I_PERMISSION_MODIFY_POWER = "i_permission_modify_power", + B_PERMISSION_MODIFY_POWER_IGNORE = "b_permission_modify_power_ignore", + B_VIRTUALSERVER_SERVERGROUP_DELETE = "b_virtualserver_servergroup_delete", + B_VIRTUALSERVER_CHANNELGROUP_DELETE = "b_virtualserver_channelgroup_delete", + I_CLIENT_PERMISSION_MODIFY_POWER = "i_client_permission_modify_power", + I_CLIENT_NEEDED_PERMISSION_MODIFY_POWER = "i_client_needed_permission_modify_power", + I_CLIENT_MAX_CLONES_UID = "i_client_max_clones_uid", + I_CLIENT_MAX_CLONES_IP = "i_client_max_clones_ip", + I_CLIENT_MAX_CLONES_HWID = "i_client_max_clones_hwid", + I_CLIENT_MAX_IDLETIME = "i_client_max_idletime", + I_CLIENT_MAX_AVATAR_FILESIZE = "i_client_max_avatar_filesize", + I_CLIENT_MAX_CHANNEL_SUBSCRIPTIONS = "i_client_max_channel_subscriptions", + I_CLIENT_MAX_CHANNELS = "i_client_max_channels", + I_CLIENT_MAX_TEMPORARY_CHANNELS = "i_client_max_temporary_channels", + I_CLIENT_MAX_SEMI_CHANNELS = "i_client_max_semi_channels", + I_CLIENT_MAX_PERMANENT_CHANNELS = "i_client_max_permanent_channels", + B_CLIENT_USE_PRIORITY_SPEAKER = "b_client_use_priority_speaker", + B_CLIENT_SKIP_CHANNELGROUP_PERMISSIONS = "b_client_skip_channelgroup_permissions", + B_CLIENT_FORCE_PUSH_TO_TALK = "b_client_force_push_to_talk", + B_CLIENT_IGNORE_BANS = "b_client_ignore_bans", + B_CLIENT_IGNORE_VPN = "b_client_ignore_vpn", + B_CLIENT_IGNORE_ANTIFLOOD = "b_client_ignore_antiflood", + B_CLIENT_ENFORCE_VALID_HWID = "b_client_enforce_valid_hwid", + B_CLIENT_ALLOW_INVALID_PACKET = "b_client_allow_invalid_packet", + B_CLIENT_ALLOW_INVALID_BADGES = "b_client_allow_invalid_badges", + B_CLIENT_ISSUE_CLIENT_QUERY_COMMAND = "b_client_issue_client_query_command", + B_CLIENT_USE_RESERVED_SLOT = "b_client_use_reserved_slot", + B_CLIENT_USE_CHANNEL_COMMANDER = "b_client_use_channel_commander", + B_CLIENT_REQUEST_TALKER = "b_client_request_talker", + B_CLIENT_AVATAR_DELETE_OTHER = "b_client_avatar_delete_other", + B_CLIENT_IS_STICKY = "b_client_is_sticky", + B_CLIENT_IGNORE_STICKY = "b_client_ignore_sticky", + B_CLIENT_MUSIC_CREATE_PERMANENT = "b_client_music_create_permanent", + B_CLIENT_MUSIC_CREATE_SEMI_PERMANENT = "b_client_music_create_semi_permanent", + B_CLIENT_MUSIC_CREATE_TEMPORARY = "b_client_music_create_temporary", + B_CLIENT_MUSIC_MODIFY_PERMANENT = "b_client_music_modify_permanent", + B_CLIENT_MUSIC_MODIFY_SEMI_PERMANENT = "b_client_music_modify_semi_permanent", + B_CLIENT_MUSIC_MODIFY_TEMPORARY = "b_client_music_modify_temporary", + I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME = "i_client_music_create_modify_max_volume", + I_CLIENT_MUSIC_LIMIT = "i_client_music_limit", + I_CLIENT_MUSIC_NEEDED_DELETE_POWER = "i_client_music_needed_delete_power", + I_CLIENT_MUSIC_DELETE_POWER = "i_client_music_delete_power", + I_CLIENT_MUSIC_PLAY_POWER = "i_client_music_play_power", + I_CLIENT_MUSIC_NEEDED_PLAY_POWER = "i_client_music_needed_play_power", + I_CLIENT_MUSIC_MODIFY_POWER = "i_client_music_modify_power", + I_CLIENT_MUSIC_NEEDED_MODIFY_POWER = "i_client_music_needed_modify_power", + I_CLIENT_MUSIC_RENAME_POWER = "i_client_music_rename_power", + I_CLIENT_MUSIC_NEEDED_RENAME_POWER = "i_client_music_needed_rename_power", + B_PLAYLIST_CREATE = "b_playlist_create", + I_PLAYLIST_VIEW_POWER = "i_playlist_view_power", + I_PLAYLIST_NEEDED_VIEW_POWER = "i_playlist_needed_view_power", + I_PLAYLIST_MODIFY_POWER = "i_playlist_modify_power", + I_PLAYLIST_NEEDED_MODIFY_POWER = "i_playlist_needed_modify_power", + I_PLAYLIST_PERMISSION_MODIFY_POWER = "i_playlist_permission_modify_power", + I_PLAYLIST_NEEDED_PERMISSION_MODIFY_POWER = "i_playlist_needed_permission_modify_power", + I_PLAYLIST_DELETE_POWER = "i_playlist_delete_power", + I_PLAYLIST_NEEDED_DELETE_POWER = "i_playlist_needed_delete_power", + I_PLAYLIST_SONG_ADD_POWER = "i_playlist_song_add_power", + I_PLAYLIST_SONG_NEEDED_ADD_POWER = "i_playlist_song_needed_add_power", + I_PLAYLIST_SONG_REMOVE_POWER = "i_playlist_song_remove_power", + I_PLAYLIST_SONG_NEEDED_REMOVE_POWER = "i_playlist_song_needed_remove_power", + B_CLIENT_INFO_VIEW = "b_client_info_view", + B_CLIENT_PERMISSIONOVERVIEW_VIEW = "b_client_permissionoverview_view", + B_CLIENT_PERMISSIONOVERVIEW_OWN = "b_client_permissionoverview_own", + B_CLIENT_REMOTEADDRESS_VIEW = "b_client_remoteaddress_view", + I_CLIENT_SERVERQUERY_VIEW_POWER = "i_client_serverquery_view_power", + I_CLIENT_NEEDED_SERVERQUERY_VIEW_POWER = "i_client_needed_serverquery_view_power", + B_CLIENT_CUSTOM_INFO_VIEW = "b_client_custom_info_view", + B_CLIENT_MUSIC_CHANNEL_LIST = "b_client_music_channel_list", + B_CLIENT_MUSIC_SERVER_LIST = "b_client_music_server_list", + I_CLIENT_MUSIC_INFO = "i_client_music_info", + I_CLIENT_MUSIC_NEEDED_INFO = "i_client_music_needed_info", + I_CLIENT_KICK_FROM_SERVER_POWER = "i_client_kick_from_server_power", + I_CLIENT_NEEDED_KICK_FROM_SERVER_POWER = "i_client_needed_kick_from_server_power", + I_CLIENT_KICK_FROM_CHANNEL_POWER = "i_client_kick_from_channel_power", + I_CLIENT_NEEDED_KICK_FROM_CHANNEL_POWER = "i_client_needed_kick_from_channel_power", + I_CLIENT_BAN_POWER = "i_client_ban_power", + I_CLIENT_NEEDED_BAN_POWER = "i_client_needed_ban_power", + I_CLIENT_MOVE_POWER = "i_client_move_power", + I_CLIENT_NEEDED_MOVE_POWER = "i_client_needed_move_power", + I_CLIENT_COMPLAIN_POWER = "i_client_complain_power", + I_CLIENT_NEEDED_COMPLAIN_POWER = "i_client_needed_complain_power", + B_CLIENT_COMPLAIN_LIST = "b_client_complain_list", + B_CLIENT_COMPLAIN_DELETE_OWN = "b_client_complain_delete_own", + B_CLIENT_COMPLAIN_DELETE = "b_client_complain_delete", + B_CLIENT_BAN_LIST = "b_client_ban_list", + B_CLIENT_BAN_LIST_GLOBAL = "b_client_ban_list_global", + B_CLIENT_BAN_TRIGGER_LIST = "b_client_ban_trigger_list", + B_CLIENT_BAN_CREATE = "b_client_ban_create", + B_CLIENT_BAN_CREATE_GLOBAL = "b_client_ban_create_global", + B_CLIENT_BAN_NAME = "b_client_ban_name", + B_CLIENT_BAN_IP = "b_client_ban_ip", + B_CLIENT_BAN_HWID = "b_client_ban_hwid", + B_CLIENT_BAN_EDIT = "b_client_ban_edit", + B_CLIENT_BAN_EDIT_GLOBAL = "b_client_ban_edit_global", + B_CLIENT_BAN_DELETE_OWN = "b_client_ban_delete_own", + B_CLIENT_BAN_DELETE = "b_client_ban_delete", + B_CLIENT_BAN_DELETE_OWN_GLOBAL = "b_client_ban_delete_own_global", + B_CLIENT_BAN_DELETE_GLOBAL = "b_client_ban_delete_global", + I_CLIENT_BAN_MAX_BANTIME = "i_client_ban_max_bantime", + I_CLIENT_PRIVATE_TEXTMESSAGE_POWER = "i_client_private_textmessage_power", + I_CLIENT_NEEDED_PRIVATE_TEXTMESSAGE_POWER = "i_client_needed_private_textmessage_power", + B_CLIENT_EVEN_TEXTMESSAGE_SEND = "b_client_even_textmessage_send", + B_CLIENT_SERVER_TEXTMESSAGE_SEND = "b_client_server_textmessage_send", + B_CLIENT_CHANNEL_TEXTMESSAGE_SEND = "b_client_channel_textmessage_send", + B_CLIENT_OFFLINE_TEXTMESSAGE_SEND = "b_client_offline_textmessage_send", + I_CLIENT_TALK_POWER = "i_client_talk_power", + I_CLIENT_NEEDED_TALK_POWER = "i_client_needed_talk_power", + I_CLIENT_POKE_POWER = "i_client_poke_power", + I_CLIENT_NEEDED_POKE_POWER = "i_client_needed_poke_power", + B_CLIENT_SET_FLAG_TALKER = "b_client_set_flag_talker", + I_CLIENT_WHISPER_POWER = "i_client_whisper_power", + I_CLIENT_NEEDED_WHISPER_POWER = "i_client_needed_whisper_power", + B_CLIENT_MODIFY_DESCRIPTION = "b_client_modify_description", + B_CLIENT_MODIFY_OWN_DESCRIPTION = "b_client_modify_own_description", + B_CLIENT_USE_BBCODE_ANY = "b_client_use_bbcode_any", + B_CLIENT_USE_BBCODE_URL = "b_client_use_bbcode_url", + B_CLIENT_USE_BBCODE_IMAGE = "b_client_use_bbcode_image", + B_CLIENT_MODIFY_DBPROPERTIES = "b_client_modify_dbproperties", + B_CLIENT_DELETE_DBPROPERTIES = "b_client_delete_dbproperties", + B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN = "b_client_create_modify_serverquery_login", + B_CLIENT_QUERY_CREATE = "b_client_query_create", + B_CLIENT_QUERY_LIST = "b_client_query_list", + B_CLIENT_QUERY_LIST_OWN = "b_client_query_list_own", + B_CLIENT_QUERY_RENAME = "b_client_query_rename", + B_CLIENT_QUERY_RENAME_OWN = "b_client_query_rename_own", + B_CLIENT_QUERY_CHANGE_PASSWORD = "b_client_query_change_password", + B_CLIENT_QUERY_CHANGE_OWN_PASSWORD = "b_client_query_change_own_password", + B_CLIENT_QUERY_CHANGE_PASSWORD_GLOBAL = "b_client_query_change_password_global", + B_CLIENT_QUERY_DELETE = "b_client_query_delete", + B_CLIENT_QUERY_DELETE_OWN = "b_client_query_delete_own", + B_FT_IGNORE_PASSWORD = "b_ft_ignore_password", + B_FT_TRANSFER_LIST = "b_ft_transfer_list", + I_FT_FILE_UPLOAD_POWER = "i_ft_file_upload_power", + I_FT_NEEDED_FILE_UPLOAD_POWER = "i_ft_needed_file_upload_power", + I_FT_FILE_DOWNLOAD_POWER = "i_ft_file_download_power", + I_FT_NEEDED_FILE_DOWNLOAD_POWER = "i_ft_needed_file_download_power", + I_FT_FILE_DELETE_POWER = "i_ft_file_delete_power", + I_FT_NEEDED_FILE_DELETE_POWER = "i_ft_needed_file_delete_power", + I_FT_FILE_RENAME_POWER = "i_ft_file_rename_power", + I_FT_NEEDED_FILE_RENAME_POWER = "i_ft_needed_file_rename_power", + I_FT_FILE_BROWSE_POWER = "i_ft_file_browse_power", + I_FT_NEEDED_FILE_BROWSE_POWER = "i_ft_needed_file_browse_power", + I_FT_DIRECTORY_CREATE_POWER = "i_ft_directory_create_power", + I_FT_NEEDED_DIRECTORY_CREATE_POWER = "i_ft_needed_directory_create_power", + I_FT_QUOTA_MB_DOWNLOAD_PER_CLIENT = "i_ft_quota_mb_download_per_client", + I_FT_QUOTA_MB_UPLOAD_PER_CLIENT = "i_ft_quota_mb_upload_per_client" } declare class PermissionInfo { name: string; @@ -1540,6 +1519,8 @@ declare class PermissionManager extends connection.AbstractCommandHandler { requests_playlist_permissions: TeaPermissionRequest[]; initializedListener: ((initialized: boolean) => void)[]; private _cacheNeededPermissions: any; + /* Static info mapping until TeaSpeak implements a detailed info */ + //TODO tr static readonly group_mapping: { name: string; deep: number; @@ -1547,12 +1528,14 @@ declare class PermissionManager extends connection.AbstractCommandHandler { private _group_mapping; public static parse_permission_bulk(json: any[], manager: PermissionManager): PermissionValue[]; constructor(client: ConnectionHandler); + destroy(); handle_command(command: connection.ServerCommand): boolean; initialized(): boolean; public requestPermissionList(); private onPermissionList(json); private onNeededPermissions(json); register_needed_permission(key: PermissionType, listener: () => any); + unregister_needed_permission(key: PermissionType, listener: () => any); private onChannelPermList(json); resolveInfo?(key: number | string | PermissionType): PermissionInfo; requestChannelPermissions(channelId: number): Promise; @@ -1563,128 +1546,131 @@ declare class PermissionManager extends connection.AbstractCommandHandler { requestPlaylistPermissions(playlist_id: number): Promise; neededPermission(key: number | string | PermissionType | PermissionInfo): NeededPermissionValue; groupedPermissions(): GroupedPermissions[]; + /** + * Generates an enum with all know permission types, used for the enum above + */ export_permission_types(); } -/* File: shared/js/PPTListener.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/PPTListener.ts */ declare enum KeyCode { - KEY_CANCEL, - KEY_HELP, - KEY_BACK_SPACE, - KEY_TAB, - KEY_CLEAR, - KEY_RETURN, - KEY_ENTER, - KEY_SHIFT, - KEY_CONTROL, - KEY_ALT, - KEY_PAUSE, - KEY_CAPS_LOCK, - KEY_ESCAPE, - KEY_SPACE, - KEY_PAGE_UP, - KEY_PAGE_DOWN, - KEY_END, - KEY_HOME, - KEY_LEFT, - KEY_UP, - KEY_RIGHT, - KEY_DOWN, - KEY_PRINTSCREEN, - KEY_INSERT, - KEY_DELETE, - KEY_0, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_SEMICOLON, - KEY_EQUALS, - KEY_A, - KEY_B, - KEY_C, - KEY_D, - KEY_E, - KEY_F, - KEY_G, - KEY_H, - KEY_I, - KEY_J, - KEY_K, - KEY_L, - KEY_M, - KEY_N, - KEY_O, - KEY_P, - KEY_Q, - KEY_R, - KEY_S, - KEY_T, - KEY_U, - KEY_V, - KEY_W, - KEY_X, - KEY_Y, - KEY_Z, - KEY_LEFT_CMD, - KEY_RIGHT_CMD, - KEY_CONTEXT_MENU, - KEY_NUMPAD0, - KEY_NUMPAD1, - KEY_NUMPAD2, - KEY_NUMPAD3, - KEY_NUMPAD4, - KEY_NUMPAD5, - KEY_NUMPAD6, - KEY_NUMPAD7, - KEY_NUMPAD8, - KEY_NUMPAD9, - KEY_MULTIPLY, - KEY_ADD, - KEY_SEPARATOR, - KEY_SUBTRACT, - KEY_DECIMAL, - KEY_DIVIDE, - KEY_F1, - KEY_F2, - KEY_F3, - KEY_F4, - KEY_F5, - KEY_F6, - KEY_F7, - KEY_F8, - KEY_F9, - KEY_F10, - KEY_F11, - KEY_F12, - KEY_F13, - KEY_F14, - KEY_F15, - KEY_F16, - KEY_F17, - KEY_F18, - KEY_F19, - KEY_F20, - KEY_F21, - KEY_F22, - KEY_F23, - KEY_F24, - KEY_NUM_LOCK, - KEY_SCROLL_LOCK, - KEY_COMMA, - KEY_PERIOD, - KEY_SLASH, - KEY_BACK_QUOTE, - KEY_OPEN_BRACKET, - KEY_BACK_SLASH, - KEY_CLOSE_BRACKET, - KEY_QUOTE, - KEY_META + KEY_CANCEL = 3, + KEY_HELP = 6, + KEY_BACK_SPACE = 8, + KEY_TAB = 9, + KEY_CLEAR = 12, + KEY_RETURN = 13, + KEY_ENTER = 14, + KEY_SHIFT = 16, + KEY_CONTROL = 17, + KEY_ALT = 18, + KEY_PAUSE = 19, + KEY_CAPS_LOCK = 20, + KEY_ESCAPE = 27, + KEY_SPACE = 32, + KEY_PAGE_UP = 33, + KEY_PAGE_DOWN = 34, + KEY_END = 35, + KEY_HOME = 36, + KEY_LEFT = 37, + KEY_UP = 38, + KEY_RIGHT = 39, + KEY_DOWN = 40, + KEY_PRINTSCREEN = 44, + KEY_INSERT = 45, + KEY_DELETE = 46, + KEY_0 = 48, + KEY_1 = 49, + KEY_2 = 50, + KEY_3 = 51, + KEY_4 = 52, + KEY_5 = 53, + KEY_6 = 54, + KEY_7 = 55, + KEY_8 = 56, + KEY_9 = 57, + KEY_SEMICOLON = 59, + KEY_EQUALS = 61, + KEY_A = 65, + KEY_B = 66, + KEY_C = 67, + KEY_D = 68, + KEY_E = 69, + KEY_F = 70, + KEY_G = 71, + KEY_H = 72, + KEY_I = 73, + KEY_J = 74, + KEY_K = 75, + KEY_L = 76, + KEY_M = 77, + KEY_N = 78, + KEY_O = 79, + KEY_P = 80, + KEY_Q = 81, + KEY_R = 82, + KEY_S = 83, + KEY_T = 84, + KEY_U = 85, + KEY_V = 86, + KEY_W = 87, + KEY_X = 88, + KEY_Y = 89, + KEY_Z = 90, + KEY_LEFT_CMD = 91, + KEY_RIGHT_CMD = 93, + KEY_CONTEXT_MENU = 93, + KEY_NUMPAD0 = 96, + KEY_NUMPAD1 = 97, + KEY_NUMPAD2 = 98, + KEY_NUMPAD3 = 99, + KEY_NUMPAD4 = 100, + KEY_NUMPAD5 = 101, + KEY_NUMPAD6 = 102, + KEY_NUMPAD7 = 103, + KEY_NUMPAD8 = 104, + KEY_NUMPAD9 = 105, + KEY_MULTIPLY = 106, + KEY_ADD = 107, + KEY_SEPARATOR = 108, + KEY_SUBTRACT = 109, + KEY_DECIMAL = 110, + KEY_DIVIDE = 111, + KEY_F1 = 112, + KEY_F2 = 113, + KEY_F3 = 114, + KEY_F4 = 115, + KEY_F5 = 116, + KEY_F6 = 117, + KEY_F7 = 118, + KEY_F8 = 119, + KEY_F9 = 120, + KEY_F10 = 121, + KEY_F11 = 122, + KEY_F12 = 123, + KEY_F13 = 124, + KEY_F14 = 125, + KEY_F15 = 126, + KEY_F16 = 127, + KEY_F17 = 128, + KEY_F18 = 129, + KEY_F19 = 130, + KEY_F20 = 131, + KEY_F21 = 132, + KEY_F22 = 133, + KEY_F23 = 134, + KEY_F24 = 135, + KEY_NUM_LOCK = 144, + KEY_SCROLL_LOCK = 145, + KEY_COMMA = 188, + KEY_PERIOD = 190, + KEY_SLASH = 191, + KEY_BACK_QUOTE = 192, + KEY_OPEN_BRACKET = 219, + KEY_BACK_SLASH = 220, + KEY_CLOSE_BRACKET = 221, + KEY_QUOTE = 222, + KEY_META = 224 } declare namespace ppt { export enum EventType { @@ -1717,7 +1703,7 @@ declare namespace ppt { export function key_description(key: KeyDescriptor); } -/* File: shared/js/profiles/ConnectionProfile.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/ConnectionProfile.ts */ declare namespace profiles { export class ConnectionProfile { id: string; @@ -1749,7 +1735,7 @@ declare namespace profiles { export function delete_profile(profile: ConnectionProfile); } -/* File: shared/js/profiles/identities/NameIdentity.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/NameIdentity.ts */ declare namespace profiles.identities { export class NameHandshakeHandler extends AbstractHandshakeIdentityHandler { readonly identity: NameIdentity; @@ -1773,7 +1759,7 @@ declare namespace profiles.identities { } } -/* File: shared/js/profiles/identities/TeaForumIdentity.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/TeaForumIdentity.ts */ declare namespace profiles.identities { export class TeaForumHandshakeHandler extends AbstractHandshakeIdentityHandler { readonly identity: TeaForumIdentity; @@ -1785,37 +1771,35 @@ declare namespace profiles.identities { protected trigger_success(); } export class TeaForumIdentity implements Identity { - private identity_data: string; - private identity_data_raw: string; - private identity_data_sign: string; + private readonly identity_data: forum.Data; valid(): boolean; - constructor(data: string, sign: string); - data_json(): string; - data_sign(): string; - name(): string; - uid(): string; - type(): IdentitifyType; - forum_user_id(); - forum_user_group(); - is_stuff(): boolean; - is_premium(): boolean; - data_age(): Date; + constructor(data: forum.Data); + data(): forum.Data; decode(data): Promise; - encode?(): string; + encode(): string; spawn_identity_handshake_handler(connection: connection.AbstractServerConnection): connection.HandshakeIdentityHandler; + name(): string; + type(): profiles.identities.IdentitifyType; + uid(): string; } export function set_static_identity(identity: TeaForumIdentity); - export function setup_forum(); + export function update_forum(); export function valid_static_forum_identity(): boolean; export function static_forum_identity(): TeaForumIdentity | undefined; } -/* File: shared/js/profiles/identities/TeamSpeakIdentity.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/TeamSpeakIdentity.ts */ declare namespace profiles.identities { export namespace CryptoHelper { + export function base64_url_encode(str); + export function base64_url_decode(str: string, pad?: boolean); + export function arraybuffer_to_string(buf); export function export_ecc_key(crypto_key: CryptoKey, public_key: boolean): Promise; export function decrypt_ts_identity(buffer: Uint8Array): Promise; export function encrypt_ts_identity(buffer: Uint8Array): Promise; + /** + * @param buffer base64 encoded ASN.1 string + */ export function decode_tomcrypt_key(buffer: string); } export class TeaSpeakHandshakeHandler extends AbstractHandshakeIdentityHandler { @@ -1857,6 +1841,11 @@ declare namespace profiles.identities { decode(data: string): Promise; encode?(): string; level(): Promise; + /** + * @param {string} a + * @param {string} b + * @description b must be smaller (in bytes) then a + */ private string_add(a: string, b: string); improve_level_for(time: number, threads: number): Promise; improve_level(target: number, threads: number, active_callback: () => boolean, callback_level?: (current: number) => any, callback_status?: (hash_rate: number) => any): Promise; @@ -1867,7 +1856,67 @@ declare namespace profiles.identities { } } -/* File: shared/js/profiles/Identity.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/identities/teaspeak-forum.ts */ +declare interface Window { + grecaptcha: GReCaptcha; +} +declare interface GReCaptcha { + render(container: string | HTMLElement, parameters: { + sitekey: string; + theme?: "dark" | "light"; + size?: "compact" | "normal"; + tabindex?: number; + callback?: (token: string) => any; + "expired-callback"?: () => any; + "error-callback"?: (error: any) => any; + }): string; /* widget_id */ + reset(widget_id?: string); +} +declare namespace forum { + export namespace gcaptcha { + export function initialize(): Promise; + export function spawn(container: JQuery, key: string, callback_data: (token: string) => any): Promise; + } + export class Data { + readonly auth_key: string; + readonly raw: string; + readonly sign: string; + parsed: { + user_id: number; + user_name: string; + data_age: number; + user_group_id: number; + is_staff: boolean; + user_groups: number[]; + }; + constructor(auth: string, raw: string, sign: string); + data_json(): string; + data_sign(): string; + name(): string; + user_id(); + user_group(); + is_stuff(): boolean; + is_premium(): boolean; + data_age(): Date; + is_expired(): boolean; + should_renew(): boolean; + } + export function logged_in(): boolean; + export function data(): Data; + export interface LoginResult { + status: "success" | "captcha" | "error"; + error_message?: string; + captcha?: { + type: "gre-captcha" | "unknown"; + data: any; /* in case of gre-captcha it would be the side key */ + }; + } + export function login(username: string, password: string, captcha?: any): Promise; + export function renew_data(): Promise<"success" | "login-required">; + export function logout(): Promise; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/profiles/Identity.ts */ declare namespace profiles.identities { export enum IdentitifyType { TEAFORO, @@ -1901,7 +1950,7 @@ declare namespace profiles.identities { } } -/* File: shared/js/proto.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/proto.ts */ declare interface Array { remove(elem?: T): boolean; last?(): T; @@ -1911,16 +1960,19 @@ declare interface JSON { map_to(object: T, json: any, variables?: string | string[], validator?: (map_field: string, map_value: string) => boolean, variable_direction?: number): T; map_field_to(object: T, value: any, field: string): T; } -type JQueryScrollType = "height" | "width"; +declare type JQueryScrollType = "height" | "width"; declare interface JQuery { render(values?: any): string; renderTag(values?: any): JQuery; hasScrollBar(direction?: JQueryScrollType): boolean; visible_height(): number; visible_width(): number; + /* bootstrap */ alert(): JQuery; modal(properties: any): this; bootstrapMaterialDesign(): this; + /* first element which matches the selector, could be the element itself or a parent */ + firstParent(selector: string): JQuery; } declare interface JQueryStatic { spawn(tagName: K): JQuery; @@ -1937,6 +1989,25 @@ declare interface Twemoji { parse(message: string): string; } declare let twemoji: Twemoji; +declare interface HighlightJS { + listLanguages(): string[]; + getLanguage(name: string): any | undefined; + highlight(language: string, text: string, ignore_illegals?: boolean): HighlightJSResult; + highlightAuto(text: string): HighlightJSResult; +} +declare interface HighlightJSResult { + language: string; + relevance: number; + value: string; + second_best?: any; +} +declare interface DOMPurify { + sanitize(html: string, config?: { + ADD_ATTR?: string[]; + }): string; +} +declare let DOMPurify: DOMPurify; +declare let remarkable: typeof window.remarkable; declare class webkitAudioContext extends AudioContext { } declare class webkitOfflineAudioContext extends OfflineAudioContext { @@ -1950,6 +2021,8 @@ declare interface Window { readonly Pointer_stringify: any; readonly jsrender: any; twemoji: Twemoji; + hljs: HighlightJS; + remarkable: any; require(id: string): any; } declare interface Navigator { @@ -1957,9 +2030,11 @@ declare interface Navigator { name: string; version: string; }; + mozGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void; + webkitGetUserMedia(constraints: MediaStreamConstraints, successCallback: NavigatorUserMediaSuccessCallback, errorCallback: NavigatorUserMediaErrorCallback): void; } -/* File: shared/js/settings.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/settings.ts */ declare interface SettingsKey { key: string; fallback_keys?: string | string[]; @@ -1996,10 +2071,12 @@ declare class Settings extends StaticSettings { static readonly KEY_DISABLE_VOICE: SettingsKey; static readonly KEY_DISABLE_MULTI_SESSION: SettingsKey; static readonly KEY_LOAD_DUMMY_ERROR: SettingsKey; + /* Control bar */ static readonly KEY_CONTROL_MUTE_INPUT: SettingsKey; static readonly KEY_CONTROL_MUTE_OUTPUT: SettingsKey; static readonly KEY_CONTROL_SHOW_QUERIES: SettingsKey; static readonly KEY_CONTROL_CHANNEL_SUBSCRIBE_ALL: SettingsKey; + /* Connect parameters */ static readonly KEY_FLAG_CONNECT_DEFAULT: SettingsKey; static readonly KEY_CONNECT_ADDRESS: SettingsKey; static readonly KEY_CONNECT_PROFILE: SettingsKey; @@ -2008,13 +2085,25 @@ declare class Settings extends StaticSettings { static readonly KEY_FLAG_CONNECT_PASSWORD: SettingsKey; static readonly KEY_CONNECT_HISTORY: SettingsKey; static readonly KEY_CERTIFICATE_CALLBACK: SettingsKey; + /* sounds */ static readonly KEY_SOUND_MASTER: SettingsKey; static readonly KEY_SOUND_MASTER_SOUNDS: SettingsKey; static readonly KEY_CHAT_FIXED_TIMESTAMPS: SettingsKey; static readonly KEY_CHAT_COLLOQUIAL_TIMESTAMPS: SettingsKey; - static readonly FN_SERVER_CHANNEL_SUBSCRIBE_MODE: (channel: ChannelEntry) => SettingsKey; + static readonly KEY_CHAT_COLORED_EMOJIES: SettingsKey; + static readonly KEY_CHAT_TAG_URLS: SettingsKey; + static readonly KEY_CHAT_ENABLE_MARKDOWN: SettingsKey; + static readonly KEY_CHAT_ENABLE_BBCODE: SettingsKey; + static readonly KEY_SWITCH_INSTANT_CHAT: SettingsKey; + static readonly KEY_SWITCH_INSTANT_CLIENT: SettingsKey; + static readonly KEY_HOSTBANNER_BACKGROUND: SettingsKey; + static readonly KEY_CHANNEL_EDIT_ADVANCED: SettingsKey; + static readonly KEY_TEAFORO_URL: SettingsKey; + static readonly KEY_FONT_SIZE: SettingsKey; + static readonly FN_SERVER_CHANNEL_SUBSCRIBE_MODE: (channel_id: number) => SettingsKey; static readonly FN_PROFILE_RECORD: (name: string) => SettingsKey; static readonly KEYS; + static initialize(); private cacheGlobal; private saveWorker: NodeJS.Timer; private updated: boolean; @@ -2026,65 +2115,68 @@ declare class Settings extends StaticSettings { } declare class ServerSettings extends SettingsBase { private cacheServer; - private currentServer: ServerEntry; + private _server_unique_id: string; private _server_save_worker: NodeJS.Timer; private _server_settings_updated: boolean; + private _destroyed; constructor(); + destroy(); server?(key: string | SettingsKey, _default?: T): T; changeServer(key: string | SettingsKey, value?: T); - setServer(server: ServerEntry); + setServer(server_unique_id: string); save(); } +declare let settings: Settings; -/* File: shared/js/sound/Sounds.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/sound/Sounds.ts */ declare enum Sound { - SOUND_TEST, - SOUND_EGG, - AWAY_ACTIVATED, - AWAY_DEACTIVATED, - MICROPHONE_MUTED, - MICROPHONE_ACTIVATED, - SOUND_MUTED, - SOUND_ACTIVATED, - CONNECTION_CONNECTED, - CONNECTION_DISCONNECTED, - CONNECTION_BANNED, - CONNECTION_DISCONNECTED_TIMEOUT, - CONNECTION_REFUSED, - SERVER_EDITED, - SERVER_EDITED_SELF, - SERVER_KICKED, - CHANNEL_CREATED, - CHANNEL_MOVED, - CHANNEL_EDITED, - CHANNEL_EDITED_SELF, - CHANNEL_DELETED, - CHANNEL_JOINED, - CHANNEL_KICKED, - USER_MOVED, - USER_MOVED_SELF, - USER_POKED_SELF, - USER_BANNED, - USER_ENTERED, - USER_ENTERED_MOVED, - USER_ENTERED_KICKED, - USER_ENTERED_CONNECT, - USER_LEFT, - USER_LEFT_MOVED, - USER_LEFT_KICKED_CHANNEL, - USER_LEFT_KICKED_SERVER, - USER_LEFT_DISCONNECT, - USER_LEFT_BANNED, - USER_LEFT_TIMEOUT, - ERROR_INSUFFICIENT_PERMISSIONS, - MESSAGE_SEND, - MESSAGE_RECEIVED, - GROUP_SERVER_ASSIGNED, - GROUP_SERVER_REVOKED, - GROUP_CHANNEL_CHANGED, - GROUP_SERVER_ASSIGNED_SELF, - GROUP_SERVER_REVOKED_SELF, - GROUP_CHANNEL_CHANGED_SELF + SOUND_TEST = "sound.test", + SOUND_EGG = "sound.egg", + AWAY_ACTIVATED = "away_activated", + AWAY_DEACTIVATED = "away_deactivated", + MICROPHONE_MUTED = "microphone.muted", + MICROPHONE_ACTIVATED = "microphone.activated", + SOUND_MUTED = "sound.muted", + SOUND_ACTIVATED = "sound.activated", + CONNECTION_CONNECTED = "connection.connected", + CONNECTION_DISCONNECTED = "connection.disconnected", + CONNECTION_BANNED = "connection.banned", + CONNECTION_DISCONNECTED_TIMEOUT = "connection.disconnected.timeout", + CONNECTION_REFUSED = "connection.refused", + SERVER_EDITED = "server.edited", + SERVER_EDITED_SELF = "server.edited.self", + SERVER_KICKED = "server.kicked", + CHANNEL_CREATED = "channel.created", + CHANNEL_MOVED = "channel.moved", + CHANNEL_EDITED = "channel.edited", + CHANNEL_EDITED_SELF = "channel.edited.self", + CHANNEL_DELETED = "channel.deleted", + CHANNEL_JOINED = "channel.joined", + CHANNEL_KICKED = "channel.kicked", + USER_MOVED = "user.moved", + USER_MOVED_SELF = "user.moved.self", + USER_POKED_SELF = "user.poked.self", + USER_BANNED = "user.banned", + USER_ENTERED = "user.joined", + USER_ENTERED_MOVED = "user.joined.moved", + USER_ENTERED_KICKED = "user.joined.kicked", + USER_ENTERED_CONNECT = "user.joined.connect", + USER_LEFT = "user.left", + USER_LEFT_MOVED = "user.left.moved", + USER_LEFT_KICKED_CHANNEL = "user.left.kicked.server", + USER_LEFT_KICKED_SERVER = "user.left.kicked.channel", + USER_LEFT_DISCONNECT = "user.left.disconnect", + USER_LEFT_BANNED = "user.left.banned", + USER_LEFT_TIMEOUT = "user.left.timeout", + ERROR_INSUFFICIENT_PERMISSIONS = "error.insufficient_permissions", + MESSAGE_SEND = "message.send", + MESSAGE_RECEIVED = "message.received", + GROUP_SERVER_ASSIGNED = "group.server.assigned", + GROUP_SERVER_REVOKED = "group.server.revoked", + GROUP_CHANNEL_CHANGED = "group.channel.changed", + GROUP_SERVER_ASSIGNED_SELF = "group.server.assigned.self", + GROUP_SERVER_REVOKED_SELF = "group.server.revoked.self", + GROUP_CHANNEL_CHANGED_SELF = "group.channel.changed.self" } declare namespace sound { export interface SoundHandle { @@ -2111,6 +2203,7 @@ declare namespace sound { ignore_muted?: boolean; ignore_overlap?: boolean; default_volume?: number; + callback?: (flag: boolean) => any; } export function resolve_sound(sound: Sound): Promise; export let manager: SoundManager; @@ -2124,13 +2217,13 @@ declare namespace sound { } } -/* File: shared/js/stats.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/stats.ts */ declare namespace stats { export enum CloseCodes { - UNSET, - RECONNECT, - INTERNAL_ERROR, - BANNED + UNSET = 3000, + RECONNECT = 3001, + INTERNAL_ERROR = 3002, + BANNED = 3100 } export enum ConnectionState { CONNECTING, @@ -2139,7 +2232,15 @@ declare namespace stats { UNSET } export class SessionConfig { + /* + * All collected statistics will only be cached by the stats server. + * No data will be saved. + */ volatile_collection_only?: boolean; + /* + * Anonymize all IP addresses which will be provided while the stats collection. + * This option is quite useless when volatile_collection_only is active. + */ anonymize_ip_addresses?: boolean; } export class Config extends SessionConfig { @@ -2164,7 +2265,7 @@ declare namespace stats { } } -/* File: shared/js/ui/channel.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/channel.ts */ declare enum ChannelType { PERMANENT, SEMI_PERMANENT, @@ -2199,7 +2300,9 @@ declare class ChannelProperties { channel_flag_maxfamilyclients_unlimited: boolean; channel_icon_id: number; channel_delete_delay: number; + //Only after request channel_description: string; + channel_flag_conversation_private: boolean; } declare class ChannelEntry { channelTree: ChannelTree; @@ -2211,10 +2314,12 @@ declare class ChannelEntry { private _channel_name_alignment: string; private _channel_name_formatted: string; private _family_index: number; + //HTML DOM elements private _tag_root: JQuery; private _tag_siblings: JQuery; private _tag_clients: JQuery; private _tag_channel: JQuery; + private _destroyed; private _cachedPassword: string; private _cached_channel_description: string; private _cached_channel_description_promise: Promise; @@ -2223,6 +2328,7 @@ declare class ChannelEntry { private _flag_subscribed: boolean; private _subscribe_mode: ChannelSubscribeMode; constructor(channelId, channelName, parent?); + destroy(); channelName(); formattedChannelName(); getChannelDescription(): Promise; @@ -2266,10 +2372,12 @@ declare class ChannelEntry { get subscribe_mode(): ChannelSubscribeMode; // @ts-ignore set subscribe_mode(mode: ChannelSubscribeMode); + // @ts-ignore + set flag_text_unread(flag: boolean); log_data(): log.server.base.Channel; } -/* File: shared/js/ui/client_move.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/client_move.ts */ declare class ClientMover { static readonly listener_root; static readonly move_element; @@ -2295,7 +2403,7 @@ declare class ClientMover { deactivate(); } -/* File: shared/js/ui/client.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/client.ts */ declare enum ClientType { CLIENT_VOICE, CLIENT_QUERY, @@ -2316,6 +2424,8 @@ declare class ClientProperties { client_servergroups: string; client_channel_group_id: number; client_lastconnected: number; + client_created: number; + client_totalconnections: number; client_flag_avatar: string; client_icon_id: number; client_away_message: string; @@ -2326,10 +2436,58 @@ declare class ClientProperties { client_input_muted: boolean; client_output_muted: boolean; client_is_channel_commander: boolean; - client_teaforum_id: number; - client_teaforum_name: string; + client_teaforo_id: number; + client_teaforo_name: string; + client_teaforo_flags: number; + /* not updated in view! */ + client_month_bytes_uploaded: number; + client_month_bytes_downloaded: number; + client_total_bytes_uploaded: number; + client_total_bytes_downloaded: number; client_talk_power: number; } +declare class ClientConnectionInfo { + connection_bandwidth_received_last_minute_control: number; + connection_bandwidth_received_last_minute_keepalive: number; + connection_bandwidth_received_last_minute_speech: number; + connection_bandwidth_received_last_second_control: number; + connection_bandwidth_received_last_second_keepalive: number; + connection_bandwidth_received_last_second_speech: number; + connection_bandwidth_sent_last_minute_control: number; + connection_bandwidth_sent_last_minute_keepalive: number; + connection_bandwidth_sent_last_minute_speech: number; + connection_bandwidth_sent_last_second_control: number; + connection_bandwidth_sent_last_second_keepalive: number; + connection_bandwidth_sent_last_second_speech: number; + connection_bytes_received_control: number; + connection_bytes_received_keepalive: number; + connection_bytes_received_speech: number; + connection_bytes_sent_control: number; + connection_bytes_sent_keepalive: number; + connection_bytes_sent_speech: number; + connection_packets_received_control: number; + connection_packets_received_keepalive: number; + connection_packets_received_speech: number; + connection_packets_sent_control: number; + connection_packets_sent_keepalive: number; + connection_packets_sent_speech: number; + connection_ping: number; + connection_ping_deviation: number; + connection_server2client_packetloss_control: number; + connection_server2client_packetloss_keepalive: number; + connection_server2client_packetloss_speech: number; + connection_server2client_packetloss_total: number; + connection_client2server_packetloss_speech: number; + connection_client2server_packetloss_keepalive: number; + connection_client2server_packetloss_control: number; + connection_client2server_packetloss_total: number; + connection_filetransfer_bandwidth_sent: number; + connection_filetransfer_bandwidth_received: number; + connection_connected_time: number; + connection_idle_time: number; + connection_client_ip: string | undefined; + connection_client_port: number; +} declare class ClientEntry { protected _clientId: number; protected _channel: ChannelEntry; @@ -2341,8 +2499,16 @@ declare class ClientEntry { protected _audio_handle: connection.voice.VoiceClient; protected _audio_volume: number; protected _audio_muted: boolean; + private _info_variables_promise: Promise; + private _info_variables_promise_timestamp: number; + private _info_connection_promise: Promise; + private _info_connection_promise_timestamp: number; + private _info_connection_promise_resolve: any; + private _info_connection_promise_reject: any; channelTree: ChannelTree; constructor(clientId: number, clientName, properties?: ClientProperties); + destroy(); + tree_unregistered(); set_audio_handle(handle: connection.voice.VoiceClient); get_audio_handle(): connection.voice.VoiceClient; // @ts-ignore @@ -2354,6 +2520,7 @@ declare class ClientEntry { is_muted(); set_muted(flag: boolean, update_icon: boolean, force?: boolean); protected initializeListener(); + protected contextmenu_info(): contextmenu.MenuEntry[]; protected assignment_context(): contextmenu.MenuEntry[]; open_text_chat(); showContextMenu(x: number, y: number, on_close?: () => void); @@ -2373,7 +2540,7 @@ declare class ClientEntry { value: string; }[]); update_displayed_client_groups(); - updateClientVariables(); + updateClientVariables(force_update?: boolean): Promise; updateClientIcon(); updateGroupIcon(group: Group); update_group_icon_order(); @@ -2385,6 +2552,9 @@ declare class ClientEntry { avatarId?(): string; update_family_index(); log_data(): log.server.base.Client; + /* max 1s ago, so we could update every second */ + request_connection_info(): Promise; + set_connection_info(info: ClientConnectionInfo); } declare class LocalClientEntry extends ClientEntry { handle: ConnectionHandler; @@ -2423,6 +2593,7 @@ declare class MusicClientEntry extends ClientEntry { private _info_promise_resolve: any; private _info_promise_reject: any; constructor(clientId, clientName); + destroy(); // @ts-ignore get properties(): MusicClientProperties; showContextMenu(x: number, y: number, on_close?: () => void): void; @@ -2431,12 +2602,12 @@ declare class MusicClientEntry extends ClientEntry { requestPlayerInfo(max_age?: number): Promise; } -/* File: shared/js/ui/elements/context_divider.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/context_divider.ts */ declare interface JQuery { dividerfy(): this; } -/* File: shared/js/ui/elements/context_menu.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/context_menu.ts */ declare namespace contextmenu { export interface MenuEntry { callback?: () => void; @@ -2477,6 +2648,7 @@ declare class HTMLContextMenuProvider implements contextmenu.ContextMenuProvider private _global_click_listener: (event) => any; private _context_menu: JQuery; private _close_callbacks: (() => any)[]; + private _visible; despawn_context_menu(); finalize(); initialize(); @@ -2486,13 +2658,13 @@ declare class HTMLContextMenuProvider implements contextmenu.ContextMenuProvider html_format_enabled(): boolean; } -/* File: shared/js/ui/elements/modal.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/modal.ts */ declare enum ElementType { HEADER, BODY, FOOTER } -type BodyCreator = (() => JQuery | JQuery[] | string) | string | JQuery | JQuery[]; +declare type BodyCreator = (() => JQuery | JQuery[] | string) | string | JQuery | JQuery[]; declare const ModalFunctions; declare class ModalProperties { template?: string; @@ -2502,6 +2674,7 @@ declare class ModalProperties { closeListener: (() => void) | (() => void)[]; registerCloseListener(listener: () => void): this; width: number | string; + min_width?: number | string; height: number | string; closeable: boolean; triggerClose(); @@ -2547,7 +2720,21 @@ declare interface JQuery { modalize(entry_callback?: (header: JQuery, body: JQuery, footer: JQuery) => ModalElements | void, properties?: ModalProperties | any): Modal; } -/* File: shared/js/ui/elements/tab.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/slider.ts */ +declare interface SliderOptions { + min_value?: number; + max_value?: number; + initial_value?: number; + step?: number; + unit?: string; + value_field?: JQuery | JQuery[]; +} +declare interface Slider { + value(value?: number): number; +} +declare function sliderfy(slider: JQuery, options?: SliderOptions): Slider; + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/tab.ts */ declare interface JQuery { asTabWidget(copy?: boolean): JQuery; tabify(copy?: boolean): this; @@ -2555,13 +2742,25 @@ declare interface JQuery { } declare var TabFunctions; -/* File: shared/js/ui/frames/chat_frame.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/elements/tooltip.ts */ +declare function tooltip(entry: JQuery); +declare namespace tooltip { + export type Handle = { + show(); + is_shown(); + hide(); + update(); + }; + export function initialize(entry: JQuery): Handle; +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/chat_frame.ts */ declare namespace chat { export enum InfoFrameMode { - NONE, - CHANNEL_CHAT, - PRIVATE_CHAT, - CLIENT_INFO + NONE = "none", + CHANNEL_CHAT = "channel_chat", + PRIVATE_CHAT = "private_chat", + CLIENT_INFO = "client_info" } export class InfoFrame { private readonly handle: Frame; @@ -2569,8 +2768,10 @@ declare namespace chat { private _mode: InfoFrameMode; private _value_ping: JQuery; private _ping_updater: number; + private _button_conversation: HTMLElement; constructor(handle: Frame); html_tag(): JQuery; + destroy(); private _build_html_tag(); update_ping(); update_channel_talk(); @@ -2586,22 +2787,57 @@ declare namespace chat { private __callback_text_changed; private __callback_key_down; private __callback_paste; + private _typing_timeout: number; + private _typing_last_event: number; + typing_interval: number; + callback_typing: () => any; callback_text: (text: string) => any; constructor(); html_tag(): JQuery; + destroy(); private _initialize_listener(); private _build_html_tag(); - private _callback_text_changed(event); + private _callback_text_changed(event: Event); private _text(element: HTMLElement); private htmlEscape(message: string): string; private _callback_paste(event: ClipboardEvent); + private test_message(message: string): boolean; private _callback_key_down(event: KeyboardEvent); set_enabled(flag: boolean); is_enabled(); focus_input(); } export namespace helpers { - export function process_urls(message: string): Promise; + namespace md2bbc { + export type RemarkToken = { + type: string; + tight: boolean; + lines: number[]; + level: number; + /* img */ + alt?: string; + src?: string; + /* link */ + href?: string; + /* table */ + align?: string; + /* code */ + params?: string; + content?: string; + hLevel?: number; + children?: RemarkToken[]; + }; + export class Renderer { + private static renderers; + private _options; + render(tokens: RemarkToken[], options: any, env: any); + private render_token(token: RemarkToken, index: number); + private render_inline(tokens: RemarkToken[], index: number); + options(): any; + maybe_escape_bb(text: string); + } + } + export function preprocess_chat_message(message: string): string; export namespace history { export function load_history(key: string): Promise; export function save_history(key: string, value: any): Promise; @@ -2625,38 +2861,43 @@ declare namespace chat { }; export function format_chat_time(date: Date): { result: string; - next_update: number; + next_update: number; /* in MS */ }; } export namespace time { export function format_online_time(secs: number): string; } } - type PrivateConversationViewEntry = { + export type PrivateConversationViewEntry = { html_tag: JQuery; }; - type PrivateConversationMessageData = { + export type PrivateConversationMessageData = { message_id: string; message: string; - sender: | ; + sender: "self" | "partner"; sender_name: string; sender_unique_id: string; sender_client_id: number; timestamp: number; }; - type PrivateConversationViewMessage = PrivateConversationMessageData & PrivateConversationViewEntry & { + export type PrivateConversationViewMessage = PrivateConversationMessageData & PrivateConversationViewEntry & { time_update_id: number; }; - type PrivateConversationViewSpacer = PrivateConversationViewEntry; + export type PrivateConversationViewSpacer = PrivateConversationViewEntry; export enum PrivateConversationState { OPEN, CLOSED, DISCONNECTED } - type DisplayedMessage = { + export type DisplayedMessage = { timestamp: number; message: PrivateConversationViewMessage | PrivateConversationViewEntry; - message_type: | ; + message_type: "spacer" | "message"; + /* structure as following + 1. time pointer + 2. unread + 3. message + */ tag_message: JQuery; tag_unread: PrivateConversationViewSpacer | undefined; tag_timepointer: PrivateConversationViewSpacer | undefined; @@ -2668,6 +2909,9 @@ declare namespace chat { private _callback_message: (text: string) => any; private _state: PrivateConversationState; private _last_message_updater_id: number; + private _last_typing: number; + private _typing_timeout: number; + private _typing_timeout_task: number; _scroll_position: number | undefined; _html_message_container: JQuery; client_unique_id: string; @@ -2681,10 +2925,11 @@ declare namespace chat { private load_history(); private save_history(); entry_tag(): JQuery; + destroy(); private _2d_flat(array: T[][]): T[]; messages_tags(): JQuery[]; append_message(message: string, sender: { - type: | ; + type: "self" | "partner"; name: string; unique_id: string; client_id: number; @@ -2696,21 +2941,25 @@ declare namespace chat { private _update_message_timestamp(); private _destroy_message(message: PrivateConversationViewMessage); private _build_message(message: PrivateConversationMessageData): PrivateConversationViewMessage; - private _build_spacer(message: string, type: | | | | | ): PrivateConversationViewSpacer; + private _build_spacer(message: string, type: "date" | "new" | "disconnect" | "reconnect" | "closed" | "error"): PrivateConversationViewSpacer; private _register_displayed_message(message: DisplayedMessage); - private _destory_view_entry(entry: PrivateConversationViewEntry); + private _destroy_view_entry(entry: PrivateConversationViewEntry); private _build_entry_tag(); + update_avatar(); close_conversation(); set_client_name(name: string); set_unread_flag(flag: boolean, update_chat_counter?: boolean); is_unread(): boolean; - private _append_state_change(state: | | ); + private _append_state_change(state: "disconnect" | "reconnect" | "closed"); state(): PrivateConversationState; set_state(state: PrivateConversationState); set_text_callback(callback: (text: string) => any, update_enabled_state?: boolean); chat_enabled(); append_error(message: string, date?: number); call_message(message: string); + private typing_expired(); + trigger_typing(); + typing_active(); } export class PrivateConverations { readonly handle: Frame; @@ -2719,12 +2968,16 @@ declare namespace chat { private _container_conversation: JQuery; private _container_conversation_messages: JQuery; private _container_conversation_list: JQuery; + private _container_typing: JQuery; private _html_no_chats: JQuery; private _conversations: PrivateConveration[]; private _current_conversation: PrivateConveration; private _select_read_timer: number; constructor(handle: Frame); + clear_client_ids(); html_tag(): JQuery; + destroy(); + current_conversation(): PrivateConveration | undefined; conversations(): PrivateConveration[]; create_conversation(client_uid: string, client_name: string, client_id: number): PrivateConveration; delete_conversation(conv: PrivateConveration, update_chat_couner?: boolean); @@ -2739,8 +2992,10 @@ declare namespace chat { clear_conversations(); set_selected_conversation(conv: PrivateConveration | undefined); update_chatbox_state(); + update_typing_state(); private _build_html_tag(); try_input_focus(); + on_show(); } export namespace channel { export type ViewEntry = { @@ -2758,10 +3013,12 @@ declare namespace chat { export class Conversation { readonly handle: ConversationManager; readonly channel_id: number; + private _flag_private: boolean; private _html_tag: JQuery; private _container_messages: JQuery; private _container_new_message: JQuery; private _container_no_permissions: JQuery; + private _container_is_private: JQuery; private _view_max_messages; private _view_older_messages: ViewEntry; private _has_older_messages: boolean; @@ -2775,18 +3032,24 @@ declare namespace chat { html_tag(): JQuery; destroy(); private _build_html_tag(); + is_unread(); mark_read(); private _mark_read(); private _generate_view_message(data: MessageData): Message; - private _generate_view_spacer(message: string, type: | | | ): ViewEntry; + private _generate_view_spacer(message: string, type: "date" | "new" | "old" | "error"): ViewEntry; last_messages_timestamp(): number; fetch_last_messages(); fetch_older_messages(); - register_new_message(message: MessageData); + register_new_message(message: MessageData, update_view?: boolean); fix_scroll(animate: boolean); fix_view_size(); chat_available(): boolean; text_send_failed(error: CommandResult | any); + set_flag_private(flag: boolean); + update_private_state(); + delete_message(message: MessageData); + delete_messages(begin: number, end: number, sender: number, limit: number); + private _delete_message(message: Message); } export class ConversationManager { readonly handle: Frame; @@ -2795,16 +3058,19 @@ declare namespace chat { private _container_conversation: JQuery; private _conversations: Conversation[]; private _current_conversation: Conversation | undefined; + private _needed_listener; constructor(handle: Frame); initialize_needed_listener(); html_tag(): JQuery; + destroy(); update_chat_box(); private _build_html_tag(); set_current_channel(channel_id: number, update_info_frame?: boolean); current_channel(): number; + /* Used by notifychanneldeleted */ delete_conversation(channel_id: number); reset(); - conversation(channel_id: number): Conversation; + conversation(channel_id: number, create?: boolean): Conversation; on_show(); } } @@ -2816,6 +3082,7 @@ declare namespace chat { previous_frame_content: FrameContent; constructor(handle: Frame); html_tag(): JQuery; + destroy(); private _build_html_tag(); current_client(): ClientEntry; set_current_client(client: ClientEntry | undefined, enforce?: boolean); @@ -2839,6 +3106,7 @@ declare namespace chat { constructor(handle: ConnectionHandler); html_tag(): JQuery; info_frame(): InfoFrame; + destroy(); private _build_html_tag(); private_conversations(): PrivateConverations; channel_conversations(): channel.ConversationManager; @@ -2851,90 +3119,47 @@ declare namespace chat { } } -/* File: shared/js/ui/frames/chat.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/chat.ts */ declare enum ChatType { GENERAL, SERVER, CHANNEL, CLIENT } +declare const xbbcode: any; declare namespace MessageHelper { export function htmlEscape(message: string): string[]; export function formatElement(object: any, escape_html?: boolean): JQuery[]; export function formatMessage(pattern: string, ...objects: any[]): JQuery[]; export function bbcode_chat(message: string): JQuery[]; -} -declare class ChatMessage { - date: Date; - message: JQuery[]; - private _html_tag: JQuery; - constructor(message: JQuery[]); - private num(num: number): string; - // @ts-ignore - get html_tag(); -} -declare class ChatEntry { - readonly handle: ChatBox; - type: ChatType; - key: string; - history: ChatMessage[]; - send_history: string[]; - owner_unique_id?: string; - private _name: string; - private _html_tag: any; - private _flag_closeable: boolean; - private _flag_unread: boolean; - private _flag_offline: boolean; - onMessageSend: (text: string) => void; - onClose: () => boolean; - constructor(handle, type: ChatType, key); - appendError(message: string, ...args); - appendMessage(message: string, fmt?: boolean, ...args); - private pushChatMessage(entry: ChatMessage); - displayHistory(); - // @ts-ignore - get html_tag(); - focus(); - // @ts-ignore - set name(newName: string); - // @ts-ignore - set flag_closeable(flag: boolean); - // @ts-ignore - set flag_unread(flag: boolean); - // @ts-ignore - get flag_offline(); - // @ts-ignore - set flag_offline(flag: boolean); - private chat_icon(): string; -} -declare class ChatBox { - static readonly URL_REGEX; - readonly connection_handler: ConnectionHandler; - htmlTag: JQuery; - chats: ChatEntry[]; - private _activeChat: ChatEntry; - private _history_index: number; - private _button_send: JQuery; - private _input_message: JQuery; - constructor(connection_handler: ConnectionHandler); - initialize(); - createChat(key, type?: ChatType): ChatEntry; - open_chats(): ChatEntry[]; - findChat(key: string): ChatEntry; - deleteChat(chat: ChatEntry); - onSend(); - // @ts-ignore - set activeChat(chat: ChatEntry); - private activeChat0(chat: ChatEntry); - // @ts-ignore - get activeChat(): ChatEntry; - channelChat(): ChatEntry; - serverChat(); - focus(); - private testMessage(message: string): boolean; + export namespace network { + export const KB; + export const MB; + export const GB; + export const TB; + export function format_bytes(value: number, options?: { + time?: string; + unit?: string; + exact?: boolean; + }): string; + } + export const K; + export const M; + export const G; + export const T; + export function format_number(value: number, options?: { + time?: string; + unit?: string; + }); + export const TIME_SECOND; + export const TIME_MINUTE; + export const TIME_HOUR; + export const TIME_DAY; + export const TIME_WEEK; + export function format_time(time: number, default_value: string); } -/* File: shared/js/ui/frames/connection_handlers.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/connection_handlers.ts */ declare let server_connections: ServerConnectionManager; declare class ServerConnectionManager { private connection_handlers: ConnectionHandler[]; @@ -2942,7 +3167,6 @@ declare class ServerConnectionManager { private _container_log_server: JQuery; private _container_channel_tree: JQuery; private _container_hostbanner: JQuery; - private _container_select_info: JQuery; private _container_chat: JQuery; private _tag: JQuery; private _tag_connection_entries: JQuery; @@ -2962,11 +3186,11 @@ declare class ServerConnectionManager { private _update_scroll_buttons(); } -/* File: shared/js/ui/frames/ControlBar.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/ControlBar.ts */ declare let control_bar: ControlBar; -type MicrophoneState = "disabled" | "muted" | "enabled"; -type HeadphoneState = "muted" | "enabled"; -type AwayState = "away-global" | "away" | "online"; +declare type MicrophoneState = "disabled" | "muted" | "enabled"; +declare type HeadphoneState = "muted" | "enabled"; +declare type AwayState = "away-global" | "away" | "online"; declare class ControlBar { private _button_away_active: AwayState; private _button_microphone: MicrophoneState; @@ -2995,6 +3219,7 @@ declare class ControlBar { set button_subscribe_all(state: boolean); // @ts-ignore set button_query_visible(state: boolean); + /* UI listener */ private on_away_toggle(); private on_away_enable(); private on_away_disable(); @@ -3024,17 +3249,20 @@ declare class ControlBar { private on_open_playlist_manage(); } -/* File: shared/js/ui/frames/hostbanner.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/hostbanner.ts */ declare class Hostbanner { readonly html_tag: JQuery; readonly client: ConnectionHandler; + private _destryed; private updater: NodeJS.Timer; constructor(client: ConnectionHandler); + destroy(); update(); + public static generate_tag(banner_url: string | undefined, gfx_interval: number, mode: number): Promise; private generate_tag?(): Promise; } -/* File: shared/js/ui/frames/MenuBar.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/MenuBar.ts */ declare namespace top_menu { export interface HRItem { } @@ -3080,7 +3308,7 @@ declare namespace top_menu { private _items: (MenuItem | HRItem)[]; private _label: string; private _callback_click: () => any; - constructor(label: string, mode: | ); + constructor(label: string, mode: "side" | "down"); append_item(label: string): top_menu.MenuItem; append_hr(): HRItem; delete_item(item: top_menu.MenuItem | top_menu.HRItem); @@ -3112,112 +3340,41 @@ declare namespace top_menu { export function initialize(); } -/* File: shared/js/ui/frames/SelectedItemInfo.ts */ -declare abstract class InfoManagerBase { - private timers: NodeJS.Timer[]; - private intervals: number[]; - protected resetTimers(); - protected resetIntervals(); - protected registerTimer(timer: NodeJS.Timer); - protected registerInterval(interval: T); - abstract available(object: V): boolean; -} -declare abstract class InfoManager extends InfoManagerBase { - protected handle?: InfoBar; - createFrame<_>(handle: InfoBar<_>, object: T, html_tag: JQuery); - abstract updateFrame(object: T, html_tag: JQuery); - finalizeFrame(object: T, frame: JQuery); - protected triggerUpdate(); -} -declare class InfoBar { - readonly handle: ConnectionHandler; - private current_selected?: AvailableTypes; - private _tag: JQuery; - private readonly _tag_info: JQuery; - private readonly _tag_banner: JQuery; - private _current_manager: InfoManagerBase; - private managers: InfoManagerBase[]; - constructor(client: ConnectionHandler); - get_tag(): JQuery; - handle_resize(); - setCurrentSelected(entry: AvailableTypes); - // @ts-ignore - get currentSelected(); - update(); - current_manager(); - is_popover(): boolean; - open_popover(); - close_popover(); - rendered_tag(); -} -declare interface Window { - Image: typeof HTMLImageElement; - HTMLImageElement: typeof HTMLImageElement; -} -declare class ClientInfoManager extends InfoManager { - available(object: V): boolean; - createFrame<_>(handle: InfoBar<_>, client: ClientEntry, html_tag: JQuery); - updateFrame(client: ClientEntry, html_tag: JQuery); - buildProperties(client: ClientEntry): any; -} -declare class ServerInfoManager extends InfoManager { - createFrame<_>(handle: InfoBar<_>, server: ServerEntry, html_tag: JQuery); - updateFrame(server: ServerEntry, html_tag: JQuery); - available(object: V): boolean; -} -declare class ChannelInfoManager extends InfoManager { - createFrame<_>(handle: InfoBar<_>, channel: ChannelEntry, html_tag: JQuery); - updateFrame(channel: ChannelEntry, html_tag: JQuery); - available(object: V): boolean; -} -declare function format_time(time: number); -declare enum MusicPlayerState { - SLEEPING, - LOADING, - PLAYING, - PAUSED, - STOPPED -} -declare class MusicInfoManager extends ClientInfoManager { - single_handler: connection.SingleCommandHandler; - createFrame<_>(handle: InfoBar<_>, channel: MusicClientEntry, html_tag: JQuery); - updateFrame(bot: MusicClientEntry, html_tag: JQuery); - update_local_volume(volume: number); - update_remote_volume(volume: number); - available(object: V): boolean; - finalizeFrame(object: ClientEntry, frame: JQuery); -} - -/* File: shared/js/ui/frames/server_log.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/frames/server_log.ts */ declare namespace log { export namespace server { export enum Type { - CONNECTION_BEGIN, - CONNECTION_HOSTNAME_RESOLVE, - CONNECTION_HOSTNAME_RESOLVE_ERROR, - CONNECTION_HOSTNAME_RESOLVED, - CONNECTION_LOGIN, - CONNECTION_CONNECTED, - CONNECTION_FAILED, - CONNECTION_VOICE_SETUP_FAILED, - GLOBAL_MESSAGE, - SERVER_WELCOME_MESSAGE, - SERVER_HOST_MESSAGE, - CLIENT_VIEW_ENTER, - CLIENT_VIEW_LEAVE, - CLIENT_VIEW_MOVE, - CLIENT_NICKNAME_CHANGED, - CLIENT_NICKNAME_CHANGE_FAILED, - CLIENT_SERVER_GROUP_ADD, - CLIENT_SERVER_GROUP_REMOVE, - CLIENT_CHANNEL_GROUP_CHANGE, - CHANNEL_CREATE, - CHANNEL_DELETE, - ERROR_CUSTOM, - ERROR_PERMISSION, - RECONNECT_SCHEDULED, - RECONNECT_EXECUTE, - RECONNECT_CANCELED + CONNECTION_BEGIN = "connection_begin", + CONNECTION_HOSTNAME_RESOLVE = "connection_hostname_resolve", + CONNECTION_HOSTNAME_RESOLVE_ERROR = "connection_hostname_resolve_error", + CONNECTION_HOSTNAME_RESOLVED = "connection_hostname_resolved", + CONNECTION_LOGIN = "connection_login", + CONNECTION_CONNECTED = "connection_connected", + CONNECTION_FAILED = "connection_failed", + CONNECTION_VOICE_SETUP_FAILED = "connection_voice_setup_failed", + CONNECTION_COMMAND_ERROR = "connection_command_error", + GLOBAL_MESSAGE = "global_message", + SERVER_WELCOME_MESSAGE = "server_welcome_message", + SERVER_HOST_MESSAGE = "server_host_message", + SERVER_HOST_MESSAGE_DISCONNECT = "server_host_message_disconnect", + SERVER_CLOSED = "server_closed", + SERVER_BANNED = "server_banned", + SERVER_REQUIRES_PASSWORD = "server_requires_password", + CLIENT_VIEW_ENTER = "client_view_enter", + CLIENT_VIEW_LEAVE = "client_view_leave", + CLIENT_VIEW_MOVE = "client_view_move", + CLIENT_NICKNAME_CHANGED = "client_nickname_changed", + CLIENT_NICKNAME_CHANGE_FAILED = "client_nickname_change_failed", + CLIENT_SERVER_GROUP_ADD = "client_server_group_add", + CLIENT_SERVER_GROUP_REMOVE = "client_server_group_remove", + CLIENT_CHANNEL_GROUP_CHANGE = "client_channel_group_change", + CHANNEL_CREATE = "channel_create", + CHANNEL_DELETE = "channel_delete", + ERROR_CUSTOM = "error_custom", + ERROR_PERMISSION = "error_permission", + RECONNECT_SCHEDULED = "reconnect_scheduled", + RECONNECT_EXECUTE = "reconnect_execute", + RECONNECT_CANCELED = "reconnect_canceled" } export namespace base { export type Client = { @@ -3261,6 +3418,12 @@ declare namespace log { export type WelcomeMessage = { message: string; }; + export type HostMessageDisconnect = { + message: string; + }; + //tr("You was moved by {3} from channel {1} to {2}") : tr("{0} was moved from channel {1} to {2} by {3}") + //tr("You switched from channel {1} to {2}") : tr("{0} switched from channel {1} to {2}") + //tr("You got kicked out of the channel {1} to channel {2} by {3}{4}") : tr("{0} got kicked from channel {1} to {2} by {3}{4}") export type ClientMove = { channel_from?: base.Channel; channel_from_own: boolean; @@ -3316,7 +3479,10 @@ declare namespace log { }; export type ConnectionVoiceSetupFailed = { reason: string; - reconnect_delay: number; + reconnect_delay: number; /* if less or equal to 0 reconnect is prohibited */ + }; + export type ConnectionCommandError = { + error: any; }; export type ClientNicknameChanged = { own_client: boolean; @@ -3327,6 +3493,15 @@ declare namespace log { export type ClientNicknameChangeFailed = { reason: string; }; + export type ServerClosed = { + message: string; + }; + export type ServerRequiresPassword = {}; + export type ServerBanned = { + message: string; + time: number; + invoker: base.Client; + }; } export type LogMessage = { type: Type; @@ -3334,32 +3509,37 @@ declare namespace log { data: any; }; export interface TypeInfo { - : event.ConnectBegin; - : event.GlobalMessage; - : event.ErrorCustom; - : event.ErrorPermission; - : event.ConnectionHostnameResolved; - : event.ConnectionHostnameResolve; - : event.ConnectionHostnameResolveError; - : event.ConnectionFailed; - : event.ConnectionLogin; - : event.ConnectionConnected; - : event.ConnectionVoiceSetupFailed; - : event.ReconnectScheduled; - : event.ReconnectCanceled; - : event.ReconnectExecute; - : event.WelcomeMessage; - : event.WelcomeMessage; - : event.ClientEnter; - : event.ClientMove; - : event.ClientLeave; - : event.ClientNicknameChangeFailed; - : event.ClientNicknameChanged; - : event.ChannelCreate; - : event.ChannelDelete; + "connection_begin": event.ConnectBegin; + "global_message": event.GlobalMessage; + "error_custom": event.ErrorCustom; + "error_permission": event.ErrorPermission; + "connection_hostname_resolved": event.ConnectionHostnameResolved; + "connection_hostname_resolve": event.ConnectionHostnameResolve; + "connection_hostname_resolve_error": event.ConnectionHostnameResolveError; + "connection_failed": event.ConnectionFailed; + "connection_login": event.ConnectionLogin; + "connection_connected": event.ConnectionConnected; + "connection_voice_setup_failed": event.ConnectionVoiceSetupFailed; + "connection_command_error": event.ConnectionCommandError; + "reconnect_scheduled": event.ReconnectScheduled; + "reconnect_canceled": event.ReconnectCanceled; + "reconnect_execute": event.ReconnectExecute; + "server_welcome_message": event.WelcomeMessage; + "server_host_message": event.WelcomeMessage; + "server_host_message_disconnect": event.HostMessageDisconnect; + "server_closed": event.ServerClosed; + "server_requires_password": event.ServerRequiresPassword; + "server_banned": event.ServerBanned; + "client_view_enter": event.ClientEnter; + "client_view_move": event.ClientMove; + "client_view_leave": event.ClientLeave; + "client_nickname_change_failed": event.ClientNicknameChangeFailed; + "client_nickname_changed": event.ClientNicknameChanged; + "channel_create": event.ChannelCreate; + "channel_delete": event.ChannelDelete; } - type MessageBuilderOptions = {}; - type MessageBuilder = (data: TypeInfo[T], options: MessageBuilderOptions) => JQuery[] | undefined; + export type MessageBuilderOptions = {}; + export type MessageBuilder = (data: TypeInfo[T], options: MessageBuilderOptions) => JQuery[] | undefined; export const MessageBuilders: { [key: string]: MessageBuilder; }; @@ -3375,6 +3555,7 @@ declare namespace log { constructor(handle: ConnectionHandler); log(type: T, data: server.TypeInfo[T]); html_tag(): JQuery; + destroy(); private append_log(message: server.LogMessage); } } @@ -3384,7 +3565,7 @@ declare namespace log { } } -/* File: shared/js/ui/htmltags.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/htmltags.ts */ declare namespace htmltags { export interface ClientProperties { client_id: number; @@ -3409,23 +3590,24 @@ declare namespace htmltags { namespace bbcodes { } } -/* File: shared/js/ui/modal/ModalAbout.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalAbout.ts */ declare namespace Modals { export function spawnAbout(); } -/* File: shared/js/ui/modal/ModalAvatar.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalAvatar.ts */ declare namespace Modals { + //TODO: Test if we could render this image and not only the browser by knowing the type. export function spawnAvatarUpload(callback_data: (data: ArrayBuffer | undefined | null) => any); } -/* File: shared/js/ui/modal/ModalAvatarList.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalAvatarList.ts */ declare namespace Modals { export const human_file_size; export function spawnAvatarList(client: ConnectionHandler); } -/* File: shared/js/ui/modal/ModalBanClient.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanClient.ts */ declare namespace Modals { export function spawnBanClient(name: string | string[], callback: (data: { length: number; @@ -3436,12 +3618,12 @@ declare namespace Modals { }) => void); } -/* File: shared/js/ui/modal/ModalBanCreate.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanCreate.ts */ declare namespace Modals { export function spawnBanCreate(connection: ConnectionHandler, base?: BanEntry, callback?: (entry?: BanEntry) => any); } -/* File: shared/js/ui/modal/ModalBanList.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBanList.ts */ declare namespace Modals { export interface BanEntry { server_id: number; @@ -3469,21 +3651,28 @@ declare namespace Modals { export function spawnBanListModal(callback_update: () => any, callback_add: () => any, callback_edit: (entry: BanEntry) => any, callback_delete: (entry: BanEntry) => any): BanListManager; } -/* File: shared/js/ui/modal/ModalBookmarks.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBookmarks.ts */ declare namespace Modals { export function spawnBookmarkModal(); } -/* File: shared/js/ui/modal/ModalBotMenue.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalBotMenue.ts */ -/* File: shared/js/ui/modal/ModalChangeVolume.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalChangeVolume.ts */ declare namespace Modals { export function spawnChangeVolume(current: number, callback: (number) => void); + /* Units are between 0 and 1 */ export function spawnChangeRemoteVolume(current: number, max_value: number, callback: (value: number) => void); } -/* File: shared/js/ui/modal/ModalConnect.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalClientInfo.ts */ +declare namespace Modals { + export function openClientInfo(client: ClientEntry); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalConnect.ts */ declare namespace connection_log { + //TODO: Save password data export type ConnectionData = { name: string; icon_id: number; @@ -3522,7 +3711,7 @@ declare namespace connection_log { } declare namespace Modals { export function spawnConnectModal(options: { - default_connect_new_tab?: boolean; + default_connect_new_tab?: boolean; /* default false */ }, defaultHost?: { url: string; enforce: boolean; @@ -3533,46 +3722,51 @@ declare namespace Modals { export const Regex; } -/* File: shared/js/ui/modal/ModalCreateChannel.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalCreateChannel.ts */ declare namespace Modals { export function createChannelModal(connection: ConnectionHandler, channel: ChannelEntry | undefined, parent: ChannelEntry | undefined, permissions: PermissionManager, callback: (properties?: ChannelProperties, permissions?: PermissionValue[]) => any); } -/* File: shared/js/ui/modal/ModalGroupAssignment.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalGroupAssignment.ts */ declare namespace Modals { export function createServerGroupAssignmentModal(client: ClientEntry, callback: (group: Group, flag: boolean) => Promise); } -/* File: shared/js/ui/modal/ModalIconSelect.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalIconSelect.ts */ declare namespace Modals { export function spawnIconSelect(client: ConnectionHandler, callback_icon?: (id: number) => any, selected_icon?: number); export function spawnIconUpload(client: ConnectionHandler); } -/* File: shared/js/ui/modal/ModalIdentity.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalIdentity.ts */ declare namespace Modals { - export function spawnTeamSpeakIdentityImprove(identity: profiles.identities.TeaSpeakIdentity): Modal; + export function spawnTeamSpeakIdentityImprove(identity: profiles.identities.TeaSpeakIdentity, name: string): Modal; export function spawnTeamSpeakIdentityImport(callback: (identity: profiles.identities.TeaSpeakIdentity) => any): Modal; } -/* File: shared/js/ui/modal/ModalInvite.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalInvite.ts */ declare namespace Modals { export function spawnInviteEditor(connection: ConnectionHandler); } -/* File: shared/js/ui/modal/ModalPlaylistEdit.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalKeySelect.ts */ +declare namespace Modals { + export function spawnKeySelect(callback: (key?: ppt.KeyEvent) => void); +} + +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistEdit.ts */ declare namespace Modals { export function spawnPlaylistSongInfo(song: PlaylistSong); export function spawnSongAdd(playlist: Playlist, callback_add: (url: string, loader: string) => any); export function spawnPlaylistEdit(client: ConnectionHandler, playlist: Playlist); } -/* File: shared/js/ui/modal/ModalPlaylistList.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPlaylistList.ts */ declare namespace Modals { export function spawnPlaylistManage(client: ConnectionHandler); } -/* File: shared/js/ui/modal/ModalPoke.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPoke.ts */ declare namespace Modals { export class PokeModal { private _handle: Modal; @@ -3582,7 +3776,7 @@ declare namespace Modals { add_poke(source: ConnectionHandler, invoker: PokeInvoker, message: string); private _handle_close(); } - type PokeInvoker = { + export type PokeInvoker = { name: string; id: number; unique_id: string; @@ -3590,7 +3784,7 @@ declare namespace Modals { export function spawnPoke(source: ConnectionHandler, invoker: PokeInvoker, message: string); } -/* File: shared/js/ui/modal/ModalQuery.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQuery.ts */ declare namespace Modals { export function spawnQueryCreate(connection: ConnectionHandler, callback_created?: (user, pass) => any); export function spawnQueryCreated(credentials: { @@ -3599,27 +3793,27 @@ declare namespace Modals { }, just_created: boolean); } -/* File: shared/js/ui/modal/ModalQueryManage.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalQueryManage.ts */ declare namespace Modals { export function spawnQueryManage(client: ConnectionHandler); } -/* File: shared/js/ui/modal/ModalServerEdit.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerEdit.ts */ declare namespace Modals { - export function createServerModal(server: ServerEntry, callback: (properties?: ServerProperties) => any); + export function createServerModal(server: ServerEntry, callback: (properties?: ServerProperties) => Promise); } -/* File: shared/js/ui/modal/ModalSettings.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalServerInfo.ts */ declare namespace Modals { - export function spawnSettingsModal(default_page?: string); + export function openServerInfo(server: ServerEntry); } -/* File: shared/js/ui/modal/ModalSettingsOld.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalSettings.ts */ declare namespace Modals { - export function spawnSettingsModal_old(): Modal; + export function spawnSettingsModal(default_page?: string): Modal; } -/* File: shared/js/ui/modal/ModalYesNo.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/ModalYesNo.ts */ declare namespace Modals { export function spawnYesNo(header: BodyCreator, body: BodyCreator, callback: (_: boolean) => any, properties?: { text_yes?: string; @@ -3627,7 +3821,7 @@ declare namespace Modals { }); } -/* File: shared/js/ui/modal/permission/CanvasPermissionEditor.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/permission/CanvasPermissionEditor.ts */ declare namespace pe { namespace ui { export namespace scheme { @@ -3691,8 +3885,17 @@ declare namespace pe { export interface InteractionListener { region: AxisAlignedBoundingBox; region_weight: number; + /** + * @return true if a redraw is required + */ on_mouse_enter?: () => RepaintMode; + /** + * @return true if a redraw is required + */ on_mouse_leave?: () => RepaintMode; + /** + * @return true if a redraw is required + */ on_click?: (event: InteractionClickEvent) => RepaintMode; mouse_cursor?: string; set_full_draw?: () => any; @@ -3757,6 +3960,8 @@ declare namespace pe { public static readonly COLUMN_PADDING; public static readonly COLUMN_VALUE; public static readonly COLUMN_GRANTED; + //public static readonly COLUMN_NEGATE = 25; + //public static readonly COLUMN_SKIP = 25; public static readonly COLUMN_NEGATE; public static readonly COLUMN_SKIP; private _permission: PermissionInfo; @@ -3850,6 +4055,7 @@ declare namespace pe { private mode_container_permissions: JQuery; private mode_container_error_permission: JQuery; private mode_container_unset: JQuery; + /* references within the container tag */ private permission_value_map: { [key: number]: PermissionValue; }; @@ -3863,10 +4069,11 @@ declare namespace pe { set_permissions(permissions?: PermissionValue[]); set_mode(mode: Modals.PermissionEditorMode); update_ui(); + set_toggle_button(callback: () => string, initial: string); } } -/* File: shared/js/ui/modal/permission/HTMLPermissionEditor.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/permission/HTMLPermissionEditor.ts */ declare namespace pe { export class HTMLPermission { readonly handle: HTMLPermissionEditor; @@ -3880,6 +4087,7 @@ declare namespace pe { tag_container_skip: JQuery; tag_container_negate: JQuery; hidden: boolean; + /* the "actual" values */ private _mask; private _tag_value: JQuery; private _tag_value_input: JQuery; @@ -3951,7 +4159,7 @@ declare namespace pe { private build_tag(); html_tag(): JQuery; set_permissions(u_permissions?: PermissionValue[]); - set_mode(mode: PermissionEditorMode); + set_mode(mode: Modals.PermissionEditorMode); trigger_change(permission: PermissionInfo, value?: Modals.PermissionEditor.PermissionValue): Promise; collapse_all(); expend_all(); @@ -3960,7 +4168,7 @@ declare namespace pe { } } -/* File: shared/js/ui/modal/permission/ModalPermissionEdit.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/modal/permission/ModalPermissionEdit.ts */ declare interface JQuery { dropdown: any; } @@ -4017,17 +4225,17 @@ declare namespace Modals { }; export type OptionsClientChannelPermissions = OptionsClientPermissions & OptionsChannelPermissions; export interface OptionMap { - : OptionsServerGroup; - : OptionsChannelGroup; - : OptionsClientPermissions; - : OptionsChannelPermissions; - : OptionsClientChannelPermissions; + "sg": OptionsServerGroup; + "cg": OptionsChannelGroup; + "clp": OptionsClientPermissions; + "chp": OptionsChannelPermissions; + "clchp": OptionsClientChannelPermissions; } export function _space(); export function spawnPermissionEdit(connection: ConnectionHandler, selected_tab?: T, options?: OptionMap[T]): Modal; } -/* File: shared/js/ui/server.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/server.ts */ declare class ServerProperties { virtualserver_host: string; virtualserver_port: number; @@ -4041,6 +4249,7 @@ declare class ServerProperties { virtualserver_queryclientsonline: number; virtualserver_channelsonline: number; virtualserver_uptime: number; + virtualserver_created: number; virtualserver_maxclients: number; virtualserver_reserved_slots: number; virtualserver_password: string; @@ -4061,6 +4270,7 @@ declare class ServerProperties { virtualserver_default_server_group: number; virtualserver_default_channel_group: number; virtualserver_default_channel_admin_group: number; + //Special requested properties virtualserver_default_client_description: string; virtualserver_default_channel_description: string; virtualserver_default_channel_topic: string; @@ -4074,10 +4284,35 @@ declare class ServerProperties { virtualserver_needed_identity_security_level: number; virtualserver_weblist_enabled: boolean; virtualserver_min_clients_in_channel_before_forced_silence: number; + virtualserver_channel_temp_delete_delay_default: number; + virtualserver_priority_speaker_dimm_modificator: number; virtualserver_max_upload_total_bandwidth: number; virtualserver_upload_quota: number; virtualserver_max_download_total_bandwidth: number; virtualserver_download_quota: number; + virtualserver_month_bytes_downloaded: number; + virtualserver_month_bytes_uploaded: number; + virtualserver_total_bytes_downloaded: number; + virtualserver_total_bytes_uploaded: number; +} +declare interface ServerConnectionInfo { + connection_filetransfer_bandwidth_sent: number; + connection_filetransfer_bandwidth_received: number; + connection_filetransfer_bytes_sent_total: number; + connection_filetransfer_bytes_received_total: number; + connection_filetransfer_bytes_sent_month: number; + connection_filetransfer_bytes_received_month: number; + connection_packets_sent_total: number; + connection_bytes_sent_total: number; + connection_packets_received_total: number; + connection_bytes_received_total: number; + connection_bandwidth_sent_last_second_total: number; + connection_bandwidth_sent_last_minute_total: number; + connection_bandwidth_received_last_second_total: number; + connection_bandwidth_received_last_minute_total: number; + connection_connected_time: number; + connection_packetloss_total: number; + connection_ping: number; } declare interface ServerAddress { host: string; @@ -4090,24 +4325,34 @@ declare class ServerEntry { private info_request_promise: Promise; private info_request_promise_resolve: any; private info_request_promise_reject: any; + private _info_connection_promise: Promise; + private _info_connection_promise_timestamp: number; + private _info_connection_promise_resolve: any; + private _info_connection_promise_reject: any; lastInfoRequest: number; nextInfoRequest: number; private _htmlTag: JQuery; + private _destroyed; constructor(tree, name, address: ServerAddress); // @ts-ignore get htmlTag(); + destroy(); initializeListener(); spawnContextMenu(x: number, y: number, on_close?: () => void); updateVariables(is_self_notify: boolean, ...variables: { key: string; value: string; }[]); + /* this result !must! be cached for at least a second */ updateProperties(): Promise; + /* max 1s ago, so we could update every second */ + request_connection_info(): Promise; + set_connection_info(info: ServerConnectionInfo); shouldUpdateProperties(): boolean; calculateUptime(): number; } -/* File: shared/js/ui/view.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/ui/view.ts */ declare class ChannelTree { client: ConnectionHandler; server: ServerEntry; @@ -4122,9 +4367,12 @@ declare class ChannelTree { private _show_queries: boolean; private channel_last?: ChannelEntry; private channel_first?: ChannelEntry; - private selected_event?: Event; + private _focused; + private _listener_document_click; + private _listener_document_key; constructor(client); tag_tree(): JQuery; + destroy(); hide_channel_tree(); show_channel_tree(); showContextMenu(x: number, y: number, on_close?: () => void); @@ -4138,6 +4386,7 @@ declare class ChannelTree { moveChannel(channel: ChannelEntry, channel_previous: ChannelEntry, parent: ChannelEntry); deleteClient(client: ClientEntry, animate_tag?: boolean); registerClient(client: ClientEntry); + unregisterClient(client: ClientEntry); insertClient(client: ClientEntry, channel: ChannelEntry): ClientEntry; moveClient(client: ClientEntry, channel: ChannelEntry); findClient?(clientId: number): ClientEntry; @@ -4160,7 +4409,7 @@ declare class ChannelTree { subscribe_all_channels(); } -/* File: shared/js/utils/helpers.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/utils/helpers.ts */ declare namespace helpers { export function hashPassword(password: string): Promise; } @@ -4174,12 +4423,23 @@ declare class LaterPromise extends Promise { rejected(reason); function_rejected(); time(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; } declare const copy_to_clipboard; -/* File: shared/js/voice/RecorderBase.ts */ +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/voice/RecorderBase.ts */ declare namespace audio { export namespace recorder { export interface InputDevice { @@ -4235,7 +4495,7 @@ declare namespace audio { } export interface StateFilter extends Filter { set_state(state: boolean): Promise; - is_active(): boolean; + is_active(): boolean; /* if true the the filter allows data to pass */ } } export enum InputState { @@ -4244,11 +4504,18 @@ declare namespace audio { RECORDING, DRY } + export enum InputStartResult { + EOK = "eok", + EUNKNOWN = "eunknown", + EBUSY = "ebusy", + ENOTALLOWED = "enotallowed", + ENOTSUPPORTED = "enotsupported" + } export interface AbstractInput { callback_begin: () => any; callback_end: () => any; current_state(): InputState; - start(): Promise; + start(): Promise; stop(): Promise; current_device(): InputDevice | undefined; set_device(device: InputDevice | undefined): Promise; @@ -4259,6 +4526,8 @@ declare namespace audio { clear_filter(); disable_filter(type: filter.Type); enable_filter(type: filter.Type); + get_volume(): number; + set_volume(volume: number); } export interface LevelMeter { device(): InputDevice; @@ -4268,11 +4537,13 @@ declare namespace audio { } } -/* File: shared/js/voice/RecorderProfile.ts */ -type VadType = "threshold" | "push_to_talk" | "active"; +/* File: /home/wolverindev/TeaSpeak/Web-Client/shared/js/voice/RecorderProfile.ts */ +declare type VadType = "threshold" | "push_to_talk" | "active"; declare interface RecorderProfileConfig { version: number; + /* devices unique id */ device_id: string | undefined; + volume: number; vad_type: VadType; vad_threshold: { threshold: number; @@ -4286,7 +4557,7 @@ declare interface RecorderProfileConfig { key_alt: boolean; }; } -declare let default_recorder: RecorderProfile; +declare let default_recorder: RecorderProfile /* needs initialize */; declare class RecorderProfile { readonly name; readonly volatile; @@ -4318,4 +4589,6 @@ declare class RecorderProfile { set_vad_ppt_delay(value: number); current_device(): audio.recorder.InputDevice | undefined; set_device(device: audio.recorder.InputDevice | undefined): Promise; + get_volume(): number; + set_volume(volume: number); } diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index af4ea6f..a3d2733 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -22,7 +22,7 @@ message("Module path: ${CMAKE_MODULE_PATH}") function(setup_nodejs) set(NodeJS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") set(NODEJS_URL "https://atom.io/download/atom-shell") - set(NODEJS_VERSION "v5.0.6") + set(NODEJS_VERSION "v6.0.7") #set(NODEJS_URL "https://nodejs.org/download/release/") #set(NODEJS_VERSION "v12.7.0") diff --git a/native/serverconnection/src/audio/AudioMerger.cpp b/native/serverconnection/src/audio/AudioMerger.cpp index 127e5c8..b1f2e63 100644 --- a/native/serverconnection/src/audio/AudioMerger.cpp +++ b/native/serverconnection/src/audio/AudioMerger.cpp @@ -100,8 +100,10 @@ bool merge::merge_channels_interleaved(void *target, size_t target_channels, con auto source_array = (float*) src; auto target_array = (float*) target; - while(samples-- > 0) - *(target_array++) = merge_ab(*(source_array++), *(source_array++)); + while(samples-- > 0) { + *(target_array++) = merge_ab(*(source_array), *(source_array + 1)); + source_array += 2; + } } else return false; diff --git a/native/serverconnection/src/audio/AudioOutput.cpp b/native/serverconnection/src/audio/AudioOutput.cpp index 9221077..1c405c3 100644 --- a/native/serverconnection/src/audio/AudioOutput.cpp +++ b/native/serverconnection/src/audio/AudioOutput.cpp @@ -18,6 +18,7 @@ void AudioOutputSource::clear() { ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { auto sample_count = samples; + _retest: { lock_guard lock(this->buffer_lock); while(sample_count > 0 && !this->sample_buffers.empty()) { @@ -44,8 +45,11 @@ ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { } if(sample_count > 0) { - if(this->on_underflow) - this->on_underflow(); + if(this->on_underflow) { + if(this->on_underflow()) { + goto _retest; + } + } this->buffering = true; } @@ -68,6 +72,8 @@ ssize_t AudioOutputSource::enqueue_samples(const void *buffer, size_t samples) { } ssize_t AudioOutputSource::enqueue_samples(const std::shared_ptr &buf) { + if(!buf) return 0; + { unique_lock lock(this->buffer_lock); if(this->max_latency > 0 && this->buffered_samples + buf->sample_size > this->max_latency) { diff --git a/native/serverconnection/src/audio/AudioOutput.h b/native/serverconnection/src/audio/AudioOutput.h index beaada1..64b11be 100644 --- a/native/serverconnection/src/audio/AudioOutput.h +++ b/native/serverconnection/src/audio/AudioOutput.h @@ -41,7 +41,8 @@ namespace tc { size_t max_latency = 0; overflow_strategy::value overflow_strategy = overflow_strategy::discard_buffer_half; - std::function on_underflow; + /* if it returns true then the it means that the buffer has been refilled, we have to test again */ + std::function on_underflow; std::function on_overflow; std::function on_read; /* will be invoked after sample read, e.g. for buffer fullup */ diff --git a/native/serverconnection/src/audio/codec/OpusConverter.cpp b/native/serverconnection/src/audio/codec/OpusConverter.cpp index d072aa1..4092d3f 100644 --- a/native/serverconnection/src/audio/codec/OpusConverter.cpp +++ b/native/serverconnection/src/audio/codec/OpusConverter.cpp @@ -117,6 +117,12 @@ bool OpusConverter::_initialize_encoder(std::string &error) { error = "failed to create encoder (" + to_string(error_id) + ")"; return false; } + + error_id = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(64000)); + if(error_id) { + error = "failed to set bitrate (" + to_string(error_id) + ")"; + return false; + } return true; } diff --git a/native/serverconnection/src/audio/js/AudioOutputStream.cpp b/native/serverconnection/src/audio/js/AudioOutputStream.cpp index 5d31b07..90c58ac 100644 --- a/native/serverconnection/src/audio/js/AudioOutputStream.cpp +++ b/native/serverconnection/src/audio/js/AudioOutputStream.cpp @@ -90,7 +90,7 @@ void AudioOutputStreamWrapper::do_wrap(const v8::Local &obj) { }); this->_own_handle->on_overflow = [&](size_t){ this->call_overflow(); }; - this->_own_handle->on_underflow = [&]{ this->call_underflow(); }; + this->_own_handle->on_underflow = [&]{ this->call_underflow(); return false; }; } } diff --git a/native/serverconnection/src/connection/ServerConnection.cpp b/native/serverconnection/src/connection/ServerConnection.cpp index 190b2fc..8c3d464 100644 --- a/native/serverconnection/src/connection/ServerConnection.cpp +++ b/native/serverconnection/src/connection/ServerConnection.cpp @@ -499,6 +499,7 @@ void ServerConnection::send_voice_data(const void *buffer, size_t buffer_length, if(head) /* head packet */ packet->enable_flag(ts::protocol::PacketFlag::Compressed); + packet->enable_flag(ts::protocol::PacketFlag::Unencrypted); //#define FUZZ_VOICE #ifdef FUZZ_VOICE diff --git a/native/serverconnection/src/connection/audio/AudioSender.cpp b/native/serverconnection/src/connection/audio/AudioSender.cpp index 1a4bc92..15c5da1 100644 --- a/native/serverconnection/src/connection/audio/AudioSender.cpp +++ b/native/serverconnection/src/connection/audio/AudioSender.cpp @@ -3,6 +3,7 @@ #include "../ServerConnection.h" #include "../../logger.h" #include "AudioEventLoop.h" +#include "../../audio/AudioMerger.h" using namespace std; using namespace tc; @@ -17,7 +18,7 @@ VoiceSender::~VoiceSender() { this->clear_buffer(); /* buffer might be accessed within encode_raw_frame, but this could not be trigered while this will be deallocated! */ } -bool VoiceSender::initialize_codec(std::string& error, connection::codec::value codec, size_t channels, size_t rate, bool reset_decoder) { +bool VoiceSender::initialize_codec(std::string& error, connection::codec::value codec, size_t channels, size_t rate, bool reset_encoder) { auto& data = this->codec[codec]; bool new_allocated = !data; if(new_allocated) { @@ -33,16 +34,17 @@ bool VoiceSender::initialize_codec(std::string& error, connection::codec::value return false; } - if(!data->converter || data->converter->channels() != channels || data->converter->sample_rate() != rate) { + if(!data->converter) { data->converter = info->new_converter(error); if(!data->converter) return false; - } else if(reset_decoder) { + } else if(reset_encoder) { data->converter->reset_encoder(); } if(!data->resampler || data->resampler->input_rate() != rate) data->resampler = make_shared(rate, data->converter->sample_rate(), data->converter->channels()); + if(!data->resampler->valid()) { error = "resampler is invalid"; return false; @@ -111,10 +113,12 @@ void VoiceSender::event_execute(const std::chrono::system_clock::time_point &poi unique_lock buffer_lock(this->raw_audio_buffer_lock); if(this->raw_audio_buffers.empty()) break; + if(chrono::system_clock::now() - now > max_time) { reschedule = true; break; } + auto entry = move(this->raw_audio_buffers.front()); this->raw_audio_buffers.pop_front(); buffer_lock.unlock(); @@ -168,15 +172,34 @@ void VoiceSender::encode_raw_frame(const std::unique_ptr &frame) { return; } - /* TODO: May test for channel and sample rate? */ - this->ensure_buffer(codec_data->resampler->estimated_output_size(frame->buffer.length())); - auto resampled_samples = codec_data->resampler->process(this->_buffer, frame->buffer.data_ptr(), frame->buffer.length() / frame->channels / 4); + auto merged_channel_byte_size = codec_data->converter->channels() * (frame->buffer.length() / frame->channels); + auto estimated_resampled_byte_size = codec_data->resampler->estimated_output_size(merged_channel_byte_size); + this->ensure_buffer(max(estimated_resampled_byte_size, merged_channel_byte_size)); + + auto codec_channels = codec_data->converter->channels(); + if(!audio::merge::merge_channels_interleaved(this->_buffer, codec_channels, frame->buffer.data_ptr(), frame->channels, frame->buffer.length() / frame->channels / 4)) { + log_warn(category::voice_connection, tr("Failed to merge channels to output stream channel count! Dropping local voice packet")); + return; + } + + auto resampled_samples = codec_data->resampler->process(this->_buffer, this->_buffer, merged_channel_byte_size / codec_channels / 4); if(resampled_samples <= 0) { log_error(category::voice_connection, tr("Resampler returned {}"), resampled_samples); return; } - auto encoded_bytes = codec_data->converter->encode(error, this->_buffer, this->_buffer, this->_buffer_size); + if(resampled_samples * codec_channels * 4 != codec_data->converter->bytes_per_frame()) { + log_error(category::voice_connection, + tr("Could not encode audio frame. Frame length is not equal to code frame length! Codec: {}, Packet: {}"), + codec_data->converter->bytes_per_frame(), resampled_samples * codec_channels * 4 + ); + return; + } + + log_trace(category::voice_connection, tr("Encode buffer size: {}"), this->_buffer_size); + + char _packet_buffer[512]; + auto encoded_bytes = codec_data->converter->encode(error, this->_buffer, _packet_buffer, 512); if(encoded_bytes <= 0) { log_error(category::voice_connection, tr("Failed to encode voice: {}"), error); return; @@ -190,6 +213,6 @@ void VoiceSender::encode_raw_frame(const std::unique_ptr &frame) { } auto server = this->handle->handle(); - server->send_voice_data(this->_buffer, encoded_bytes, codec, flag_head); + server->send_voice_data(_packet_buffer, encoded_bytes, codec, flag_head); } } diff --git a/native/serverconnection/src/connection/audio/VoiceClient.cpp b/native/serverconnection/src/connection/audio/VoiceClient.cpp index 44a5562..2a3ae73 100644 --- a/native/serverconnection/src/connection/audio/VoiceClient.cpp +++ b/native/serverconnection/src/connection/audio/VoiceClient.cpp @@ -226,6 +226,10 @@ VoiceClient::VoiceClient(const std::shared_ptr&, uint16_t clien } } } + + play_premature_packets = true; /* try to replay any premature packets because we assume that the other packets got lost */ + audio::decode_event_loop->schedule(static_pointer_cast(this->ref())); + return false; }; this->output_source->on_overflow = [&](size_t count){ log_warn(category::audio, tr("Client {} has a audio buffer overflow of {}."), this->_client_id, count); @@ -286,7 +290,6 @@ void VoiceClient::process_packet(uint16_t packet_id, const pipes::buffer_view& b this->audio_decode_queue.push_back(move(encoded_buffer)); } - /* ‘tc::event::EventEntry’ is an inaccessible base of ‘tc::connection::VoiceClient’ => So we need a */ audio::decode_event_loop->schedule(static_pointer_cast(this->ref())); } @@ -303,12 +306,42 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch auto now = chrono::system_clock::now(); while(true) { unique_lock buffer_lock(this->audio_decode_queue_lock); + if(this->play_premature_packets) { + this->play_premature_packets = false; + + for(auto& codec_data : this->codec) { + if(!codec_data) continue; + + if(!codec_data->premature_packets.empty()) { + size_t play_count = 0; + while(!codec_data->premature_packets.empty()) { + auto& packet = codec_data->premature_packets.front(); + + //Test if we're able to replay stuff again + if((uint16_t) (codec_data->last_packet_id + 1) < packet.packet_id && play_count > 0) //Only check for the order if we replayed one already + break; //Nothing new + + this->output_source->enqueue_samples(packet.buffer); + codec_data->last_packet_id = packet.packet_id; + codec_data->premature_packets.pop_front(); + play_count++; + } + + if(play_count > 0) + log_debug(category::audio, tr("Replayed {} premature packets for client {}"), play_count, this->_client_id); + break; + } + } + } + if(this->audio_decode_queue.empty()) break; + if(chrono::system_clock::now() - now > max_time) { reschedule = true; break; } + auto entry = move(this->audio_decode_queue.front()); this->audio_decode_queue.pop_front(); buffer_lock.unlock(); @@ -323,6 +356,7 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch } } +//FIXME premature packets dont work #define MAX_LOST_PACKETS (6) void VoiceClient::process_encoded_buffer(const std::unique_ptr &buffer) { string error; @@ -362,26 +396,39 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr &b } uint16_t diff; - if(codec_data->last_packet_id > buffer->packet_id) { - auto local_index = (uint16_t) (codec_data->last_packet_id + MAX_LOST_PACKETS); - if(local_index < buffer->packet_id) - diff = 0xFF; - else - diff = static_cast(MAX_LOST_PACKETS - (local_index - buffer->packet_id)); - } else { - diff = buffer->packet_id - codec_data->last_packet_id; - } + bool premature = false; - if(codec_data->last_packet_timestamp + chrono::seconds(1) < buffer->receive_timestamp || this->_state >= state::stopping) + if(codec_data->last_packet_timestamp + chrono::seconds(1) < buffer->receive_timestamp || this->_state >= state::stopping) { diff = 0xFFFF; + } else { + if(codec_data->last_packet_id > buffer->packet_id) { + auto local_index = (uint16_t) (codec_data->last_packet_id + MAX_LOST_PACKETS); + if(local_index < buffer->packet_id) + diff = 0xFF; /* we got in a new generation */ + else { + log_warn(category::audio, + tr("Received voice packet for client {} with is older than the last we received (Current index: {}, Packet index: {}). Dropping packet."), + this->_client_id, buffer->packet_id, codec_data->last_packet_id + ); + return; + } + } else { + diff = buffer->packet_id - codec_data->last_packet_id; + } + } const auto old_packet_id = codec_data->last_packet_id; codec_data->last_packet_timestamp = buffer->receive_timestamp; - codec_data->last_packet_id = buffer->packet_id; if(buffer->buffer.empty()) { - /* lets playpack the last samples and we're done */ + /* lets playback the last samples and we're done */ this->set_state(state::stopping); + + /* enqueue all premature packets (list should be already ordered!) */ + for(const auto& packet : codec_data->premature_packets) + this->output_source->enqueue_samples(packet.buffer); + codec_data->premature_packets.clear(); + log_trace(category::voice_connection, tr("Stopping replay for client {}. Empty buffer!"), this->_client_id); return; } @@ -395,10 +442,14 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr &b if(diff <= MAX_LOST_PACKETS) { if(diff > 0) { - log_debug(category::voice_connection, tr("Client {} dropped one or more audio packets. Old packet id: {}, New packet id: {}, Diff: {}"), this->_client_id, old_packet_id, buffer->packet_id, diff); - auto status = codec_data->converter->decode_lost(error, diff); - if(status < 0) - log_warn(category::voice_connection, tr("Failed to decode (skip) dropped packets. Return code {} => {}"), status, error); + log_debug(category::voice_connection, + tr("Client {} dropped one or more audio packets. Old packet id: {}, New packet id: {}, Diff: {}"), + this->_client_id, old_packet_id, buffer->packet_id, diff); + /* lets first handle packet as "lost", even thou we're enqueueing it as premature */ + //auto status = codec_data->converter->decode_lost(error, diff); + //if(status < 0) + // log_warn(category::voice_connection, tr("Failed to decode (skip) dropped packets. Return code {} => {}"), status, error); + premature = this->state() != state::stopped; } } else { log_debug(category::voice_connection, tr("Client {} resetted decoder. Old packet id: {}, New packet id: {}, diff: {}"), this->_client_id, old_packet_id, buffer->packet_id, diff); @@ -409,6 +460,30 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr &b } } + if(!premature) { + codec_data->last_packet_id = buffer->packet_id; + + /* test if any premature got its original place */ + { + size_t play_count = 0; + while(!codec_data->premature_packets.empty()) { + auto& packet = codec_data->premature_packets.front(); + + //Test if we're able to replay stuff again + if((uint16_t) (codec_data->last_packet_id + 1) < packet.packet_id) + break; //Nothing new + + this->output_source->enqueue_samples(packet.buffer); + codec_data->last_packet_id = packet.packet_id; + codec_data->premature_packets.pop_front(); + play_count++; + } + + if(play_count > 0) + log_debug(category::audio, tr("Replayed {} premature packets for client {}"), play_count, this->_client_id); + } + } + char target_buffer[target_buffer_length]; if(target_buffer_length < codec_data->converter->expected_decoded_length(buffer->buffer.data_ptr(), buffer->buffer.length())) { log_warn(category::voice_connection, tr("Failed to decode audio data. Target buffer is smaller then expected bytes ({} < {})"), target_buffer_length, codec_data->converter->expected_decoded_length(buffer->buffer.data_ptr(), buffer->buffer.length())); @@ -442,8 +517,29 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr &b *(buf++) *= this->_volume; } - auto enqueued = this->output_source->enqueue_samples(target_buffer, resampled_samples); - if(enqueued != resampled_samples) - log_warn(category::voice_connection, tr("Failed to enqueue all samples for client {}. Enqueued {} of {}"), this->_client_id, enqueued, resampled_samples); - this->set_state(state::playing); + if(premature) { + auto audio_buffer = audio::SampleBuffer::allocate((uint8_t) this->output_source->channel_count, (uint16_t) resampled_samples); + + audio_buffer->sample_index = 0; + memcpy(audio_buffer->sample_data, target_buffer, this->output_source->channel_count * resampled_samples * 4); + + auto it = codec_data->premature_packets.begin(); + for(; it != codec_data->premature_packets.end(); it++) { + if(it->packet_id > buffer->packet_id) { + break; /* it is set to the right position */ + } + } + codec_data->premature_packets.insert(it, { + buffer->packet_id, + audio_buffer + }); + std::stable_sort(codec_data->premature_packets.begin(), codec_data->premature_packets.end(), [](const PrematureAudioPacket& a, const PrematureAudioPacket& b) { + return a.packet_id < b.packet_id; + }); + } else { + auto enqueued = this->output_source->enqueue_samples(target_buffer, resampled_samples); + if(enqueued != resampled_samples) + log_warn(category::voice_connection, tr("Failed to enqueue all samples for client {}. Enqueued {} of {}"), this->_client_id, enqueued, resampled_samples); + this->set_state(state::playing); + } } \ No newline at end of file diff --git a/native/serverconnection/src/connection/audio/VoiceClient.h b/native/serverconnection/src/connection/audio/VoiceClient.h index 6788849..9e3ce86 100644 --- a/native/serverconnection/src/connection/audio/VoiceClient.h +++ b/native/serverconnection/src/connection/audio/VoiceClient.h @@ -88,6 +88,11 @@ namespace tc { inline std::shared_ptr output_stream() { return this->output_source; } private: + struct PrematureAudioPacket { + uint16_t packet_id = 0; + std::shared_ptr buffer; + }; + struct AudioCodec { uint16_t last_packet_id = 0; std::chrono::system_clock::time_point last_packet_timestamp; @@ -95,6 +100,8 @@ namespace tc { bool successfully_initialized; std::shared_ptr converter; std::shared_ptr resampler; + + std::deque premature_packets; }; std::array, codec::MAX + 1> codec{ @@ -112,6 +119,8 @@ namespace tc { uint16_t _client_id; float _volume = 1.f; + bool play_premature_packets = false; + std::chrono::system_clock::time_point _last_received_packet; state::value _state = state::stopped; inline void set_state(state::value value) { diff --git a/native/serverconnection/src/connection/audio/VoiceConnection.cpp b/native/serverconnection/src/connection/audio/VoiceConnection.cpp index 145b682..eb250d8 100644 --- a/native/serverconnection/src/connection/audio/VoiceConnection.cpp +++ b/native/serverconnection/src/connection/audio/VoiceConnection.cpp @@ -149,12 +149,6 @@ NAN_METHOD(VoiceConnectionWrap::unregister_client) { NAN_METHOD(VoiceConnectionWrap::_audio_source) { auto client = ObjectWrap::Unwrap(info.Holder()); - - if(info.Length() != 1) { - Nan::ThrowError("invalid argument count"); - return; - } - info.GetReturnValue().Set(client->_voice_recoder_handle.Get(info.GetIsolate())); } @@ -192,7 +186,10 @@ NAN_METHOD(VoiceConnectionWrap::set_audio_source) { lock_guard read_lock(this->_voice_recoder_ptr->native_read_callback_lock); this->_voice_recoder_ptr->native_read_callback = [weak_handle, sample_rate, channels](const void* buffer, size_t length) { auto handle = weak_handle.lock(); - if(!handle) return; + if(!handle) { + log_warn(category::audio, tr("Missing voice connection handle. Dropping input!")); + return; + } shared_ptr sender = handle->voice_sender(); if(sender) { @@ -200,6 +197,9 @@ NAN_METHOD(VoiceConnectionWrap::set_audio_source) { sender->send_data(buffer, length, sample_rate, channels); else sender->send_stop(); + } else { + log_warn(category::audio, tr("Missing voice connection audio sender. Dropping input!")); + return; } }; } diff --git a/native/serverconnection/src/connection/ft/FileTransferObject.cpp b/native/serverconnection/src/connection/ft/FileTransferObject.cpp index cf6e4ac..40ea10a 100644 --- a/native/serverconnection/src/connection/ft/FileTransferObject.cpp +++ b/native/serverconnection/src/connection/ft/FileTransferObject.cpp @@ -10,6 +10,11 @@ using namespace std; TransferJSBufferTarget::TransferJSBufferTarget() { log_allocate("TransferJSBufferTarget", this); + + if(!this->_js_buffer.IsEmpty()) { + assert(v8::Isolate::GetCurrent()); + this->_js_buffer.Reset(); + } } TransferJSBufferTarget::~TransferJSBufferTarget() { @@ -74,6 +79,11 @@ NAN_METHOD(TransferJSBufferTarget::create_from_buffer) { TransferJSBufferSource::~TransferJSBufferSource() { log_free("TransferJSBufferSource", this); + + if(!this->_js_buffer.IsEmpty()) { + assert(v8::Isolate::GetCurrent()); + this->_js_buffer.Reset(); + } } TransferJSBufferSource::TransferJSBufferSource() { log_allocate("TransferJSBufferSource", this); diff --git a/native/serverconnection/src/connection/ft/FileTransferObject.h b/native/serverconnection/src/connection/ft/FileTransferObject.h index 54222c1..171970f 100644 --- a/native/serverconnection/src/connection/ft/FileTransferObject.h +++ b/native/serverconnection/src/connection/ft/FileTransferObject.h @@ -79,7 +79,7 @@ namespace tc { TransferJSBufferSource(); virtual ~TransferJSBufferSource(); - std::string name() const override { return "TransferJSBufferTarget"; } + std::string name() const override { return "TransferJSBufferSource"; } bool initialize(std::string &string) override; void finalize() override; diff --git a/package.json b/package.json index d6e6bbc..2983bba 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "assert-plus": "^1.0.0", "aws-sign2": "^0.7.0", "aws4": "^1.8.0", - "electron": "5.0.6", + "electron": "6.0.7", "electron-installer-windows": "^1.1.1", "electron-navigation": "^1.5.8", "electron-rebuild": "^1.8.5",