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