001package com.github.theholywaffle.teamspeak3; 002 003/* 004 * #%L 005 * TeamSpeak 3 Java API 006 * %% 007 * Copyright (C) 2014 Bert De Geyter 008 * %% 009 * Permission is hereby granted, free of charge, to any person obtaining a copy 010 * of this software and associated documentation files (the "Software"), to deal 011 * in the Software without restriction, including without limitation the rights 012 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 013 * copies of the Software, and to permit persons to whom the Software is 014 * furnished to do so, subject to the following conditions: 015 * 016 * The above copyright notice and this permission notice shall be included in 017 * all copies or substantial portions of the Software. 018 * 019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 022 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 023 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 024 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 025 * THE SOFTWARE. 026 * #L% 027 */ 028 029import com.github.theholywaffle.teamspeak3.api.*; 030import com.github.theholywaffle.teamspeak3.api.event.TS3EventType; 031import com.github.theholywaffle.teamspeak3.api.event.TS3Listener; 032import com.github.theholywaffle.teamspeak3.api.exception.TS3CommandFailedException; 033import com.github.theholywaffle.teamspeak3.api.exception.TS3Exception; 034import com.github.theholywaffle.teamspeak3.api.exception.TS3FileTransferFailedException; 035import com.github.theholywaffle.teamspeak3.api.wrapper.*; 036import com.github.theholywaffle.teamspeak3.commands.*; 037 038import java.io.ByteArrayInputStream; 039import java.io.ByteArrayOutputStream; 040import java.io.IOException; 041import java.io.InputStream; 042import java.io.OutputStream; 043import java.util.*; 044import java.util.concurrent.TimeUnit; 045import java.util.function.Function; 046import java.util.regex.Pattern; 047import java.util.stream.Collectors; 048 049/** 050 * Asynchronous version of {@link TS3Api} to interact with the {@link TS3Query}. 051 * <p> 052 * This class is used to easily interact with a {@link TS3Query}. It constructs commands, 053 * sends them to the TeamSpeak3 server, processes the response and returns the result. 054 * </p><p> 055 * All methods in this class are asynchronous (so they won't block) and 056 * will return a {@link CommandFuture} of the corresponding return type in {@link TS3Api}. 057 * If a command fails, no exception will be thrown directly. It will however be rethrown in 058 * {@link CommandFuture#get()} and {@link CommandFuture#get(long, TimeUnit)}. 059 * Usually, the thrown exception is a {@link TS3CommandFailedException}, which will get you 060 * access to the {@link QueryError} from which more information about the error can be obtained. 061 * </p><p> 062 * Also note that while these methods are asynchronous, the commands will still be sent through a 063 * synchronous command pipeline. That means if an asynchronous method is called immediately 064 * followed by a synchronous method, the synchronous method will first have to wait until the 065 * asynchronous method completed until it its command is sent. 066 * </p><p> 067 * You won't be able to execute most commands while you're not logged in due to missing permissions. 068 * Make sure to either pass your login credentials to the {@link TS3Config} object when 069 * creating the {@code TS3Query} or to call {@link #login(String, String)} to log in. 070 * </p><p> 071 * After that, most commands also require you to select a {@linkplain VirtualServer virtual server}. 072 * To do so, call either {@link #selectVirtualServerByPort(int)} or {@link #selectVirtualServerById(int)}. 073 * </p> 074 * 075 * @see TS3Api The synchronous version of the API 076 */ 077public class TS3ApiAsync { 078 079 /** 080 * The TS3 query that holds the event manager and the file transfer helper. 081 */ 082 private final TS3Query query; 083 084 /** 085 * The queue that this TS3ApiAsync sends its commands to. 086 */ 087 private final CommandQueue commandQueue; 088 089 /** 090 * Creates a new asynchronous API object for the given {@code TS3Query}. 091 * <p> 092 * <b>Usually, this constructor should not be called.</b> Use {@link TS3Query#getAsyncApi()} instead. 093 * </p> 094 * 095 * @param query 096 * the TS3Query to use 097 * @param commandQueue 098 * the queue to send commands to 099 */ 100 TS3ApiAsync(TS3Query query, CommandQueue commandQueue) { 101 this.query = query; 102 this.commandQueue = commandQueue; 103 } 104 105 /** 106 * Adds a new ban entry. At least one of the parameters {@code ip}, {@code name} or {@code uid} needs to be non-null. 107 * Returns the ID of the newly created ban entry. 108 * 109 * @param ip 110 * a RegEx pattern to match a client's IP against, can be {@code null} 111 * @param name 112 * a RegEx pattern to match a client's name against, can be {@code null} 113 * @param uid 114 * the unique identifier of a client, can be {@code null} 115 * @param timeInSeconds 116 * the duration of the ban in seconds. 0 equals a permanent ban 117 * @param reason 118 * the reason for the ban, can be {@code null} 119 * 120 * @return the ID of the newly created ban entry 121 * 122 * @throws TS3CommandFailedException 123 * if the execution of a command fails 124 * @querycommands 1 125 * @see Pattern RegEx Pattern 126 * @see #addBan(String, String, String, String, long, String) 127 * @see Client#getId() 128 * @see Client#getUniqueIdentifier() 129 * @see ClientInfo#getIp() 130 */ 131 public CommandFuture<Integer> addBan(String ip, String name, String uid, long timeInSeconds, String reason) { 132 return addBan(ip, name, uid, null, timeInSeconds, reason); 133 } 134 135 /** 136 * Adds a new ban entry. At least one of the parameters {@code ip}, {@code name}, {@code uid}, or 137 * {@code myTSId} needs to be non-null. Returns the ID of the newly created ban entry. 138 * <p> 139 * Note that creating a ban entry for the {@code "empty"} "myTeamSpeak" ID will ban all clients who 140 * don't have a linked "myTeamSpeak" account. 141 * </p> 142 * 143 * @param ip 144 * a RegEx pattern to match a client's IP against, can be {@code null} 145 * @param name 146 * a RegEx pattern to match a client's name against, can be {@code null} 147 * @param uid 148 * the unique identifier of a client, can be {@code null} 149 * @param myTSId 150 * the "myTeamSpeak" ID of a client, the string {@code "empty"}, or {@code null} 151 * @param timeInSeconds 152 * the duration of the ban in seconds. 0 equals a permanent ban 153 * @param reason 154 * the reason for the ban, can be {@code null} 155 * 156 * @return the ID of the newly created ban entry 157 * 158 * @throws TS3CommandFailedException 159 * if the execution of a command fails 160 * @querycommands 1 161 * @see Pattern RegEx Pattern 162 * @see Client#getId() 163 * @see Client#getUniqueIdentifier() 164 * @see ClientInfo#getIp() 165 */ 166 public CommandFuture<Integer> addBan(String ip, String name, String uid, String myTSId, long timeInSeconds, String reason) { 167 Command cmd = BanCommands.banAdd(ip, name, uid, myTSId, timeInSeconds, reason); 168 return executeAndReturnIntProperty(cmd, "banid"); 169 } 170 171 /** 172 * Adds a specified permission to a client in a specific channel. 173 * 174 * @param channelId 175 * the ID of the channel wherein the permission should be granted 176 * @param clientDBId 177 * the database ID of the client to add a permission to 178 * @param permName 179 * the name of the permission to grant 180 * @param permValue 181 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 182 * 183 * @return a future to track the progress of this command 184 * 185 * @throws TS3CommandFailedException 186 * if the execution of a command fails 187 * @querycommands 1 188 * @see Channel#getId() 189 * @see Client#getDatabaseId() 190 * @see Permission 191 */ 192 public CommandFuture<Void> addChannelClientPermission(int channelId, int clientDBId, String permName, int permValue) { 193 Command cmd = PermissionCommands.channelClientAddPerm(channelId, clientDBId, permName, permValue); 194 return executeAndReturnError(cmd); 195 } 196 197 /** 198 * Creates a new channel group for clients using a given name and returns its ID. 199 * <p> 200 * To create channel group templates or ones for server queries, 201 * use {@link #addChannelGroup(String, PermissionGroupDatabaseType)}. 202 * </p> 203 * 204 * @param name 205 * the name of the new channel group 206 * 207 * @return the ID of the newly created channel group 208 * 209 * @throws TS3CommandFailedException 210 * if the execution of a command fails 211 * @querycommands 1 212 * @see ChannelGroup 213 */ 214 public CommandFuture<Integer> addChannelGroup(String name) { 215 return addChannelGroup(name, null); 216 } 217 218 /** 219 * Creates a new channel group using a given name and returns its ID. 220 * 221 * @param name 222 * the name of the new channel group 223 * @param type 224 * the desired type of channel group 225 * 226 * @return the ID of the newly created channel group 227 * 228 * @throws TS3CommandFailedException 229 * if the execution of a command fails 230 * @querycommands 1 231 * @see ChannelGroup 232 */ 233 public CommandFuture<Integer> addChannelGroup(String name, PermissionGroupDatabaseType type) { 234 Command cmd = ChannelGroupCommands.channelGroupAdd(name, type); 235 return executeAndReturnIntProperty(cmd, "cgid"); 236 } 237 238 /** 239 * Adds a specified permission to a channel group. 240 * 241 * @param groupId 242 * the ID of the channel group to grant the permission 243 * @param permName 244 * the name of the permission to be granted 245 * @param permValue 246 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 247 * 248 * @return a future to track the progress of this command 249 * 250 * @throws TS3CommandFailedException 251 * if the execution of a command fails 252 * @querycommands 1 253 * @see ChannelGroup#getId() 254 * @see Permission 255 */ 256 public CommandFuture<Void> addChannelGroupPermission(int groupId, String permName, int permValue) { 257 Command cmd = PermissionCommands.channelGroupAddPerm(groupId, permName, permValue); 258 return executeAndReturnError(cmd); 259 } 260 261 /** 262 * Adds a specified permission to a channel. 263 * 264 * @param channelId 265 * the ID of the channel wherein the permission should be granted 266 * @param permName 267 * the name of the permission to grant 268 * @param permValue 269 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 270 * 271 * @return a future to track the progress of this command 272 * 273 * @throws TS3CommandFailedException 274 * if the execution of a command fails 275 * @querycommands 1 276 * @see Channel#getId() 277 * @see Permission 278 */ 279 public CommandFuture<Void> addChannelPermission(int channelId, String permName, int permValue) { 280 Command cmd = PermissionCommands.channelAddPerm(channelId, permName, permValue); 281 return executeAndReturnError(cmd); 282 } 283 284 /** 285 * Adds a specified permission to a channel. 286 * 287 * @deprecated 288 * This method is no longer preferred for adding permissions to a client. 289 * <p> 290 * Use {@link TS3ApiAsync#addClientPermission(int, IPermissionType, int, boolean)} 291 * or {@link TS3ApiAsync#addClientPermission(int, BPermissionType, boolean, boolean)} instead. 292 * </p> 293 * 294 * @param clientDBId 295 * the database ID of the client to grant the permission 296 * @param permName 297 * the name of the permission to grant 298 * @param value 299 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 300 * @param skipped 301 * if set to {@code true}, the permission will not be overridden by channel group permissions 302 * 303 * @return a future to track the progress of this command 304 * 305 * @throws TS3CommandFailedException 306 * if the execution of a command fails 307 * @querycommands 1 308 * @see Client#getDatabaseId() 309 * @see Permission 310 */ 311 @Deprecated 312 public CommandFuture<Void> addClientPermission(int clientDBId, String permName, int value, boolean skipped) { 313 Command cmd = PermissionCommands.clientAddPerm(clientDBId, permName, value, skipped); 314 return executeAndReturnError(cmd); 315 } 316 317 /** 318 * Adds a specified permission to a client. 319 * 320 * @param clientDBId 321 * the database ID of the client to grant the permission 322 * @param permName 323 * the enum of the permission to grant 324 * @see IPermissionType 325 * @param value 326 * the numeric value of the permission 327 * @param skipped 328 * if set to {@code true}, the permission will not be overridden by channel group permissions 329 * 330 * @return a future to track the progress of this command 331 * 332 * @throws TS3CommandFailedException 333 * if the execution of a command fails 334 * @querycommands 1 335 * @see Client#getDatabaseId() 336 * @see Permission 337 */ 338 public CommandFuture<Void> addClientPermission(int clientDBId, IPermissionType permName, int value, boolean skipped) { 339 Command cmd = PermissionCommands.clientAddPerm(clientDBId, permName.getName(), value, skipped); 340 return executeAndReturnError(cmd); 341 } 342 343 /** 344 * Adds a specified permission to a client. 345 * 346 * @param clientDBId 347 * the database ID of the client to grant the permission 348 * @param permName 349 * the enum of the permission to grant 350 * @see BPermissionType 351 * @param value 352 * the boolean value of the permission 353 * @param skipped 354 * if set to {@code true}, the permission will not be overridden by channel group permissions 355 * 356 * @return a future to track the progress of this command 357 * 358 * @throws TS3CommandFailedException 359 * if the execution of a command fails 360 * @querycommands 1 361 * @see Client#getDatabaseId() 362 * @see Permission 363 */ 364 public CommandFuture<Void> addClientPermission(int clientDBId, BPermissionType permName, boolean value, boolean skipped) { 365 Command cmd = PermissionCommands.clientAddPerm(clientDBId, permName.getName(), value, skipped); 366 return executeAndReturnError(cmd); 367 } 368 369 /** 370 * Adds a client to the specified server group. 371 * <p> 372 * Please note that a client cannot be added to default groups or template groups. 373 * </p> 374 * 375 * @param groupId 376 * the ID of the server group to add the client to 377 * @param clientDatabaseId 378 * the database ID of the client to add 379 * 380 * @return a future to track the progress of this command 381 * 382 * @throws TS3CommandFailedException 383 * if the execution of a command fails 384 * @querycommands 1 385 * @see ServerGroup#getId() 386 * @see Client#getDatabaseId() 387 */ 388 public CommandFuture<Void> addClientToServerGroup(int groupId, int clientDatabaseId) { 389 Command cmd = ServerGroupCommands.serverGroupAddClient(groupId, clientDatabaseId); 390 return executeAndReturnError(cmd); 391 } 392 393 /** 394 * Submits a complaint about the specified client. 395 * The length of the message is limited to 200 UTF-8 bytes and BB codes in it will be ignored. 396 * 397 * @param clientDBId 398 * the database ID of the client 399 * @param message 400 * the message of the complaint, may not contain BB codes 401 * 402 * @return a future to track the progress of this command 403 * 404 * @throws TS3CommandFailedException 405 * if the execution of a command fails 406 * @querycommands 1 407 * @see Client#getDatabaseId() 408 * @see Complaint#getMessage() 409 */ 410 public CommandFuture<Void> addComplaint(int clientDBId, String message) { 411 Command cmd = ComplaintCommands.complainAdd(clientDBId, message); 412 return executeAndReturnError(cmd); 413 } 414 415 /** 416 * Adds a specified permission to all server groups of the type specified by {@code type} on all virtual servers. 417 * 418 * @param type 419 * the kind of server group this permission should be added to 420 * @param permName 421 * the name of the permission to be granted 422 * @param value 423 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 424 * @param negated 425 * if set to true, the lowest permission value will be selected instead of the highest 426 * @param skipped 427 * if set to true, this permission will not be overridden by client or channel group permissions 428 * 429 * @return a future to track the progress of this command 430 * 431 * @throws TS3CommandFailedException 432 * if the execution of a command fails 433 * @querycommands 1 434 * @see ServerGroupType 435 * @see Permission 436 */ 437 public CommandFuture<Void> addPermissionToAllServerGroups(ServerGroupType type, String permName, int value, boolean negated, boolean skipped) { 438 Command cmd = PermissionCommands.serverGroupAutoAddPerm(type, permName, value, negated, skipped); 439 return executeAndReturnError(cmd); 440 } 441 442 /** 443 * Create a new privilege key that allows one client to join a server or channel group. 444 * <ul> 445 * <li>If {@code type} is set to {@linkplain PrivilegeKeyType#SERVER_GROUP SERVER_GROUP}, 446 * {@code groupId} is used as a server group ID and {@code channelId} is ignored.</li> 447 * <li>If {@code type} is set to {@linkplain PrivilegeKeyType#CHANNEL_GROUP CHANNEL_GROUP}, 448 * {@code groupId} is used as a channel group ID and {@code channelId} is used as the channel in which the group should be set.</li> 449 * </ul> 450 * 451 * @param type 452 * the type of token that should be created 453 * @param groupId 454 * the ID of the server or channel group 455 * @param channelId 456 * the ID of the channel, in case the token is channel group token 457 * @param description 458 * the description for the token, can be null 459 * 460 * @return the created token for a client to use 461 * 462 * @throws TS3CommandFailedException 463 * if the execution of a command fails 464 * @querycommands 1 465 * @see PrivilegeKeyType 466 * @see #addPrivilegeKeyServerGroup(int, String) 467 * @see #addPrivilegeKeyChannelGroup(int, int, String) 468 */ 469 public CommandFuture<String> addPrivilegeKey(PrivilegeKeyType type, int groupId, int channelId, String description) { 470 Command cmd = PrivilegeKeyCommands.privilegeKeyAdd(type, groupId, channelId, description); 471 return executeAndReturnStringProperty(cmd, "token"); 472 } 473 474 /** 475 * Creates a new privilege key for a channel group. 476 * 477 * @param channelGroupId 478 * the ID of the channel group 479 * @param channelId 480 * the ID of the channel in which the channel group should be set 481 * @param description 482 * the description for the token, can be null 483 * 484 * @return the created token for a client to use 485 * 486 * @throws TS3CommandFailedException 487 * if the execution of a command fails 488 * @querycommands 1 489 * @see ChannelGroup#getId() 490 * @see Channel#getId() 491 * @see #addPrivilegeKey(PrivilegeKeyType, int, int, String) 492 * @see #addPrivilegeKeyServerGroup(int, String) 493 */ 494 public CommandFuture<String> addPrivilegeKeyChannelGroup(int channelGroupId, int channelId, String description) { 495 return addPrivilegeKey(PrivilegeKeyType.CHANNEL_GROUP, channelGroupId, channelId, description); 496 } 497 498 /** 499 * Creates a new privilege key for a server group. 500 * 501 * @param serverGroupId 502 * the ID of the server group 503 * @param description 504 * the description for the token, can be null 505 * 506 * @return the created token for a client to use 507 * 508 * @throws TS3CommandFailedException 509 * if the execution of a command fails 510 * @querycommands 1 511 * @see ServerGroup#getId() 512 * @see #addPrivilegeKey(PrivilegeKeyType, int, int, String) 513 * @see #addPrivilegeKeyChannelGroup(int, int, String) 514 */ 515 public CommandFuture<String> addPrivilegeKeyServerGroup(int serverGroupId, String description) { 516 return addPrivilegeKey(PrivilegeKeyType.SERVER_GROUP, serverGroupId, 0, description); 517 } 518 519 /** 520 * Creates a new server group for clients using a given name and returns its ID. 521 * <p> 522 * To create server group templates or ones for server queries, 523 * use {@link #addServerGroup(String, PermissionGroupDatabaseType)}. 524 * </p> 525 * 526 * @param name 527 * the name of the new server group 528 * 529 * @return the ID of the newly created server group 530 * 531 * @throws TS3CommandFailedException 532 * if the execution of a command fails 533 * @querycommands 1 534 * @see ServerGroup 535 */ 536 public CommandFuture<Integer> addServerGroup(String name) { 537 return addServerGroup(name, PermissionGroupDatabaseType.REGULAR); 538 } 539 540 /** 541 * Creates a new server group using a given name and returns its ID. 542 * 543 * @param name 544 * the name of the new server group 545 * @param type 546 * the desired type of server group 547 * 548 * @return the ID of the newly created server group 549 * 550 * @throws TS3CommandFailedException 551 * if the execution of a command fails 552 * @querycommands 1 553 * @see ServerGroup 554 * @see PermissionGroupDatabaseType 555 */ 556 public CommandFuture<Integer> addServerGroup(String name, PermissionGroupDatabaseType type) { 557 Command cmd = ServerGroupCommands.serverGroupAdd(name, type); 558 return executeAndReturnIntProperty(cmd, "sgid"); 559 } 560 561 /** 562 * Adds a specified permission to a server group. 563 * 564 * @param groupId 565 * the ID of the channel group to which the permission should be added 566 * @param permName 567 * the name of the permission to add 568 * @param value 569 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 570 * @param negated 571 * if set to true, the lowest permission value will be selected instead of the highest 572 * @param skipped 573 * if set to true, this permission will not be overridden by client or channel group permissions 574 * 575 * @return a future to track the progress of this command 576 * 577 * @throws TS3CommandFailedException 578 * if the execution of a command fails 579 * @querycommands 1 580 * @see ServerGroup#getId() 581 * @see Permission 582 */ 583 public CommandFuture<Void> addServerGroupPermission(int groupId, String permName, int value, boolean negated, boolean skipped) { 584 Command cmd = PermissionCommands.serverGroupAddPerm(groupId, permName, value, negated, skipped); 585 return executeAndReturnError(cmd); 586 } 587 588 /** 589 * Creates a server query login with name {@code loginName} for the client specified by {@code clientDBId} 590 * on the currently selected virtual server and returns the password of the created login. 591 * If the client already had a server query login, the existing login will be deleted and replaced. 592 * <p> 593 * Moreover, this method can be used to create new <i>global</i> server query logins that are not tied to any 594 * particular virtual server or client. To create such a server query login, make sure no virtual server is 595 * selected (e.g. use {@code selectVirtualServerById(0)}) and call this method with {@code clientDBId = 0}. 596 * </p> 597 * 598 * @param loginName 599 * the name of the server query login to add 600 * @param clientDBId 601 * the database ID of the client for which a server query login should be created 602 * 603 * @return an object containing the password of the new server query login 604 * 605 * @throws TS3CommandFailedException 606 * if the execution of a command fails 607 * @querycommands 1 608 * @see #deleteServerQueryLogin(int) 609 * @see #getServerQueryLogins() 610 * @see #updateServerQueryLogin(String) 611 */ 612 public CommandFuture<CreatedQueryLogin> addServerQueryLogin(String loginName, int clientDBId) { 613 Command cmd = QueryLoginCommands.queryLoginAdd(loginName, clientDBId); 614 return executeAndTransformFirst(cmd, CreatedQueryLogin::new); 615 } 616 617 /** 618 * Adds one or more {@link TS3Listener}s to the event manager of the query. 619 * These listeners will be notified when the TS3 server fires an event. 620 * <p> 621 * Note that for the TS3 server to fire events, you must first also register 622 * the event types you want to listen to. 623 * </p> 624 * 625 * @param listeners 626 * one or more listeners to register 627 * 628 * @see #registerAllEvents() 629 * @see #registerEvent(TS3EventType, int) 630 * @see TS3Listener 631 * @see TS3EventType 632 */ 633 public void addTS3Listeners(TS3Listener... listeners) { 634 query.getEventManager().addListeners(listeners); 635 } 636 637 /** 638 * Bans a client with a given client ID for a given time. 639 * <p> 640 * Please note that this will create up to three separate ban rules, 641 * one for the targeted client's IP address, one for their unique identifier, 642 * and potentially one more entry for their "myTeamSpeak" ID, if available. 643 * </p><p> 644 * <i>Exception:</i> If the banned client connects via a loopback address 645 * (i.e. {@code 127.0.0.1} or {@code localhost}), no IP ban is created. 646 * </p> 647 * 648 * @param clientId 649 * the ID of the client 650 * @param timeInSeconds 651 * the duration of the ban in seconds. 0 equals a permanent ban 652 * 653 * @return an array containing the IDs of the created ban entries 654 * 655 * @throws TS3CommandFailedException 656 * if the execution of a command fails 657 * @querycommands 1 658 * @see Client#getId() 659 * @see #addBan(String, String, String, long, String) 660 */ 661 public CommandFuture<int[]> banClient(int clientId, long timeInSeconds) { 662 return banClient(clientId, timeInSeconds, null); 663 } 664 665 /** 666 * Bans a client with a given client ID for a given time for the specified reason. 667 * <p> 668 * Please note that this will create up to three separate ban rules, 669 * one for the targeted client's IP address, one for their unique identifier, 670 * and potentially one more entry for their "myTeamSpeak" ID, if available. 671 * </p><p> 672 * <i>Exception:</i> If the banned client connects via a loopback address 673 * (i.e. {@code 127.0.0.1} or {@code localhost}), no IP ban is created. 674 * </p> 675 * 676 * @param clientId 677 * the ID of the client 678 * @param timeInSeconds 679 * the duration of the ban in seconds. 0 equals a permanent ban 680 * @param reason 681 * the reason for the ban, can be null 682 * 683 * @return an array containing the IDs of the created ban entries 684 * 685 * @throws TS3CommandFailedException 686 * if the execution of a command fails 687 * @querycommands 1 688 * @see Client#getId() 689 * @see #addBan(String, String, String, long, String) 690 */ 691 public CommandFuture<int[]> banClient(int clientId, long timeInSeconds, String reason) { 692 Command cmd = BanCommands.banClient(new int[] {clientId}, timeInSeconds, reason, false); 693 return executeAndReturnIntArray(cmd, "banid"); 694 } 695 696 /** 697 * Bans a client with a given client ID permanently for the specified reason. 698 * <p> 699 * Please note that this will create up to three separate ban rules, 700 * one for the targeted client's IP address, one for their unique identifier, 701 * and potentially one more entry for their "myTeamSpeak" ID, if available. 702 * </p><p> 703 * <i>Exception:</i> If the banned client connects via a loopback address 704 * (i.e. {@code 127.0.0.1} or {@code localhost}), no IP ban is created. 705 * </p> 706 * 707 * @param clientId 708 * the ID of the client 709 * @param reason 710 * the reason for the ban, can be null 711 * 712 * @return an array containing the IDs of the created ban entries 713 * 714 * @throws TS3CommandFailedException 715 * if the execution of a command fails 716 * @querycommands 1 717 * @see Client#getId() 718 * @see #addBan(String, String, String, long, String) 719 */ 720 public CommandFuture<int[]> banClient(int clientId, String reason) { 721 return banClient(clientId, 0, reason); 722 } 723 724 /** 725 * Bans multiple clients by their client ID for a given time for the specified reason. 726 * <p> 727 * Please note that this will create up to three separate ban rules for each client, 728 * one for the targeted client's IP address, one for their unique identifier, 729 * and potentially one more entry for their "myTeamSpeak" ID, if available. 730 * </p><p> 731 * <i>Exception:</i> If the banned client connects via a loopback address 732 * (i.e. {@code 127.0.0.1} or {@code localhost}), no IP ban is created. 733 * </p><p> 734 * <i>Exception:</i> If two or more clients are connecting from the 735 * same IP address, only one IP ban entry for that IP will be created. 736 * </p> 737 * 738 * @param clientIds 739 * the IDs of the clients to be banned 740 * @param timeInSeconds 741 * the duration of the ban in seconds. 0 equals a permanent ban 742 * @param reason 743 * the reason for the ban, can be null 744 * @param continueOnError 745 * if true, continue to the next client if banning one client fails, else do not create any bans on error 746 * 747 * @return an array containing the IDs of the created ban entries 748 * 749 * @throws TS3CommandFailedException 750 * if the execution of a command fails 751 * @querycommands 1 752 * @see Client#getId() 753 * @see #addBan(String, String, String, long, String) 754 */ 755 public CommandFuture<int[]> banClients(int[] clientIds, long timeInSeconds, String reason, boolean continueOnError) { 756 if (clientIds == null) throw new IllegalArgumentException("Client ID array was null"); 757 if (clientIds.length == 0) return CommandFuture.immediate(new int[0]); // Success 758 759 Command cmd = BanCommands.banClient(clientIds, timeInSeconds, reason, continueOnError); 760 return executeAndReturnIntArray(cmd, "banid"); 761 } 762 763 /** 764 * Sends a text message to all clients on all virtual servers. 765 * These messages will appear to clients in the tab for server messages. 766 * 767 * @param message 768 * the message to be sent 769 * 770 * @return a future to track the progress of this command 771 * 772 * @throws TS3CommandFailedException 773 * if the execution of a command fails 774 * @querycommands 1 775 */ 776 public CommandFuture<Void> broadcast(String message) { 777 Command cmd = ServerCommands.gm(message); 778 return executeAndReturnError(cmd); 779 } 780 781 /** 782 * Creates a copy of the channel group specified by {@code sourceGroupId}, 783 * overwriting any other channel group specified by {@code targetGroupId}. 784 * <p> 785 * The parameter {@code type} can be used to create server query and template groups. 786 * </p> 787 * 788 * @param sourceGroupId 789 * the ID of the channel group to copy 790 * @param targetGroupId 791 * the ID of another channel group to overwrite 792 * @param type 793 * the desired type of channel group 794 * 795 * @return a future to track the progress of this command 796 * 797 * @throws TS3CommandFailedException 798 * if the execution of a command fails 799 * @querycommands 1 800 * @see ChannelGroup#getId() 801 */ 802 public CommandFuture<Void> copyChannelGroup(int sourceGroupId, int targetGroupId, PermissionGroupDatabaseType type) { 803 if (targetGroupId <= 0) { 804 throw new IllegalArgumentException("To create a new channel group, use the method with a String argument"); 805 } 806 807 Command cmd = ChannelGroupCommands.channelGroupCopy(sourceGroupId, targetGroupId, type); 808 return executeAndReturnError(cmd); 809 } 810 811 /** 812 * Creates a copy of the channel group specified by {@code sourceGroupId} with a given name 813 * and returns the ID of the newly created channel group. 814 * 815 * @param sourceGroupId 816 * the ID of the channel group to copy 817 * @param targetName 818 * the name for the copy of the channel group 819 * @param type 820 * the desired type of channel group 821 * 822 * @return the ID of the newly created channel group 823 * 824 * @throws TS3CommandFailedException 825 * if the execution of a command fails 826 * @querycommands 1 827 * @see ChannelGroup#getId() 828 */ 829 public CommandFuture<Integer> copyChannelGroup(int sourceGroupId, String targetName, PermissionGroupDatabaseType type) { 830 Command cmd = ChannelGroupCommands.channelGroupCopy(sourceGroupId, targetName, type); 831 return executeAndReturnIntProperty(cmd, "cgid"); 832 } 833 834 /** 835 * Creates a copy of the server group specified by {@code sourceGroupId}, 836 * overwriting another server group specified by {@code targetGroupId}. 837 * <p> 838 * The parameter {@code type} can be used to create server query and template groups. 839 * </p> 840 * 841 * @param sourceGroupId 842 * the ID of the server group to copy 843 * @param targetGroupId 844 * the ID of another server group to overwrite 845 * @param type 846 * the desired type of server group 847 * 848 * @return the ID of the newly created server group 849 * 850 * @throws TS3CommandFailedException 851 * if the execution of a command fails 852 * @querycommands 1 853 * @see ServerGroup#getId() 854 */ 855 public CommandFuture<Integer> copyServerGroup(int sourceGroupId, int targetGroupId, PermissionGroupDatabaseType type) { 856 if (targetGroupId <= 0) { 857 throw new IllegalArgumentException("To create a new server group, use the method with a String argument"); 858 } 859 860 Command cmd = ServerGroupCommands.serverGroupCopy(sourceGroupId, targetGroupId, type); 861 return executeAndReturnIntProperty(cmd, "sgid"); 862 } 863 864 /** 865 * Creates a copy of the server group specified by {@code sourceGroupId} with a given name 866 * and returns the ID of the newly created server group. 867 * 868 * @param sourceGroupId 869 * the ID of the server group to copy 870 * @param targetName 871 * the name for the copy of the server group 872 * @param type 873 * the desired type of server group 874 * 875 * @return the ID of the newly created server group 876 * 877 * @throws TS3CommandFailedException 878 * if the execution of a command fails 879 * @querycommands 1 880 * @see ServerGroup#getId() 881 */ 882 public CommandFuture<Integer> copyServerGroup(int sourceGroupId, String targetName, PermissionGroupDatabaseType type) { 883 Command cmd = ServerGroupCommands.serverGroupCopy(sourceGroupId, targetName, type); 884 return executeAndReturnIntProperty(cmd, "sgid"); 885 } 886 887 /** 888 * Creates a new channel with a given name using the given properties and returns its ID. 889 * 890 * @param name 891 * the name for the new channel 892 * @param options 893 * a map of options that should be set for the channel 894 * 895 * @return the ID of the newly created channel 896 * 897 * @throws TS3CommandFailedException 898 * if the execution of a command fails 899 * @querycommands 1 900 * @see Channel 901 */ 902 public CommandFuture<Integer> createChannel(String name, Map<ChannelProperty, String> options) { 903 Command cmd = ChannelCommands.channelCreate(name, options); 904 return executeAndReturnIntProperty(cmd, "cid"); 905 } 906 907 /** 908 * Creates a new directory on the file repository in the specified channel. 909 * 910 * @param directoryPath 911 * the path to the directory that should be created 912 * @param channelId 913 * the ID of the channel the directory should be created in 914 * 915 * @return a future to track the progress of this command 916 * 917 * @throws TS3CommandFailedException 918 * if the execution of a command fails 919 * @querycommands 1 920 * @see FileInfo#getPath() 921 * @see Channel#getId() 922 */ 923 public CommandFuture<Void> createFileDirectory(String directoryPath, int channelId) { 924 return createFileDirectory(directoryPath, channelId, null); 925 } 926 927 /** 928 * Creates a new directory on the file repository in the specified channel. 929 * 930 * @param directoryPath 931 * the path to the directory that should be created 932 * @param channelId 933 * the ID of the channel the directory should be created in 934 * @param channelPassword 935 * the password of that channel 936 * 937 * @return a future to track the progress of this command 938 * 939 * @throws TS3CommandFailedException 940 * if the execution of a command fails 941 * @querycommands 1 942 * @see FileInfo#getPath() 943 * @see Channel#getId() 944 */ 945 public CommandFuture<Void> createFileDirectory(String directoryPath, int channelId, String channelPassword) { 946 Command cmd = FileCommands.ftCreateDir(directoryPath, channelId, channelPassword); 947 return executeAndReturnError(cmd); 948 } 949 950 /** 951 * Creates a new virtual server with the given name and returns an object containing the ID of the newly 952 * created virtual server, the default server admin token and the virtual server's voice port. Usually, 953 * the virtual server is also automatically started. This can be turned off on the TS3 server, though. 954 * <p> 955 * If {@link VirtualServerProperty#VIRTUALSERVER_PORT} is not specified in the virtual server properties, 956 * the server will test for the first unused UDP port. 957 * </p><p> 958 * Please also note that creating virtual servers usually requires the server query admin account 959 * and that there is a limit to how many virtual servers can be created, which is dependent on your license. 960 * Unlicensed TS3 server instances are limited to 1 virtual server with up to 32 client slots. 961 * </p> 962 * 963 * @param name 964 * the name for the new virtual server 965 * @param options 966 * a map of options that should be set for the virtual server 967 * 968 * @return information about the newly created virtual server 969 * 970 * @throws TS3CommandFailedException 971 * if the execution of a command fails 972 * @querycommands 1 973 * @see VirtualServer 974 */ 975 public CommandFuture<CreatedVirtualServer> createServer(String name, Map<VirtualServerProperty, String> options) { 976 Command cmd = VirtualServerCommands.serverCreate(name, options); 977 return executeAndTransformFirst(cmd, CreatedVirtualServer::new); 978 } 979 980 /** 981 * Creates a {@link Snapshot} of the selected virtual server containing all settings, 982 * groups and known client identities. The data from a server snapshot can be 983 * used to restore a virtual servers configuration. 984 * 985 * @return a snapshot of the virtual server 986 * 987 * @throws TS3CommandFailedException 988 * if the execution of a command fails 989 * @querycommands 1 990 * @see #deployServerSnapshot(Snapshot) 991 */ 992 public CommandFuture<Snapshot> createServerSnapshot() { 993 Command cmd = VirtualServerCommands.serverSnapshotCreate(); 994 CommandFuture<Snapshot> future = cmd.getFuture() 995 .map(result -> new Snapshot(result.getRawResponse())); 996 997 commandQueue.enqueueCommand(cmd); 998 return future; 999 } 1000 1001 /** 1002 * Deletes all active ban rules from the server. Use with caution. 1003 * 1004 * @return a future to track the progress of this command 1005 * 1006 * @throws TS3CommandFailedException 1007 * if the execution of a command fails 1008 * @querycommands 1 1009 */ 1010 public CommandFuture<Void> deleteAllBans() { 1011 Command cmd = BanCommands.banDelAll(); 1012 return executeAndReturnError(cmd); 1013 } 1014 1015 /** 1016 * Deletes all complaints about the client with specified database ID from the server. 1017 * 1018 * @param clientDBId 1019 * the database ID of the client 1020 * 1021 * @return a future to track the progress of this command 1022 * 1023 * @throws TS3CommandFailedException 1024 * if the execution of a command fails 1025 * @querycommands 1 1026 * @see Client#getDatabaseId() 1027 * @see Complaint 1028 */ 1029 public CommandFuture<Void> deleteAllComplaints(int clientDBId) { 1030 Command cmd = ComplaintCommands.complainDelAll(clientDBId); 1031 return executeAndReturnError(cmd); 1032 } 1033 1034 /** 1035 * Deletes the ban rule with the specified ID from the server. 1036 * 1037 * @param banId 1038 * the ID of the ban to delete 1039 * 1040 * @return a future to track the progress of this command 1041 * 1042 * @throws TS3CommandFailedException 1043 * if the execution of a command fails 1044 * @querycommands 1 1045 * @see Ban#getId() 1046 */ 1047 public CommandFuture<Void> deleteBan(int banId) { 1048 Command cmd = BanCommands.banDel(banId); 1049 return executeAndReturnError(cmd); 1050 } 1051 1052 /** 1053 * Deletes an existing channel specified by its ID, kicking all clients out of the channel. 1054 * 1055 * @param channelId 1056 * the ID of the channel to delete 1057 * 1058 * @return a future to track the progress of this command 1059 * 1060 * @throws TS3CommandFailedException 1061 * if the execution of a command fails 1062 * @querycommands 1 1063 * @see Channel#getId() 1064 * @see #deleteChannel(int, boolean) 1065 * @see #kickClientFromChannel(String, int...) 1066 */ 1067 public CommandFuture<Void> deleteChannel(int channelId) { 1068 return deleteChannel(channelId, true); 1069 } 1070 1071 /** 1072 * Deletes an existing channel with a given ID. 1073 * If {@code force} is true, the channel will be deleted even if there are clients within, 1074 * else the command will fail in this situation. 1075 * 1076 * @param channelId 1077 * the ID of the channel to delete 1078 * @param force 1079 * whether clients should be kicked out of the channel 1080 * 1081 * @return a future to track the progress of this command 1082 * 1083 * @throws TS3CommandFailedException 1084 * if the execution of a command fails 1085 * @querycommands 1 1086 * @see Channel#getId() 1087 * @see #kickClientFromChannel(String, int...) 1088 */ 1089 public CommandFuture<Void> deleteChannel(int channelId, boolean force) { 1090 Command cmd = ChannelCommands.channelDelete(channelId, force); 1091 return executeAndReturnError(cmd); 1092 } 1093 1094 /** 1095 * Removes a specified permission from a client in a specific channel. 1096 * 1097 * @param channelId 1098 * the ID of the channel wherein the permission should be removed 1099 * @param clientDBId 1100 * the database ID of the client 1101 * @param permName 1102 * the name of the permission to revoke 1103 * 1104 * @return a future to track the progress of this command 1105 * 1106 * @throws TS3CommandFailedException 1107 * if the execution of a command fails 1108 * @querycommands 1 1109 * @see Channel#getId() 1110 * @see Client#getDatabaseId() 1111 * @see Permission#getName() 1112 */ 1113 public CommandFuture<Void> deleteChannelClientPermission(int channelId, int clientDBId, String permName) { 1114 Command cmd = PermissionCommands.channelClientDelPerm(channelId, clientDBId, permName); 1115 return executeAndReturnError(cmd); 1116 } 1117 1118 /** 1119 * Removes the channel group with the given ID. 1120 * 1121 * @param groupId 1122 * the ID of the channel group 1123 * 1124 * @return a future to track the progress of this command 1125 * 1126 * @throws TS3CommandFailedException 1127 * if the execution of a command fails 1128 * @querycommands 1 1129 * @see ChannelGroup#getId() 1130 */ 1131 public CommandFuture<Void> deleteChannelGroup(int groupId) { 1132 return deleteChannelGroup(groupId, true); 1133 } 1134 1135 /** 1136 * Removes the channel group with the given ID. 1137 * If {@code force} is true, the channel group will be deleted even if it still contains clients, 1138 * else the command will fail in this situation. 1139 * 1140 * @param groupId 1141 * the ID of the channel group 1142 * @param force 1143 * whether the channel group should be deleted even if it still contains clients 1144 * 1145 * @return a future to track the progress of this command 1146 * 1147 * @throws TS3CommandFailedException 1148 * if the execution of a command fails 1149 * @querycommands 1 1150 * @see ChannelGroup#getId() 1151 */ 1152 public CommandFuture<Void> deleteChannelGroup(int groupId, boolean force) { 1153 Command cmd = ChannelGroupCommands.channelGroupDel(groupId, force); 1154 return executeAndReturnError(cmd); 1155 } 1156 1157 /** 1158 * Removes a permission from the channel group with the given ID. 1159 * 1160 * @param groupId 1161 * the ID of the channel group 1162 * @param permName 1163 * the name of the permission to revoke 1164 * 1165 * @return a future to track the progress of this command 1166 * 1167 * @throws TS3CommandFailedException 1168 * if the execution of a command fails 1169 * @querycommands 1 1170 * @see ChannelGroup#getId() 1171 * @see Permission#getName() 1172 */ 1173 public CommandFuture<Void> deleteChannelGroupPermission(int groupId, String permName) { 1174 Command cmd = PermissionCommands.channelGroupDelPerm(groupId, permName); 1175 return executeAndReturnError(cmd); 1176 } 1177 1178 /** 1179 * Removes a permission from the channel with the given ID. 1180 * 1181 * @param channelId 1182 * the ID of the channel 1183 * @param permName 1184 * the name of the permission to revoke 1185 * 1186 * @return a future to track the progress of this command 1187 * 1188 * @throws TS3CommandFailedException 1189 * if the execution of a command fails 1190 * @querycommands 1 1191 * @see Channel#getId() 1192 * @see Permission#getName() 1193 */ 1194 public CommandFuture<Void> deleteChannelPermission(int channelId, String permName) { 1195 Command cmd = PermissionCommands.channelDelPerm(channelId, permName); 1196 return executeAndReturnError(cmd); 1197 } 1198 1199 /** 1200 * Removes a permission from a client. 1201 * 1202 * @deprecated 1203 * This method is no longer preferred for removing permissions from a client. 1204 * <p> 1205 * Use {@link TS3ApiAsync#deleteClientPermission(int, IPermissionType)} 1206 * or {@link TS3ApiAsync#deleteClientPermission(int, BPermissionType)} instead. 1207 * </p> 1208 * 1209 * @param clientDBId 1210 * the database ID of the client 1211 * @param permName 1212 * the name of the permission to revoke 1213 * 1214 * @return a future to track the progress of this command 1215 * 1216 * @throws TS3CommandFailedException 1217 * if the execution of a command fails 1218 * @querycommands 1 1219 * @see Client#getDatabaseId() 1220 * @see Permission#getName() 1221 */ 1222 @Deprecated 1223 public CommandFuture<Void> deleteClientPermission(int clientDBId, String permName) { 1224 Command cmd = PermissionCommands.clientDelPerm(clientDBId, permName); 1225 return executeAndReturnError(cmd); 1226 } 1227 1228 /** 1229 * Removes a permission from a client. 1230 * 1231 * @param clientDBId 1232 * the database ID of the client 1233 * @param permName 1234 * the enum of the permission to revoke 1235 * @see IPermissionType 1236 * 1237 * @return a future to track the progress of this command 1238 * 1239 * @throws TS3CommandFailedException 1240 * if the execution of a command fails 1241 * @querycommands 1 1242 * @see Client#getDatabaseId() 1243 * @see Permission#getName() 1244 */ 1245 public CommandFuture<Void> deleteClientPermission(int clientDBId, IPermissionType permName) { 1246 Command cmd = PermissionCommands.clientDelPerm(clientDBId, permName.getName()); 1247 return executeAndReturnError(cmd); 1248 } 1249 1250 /** 1251 * Removes a permission from a client. 1252 * 1253 * @param clientDBId 1254 * the database ID of the client 1255 * @param permName 1256 * the enum of the permission to revoke 1257 * @see BPermissionType 1258 * 1259 * @return a future to track the progress of this command 1260 * 1261 * @throws TS3CommandFailedException 1262 * if the execution of a command fails 1263 * @querycommands 1 1264 * @see Client#getDatabaseId() 1265 * @see Permission#getName() 1266 */ 1267 public CommandFuture<Void> deleteClientPermission(int clientDBId, BPermissionType permName) { 1268 Command cmd = PermissionCommands.clientDelPerm(clientDBId, permName.getName()); 1269 return executeAndReturnError(cmd); 1270 } 1271 1272 /** 1273 * Deletes the complaint about the client with database ID {@code targetClientDBId} submitted by 1274 * the client with database ID {@code fromClientDBId} from the server. 1275 * 1276 * @param targetClientDBId 1277 * the database ID of the client the complaint is about 1278 * @param fromClientDBId 1279 * the database ID of the client who added the complaint 1280 * 1281 * @return a future to track the progress of this command 1282 * 1283 * @throws TS3CommandFailedException 1284 * if the execution of a command fails 1285 * @querycommands 1 1286 * @see Complaint 1287 * @see Client#getDatabaseId() 1288 */ 1289 public CommandFuture<Void> deleteComplaint(int targetClientDBId, int fromClientDBId) { 1290 Command cmd = ComplaintCommands.complainDel(targetClientDBId, fromClientDBId); 1291 return executeAndReturnError(cmd); 1292 } 1293 1294 /** 1295 * Removes the {@code key} custom client property from a client. 1296 * 1297 * @param clientDBId 1298 * the database ID of the target client 1299 * @param key 1300 * the key of the custom property to delete, cannot be {@code null} 1301 * 1302 * @return a future to track the progress of this command 1303 * 1304 * @throws TS3CommandFailedException 1305 * if the execution of a command fails 1306 * @querycommands 1 1307 * @see Client#getDatabaseId() 1308 */ 1309 public CommandFuture<Void> deleteCustomClientProperty(int clientDBId, String key) { 1310 if (key == null) throw new IllegalArgumentException("Key cannot be null"); 1311 1312 Command cmd = CustomPropertyCommands.customDelete(clientDBId, key); 1313 return executeAndReturnError(cmd); 1314 } 1315 1316 /** 1317 * Removes all stored database information about the specified client. 1318 * Please note that this data is also automatically removed after a configured time (usually 90 days). 1319 * <p> 1320 * See {@link DatabaseClientInfo} for a list of stored information about a client. 1321 * </p> 1322 * 1323 * @param clientDBId 1324 * the database ID of the client 1325 * 1326 * @return a future to track the progress of this command 1327 * 1328 * @throws TS3CommandFailedException 1329 * if the execution of a command fails 1330 * @querycommands 1 1331 * @see Client#getDatabaseId() 1332 * @see #getDatabaseClientInfo(int) 1333 * @see DatabaseClientInfo 1334 */ 1335 public CommandFuture<Void> deleteDatabaseClientProperties(int clientDBId) { 1336 Command cmd = DatabaseClientCommands.clientDBDelete(clientDBId); 1337 return executeAndReturnError(cmd); 1338 } 1339 1340 /** 1341 * Deletes a file or directory from the file repository in the specified channel. 1342 * 1343 * @param filePath 1344 * the path to the file or directory 1345 * @param channelId 1346 * the ID of the channel the file or directory resides in 1347 * 1348 * @return a future to track the progress of this command 1349 * 1350 * @throws TS3CommandFailedException 1351 * if the execution of a command fails 1352 * @querycommands 1 1353 * @see FileInfo#getPath() 1354 * @see Channel#getId() 1355 */ 1356 public CommandFuture<Void> deleteFile(String filePath, int channelId) { 1357 return deleteFile(filePath, channelId, null); 1358 } 1359 1360 /** 1361 * Deletes a file or directory from the file repository in the specified channel. 1362 * 1363 * @param filePath 1364 * the path to the file or directory 1365 * @param channelId 1366 * the ID of the channel the file or directory resides in 1367 * @param channelPassword 1368 * the password of that channel 1369 * 1370 * @return a future to track the progress of this command 1371 * 1372 * @throws TS3CommandFailedException 1373 * if the execution of a command fails 1374 * @querycommands 1 1375 * @see FileInfo#getPath() 1376 * @see Channel#getId() 1377 */ 1378 public CommandFuture<Void> deleteFile(String filePath, int channelId, String channelPassword) { 1379 Command cmd = FileCommands.ftDeleteFile(channelId, channelPassword, filePath); 1380 return executeAndReturnError(cmd); 1381 } 1382 1383 /** 1384 * Deletes multiple files or directories from the file repository in the specified channel. 1385 * 1386 * @param filePaths 1387 * the paths to the files or directories 1388 * @param channelId 1389 * the ID of the channel the file or directory resides in 1390 * 1391 * @return a future to track the progress of this command 1392 * 1393 * @throws TS3CommandFailedException 1394 * if the execution of a command fails 1395 * @querycommands 1 1396 * @see FileInfo#getPath() 1397 * @see Channel#getId() 1398 */ 1399 public CommandFuture<Void> deleteFiles(String[] filePaths, int channelId) { 1400 return deleteFiles(filePaths, channelId, null); 1401 } 1402 1403 /** 1404 * Deletes multiple files or directories from the file repository in the specified channel. 1405 * 1406 * @param filePaths 1407 * the paths to the files or directories 1408 * @param channelId 1409 * the ID of the channel the file or directory resides in 1410 * @param channelPassword 1411 * the password of that channel 1412 * 1413 * @return a future to track the progress of this command 1414 * 1415 * @throws TS3CommandFailedException 1416 * if the execution of a command fails 1417 * @querycommands 1 1418 * @see FileInfo#getPath() 1419 * @see Channel#getId() 1420 */ 1421 public CommandFuture<Void> deleteFiles(String[] filePaths, int channelId, String channelPassword) { 1422 Command cmd = FileCommands.ftDeleteFile(channelId, channelPassword, filePaths); 1423 return executeAndReturnError(cmd); 1424 } 1425 1426 /** 1427 * Deletes an icon from the icon directory in the file repository. 1428 * 1429 * @param iconId 1430 * the ID of the icon to delete 1431 * 1432 * @return a future to track the progress of this command 1433 * 1434 * @throws TS3CommandFailedException 1435 * if the execution of a command fails 1436 * @querycommands 1 1437 * @see IconFile#getIconId() 1438 */ 1439 public CommandFuture<Void> deleteIcon(long iconId) { 1440 String iconPath = "/icon_" + iconId; 1441 return deleteFile(iconPath, 0); 1442 } 1443 1444 /** 1445 * Deletes multiple icons from the icon directory in the file repository. 1446 * 1447 * @param iconIds 1448 * the IDs of the icons to delete 1449 * 1450 * @return a future to track the progress of this command 1451 * 1452 * @throws TS3CommandFailedException 1453 * if the execution of a command fails 1454 * @querycommands 1 1455 * @see IconFile#getIconId() 1456 */ 1457 public CommandFuture<Void> deleteIcons(long... iconIds) { 1458 String[] iconPaths = new String[iconIds.length]; 1459 for (int i = 0; i < iconIds.length; ++i) { 1460 iconPaths[i] = "/icon_" + iconIds[i]; 1461 } 1462 return deleteFiles(iconPaths, 0); 1463 } 1464 1465 /** 1466 * Deletes the offline message with the specified ID. 1467 * 1468 * @param messageId 1469 * the ID of the offline message to delete 1470 * 1471 * @return a future to track the progress of this command 1472 * 1473 * @throws TS3CommandFailedException 1474 * if the execution of a command fails 1475 * @querycommands 1 1476 * @see Message#getId() 1477 */ 1478 public CommandFuture<Void> deleteOfflineMessage(int messageId) { 1479 Command cmd = MessageCommands.messageDel(messageId); 1480 return executeAndReturnError(cmd); 1481 } 1482 1483 /** 1484 * Removes a specified permission from all server groups of the type specified by {@code type} on all virtual servers. 1485 * 1486 * @param type 1487 * the kind of server group this permission should be removed from 1488 * @param permName 1489 * the name of the permission to remove 1490 * 1491 * @return a future to track the progress of this command 1492 * 1493 * @throws TS3CommandFailedException 1494 * if the execution of a command fails 1495 * @querycommands 1 1496 * @see ServerGroupType 1497 * @see Permission#getName() 1498 */ 1499 public CommandFuture<Void> deletePermissionFromAllServerGroups(ServerGroupType type, String permName) { 1500 Command cmd = PermissionCommands.serverGroupAutoDelPerm(type, permName); 1501 return executeAndReturnError(cmd); 1502 } 1503 1504 /** 1505 * Deletes the privilege key with the given token. 1506 * 1507 * @param token 1508 * the token of the privilege key 1509 * 1510 * @return a future to track the progress of this command 1511 * 1512 * @throws TS3CommandFailedException 1513 * if the execution of a command fails 1514 * @querycommands 1 1515 * @see PrivilegeKey 1516 */ 1517 public CommandFuture<Void> deletePrivilegeKey(String token) { 1518 Command cmd = PrivilegeKeyCommands.privilegeKeyDelete(token); 1519 return executeAndReturnError(cmd); 1520 } 1521 1522 /** 1523 * Deletes the virtual server with the specified ID. 1524 * <p> 1525 * Only stopped virtual servers can be deleted. 1526 * </p> 1527 * 1528 * @param serverId 1529 * the ID of the virtual server 1530 * 1531 * @return a future to track the progress of this command 1532 * 1533 * @throws TS3CommandFailedException 1534 * if the execution of a command fails 1535 * @querycommands 1 1536 * @see VirtualServer#getId() 1537 * @see #stopServer(int) 1538 */ 1539 public CommandFuture<Void> deleteServer(int serverId) { 1540 Command cmd = VirtualServerCommands.serverDelete(serverId); 1541 return executeAndReturnError(cmd); 1542 } 1543 1544 /** 1545 * Deletes the server group with the specified ID, even if the server group still contains clients. 1546 * 1547 * @param groupId 1548 * the ID of the server group 1549 * 1550 * @return a future to track the progress of this command 1551 * 1552 * @throws TS3CommandFailedException 1553 * if the execution of a command fails 1554 * @querycommands 1 1555 * @see ServerGroup#getId() 1556 */ 1557 public CommandFuture<Void> deleteServerGroup(int groupId) { 1558 return deleteServerGroup(groupId, true); 1559 } 1560 1561 /** 1562 * Deletes a server group with the specified ID. 1563 * <p> 1564 * If {@code force} is true, the server group will be deleted even if it contains clients, 1565 * else the command will fail in this situation. 1566 * </p> 1567 * 1568 * @param groupId 1569 * the ID of the server group 1570 * @param force 1571 * whether the server group should be deleted if it still contains clients 1572 * 1573 * @return a future to track the progress of this command 1574 * 1575 * @throws TS3CommandFailedException 1576 * if the execution of a command fails 1577 * @querycommands 1 1578 * @see ServerGroup#getId() 1579 */ 1580 public CommandFuture<Void> deleteServerGroup(int groupId, boolean force) { 1581 Command cmd = ServerGroupCommands.serverGroupDel(groupId, force); 1582 return executeAndReturnError(cmd); 1583 } 1584 1585 /** 1586 * Removes a permission from the server group with the given ID. 1587 * 1588 * @param groupId 1589 * the ID of the server group 1590 * @param permName 1591 * the name of the permission to revoke 1592 * 1593 * @return a future to track the progress of this command 1594 * 1595 * @throws TS3CommandFailedException 1596 * if the execution of a command fails 1597 * @querycommands 1 1598 * @see ServerGroup#getId() 1599 * @see Permission#getName() 1600 */ 1601 public CommandFuture<Void> deleteServerGroupPermission(int groupId, String permName) { 1602 Command cmd = PermissionCommands.serverGroupDelPerm(groupId, permName); 1603 return executeAndReturnError(cmd); 1604 } 1605 1606 /** 1607 * Deletes the server query login with the specified client database ID. 1608 * <p> 1609 * If you only know the name of the server query login, use {@link #getServerQueryLoginsByName(String)} first. 1610 * </p> 1611 * 1612 * @param clientDBId 1613 * the client database ID of the server query login (usually the ID of the associated client) 1614 * 1615 * @return a future to track the progress of this command 1616 * 1617 * @throws TS3CommandFailedException 1618 * if the execution of a command fails 1619 * @querycommands 1 1620 * @see #addServerQueryLogin(String, int) 1621 * @see #getServerQueryLogins() 1622 * @see #updateServerQueryLogin(String) 1623 */ 1624 public CommandFuture<Void> deleteServerQueryLogin(int clientDBId) { 1625 Command cmd = QueryLoginCommands.queryLoginDel(clientDBId); 1626 return executeAndReturnError(cmd); 1627 } 1628 1629 /** 1630 * Restores the selected virtual servers configuration using the data from a 1631 * previously created server snapshot. 1632 * 1633 * @param snapshot 1634 * the snapshot to restore 1635 * 1636 * @return a future to track the progress of this command 1637 * 1638 * @throws TS3CommandFailedException 1639 * if the execution of a command fails 1640 * @querycommands 1 1641 * @see #createServerSnapshot() 1642 */ 1643 public CommandFuture<Void> deployServerSnapshot(Snapshot snapshot) { 1644 return deployServerSnapshot(snapshot.get()); 1645 } 1646 1647 /** 1648 * Restores the configuration of the selected virtual server using the data from a 1649 * previously created server snapshot. 1650 * 1651 * @param snapshot 1652 * the snapshot to restore 1653 * 1654 * @return a future to track the progress of this command 1655 * 1656 * @throws TS3CommandFailedException 1657 * if the execution of a command fails 1658 * @querycommands 1 1659 * @see #createServerSnapshot() 1660 */ 1661 public CommandFuture<Void> deployServerSnapshot(String snapshot) { 1662 Command cmd = VirtualServerCommands.serverSnapshotDeploy(snapshot); 1663 return executeAndReturnError(cmd); 1664 } 1665 1666 /** 1667 * Downloads a file from the file repository at a given path and channel 1668 * and writes the file's bytes to an open {@link OutputStream}. 1669 * <p> 1670 * It is the user's responsibility to ensure that the given {@code OutputStream} is 1671 * open and to close the stream again once the download has finished. 1672 * </p><p> 1673 * Note that this method will not read the entire file to memory and can thus 1674 * download arbitrarily sized files from the file repository. 1675 * </p> 1676 * 1677 * @param dataOut 1678 * a stream that the downloaded data should be written to 1679 * @param filePath 1680 * the path of the file on the file repository 1681 * @param channelId 1682 * the ID of the channel to download the file from 1683 * 1684 * @return how many bytes were downloaded 1685 * 1686 * @throws TS3CommandFailedException 1687 * if the execution of a command fails 1688 * @throws TS3FileTransferFailedException 1689 * if the file transfer fails for any reason 1690 * @querycommands 1 1691 * @see FileInfo#getPath() 1692 * @see Channel#getId() 1693 * @see #downloadFileDirect(String, int) 1694 */ 1695 public CommandFuture<Long> downloadFile(OutputStream dataOut, String filePath, int channelId) { 1696 return downloadFile(dataOut, filePath, channelId, null); 1697 } 1698 1699 /** 1700 * Downloads a file from the file repository at a given path and channel 1701 * and writes the file's bytes to an open {@link OutputStream}. 1702 * <p> 1703 * It is the user's responsibility to ensure that the given {@code OutputStream} is 1704 * open and to close the stream again once the download has finished. 1705 * </p><p> 1706 * Note that this method will not read the entire file to memory and can thus 1707 * download arbitrarily sized files from the file repository. 1708 * </p> 1709 * 1710 * @param dataOut 1711 * a stream that the downloaded data should be written to 1712 * @param filePath 1713 * the path of the file on the file repository 1714 * @param channelId 1715 * the ID of the channel to download the file from 1716 * @param channelPassword 1717 * that channel's password 1718 * 1719 * @return how many bytes were downloaded 1720 * 1721 * @throws TS3CommandFailedException 1722 * if the execution of a command fails 1723 * @throws TS3FileTransferFailedException 1724 * if the file transfer fails for any reason 1725 * @querycommands 1 1726 * @see FileInfo#getPath() 1727 * @see Channel#getId() 1728 * @see #downloadFileDirect(String, int, String) 1729 */ 1730 public CommandFuture<Long> downloadFile(OutputStream dataOut, String filePath, int channelId, String channelPassword) { 1731 FileTransferHelper helper = query.getFileTransferHelper(); 1732 int transferId = helper.getClientTransferId(); 1733 Command cmd = FileCommands.ftInitDownload(transferId, filePath, channelId, channelPassword); 1734 CommandFuture<Long> future = new CommandFuture<>(); 1735 1736 executeAndTransformFirst(cmd, FileTransferParameters::new).onSuccess(params -> { 1737 QueryError error = params.getQueryError(); 1738 if (!error.isSuccessful()) { 1739 future.fail(new TS3CommandFailedException(error, cmd.getName())); 1740 return; 1741 } 1742 1743 try { 1744 query.getFileTransferHelper().downloadFile(dataOut, params); 1745 } catch (IOException e) { 1746 future.fail(new TS3FileTransferFailedException("Download failed", e)); 1747 return; 1748 } 1749 future.set(params.getFileSize()); 1750 }).forwardFailure(future); 1751 1752 return future; 1753 } 1754 1755 /** 1756 * Downloads a file from the file repository at a given path and channel 1757 * and returns the file's bytes as a byte array. 1758 * <p> 1759 * Note that this method <strong>will read the entire file to memory</strong>. 1760 * That means that if a file is larger than 2<sup>31</sup>-1 bytes in size, 1761 * the download will fail. 1762 * </p> 1763 * 1764 * @param filePath 1765 * the path of the file on the file repository 1766 * @param channelId 1767 * the ID of the channel to download the file from 1768 * 1769 * @return a byte array containing the file's data 1770 * 1771 * @throws TS3CommandFailedException 1772 * if the execution of a command fails 1773 * @throws TS3FileTransferFailedException 1774 * if the file transfer fails for any reason 1775 * @querycommands 1 1776 * @see FileInfo#getPath() 1777 * @see Channel#getId() 1778 * @see #downloadFile(OutputStream, String, int) 1779 */ 1780 public CommandFuture<byte[]> downloadFileDirect(String filePath, int channelId) { 1781 return downloadFileDirect(filePath, channelId, null); 1782 } 1783 1784 /** 1785 * Downloads a file from the file repository at a given path and channel 1786 * and returns the file's bytes as a byte array. 1787 * <p> 1788 * Note that this method <strong>will read the entire file to memory</strong>. 1789 * That means that if a file is larger than 2<sup>31</sup>-1 bytes in size, 1790 * the download will fail. 1791 * </p> 1792 * 1793 * @param filePath 1794 * the path of the file on the file repository 1795 * @param channelId 1796 * the ID of the channel to download the file from 1797 * @param channelPassword 1798 * that channel's password 1799 * 1800 * @return a byte array containing the file's data 1801 * 1802 * @throws TS3CommandFailedException 1803 * if the execution of a command fails 1804 * @throws TS3FileTransferFailedException 1805 * if the file transfer fails for any reason 1806 * @querycommands 1 1807 * @see FileInfo#getPath() 1808 * @see Channel#getId() 1809 * @see #downloadFile(OutputStream, String, int, String) 1810 */ 1811 public CommandFuture<byte[]> downloadFileDirect(String filePath, int channelId, String channelPassword) { 1812 FileTransferHelper helper = query.getFileTransferHelper(); 1813 int transferId = helper.getClientTransferId(); 1814 Command cmd = FileCommands.ftInitDownload(transferId, filePath, channelId, channelPassword); 1815 CommandFuture<byte[]> future = new CommandFuture<>(); 1816 1817 executeAndTransformFirst(cmd, FileTransferParameters::new).onSuccess(params -> { 1818 QueryError error = params.getQueryError(); 1819 if (!error.isSuccessful()) { 1820 future.fail(new TS3CommandFailedException(error, cmd.getName())); 1821 return; 1822 } 1823 1824 long fileSize = params.getFileSize(); 1825 if (fileSize > Integer.MAX_VALUE) { 1826 future.fail(new TS3FileTransferFailedException("File too big for byte array")); 1827 return; 1828 } 1829 ByteArrayOutputStream dataOut = new ByteArrayOutputStream((int) fileSize); 1830 1831 try { 1832 query.getFileTransferHelper().downloadFile(dataOut, params); 1833 } catch (IOException e) { 1834 future.fail(new TS3FileTransferFailedException("Download failed", e)); 1835 return; 1836 } 1837 future.set(dataOut.toByteArray()); 1838 }).forwardFailure(future); 1839 1840 return future; 1841 } 1842 1843 /** 1844 * Downloads an icon from the icon directory in the file repository 1845 * and writes the file's bytes to an open {@link OutputStream}. 1846 * <p> 1847 * It is the user's responsibility to ensure that the given {@code OutputStream} is 1848 * open and to close the stream again once the download has finished. 1849 * </p> 1850 * 1851 * @param dataOut 1852 * a stream that the downloaded data should be written to 1853 * @param iconId 1854 * the ID of the icon that should be downloaded 1855 * 1856 * @return a byte array containing the icon file's data 1857 * 1858 * @throws TS3CommandFailedException 1859 * if the execution of a command fails 1860 * @throws TS3FileTransferFailedException 1861 * if the file transfer fails for any reason 1862 * @querycommands 1 1863 * @see IconFile#getIconId() 1864 * @see #downloadIconDirect(long) 1865 * @see #uploadIcon(InputStream, long) 1866 */ 1867 public CommandFuture<Long> downloadIcon(OutputStream dataOut, long iconId) { 1868 String iconPath = "/icon_" + iconId; 1869 return downloadFile(dataOut, iconPath, 0); 1870 } 1871 1872 /** 1873 * Downloads an icon from the icon directory in the file repository 1874 * and returns the file's bytes as a byte array. 1875 * <p> 1876 * Note that this method <strong>will read the entire file to memory</strong>. 1877 * </p> 1878 * 1879 * @param iconId 1880 * the ID of the icon that should be downloaded 1881 * 1882 * @return a byte array containing the icon file's data 1883 * 1884 * @throws TS3CommandFailedException 1885 * if the execution of a command fails 1886 * @throws TS3FileTransferFailedException 1887 * if the file transfer fails for any reason 1888 * @querycommands 1 1889 * @see IconFile#getIconId() 1890 * @see #downloadIcon(OutputStream, long) 1891 * @see #uploadIconDirect(byte[]) 1892 */ 1893 public CommandFuture<byte[]> downloadIconDirect(long iconId) { 1894 String iconPath = "/icon_" + iconId; 1895 return downloadFileDirect(iconPath, 0); 1896 } 1897 1898 /** 1899 * Changes a channel's configuration using the given properties. 1900 * 1901 * @param channelId 1902 * the ID of the channel to edit 1903 * @param options 1904 * the map of properties to modify 1905 * 1906 * @return a future to track the progress of this command 1907 * 1908 * @throws TS3CommandFailedException 1909 * if the execution of a command fails 1910 * @querycommands 1 1911 * @see Channel#getId() 1912 */ 1913 public CommandFuture<Void> editChannel(int channelId, Map<ChannelProperty, String> options) { 1914 Command cmd = ChannelCommands.channelEdit(channelId, options); 1915 return executeAndReturnError(cmd); 1916 } 1917 1918 /** 1919 * Changes a single property of the given channel. 1920 * <p> 1921 * Note that one can set many properties at once with the overloaded method that 1922 * takes a map of channel properties and strings. 1923 * </p> 1924 * 1925 * @param channelId 1926 * the ID of the channel to edit 1927 * @param property 1928 * the channel property to modify, make sure it is editable 1929 * @param value 1930 * the new value of the property 1931 * 1932 * @return a future to track the progress of this command 1933 * 1934 * @throws TS3CommandFailedException 1935 * if the execution of a command fails 1936 * @querycommands 1 1937 * @see Channel#getId() 1938 * @see #editChannel(int, Map) 1939 */ 1940 public CommandFuture<Void> editChannel(int channelId, ChannelProperty property, String value) { 1941 return editChannel(channelId, Collections.singletonMap(property, value)); 1942 } 1943 1944 /** 1945 * Changes a client's configuration using given properties. 1946 * <p> 1947 * Only {@link ClientProperty#CLIENT_DESCRIPTION} can be changed for other clients. 1948 * To update the current client's properties, use {@link #updateClient(Map)} 1949 * or {@link #updateClient(ClientProperty, String)}. 1950 * </p> 1951 * 1952 * @param clientId 1953 * the ID of the client to edit 1954 * @param options 1955 * the map of properties to modify 1956 * 1957 * @return a future to track the progress of this command 1958 * 1959 * @throws TS3CommandFailedException 1960 * if the execution of a command fails 1961 * @querycommands 1 1962 * @see Client#getId() 1963 * @see #updateClient(Map) 1964 */ 1965 public CommandFuture<Void> editClient(int clientId, Map<ClientProperty, String> options) { 1966 Command cmd = ClientCommands.clientEdit(clientId, options); 1967 return executeAndReturnError(cmd); 1968 } 1969 1970 /** 1971 * Changes a single property of the given client. 1972 * <p> 1973 * Only {@link ClientProperty#CLIENT_DESCRIPTION} can be changed for other clients. 1974 * To update the current client's properties, use {@link #updateClient(Map)} 1975 * or {@link #updateClient(ClientProperty, String)}. 1976 * </p> 1977 * 1978 * @param clientId 1979 * the ID of the client to edit 1980 * @param property 1981 * the client property to modify, make sure it is editable 1982 * @param value 1983 * the new value of the property 1984 * 1985 * @return a future to track the progress of this command 1986 * 1987 * @throws TS3CommandFailedException 1988 * if the execution of a command fails 1989 * @querycommands 1 1990 * @see Client#getId() 1991 * @see #editClient(int, Map) 1992 * @see #updateClient(Map) 1993 */ 1994 public CommandFuture<Void> editClient(int clientId, ClientProperty property, String value) { 1995 return editClient(clientId, Collections.singletonMap(property, value)); 1996 } 1997 1998 /** 1999 * Changes a client's database settings using given properties. 2000 * 2001 * @param clientDBId 2002 * the database ID of the client to edit 2003 * @param options 2004 * the map of properties to modify 2005 * 2006 * @return a future to track the progress of this command 2007 * 2008 * @throws TS3CommandFailedException 2009 * if the execution of a command fails 2010 * @querycommands 1 2011 * @see DatabaseClientInfo 2012 * @see Client#getDatabaseId() 2013 */ 2014 public CommandFuture<Void> editDatabaseClient(int clientDBId, Map<ClientProperty, String> options) { 2015 Command cmd = DatabaseClientCommands.clientDBEdit(clientDBId, options); 2016 return executeAndReturnError(cmd); 2017 } 2018 2019 /** 2020 * Changes the server instance configuration using given properties. 2021 * If the given property is not changeable, {@code IllegalArgumentException} will be thrown. 2022 * 2023 * @param property 2024 * the property to edit, must be changeable 2025 * @param value 2026 * the new value for the edit 2027 * 2028 * @return a future to track the progress of this command 2029 * 2030 * @throws IllegalArgumentException 2031 * if {@code property} is not changeable 2032 * @throws TS3CommandFailedException 2033 * if the execution of a command fails 2034 * @querycommands 1 2035 * @see ServerInstanceProperty#isChangeable() 2036 */ 2037 public CommandFuture<Void> editInstance(ServerInstanceProperty property, String value) { 2038 Command cmd = ServerCommands.instanceEdit(Collections.singletonMap(property, value)); 2039 return executeAndReturnError(cmd); 2040 } 2041 2042 /** 2043 * Changes the configuration of the selected virtual server using given properties. 2044 * 2045 * @param options 2046 * the map of properties to edit 2047 * 2048 * @return a future to track the progress of this command 2049 * 2050 * @throws TS3CommandFailedException 2051 * if the execution of a command fails 2052 * @querycommands 1 2053 * @see VirtualServerProperty 2054 */ 2055 public CommandFuture<Void> editServer(Map<VirtualServerProperty, String> options) { 2056 Command cmd = VirtualServerCommands.serverEdit(options); 2057 return executeAndReturnError(cmd); 2058 } 2059 2060 /** 2061 * Gets a list of all bans on the selected virtual server. 2062 * 2063 * @return a list of all bans on the virtual server 2064 * 2065 * @throws TS3CommandFailedException 2066 * if the execution of a command fails 2067 * @querycommands 1 2068 * @see Ban 2069 */ 2070 public CommandFuture<List<Ban>> getBans() { 2071 Command cmd = BanCommands.banList(); 2072 return executeAndTransform(cmd, Ban::new); 2073 } 2074 2075 /** 2076 * Gets a list of IP addresses used by the server instance. 2077 * 2078 * @return the list of bound IP addresses 2079 * 2080 * @throws TS3CommandFailedException 2081 * if the execution of a command fails 2082 * @querycommands 1 2083 * @see Binding 2084 */ 2085 public CommandFuture<List<Binding>> getBindings() { 2086 Command cmd = ServerCommands.bindingList(); 2087 return executeAndTransform(cmd, Binding::new); 2088 } 2089 2090 /** 2091 * Finds and returns the channel matching the given name exactly. 2092 * 2093 * @param name 2094 * the name of the channel 2095 * @param ignoreCase 2096 * whether the case of the name should be ignored 2097 * 2098 * @return the found channel or {@code null} if no channel was found 2099 * 2100 * @throws TS3CommandFailedException 2101 * if the execution of a command fails 2102 * @querycommands 1 2103 * @see Channel 2104 * @see #getChannelsByName(String) 2105 */ 2106 public CommandFuture<Channel> getChannelByNameExact(String name, boolean ignoreCase) { 2107 String caseName = ignoreCase ? name.toLowerCase(Locale.ROOT) : name; 2108 2109 return getChannels().map(allChannels -> { 2110 for (Channel c : allChannels) { 2111 String channelName = ignoreCase ? c.getName().toLowerCase(Locale.ROOT) : c.getName(); 2112 if (caseName.equals(channelName)) return c; 2113 } 2114 return null; // Not found 2115 }); 2116 } 2117 2118 /** 2119 * Gets a list of channels whose names contain the given search string. 2120 * 2121 * @param name 2122 * the name to search 2123 * 2124 * @return a list of all channels with names matching the search pattern 2125 * 2126 * @throws TS3CommandFailedException 2127 * if the execution of a command fails 2128 * @querycommands 2 2129 * @see Channel 2130 * @see #getChannelByNameExact(String, boolean) 2131 */ 2132 public CommandFuture<List<Channel>> getChannelsByName(String name) { 2133 Command cmd = ChannelCommands.channelFind(name); 2134 CommandFuture<List<Channel>> future = new CommandFuture<>(); 2135 2136 CommandFuture<List<Integer>> channelIds = executeAndMap(cmd, response -> response.getInt("cid")); 2137 CommandFuture<List<Channel>> allChannels = getChannels(); 2138 2139 findByKey(channelIds, allChannels, Channel::getId) 2140 .forwardSuccess(future) 2141 .onFailure(transformError(future, 768, Collections.emptyList())); 2142 2143 return future; 2144 } 2145 2146 /** 2147 * Displays a list of permissions defined for a client in a specific channel. 2148 * 2149 * @param channelId 2150 * the ID of the channel 2151 * @param clientDBId 2152 * the database ID of the client 2153 * 2154 * @return a list of permissions for the user in the specified channel 2155 * 2156 * @throws TS3CommandFailedException 2157 * if the execution of a command fails 2158 * @querycommands 1 2159 * @see Channel#getId() 2160 * @see Client#getDatabaseId() 2161 * @see Permission 2162 */ 2163 public CommandFuture<List<Permission>> getChannelClientPermissions(int channelId, int clientDBId) { 2164 Command cmd = PermissionCommands.channelClientPermList(channelId, clientDBId); 2165 return executeAndTransform(cmd, Permission::new); 2166 } 2167 2168 /** 2169 * Gets all client / channel ID combinations currently assigned to channel groups. 2170 * All three parameters are optional and can be turned off by setting it to {@code -1}. 2171 * 2172 * @param channelId 2173 * restricts the search to the channel with a specified ID. Set to {@code -1} to ignore. 2174 * @param clientDBId 2175 * restricts the search to the client with a specified database ID. Set to {@code -1} to ignore. 2176 * @param groupId 2177 * restricts the search to the channel group with the specified ID. Set to {@code -1} to ignore. 2178 * 2179 * @return a list of combinations of channel ID, client database ID and channel group ID 2180 * 2181 * @throws TS3CommandFailedException 2182 * if the execution of a command fails 2183 * @querycommands 1 2184 * @see Channel#getId() 2185 * @see Client#getDatabaseId() 2186 * @see ChannelGroup#getId() 2187 * @see ChannelGroupClient 2188 */ 2189 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClients(int channelId, int clientDBId, int groupId) { 2190 Command cmd = ChannelGroupCommands.channelGroupClientList(channelId, clientDBId, groupId); 2191 return executeAndTransform(cmd, ChannelGroupClient::new); 2192 } 2193 2194 /** 2195 * Gets all client / channel ID combinations currently assigned to the specified channel group. 2196 * 2197 * @param groupId 2198 * the ID of the channel group whose client / channel assignments should be returned. 2199 * 2200 * @return a list of combinations of channel ID, client database ID and channel group ID 2201 * 2202 * @throws TS3CommandFailedException 2203 * if the execution of a command fails 2204 * @querycommands 1 2205 * @see ChannelGroup#getId() 2206 * @see ChannelGroupClient 2207 * @see #getChannelGroupClients(int, int, int) 2208 */ 2209 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClientsByChannelGroupId(int groupId) { 2210 return getChannelGroupClients(-1, -1, groupId); 2211 } 2212 2213 /** 2214 * Gets all channel group assignments in the specified channel. 2215 * 2216 * @param channelId 2217 * the ID of the channel whose channel group assignments should be returned. 2218 * 2219 * @return a list of combinations of channel ID, client database ID and channel group ID 2220 * 2221 * @throws TS3CommandFailedException 2222 * if the execution of a command fails 2223 * @querycommands 1 2224 * @see Channel#getId() 2225 * @see ChannelGroupClient 2226 * @see #getChannelGroupClients(int, int, int) 2227 */ 2228 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClientsByChannelId(int channelId) { 2229 return getChannelGroupClients(channelId, -1, -1); 2230 } 2231 2232 /** 2233 * Gets all channel group assignments for the specified client. 2234 * 2235 * @param clientDBId 2236 * the database ID of the client whose channel group 2237 * 2238 * @return a list of combinations of channel ID, client database ID and channel group ID 2239 * 2240 * @throws TS3CommandFailedException 2241 * if the execution of a command fails 2242 * @querycommands 1 2243 * @see Client#getDatabaseId() 2244 * @see ChannelGroupClient 2245 * @see #getChannelGroupClients(int, int, int) 2246 */ 2247 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClientsByClientDBId(int clientDBId) { 2248 return getChannelGroupClients(-1, clientDBId, -1); 2249 } 2250 2251 /** 2252 * Gets a list of all permissions assigned to the specified channel group. 2253 * 2254 * @param groupId 2255 * the ID of the channel group. 2256 * 2257 * @return a list of permissions assigned to the channel group 2258 * 2259 * @throws TS3CommandFailedException 2260 * if the execution of a command fails 2261 * @querycommands 1 2262 * @see ChannelGroup#getId() 2263 * @see Permission 2264 */ 2265 public CommandFuture<List<Permission>> getChannelGroupPermissions(int groupId) { 2266 Command cmd = PermissionCommands.channelGroupPermList(groupId); 2267 return executeAndTransform(cmd, Permission::new); 2268 } 2269 2270 /** 2271 * Gets a list of all channel groups on the selected virtual server. 2272 * 2273 * @return a list of all channel groups on the virtual server 2274 * 2275 * @throws TS3CommandFailedException 2276 * if the execution of a command fails 2277 * @querycommands 1 2278 * @see ChannelGroup 2279 */ 2280 public CommandFuture<List<ChannelGroup>> getChannelGroups() { 2281 Command cmd = ChannelGroupCommands.channelGroupList(); 2282 return executeAndTransform(cmd, ChannelGroup::new); 2283 } 2284 2285 /** 2286 * Gets detailed configuration information about the channel specified channel. 2287 * 2288 * @param channelId 2289 * the ID of the channel 2290 * 2291 * @return information about the channel 2292 * 2293 * @throws TS3CommandFailedException 2294 * if the execution of a command fails 2295 * @querycommands 1 2296 * @see Channel#getId() 2297 * @see ChannelInfo 2298 */ 2299 public CommandFuture<ChannelInfo> getChannelInfo(int channelId) { 2300 Command cmd = ChannelCommands.channelInfo(channelId); 2301 return executeAndTransformFirst(cmd, map -> new ChannelInfo(channelId, map)); 2302 } 2303 2304 /** 2305 * Gets a list of all permissions assigned to the specified channel. 2306 * 2307 * @param channelId 2308 * the ID of the channel 2309 * 2310 * @return a list of all permissions assigned to the channel 2311 * 2312 * @throws TS3CommandFailedException 2313 * if the execution of a command fails 2314 * @querycommands 1 2315 * @see Channel#getId() 2316 * @see Permission 2317 */ 2318 public CommandFuture<List<Permission>> getChannelPermissions(int channelId) { 2319 Command cmd = PermissionCommands.channelPermList(channelId); 2320 return executeAndTransform(cmd, Permission::new); 2321 } 2322 2323 /** 2324 * Gets a list of all channels on the selected virtual server. 2325 * 2326 * @return a list of all channels on the virtual server 2327 * 2328 * @throws TS3CommandFailedException 2329 * if the execution of a command fails 2330 * @querycommands 1 2331 * @see Channel 2332 */ 2333 public CommandFuture<List<Channel>> getChannels() { 2334 Command cmd = ChannelCommands.channelList(); 2335 return executeAndTransform(cmd, Channel::new); 2336 } 2337 2338 /** 2339 * Finds and returns the client whose nickname matches the given name exactly. 2340 * 2341 * @param name 2342 * the name of the client 2343 * @param ignoreCase 2344 * whether the case of the name should be ignored 2345 * 2346 * @return the found client or {@code null} if no client was found 2347 * 2348 * @throws TS3CommandFailedException 2349 * if the execution of a command fails 2350 * @querycommands 1 2351 * @see Client 2352 * @see #getClientsByName(String) 2353 */ 2354 public CommandFuture<Client> getClientByNameExact(String name, boolean ignoreCase) { 2355 String caseName = ignoreCase ? name.toLowerCase(Locale.ROOT) : name; 2356 2357 return getClients().map(allClients -> { 2358 for (Client c : allClients) { 2359 String clientName = ignoreCase ? c.getNickname().toLowerCase(Locale.ROOT) : c.getNickname(); 2360 if (caseName.equals(clientName)) return c; 2361 } 2362 return null; // Not found 2363 }); 2364 } 2365 2366 /** 2367 * Gets a list of clients whose nicknames contain the given search string. 2368 * 2369 * @param name 2370 * the name to search 2371 * 2372 * @return a list of all clients with nicknames matching the search pattern 2373 * 2374 * @throws TS3CommandFailedException 2375 * if the execution of a command fails 2376 * @querycommands 2 2377 * @see Client 2378 * @see #getClientByNameExact(String, boolean) 2379 */ 2380 public CommandFuture<List<Client>> getClientsByName(String name) { 2381 Command cmd = ClientCommands.clientFind(name); 2382 CommandFuture<List<Client>> future = new CommandFuture<>(); 2383 2384 CommandFuture<List<Integer>> clientIds = executeAndMap(cmd, response -> response.getInt("clid")); 2385 CommandFuture<List<Client>> allClients = getClients(); 2386 2387 findByKey(clientIds, allClients, Client::getId) 2388 .forwardSuccess(future) 2389 .onFailure(transformError(future, 512, Collections.emptyList())); 2390 2391 return future; 2392 } 2393 2394 /** 2395 * Gets information about the client with the specified unique identifier. 2396 * 2397 * @param clientUId 2398 * the unique identifier of the client 2399 * 2400 * @return information about the client 2401 * 2402 * @throws TS3CommandFailedException 2403 * if the execution of a command fails 2404 * @querycommands 2 2405 * @see Client#getUniqueIdentifier() 2406 * @see ClientInfo 2407 */ 2408 public CommandFuture<ClientInfo> getClientByUId(String clientUId) { 2409 Command cmd = ClientCommands.clientGetIds(clientUId); 2410 return executeAndReturnIntProperty(cmd, "clid") 2411 .then(this::getClientInfo); 2412 } 2413 2414 /** 2415 * Gets information about the client with the specified client ID. 2416 * 2417 * @param clientId 2418 * the client ID of the client 2419 * 2420 * @return information about the client 2421 * 2422 * @throws TS3CommandFailedException 2423 * if the execution of a command fails 2424 * @querycommands 1 2425 * @see Client#getId() 2426 * @see ClientInfo 2427 */ 2428 public CommandFuture<ClientInfo> getClientInfo(int clientId) { 2429 Command cmd = ClientCommands.clientInfo(clientId); 2430 return executeAndTransformFirst(cmd, map -> new ClientInfo(clientId, map)); 2431 } 2432 2433 /** 2434 * Gets a list of all permissions assigned to the specified client. 2435 * 2436 * @param clientDBId 2437 * the database ID of the client 2438 * 2439 * @return a list of all permissions assigned to the client 2440 * 2441 * @throws TS3CommandFailedException 2442 * if the execution of a command fails 2443 * @querycommands 1 2444 * @see Client#getDatabaseId() 2445 * @see Permission 2446 */ 2447 public CommandFuture<List<Permission>> getClientPermissions(int clientDBId) { 2448 Command cmd = PermissionCommands.clientPermList(clientDBId); 2449 return executeAndTransform(cmd, Permission::new); 2450 } 2451 2452 /** 2453 * Gets a list of all clients on the selected virtual server. 2454 * 2455 * @return a list of all clients on the virtual server 2456 * 2457 * @throws TS3CommandFailedException 2458 * if the execution of a command fails 2459 * @querycommands 1 2460 * @see Client 2461 */ 2462 public CommandFuture<List<Client>> getClients() { 2463 Command cmd = ClientCommands.clientList(); 2464 return executeAndTransform(cmd, Client::new); 2465 } 2466 2467 /** 2468 * Gets a list of all complaints on the selected virtual server. 2469 * 2470 * @return a list of all complaints on the virtual server 2471 * 2472 * @throws TS3CommandFailedException 2473 * if the execution of a command fails 2474 * @querycommands 1 2475 * @see Complaint 2476 * @see #getComplaints(int) 2477 */ 2478 public CommandFuture<List<Complaint>> getComplaints() { 2479 return getComplaints(-1); 2480 } 2481 2482 /** 2483 * Gets a list of all complaints about the specified client. 2484 * 2485 * @param clientDBId 2486 * the database ID of the client 2487 * 2488 * @return a list of all complaints about the specified client 2489 * 2490 * @throws TS3CommandFailedException 2491 * if the execution of a command fails 2492 * @querycommands 1 2493 * @see Client#getDatabaseId() 2494 * @see Complaint 2495 */ 2496 public CommandFuture<List<Complaint>> getComplaints(int clientDBId) { 2497 Command cmd = ComplaintCommands.complainList(clientDBId); 2498 return executeAndTransform(cmd, Complaint::new); 2499 } 2500 2501 /** 2502 * Gets detailed connection information about the selected virtual server. 2503 * 2504 * @return connection information about the selected virtual server 2505 * 2506 * @throws TS3CommandFailedException 2507 * if the execution of a command fails 2508 * @querycommands 1 2509 * @see ConnectionInfo 2510 * @see #getServerInfo() 2511 */ 2512 public CommandFuture<ConnectionInfo> getConnectionInfo() { 2513 Command cmd = VirtualServerCommands.serverRequestConnectionInfo(); 2514 return executeAndTransformFirst(cmd, ConnectionInfo::new); 2515 } 2516 2517 /** 2518 * Gets a map of all custom client properties and their values 2519 * assigned to the client with database ID {@code clientDBId}. 2520 * 2521 * @param clientDBId 2522 * the database ID of the target client 2523 * 2524 * @return a map of the client's custom client property assignments 2525 * 2526 * @throws TS3CommandFailedException 2527 * if the execution of a command fails 2528 * @querycommands 1 2529 * @see Client#getDatabaseId() 2530 * @see #searchCustomClientProperty(String) 2531 * @see #searchCustomClientProperty(String, String) 2532 */ 2533 public CommandFuture<Map<String, String>> getCustomClientProperties(int clientDBId) { 2534 Command cmd = CustomPropertyCommands.customInfo(clientDBId); 2535 CommandFuture<Map<String, String>> future = cmd.getFuture() 2536 .map(result -> { 2537 List<Wrapper> response = result.getResponses(); 2538 Map<String, String> properties = new HashMap<>(response.size()); 2539 for (Wrapper wrapper : response) { 2540 properties.put(wrapper.get("ident"), wrapper.get("value")); 2541 } 2542 2543 return properties; 2544 }); 2545 2546 commandQueue.enqueueCommand(cmd); 2547 return future; 2548 } 2549 2550 /** 2551 * Gets all clients in the database whose last nickname matches the specified name <b>exactly</b>. 2552 * 2553 * @param name 2554 * the nickname for the clients to match 2555 * 2556 * @return a list of all clients with a matching nickname 2557 * 2558 * @throws TS3CommandFailedException 2559 * if the execution of a command fails 2560 * @querycommands 1 + n, 2561 * where n is the amount of database clients with a matching nickname 2562 * @see Client#getNickname() 2563 */ 2564 public CommandFuture<List<DatabaseClientInfo>> getDatabaseClientsByName(String name) { 2565 Command cmd = DatabaseClientCommands.clientDBFind(name, false); 2566 2567 return executeAndMap(cmd, response -> response.getInt("cldbid")) 2568 .then(dbClientIds -> { 2569 Collection<CommandFuture<DatabaseClientInfo>> infoFutures = new ArrayList<>(dbClientIds.size()); 2570 for (int dbClientId : dbClientIds) { 2571 infoFutures.add(getDatabaseClientInfo(dbClientId)); 2572 } 2573 return CommandFuture.ofAll(infoFutures); 2574 }); 2575 } 2576 2577 /** 2578 * Gets information about the client with the specified unique identifier in the server database. 2579 * 2580 * @param clientUId 2581 * the unique identifier of the client 2582 * 2583 * @return the database client or {@code null} if no client was found 2584 * 2585 * @throws TS3CommandFailedException 2586 * if the execution of a command fails 2587 * @querycommands 2 2588 * @see Client#getUniqueIdentifier() 2589 * @see DatabaseClientInfo 2590 */ 2591 public CommandFuture<DatabaseClientInfo> getDatabaseClientByUId(String clientUId) { 2592 Command cmd = DatabaseClientCommands.clientDBFind(clientUId, true); 2593 CommandFuture<DatabaseClientInfo> future = cmd.getFuture() 2594 .then(result -> { 2595 if (result.getResponses().isEmpty()) { 2596 return null; 2597 } else { 2598 int databaseId = result.getFirstResponse().getInt("cldbid"); 2599 return getDatabaseClientInfo(databaseId); 2600 } 2601 }); 2602 2603 commandQueue.enqueueCommand(cmd); 2604 return future; 2605 } 2606 2607 /** 2608 * Gets information about the client with the specified database ID in the server database. 2609 * 2610 * @param clientDBId 2611 * the database ID of the client 2612 * 2613 * @return the database client or {@code null} if no client was found 2614 * 2615 * @throws TS3CommandFailedException 2616 * if the execution of a command fails 2617 * @querycommands 1 2618 * @see Client#getDatabaseId() 2619 * @see DatabaseClientInfo 2620 */ 2621 public CommandFuture<DatabaseClientInfo> getDatabaseClientInfo(int clientDBId) { 2622 Command cmd = DatabaseClientCommands.clientDBInfo(clientDBId); 2623 return executeAndTransformFirst(cmd, DatabaseClientInfo::new); 2624 } 2625 2626 /** 2627 * Gets information about all clients in the server database. 2628 * <p> 2629 * As this method uses internal commands which can only return 200 clients at once, 2630 * this method can take quite some time to execute. 2631 * </p><p> 2632 * Also keep in mind that the client database can easily accumulate several thousand entries. 2633 * </p> 2634 * 2635 * @return a {@link List} of all database clients 2636 * 2637 * @throws TS3CommandFailedException 2638 * if the execution of a command fails 2639 * @querycommands 1 + n, 2640 * where n = Math.ceil([amount of database clients] / 200) 2641 * @see DatabaseClient 2642 */ 2643 public CommandFuture<List<DatabaseClient>> getDatabaseClients() { 2644 Command cmd = DatabaseClientCommands.clientDBList(0, 1, true); 2645 2646 return executeAndReturnIntProperty(cmd, "count") 2647 .then(count -> { 2648 Collection<CommandFuture<List<DatabaseClient>>> futures = new ArrayList<>((count + 199) / 200); 2649 for (int i = 0; i < count; i += 200) { 2650 futures.add(getDatabaseClients(i, 200)); 2651 } 2652 return CommandFuture.ofAll(futures); 2653 }).map(listOfLists -> listOfLists.stream() 2654 .flatMap(List::stream) 2655 .collect(Collectors.toList())); 2656 } 2657 2658 /** 2659 * Gets information about a set number of clients in the server database, starting at {@code offset}. 2660 * 2661 * @param offset 2662 * the index of the first database client to be returned. 2663 * Note that this is <b>not</b> a database ID, but an arbitrary, 0-based index. 2664 * @param count 2665 * the number of database clients that should be returned. 2666 * Any integer greater than 200 might cause problems with the connection 2667 * 2668 * @return a {@link List} of database clients 2669 * 2670 * @throws TS3CommandFailedException 2671 * if the execution of a command fails 2672 * @querycommands 1 2673 * @see DatabaseClient 2674 */ 2675 public CommandFuture<List<DatabaseClient>> getDatabaseClients(int offset, int count) { 2676 Command cmd = DatabaseClientCommands.clientDBList(offset, count, false); 2677 return executeAndTransform(cmd, DatabaseClient::new); 2678 } 2679 2680 /** 2681 * Gets information about a file on the file repository in the specified channel. 2682 * <p> 2683 * Note that this method does not work on directories and the information returned by this 2684 * method is identical to the one returned by {@link #getFileList(String, int, String)} 2685 * </p> 2686 * 2687 * @param filePath 2688 * the path to the file 2689 * @param channelId 2690 * the ID of the channel the file resides in 2691 * 2692 * @return some information about the file 2693 * 2694 * @throws TS3CommandFailedException 2695 * if the execution of a command fails 2696 * @querycommands 1 2697 * @see FileInfo#getPath() 2698 * @see Channel#getId() 2699 */ 2700 public CommandFuture<FileInfo> getFileInfo(String filePath, int channelId) { 2701 return getFileInfo(filePath, channelId, null); 2702 } 2703 2704 /** 2705 * Gets information about a file on the file repository in the specified channel. 2706 * <p> 2707 * Note that this method does not work on directories and the information returned by this 2708 * method is identical to the one returned by {@link #getFileList(String, int, String)} 2709 * </p> 2710 * 2711 * @param filePath 2712 * the path to the file 2713 * @param channelId 2714 * the ID of the channel the file resides in 2715 * @param channelPassword 2716 * the password of that channel 2717 * 2718 * @return some information about the file 2719 * 2720 * @throws TS3CommandFailedException 2721 * if the execution of a command fails 2722 * @querycommands 1 2723 * @see FileInfo#getPath() 2724 * @see Channel#getId() 2725 */ 2726 public CommandFuture<FileInfo> getFileInfo(String filePath, int channelId, String channelPassword) { 2727 Command cmd = FileCommands.ftGetFileInfo(channelId, channelPassword, filePath); 2728 return executeAndTransformFirst(cmd, FileInfo::new); 2729 } 2730 2731 /** 2732 * Gets information about multiple files on the file repository in the specified channel. 2733 * <p> 2734 * Note that this method does not work on directories and the information returned by this 2735 * method is identical to the one returned by {@link #getFileList(String, int, String)} 2736 * </p> 2737 * 2738 * @param filePaths 2739 * the paths to the files 2740 * @param channelId 2741 * the ID of the channel the file resides in 2742 * 2743 * @return some information about the file 2744 * 2745 * @throws TS3CommandFailedException 2746 * if the execution of a command fails 2747 * @querycommands 1 2748 * @see FileInfo#getPath() 2749 * @see Channel#getId() 2750 */ 2751 public CommandFuture<List<FileInfo>> getFileInfos(String[] filePaths, int channelId) { 2752 return getFileInfos(filePaths, channelId, null); 2753 } 2754 2755 /** 2756 * Gets information about multiple files on the file repository in the specified channel. 2757 * <p> 2758 * Note that this method does not work on directories and the information returned by this 2759 * method is identical to the one returned by {@link #getFileList(String, int, String)} 2760 * </p> 2761 * 2762 * @param filePaths 2763 * the paths to the files 2764 * @param channelId 2765 * the ID of the channel the file resides in 2766 * @param channelPassword 2767 * the password of that channel 2768 * 2769 * @return some information about the file 2770 * 2771 * @throws TS3CommandFailedException 2772 * if the execution of a command fails 2773 * @querycommands 1 2774 * @see FileInfo#getPath() 2775 * @see Channel#getId() 2776 */ 2777 public CommandFuture<List<FileInfo>> getFileInfos(String[] filePaths, int channelId, String channelPassword) { 2778 Command cmd = FileCommands.ftGetFileInfo(channelId, channelPassword, filePaths); 2779 return executeAndTransform(cmd, FileInfo::new); 2780 } 2781 2782 /** 2783 * Gets information about multiple files on the file repository in multiple channels. 2784 * <p> 2785 * Note that this method does not work on directories and the information returned by this 2786 * method is identical to the one returned by {@link #getFileList(String, int, String)} 2787 * </p> 2788 * 2789 * @param filePaths 2790 * the paths to the files, may not be {@code null} and may not contain {@code null} elements 2791 * @param channelIds 2792 * the IDs of the channels the file resides in, may not be {@code null} 2793 * @param channelPasswords 2794 * the passwords of those channels, may be {@code null} and may contain {@code null} elements 2795 * 2796 * @return some information about the files 2797 * 2798 * @throws IllegalArgumentException 2799 * if the dimensions of {@code filePaths}, {@code channelIds} and {@code channelPasswords} don't match 2800 * @throws TS3CommandFailedException 2801 * if the execution of a command fails 2802 * @querycommands 1 2803 * @see FileInfo#getPath() 2804 * @see Channel#getId() 2805 */ 2806 public CommandFuture<List<FileInfo>> getFileInfos(String[] filePaths, int[] channelIds, String[] channelPasswords) { 2807 Command cmd = FileCommands.ftGetFileInfo(channelIds, channelPasswords, filePaths); 2808 return executeAndTransform(cmd, FileInfo::new); 2809 } 2810 2811 /** 2812 * Gets a list of files and directories in the specified parent directory and channel. 2813 * 2814 * @param directoryPath 2815 * the path to the parent directory 2816 * @param channelId 2817 * the ID of the channel the directory resides in 2818 * 2819 * @return the files and directories in the parent directory 2820 * 2821 * @throws TS3CommandFailedException 2822 * if the execution of a command fails 2823 * @querycommands 1 2824 * @see FileInfo#getPath() 2825 * @see Channel#getId() 2826 */ 2827 public CommandFuture<List<FileListEntry>> getFileList(String directoryPath, int channelId) { 2828 return getFileList(directoryPath, channelId, null); 2829 } 2830 2831 /** 2832 * Gets a list of files and directories in the specified parent directory and channel. 2833 * 2834 * @param directoryPath 2835 * the path to the parent directory 2836 * @param channelId 2837 * the ID of the channel the directory resides in 2838 * @param channelPassword 2839 * the password of that channel 2840 * 2841 * @return the files and directories in the parent directory 2842 * 2843 * @throws TS3CommandFailedException 2844 * if the execution of a command fails 2845 * @querycommands 1 2846 * @see FileInfo#getPath() 2847 * @see Channel#getId() 2848 */ 2849 public CommandFuture<List<FileListEntry>> getFileList(String directoryPath, int channelId, String channelPassword) { 2850 Command cmd = FileCommands.ftGetFileList(directoryPath, channelId, channelPassword); 2851 return executeAndTransform(cmd, FileListEntry::new); 2852 } 2853 2854 /** 2855 * Gets a list of active or recently active file transfers. 2856 * 2857 * @return a list of file transfers 2858 * 2859 * @throws TS3CommandFailedException 2860 * if the execution of a command fails 2861 * @querycommands 1 2862 */ 2863 public CommandFuture<List<FileTransfer>> getFileTransfers() { 2864 Command cmd = FileCommands.ftList(); 2865 return executeAndTransform(cmd, FileTransfer::new); 2866 } 2867 2868 /** 2869 * Displays detailed configuration information about the server instance including 2870 * uptime, number of virtual servers online, traffic information, etc. 2871 * 2872 * @return information about the host 2873 * 2874 * @throws TS3CommandFailedException 2875 * if the execution of a command fails 2876 * @querycommands 1 2877 */ 2878 public CommandFuture<HostInfo> getHostInfo() { 2879 Command cmd = ServerCommands.hostInfo(); 2880 return executeAndTransformFirst(cmd, HostInfo::new); 2881 } 2882 2883 /** 2884 * Gets a list of all icon files on this virtual server. 2885 * 2886 * @return a list of all icons 2887 */ 2888 public CommandFuture<List<IconFile>> getIconList() { 2889 return getFileList("/icons/", 0) 2890 .map(result -> { 2891 List<IconFile> icons = new ArrayList<>(result.size()); 2892 for (FileListEntry file : result) { 2893 if (file.isDirectory() || file.isStillUploading()) continue; 2894 icons.add(new IconFile(file.getMap())); 2895 } 2896 return icons; 2897 }); 2898 } 2899 2900 /** 2901 * Displays the server instance configuration including database revision number, 2902 * the file transfer port, default group IDs, etc. 2903 * 2904 * @return information about the TeamSpeak server instance. 2905 * 2906 * @throws TS3CommandFailedException 2907 * if the execution of a command fails 2908 * @querycommands 1 2909 */ 2910 public CommandFuture<InstanceInfo> getInstanceInfo() { 2911 Command cmd = ServerCommands.instanceInfo(); 2912 return executeAndTransformFirst(cmd, InstanceInfo::new); 2913 } 2914 2915 /** 2916 * Fetches the specified amount of log entries from the server log. 2917 * 2918 * @param lines 2919 * the amount of log entries to fetch, in the range between 1 and 100. 2920 * Returns 100 entries if the argument is not in range 2921 * 2922 * @return a list of the latest log entries 2923 * 2924 * @throws TS3CommandFailedException 2925 * if the execution of a command fails 2926 * @querycommands 1 2927 */ 2928 public CommandFuture<List<String>> getInstanceLogEntries(int lines) { 2929 Command cmd = ServerCommands.logView(lines, true); 2930 return executeAndMap(cmd, response -> response.get("l")); 2931 } 2932 2933 /** 2934 * Fetches the last 100 log entries from the server log. 2935 * 2936 * @return a list of up to 100 log entries 2937 * 2938 * @throws TS3CommandFailedException 2939 * if the execution of a command fails 2940 * @querycommands 1 2941 */ 2942 public CommandFuture<List<String>> getInstanceLogEntries() { 2943 return getInstanceLogEntries(100); 2944 } 2945 2946 /** 2947 * Reads the message body of a message. This will not set the read flag, though. 2948 * 2949 * @param messageId 2950 * the ID of the message to be read 2951 * 2952 * @return the body of the message with the specified ID or {@code null} if there was no message with that ID 2953 * 2954 * @throws TS3CommandFailedException 2955 * if the execution of a command fails 2956 * @querycommands 1 2957 * @see Message#getId() 2958 * @see #setMessageRead(int) 2959 */ 2960 public CommandFuture<String> getOfflineMessage(int messageId) { 2961 Command cmd = MessageCommands.messageGet(messageId); 2962 return executeAndReturnStringProperty(cmd, "message"); 2963 } 2964 2965 /** 2966 * Reads the message body of a message. This will not set the read flag, though. 2967 * 2968 * @param message 2969 * the message to be read 2970 * 2971 * @return the body of the message with the specified ID or {@code null} if there was no message with that ID 2972 * 2973 * @throws TS3CommandFailedException 2974 * if the execution of a command fails 2975 * @querycommands 1 2976 * @see Message#getId() 2977 * @see #setMessageRead(Message) 2978 */ 2979 public CommandFuture<String> getOfflineMessage(Message message) { 2980 return getOfflineMessage(message.getId()); 2981 } 2982 2983 /** 2984 * Gets a list of all offline messages for the server query. 2985 * The returned messages lack their message body, though. 2986 * To read the actual message, use {@link #getOfflineMessage(int)} or {@link #getOfflineMessage(Message)}. 2987 * 2988 * @return a list of all offline messages this server query has received 2989 * 2990 * @throws TS3CommandFailedException 2991 * if the execution of a command fails 2992 * @querycommands 1 2993 */ 2994 public CommandFuture<List<Message>> getOfflineMessages() { 2995 Command cmd = MessageCommands.messageList(); 2996 return executeAndTransform(cmd, Message::new); 2997 } 2998 2999 /** 3000 * Displays detailed information about all assignments of the permission specified 3001 * with {@code permName}. The output includes the type and the ID of the client, 3002 * channel or group associated with the permission. 3003 * 3004 * @param permName 3005 * the name of the permission 3006 * 3007 * @return a list of permission assignments 3008 * 3009 * @throws TS3CommandFailedException 3010 * if the execution of a command fails 3011 * @querycommands 1 3012 * @see #getPermissionOverview(int, int) 3013 */ 3014 public CommandFuture<List<PermissionAssignment>> getPermissionAssignments(String permName) { 3015 Command cmd = PermissionCommands.permFind(permName); 3016 CommandFuture<List<PermissionAssignment>> future = new CommandFuture<>(); 3017 3018 executeAndTransform(cmd, PermissionAssignment::new) 3019 .forwardSuccess(future) 3020 .onFailure(transformError(future, 2562, Collections.emptyList())); 3021 3022 return future; 3023 } 3024 3025 /** 3026 * Gets the ID of the permission specified by {@code permName}. 3027 * <p> 3028 * Note that the use of numeric permission IDs is deprecated 3029 * and that this API only uses the string variant of the IDs. 3030 * </p> 3031 * 3032 * @param permName 3033 * the name of the permission 3034 * 3035 * @return the numeric ID of the specified permission 3036 * 3037 * @throws TS3CommandFailedException 3038 * if the execution of a command fails 3039 * @querycommands 1 3040 */ 3041 public CommandFuture<Integer> getPermissionIdByName(String permName) { 3042 Command cmd = PermissionCommands.permIdGetByName(permName); 3043 return executeAndReturnIntProperty(cmd, "permid"); 3044 } 3045 3046 /** 3047 * Gets the IDs of the permissions specified by {@code permNames}. 3048 * <p> 3049 * Note that the use of numeric permission IDs is deprecated 3050 * and that this API only uses the string variant of the IDs. 3051 * </p> 3052 * 3053 * @param permNames 3054 * the names of the permissions 3055 * 3056 * @return the numeric IDs of the specified permission 3057 * 3058 * @throws IllegalArgumentException 3059 * if {@code permNames} is {@code null} 3060 * @throws TS3CommandFailedException 3061 * if the execution of a command fails 3062 * @querycommands 1 3063 */ 3064 public CommandFuture<int[]> getPermissionIdsByName(String... permNames) { 3065 Command cmd = PermissionCommands.permIdGetByName(permNames); 3066 return executeAndReturnIntArray(cmd, "permid"); 3067 } 3068 3069 /** 3070 * Gets a list of all assigned permissions for a client in a specified channel. 3071 * If you do not care about channel permissions, set {@code channelId} to {@code 0}. 3072 * 3073 * @param channelId 3074 * the ID of the channel 3075 * @param clientDBId 3076 * the database ID of the client to create the overview for 3077 * 3078 * @return a list of all permission assignments for the client in the specified channel 3079 * 3080 * @throws TS3CommandFailedException 3081 * if the execution of a command fails 3082 * @querycommands 1 3083 * @see Channel#getId() 3084 * @see Client#getDatabaseId() 3085 */ 3086 public CommandFuture<List<PermissionAssignment>> getPermissionOverview(int channelId, int clientDBId) { 3087 Command cmd = PermissionCommands.permOverview(channelId, clientDBId); 3088 return executeAndTransform(cmd, PermissionAssignment::new); 3089 } 3090 3091 /** 3092 * Displays a list of all permissions, including ID, name and description. 3093 * 3094 * @return a list of all permissions 3095 * 3096 * @throws TS3CommandFailedException 3097 * if the execution of a command fails 3098 * @querycommands 1 3099 */ 3100 public CommandFuture<List<PermissionInfo>> getPermissions() { 3101 Command cmd = PermissionCommands.permissionList(); 3102 return executeAndTransform(cmd, PermissionInfo::new); 3103 } 3104 3105 /** 3106 * Displays the current value of the specified permission for this server query instance. 3107 * 3108 * @param permName 3109 * the name of the permission 3110 * 3111 * @return the permission value, usually ranging from 0 to 100 3112 * 3113 * @throws TS3CommandFailedException 3114 * if the execution of a command fails 3115 * @querycommands 1 3116 */ 3117 public CommandFuture<Integer> getPermissionValue(String permName) { 3118 Command cmd = PermissionCommands.permGet(permName); 3119 return executeAndReturnIntProperty(cmd, "permvalue"); 3120 } 3121 3122 /** 3123 * Displays the current values of the specified permissions for this server query instance. 3124 * 3125 * @param permNames 3126 * the names of the permissions 3127 * 3128 * @return the permission values, usually ranging from 0 to 100 3129 * 3130 * @throws IllegalArgumentException 3131 * if {@code permNames} is {@code null} 3132 * @throws TS3CommandFailedException 3133 * if the execution of a command fails 3134 * @querycommands 1 3135 */ 3136 public CommandFuture<int[]> getPermissionValues(String... permNames) { 3137 Command cmd = PermissionCommands.permGet(permNames); 3138 return executeAndReturnIntArray(cmd, "permvalue"); 3139 } 3140 3141 /** 3142 * Gets a list of all available tokens to join channel or server groups, 3143 * including their type and group IDs. 3144 * 3145 * @return a list of all generated, but still unclaimed privilege keys 3146 * 3147 * @throws TS3CommandFailedException 3148 * if the execution of a command fails 3149 * @querycommands 1 3150 * @see #addPrivilegeKey(PrivilegeKeyType, int, int, String) 3151 * @see #usePrivilegeKey(String) 3152 */ 3153 public CommandFuture<List<PrivilegeKey>> getPrivilegeKeys() { 3154 Command cmd = PrivilegeKeyCommands.privilegeKeyList(); 3155 return executeAndTransform(cmd, PrivilegeKey::new); 3156 } 3157 3158 /** 3159 * Gets a list of all clients in the specified server group. 3160 * 3161 * @param serverGroupId 3162 * the ID of the server group for which the clients should be looked up 3163 * 3164 * @return a list of all clients in the server group 3165 * 3166 * @throws TS3CommandFailedException 3167 * if the execution of a command fails 3168 * @querycommands 1 3169 */ 3170 public CommandFuture<List<ServerGroupClient>> getServerGroupClients(int serverGroupId) { 3171 Command cmd = ServerGroupCommands.serverGroupClientList(serverGroupId); 3172 return executeAndTransform(cmd, ServerGroupClient::new); 3173 } 3174 3175 /** 3176 * Gets a list of all clients in the specified server group. 3177 * 3178 * @param serverGroup 3179 * the server group for which the clients should be looked up 3180 * 3181 * @return a list of all clients in the server group 3182 * 3183 * @throws TS3CommandFailedException 3184 * if the execution of a command fails 3185 * @querycommands 1 3186 */ 3187 public CommandFuture<List<ServerGroupClient>> getServerGroupClients(ServerGroup serverGroup) { 3188 return getServerGroupClients(serverGroup.getId()); 3189 } 3190 3191 /** 3192 * Gets a list of all permissions assigned to the specified server group. 3193 * 3194 * @param serverGroupId 3195 * the ID of the server group for which the permissions should be looked up 3196 * 3197 * @return a list of all permissions assigned to the server group 3198 * 3199 * @throws TS3CommandFailedException 3200 * if the execution of a command fails 3201 * @querycommands 1 3202 * @see ServerGroup#getId() 3203 * @see #getServerGroupPermissions(ServerGroup) 3204 */ 3205 public CommandFuture<List<Permission>> getServerGroupPermissions(int serverGroupId) { 3206 Command cmd = PermissionCommands.serverGroupPermList(serverGroupId); 3207 return executeAndTransform(cmd, Permission::new); 3208 } 3209 3210 /** 3211 * Gets a list of all permissions assigned to the specified server group. 3212 * 3213 * @param serverGroup 3214 * the server group for which the permissions should be looked up 3215 * 3216 * @return a list of all permissions assigned to the server group 3217 * 3218 * @throws TS3CommandFailedException 3219 * if the execution of a command fails 3220 * @querycommands 1 3221 */ 3222 public CommandFuture<List<Permission>> getServerGroupPermissions(ServerGroup serverGroup) { 3223 return getServerGroupPermissions(serverGroup.getId()); 3224 } 3225 3226 /** 3227 * Gets a list of all server groups on the virtual server. 3228 * <p> 3229 * Depending on your permissions, the output may also contain 3230 * global server query groups and template groups. 3231 * </p> 3232 * 3233 * @return a list of all server groups 3234 * 3235 * @throws TS3CommandFailedException 3236 * if the execution of a command fails 3237 * @querycommands 1 3238 */ 3239 public CommandFuture<List<ServerGroup>> getServerGroups() { 3240 Command cmd = ServerGroupCommands.serverGroupList(); 3241 return executeAndTransform(cmd, ServerGroup::new); 3242 } 3243 3244 /** 3245 * Gets a list of all server groups set for a client. 3246 * 3247 * @param clientDatabaseId 3248 * the database ID of the client for which the server groups should be looked up 3249 * 3250 * @return a list of all server groups set for the client 3251 * 3252 * @throws TS3CommandFailedException 3253 * if the execution of a command fails 3254 * @querycommands 2 3255 * @see Client#getDatabaseId() 3256 * @see #getServerGroupsByClient(Client) 3257 */ 3258 public CommandFuture<List<ServerGroup>> getServerGroupsByClientId(int clientDatabaseId) { 3259 Command cmd = ServerGroupCommands.serverGroupsByClientId(clientDatabaseId); 3260 3261 CommandFuture<List<Integer>> serverGroupIds = executeAndMap(cmd, response -> response.getInt("sgid")); 3262 CommandFuture<List<ServerGroup>> allServerGroups = getServerGroups(); 3263 3264 return findByKey(serverGroupIds, allServerGroups, ServerGroup::getId); 3265 } 3266 3267 /** 3268 * Gets a list of all server groups set for a client. 3269 * 3270 * @param client 3271 * the client for which the server groups should be looked up 3272 * 3273 * @return a list of all server group set for the client 3274 * 3275 * @throws TS3CommandFailedException 3276 * if the execution of a command fails 3277 * @querycommands 2 3278 * @see #getServerGroupsByClientId(int) 3279 */ 3280 public CommandFuture<List<ServerGroup>> getServerGroupsByClient(Client client) { 3281 return getServerGroupsByClientId(client.getDatabaseId()); 3282 } 3283 3284 /** 3285 * Gets the ID of a virtual server by its port. 3286 * 3287 * @param port 3288 * the port of a virtual server 3289 * 3290 * @return the ID of the virtual server 3291 * 3292 * @throws TS3CommandFailedException 3293 * if the execution of a command fails 3294 * @querycommands 1 3295 * @see VirtualServer#getPort() 3296 * @see VirtualServer#getId() 3297 */ 3298 public CommandFuture<Integer> getServerIdByPort(int port) { 3299 Command cmd = VirtualServerCommands.serverIdGetByPort(port); 3300 return executeAndReturnIntProperty(cmd, "server_id"); 3301 } 3302 3303 /** 3304 * Gets detailed information about the virtual server the server query is currently in. 3305 * 3306 * @return information about the current virtual server 3307 * 3308 * @throws TS3CommandFailedException 3309 * if the execution of a command fails 3310 * @querycommands 1 3311 */ 3312 public CommandFuture<VirtualServerInfo> getServerInfo() { 3313 Command cmd = VirtualServerCommands.serverInfo(); 3314 return executeAndTransformFirst(cmd, VirtualServerInfo::new); 3315 } 3316 3317 /** 3318 * Gets a list of all server query logins (containing login name, virtual server ID, and client database ID). 3319 * If a virtual server is selected, only the server query logins of the selected virtual server are returned. 3320 * 3321 * @return a list of {@code QueryLogin} objects describing existing server query logins 3322 * 3323 * @throws TS3CommandFailedException 3324 * if the execution of a command fails 3325 * @querycommands 1 3326 * @see #addServerQueryLogin(String, int) 3327 * @see #deleteServerQueryLogin(int) 3328 * @see #getServerQueryLoginsByName(String) 3329 * @see #updateServerQueryLogin(String) 3330 */ 3331 public CommandFuture<List<QueryLogin>> getServerQueryLogins() { 3332 return getServerQueryLoginsByName(null); 3333 } 3334 3335 /** 3336 * Gets a list of all server query logins (containing login name, virtual server ID, and client database ID) 3337 * whose login name matches the specified SQL-like pattern. 3338 * If a virtual server is selected, only the server query logins of the selected virtual server are returned. 3339 * 3340 * @param pattern 3341 * the SQL-like pattern to match the server query login name against 3342 * 3343 * @return a list of {@code QueryLogin} objects describing existing server query logins 3344 * 3345 * @throws TS3CommandFailedException 3346 * if the execution of a command fails 3347 * @querycommands 1 3348 * @see #addServerQueryLogin(String, int) 3349 * @see #deleteServerQueryLogin(int) 3350 * @see #getServerQueryLogins() 3351 * @see #updateServerQueryLogin(String) 3352 */ 3353 public CommandFuture<List<QueryLogin>> getServerQueryLoginsByName(String pattern) { 3354 Command cmd = QueryLoginCommands.queryLoginList(pattern); 3355 return executeAndTransform(cmd, QueryLogin::new); 3356 } 3357 3358 /** 3359 * Gets the version, build number and platform of the TeamSpeak3 server. 3360 * 3361 * @return the version information of the server 3362 * 3363 * @throws TS3CommandFailedException 3364 * if the execution of a command fails 3365 * @querycommands 1 3366 */ 3367 public CommandFuture<Version> getVersion() { 3368 Command cmd = ServerCommands.version(); 3369 return executeAndTransformFirst(cmd, Version::new); 3370 } 3371 3372 /** 3373 * Gets a list of all virtual servers including their ID, status, number of clients online, etc. 3374 * 3375 * @return a list of all virtual servers 3376 * 3377 * @throws TS3CommandFailedException 3378 * if the execution of a command fails 3379 * @querycommands 1 3380 */ 3381 public CommandFuture<List<VirtualServer>> getVirtualServers() { 3382 Command cmd = VirtualServerCommands.serverList(); 3383 return executeAndTransform(cmd, VirtualServer::new); 3384 } 3385 3386 /** 3387 * Fetches the specified amount of log entries from the currently selected virtual server. 3388 * If no virtual server is selected, the entries will be read from the server log instead. 3389 * 3390 * @param lines 3391 * the amount of log entries to fetch, in the range between 1 and 100. 3392 * Returns 100 entries if the argument is not in range 3393 * 3394 * @return a list of the latest log entries 3395 * 3396 * @throws TS3CommandFailedException 3397 * if the execution of a command fails 3398 * @querycommands 1 3399 */ 3400 public CommandFuture<List<String>> getVirtualServerLogEntries(int lines) { 3401 Command cmd = ServerCommands.logView(lines, false); 3402 return executeAndMap(cmd, response -> response.get("l")); 3403 } 3404 3405 /** 3406 * Fetches the last 100 log entries from the currently selected virtual server. 3407 * If no virtual server is selected, the entries will be read from the server log instead. 3408 * 3409 * @return a list of up to 100 log entries 3410 * 3411 * @throws TS3CommandFailedException 3412 * if the execution of a command fails 3413 * @querycommands 1 3414 */ 3415 public CommandFuture<List<String>> getVirtualServerLogEntries() { 3416 return getVirtualServerLogEntries(100); 3417 } 3418 3419 /** 3420 * Checks whether the client with the specified client ID is online. 3421 * <p> 3422 * Please note that there is no guarantee that the client will still be 3423 * online by the time the next command is executed. 3424 * </p> 3425 * 3426 * @param clientId 3427 * the ID of the client 3428 * 3429 * @return {@code true} if the client is online, {@code false} otherwise 3430 * 3431 * @querycommands 1 3432 * @see #getClientInfo(int) 3433 */ 3434 public CommandFuture<Boolean> isClientOnline(int clientId) { 3435 Command cmd = ClientCommands.clientInfo(clientId); 3436 CommandFuture<Boolean> future = new CommandFuture<>(); 3437 3438 cmd.getFuture() 3439 .onSuccess(__ -> future.set(true)) 3440 .onFailure(transformError(future, 512, false)); 3441 3442 commandQueue.enqueueCommand(cmd); 3443 return future; 3444 } 3445 3446 /** 3447 * Checks whether the client with the specified unique identifier is online. 3448 * <p> 3449 * Please note that there is no guarantee that the client will still be 3450 * online by the time the next command is executed. 3451 * </p> 3452 * 3453 * @param clientUId 3454 * the unique ID of the client 3455 * 3456 * @return {@code true} if the client is online, {@code false} otherwise 3457 * 3458 * @querycommands 1 3459 * @see #getClientByUId(String) 3460 */ 3461 public CommandFuture<Boolean> isClientOnline(String clientUId) { 3462 Command cmd = ClientCommands.clientGetIds(clientUId); 3463 CommandFuture<Boolean> future = cmd.getFuture() 3464 .map(result -> !result.getResponses().isEmpty()); 3465 3466 commandQueue.enqueueCommand(cmd); 3467 return future; 3468 } 3469 3470 /** 3471 * Kicks one or more clients from their current channels. 3472 * This will move the kicked clients into the default channel and 3473 * won't do anything if the clients are already in the default channel. 3474 * 3475 * @param clientIds 3476 * the IDs of the clients to kick 3477 * 3478 * @return a future to track the progress of this command 3479 * 3480 * @throws TS3CommandFailedException 3481 * if the execution of a command fails 3482 * @querycommands 1 3483 * @see #kickClientFromChannel(Client...) 3484 * @see #kickClientFromChannel(String, int...) 3485 */ 3486 public CommandFuture<Void> kickClientFromChannel(int... clientIds) { 3487 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, null, clientIds); 3488 } 3489 3490 /** 3491 * Kicks one or more clients from their current channels. 3492 * This will move the kicked clients into the default channel and 3493 * won't do anything if the clients are already in the default channel. 3494 * 3495 * @param clients 3496 * the clients to kick 3497 * 3498 * @return a future to track the progress of this command 3499 * 3500 * @throws TS3CommandFailedException 3501 * if the execution of a command fails 3502 * @querycommands 1 3503 * @see #kickClientFromChannel(int...) 3504 * @see #kickClientFromChannel(String, Client...) 3505 */ 3506 public CommandFuture<Void> kickClientFromChannel(Client... clients) { 3507 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, null, clients); 3508 } 3509 3510 /** 3511 * Kicks one or more clients from their current channels for the specified reason. 3512 * This will move the kicked clients into the default channel and 3513 * won't do anything if the clients are already in the default channel. 3514 * 3515 * @param message 3516 * the reason message to display to the clients 3517 * @param clientIds 3518 * the IDs of the clients to kick 3519 * 3520 * @return a future to track the progress of this command 3521 * 3522 * @throws TS3CommandFailedException 3523 * if the execution of a command fails 3524 * @querycommands 1 3525 * @see Client#getId() 3526 * @see #kickClientFromChannel(int...) 3527 * @see #kickClientFromChannel(String, Client...) 3528 */ 3529 public CommandFuture<Void> kickClientFromChannel(String message, int... clientIds) { 3530 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, message, clientIds); 3531 } 3532 3533 /** 3534 * Kicks one or more clients from their current channels for the specified reason. 3535 * This will move the kicked clients into the default channel and 3536 * won't do anything if the clients are already in the default channel. 3537 * 3538 * @param message 3539 * the reason message to display to the clients 3540 * @param clients 3541 * the clients to kick 3542 * 3543 * @return a future to track the progress of this command 3544 * 3545 * @throws TS3CommandFailedException 3546 * if the execution of a command fails 3547 * @querycommands 1 3548 * @see #kickClientFromChannel(Client...) 3549 * @see #kickClientFromChannel(String, int...) 3550 */ 3551 public CommandFuture<Void> kickClientFromChannel(String message, Client... clients) { 3552 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, message, clients); 3553 } 3554 3555 /** 3556 * Kicks one or more clients from the server. 3557 * 3558 * @param clientIds 3559 * the IDs of the clients to kick 3560 * 3561 * @return a future to track the progress of this command 3562 * 3563 * @throws TS3CommandFailedException 3564 * if the execution of a command fails 3565 * @querycommands 1 3566 * @see Client#getId() 3567 * @see #kickClientFromServer(Client...) 3568 * @see #kickClientFromServer(String, int...) 3569 */ 3570 public CommandFuture<Void> kickClientFromServer(int... clientIds) { 3571 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, null, clientIds); 3572 } 3573 3574 /** 3575 * Kicks one or more clients from the server. 3576 * 3577 * @param clients 3578 * the clients to kick 3579 * 3580 * @return a future to track the progress of this command 3581 * 3582 * @throws TS3CommandFailedException 3583 * if the execution of a command fails 3584 * @querycommands 1 3585 * @see #kickClientFromServer(int...) 3586 * @see #kickClientFromServer(String, Client...) 3587 */ 3588 public CommandFuture<Void> kickClientFromServer(Client... clients) { 3589 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, null, clients); 3590 } 3591 3592 /** 3593 * Kicks one or more clients from the server for the specified reason. 3594 * 3595 * @param message 3596 * the reason message to display to the clients 3597 * @param clientIds 3598 * the IDs of the clients to kick 3599 * 3600 * @return a future to track the progress of this command 3601 * 3602 * @throws TS3CommandFailedException 3603 * if the execution of a command fails 3604 * @querycommands 1 3605 * @see Client#getId() 3606 * @see #kickClientFromServer(int...) 3607 * @see #kickClientFromServer(String, Client...) 3608 */ 3609 public CommandFuture<Void> kickClientFromServer(String message, int... clientIds) { 3610 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, message, clientIds); 3611 } 3612 3613 /** 3614 * Kicks one or more clients from the server for the specified reason. 3615 * 3616 * @param message 3617 * the reason message to display to the clients 3618 * @param clients 3619 * the clients to kick 3620 * 3621 * @return a future to track the progress of this command 3622 * 3623 * @throws TS3CommandFailedException 3624 * if the execution of a command fails 3625 * @querycommands 1 3626 * @see #kickClientFromServer(Client...) 3627 * @see #kickClientFromServer(String, int...) 3628 */ 3629 public CommandFuture<Void> kickClientFromServer(String message, Client... clients) { 3630 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, message, clients); 3631 } 3632 3633 /** 3634 * Kicks a list of clients from either the channel or the server for a given reason. 3635 * 3636 * @param reason 3637 * where to kick the clients from 3638 * @param message 3639 * the reason message to display to the clients 3640 * @param clients 3641 * the clients to kick 3642 * 3643 * @return a future to track the progress of this command 3644 * 3645 * @throws TS3CommandFailedException 3646 * if the execution of a command fails 3647 * @querycommands 1 3648 */ 3649 private CommandFuture<Void> kickClients(ReasonIdentifier reason, String message, Client... clients) { 3650 int[] clientIds = new int[clients.length]; 3651 for (int i = 0; i < clients.length; ++i) { 3652 clientIds[i] = clients[i].getId(); 3653 } 3654 return kickClients(reason, message, clientIds); 3655 } 3656 3657 /** 3658 * Kicks a list of clients from either the channel or the server for a given reason. 3659 * 3660 * @param reason 3661 * where to kick the clients from 3662 * @param message 3663 * the reason message to display to the clients 3664 * @param clientIds 3665 * the IDs of the clients to kick 3666 * 3667 * @return a future to track the progress of this command 3668 * 3669 * @throws TS3CommandFailedException 3670 * if the execution of a command fails 3671 * @querycommands 1 3672 * @see Client#getId() 3673 */ 3674 private CommandFuture<Void> kickClients(ReasonIdentifier reason, String message, int... clientIds) { 3675 Command cmd = ClientCommands.clientKick(reason, message, clientIds); 3676 return executeAndReturnError(cmd); 3677 } 3678 3679 /** 3680 * Logs the server query in using the specified username and password. 3681 * <p> 3682 * Note that you can also set the login in the {@link TS3Config}, 3683 * so that you will be logged in right after the connection is established. 3684 * </p> 3685 * 3686 * @param username 3687 * the username of the server query 3688 * @param password 3689 * the password to use 3690 * 3691 * @return a future to track the progress of this command 3692 * 3693 * @throws TS3CommandFailedException 3694 * if the execution of a command fails 3695 * @querycommands 1 3696 * @see #logout() 3697 */ 3698 public CommandFuture<Void> login(String username, String password) { 3699 Command cmd = QueryCommands.logIn(username, password); 3700 return executeAndReturnError(cmd); 3701 } 3702 3703 /** 3704 * Logs the server query out and deselects the current virtual server. 3705 * 3706 * @return a future to track the progress of this command 3707 * 3708 * @throws TS3CommandFailedException 3709 * if the execution of a command fails 3710 * @querycommands 1 3711 * @see #login(String, String) 3712 */ 3713 public CommandFuture<Void> logout() { 3714 Command cmd = QueryCommands.logOut(); 3715 return executeAndReturnError(cmd); 3716 } 3717 3718 /** 3719 * Moves a channel to a new parent channel specified by its ID. 3720 * To move a channel to root level, set {@code channelTargetId} to {@code 0}. 3721 * <p> 3722 * This will move the channel right below the specified parent channel, above all other child channels. 3723 * This command will fail if the channel already has the specified target channel as the parent channel. 3724 * </p> 3725 * 3726 * @param channelId 3727 * the channel to move 3728 * @param channelTargetId 3729 * the new parent channel for the specified channel 3730 * 3731 * @return a future to track the progress of this command 3732 * 3733 * @throws TS3CommandFailedException 3734 * if the execution of a command fails 3735 * @querycommands 1 3736 * @see Channel#getId() 3737 * @see #moveChannel(int, int, int) 3738 */ 3739 public CommandFuture<Void> moveChannel(int channelId, int channelTargetId) { 3740 return moveChannel(channelId, channelTargetId, 0); 3741 } 3742 3743 /** 3744 * Moves a channel to a new parent channel specified by its ID. 3745 * To move a channel to root level, set {@code channelTargetId} to {@code 0}. 3746 * <p> 3747 * The channel will be ordered below the channel with the ID specified by {@code order}. 3748 * To move the channel right below the parent channel, set {@code order} to {@code 0}. 3749 * </p><p> 3750 * Note that you can't re-order a channel without also changing its parent channel with this method. 3751 * Use {@link #editChannel(int, ChannelProperty, String)} to change {@link ChannelProperty#CHANNEL_ORDER} instead. 3752 * </p> 3753 * 3754 * @param channelId 3755 * the channel to move 3756 * @param channelTargetId 3757 * the new parent channel for the specified channel 3758 * @param order 3759 * the channel to sort the specified channel below 3760 * 3761 * @return a future to track the progress of this command 3762 * 3763 * @throws TS3CommandFailedException 3764 * if the execution of a command fails 3765 * @querycommands 1 3766 * @see Channel#getId() 3767 * @see #moveChannel(int, int) 3768 */ 3769 public CommandFuture<Void> moveChannel(int channelId, int channelTargetId, int order) { 3770 Command cmd = ChannelCommands.channelMove(channelId, channelTargetId, order); 3771 return executeAndReturnError(cmd); 3772 } 3773 3774 /** 3775 * Moves a single client into a channel. 3776 * <p> 3777 * Consider using {@link #moveClients(int[], int)} to move multiple clients. 3778 * </p> 3779 * 3780 * @param clientId 3781 * the ID of the client to move 3782 * @param channelId 3783 * the ID of the channel to move the client into 3784 * 3785 * @return a future to track the progress of this command 3786 * 3787 * @throws TS3CommandFailedException 3788 * if the execution of a command fails 3789 * @querycommands 1 3790 * @see Client#getId() 3791 * @see Channel#getId() 3792 */ 3793 public CommandFuture<Void> moveClient(int clientId, int channelId) { 3794 return moveClient(clientId, channelId, null); 3795 } 3796 3797 /** 3798 * Moves multiple clients into a channel. 3799 * Immediately returns {@code true} for an empty client ID array. 3800 * <p> 3801 * Use this method instead of {@link #moveClient(int, int)} for moving 3802 * several clients as this will only send 1 command to the server and thus complete faster. 3803 * </p> 3804 * 3805 * @param clientIds 3806 * the IDs of the clients to move, cannot be {@code null} 3807 * @param channelId 3808 * the ID of the channel to move the clients into 3809 * 3810 * @return a future to track the progress of this command 3811 * 3812 * @throws IllegalArgumentException 3813 * if {@code clientIds} is {@code null} 3814 * @throws TS3CommandFailedException 3815 * if the execution of a command fails 3816 * @querycommands 1 3817 * @see Client#getId() 3818 * @see Channel#getId() 3819 */ 3820 public CommandFuture<Void> moveClients(int[] clientIds, int channelId) { 3821 return moveClients(clientIds, channelId, null); 3822 } 3823 3824 /** 3825 * Moves a single client into a channel. 3826 * <p> 3827 * Consider using {@link #moveClients(Client[], ChannelBase)} to move multiple clients. 3828 * </p> 3829 * 3830 * @param client 3831 * the client to move, cannot be {@code null} 3832 * @param channel 3833 * the channel to move the client into, cannot be {@code null} 3834 * 3835 * @return a future to track the progress of this command 3836 * 3837 * @throws IllegalArgumentException 3838 * if {@code client} or {@code channel} is {@code null} 3839 * @throws TS3CommandFailedException 3840 * if the execution of a command fails 3841 * @querycommands 1 3842 */ 3843 public CommandFuture<Void> moveClient(Client client, ChannelBase channel) { 3844 return moveClient(client, channel, null); 3845 } 3846 3847 /** 3848 * Moves multiple clients into a channel. 3849 * Immediately returns {@code true} for an empty client array. 3850 * <p> 3851 * Use this method instead of {@link #moveClient(Client, ChannelBase)} for moving 3852 * several clients as this will only send 1 command to the server and thus complete faster. 3853 * </p> 3854 * 3855 * @param clients 3856 * the clients to move, cannot be {@code null} 3857 * @param channel 3858 * the channel to move the clients into, cannot be {@code null} 3859 * 3860 * @return a future to track the progress of this command 3861 * 3862 * @throws IllegalArgumentException 3863 * if {@code clients} or {@code channel} is {@code null} 3864 * @throws TS3CommandFailedException 3865 * if the execution of a command fails 3866 * @querycommands 1 3867 */ 3868 public CommandFuture<Void> moveClients(Client[] clients, ChannelBase channel) { 3869 return moveClients(clients, channel, null); 3870 } 3871 3872 /** 3873 * Moves a single client into a channel using the specified password. 3874 * <p> 3875 * Consider using {@link #moveClients(int[], int, String)} to move multiple clients. 3876 * </p> 3877 * 3878 * @param clientId 3879 * the ID of the client to move 3880 * @param channelId 3881 * the ID of the channel to move the client into 3882 * @param channelPassword 3883 * the password of the channel, can be {@code null} 3884 * 3885 * @return a future to track the progress of this command 3886 * 3887 * @throws TS3CommandFailedException 3888 * if the execution of a command fails 3889 * @querycommands 1 3890 * @see Client#getId() 3891 * @see Channel#getId() 3892 */ 3893 public CommandFuture<Void> moveClient(int clientId, int channelId, String channelPassword) { 3894 Command cmd = ClientCommands.clientMove(clientId, channelId, channelPassword); 3895 return executeAndReturnError(cmd); 3896 } 3897 3898 /** 3899 * Moves multiple clients into a channel using the specified password. 3900 * Immediately returns {@code true} for an empty client ID array. 3901 * <p> 3902 * Use this method instead of {@link #moveClient(int, int, String)} for moving 3903 * several clients as this will only send 1 command to the server and thus complete faster. 3904 * </p> 3905 * 3906 * @param clientIds 3907 * the IDs of the clients to move, cannot be {@code null} 3908 * @param channelId 3909 * the ID of the channel to move the clients into 3910 * @param channelPassword 3911 * the password of the channel, can be {@code null} 3912 * 3913 * @return a future to track the progress of this command 3914 * 3915 * @throws IllegalArgumentException 3916 * if {@code clientIds} is {@code null} 3917 * @throws TS3CommandFailedException 3918 * if the execution of a command fails 3919 * @querycommands 1 3920 * @see Client#getId() 3921 * @see Channel#getId() 3922 */ 3923 public CommandFuture<Void> moveClients(int[] clientIds, int channelId, String channelPassword) { 3924 if (clientIds == null) throw new IllegalArgumentException("Client ID array was null"); 3925 if (clientIds.length == 0) return CommandFuture.immediate(null); // Success 3926 3927 Command cmd = ClientCommands.clientMove(clientIds, channelId, channelPassword); 3928 return executeAndReturnError(cmd); 3929 } 3930 3931 /** 3932 * Moves a single client into a channel using the specified password. 3933 * <p> 3934 * Consider using {@link #moveClients(Client[], ChannelBase, String)} to move multiple clients. 3935 * </p> 3936 * 3937 * @param client 3938 * the client to move, cannot be {@code null} 3939 * @param channel 3940 * the channel to move the client into, cannot be {@code null} 3941 * @param channelPassword 3942 * the password of the channel, can be {@code null} 3943 * 3944 * @return a future to track the progress of this command 3945 * 3946 * @throws IllegalArgumentException 3947 * if {@code client} or {@code channel} is {@code null} 3948 * @throws TS3CommandFailedException 3949 * if the execution of a command fails 3950 * @querycommands 1 3951 */ 3952 public CommandFuture<Void> moveClient(Client client, ChannelBase channel, String channelPassword) { 3953 if (client == null) throw new IllegalArgumentException("Client cannot be null"); 3954 if (channel == null) throw new IllegalArgumentException("Channel cannot be null"); 3955 3956 return moveClient(client.getId(), channel.getId(), channelPassword); 3957 } 3958 3959 /** 3960 * Moves multiple clients into a channel using the specified password. 3961 * Immediately returns {@code true} for an empty client array. 3962 * <p> 3963 * Use this method instead of {@link #moveClient(Client, ChannelBase, String)} for moving 3964 * several clients as this will only send 1 command to the server and thus complete faster. 3965 * </p> 3966 * 3967 * @param clients 3968 * the clients to move, cannot be {@code null} 3969 * @param channel 3970 * the channel to move the clients into, cannot be {@code null} 3971 * @param channelPassword 3972 * the password of the channel, can be {@code null} 3973 * 3974 * @return a future to track the progress of this command 3975 * 3976 * @throws IllegalArgumentException 3977 * if {@code clients} or {@code channel} is {@code null} 3978 * @throws TS3CommandFailedException 3979 * if the execution of a command fails 3980 * @querycommands 1 3981 */ 3982 public CommandFuture<Void> moveClients(Client[] clients, ChannelBase channel, String channelPassword) { 3983 if (clients == null) throw new IllegalArgumentException("Client array cannot be null"); 3984 if (channel == null) throw new IllegalArgumentException("Channel cannot be null"); 3985 3986 int[] clientIds = new int[clients.length]; 3987 for (int i = 0; i < clients.length; i++) { 3988 clientIds[i] = clients[i].getId(); 3989 } 3990 return moveClients(clientIds, channel.getId(), channelPassword); 3991 } 3992 3993 /** 3994 * Moves and renames a file on the file repository within the same channel. 3995 * 3996 * @param oldPath 3997 * the current path to the file 3998 * @param newPath 3999 * the desired new path 4000 * @param channelId 4001 * the ID of the channel the file resides in 4002 * 4003 * @return a future to track the progress of this command 4004 * 4005 * @throws TS3CommandFailedException 4006 * if the execution of a command fails 4007 * @querycommands 1 4008 * @see FileInfo#getPath() 4009 * @see Channel#getId() 4010 * @see #moveFile(String, String, int, int) moveFile to a different channel 4011 */ 4012 public CommandFuture<Void> moveFile(String oldPath, String newPath, int channelId) { 4013 return moveFile(oldPath, newPath, channelId, null); 4014 } 4015 4016 /** 4017 * Renames a file on the file repository and moves it to a new path in a different channel. 4018 * 4019 * @param oldPath 4020 * the current path to the file 4021 * @param newPath 4022 * the desired new path 4023 * @param oldChannelId 4024 * the ID of the channel the file currently resides in 4025 * @param newChannelId 4026 * the ID of the channel the file should be moved to 4027 * 4028 * @return a future to track the progress of this command 4029 * 4030 * @throws TS3CommandFailedException 4031 * if the execution of a command fails 4032 * @querycommands 1 4033 * @see FileInfo#getPath() 4034 * @see Channel#getId() 4035 * @see #moveFile(String, String, int) moveFile within the same channel 4036 */ 4037 public CommandFuture<Void> moveFile(String oldPath, String newPath, int oldChannelId, int newChannelId) { 4038 return moveFile(oldPath, newPath, oldChannelId, null, newChannelId, null); 4039 } 4040 4041 /** 4042 * Moves and renames a file on the file repository within the same channel. 4043 * 4044 * @param oldPath 4045 * the current path to the file 4046 * @param newPath 4047 * the desired new path 4048 * @param channelId 4049 * the ID of the channel the file resides in 4050 * @param channelPassword 4051 * the password of the channel 4052 * 4053 * @return a future to track the progress of this command 4054 * 4055 * @throws TS3CommandFailedException 4056 * if the execution of a command fails 4057 * @querycommands 1 4058 * @see FileInfo#getPath() 4059 * @see Channel#getId() 4060 * @see #moveFile(String, String, int, String, int, String) moveFile to a different channel 4061 */ 4062 public CommandFuture<Void> moveFile(String oldPath, String newPath, int channelId, String channelPassword) { 4063 Command cmd = FileCommands.ftRenameFile(oldPath, newPath, channelId, channelPassword); 4064 return executeAndReturnError(cmd); 4065 } 4066 4067 /** 4068 * Renames a file on the file repository and moves it to a new path in a different channel. 4069 * 4070 * @param oldPath 4071 * the current path to the file 4072 * @param newPath 4073 * the desired new path 4074 * @param oldChannelId 4075 * the ID of the channel the file currently resides in 4076 * @param oldPassword 4077 * the password of the current channel 4078 * @param newChannelId 4079 * the ID of the channel the file should be moved to 4080 * @param newPassword 4081 * the password of the new channel 4082 * 4083 * @return a future to track the progress of this command 4084 * 4085 * @throws TS3CommandFailedException 4086 * if the execution of a command fails 4087 * @querycommands 1 4088 * @see FileInfo#getPath() 4089 * @see Channel#getId() 4090 * @see #moveFile(String, String, int, String) moveFile within the same channel 4091 */ 4092 public CommandFuture<Void> moveFile(String oldPath, String newPath, int oldChannelId, String oldPassword, int newChannelId, String newPassword) { 4093 Command cmd = FileCommands.ftRenameFile(oldPath, newPath, oldChannelId, oldPassword, newChannelId, newPassword); 4094 return executeAndReturnError(cmd); 4095 } 4096 4097 /** 4098 * Moves the server query into a channel. 4099 * 4100 * @param channelId 4101 * the ID of the channel to move the server query into 4102 * 4103 * @return a future to track the progress of this command 4104 * 4105 * @throws TS3CommandFailedException 4106 * if the execution of a command fails 4107 * @querycommands 1 4108 * @see Channel#getId() 4109 */ 4110 public CommandFuture<Void> moveQuery(int channelId) { 4111 return moveClient(0, channelId, null); 4112 } 4113 4114 /** 4115 * Moves the server query into a channel. 4116 * 4117 * @param channel 4118 * the channel to move the server query into, cannot be {@code null} 4119 * 4120 * @return a future to track the progress of this command 4121 * 4122 * @throws IllegalArgumentException 4123 * if {@code channel} is {@code null} 4124 * @throws TS3CommandFailedException 4125 * if the execution of a command fails 4126 * @querycommands 1 4127 */ 4128 public CommandFuture<Void> moveQuery(ChannelBase channel) { 4129 if (channel == null) throw new IllegalArgumentException("Channel cannot be null"); 4130 4131 return moveClient(0, channel.getId(), null); 4132 } 4133 4134 /** 4135 * Moves the server query into a channel using the specified password. 4136 * 4137 * @param channelId 4138 * the ID of the channel to move the client into 4139 * @param channelPassword 4140 * the password of the channel, can be {@code null} 4141 * 4142 * @return a future to track the progress of this command 4143 * 4144 * @throws TS3CommandFailedException 4145 * if the execution of a command fails 4146 * @querycommands 1 4147 * @see Channel#getId() 4148 */ 4149 public CommandFuture<Void> moveQuery(int channelId, String channelPassword) { 4150 return moveClient(0, channelId, channelPassword); 4151 } 4152 4153 /** 4154 * Moves the server query into a channel using the specified password. 4155 * 4156 * @param channel 4157 * the channel to move the client into, cannot be {@code null} 4158 * @param channelPassword 4159 * the password of the channel, can be {@code null} 4160 * 4161 * @return a future to track the progress of this command 4162 * 4163 * @throws IllegalArgumentException 4164 * if {@code channel} is {@code null} 4165 * @throws TS3CommandFailedException 4166 * if the execution of a command fails 4167 * @querycommands 1 4168 */ 4169 public CommandFuture<Void> moveQuery(ChannelBase channel, String channelPassword) { 4170 if (channel == null) throw new IllegalArgumentException("Channel cannot be null"); 4171 4172 return moveClient(0, channel.getId(), channelPassword); 4173 } 4174 4175 /** 4176 * Pokes the client with the specified client ID. 4177 * This opens up a small popup window for the client containing your message and plays a sound. 4178 * The displayed message will be formatted like this: <br> 4179 * {@code hh:mm:ss - "Your Nickname" poked you: <your message in green color>} 4180 * <p> 4181 * The displayed message length is limited to 100 UTF-8 bytes. 4182 * If a client has already received a poke message, all subsequent pokes will simply add a line 4183 * to the already opened popup window and will still play a sound. 4184 * </p> 4185 * 4186 * @param clientId 4187 * the ID of the client to poke 4188 * @param message 4189 * the message to send, may contain BB codes 4190 * 4191 * @return a future to track the progress of this command 4192 * 4193 * @throws TS3CommandFailedException 4194 * if the execution of a command fails 4195 * @querycommands 1 4196 * @see Client#getId() 4197 */ 4198 public CommandFuture<Void> pokeClient(int clientId, String message) { 4199 Command cmd = ClientCommands.clientPoke(clientId, message); 4200 return executeAndReturnError(cmd); 4201 } 4202 4203 /** 4204 * Terminates the connection with the TeamSpeak3 server. 4205 * <p> 4206 * This command should never be executed by a user of this API, 4207 * as it leaves the query in an undefined state. To terminate 4208 * a connection regularly, use {@link TS3Query#exit()}. 4209 * </p> 4210 * 4211 * @throws TS3CommandFailedException 4212 * if the execution of a command fails 4213 * @querycommands 1 4214 */ 4215 CommandFuture<Void> quit() { 4216 Command cmd = QueryCommands.quit(); 4217 return executeAndReturnError(cmd); 4218 } 4219 4220 /** 4221 * Registers the server query to receive notifications about all server events. 4222 * <p> 4223 * This means that the following actions will trigger event notifications: 4224 * </p> 4225 * <ul> 4226 * <li>A client joins the server or disconnects from it</li> 4227 * <li>A client switches channels</li> 4228 * <li>A client sends a server message</li> 4229 * <li>A client sends a channel message <b>in the channel the query is in</b></li> 4230 * <li>A client sends a private message to <b>the server query</b></li> 4231 * <li>A client uses a privilege key</li> 4232 * </ul> 4233 * <p> 4234 * The limitations to when the query receives notifications about chat events cannot be circumvented. 4235 * </p> 4236 * To be able to process these events in your application, register an event listener. 4237 * 4238 * @return whether all commands succeeded or not 4239 * 4240 * @throws TS3CommandFailedException 4241 * if the execution of a command fails 4242 * @querycommands 6 4243 * @see #addTS3Listeners(TS3Listener...) 4244 */ 4245 public CommandFuture<Void> registerAllEvents() { 4246 Collection<CommandFuture<Void>> eventFutures = Arrays.asList( 4247 registerEvent(TS3EventType.SERVER), 4248 registerEvent(TS3EventType.TEXT_SERVER), 4249 registerEvent(TS3EventType.CHANNEL, 0), 4250 registerEvent(TS3EventType.TEXT_CHANNEL, 0), 4251 registerEvent(TS3EventType.TEXT_PRIVATE), 4252 registerEvent(TS3EventType.PRIVILEGE_KEY_USED) 4253 ); 4254 4255 return CommandFuture.ofAll(eventFutures) 4256 .map(__ -> null); // Return success as Void, not List<Void> 4257 } 4258 4259 /** 4260 * Registers the server query to receive notifications about a given event type. 4261 * <p> 4262 * If used with {@link TS3EventType#TEXT_CHANNEL}, this will listen to chat events in the current channel. 4263 * If used with {@link TS3EventType#CHANNEL}, this will listen to <b>all</b> channel events. 4264 * To specify a different channel for channel events, use {@link #registerEvent(TS3EventType, int)}. 4265 * </p> 4266 * 4267 * @param eventType 4268 * the event type to be notified about 4269 * 4270 * @return a future to track the progress of this command 4271 * 4272 * @throws TS3CommandFailedException 4273 * if the execution of a command fails 4274 * @querycommands 1 4275 * @see #addTS3Listeners(TS3Listener...) 4276 * @see #registerEvent(TS3EventType, int) 4277 * @see #registerAllEvents() 4278 */ 4279 public CommandFuture<Void> registerEvent(TS3EventType eventType) { 4280 if (eventType == TS3EventType.CHANNEL || eventType == TS3EventType.TEXT_CHANNEL) { 4281 return registerEvent(eventType, 0); 4282 } else { 4283 return registerEvent(eventType, -1); 4284 } 4285 } 4286 4287 /** 4288 * Registers the server query to receive notifications about a given event type. 4289 * 4290 * @param eventType 4291 * the event type to be notified about 4292 * @param channelId 4293 * the ID of the channel to listen to, will be ignored if set to {@code -1}. 4294 * Can be set to {@code 0} for {@link TS3EventType#CHANNEL} to receive notifications about all channel switches. 4295 * 4296 * @return a future to track the progress of this command 4297 * 4298 * @throws TS3CommandFailedException 4299 * if the execution of a command fails 4300 * @querycommands 1 4301 * @see Channel#getId() 4302 * @see #addTS3Listeners(TS3Listener...) 4303 * @see #registerAllEvents() 4304 */ 4305 public CommandFuture<Void> registerEvent(TS3EventType eventType, int channelId) { 4306 Command cmd = QueryCommands.serverNotifyRegister(eventType, channelId); 4307 return executeAndReturnError(cmd); 4308 } 4309 4310 /** 4311 * Registers the server query to receive notifications about multiple given event types. 4312 * <p> 4313 * If used with {@link TS3EventType#TEXT_CHANNEL}, this will listen to chat events in the current channel. 4314 * If used with {@link TS3EventType#CHANNEL}, this will listen to <b>all</b> channel events. 4315 * To specify a different channel for channel events, use {@link #registerEvent(TS3EventType, int)}. 4316 * </p> 4317 * 4318 * @param eventTypes 4319 * the event types to be notified about 4320 * 4321 * @return a future to track the progress of this command 4322 * 4323 * @throws TS3CommandFailedException 4324 * if the execution of a command fails 4325 * @querycommands n, one command per TS3EventType 4326 * @see #addTS3Listeners(TS3Listener...) 4327 * @see #registerEvent(TS3EventType, int) 4328 * @see #registerAllEvents() 4329 */ 4330 public CommandFuture<Void> registerEvents(TS3EventType... eventTypes) { 4331 if (eventTypes.length == 0) return CommandFuture.immediate(null); // Success 4332 4333 Collection<CommandFuture<Void>> registerFutures = new ArrayList<>(eventTypes.length); 4334 for (TS3EventType type : eventTypes) { 4335 registerFutures.add(registerEvent(type)); 4336 } 4337 4338 return CommandFuture.ofAll(registerFutures) 4339 .map(__ -> null); // Return success as Void, not List<Void> 4340 } 4341 4342 /** 4343 * Removes the client specified by its database ID from the specified server group. 4344 * 4345 * @param serverGroupId 4346 * the ID of the server group 4347 * @param clientDatabaseId 4348 * the database ID of the client 4349 * 4350 * @return a future to track the progress of this command 4351 * 4352 * @throws TS3CommandFailedException 4353 * if the execution of a command fails 4354 * @querycommands 1 4355 * @see ServerGroup#getId() 4356 * @see Client#getDatabaseId() 4357 * @see #removeClientFromServerGroup(ServerGroup, Client) 4358 */ 4359 public CommandFuture<Void> removeClientFromServerGroup(int serverGroupId, int clientDatabaseId) { 4360 Command cmd = ServerGroupCommands.serverGroupDelClient(serverGroupId, clientDatabaseId); 4361 return executeAndReturnError(cmd); 4362 } 4363 4364 /** 4365 * Removes the specified client from the specified server group. 4366 * 4367 * @param serverGroup 4368 * the server group to remove the client from 4369 * @param client 4370 * the client to remove from the server group 4371 * 4372 * @return a future to track the progress of this command 4373 * 4374 * @throws TS3CommandFailedException 4375 * if the execution of a command fails 4376 * @querycommands 1 4377 * @see #removeClientFromServerGroup(int, int) 4378 */ 4379 public CommandFuture<Void> removeClientFromServerGroup(ServerGroup serverGroup, Client client) { 4380 return removeClientFromServerGroup(serverGroup.getId(), client.getDatabaseId()); 4381 } 4382 4383 /** 4384 * Removes one or more {@link TS3Listener}s to the event manager of the query. 4385 * <p> 4386 * If a listener was not actually registered, it will be ignored and no exception will be thrown. 4387 * </p> 4388 * 4389 * @param listeners 4390 * one or more listeners to remove 4391 * 4392 * @see #addTS3Listeners(TS3Listener...) 4393 * @see TS3Listener 4394 * @see TS3EventType 4395 */ 4396 public void removeTS3Listeners(TS3Listener... listeners) { 4397 query.getEventManager().removeListeners(listeners); 4398 } 4399 4400 /** 4401 * Renames the channel group with the specified ID. 4402 * 4403 * @param channelGroupId 4404 * the ID of the channel group to rename 4405 * @param name 4406 * the new name for the channel group 4407 * 4408 * @return a future to track the progress of this command 4409 * 4410 * @throws TS3CommandFailedException 4411 * if the execution of a command fails 4412 * @querycommands 1 4413 * @see ChannelGroup#getId() 4414 * @see #renameChannelGroup(ChannelGroup, String) 4415 */ 4416 public CommandFuture<Void> renameChannelGroup(int channelGroupId, String name) { 4417 Command cmd = ChannelGroupCommands.channelGroupRename(channelGroupId, name); 4418 return executeAndReturnError(cmd); 4419 } 4420 4421 /** 4422 * Renames the specified channel group. 4423 * 4424 * @param channelGroup 4425 * the channel group to rename 4426 * @param name 4427 * the new name for the channel group 4428 * 4429 * @return a future to track the progress of this command 4430 * 4431 * @throws TS3CommandFailedException 4432 * if the execution of a command fails 4433 * @querycommands 1 4434 * @see #renameChannelGroup(int, String) 4435 */ 4436 public CommandFuture<Void> renameChannelGroup(ChannelGroup channelGroup, String name) { 4437 return renameChannelGroup(channelGroup.getId(), name); 4438 } 4439 4440 /** 4441 * Renames the server group with the specified ID. 4442 * 4443 * @param serverGroupId 4444 * the ID of the server group to rename 4445 * @param name 4446 * the new name for the server group 4447 * 4448 * @return a future to track the progress of this command 4449 * 4450 * @throws TS3CommandFailedException 4451 * if the execution of a command fails 4452 * @querycommands 1 4453 * @see ServerGroup#getId() 4454 * @see #renameServerGroup(ServerGroup, String) 4455 */ 4456 public CommandFuture<Void> renameServerGroup(int serverGroupId, String name) { 4457 Command cmd = ServerGroupCommands.serverGroupRename(serverGroupId, name); 4458 return executeAndReturnError(cmd); 4459 } 4460 4461 /** 4462 * Renames the specified server group. 4463 * 4464 * @param serverGroup 4465 * the server group to rename 4466 * @param name 4467 * the new name for the server group 4468 * 4469 * @return a future to track the progress of this command 4470 * 4471 * @throws TS3CommandFailedException 4472 * if the execution of a command fails 4473 * @querycommands 1 4474 * @see #renameServerGroup(int, String) 4475 */ 4476 public CommandFuture<Void> renameServerGroup(ServerGroup serverGroup, String name) { 4477 return renameServerGroup(serverGroup.getId(), name); 4478 } 4479 4480 /** 4481 * Resets all permissions and deletes all server / channel groups. Use carefully. 4482 * 4483 * @return a token for a new administrator account 4484 * 4485 * @throws TS3CommandFailedException 4486 * if the execution of a command fails 4487 * @querycommands 1 4488 */ 4489 public CommandFuture<String> resetPermissions() { 4490 Command cmd = PermissionCommands.permReset(); 4491 return executeAndReturnStringProperty(cmd, "token"); 4492 } 4493 4494 /** 4495 * Finds all clients that have any value associated with the {@code key} custom client property, 4496 * and returns the client's database ID and the key and value of the matching custom property. 4497 * 4498 * @param key 4499 * the key to search for, cannot be {@code null} 4500 * 4501 * @return a list of client database IDs and their matching custom client properties 4502 * 4503 * @throws TS3CommandFailedException 4504 * if the execution of a command fails 4505 * @querycommands 1 4506 * @see Client#getDatabaseId() 4507 * @see #searchCustomClientProperty(String, String) 4508 * @see #getCustomClientProperties(int) 4509 */ 4510 public CommandFuture<List<CustomPropertyAssignment>> searchCustomClientProperty(String key) { 4511 return searchCustomClientProperty(key, "%"); 4512 } 4513 4514 /** 4515 * Finds all clients whose value associated with the {@code key} custom client property matches the 4516 * SQL-like pattern {@code valuePattern}, and returns the client's database ID and the key and value 4517 * of the matching custom property. 4518 * <p> 4519 * Patterns are case insensitive. They support the wildcard characters {@code %}, which matches any sequence of 4520 * zero or more characters, and {@code _}, which matches exactly one arbitrary character. 4521 * </p> 4522 * 4523 * @param key 4524 * the key to search for, cannot be {@code null} 4525 * @param valuePattern 4526 * the pattern that values need to match to be included 4527 * 4528 * @return a list of client database IDs and their matching custom client properties 4529 * 4530 * @throws TS3CommandFailedException 4531 * if the execution of a command fails 4532 * @querycommands 1 4533 * @see Client#getDatabaseId() 4534 * @see #searchCustomClientProperty(String) 4535 * @see #getCustomClientProperties(int) 4536 */ 4537 public CommandFuture<List<CustomPropertyAssignment>> searchCustomClientProperty(String key, String valuePattern) { 4538 if (key == null) throw new IllegalArgumentException("Key cannot be null"); 4539 4540 Command cmd = CustomPropertyCommands.customSearch(key, valuePattern); 4541 return executeAndTransform(cmd, CustomPropertyAssignment::new); 4542 } 4543 4544 /** 4545 * Moves the server query into the virtual server with the specified ID. 4546 * 4547 * @param id 4548 * the ID of the virtual server 4549 * 4550 * @return a future to track the progress of this command 4551 * 4552 * @throws TS3CommandFailedException 4553 * if the execution of a command fails 4554 * @querycommands 1 4555 * @see VirtualServer#getId() 4556 * @see #selectVirtualServerById(int, String) 4557 * @see #selectVirtualServerByPort(int) 4558 * @see #selectVirtualServer(VirtualServer) 4559 */ 4560 public CommandFuture<Void> selectVirtualServerById(int id) { 4561 return selectVirtualServerById(id, null); 4562 } 4563 4564 /** 4565 * Moves the server query into the virtual server with the specified ID 4566 * and sets the server query's nickname. 4567 * <p> 4568 * The nickname must be between 3 and 30 UTF-8 bytes long. BB codes will be ignored. 4569 * </p> 4570 * 4571 * @param id 4572 * the ID of the virtual server 4573 * @param nickname 4574 * the nickname, or {@code null} if the nickname should not be set 4575 * 4576 * @return a future to track the progress of this command 4577 * 4578 * @throws TS3CommandFailedException 4579 * if the execution of a command fails 4580 * @querycommands 1 4581 * @see VirtualServer#getId() 4582 * @see #selectVirtualServerById(int) 4583 * @see #selectVirtualServerByPort(int, String) 4584 * @see #selectVirtualServer(VirtualServer, String) 4585 */ 4586 public CommandFuture<Void> selectVirtualServerById(int id, String nickname) { 4587 Command cmd = QueryCommands.useId(id, nickname); 4588 return executeAndReturnError(cmd); 4589 } 4590 4591 /** 4592 * Moves the server query into the virtual server with the specified voice port. 4593 * 4594 * @param port 4595 * the voice port of the virtual server 4596 * 4597 * @return a future to track the progress of this command 4598 * 4599 * @throws TS3CommandFailedException 4600 * if the execution of a command fails 4601 * @querycommands 1 4602 * @see VirtualServer#getPort() 4603 * @see #selectVirtualServerById(int) 4604 * @see #selectVirtualServerByPort(int, String) 4605 * @see #selectVirtualServer(VirtualServer) 4606 */ 4607 public CommandFuture<Void> selectVirtualServerByPort(int port) { 4608 return selectVirtualServerByPort(port, null); 4609 } 4610 4611 /** 4612 * Moves the server query into the virtual server with the specified voice port 4613 * and sets the server query's nickname. 4614 * <p> 4615 * The nickname must be between 3 and 30 UTF-8 bytes long. BB codes will be ignored. 4616 * </p> 4617 * 4618 * @param port 4619 * the voice port of the virtual server 4620 * @param nickname 4621 * the nickname, or {@code null} if the nickname should not be set 4622 * 4623 * @return a future to track the progress of this command 4624 * 4625 * @throws TS3CommandFailedException 4626 * if the execution of a command fails 4627 * @querycommands 1 4628 * @see VirtualServer#getPort() 4629 * @see #selectVirtualServerById(int, String) 4630 * @see #selectVirtualServerByPort(int) 4631 * @see #selectVirtualServer(VirtualServer, String) 4632 */ 4633 public CommandFuture<Void> selectVirtualServerByPort(int port, String nickname) { 4634 Command cmd = QueryCommands.usePort(port, nickname); 4635 return executeAndReturnError(cmd); 4636 } 4637 4638 /** 4639 * Moves the server query into the specified virtual server. 4640 * 4641 * @param server 4642 * the virtual server to move into 4643 * 4644 * @return a future to track the progress of this command 4645 * 4646 * @throws TS3CommandFailedException 4647 * if the execution of a command fails 4648 * @querycommands 1 4649 * @see #selectVirtualServerById(int) 4650 * @see #selectVirtualServerByPort(int) 4651 * @see #selectVirtualServer(VirtualServer, String) 4652 */ 4653 public CommandFuture<Void> selectVirtualServer(VirtualServer server) { 4654 return selectVirtualServerById(server.getId()); 4655 } 4656 4657 /** 4658 * Moves the server query into the specified virtual server 4659 * and sets the server query's nickname. 4660 * <p> 4661 * The nickname must be between 3 and 30 UTF-8 bytes long. BB codes will be ignored. 4662 * </p> 4663 * 4664 * @param server 4665 * the virtual server to move into 4666 * @param nickname 4667 * the nickname, or {@code null} if the nickname should not be set 4668 * 4669 * @return a future to track the progress of this command 4670 * 4671 * @throws TS3CommandFailedException 4672 * if the execution of a command fails 4673 * @querycommands 1 4674 * @see #selectVirtualServerById(int, String) 4675 * @see #selectVirtualServerByPort(int, String) 4676 * @see #selectVirtualServer(VirtualServer) 4677 */ 4678 public CommandFuture<Void> selectVirtualServer(VirtualServer server, String nickname) { 4679 return selectVirtualServerById(server.getId(), nickname); 4680 } 4681 4682 /** 4683 * Sends an offline message to the client with the given unique identifier. 4684 * <p> 4685 * The message subject's length is limited to 200 UTF-8 bytes and BB codes in it will be ignored. 4686 * The message body's length is limited to 4096 UTF-8 bytes and accepts BB codes 4687 * </p> 4688 * 4689 * @param clientUId 4690 * the unique identifier of the client to send the message to 4691 * @param subject 4692 * the subject for the message, may not contain BB codes 4693 * @param message 4694 * the actual message body, may contain BB codes 4695 * 4696 * @return a future to track the progress of this command 4697 * 4698 * @throws TS3CommandFailedException 4699 * if the execution of a command fails 4700 * @querycommands 1 4701 * @see Client#getUniqueIdentifier() 4702 * @see Message 4703 */ 4704 public CommandFuture<Void> sendOfflineMessage(String clientUId, String subject, String message) { 4705 Command cmd = MessageCommands.messageAdd(clientUId, subject, message); 4706 return executeAndReturnError(cmd); 4707 } 4708 4709 /** 4710 * Sends a text message either to the whole virtual server, a channel or specific client. 4711 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 4712 * <p> 4713 * To send a message to all virtual servers, use {@link #broadcast(String)}. 4714 * To send an offline message, use {@link #sendOfflineMessage(String, String, String)}. 4715 * </p> 4716 * 4717 * @param targetMode 4718 * where the message should be sent to 4719 * @param targetId 4720 * the client ID of the recipient of this message. This value is ignored unless {@code targetMode} is {@code CLIENT} 4721 * @param message 4722 * the text message to send 4723 * 4724 * @return a future to track the progress of this command 4725 * 4726 * @throws TS3CommandFailedException 4727 * if the execution of a command fails 4728 * @querycommands 1 4729 * @see Client#getId() 4730 */ 4731 public CommandFuture<Void> sendTextMessage(TextMessageTargetMode targetMode, int targetId, String message) { 4732 Command cmd = ClientCommands.sendTextMessage(targetMode.getIndex(), targetId, message); 4733 return executeAndReturnError(cmd); 4734 } 4735 4736 /** 4737 * Sends a text message to the channel with the specified ID. 4738 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 4739 * <p> 4740 * This will move the client into the channel with the specified channel ID, 4741 * <b>but will not move it back to the original channel!</b> 4742 * </p> 4743 * 4744 * @param channelId 4745 * the ID of the channel to which the message should be sent to 4746 * @param message 4747 * the text message to send 4748 * 4749 * @return a future to track the progress of this command 4750 * 4751 * @throws TS3CommandFailedException 4752 * if the execution of a command fails 4753 * @querycommands 1 4754 * @see #sendChannelMessage(String) 4755 * @see Channel#getId() 4756 */ 4757 public CommandFuture<Void> sendChannelMessage(int channelId, String message) { 4758 return moveQuery(channelId) 4759 .then(__ -> sendTextMessage(TextMessageTargetMode.CHANNEL, 0, message)); 4760 } 4761 4762 /** 4763 * Sends a text message to the channel the server query is currently in. 4764 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 4765 * 4766 * @param message 4767 * the text message to send 4768 * 4769 * @return a future to track the progress of this command 4770 * 4771 * @throws TS3CommandFailedException 4772 * if the execution of a command fails 4773 * @querycommands 1 4774 */ 4775 public CommandFuture<Void> sendChannelMessage(String message) { 4776 return sendTextMessage(TextMessageTargetMode.CHANNEL, 0, message); 4777 } 4778 4779 /** 4780 * Sends a text message to the virtual server with the specified ID. 4781 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 4782 * <p> 4783 * This will move the client to the virtual server with the specified server ID, 4784 * <b>but will not move it back to the original virtual server!</b> 4785 * </p> 4786 * 4787 * @param serverId 4788 * the ID of the virtual server to which the message should be sent to 4789 * @param message 4790 * the text message to send 4791 * 4792 * @return a future to track the progress of this command 4793 * 4794 * @throws TS3CommandFailedException 4795 * if the execution of a command fails 4796 * @querycommands 1 4797 * @see #sendServerMessage(String) 4798 * @see VirtualServer#getId() 4799 */ 4800 public CommandFuture<Void> sendServerMessage(int serverId, String message) { 4801 return selectVirtualServerById(serverId) 4802 .then(__ -> sendTextMessage(TextMessageTargetMode.SERVER, 0, message)); 4803 } 4804 4805 /** 4806 * Sends a text message to the virtual server the server query is currently in. 4807 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 4808 * 4809 * @param message 4810 * the text message to send 4811 * 4812 * @return a future to track the progress of this command 4813 * 4814 * @throws TS3CommandFailedException 4815 * if the execution of a command fails 4816 * @querycommands 1 4817 */ 4818 public CommandFuture<Void> sendServerMessage(String message) { 4819 return sendTextMessage(TextMessageTargetMode.SERVER, 0, message); 4820 } 4821 4822 /** 4823 * Sends a private message to the client with the specified client ID. 4824 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 4825 * 4826 * @param clientId 4827 * the ID of the client to send the message to 4828 * @param message 4829 * the text message to send 4830 * 4831 * @return a future to track the progress of this command 4832 * 4833 * @throws TS3CommandFailedException 4834 * if the execution of a command fails 4835 * @querycommands 1 4836 * @see Client#getId() 4837 */ 4838 public CommandFuture<Void> sendPrivateMessage(int clientId, String message) { 4839 return sendTextMessage(TextMessageTargetMode.CLIENT, clientId, message); 4840 } 4841 4842 /** 4843 * Sets a channel group for a client in a specific channel. 4844 * 4845 * @param groupId 4846 * the ID of the group the client should join 4847 * @param channelId 4848 * the ID of the channel where the channel group should be assigned 4849 * @param clientDBId 4850 * the database ID of the client for which the channel group should be set 4851 * 4852 * @return a future to track the progress of this command 4853 * 4854 * @throws TS3CommandFailedException 4855 * if the execution of a command fails 4856 * @querycommands 1 4857 * @see ChannelGroup#getId() 4858 * @see Channel#getId() 4859 * @see Client#getDatabaseId() 4860 */ 4861 public CommandFuture<Void> setClientChannelGroup(int groupId, int channelId, int clientDBId) { 4862 Command cmd = ChannelGroupCommands.setClientChannelGroup(groupId, channelId, clientDBId); 4863 return executeAndReturnError(cmd); 4864 } 4865 4866 /** 4867 * Sets the value of the multiple custom client properties for a client. 4868 * <p> 4869 * If any key present in the map already has a value assigned for this client, 4870 * the existing value will be overwritten. 4871 * This method does not delete keys not present in the map. 4872 * </p><p> 4873 * If {@code properties} contains an entry with {@code null} as its key, 4874 * that entry will be ignored and no exception will be thrown. 4875 * </p> 4876 * 4877 * @param clientDBId 4878 * the database ID of the target client 4879 * @param properties 4880 * the map of properties to set, cannot be {@code null} 4881 * 4882 * @return a future to track the progress of this command 4883 * 4884 * @throws TS3CommandFailedException 4885 * if the execution of a command fails 4886 * @querycommands properties.size() 4887 * @see Client#getDatabaseId() 4888 * @see #setCustomClientProperty(int, String, String) 4889 * @see #deleteCustomClientProperty(int, String) 4890 */ 4891 public CommandFuture<Void> setCustomClientProperties(int clientDBId, Map<String, String> properties) { 4892 Collection<CommandFuture<Void>> futures = new ArrayList<>(properties.size()); 4893 4894 for (Map.Entry<String, String> entry : properties.entrySet()) { 4895 String key = entry.getKey(); 4896 String value = entry.getValue(); 4897 4898 if (key != null) { 4899 futures.add(setCustomClientProperty(clientDBId, key, value)); 4900 } 4901 } 4902 4903 return CommandFuture.ofAll(futures) 4904 .map(__ -> null); // Return success as Void, not List<Void> 4905 } 4906 4907 /** 4908 * Sets the value of the {@code key} custom client property for a client. 4909 * <p> 4910 * If there is already an assignment of the {@code key} custom client property 4911 * for this client, the existing value will be overwritten. 4912 * </p> 4913 * 4914 * @param clientDBId 4915 * the database ID of the target client 4916 * @param key 4917 * the key of the custom property to set, cannot be {@code null} 4918 * @param value 4919 * the (new) value of the custom property to set 4920 * 4921 * @return a future to track the progress of this command 4922 * 4923 * @throws TS3CommandFailedException 4924 * if the execution of a command fails 4925 * @querycommands 1 4926 * @see Client#getDatabaseId() 4927 * @see #setCustomClientProperties(int, Map) 4928 * @see #deleteCustomClientProperty(int, String) 4929 */ 4930 public CommandFuture<Void> setCustomClientProperty(int clientDBId, String key, String value) { 4931 if (key == null) throw new IllegalArgumentException("Key cannot be null"); 4932 4933 Command cmd = CustomPropertyCommands.customSet(clientDBId, key, value); 4934 return executeAndReturnError(cmd); 4935 } 4936 4937 /** 4938 * Sets the read flag to {@code true} for a given message. This will not delete the message. 4939 * 4940 * @param messageId 4941 * the ID of the message for which the read flag should be set 4942 * 4943 * @return a future to track the progress of this command 4944 * 4945 * @throws TS3CommandFailedException 4946 * if the execution of a command fails 4947 * @querycommands 1 4948 * @see #setMessageReadFlag(int, boolean) 4949 */ 4950 public CommandFuture<Void> setMessageRead(int messageId) { 4951 return setMessageReadFlag(messageId, true); 4952 } 4953 4954 /** 4955 * Sets the read flag to {@code true} for a given message. This will not delete the message. 4956 * 4957 * @param message 4958 * the message for which the read flag should be set 4959 * 4960 * @return a future to track the progress of this command 4961 * 4962 * @throws TS3CommandFailedException 4963 * if the execution of a command fails 4964 * @querycommands 1 4965 * @see #setMessageRead(int) 4966 * @see #setMessageReadFlag(Message, boolean) 4967 * @see #deleteOfflineMessage(int) 4968 */ 4969 public CommandFuture<Void> setMessageRead(Message message) { 4970 return setMessageReadFlag(message.getId(), true); 4971 } 4972 4973 /** 4974 * Sets the read flag for a given message. This will not delete the message. 4975 * 4976 * @param messageId 4977 * the ID of the message for which the read flag should be set 4978 * @param read 4979 * the boolean value to which the read flag should be set 4980 * 4981 * @return a future to track the progress of this command 4982 * 4983 * @throws TS3CommandFailedException 4984 * if the execution of a command fails 4985 * @querycommands 1 4986 * @see #setMessageRead(int) 4987 * @see #setMessageReadFlag(Message, boolean) 4988 * @see #deleteOfflineMessage(int) 4989 */ 4990 public CommandFuture<Void> setMessageReadFlag(int messageId, boolean read) { 4991 Command cmd = MessageCommands.messageUpdateFlag(messageId, read); 4992 return executeAndReturnError(cmd); 4993 } 4994 4995 /** 4996 * Sets the read flag for a given message. This will not delete the message. 4997 * 4998 * @param message 4999 * the message for which the read flag should be set 5000 * @param read 5001 * the boolean value to which the read flag should be set 5002 * 5003 * @return a future to track the progress of this command 5004 * 5005 * @throws TS3CommandFailedException 5006 * if the execution of a command fails 5007 * @querycommands 1 5008 * @see #setMessageRead(Message) 5009 * @see #setMessageReadFlag(int, boolean) 5010 * @see #deleteOfflineMessage(int) 5011 */ 5012 public CommandFuture<Void> setMessageReadFlag(Message message, boolean read) { 5013 return setMessageReadFlag(message.getId(), read); 5014 } 5015 5016 /** 5017 * Sets the nickname of the server query client. 5018 * <p> 5019 * The nickname must be between 3 and 30 UTF-8 bytes long. BB codes will be ignored. 5020 * </p> 5021 * 5022 * @param nickname 5023 * the new nickname, may not be {@code null} 5024 * 5025 * @return a future to track the progress of this command 5026 * 5027 * @throws TS3CommandFailedException 5028 * if the execution of a command fails 5029 * @querycommands 1 5030 * @see #updateClient(Map) 5031 */ 5032 public CommandFuture<Void> setNickname(String nickname) { 5033 Map<ClientProperty, String> options = Collections.singletonMap(ClientProperty.CLIENT_NICKNAME, nickname); 5034 return updateClient(options); 5035 } 5036 5037 /** 5038 * Starts the virtual server with the specified ID. 5039 * 5040 * @param serverId 5041 * the ID of the virtual server 5042 * 5043 * @return a future to track the progress of this command 5044 * 5045 * @throws TS3CommandFailedException 5046 * if the execution of a command fails 5047 * @querycommands 1 5048 */ 5049 public CommandFuture<Void> startServer(int serverId) { 5050 Command cmd = VirtualServerCommands.serverStart(serverId); 5051 return executeAndReturnError(cmd); 5052 } 5053 5054 /** 5055 * Starts the specified virtual server. 5056 * 5057 * @param virtualServer 5058 * the virtual server to start 5059 * 5060 * @return a future to track the progress of this command 5061 * 5062 * @throws TS3CommandFailedException 5063 * if the execution of a command fails 5064 * @querycommands 1 5065 */ 5066 public CommandFuture<Void> startServer(VirtualServer virtualServer) { 5067 return startServer(virtualServer.getId()); 5068 } 5069 5070 /** 5071 * Stops the virtual server with the specified ID. 5072 * 5073 * @param serverId 5074 * the ID of the virtual server 5075 * 5076 * @return a future to track the progress of this command 5077 * 5078 * @throws TS3CommandFailedException 5079 * if the execution of a command fails 5080 * @querycommands 1 5081 */ 5082 public CommandFuture<Void> stopServer(int serverId) { 5083 return stopServer(serverId, null); 5084 } 5085 5086 /** 5087 * Stops the virtual server with the specified ID. 5088 * 5089 * @param serverId 5090 * the ID of the virtual server 5091 * @param reason 5092 * the reason message to display to clients when they are disconnected 5093 * 5094 * @return a future to track the progress of this command 5095 * 5096 * @throws TS3CommandFailedException 5097 * if the execution of a command fails 5098 * @querycommands 1 5099 */ 5100 public CommandFuture<Void> stopServer(int serverId, String reason) { 5101 Command cmd = VirtualServerCommands.serverStop(serverId, reason); 5102 return executeAndReturnError(cmd); 5103 } 5104 5105 /** 5106 * Stops the specified virtual server. 5107 * 5108 * @param virtualServer 5109 * the virtual server to stop 5110 * 5111 * @return a future to track the progress of this command 5112 * 5113 * @throws TS3CommandFailedException 5114 * if the execution of a command fails 5115 * @querycommands 1 5116 */ 5117 public CommandFuture<Void> stopServer(VirtualServer virtualServer) { 5118 return stopServer(virtualServer.getId(), null); 5119 } 5120 5121 /** 5122 * Stops the specified virtual server. 5123 * 5124 * @param virtualServer 5125 * the virtual server to stop 5126 * @param reason 5127 * the reason message to display to clients when they are disconnected 5128 * 5129 * @return a future to track the progress of this command 5130 * 5131 * @throws TS3CommandFailedException 5132 * if the execution of a command fails 5133 * @querycommands 1 5134 */ 5135 public CommandFuture<Void> stopServer(VirtualServer virtualServer, String reason) { 5136 return stopServer(virtualServer.getId(), reason); 5137 } 5138 5139 /** 5140 * Stops the entire TeamSpeak 3 Server instance by shutting down the process. 5141 * <p> 5142 * To have permission to use this command, you need to use the server query admin login. 5143 * </p> 5144 * 5145 * @return a future to track the progress of this command 5146 * 5147 * @throws TS3CommandFailedException 5148 * if the execution of a command fails 5149 * @querycommands 1 5150 */ 5151 public CommandFuture<Void> stopServerProcess() { 5152 return stopServerProcess(null); 5153 } 5154 5155 /** 5156 * Stops the entire TeamSpeak 3 Server instance by shutting down the process. 5157 * <p> 5158 * To have permission to use this command, you need to use the server query admin login. 5159 * </p> 5160 * 5161 * @param reason 5162 * the reason message to display to clients when they are disconnected 5163 * 5164 * @return a future to track the progress of this command 5165 * 5166 * @throws TS3CommandFailedException 5167 * if the execution of a command fails 5168 * @querycommands 1 5169 */ 5170 public CommandFuture<Void> stopServerProcess(String reason) { 5171 Command cmd = ServerCommands.serverProcessStop(reason); 5172 return executeAndReturnError(cmd); 5173 } 5174 5175 /** 5176 * Unregisters the server query from receiving any event notifications. 5177 * 5178 * @return a future to track the progress of this command 5179 * 5180 * @throws TS3CommandFailedException 5181 * if the execution of a command fails 5182 * @querycommands 1 5183 */ 5184 public CommandFuture<Void> unregisterAllEvents() { 5185 Command cmd = QueryCommands.serverNotifyUnregister(); 5186 return executeAndReturnError(cmd); 5187 } 5188 5189 /** 5190 * Updates several client properties for this server query instance. 5191 * 5192 * @param options 5193 * the map of properties to update 5194 * 5195 * @return a future to track the progress of this command 5196 * 5197 * @throws TS3CommandFailedException 5198 * if the execution of a command fails 5199 * @querycommands 1 5200 * @see #updateClient(ClientProperty, String) 5201 * @see #editClient(int, Map) 5202 */ 5203 public CommandFuture<Void> updateClient(Map<ClientProperty, String> options) { 5204 Command cmd = ClientCommands.clientUpdate(options); 5205 return executeAndReturnError(cmd); 5206 } 5207 5208 /** 5209 * Changes a single client property for this server query instance. 5210 * <p> 5211 * Note that one can set many properties at once with the overloaded method that 5212 * takes a map of client properties and strings. 5213 * </p> 5214 * 5215 * @param property 5216 * the client property to modify, make sure it is editable 5217 * @param value 5218 * the new value of the property 5219 * 5220 * @return a future to track the progress of this command 5221 * 5222 * @throws TS3CommandFailedException 5223 * if the execution of a command fails 5224 * @querycommands 1 5225 * @see #updateClient(Map) 5226 * @see #editClient(int, Map) 5227 */ 5228 public CommandFuture<Void> updateClient(ClientProperty property, String value) { 5229 return updateClient(Collections.singletonMap(property, value)); 5230 } 5231 5232 /** 5233 * Generates new login credentials for the currently connected server query instance, using the given name. 5234 * <p> 5235 * <b>This will remove the current login credentials!</b> You won't be logged out, but after disconnecting, 5236 * the old credentials will no longer work. Make sure to not lock yourselves out! 5237 * </p> 5238 * 5239 * @param loginName 5240 * the name for the server query login 5241 * 5242 * @return the generated password for the server query login 5243 * 5244 * @throws TS3CommandFailedException 5245 * if the execution of a command fails 5246 * @querycommands 1 5247 * @see #addServerQueryLogin(String, int) 5248 * @see #deleteServerQueryLogin(int) 5249 * @see #getServerQueryLogins() 5250 */ 5251 public CommandFuture<String> updateServerQueryLogin(String loginName) { 5252 Command cmd = ClientCommands.clientSetServerQueryLogin(loginName); 5253 return executeAndReturnStringProperty(cmd, "client_login_password"); 5254 } 5255 5256 /** 5257 * Uploads a file to the file repository at a given path and channel 5258 * by reading {@code dataLength} bytes from an open {@link InputStream}. 5259 * <p> 5260 * It is the user's responsibility to ensure that the given {@code InputStream} is 5261 * open and that {@code dataLength} bytes can eventually be read from it. The user is 5262 * also responsible for closing the stream once the upload has finished. 5263 * </p><p> 5264 * Note that this method will not read the entire file to memory and can thus 5265 * upload arbitrarily sized files to the file repository. 5266 * </p> 5267 * 5268 * @param dataIn 5269 * a stream that contains the data that should be uploaded 5270 * @param dataLength 5271 * how many bytes should be read from the stream 5272 * @param filePath 5273 * the path the file should have after being uploaded 5274 * @param overwrite 5275 * if {@code false}, fails if there's already a file at {@code filePath} 5276 * @param channelId 5277 * the ID of the channel to upload the file to 5278 * 5279 * @return a future to track the progress of this command 5280 * 5281 * @throws TS3CommandFailedException 5282 * if the execution of a command fails 5283 * @throws TS3FileTransferFailedException 5284 * if the file transfer fails for any reason 5285 * @querycommands 1 5286 * @see FileInfo#getPath() 5287 * @see Channel#getId() 5288 * @see #uploadFileDirect(byte[], String, boolean, int, String) 5289 */ 5290 public CommandFuture<Void> uploadFile(InputStream dataIn, long dataLength, String filePath, boolean overwrite, int channelId) { 5291 return uploadFile(dataIn, dataLength, filePath, overwrite, channelId, null); 5292 } 5293 5294 /** 5295 * Uploads a file to the file repository at a given path and channel 5296 * by reading {@code dataLength} bytes from an open {@link InputStream}. 5297 * <p> 5298 * It is the user's responsibility to ensure that the given {@code InputStream} is 5299 * open and that {@code dataLength} bytes can eventually be read from it. The user is 5300 * also responsible for closing the stream once the upload has finished. 5301 * </p><p> 5302 * Note that this method will not read the entire file to memory and can thus 5303 * upload arbitrarily sized files to the file repository. 5304 * </p> 5305 * 5306 * @param dataIn 5307 * a stream that contains the data that should be uploaded 5308 * @param dataLength 5309 * how many bytes should be read from the stream 5310 * @param filePath 5311 * the path the file should have after being uploaded 5312 * @param overwrite 5313 * if {@code false}, fails if there's already a file at {@code filePath} 5314 * @param channelId 5315 * the ID of the channel to upload the file to 5316 * @param channelPassword 5317 * that channel's password 5318 * 5319 * @return a future to track the progress of this command 5320 * 5321 * @throws TS3CommandFailedException 5322 * if the execution of a command fails 5323 * @throws TS3FileTransferFailedException 5324 * if the file transfer fails for any reason 5325 * @querycommands 1 5326 * @see FileInfo#getPath() 5327 * @see Channel#getId() 5328 * @see #uploadFileDirect(byte[], String, boolean, int, String) 5329 */ 5330 public CommandFuture<Void> uploadFile(InputStream dataIn, long dataLength, String filePath, boolean overwrite, int channelId, String channelPassword) { 5331 FileTransferHelper helper = query.getFileTransferHelper(); 5332 int transferId = helper.getClientTransferId(); 5333 Command cmd = FileCommands.ftInitUpload(transferId, filePath, channelId, channelPassword, dataLength, overwrite); 5334 CommandFuture<Void> future = new CommandFuture<>(); 5335 5336 executeAndTransformFirst(cmd, FileTransferParameters::new).onSuccess(params -> { 5337 QueryError error = params.getQueryError(); 5338 if (!error.isSuccessful()) { 5339 future.fail(new TS3CommandFailedException(error, cmd.getName())); 5340 return; 5341 } 5342 5343 try { 5344 query.getFileTransferHelper().uploadFile(dataIn, dataLength, params); 5345 } catch (IOException e) { 5346 future.fail(new TS3FileTransferFailedException("Upload failed", e)); 5347 return; 5348 } 5349 future.set(null); // Mark as successful 5350 }).forwardFailure(future); 5351 5352 return future; 5353 } 5354 5355 /** 5356 * Uploads a file that is already stored in memory to the file repository 5357 * at a given path and channel. 5358 * 5359 * @param data 5360 * the file's data as a byte array 5361 * @param filePath 5362 * the path the file should have after being uploaded 5363 * @param overwrite 5364 * if {@code false}, fails if there's already a file at {@code filePath} 5365 * @param channelId 5366 * the ID of the channel to upload the file to 5367 * 5368 * @return a future to track the progress of this command 5369 * 5370 * @throws TS3CommandFailedException 5371 * if the execution of a command fails 5372 * @throws TS3FileTransferFailedException 5373 * if the file transfer fails for any reason 5374 * @querycommands 1 5375 * @see FileInfo#getPath() 5376 * @see Channel#getId() 5377 * @see #uploadFile(InputStream, long, String, boolean, int) 5378 */ 5379 public CommandFuture<Void> uploadFileDirect(byte[] data, String filePath, boolean overwrite, int channelId) { 5380 return uploadFileDirect(data, filePath, overwrite, channelId, null); 5381 } 5382 5383 /** 5384 * Uploads a file that is already stored in memory to the file repository 5385 * at a given path and channel. 5386 * 5387 * @param data 5388 * the file's data as a byte array 5389 * @param filePath 5390 * the path the file should have after being uploaded 5391 * @param overwrite 5392 * if {@code false}, fails if there's already a file at {@code filePath} 5393 * @param channelId 5394 * the ID of the channel to upload the file to 5395 * @param channelPassword 5396 * that channel's password 5397 * 5398 * @return a future to track the progress of this command 5399 * 5400 * @throws TS3CommandFailedException 5401 * if the execution of a command fails 5402 * @throws TS3FileTransferFailedException 5403 * if the file transfer fails for any reason 5404 * @querycommands 1 5405 * @see FileInfo#getPath() 5406 * @see Channel#getId() 5407 * @see #uploadFile(InputStream, long, String, boolean, int, String) 5408 */ 5409 public CommandFuture<Void> uploadFileDirect(byte[] data, String filePath, boolean overwrite, int channelId, String channelPassword) { 5410 return uploadFile(new ByteArrayInputStream(data), data.length, filePath, overwrite, channelId, channelPassword); 5411 } 5412 5413 /** 5414 * Uploads an icon to the icon directory in the file repository 5415 * by reading {@code dataLength} bytes from an open {@link InputStream}. 5416 * <p> 5417 * It is the user's responsibility to ensure that the given {@code InputStream} is 5418 * open and that {@code dataLength} bytes can eventually be read from it. The user is 5419 * also responsible for closing the stream once the upload has finished. 5420 * </p><p> 5421 * Note that unlike the file upload methods, this <strong>will read the entire file to memory</strong>. 5422 * This is because the CRC32 hash must be calculated before the icon can be uploaded. 5423 * That means that all icon files must be less than 2<sup>31</sup>-1 bytes in size. 5424 * </p> 5425 * Uploads that is already stored in memory to the icon directory 5426 * in the file repository. If this icon has already been uploaded or 5427 * if a hash collision occurs (CRC32), this command will fail. 5428 * 5429 * @param dataIn 5430 * a stream that contains the data that should be uploaded 5431 * @param dataLength 5432 * how many bytes should be read from the stream 5433 * 5434 * @return the ID of the uploaded icon 5435 * 5436 * @throws TS3CommandFailedException 5437 * if the execution of a command fails 5438 * @throws TS3FileTransferFailedException 5439 * if the file transfer fails for any reason 5440 * @querycommands 1 5441 * @see IconFile#getIconId() 5442 * @see #uploadIconDirect(byte[]) 5443 * @see #downloadIcon(OutputStream, long) 5444 */ 5445 public CommandFuture<Long> uploadIcon(InputStream dataIn, long dataLength) { 5446 byte[] data; 5447 try { 5448 data = FileTransferHelper.readFully(dataIn, dataLength); 5449 } catch (IOException e) { 5450 throw new TS3FileTransferFailedException("Reading stream failed", e); 5451 } 5452 return uploadIconDirect(data); 5453 } 5454 5455 /** 5456 * Uploads an icon that is already stored in memory to the icon directory 5457 * in the file repository. If this icon has already been uploaded or 5458 * if a CRC32 hash collision occurs, this command will fail. 5459 * 5460 * @param data 5461 * the icon's data as a byte array 5462 * 5463 * @return the ID of the uploaded icon 5464 * 5465 * @throws TS3CommandFailedException 5466 * if the execution of a command fails 5467 * @throws TS3FileTransferFailedException 5468 * if the file transfer fails for any reason 5469 * @querycommands 1 5470 * @see IconFile#getIconId() 5471 * @see #uploadIcon(InputStream, long) 5472 * @see #downloadIconDirect(long) 5473 */ 5474 public CommandFuture<Long> uploadIconDirect(byte[] data) { 5475 CommandFuture<Long> future = new CommandFuture<>(); 5476 5477 long iconId = FileTransferHelper.getIconId(data); 5478 String path = "/icon_" + iconId; 5479 5480 uploadFileDirect(data, path, false, 0) 5481 .onSuccess(__ -> future.set(iconId)) 5482 .onFailure(transformError(future, 2050, iconId)); 5483 5484 return future; 5485 } 5486 5487 /** 5488 * Uses an existing privilege key to join a server or channel group. 5489 * 5490 * @param token 5491 * the privilege key to use 5492 * 5493 * @return a future to track the progress of this command 5494 * 5495 * @throws TS3CommandFailedException 5496 * if the execution of a command fails 5497 * @querycommands 1 5498 * @see PrivilegeKey 5499 * @see #addPrivilegeKey(PrivilegeKeyType, int, int, String) 5500 * @see #usePrivilegeKey(PrivilegeKey) 5501 */ 5502 public CommandFuture<Void> usePrivilegeKey(String token) { 5503 Command cmd = PrivilegeKeyCommands.privilegeKeyUse(token); 5504 return executeAndReturnError(cmd); 5505 } 5506 5507 /** 5508 * Uses an existing privilege key to join a server or channel group. 5509 * 5510 * @param privilegeKey 5511 * the privilege key to use 5512 * 5513 * @return a future to track the progress of this command 5514 * 5515 * @throws TS3CommandFailedException 5516 * if the execution of a command fails 5517 * @querycommands 1 5518 * @see PrivilegeKey 5519 * @see #addPrivilegeKey(PrivilegeKeyType, int, int, String) 5520 * @see #usePrivilegeKey(String) 5521 */ 5522 public CommandFuture<Void> usePrivilegeKey(PrivilegeKey privilegeKey) { 5523 return usePrivilegeKey(privilegeKey.getToken()); 5524 } 5525 5526 /** 5527 * Gets information about the current server query instance. 5528 * 5529 * @return information about the server query instance 5530 * 5531 * @throws TS3CommandFailedException 5532 * if the execution of a command fails 5533 * @querycommands 1 5534 * @see #getClientInfo(int) 5535 */ 5536 public CommandFuture<ServerQueryInfo> whoAmI() { 5537 Command cmd = QueryCommands.whoAmI(); 5538 return executeAndTransformFirst(cmd, ServerQueryInfo::new); 5539 } 5540 5541 /** 5542 * Checks whether a given {@link TS3Exception} is a {@link TS3CommandFailedException} with the 5543 * specified error ID. 5544 * 5545 * @param exception 5546 * the exception to check 5547 * @param errorId 5548 * the error ID to match 5549 * 5550 * @return whether {@code exception} is a {@code TS3CommandFailedException} with error ID {@code errorId}. 5551 */ 5552 private static boolean isQueryError(TS3Exception exception, int errorId) { 5553 if (exception instanceof TS3CommandFailedException) { 5554 TS3CommandFailedException cfe = (TS3CommandFailedException) exception; 5555 return (cfe.getError().getId() == errorId); 5556 } else { 5557 return false; 5558 } 5559 } 5560 5561 /** 5562 * Creates a {@code FailureListener} that checks whether the caught exception is 5563 * a {@code TS3CommandFailedException} with error ID {@code errorId}. 5564 * <p> 5565 * If so, the listener makes {@code future} succeed by setting its result value to an empty 5566 * list with element type {@code T}. Else, the caught exception is forwarded to {@code future}. 5567 * </p> 5568 * 5569 * @param future 5570 * the future to forward the result to 5571 * @param errorId 5572 * the error ID to catch 5573 * @param replacement 5574 * the value to 5575 * @param <T> 5576 * the type of {@code replacement} and element type of {@code future} 5577 * 5578 * @return a {@code FailureListener} with the described properties 5579 */ 5580 private static <T> CommandFuture.FailureListener transformError(CommandFuture<T> future, int errorId, T replacement) { 5581 return exception -> { 5582 if (isQueryError(exception, errorId)) { 5583 future.set(replacement); 5584 } else { 5585 future.fail(exception); 5586 } 5587 }; 5588 } 5589 5590 /** 5591 * Executes a command and sets the returned future to true if the command succeeded. 5592 * 5593 * @param command 5594 * the command to execute 5595 * 5596 * @return a future to track the progress of this command 5597 */ 5598 private CommandFuture<Void> executeAndReturnError(Command command) { 5599 CommandFuture<Void> future = command.getFuture() 5600 .map(__ -> null); // Mark as successful 5601 5602 commandQueue.enqueueCommand(command); 5603 return future; 5604 } 5605 5606 /** 5607 * Executes a command, checking for failure and returning a single 5608 * {@code String} property from the first response map. 5609 * 5610 * @param command 5611 * the command to execute 5612 * @param property 5613 * the name of the property to return 5614 * 5615 * @return the value of the specified {@code String} property 5616 */ 5617 private CommandFuture<String> executeAndReturnStringProperty(Command command, String property) { 5618 CommandFuture<String> future = command.getFuture() 5619 .map(result -> result.getFirstResponse().get(property)); 5620 5621 commandQueue.enqueueCommand(command); 5622 return future; 5623 } 5624 5625 /** 5626 * Executes a command and returns a single {@code Integer} property from the first response map. 5627 * 5628 * @param command 5629 * the command to execute 5630 * @param property 5631 * the name of the property to return 5632 * 5633 * @return the value of the specified {@code Integer} property 5634 */ 5635 private CommandFuture<Integer> executeAndReturnIntProperty(Command command, String property) { 5636 CommandFuture<Integer> future = command.getFuture() 5637 .map(result -> result.getFirstResponse().getInt(property)); 5638 5639 commandQueue.enqueueCommand(command); 5640 return future; 5641 } 5642 5643 private CommandFuture<int[]> executeAndReturnIntArray(Command command, String property) { 5644 CommandFuture<int[]> future = command.getFuture() 5645 .map(result -> { 5646 List<Wrapper> responses = result.getResponses(); 5647 int[] values = new int[responses.size()]; 5648 int i = 0; 5649 5650 for (Wrapper response : responses) { 5651 values[i++] = response.getInt(property); 5652 } 5653 return values; 5654 }); 5655 5656 commandQueue.enqueueCommand(command); 5657 return future; 5658 } 5659 5660 /** 5661 * Executes a command, checks for failure and transforms the first 5662 * response map by invoking {@code fn}. 5663 * 5664 * @param command 5665 * the command to execute 5666 * @param fn 5667 * the function that creates a new wrapper of type {@code T} 5668 * @param <T> 5669 * the wrapper class the map should be wrapped with 5670 * 5671 * @return a future of a {@code T} wrapper of the first response map 5672 */ 5673 private <T extends Wrapper> CommandFuture<T> executeAndTransformFirst(Command command, Function<Map<String, String>, T> fn) { 5674 return executeAndMapFirst(command, wrapper -> fn.apply(wrapper.getMap())); 5675 } 5676 5677 /** 5678 * Executes a command, checks for failure and maps the first 5679 * response wrapper by using {@code fn}. 5680 * 5681 * @param command 5682 * the command to execute 5683 * @param fn 5684 * a mapping function from {@code Wrapper} to {@code T} 5685 * @param <T> 5686 * the result type of the mapping function {@code fn} 5687 * 5688 * @return a future of a {@code T} 5689 */ 5690 private <T> CommandFuture<T> executeAndMapFirst(Command command, Function<Wrapper, T> fn) { 5691 CommandFuture<T> future = command.getFuture() 5692 .map(result -> fn.apply(result.getFirstResponse())); 5693 5694 commandQueue.enqueueCommand(command); 5695 return future; 5696 } 5697 5698 /** 5699 * Executes a command, checks for failure and transforms all 5700 * response maps to a wrapper by invoking {@code fn} on each map. 5701 * 5702 * @param command 5703 * the command to execute 5704 * @param fn 5705 * the function that creates the new wrappers of type {@code T} 5706 * @param <T> 5707 * the wrapper class the maps should be wrapped with 5708 * 5709 * @return a future of a list of wrapped response maps 5710 */ 5711 private <T extends Wrapper> CommandFuture<List<T>> executeAndTransform(Command command, Function<Map<String, String>, T> fn) { 5712 return executeAndMap(command, wrapper -> fn.apply(wrapper.getMap())); 5713 } 5714 5715 /** 5716 * Executes a command, checks for failure and maps all response 5717 * wrappers by using {@code fn}. 5718 * 5719 * @param command 5720 * the command to execute 5721 * @param fn 5722 * a mapping function from {@code Wrapper} to {@code T} 5723 * @param <T> 5724 * the result type of the mapping function {@code fn} 5725 * 5726 * @return a future of a list of {@code T} 5727 */ 5728 private <T> CommandFuture<List<T>> executeAndMap(Command command, Function<Wrapper, T> fn) { 5729 CommandFuture<List<T>> future = command.getFuture() 5730 .map(result -> { 5731 List<Wrapper> response = result.getResponses(); 5732 List<T> transformed = new ArrayList<>(response.size()); 5733 for (Wrapper wrapper : response) { 5734 transformed.add(fn.apply(wrapper)); 5735 } 5736 5737 return transformed; 5738 }); 5739 5740 commandQueue.enqueueCommand(command); 5741 return future; 5742 } 5743 5744 /** 5745 * Computes a sub-list of the list of values produced by {@code valuesFuture} where 5746 * each value matches a key in the list of keys produced by {@code keysFuture}. 5747 * <p> 5748 * The returned future succeeds if {@code keysFuture} and {@code valuesFuture} succeed and 5749 * fails if {@code keysFuture} or {@code valuesFuture} fails. 5750 * </p><p> 5751 * {@code null} keys, {@code null} values, and keys without a matching value are ignored. 5752 * If multiple values map to the same key, only the first value is used. 5753 * </p><p> 5754 * The order of values in the resulting list follows the order of matching keys, 5755 * not the order of the original value list. 5756 * </p> 5757 * 5758 * @param keysFuture 5759 * the future producing a list of keys of type {@code K} 5760 * @param valuesFuture 5761 * the future producing a list of values of type {@code V} 5762 * @param keyMapper 5763 * a function extracting keys from the value type 5764 * @param <K> 5765 * the key type 5766 * @param <V> 5767 * the value type 5768 * 5769 * @return a future of a list of values of type {@code V} 5770 */ 5771 private static <K, V> CommandFuture<List<V>> findByKey(CommandFuture<List<K>> keysFuture, CommandFuture<List<V>> valuesFuture, 5772 Function<? super V, ? extends K> keyMapper) { 5773 CommandFuture<List<V>> future = new CommandFuture<>(); 5774 5775 keysFuture.onSuccess(keys -> 5776 valuesFuture.onSuccess(values -> { 5777 Map<K, V> valueMap = values.stream().collect(Collectors.toMap(keyMapper, Function.identity(), (l, r) -> l)); 5778 List<V> foundValues = new ArrayList<>(keys.size()); 5779 5780 for (K key : keys) { 5781 if (key == null) continue; 5782 V value = valueMap.get(key); 5783 if (value == null) continue; 5784 foundValues.add(value); 5785 } 5786 5787 future.set(foundValues); 5788 }).forwardFailure(future) 5789 ).forwardFailure(future); 5790 5791 return future; 5792 } 5793}