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