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.wrapper.*; 034import com.github.theholywaffle.teamspeak3.commands.*; 035 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.Collections; 039import java.util.List; 040import java.util.Map; 041import java.util.concurrent.TimeUnit; 042import java.util.regex.Pattern; 043 044/** 045 * Asynchronous version of {@link TS3Api} to interact with the {@link TS3Query}. 046 * <p> 047 * This class is used to easily interact with a {@link TS3Query}. It constructs commands, 048 * sends them to the TeamSpeak3 server, processes the response and returns the result. 049 * </p><p> 050 * All methods in this class are asynchronous (so they won't block) and 051 * will return a {@link CommandFuture} of the corresponding return type in {@link TS3Api}. 052 * If a command fails, no exception will be thrown directly. It will however be rethrown in 053 * {@link CommandFuture#get()} and {@link CommandFuture#get(long, TimeUnit)}. 054 * Usually, the thrown exception is a {@link TS3CommandFailedException}, which will get you 055 * access to the {@link QueryError} from which more information about the error can be obtained. 056 * </p><p> 057 * Also note that while these methods are asynchronous, the commands will still be sent through a 058 * synchronous command pipeline. That means if an asynchronous method is called immediately 059 * followed by a synchronous method, the synchronous method will first have to wait until the 060 * asynchronous method completed until it its command is sent. 061 * </p><p> 062 * You won't be able to execute most commands while you're not logged in due to missing permissions. 063 * Make sure to either pass your login credentials to the {@link TS3Config} object when 064 * creating the {@code TS3Query} or to call {@link #login(String, String)} to log in. 065 * </p><p> 066 * After that, most commands also require you to select a {@linkplain VirtualServer virtual server}. 067 * To do so, call either {@link #selectVirtualServerByPort(int)} or {@link #selectVirtualServerById(int)}. 068 * </p> 069 * 070 * @see TS3Api The synchronous version of the API 071 */ 072public class TS3ApiAsync { 073 074 /** 075 * The TS3 query to which this API sends its commands. 076 */ 077 private final TS3Query query; 078 079 /** 080 * Creates a new asynchronous API object for the given {@code TS3Query}. 081 * <p> 082 * <b>Usually, this constructor should not be called.</b> Use {@link TS3Query#getAsyncApi()} instead. 083 * </p> 084 * 085 * @param query 086 * the TS3Query to call 087 */ 088 public TS3ApiAsync(TS3Query query) { 089 this.query = query; 090 } 091 092 /** 093 * Adds a new ban entry. At least one of the parameters {@code ip}, {@code name} or {@code uid} needs to be not null. 094 * Returns the ID of the newly created ban. 095 * 096 * @param ip 097 * a RegEx pattern to match a client's IP against, can be null 098 * @param name 099 * a RegEx pattern to match a client's name against, can be null 100 * @param uid 101 * the unique identifier of a client, can be null 102 * @param timeInSeconds 103 * the duration of the ban in seconds. 0 equals a permanent ban 104 * @param reason 105 * the reason for the ban, can be null 106 * 107 * @return the ID of the newly created ban entry 108 * 109 * @querycommands 1 110 * @see Pattern RegEx Pattern 111 * @see Client#getId() 112 * @see Client#getUniqueIdentifier() 113 * @see ClientInfo#getIp() 114 */ 115 public CommandFuture<Integer> addBan(String ip, String name, String uid, long timeInSeconds, String reason) { 116 if (ip == null && name == null && uid == null) { 117 throw new IllegalArgumentException("Either IP, Name or UID must be set"); 118 } 119 120 final CBanAdd add = new CBanAdd(ip, name, uid, timeInSeconds, reason); 121 return executeAndReturnIntProperty(add, "banid"); 122 } 123 124 /** 125 * Adds a specified permission to a client in a specific channel. 126 * 127 * @param channelId 128 * the ID of the channel wherein the permission should be granted 129 * @param clientDBId 130 * the database ID of the client to add a permission to 131 * @param permName 132 * the name of the permission to grant 133 * @param permValue 134 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 135 * 136 * @return whether the command succeeded or not 137 * 138 * @querycommands 1 139 * @see Channel#getId() 140 * @see Client#getDatabaseId() 141 * @see Permission 142 */ 143 public CommandFuture<Boolean> addChannelClientPermission(int channelId, int clientDBId, String permName, int permValue) { 144 final CChannelClientAddPerm add = new CChannelClientAddPerm(channelId, clientDBId, permName, permValue); 145 return executeAndReturnError(add); 146 } 147 148 /** 149 * Creates a new channel group for clients using a given name and returns its ID. 150 * <p> 151 * To create channel group templates or ones for server queries, 152 * use {@link #addChannelGroup(String, PermissionGroupDatabaseType)}. 153 * </p> 154 * 155 * @param name 156 * the name of the new channel group 157 * 158 * @return the ID of the newly created channel group 159 * 160 * @querycommands 1 161 * @see ChannelGroup 162 */ 163 public CommandFuture<Integer> addChannelGroup(String name) { 164 return addChannelGroup(name, null); 165 } 166 167 /** 168 * Creates a new channel group using a given name and returns its ID. 169 * 170 * @param name 171 * the name of the new channel group 172 * @param type 173 * the desired type of channel group 174 * 175 * @return the ID of the newly created channel group 176 * 177 * @querycommands 1 178 * @see ChannelGroup 179 */ 180 public CommandFuture<Integer> addChannelGroup(String name, PermissionGroupDatabaseType type) { 181 final CChannelGroupAdd add = new CChannelGroupAdd(name, type); 182 return executeAndReturnIntProperty(add, "cgid"); 183 } 184 185 /** 186 * Adds a specified permission to a channel group. 187 * 188 * @param groupId 189 * the ID of the channel group to grant the permission 190 * @param permName 191 * the name of the permission to be granted 192 * @param permValue 193 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 194 * 195 * @return whether the command succeeded or not 196 * 197 * @querycommands 1 198 * @see ChannelGroup#getId() 199 * @see Permission 200 */ 201 public CommandFuture<Boolean> addChannelGroupPermission(int groupId, String permName, int permValue) { 202 final CChannelGroupAddPerm add = new CChannelGroupAddPerm(groupId, permName, permValue); 203 return executeAndReturnError(add); 204 } 205 206 /** 207 * Adds a specified permission to a channel. 208 * 209 * @param channelId 210 * the ID of the channel wherein the permission should be granted 211 * @param permName 212 * the name of the permission to grant 213 * @param permValue 214 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 215 * 216 * @return whether the command succeeded or not 217 * 218 * @querycommands 1 219 * @see Channel#getId() 220 * @see Permission 221 */ 222 public CommandFuture<Boolean> addChannelPermission(int channelId, String permName, int permValue) { 223 final CChannelAddPerm perm = new CChannelAddPerm(channelId, permName, permValue); 224 return executeAndReturnError(perm); 225 } 226 227 /** 228 * Adds a specified permission to a channel. 229 * 230 * @param clientDBId 231 * the database ID of the client to grant the permission 232 * @param permName 233 * the name of the permission to grant 234 * @param value 235 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 236 * @param skipped 237 * if set to {@code true}, the permission will not be overridden by channel permissions 238 * 239 * @return whether the command succeeded or not 240 * 241 * @querycommands 1 242 * @see Client#getDatabaseId() 243 * @see Permission 244 */ 245 public CommandFuture<Boolean> addClientPermission(int clientDBId, String permName, int value, boolean skipped) { 246 final CClientAddPerm add = new CClientAddPerm(clientDBId, permName, value, skipped); 247 return executeAndReturnError(add); 248 } 249 250 /** 251 * Adds a client to the specified server group. 252 * <p> 253 * Please note that a client cannot be added to default groups or template groups. 254 * </p> 255 * 256 * @param groupId 257 * the ID of the server group to add the client to 258 * @param clientDatabaseId 259 * the database ID of the client to add 260 * 261 * @return whether the command succeeded or not 262 * 263 * @querycommands 1 264 * @see ServerGroup#getId() 265 * @see Client#getDatabaseId() 266 */ 267 public CommandFuture<Boolean> addClientToServerGroup(int groupId, int clientDatabaseId) { 268 final CServerGroupAddClient add = new CServerGroupAddClient(groupId, clientDatabaseId); 269 return executeAndReturnError(add); 270 } 271 272 /** 273 * Submits a complaint about the specified client. 274 * The length of the message is limited to 200 UTF-8 bytes and BB codes in it will be ignored. 275 * 276 * @param clientDBId 277 * the database ID of the client 278 * @param message 279 * the message of the complaint, may not contain BB codes 280 * 281 * @return whether the command succeeded or not 282 * 283 * @querycommands 1 284 * @see Client#getDatabaseId() 285 * @see Complaint#getMessage() 286 */ 287 public CommandFuture<Boolean> addComplaint(int clientDBId, String message) { 288 final CComplainAdd add = new CComplainAdd(clientDBId, message); 289 return executeAndReturnError(add); 290 } 291 292 /** 293 * Adds a specified permission to all server groups of the type specified by {@code type} on all virtual servers. 294 * 295 * @param type 296 * the kind of server group this permission should be added to 297 * @param permName 298 * the name of the permission to be granted 299 * @param value 300 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 301 * @param negated 302 * if set to true, the lowest permission value will be selected instead of the highest 303 * @param skipped 304 * if set to true, this permission will not be overridden by client of channel permissions 305 * 306 * @return whether the command succeeded or not 307 * 308 * @querycommands 1 309 * @see ServerGroupType 310 * @see Permission 311 */ 312 public CommandFuture<Boolean> addPermissionToAllServerGroups(ServerGroupType type, String permName, int value, boolean negated, boolean skipped) { 313 final CServerGroupAutoAddPerm add = new CServerGroupAutoAddPerm(type, permName, value, negated, skipped); 314 return executeAndReturnError(add); 315 } 316 317 /** 318 * Create a new privilege key that allows one client to join a server or channel group. 319 * <ul> 320 * <li>If {@code type} is set to {@linkplain TokenType#SERVER_GROUP SERVER_GROUP}, 321 * {@code groupId} is used as a server group ID and {@code channelId} is ignored.</li> 322 * <li>If {@code type} is set to {@linkplain TokenType#CHANNEL_GROUP CHANNEL_GROUP}, 323 * {@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> 324 * </ul> 325 * 326 * @param type 327 * the type of token that should be created 328 * @param groupId 329 * the ID of the server or channel group 330 * @param channelId 331 * the ID of the channel, in case the token is channel group token 332 * @param description 333 * the description for the token, can be null 334 * 335 * @return the created token for a client to use 336 * 337 * @querycommands 1 338 * @see TokenType 339 * @see #addPrivilegeKeyServerGroup(int, String) 340 * @see #addPrivilegeKeyChannelGroup(int, int, String) 341 */ 342 public CommandFuture<String> addPrivilegeKey(TokenType type, int groupId, int channelId, String description) { 343 final CPrivilegeKeyAdd add = new CPrivilegeKeyAdd(type, groupId, channelId, description); 344 return executeAndReturnStringProperty(add, "token"); 345 } 346 347 /** 348 * Creates a new privilege key for a channel group. 349 * 350 * @param channelGroupId 351 * the ID of the channel group 352 * @param channelId 353 * the ID of the channel in which the channel group should be set 354 * @param description 355 * the description for the token, can be null 356 * 357 * @return the created token for a client to use 358 * 359 * @querycommands 1 360 * @see ChannelGroup#getId() 361 * @see Channel#getId() 362 * @see #addPrivilegeKey(TokenType, int, int, String) 363 * @see #addPrivilegeKeyServerGroup(int, String) 364 */ 365 public CommandFuture<String> addPrivilegeKeyChannelGroup(int channelGroupId, int channelId, String description) { 366 return addPrivilegeKey(TokenType.CHANNEL_GROUP, channelGroupId, channelId, description); 367 } 368 369 /** 370 * Creates a new privilege key for a server group. 371 * 372 * @param serverGroupId 373 * the ID of the server group 374 * @param description 375 * the description for the token, can be null 376 * 377 * @return the created token for a client to use 378 * 379 * @querycommands 1 380 * @see ServerGroup#getId() 381 * @see #addPrivilegeKey(TokenType, int, int, String) 382 * @see #addPrivilegeKeyChannelGroup(int, int, String) 383 */ 384 public CommandFuture<String> addPrivilegeKeyServerGroup(int serverGroupId, String description) { 385 return addPrivilegeKey(TokenType.SERVER_GROUP, serverGroupId, 0, description); 386 } 387 388 /** 389 * Creates a new server group for clients using a given name and returns its ID. 390 * <p> 391 * To create server group templates or ones for server queries, 392 * use {@link #addServerGroup(String, PermissionGroupDatabaseType)}. 393 * </p> 394 * 395 * @param name 396 * the name of the new server group 397 * 398 * @return the ID of the newly created server group 399 * 400 * @querycommands 1 401 * @see ServerGroup 402 */ 403 public CommandFuture<Integer> addServerGroup(String name) { 404 return addServerGroup(name, PermissionGroupDatabaseType.REGULAR); 405 } 406 407 /** 408 * Creates a new server group using a given name and returns its ID. 409 * 410 * @param name 411 * the name of the new server group 412 * @param type 413 * the desired type of server group 414 * 415 * @return the ID of the newly created server group 416 * 417 * @querycommands 1 418 * @see ServerGroup 419 * @see PermissionGroupDatabaseType 420 */ 421 public CommandFuture<Integer> addServerGroup(String name, PermissionGroupDatabaseType type) { 422 final CServerGroupAdd add = new CServerGroupAdd(name, type); 423 return executeAndReturnIntProperty(add, "sgid"); 424 } 425 426 /** 427 * Adds a specified permission to a server group. 428 * 429 * @param groupId 430 * the ID of the channel group to which the permission should be added 431 * @param permName 432 * the name of the permission to add 433 * @param value 434 * the numeric value of the permission (or for boolean permissions: 1 = true, 0 = false) 435 * @param negated 436 * if set to true, the lowest permission value will be selected instead of the highest 437 * @param skipped 438 * if set to true, this permission will not be overridden by client of channel permissions 439 * 440 * @return whether the command succeeded or not 441 * 442 * @querycommands 1 443 * @see ServerGroup#getId() 444 * @see Permission 445 */ 446 public CommandFuture<Boolean> addServerGroupPermission(int groupId, String permName, int value, boolean negated, boolean skipped) { 447 final CServerGroupAddPerm add = new CServerGroupAddPerm(groupId, permName, value, negated, skipped); 448 return executeAndReturnError(add); 449 } 450 451 /** 452 * Adds one or more {@link TS3Listener}s to the event manager of the query. 453 * These listeners will be notified when the TS3 server fires an event. 454 * <p> 455 * Note that for the TS3 server to fire events, you must first also register 456 * the event types you want to listen to. 457 * </p> 458 * 459 * @param listeners 460 * one or more listeners to register 461 * 462 * @see #registerAllEvents() 463 * @see #registerEvent(TS3EventType, int) 464 * @see TS3Listener 465 * @see TS3EventType 466 */ 467 public void addTS3Listeners(TS3Listener... listeners) { 468 query.getEventManager().addListeners(listeners); 469 } 470 471 /** 472 * Bans a client with a given client ID for a given time. 473 * <p> 474 * Please note that this will create two separate ban rules, 475 * one for the targeted client's IP address and their unique identifier. 476 * </p> 477 * 478 * @param clientId 479 * the ID of the client 480 * @param timeInSeconds 481 * the duration of the ban in seconds. 0 equals a permanent ban 482 * 483 * @return an array containing the IDs of the first and the second ban entry 484 * 485 * @querycommands 1 486 * @see Client#getId() 487 * @see #addBan(String, String, String, long, String) 488 */ 489 public CommandFuture<Integer[]> banClient(int clientId, long timeInSeconds) { 490 return banClient(clientId, timeInSeconds, null); 491 } 492 493 /** 494 * Bans a client with a given client ID for a given time for the specified reason. 495 * <p> 496 * Please note that this will create two separate ban rules, 497 * one for the targeted client's IP address and their unique identifier. 498 * </p> 499 * 500 * @param clientId 501 * the ID of the client 502 * @param timeInSeconds 503 * the duration of the ban in seconds. 0 equals a permanent ban 504 * @param reason 505 * the reason for the ban, can be null 506 * 507 * @return an array containing the IDs of the first and the second ban entry 508 * 509 * @querycommands 1 510 * @see Client#getId() 511 * @see #addBan(String, String, String, long, String) 512 */ 513 public CommandFuture<Integer[]> banClient(int clientId, long timeInSeconds, String reason) { 514 final CBanClient client = new CBanClient(clientId, timeInSeconds, reason); 515 final CommandFuture<Integer[]> future = new CommandFuture<>(); 516 517 query.doCommandAsync(client, new Callback() { 518 @Override 519 public void handle() { 520 if (hasFailed(client, future)) return; 521 522 final List<Wrapper> response = client.getResponse(); 523 final int banId1 = response.get(0).getInt("banid"); 524 final int banId2 = response.get(1).getInt("banid"); 525 future.set(new Integer[] {banId1, banId2}); 526 } 527 }); 528 return future; 529 } 530 531 /** 532 * Bans a client with a given client ID permanently for the specified reason. 533 * <p> 534 * Please note that this will create two separate ban rules, 535 * one for the targeted client's IP address and their unique identifier. 536 * </p> 537 * 538 * @param clientId 539 * the ID of the client 540 * @param reason 541 * the reason for the ban, can be null 542 * 543 * @return an array containing the IDs of the first and the second ban entry 544 * 545 * @querycommands 1 546 * @see Client#getId() 547 * @see #addBan(String, String, String, long, String) 548 */ 549 public CommandFuture<Integer[]> banClient(int clientId, String reason) { 550 return banClient(clientId, 0, reason); 551 } 552 553 /** 554 * Sends a text message to all clients on all virtual servers. 555 * These messages will appear to clients in the tab for server messages. 556 * 557 * @param message 558 * the message to be sent 559 * 560 * @return whether the command succeeded or not 561 * 562 * @querycommands 1 563 */ 564 public CommandFuture<Boolean> broadcast(String message) { 565 final CGM broadcast = new CGM(message); 566 return executeAndReturnError(broadcast); 567 } 568 569 /** 570 * Creates a copy of the channel group specified by {@code sourceGroupId}, 571 * overwriting any other channel group specified by {@code targetGroupId}. 572 * <p> 573 * The parameter {@code type} can be used to create server query and template groups. 574 * </p> 575 * 576 * @param sourceGroupId 577 * the ID of the channel group to copy 578 * @param targetGroupId 579 * the ID of another channel group to overwrite 580 * @param type 581 * the desired type of channel group 582 * 583 * @return whether the command succeeded or not 584 * 585 * @querycommands 1 586 * @see ChannelGroup#getId() 587 */ 588 public CommandFuture<Boolean> copyChannelGroup(int sourceGroupId, int targetGroupId, PermissionGroupDatabaseType type) { 589 if (targetGroupId <= 0) { 590 throw new IllegalArgumentException("To create a new channel group, use the method with a String argument"); 591 } 592 593 final CChannelGroupCopy copy = new CChannelGroupCopy(sourceGroupId, targetGroupId, type); 594 return executeAndReturnError(copy); 595 } 596 597 /** 598 * Creates a copy of the channel group specified by {@code sourceGroupId} with a given name 599 * and returns the ID of the newly created channel group. 600 * 601 * @param sourceGroupId 602 * the ID of the channel group to copy 603 * @param targetName 604 * the name for the copy of the channel group 605 * @param type 606 * the desired type of channel group 607 * 608 * @return the ID of the newly created channel group 609 * 610 * @querycommands 1 611 * @see ChannelGroup#getId() 612 */ 613 public CommandFuture<Integer> copyChannelGroup(int sourceGroupId, String targetName, PermissionGroupDatabaseType type) { 614 final CChannelGroupCopy copy = new CChannelGroupCopy(sourceGroupId, targetName, type); 615 return executeAndReturnIntProperty(copy, "cgid"); 616 } 617 618 /** 619 * Creates a copy of the server group specified by {@code sourceGroupId}, 620 * overwriting another server group specified by {@code targetGroupId}. 621 * <p> 622 * The parameter {@code type} can be used to create server query and template groups. 623 * </p> 624 * 625 * @param sourceGroupId 626 * the ID of the server group to copy 627 * @param targetGroupId 628 * the ID of another server group to overwrite 629 * @param type 630 * the desired type of server group 631 * 632 * @return whether the command succeeded or not 633 * 634 * @querycommands 1 635 * @see ServerGroup#getId() 636 */ 637 public CommandFuture<Integer> copyServerGroup(int sourceGroupId, int targetGroupId, PermissionGroupDatabaseType type) { 638 if (targetGroupId <= 0) { 639 throw new IllegalArgumentException("To create a new server group, use the method with a String argument"); 640 } 641 642 final CServerGroupCopy copy = new CServerGroupCopy(sourceGroupId, targetGroupId, type); 643 return executeAndReturnIntProperty(copy, "sgid"); 644 } 645 646 /** 647 * Creates a copy of the server group specified by {@code sourceGroupId} with a given name 648 * and returns the ID of the newly created server group. 649 * 650 * @param sourceGroupId 651 * the ID of the server group to copy 652 * @param targetName 653 * the name for the copy of the server group 654 * @param type 655 * the desired type of server group 656 * 657 * @return the ID of the newly created server group 658 * 659 * @querycommands 1 660 * @see ServerGroup#getId() 661 */ 662 public CommandFuture<Integer> copyServerGroup(int sourceGroupId, String targetName, PermissionGroupDatabaseType type) { 663 final CServerGroupCopy copy = new CServerGroupCopy(sourceGroupId, targetName, type); 664 return executeAndReturnIntProperty(copy, "sgid"); 665 } 666 667 /** 668 * Creates a new channel with a given name using the given properties and returns its ID. 669 * 670 * @param name 671 * the name for the new channel 672 * @param options 673 * a map of options that should be set for the channel 674 * 675 * @return the ID of the newly created channel 676 * 677 * @querycommands 1 678 * @see Channel 679 */ 680 public CommandFuture<Integer> createChannel(String name, Map<ChannelProperty, String> options) { 681 final CChannelCreate create = new CChannelCreate(name, options); 682 return executeAndReturnIntProperty(create, "cid"); 683 } 684 685 /** 686 * Creates a new virtual server with the given name and returns an object containing the ID of the newly 687 * created virtual server, the default server admin token and the virtual server's voice port. Usually, 688 * the virtual server is also automatically started. This can be turned off on the TS3 server, though. 689 * <p> 690 * If {@link VirtualServerProperty#VIRTUALSERVER_PORT} is not specified in the virtual server properties, 691 * the server will test for the first unused UDP port. 692 * </p><p> 693 * Please also note that creating virtual servers usually requires the server query admin account 694 * and that there is a limit to how many virtual servers can be created, which is dependent on your license. 695 * Unlicensed TS3 server instances are limited to 1 virtual server with up to 32 client slots. 696 * </p> 697 * 698 * @param name 699 * the name for the new virtual server 700 * @param options 701 * a map of options that should be set for the virtual server 702 * 703 * @return information about the newly created virtual server 704 * 705 * @querycommands 1 706 * @see VirtualServer 707 */ 708 public CommandFuture<CreatedVirtualServer> createServer(String name, Map<VirtualServerProperty, String> options) { 709 final CServerCreate create = new CServerCreate(name, options); 710 final CommandFuture<CreatedVirtualServer> future = new CommandFuture<>(); 711 712 query.doCommandAsync(create, new Callback() { 713 @Override 714 public void handle() { 715 if (hasFailed(create, future)) return; 716 future.set(new CreatedVirtualServer(create.getFirstResponse().getMap())); 717 } 718 }); 719 return future; 720 } 721 722 /** 723 * Creates a {@link Snapshot} of the selected virtual server containing all settings, 724 * groups and known client identities. The data from a server snapshot can be 725 * used to restore a virtual servers configuration. 726 * 727 * @return a snapshot of the virtual server 728 * 729 * @querycommands 1 730 * @see #deployServerSnapshot(Snapshot) 731 */ 732 public CommandFuture<Snapshot> createServerSnapshot() { 733 final CServerSnapshotCreate create = new CServerSnapshotCreate(); 734 final CommandFuture<Snapshot> future = new CommandFuture<>(); 735 736 query.doCommandAsync(create, new Callback() { 737 @Override 738 public void handle() { 739 if (hasFailed(create, future)) return; 740 future.set(new Snapshot(create.getRaw())); 741 } 742 }); 743 return future; 744 } 745 746 /** 747 * Deletes all active ban rules from the server. Use with caution. 748 * 749 * @return whether the command succeeded or not 750 * 751 * @querycommands 1 752 */ 753 public CommandFuture<Boolean> deleteAllBans() { 754 final CBanDelAll del = new CBanDelAll(); 755 return executeAndReturnError(del); 756 } 757 758 /** 759 * Deletes all complaints about the client with specified database ID from the server. 760 * 761 * @param clientDBId 762 * the database ID of the client 763 * 764 * @return whether the command succeeded or not 765 * 766 * @querycommands 1 767 * @see Client#getDatabaseId() 768 * @see Complaint 769 */ 770 public CommandFuture<Boolean> deleteAllComplaints(int clientDBId) { 771 final CComplainDelAll del = new CComplainDelAll(clientDBId); 772 return executeAndReturnError(del); 773 } 774 775 /** 776 * Deletes the ban rule with the specified ID from the server. 777 * 778 * @param banId 779 * the ID of the ban to delete 780 * 781 * @return whether the command succeeded or not 782 * 783 * @querycommands 1 784 * @see Ban#getId() 785 */ 786 public CommandFuture<Boolean> deleteBan(int banId) { 787 final CBanDel del = new CBanDel(banId); 788 return executeAndReturnError(del); 789 } 790 791 /** 792 * Deletes an existing channel specified by its ID, kicking all clients out of the channel. 793 * 794 * @param channelId 795 * the ID of the channel to delete 796 * 797 * @return whether the command succeeded or not 798 * 799 * @querycommands 1 800 * @see Channel#getId() 801 * @see #deleteChannel(int, boolean) 802 * @see #kickClientFromChannel(String, int...) 803 */ 804 public CommandFuture<Boolean> deleteChannel(int channelId) { 805 return deleteChannel(channelId, true); 806 } 807 808 /** 809 * Deletes an existing channel with a given ID. 810 * If {@code force} is true, the channel will be deleted even if there are clients within, 811 * else the command will fail in this situation. 812 * 813 * @param channelId 814 * the ID of the channel to delete 815 * @param force 816 * whether clients should be kicked out of the channel 817 * 818 * @return whether the command succeeded or not 819 * 820 * @querycommands 1 821 * @see Channel#getId() 822 * @see #kickClientFromChannel(String, int...) 823 */ 824 public CommandFuture<Boolean> deleteChannel(int channelId, boolean force) { 825 final CChannelDelete del = new CChannelDelete(channelId, force); 826 return executeAndReturnError(del); 827 } 828 829 /** 830 * Removes a specified permission from a client in a specific channel. 831 * 832 * @param channelId 833 * the ID of the channel wherein the permission should be removed 834 * @param clientDBId 835 * the database ID of the client 836 * @param permName 837 * the name of the permission to revoke 838 * 839 * @return whether the command succeeded or not 840 * 841 * @querycommands 1 842 * @see Channel#getId() 843 * @see Client#getDatabaseId() 844 * @see Permission#getName() 845 */ 846 public CommandFuture<Boolean> deleteChannelClientPermission(int channelId, int clientDBId, String permName) { 847 final CChannelClientDelPerm del = new CChannelClientDelPerm(channelId, clientDBId, permName); 848 return executeAndReturnError(del); 849 } 850 851 /** 852 * Removes the channel group with the given ID. 853 * 854 * @param groupId 855 * the ID of the channel group 856 * 857 * @return whether the command succeeded or not 858 * 859 * @querycommands 1 860 * @see ChannelGroup#getId() 861 */ 862 public CommandFuture<Boolean> deleteChannelGroup(int groupId) { 863 return deleteChannelGroup(groupId, true); 864 } 865 866 /** 867 * Removes the channel group with the given ID. 868 * If {@code force} is true, the channel group will be deleted even if it still contains clients, 869 * else the command will fail in this situation. 870 * 871 * @param groupId 872 * the ID of the channel group 873 * @param force 874 * whether the channel group should be deleted even if it still contains clients 875 * 876 * @return whether the command succeeded or not 877 * 878 * @querycommands 1 879 * @see ChannelGroup#getId() 880 */ 881 public CommandFuture<Boolean> deleteChannelGroup(int groupId, boolean force) { 882 final CChannelGroupDel del = new CChannelGroupDel(groupId, force); 883 return executeAndReturnError(del); 884 } 885 886 /** 887 * Removes a permission from the channel group with the given ID. 888 * 889 * @param groupId 890 * the ID of the channel group 891 * @param permName 892 * the name of the permission to revoke 893 * 894 * @return whether the command succeeded or not 895 * 896 * @querycommands 1 897 * @see ChannelGroup#getId() 898 * @see Permission#getName() 899 */ 900 public CommandFuture<Boolean> deleteChannelGroupPermission(int groupId, String permName) { 901 final CChannelGroupDelPerm del = new CChannelGroupDelPerm(groupId, permName); 902 return executeAndReturnError(del); 903 } 904 905 /** 906 * Removes a permission from the channel with the given ID. 907 * 908 * @param channelId 909 * the ID of the channel 910 * @param permName 911 * the name of the permission to revoke 912 * 913 * @return whether the command succeeded or not 914 * 915 * @querycommands 1 916 * @see Channel#getId() 917 * @see Permission#getName() 918 */ 919 public CommandFuture<Boolean> deleteChannelPermission(int channelId, String permName) { 920 final CChannelDelPerm del = new CChannelDelPerm(channelId, permName); 921 return executeAndReturnError(del); 922 } 923 924 /** 925 * Removes a permission from a client. 926 * 927 * @param clientDBId 928 * the database ID of the client 929 * @param permName 930 * the name of the permission to revoke 931 * 932 * @return whether the command succeeded or not 933 * 934 * @querycommands 1 935 * @see Client#getDatabaseId() 936 * @see Permission#getName() 937 */ 938 public CommandFuture<Boolean> deleteClientPermission(int clientDBId, String permName) { 939 final CClientDelPerm del = new CClientDelPerm(clientDBId, permName); 940 return executeAndReturnError(del); 941 } 942 943 /** 944 * Deletes the complaint about the client with database ID {@code targetClientDBId} submitted by 945 * the client with database ID {@code fromClientDBId} from the server. 946 * 947 * @param targetClientDBId 948 * the database ID of the client the complaint is about 949 * @param fromClientDBId 950 * the database ID of the client who added the complaint 951 * 952 * @return whether the command succeeded or not 953 * 954 * @querycommands 1 955 * @see Complaint 956 * @see Client#getDatabaseId() 957 */ 958 public CommandFuture<Boolean> deleteComplaint(int targetClientDBId, int fromClientDBId) { 959 final CComplainDel del = new CComplainDel(targetClientDBId, fromClientDBId); 960 return executeAndReturnError(del); 961 } 962 963 /** 964 * Removes all stored database information about the specified client. 965 * Please note that this data is also automatically removed after a configured time (usually 90 days). 966 * <p> 967 * See {@link DatabaseClientInfo} for a list of stored information about a client. 968 * </p> 969 * 970 * @param clientDBId 971 * the database ID of the client 972 * 973 * @return whether the command succeeded or not 974 * 975 * @querycommands 1 976 * @see Client#getDatabaseId() 977 * @see #getDatabaseClientInfo(int) 978 * @see DatabaseClientInfo 979 */ 980 public CommandFuture<Boolean> deleteDatabaseClientProperties(int clientDBId) { 981 final CClientDBDelete del = new CClientDBDelete(clientDBId); 982 return executeAndReturnError(del); 983 } 984 985 /** 986 * Deletes the offline message with the specified ID. 987 * 988 * @param messageId 989 * the ID of the offline message to delete 990 * 991 * @return whether the command succeeded or not 992 * 993 * @querycommands 1 994 * @see Message#getId() 995 */ 996 public CommandFuture<Boolean> deleteOfflineMessage(int messageId) { 997 final CMessageDel del = new CMessageDel(messageId); 998 return executeAndReturnError(del); 999 } 1000 1001 /** 1002 * Removes a specified permission from all server groups of the type specified by {@code type} on all virtual servers. 1003 * 1004 * @param type 1005 * the kind of server group this permission should be removed from 1006 * @param permName 1007 * the name of the permission to remove 1008 * 1009 * @return whether the command succeeded or not 1010 * 1011 * @querycommands 1 1012 * @see ServerGroupType 1013 * @see Permission#getName() 1014 */ 1015 public CommandFuture<Boolean> deletePermissionFromAllServerGroups(ServerGroupType type, String permName) { 1016 final CServerGroupAutoDelPerm del = new CServerGroupAutoDelPerm(type, permName); 1017 return executeAndReturnError(del); 1018 } 1019 1020 /** 1021 * Deletes the privilege key with the given token. 1022 * 1023 * @param token 1024 * the token of the privilege key 1025 * 1026 * @return whether the command succeeded or not 1027 * 1028 * @querycommands 1 1029 * @see PrivilegeKey 1030 */ 1031 public CommandFuture<Boolean> deletePrivilegeKey(String token) { 1032 final CPrivilegeKeyDelete del = new CPrivilegeKeyDelete(token); 1033 return executeAndReturnError(del); 1034 } 1035 1036 /** 1037 * Deletes the virtual server with the specified ID. 1038 * <p> 1039 * Only stopped virtual servers can be deleted. 1040 * </p> 1041 * 1042 * @param serverId 1043 * the ID of the virtual server 1044 * 1045 * @return whether the command succeeded or not 1046 * 1047 * @querycommands 1 1048 * @see VirtualServer#getId() 1049 * @see #stopServer(int) 1050 */ 1051 public CommandFuture<Boolean> deleteServer(int serverId) { 1052 final CServerDelete delete = new CServerDelete(serverId); 1053 return executeAndReturnError(delete); 1054 } 1055 1056 /** 1057 * Deletes the server group with the specified ID, even if the server group still contains clients. 1058 * 1059 * @param groupId 1060 * the ID of the server group 1061 * 1062 * @return whether the command succeeded or not 1063 * 1064 * @querycommands 1 1065 * @see ServerGroup#getId() 1066 */ 1067 public CommandFuture<Boolean> deleteServerGroup(int groupId) { 1068 return deleteServerGroup(groupId, true); 1069 } 1070 1071 /** 1072 * Deletes a server group with the specified ID. 1073 * <p> 1074 * If {@code force} is true, the server group will be deleted even if it contains clients, 1075 * else the command will fail in this situation. 1076 * </p> 1077 * 1078 * @param groupId 1079 * the ID of the server group 1080 * @param force 1081 * whether the server group should be deleted if it still contains clients 1082 * 1083 * @return whether the command succeeded or not 1084 * 1085 * @querycommands 1 1086 * @see ServerGroup#getId() 1087 */ 1088 public CommandFuture<Boolean> deleteServerGroup(int groupId, boolean force) { 1089 final CServerGroupDel del = new CServerGroupDel(groupId, force); 1090 return executeAndReturnError(del); 1091 } 1092 1093 /** 1094 * Removes a permission from the server group with the given ID. 1095 * 1096 * @param groupId 1097 * the ID of the server group 1098 * @param permName 1099 * the name of the permission to revoke 1100 * 1101 * @return whether the command succeeded or not 1102 * 1103 * @querycommands 1 1104 * @see ServerGroup#getId() 1105 * @see Permission#getName() 1106 */ 1107 public CommandFuture<Boolean> deleteServerGroupPermission(int groupId, String permName) { 1108 final CServerGroupDelPerm del = new CServerGroupDelPerm(groupId, permName); 1109 return executeAndReturnError(del); 1110 } 1111 1112 /** 1113 * Restores the selected virtual servers configuration using the data from a 1114 * previously created server snapshot. 1115 * 1116 * @param snapshot 1117 * the snapshot to restore 1118 * 1119 * @return whether the command succeeded or not 1120 * 1121 * @querycommands 1 1122 * @see #createServerSnapshot() 1123 */ 1124 public CommandFuture<Boolean> deployServerSnapshot(Snapshot snapshot) { 1125 return deployServerSnapshot(snapshot.get()); 1126 } 1127 1128 /** 1129 * Restores the configuration of the selected virtual server using the data from a 1130 * previously created server snapshot. 1131 * 1132 * @param snapshot 1133 * the snapshot to restore 1134 * 1135 * @return whether the command succeeded or not 1136 * 1137 * @querycommands 1 1138 * @see #createServerSnapshot() 1139 */ 1140 public CommandFuture<Boolean> deployServerSnapshot(String snapshot) { 1141 final CServerSnapshotDeploy deploy = new CServerSnapshotDeploy(snapshot); 1142 return executeAndReturnError(deploy); 1143 } 1144 1145 /** 1146 * Changes a channel's configuration using the given properties. 1147 * 1148 * @param channelId 1149 * the ID of the channel to edit 1150 * @param options 1151 * the map of properties to modify 1152 * 1153 * @return whether the command succeeded or not 1154 * 1155 * @querycommands 1 1156 * @see Channel#getId() 1157 */ 1158 public CommandFuture<Boolean> editChannel(int channelId, Map<ChannelProperty, String> options) { 1159 final CChannelEdit edit = new CChannelEdit(channelId, options); 1160 return executeAndReturnError(edit); 1161 } 1162 1163 /** 1164 * Changes a client's configuration using given properties. 1165 * <p> 1166 * Only {@link ClientProperty#CLIENT_DESCRIPTION} can be changed for other clients. 1167 * To update the current client's properties, use {@link #updateClient(Map)}. 1168 * </p> 1169 * 1170 * @param clientId 1171 * the ID of the client to edit 1172 * @param options 1173 * the map of properties to modify 1174 * 1175 * @return whether the command succeeded or not 1176 * 1177 * @querycommands 1 1178 * @see Client#getId() 1179 * @see #updateClient(Map) 1180 */ 1181 public CommandFuture<Boolean> editClient(int clientId, Map<ClientProperty, String> options) { 1182 final CClientEdit edit = new CClientEdit(clientId, options); 1183 return executeAndReturnError(edit); 1184 } 1185 1186 /** 1187 * Changes a client's database settings using given properties. 1188 * 1189 * @param clientDBId 1190 * the database ID of the client to edit 1191 * @param options 1192 * the map of properties to modify 1193 * 1194 * @return whether the command succeeded or not 1195 * 1196 * @querycommands 1 1197 * @see DatabaseClientInfo 1198 * @see Client#getDatabaseId() 1199 */ 1200 public CommandFuture<Boolean> editDatabaseClient(int clientDBId, Map<ClientProperty, String> options) { 1201 final CClientDBEdit edit = new CClientDBEdit(clientDBId, options); 1202 return executeAndReturnError(edit); 1203 } 1204 1205 /** 1206 * Changes the server instance configuration using given properties. 1207 * If the given property is not changeable, {@code IllegalArgumentException} will be thrown. 1208 * 1209 * @param property 1210 * the property to edit, must be changeable 1211 * @param value 1212 * the new value for the edit 1213 * 1214 * @return whether the command succeeded or not 1215 * 1216 * @throws IllegalArgumentException 1217 * if {@code property} is not changeable 1218 * @querycommands 1 1219 * @see ServerInstanceProperty#isChangeable() 1220 */ 1221 public CommandFuture<Boolean> editInstance(ServerInstanceProperty property, String value) { 1222 if (!property.isChangeable()) { 1223 throw new IllegalArgumentException("Property is not changeable"); 1224 } 1225 1226 final CInstanceEdit edit = new CInstanceEdit(property, value); 1227 return executeAndReturnError(edit); 1228 } 1229 1230 /** 1231 * Changes the configuration of the selected virtual server using given properties. 1232 * 1233 * @param options 1234 * the map of properties to edit 1235 * 1236 * @return whether the command succeeded or not 1237 * 1238 * @querycommands 1 1239 * @see VirtualServerProperty 1240 */ 1241 public CommandFuture<Boolean> editServer(Map<VirtualServerProperty, String> options) { 1242 final CServerEdit edit = new CServerEdit(options); 1243 return executeAndReturnError(edit); 1244 } 1245 1246 /** 1247 * Gets a list of all bans on the selected virtual server. 1248 * 1249 * @return a list of all bans on the virtual server 1250 * 1251 * @querycommands 1 1252 * @see Ban 1253 */ 1254 public CommandFuture<List<Ban>> getBans() { 1255 final CBanList list = new CBanList(); 1256 final CommandFuture<List<Ban>> future = new CommandFuture<>(); 1257 1258 query.doCommandAsync(list, new Callback() { 1259 @Override 1260 public void handle() { 1261 if (hasFailed(list, future)) return; 1262 1263 final List<Wrapper> responses = list.getResponse(); 1264 final List<Ban> bans = new ArrayList<>(responses.size()); 1265 1266 for (final Wrapper response : responses) { 1267 bans.add(new Ban(response.getMap())); 1268 } 1269 future.set(bans); 1270 } 1271 }); 1272 return future; 1273 } 1274 1275 /** 1276 * Gets a list of IP addresses used by the server instance. 1277 * 1278 * @return the list of bound IP addresses 1279 * 1280 * @querycommands 1 1281 * @see Binding 1282 */ 1283 public CommandFuture<List<Binding>> getBindings() { 1284 final CBindingList list = new CBindingList(); 1285 final CommandFuture<List<Binding>> future = new CommandFuture<>(); 1286 1287 query.doCommandAsync(list, new Callback() { 1288 @Override 1289 public void handle() { 1290 if (hasFailed(list, future)) return; 1291 1292 final List<Wrapper> responses = list.getResponse(); 1293 final List<Binding> bindings = new ArrayList<>(responses.size()); 1294 1295 for (final Wrapper response : responses) { 1296 bindings.add(new Binding(response.getMap())); 1297 } 1298 future.set(bindings); 1299 } 1300 }); 1301 return future; 1302 } 1303 1304 /** 1305 * Finds and returns the channel matching the given name exactly. 1306 * 1307 * @param name 1308 * the name of the channel 1309 * @param ignoreCase 1310 * whether the case of the name should be ignored 1311 * 1312 * @return the found channel or {@code null} if no channel was found 1313 * 1314 * @querycommands 1 1315 * @see Channel 1316 * @see #getChannelsByName(String) 1317 */ 1318 public CommandFuture<Channel> getChannelByNameExact(String name, final boolean ignoreCase) { 1319 final CommandFuture<Channel> future = new CommandFuture<>(); 1320 final String caseName = ignoreCase ? name.toLowerCase() : name; 1321 1322 getChannels().onSuccess(new CommandFuture.SuccessListener<List<Channel>>() { 1323 @Override 1324 public void handleSuccess(final List<Channel> allChannels) { 1325 for (final Channel c : allChannels) { 1326 final String channelName = ignoreCase ? c.getName().toLowerCase() : c.getName(); 1327 if (caseName.equals(channelName)) { 1328 future.set(c); 1329 return; 1330 } 1331 } 1332 future.set(null); // Not found 1333 } 1334 }).forwardFailure(future); 1335 return future; 1336 } 1337 1338 /** 1339 * Gets a list of channels whose names contain the given search string. 1340 * 1341 * @param name 1342 * the name to search 1343 * 1344 * @return a list of all channels with names matching the search pattern 1345 * 1346 * @querycommands 2 1347 * @see Channel 1348 * @see #getChannelByNameExact(String, boolean) 1349 */ 1350 public CommandFuture<List<Channel>> getChannelsByName(String name) { 1351 final CChannelFind find = new CChannelFind(name); 1352 final CommandFuture<List<Channel>> future = new CommandFuture<>(); 1353 1354 getChannels().onSuccess(new CommandFuture.SuccessListener<List<Channel>>() { 1355 @Override 1356 public void handleSuccess(final List<Channel> allChannels) { 1357 query.doCommandAsync(find, new Callback() { 1358 @Override 1359 public void handle() { 1360 if (hasFailed(find, future)) return; 1361 1362 final List<Wrapper> responses = find.getResponse(); 1363 final List<Channel> channels = new ArrayList<>(responses.size()); 1364 1365 for (final Wrapper response : responses) { 1366 final int channelId = response.getInt("cid"); 1367 for (final Channel c : allChannels) { 1368 if (c.getId() == channelId) { 1369 channels.add(c); 1370 break; 1371 } 1372 } 1373 } 1374 future.set(channels); 1375 } 1376 }); 1377 } 1378 }).forwardFailure(future); 1379 return future; 1380 } 1381 1382 /** 1383 * Displays a list of permissions defined for a client in a specific channel. 1384 * 1385 * @param channelId 1386 * the ID of the channel 1387 * @param clientDBId 1388 * the database ID of the client 1389 * 1390 * @return a list of permissions for the user in the specified channel 1391 * 1392 * @querycommands 1 1393 * @see Channel#getId() 1394 * @see Client#getDatabaseId() 1395 * @see Permission 1396 */ 1397 public CommandFuture<List<Permission>> getChannelClientPermissions(int channelId, int clientDBId) { 1398 final CChannelClientPermList list = new CChannelClientPermList(channelId, clientDBId); 1399 final CommandFuture<List<Permission>> future = new CommandFuture<>(); 1400 1401 query.doCommandAsync(list, new Callback() { 1402 @Override 1403 public void handle() { 1404 if (hasFailed(list, future)) return; 1405 1406 final List<Wrapper> responses = list.getResponse(); 1407 final List<Permission> permissions = new ArrayList<>(responses.size()); 1408 1409 for (final Wrapper response : responses) { 1410 permissions.add(new Permission(response.getMap())); 1411 } 1412 future.set(permissions); 1413 } 1414 }); 1415 return future; 1416 } 1417 1418 /** 1419 * Gets all client / channel ID combinations currently assigned to channel groups. 1420 * All three parameters are optional and can be turned off by setting it to {@code -1}. 1421 * 1422 * @param channelId 1423 * restricts the search to the channel with a specified ID. Set to {@code -1} to ignore. 1424 * @param clientDBId 1425 * restricts the search to the client with a specified database ID. Set to {@code -1} to ignore. 1426 * @param groupId 1427 * restricts the search to the channel group with the specified ID. Set to {@code -1} to ignore. 1428 * 1429 * @return a list of combinations of channel ID, client database ID and channel group ID 1430 * 1431 * @querycommands 1 1432 * @see Channel#getId() 1433 * @see Client#getDatabaseId() 1434 * @see ChannelGroup#getId() 1435 * @see ChannelGroupClient 1436 */ 1437 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClients(int channelId, int clientDBId, int groupId) { 1438 final CChannelGroupClientList list = new CChannelGroupClientList(channelId, clientDBId, groupId); 1439 final CommandFuture<List<ChannelGroupClient>> future = new CommandFuture<>(); 1440 1441 query.doCommandAsync(list, new Callback() { 1442 @Override 1443 public void handle() { 1444 if (hasFailed(list, future)) return; 1445 1446 final List<Wrapper> responses = list.getResponse(); 1447 final List<ChannelGroupClient> clients = new ArrayList<>(responses.size()); 1448 1449 for (final Wrapper response : responses) { 1450 clients.add(new ChannelGroupClient(response.getMap())); 1451 } 1452 future.set(clients); 1453 } 1454 }); 1455 return future; 1456 } 1457 1458 /** 1459 * Gets all client / channel ID combinations currently assigned to the specified channel group. 1460 * 1461 * @param groupId 1462 * the ID of the channel group whose client / channel assignments should be returned. 1463 * 1464 * @return a list of combinations of channel ID, client database ID and channel group ID 1465 * 1466 * @querycommands 1 1467 * @see ChannelGroup#getId() 1468 * @see ChannelGroupClient 1469 * @see #getChannelGroupClients(int, int, int) 1470 */ 1471 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClientsByChannelGroupId(int groupId) { 1472 return getChannelGroupClients(-1, -1, groupId); 1473 } 1474 1475 /** 1476 * Gets all channel group assignments in the specified channel. 1477 * 1478 * @param channelId 1479 * the ID of the channel whose channel group assignments should be returned. 1480 * 1481 * @return a list of combinations of channel ID, client database ID and channel group ID 1482 * 1483 * @querycommands 1 1484 * @see Channel#getId() 1485 * @see ChannelGroupClient 1486 * @see #getChannelGroupClients(int, int, int) 1487 */ 1488 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClientsByChannelId(int channelId) { 1489 return getChannelGroupClients(channelId, -1, -1); 1490 } 1491 1492 /** 1493 * Gets all channel group assignments for the specified client. 1494 * 1495 * @param clientDBId 1496 * the database ID of the client whose channel group 1497 * 1498 * @return a list of combinations of channel ID, client database ID and channel group ID 1499 * 1500 * @querycommands 1 1501 * @see Client#getDatabaseId() 1502 * @see ChannelGroupClient 1503 * @see #getChannelGroupClients(int, int, int) 1504 */ 1505 public CommandFuture<List<ChannelGroupClient>> getChannelGroupClientsByClientDBId(int clientDBId) { 1506 return getChannelGroupClients(-1, clientDBId, -1); 1507 } 1508 1509 /** 1510 * Gets a list of all permissions assigned to the specified channel group. 1511 * 1512 * @param groupId 1513 * the ID of the channel group. 1514 * 1515 * @return a list of permissions assigned to the channel group 1516 * 1517 * @querycommands 1 1518 * @see ChannelGroup#getId() 1519 * @see Permission 1520 */ 1521 public CommandFuture<List<Permission>> getChannelGroupPermissions(int groupId) { 1522 final CChannelGroupPermList list = new CChannelGroupPermList(groupId); 1523 final CommandFuture<List<Permission>> future = new CommandFuture<>(); 1524 1525 query.doCommandAsync(list, new Callback() { 1526 @Override 1527 public void handle() { 1528 if (hasFailed(list, future)) return; 1529 1530 final List<Wrapper> responses = list.getResponse(); 1531 final List<Permission> permissions = new ArrayList<>(responses.size()); 1532 1533 for (final Wrapper response : responses) { 1534 permissions.add(new Permission(response.getMap())); 1535 } 1536 future.set(permissions); 1537 } 1538 }); 1539 return future; 1540 } 1541 1542 /** 1543 * Gets a list of all channel groups on the selected virtual server. 1544 * 1545 * @return a list of all channel groups on the virtual server 1546 * 1547 * @querycommands 1 1548 * @see ChannelGroup 1549 */ 1550 public CommandFuture<List<ChannelGroup>> getChannelGroups() { 1551 final CChannelGroupList list = new CChannelGroupList(); 1552 final CommandFuture<List<ChannelGroup>> future = new CommandFuture<>(); 1553 1554 query.doCommandAsync(list, new Callback() { 1555 @Override 1556 public void handle() { 1557 if (hasFailed(list, future)) return; 1558 1559 final List<Wrapper> responses = list.getResponse(); 1560 final List<ChannelGroup> groups = new ArrayList<>(responses.size()); 1561 1562 for (final Wrapper response : responses) { 1563 groups.add(new ChannelGroup(response.getMap())); 1564 } 1565 future.set(groups); 1566 } 1567 }); 1568 return future; 1569 } 1570 1571 /** 1572 * Gets detailed configuration information about the channel specified channel. 1573 * 1574 * @param channelId 1575 * the ID of the channel 1576 * 1577 * @return information about the channel 1578 * 1579 * @querycommands 1 1580 * @see Channel#getId() 1581 * @see ChannelInfo 1582 */ 1583 public CommandFuture<ChannelInfo> getChannelInfo(final int channelId) { 1584 final CChannelInfo info = new CChannelInfo(channelId); 1585 final CommandFuture<ChannelInfo> future = new CommandFuture<>(); 1586 1587 query.doCommandAsync(info, new Callback() { 1588 @Override 1589 public void handle() { 1590 if (hasFailed(info, future)) return; 1591 future.set(new ChannelInfo(channelId, info.getFirstResponse().getMap())); 1592 } 1593 }); 1594 return future; 1595 } 1596 1597 /** 1598 * Gets a list of all permissions assigned to the specified channel. 1599 * 1600 * @param channelId 1601 * the ID of the channel 1602 * 1603 * @return a list of all permissions assigned to the channel 1604 * 1605 * @querycommands 1 1606 * @see Channel#getId() 1607 * @see Permission 1608 */ 1609 public CommandFuture<List<Permission>> getChannelPermissions(int channelId) { 1610 final CChannelPermList list = new CChannelPermList(channelId); 1611 final CommandFuture<List<Permission>> future = new CommandFuture<>(); 1612 1613 query.doCommandAsync(list, new Callback() { 1614 @Override 1615 public void handle() { 1616 if (hasFailed(list, future)) return; 1617 1618 final List<Wrapper> responses = list.getResponse(); 1619 final List<Permission> permissions = new ArrayList<>(responses.size()); 1620 1621 for (final Wrapper response : responses) { 1622 permissions.add(new Permission(response.getMap())); 1623 } 1624 future.set(permissions); 1625 } 1626 }); 1627 return future; 1628 } 1629 1630 /** 1631 * Gets a list of all channels on the selected virtual server. 1632 * 1633 * @return a list of all channels on the virtual server 1634 * 1635 * @querycommands 1 1636 * @see Channel 1637 */ 1638 public CommandFuture<List<Channel>> getChannels() { 1639 final CChannelList list = new CChannelList(); 1640 final CommandFuture<List<Channel>> future = new CommandFuture<>(); 1641 1642 query.doCommandAsync(list, new Callback() { 1643 @Override 1644 public void handle() { 1645 if (hasFailed(list, future)) return; 1646 1647 final List<Wrapper> responses = list.getResponse(); 1648 final List<Channel> channels = new ArrayList<>(responses.size()); 1649 1650 for (final Wrapper response : responses) { 1651 channels.add(new Channel(response.getMap())); 1652 } 1653 future.set(channels); 1654 } 1655 }); 1656 return future; 1657 } 1658 1659 /** 1660 * Finds and returns the client whose nickname matches the given name exactly. 1661 * 1662 * @param name 1663 * the name of the client 1664 * @param ignoreCase 1665 * whether the case of the name should be ignored 1666 * 1667 * @return the found client or {@code null} if no client was found 1668 * 1669 * @querycommands 1 1670 * @see Client 1671 * @see #getClientsByName(String) 1672 */ 1673 public CommandFuture<Client> getClientByNameExact(String name, final boolean ignoreCase) { 1674 final CommandFuture<Client> future = new CommandFuture<>(); 1675 final String caseName = ignoreCase ? name.toLowerCase() : name; 1676 1677 getClients().onSuccess(new CommandFuture.SuccessListener<List<Client>>() { 1678 @Override 1679 public void handleSuccess(final List<Client> allClients) { 1680 for (final Client c : allClients) { 1681 final String clientName = ignoreCase ? c.getNickname().toLowerCase() : c.getNickname(); 1682 if (caseName.equals(clientName)) { 1683 future.set(c); 1684 return; 1685 } 1686 } 1687 future.set(null); // Not found 1688 } 1689 }).forwardFailure(future); 1690 return future; 1691 } 1692 1693 /** 1694 * Gets a list of clients whose nicknames contain the given search string. 1695 * 1696 * @param name 1697 * the name to search 1698 * 1699 * @return a list of all clients with nicknames matching the search pattern 1700 * 1701 * @querycommands 2 1702 * @see Client 1703 * @see #getClientByNameExact(String, boolean) 1704 */ 1705 public CommandFuture<List<Client>> getClientsByName(String name) { 1706 final CClientFind find = new CClientFind(name); 1707 final CommandFuture<List<Client>> future = new CommandFuture<>(); 1708 1709 getClients().onSuccess(new CommandFuture.SuccessListener<List<Client>>() { 1710 @Override 1711 public void handleSuccess(final List<Client> allClients) { 1712 query.doCommandAsync(find, new Callback() { 1713 @Override 1714 public void handle() { 1715 if (hasFailed(find, future)) return; 1716 1717 final List<Wrapper> responses = find.getResponse(); 1718 final List<Client> clients = new ArrayList<>(responses.size()); 1719 1720 for (final Wrapper response : responses) { 1721 for (final Client c : allClients) { 1722 if (c.getId() == response.getInt("clid")) { 1723 clients.add(c); 1724 break; 1725 } 1726 } 1727 } 1728 future.set(clients); 1729 } 1730 }); 1731 } 1732 }).forwardFailure(future); 1733 return future; 1734 } 1735 1736 /** 1737 * Gets information about the client with the specified unique identifier. 1738 * 1739 * @param clientUId 1740 * the unique identifier of the client 1741 * 1742 * @return the client or {@code null} if no client was found 1743 * 1744 * @querycommands 2 1745 * @see Client#getUniqueIdentifier() 1746 * @see ClientInfo 1747 */ 1748 public CommandFuture<ClientInfo> getClientByUId(String clientUId) { 1749 final CClientGetIds get = new CClientGetIds(clientUId); 1750 final CommandFuture<ClientInfo> future = new CommandFuture<>(); 1751 1752 query.doCommandAsync(get, new Callback() { 1753 @Override 1754 public void handle() { 1755 if (hasFailed(get, future)) return; 1756 1757 getClientInfo(get.getFirstResponse().getInt("clid")).forwardResult(future); 1758 } 1759 }); 1760 return future; 1761 } 1762 1763 /** 1764 * Gets information about the client with the specified client ID. 1765 * 1766 * @param clientId 1767 * the client ID of the client 1768 * 1769 * @return the client or {@code null} if no client was found 1770 * 1771 * @querycommands 1 1772 * @see Client#getId() 1773 * @see ClientInfo 1774 */ 1775 public CommandFuture<ClientInfo> getClientInfo(final int clientId) { 1776 final CClientInfo info = new CClientInfo(clientId); 1777 final CommandFuture<ClientInfo> future = new CommandFuture<>(); 1778 1779 query.doCommandAsync(info, new Callback() { 1780 @Override 1781 public void handle() { 1782 if (hasFailed(info, future)) return; 1783 future.set(new ClientInfo(clientId, info.getFirstResponse().getMap())); 1784 } 1785 }); 1786 return future; 1787 } 1788 1789 /** 1790 * Gets a list of all permissions assigned to the specified client. 1791 * 1792 * @param clientDBId 1793 * the database ID of the client 1794 * 1795 * @return a list of all permissions assigned to the client 1796 * 1797 * @querycommands 1 1798 * @see Client#getDatabaseId() 1799 * @see Permission 1800 */ 1801 public CommandFuture<List<Permission>> getClientPermissions(int clientDBId) { 1802 final CClientPermList list = new CClientPermList(clientDBId); 1803 final CommandFuture<List<Permission>> future = new CommandFuture<>(); 1804 1805 query.doCommandAsync(list, new Callback() { 1806 @Override 1807 public void handle() { 1808 if (hasFailed(list, future)) return; 1809 1810 final List<Wrapper> responses = list.getResponse(); 1811 final List<Permission> permissions = new ArrayList<>(responses.size()); 1812 1813 for (final Wrapper response : responses) { 1814 permissions.add(new Permission(response.getMap())); 1815 } 1816 future.set(permissions); 1817 } 1818 }); 1819 return future; 1820 } 1821 1822 /** 1823 * Gets a list of all clients on the selected virtual server. 1824 * 1825 * @return a list of all clients on the virtual server 1826 * 1827 * @querycommands 1 1828 * @see Client 1829 */ 1830 public CommandFuture<List<Client>> getClients() { 1831 final CClientList list = new CClientList(); 1832 final CommandFuture<List<Client>> future = new CommandFuture<>(); 1833 1834 query.doCommandAsync(list, new Callback() { 1835 @Override 1836 public void handle() { 1837 if (hasFailed(list, future)) return; 1838 1839 final List<Wrapper> responses = list.getResponse(); 1840 final List<Client> clients = new ArrayList<>(responses.size()); 1841 1842 for (final Wrapper response : responses) { 1843 clients.add(new Client(response.getMap())); 1844 } 1845 future.set(clients); 1846 } 1847 }); 1848 return future; 1849 } 1850 1851 /** 1852 * Gets a list of all complaints on the selected virtual server. 1853 * 1854 * @return a list of all complaints on the virtual server 1855 * 1856 * @querycommands 1 1857 * @see Complaint 1858 * @see #getComplaints(int) 1859 */ 1860 public CommandFuture<List<Complaint>> getComplaints() { 1861 return getComplaints(-1); 1862 } 1863 1864 /** 1865 * Gets a list of all complaints about the specified client. 1866 * 1867 * @param clientDBId 1868 * the database ID of the client 1869 * 1870 * @return a list of all complaints about the specified client 1871 * 1872 * @querycommands 1 1873 * @see Client#getDatabaseId() 1874 * @see Complaint 1875 */ 1876 public CommandFuture<List<Complaint>> getComplaints(int clientDBId) { 1877 final CComplainList list = new CComplainList(clientDBId); 1878 final CommandFuture<List<Complaint>> future = new CommandFuture<>(); 1879 1880 query.doCommandAsync(list, new Callback() { 1881 @Override 1882 public void handle() { 1883 if (hasFailed(list, future)) return; 1884 1885 final List<Wrapper> responses = list.getResponse(); 1886 final List<Complaint> complaints = new ArrayList<>(responses.size()); 1887 1888 for (final Wrapper response : responses) { 1889 complaints.add(new Complaint(response.getMap())); 1890 } 1891 future.set(complaints); 1892 } 1893 }); 1894 return future; 1895 } 1896 1897 /** 1898 * Gets detailed connection information about the selected virtual server. 1899 * 1900 * @return connection information about the selected virtual server 1901 * 1902 * @querycommands 1 1903 * @see ConnectionInfo 1904 * @see #getServerInfo() 1905 */ 1906 public CommandFuture<ConnectionInfo> getConnectionInfo() { 1907 final CServerRequestConnectionInfo info = new CServerRequestConnectionInfo(); 1908 final CommandFuture<ConnectionInfo> future = new CommandFuture<>(); 1909 1910 query.doCommandAsync(info, new Callback() { 1911 @Override 1912 public void handle() { 1913 if (hasFailed(info, future)) return; 1914 future.set(new ConnectionInfo(info.getFirstResponse().getMap())); 1915 } 1916 }); 1917 return future; 1918 } 1919 1920 /** 1921 * Gets all clients in the database whose last nickname matches the specified name <b>exactly</b>. 1922 * 1923 * @param name 1924 * the nickname for the clients to match 1925 * 1926 * @return a list of all clients with a matching nickname 1927 * 1928 * @querycommands 1 + n, 1929 * where n is the amount of database clients with a matching nickname 1930 * @see Client#getNickname() 1931 */ 1932 public CommandFuture<List<DatabaseClientInfo>> getDatabaseClientsByName(String name) { 1933 final CClientDBFind find = new CClientDBFind(name, false); 1934 final CommandFuture<List<DatabaseClientInfo>> future = new CommandFuture<>(); 1935 1936 query.doCommandAsync(find, new Callback() { 1937 @Override 1938 public void handle() { 1939 if (hasFailed(find, future)) return; 1940 1941 final List<Wrapper> responses = find.getResponse(); 1942 final Collection<CommandFuture<DatabaseClientInfo>> infoFutures = new ArrayList<>(responses.size()); 1943 for (Wrapper response : responses) { 1944 final int databaseId = response.getInt("cldbid"); 1945 infoFutures.add(getDatabaseClientInfo(databaseId)); 1946 } 1947 1948 CommandFuture.ofAll(infoFutures).forwardResult(future); 1949 } 1950 }); 1951 return future; 1952 } 1953 1954 /** 1955 * Gets information about the client with the specified unique identifier in the server database. 1956 * 1957 * @param clientUId 1958 * the unique identifier of the client 1959 * 1960 * @return the database client or {@code null} if no client was found 1961 * 1962 * @querycommands 2 1963 * @see Client#getUniqueIdentifier() 1964 * @see DatabaseClientInfo 1965 */ 1966 public CommandFuture<DatabaseClientInfo> getDatabaseClientByUId(String clientUId) { 1967 final CClientGetDBIdFromUId get = new CClientGetDBIdFromUId(clientUId); 1968 final CommandFuture<DatabaseClientInfo> future = new CommandFuture<>(); 1969 1970 query.doCommandAsync(get, new Callback() { 1971 @Override 1972 public void handle() { 1973 if (hasFailed(get, future)) return; 1974 1975 getDatabaseClientInfo(get.getFirstResponse().getInt("cldbid")).forwardResult(future); 1976 } 1977 }); 1978 return future; 1979 } 1980 1981 /** 1982 * Gets information about the client with the specified database ID in the server database. 1983 * 1984 * @param clientDBId 1985 * the database ID of the client 1986 * 1987 * @return the database client or {@code null} if no client was found 1988 * 1989 * @querycommands 1 1990 * @see Client#getDatabaseId() 1991 * @see DatabaseClientInfo 1992 */ 1993 public CommandFuture<DatabaseClientInfo> getDatabaseClientInfo(int clientDBId) { 1994 final CClientDBInfo info = new CClientDBInfo(clientDBId); 1995 final CommandFuture<DatabaseClientInfo> future = new CommandFuture<>(); 1996 1997 query.doCommandAsync(info, new Callback() { 1998 @Override 1999 public void handle() { 2000 if (hasFailed(info, future)) return; 2001 future.set(new DatabaseClientInfo(info.getFirstResponse().getMap())); 2002 } 2003 }); 2004 return future; 2005 } 2006 2007 /** 2008 * Gets information about all clients in the server database. 2009 * <p> 2010 * As this method uses internal commands which can only return 200 clients at once, 2011 * this method can take quite some time to execute. 2012 * </p><p> 2013 * Also keep in mind that the client database can easily accumulate several thousand entries. 2014 * </p> 2015 * 2016 * @return a {@link List} of all database clients 2017 * 2018 * @querycommands 1 + n, 2019 * where n = Math.ceil([amount of database clients] / 200) 2020 * @see DatabaseClient 2021 */ 2022 public CommandFuture<List<DatabaseClient>> getDatabaseClients() { 2023 final CClientDBList countList = new CClientDBList(0, 1, true); 2024 final CommandFuture<List<DatabaseClient>> future = new CommandFuture<>(); 2025 2026 query.doCommandAsync(countList, new Callback() { 2027 @Override 2028 public void handle() { 2029 if (hasFailed(countList, future)) return; 2030 2031 final int count = countList.getFirstResponse().getInt("count"); 2032 final int futuresCount = ((count - 1) / 200) + 1; 2033 final Collection<CommandFuture<List<DatabaseClient>>> futures = new ArrayList<>(futuresCount); 2034 for (int i = 0; i < count; i += 200) { 2035 futures.add(getDatabaseClients(i, 200)); 2036 } 2037 2038 CommandFuture.ofAll(futures).onSuccess(new CommandFuture.SuccessListener<List<List<DatabaseClient>>>() { 2039 @Override 2040 public void handleSuccess(List<List<DatabaseClient>> result) { 2041 int total = 0; 2042 for (List<DatabaseClient> list : result) { 2043 total += list.size(); 2044 } 2045 2046 final List<DatabaseClient> combination = new ArrayList<>(total); 2047 for (List<DatabaseClient> list : result) { 2048 combination.addAll(list); 2049 } 2050 future.set(combination); 2051 } 2052 }).forwardFailure(future); 2053 } 2054 }); 2055 return future; 2056 } 2057 2058 /** 2059 * Gets information about a set number of clients in the server database, starting at {@code offset}. 2060 * 2061 * @param offset 2062 * the index of the first database client to be returned. 2063 * Note that this is <b>not</b> a database ID, but an arbitrary, 0-based index. 2064 * @param count 2065 * the number of database clients that should be returned. 2066 * Any integer greater than 200 might cause problems with the connection 2067 * 2068 * @return a {@link List} of database clients 2069 * 2070 * @querycommands 1 2071 * @see DatabaseClient 2072 */ 2073 public CommandFuture<List<DatabaseClient>> getDatabaseClients(final int offset, final int count) { 2074 final CClientDBList list = new CClientDBList(offset, count, false); 2075 final CommandFuture<List<DatabaseClient>> future = new CommandFuture<>(); 2076 2077 query.doCommandAsync(list, new Callback() { 2078 @Override 2079 public void handle() { 2080 if (hasFailed(list, future)) return; 2081 2082 final List<DatabaseClient> clients = new ArrayList<>(count); 2083 for (final Wrapper response : list.getResponse()) { 2084 clients.add(new DatabaseClient(response.getMap())); 2085 } 2086 future.set(clients); 2087 } 2088 }); 2089 return future; 2090 } 2091 2092 /** 2093 * Displays detailed configuration information about the server instance including 2094 * uptime, number of virtual servers online, traffic information, etc. 2095 * 2096 * @return information about the host 2097 * 2098 * @querycommands 1 2099 */ 2100 public CommandFuture<HostInfo> getHostInfo() { 2101 final CHostInfo info = new CHostInfo(); 2102 final CommandFuture<HostInfo> future = new CommandFuture<>(); 2103 2104 query.doCommandAsync(info, new Callback() { 2105 @Override 2106 public void handle() { 2107 if (hasFailed(info, future)) return; 2108 future.set(new HostInfo(info.getFirstResponse().getMap())); 2109 } 2110 }); 2111 return future; 2112 } 2113 2114 /** 2115 * Displays the server instance configuration including database revision number, 2116 * the file transfer port, default group IDs, etc. 2117 * 2118 * @return information about the TeamSpeak server instance. 2119 * 2120 * @querycommands 1 2121 */ 2122 public CommandFuture<InstanceInfo> getInstanceInfo() { 2123 final CInstanceInfo info = new CInstanceInfo(); 2124 final CommandFuture<InstanceInfo> future = new CommandFuture<>(); 2125 2126 query.doCommandAsync(info, new Callback() { 2127 @Override 2128 public void handle() { 2129 if (hasFailed(info, future)) return; 2130 future.set(new InstanceInfo(info.getFirstResponse().getMap())); 2131 } 2132 }); 2133 return future; 2134 } 2135 2136 /** 2137 * Reads the message body of a message. This will not set the read flag, though. 2138 * 2139 * @param messageId 2140 * the ID of the message to be read 2141 * 2142 * @return the body of the message with the specified ID or {@code null} if there was no message with that ID 2143 * 2144 * @querycommands 1 2145 * @see Message#getId() 2146 * @see #setMessageRead(int) 2147 */ 2148 public CommandFuture<String> getOfflineMessage(int messageId) { 2149 final CMessageGet get = new CMessageGet(messageId); 2150 return executeAndReturnStringProperty(get, "message"); 2151 } 2152 2153 /** 2154 * Reads the message body of a message. This will not set the read flag, though. 2155 * 2156 * @param message 2157 * the message to be read 2158 * 2159 * @return the body of the message with the specified ID or {@code null} if there was no message with that ID 2160 * 2161 * @querycommands 1 2162 * @see Message#getId() 2163 * @see #setMessageRead(Message) 2164 */ 2165 public CommandFuture<String> getOfflineMessage(Message message) { 2166 return getOfflineMessage(message.getId()); 2167 } 2168 2169 /** 2170 * Gets a list of all offline messages for the server query. 2171 * The returned messages lack their message body, though. 2172 * To read the actual message, use {@link #getOfflineMessage(int)} or {@link #getOfflineMessage(Message)}. 2173 * 2174 * @return a list of all offline messages this server query has received 2175 * 2176 * @querycommands 1 2177 */ 2178 public CommandFuture<List<Message>> getOfflineMessages() { 2179 final CMessageList list = new CMessageList(); 2180 final CommandFuture<List<Message>> future = new CommandFuture<>(); 2181 2182 query.doCommandAsync(list, new Callback() { 2183 @Override 2184 public void handle() { 2185 if (hasFailed(list, future)) return; 2186 2187 final List<Wrapper> responses = list.getResponse(); 2188 final List<Message> msg = new ArrayList<>(responses.size()); 2189 2190 for (final Wrapper response : responses) { 2191 msg.add(new Message(response.getMap())); 2192 } 2193 future.set(msg); 2194 } 2195 }); 2196 return future; 2197 } 2198 2199 /** 2200 * Displays detailed information about all assignments of the permission specified 2201 * with {@code permName}. The output includes the type and the ID of the client, 2202 * channel or group associated with the permission. 2203 * 2204 * @param permName 2205 * the name of the permission 2206 * 2207 * @return a list of permission assignments 2208 * 2209 * @querycommands 1 2210 * @see #getPermissionOverview(int, int) 2211 */ 2212 public CommandFuture<List<AdvancedPermission>> getPermissionAssignments(String permName) { 2213 final CPermFind find = new CPermFind(permName); 2214 final CommandFuture<List<AdvancedPermission>> future = new CommandFuture<>(); 2215 2216 query.doCommandAsync(find, new Callback() { 2217 @Override 2218 public void handle() { 2219 if (hasFailed(find, future)) return; 2220 2221 final List<Wrapper> responses = find.getResponse(); 2222 final List<AdvancedPermission> assignments = new ArrayList<>(responses.size()); 2223 2224 for (final Wrapper response : responses) { 2225 assignments.add(new AdvancedPermission(response.getMap())); 2226 } 2227 future.set(assignments); 2228 } 2229 }); 2230 return future; 2231 } 2232 2233 /** 2234 * Gets the ID of the permission specified by {@code permName}. 2235 * <p> 2236 * Note that the use of numeric permission IDs is deprecated 2237 * and that this API only uses the string variant of the IDs. 2238 * </p> 2239 * 2240 * @param permName 2241 * the name of the permission 2242 * 2243 * @return the numeric ID of the specified permission 2244 * 2245 * @querycommands 1 2246 */ 2247 public CommandFuture<Integer> getPermissionIdByName(String permName) { 2248 final CPermIdGetByName get = new CPermIdGetByName(permName); 2249 return executeAndReturnIntProperty(get, "permid"); 2250 } 2251 2252 /** 2253 * Gets a list of all assigned permissions for a client in a specified channel. 2254 * If you do not care about channel permissions, set {@code channelId} to {@code -1}. 2255 * 2256 * @param channelId 2257 * the ID of the channel 2258 * @param clientDBId 2259 * the database ID of the client to create the overview for 2260 * 2261 * @return a list of all permission assignments for the client in the specified channel 2262 * 2263 * @querycommands 1 2264 * @see Channel#getId() 2265 * @see Client#getDatabaseId() 2266 */ 2267 public CommandFuture<List<AdvancedPermission>> getPermissionOverview(int channelId, int clientDBId) { 2268 final CPermOverview overview = new CPermOverview(channelId, clientDBId); 2269 final CommandFuture<List<AdvancedPermission>> future = new CommandFuture<>(); 2270 2271 query.doCommandAsync(overview, new Callback() { 2272 @Override 2273 public void handle() { 2274 if (hasFailed(overview, future)) return; 2275 2276 final List<Wrapper> responses = overview.getResponse(); 2277 final List<AdvancedPermission> permissions = new ArrayList<>(responses.size()); 2278 2279 for (final Wrapper response : responses) { 2280 permissions.add(new AdvancedPermission(response.getMap())); 2281 } 2282 future.set(permissions); 2283 } 2284 }); 2285 return future; 2286 } 2287 2288 /** 2289 * Displays a list of all permissions, including ID, name and description. 2290 * 2291 * @return a list of all permissions 2292 * 2293 * @querycommands 1 2294 */ 2295 public CommandFuture<List<PermissionInfo>> getPermissions() { 2296 final CPermissionList list = new CPermissionList(); 2297 final CommandFuture<List<PermissionInfo>> future = new CommandFuture<>(); 2298 2299 query.doCommandAsync(list, new Callback() { 2300 @Override 2301 public void handle() { 2302 if (hasFailed(list, future)) return; 2303 2304 final List<Wrapper> responses = list.getResponse(); 2305 final List<PermissionInfo> permissions = new ArrayList<>(responses.size()); 2306 2307 for (final Wrapper response : responses) { 2308 permissions.add(new PermissionInfo(response.getMap())); 2309 } 2310 future.set(permissions); 2311 } 2312 }); 2313 return future; 2314 } 2315 2316 /** 2317 * Displays the current value of the specified permission for this server query instance. 2318 * 2319 * @param permName 2320 * the name of the permission 2321 * 2322 * @return the permission value, usually ranging from 0 to 100 2323 * 2324 * @querycommands 1 2325 */ 2326 public CommandFuture<Integer> getPermissionValue(String permName) { 2327 final CPermGet get = new CPermGet(permName); 2328 return executeAndReturnIntProperty(get, "permvalue"); 2329 } 2330 2331 /** 2332 * Gets a list of all available tokens to join channel or server groups, 2333 * including their type and group IDs. 2334 * 2335 * @return a list of all generated, but still unclaimed privilege keys 2336 * 2337 * @querycommands 1 2338 * @see #addPrivilegeKey(TokenType, int, int, String) 2339 * @see #usePrivilegeKey(String) 2340 */ 2341 public CommandFuture<List<PrivilegeKey>> getPrivilegeKeys() { 2342 final CPrivilegeKeyList list = new CPrivilegeKeyList(); 2343 final CommandFuture<List<PrivilegeKey>> future = new CommandFuture<>(); 2344 2345 query.doCommandAsync(list, new Callback() { 2346 @Override 2347 public void handle() { 2348 if (hasFailed(list, future)) return; 2349 2350 final List<Wrapper> responses = list.getResponse(); 2351 final List<PrivilegeKey> keys = new ArrayList<>(responses.size()); 2352 2353 for (final Wrapper response : responses) { 2354 keys.add(new PrivilegeKey(response.getMap())); 2355 } 2356 future.set(keys); 2357 } 2358 }); 2359 return future; 2360 } 2361 2362 /** 2363 * Gets a list of all clients in the specified server group. 2364 * 2365 * @param serverGroupId 2366 * the ID of the server group for which the clients should be looked up 2367 * 2368 * @return a list of all clients in the server group 2369 * 2370 * @querycommands 1 2371 */ 2372 public CommandFuture<List<ServerGroupClient>> getServerGroupClients(int serverGroupId) { 2373 final CServerGroupClientList list = new CServerGroupClientList(serverGroupId); 2374 final CommandFuture<List<ServerGroupClient>> future = new CommandFuture<>(); 2375 2376 query.doCommandAsync(list, new Callback() { 2377 @Override 2378 public void handle() { 2379 if (hasFailed(list, future)) return; 2380 2381 final List<Wrapper> responses = list.getResponse(); 2382 final List<ServerGroupClient> clients = new ArrayList<>(responses.size()); 2383 2384 for (final Wrapper response : responses) { 2385 clients.add(new ServerGroupClient(response.getMap())); 2386 } 2387 future.set(clients); 2388 } 2389 }); 2390 return future; 2391 } 2392 2393 /** 2394 * Gets a list of all clients in the specified server group. 2395 * 2396 * @param serverGroup 2397 * the server group for which the clients should be looked up 2398 * 2399 * @return a list of all clients in the server group 2400 * 2401 * @querycommands 1 2402 */ 2403 public CommandFuture<List<ServerGroupClient>> getServerGroupClients(ServerGroup serverGroup) { 2404 return getServerGroupClients(serverGroup.getId()); 2405 } 2406 2407 /** 2408 * Gets a list of all permissions assigned to the specified server group. 2409 * 2410 * @param serverGroupId 2411 * the ID of the server group for which the permissions should be looked up 2412 * 2413 * @return a list of all permissions assigned to the server group 2414 * 2415 * @querycommands 1 2416 * @see ServerGroup#getId() 2417 * @see #getServerGroupPermissions(ServerGroup) 2418 */ 2419 public CommandFuture<List<Permission>> getServerGroupPermissions(int serverGroupId) { 2420 final CServerGroupPermList list = new CServerGroupPermList(serverGroupId); 2421 final CommandFuture<List<Permission>> future = new CommandFuture<>(); 2422 2423 query.doCommandAsync(list, new Callback() { 2424 @Override 2425 public void handle() { 2426 if (hasFailed(list, future)) return; 2427 2428 final List<Wrapper> responses = list.getResponse(); 2429 final List<Permission> permissions = new ArrayList<>(responses.size()); 2430 2431 for (final Wrapper response : responses) { 2432 permissions.add(new Permission(response.getMap())); 2433 } 2434 future.set(permissions); 2435 } 2436 }); 2437 return future; 2438 } 2439 2440 /** 2441 * Gets a list of all permissions assigned to the specified server group. 2442 * 2443 * @param serverGroup 2444 * the server group for which the permissions should be looked up 2445 * 2446 * @return a list of all permissions assigned to the server group 2447 * 2448 * @querycommands 1 2449 */ 2450 public CommandFuture<List<Permission>> getServerGroupPermissions(ServerGroup serverGroup) { 2451 return getServerGroupPermissions(serverGroup.getId()); 2452 } 2453 2454 /** 2455 * Gets a list of all server groups on the virtual server. 2456 * <p> 2457 * Depending on your permissions, the output may also contain 2458 * global server query groups and template groups. 2459 * </p> 2460 * 2461 * @return a list of all server groups 2462 * 2463 * @querycommands 1 2464 */ 2465 public CommandFuture<List<ServerGroup>> getServerGroups() { 2466 final CServerGroupList list = new CServerGroupList(); 2467 final CommandFuture<List<ServerGroup>> future = new CommandFuture<>(); 2468 2469 query.doCommandAsync(list, new Callback() { 2470 @Override 2471 public void handle() { 2472 if (hasFailed(list, future)) return; 2473 2474 final List<Wrapper> responses = list.getResponse(); 2475 final List<ServerGroup> groups = new ArrayList<>(responses.size()); 2476 2477 for (final Wrapper response : responses) { 2478 groups.add(new ServerGroup(response.getMap())); 2479 } 2480 future.set(groups); 2481 } 2482 }); 2483 return future; 2484 } 2485 2486 /** 2487 * Gets a list of all server groups set for a client. 2488 * 2489 * @param clientDatabaseId 2490 * the database ID of the client for which the server groups should be looked up 2491 * 2492 * @return a list of all server groups set for the client 2493 * 2494 * @querycommands 2 2495 * @see Client#getDatabaseId() 2496 * @see #getServerGroupsByClient(Client) 2497 */ 2498 public CommandFuture<List<ServerGroup>> getServerGroupsByClientId(int clientDatabaseId) { 2499 final CServerGroupsByClientId client = new CServerGroupsByClientId(clientDatabaseId); 2500 final CommandFuture<List<ServerGroup>> future = new CommandFuture<>(); 2501 2502 getServerGroups().onSuccess(new CommandFuture.SuccessListener<List<ServerGroup>>() { 2503 @Override 2504 public void handleSuccess(final List<ServerGroup> allServerGroups) { 2505 query.doCommandAsync(client, new Callback() { 2506 @Override 2507 public void handle() { 2508 if (hasFailed(client, future)) return; 2509 2510 final List<Wrapper> responses = client.getResponse(); 2511 final List<ServerGroup> list = new ArrayList<>(responses.size()); 2512 2513 for (final Wrapper response : responses) { 2514 for (final ServerGroup s : allServerGroups) { 2515 if (s.getId() == response.getInt("sgid")) { 2516 list.add(s); 2517 } 2518 } 2519 } 2520 future.set(list); 2521 } 2522 }); 2523 } 2524 }).forwardFailure(future); 2525 return future; 2526 } 2527 2528 /** 2529 * Gets a list of all server groups set for a client. 2530 * 2531 * @param client 2532 * the client for which the server groups should be looked up 2533 * 2534 * @return a list of all server group set for the client 2535 * 2536 * @querycommands 2 2537 * @see #getServerGroupsByClientId(int) 2538 */ 2539 public CommandFuture<List<ServerGroup>> getServerGroupsByClient(Client client) { 2540 return getServerGroupsByClientId(client.getDatabaseId()); 2541 } 2542 2543 /** 2544 * Gets the ID of a virtual server by its port. 2545 * 2546 * @param port 2547 * the port of a virtual server 2548 * 2549 * @return the ID of the virtual server 2550 * 2551 * @querycommands 1 2552 * @see VirtualServer#getPort() 2553 * @see VirtualServer#getId() 2554 */ 2555 public CommandFuture<Integer> getServerIdByPort(int port) { 2556 final CServerIdGetByPort s = new CServerIdGetByPort(port); 2557 return executeAndReturnIntProperty(s, "server_id"); 2558 } 2559 2560 /** 2561 * Gets detailed information about the virtual server the server query is currently in. 2562 * 2563 * @return information about the current virtual server 2564 * 2565 * @querycommands 1 2566 */ 2567 public CommandFuture<VirtualServerInfo> getServerInfo() { 2568 final CServerInfo info = new CServerInfo(); 2569 final CommandFuture<VirtualServerInfo> future = new CommandFuture<>(); 2570 2571 query.doCommandAsync(info, new Callback() { 2572 @Override 2573 public void handle() { 2574 if (hasFailed(info, future)) return; 2575 future.set(new VirtualServerInfo(info.getFirstResponse().getMap())); 2576 } 2577 }); 2578 return future; 2579 } 2580 2581 /** 2582 * Gets the version, build number and platform of the TeamSpeak3 server. 2583 * 2584 * @return the version information of the server 2585 * 2586 * @querycommands 1 2587 */ 2588 public CommandFuture<Version> getVersion() { 2589 final CVersion version = new CVersion(); 2590 final CommandFuture<Version> future = new CommandFuture<>(); 2591 2592 query.doCommandAsync(version, new Callback() { 2593 @Override 2594 public void handle() { 2595 if (hasFailed(version, future)) return; 2596 future.set(new Version(version.getFirstResponse().getMap())); 2597 } 2598 }); 2599 return future; 2600 } 2601 2602 /** 2603 * Gets a list of all virtual servers including their ID, status, number of clients online, etc. 2604 * 2605 * @return a list of all virtual servers 2606 * 2607 * @querycommands 1 2608 */ 2609 public CommandFuture<List<VirtualServer>> getVirtualServers() { 2610 final CServerList serverList = new CServerList(); 2611 final CommandFuture<List<VirtualServer>> future = new CommandFuture<>(); 2612 2613 query.doCommandAsync(serverList, new Callback() { 2614 @Override 2615 public void handle() { 2616 if (hasFailed(serverList, future)) return; 2617 2618 final List<Wrapper> responses = serverList.getResponse(); 2619 final List<VirtualServer> servers = new ArrayList<>(responses.size()); 2620 2621 for (final Wrapper response : responses) { 2622 servers.add((new VirtualServer(response.getMap()))); 2623 } 2624 future.set(servers); 2625 } 2626 }); 2627 return future; 2628 } 2629 2630 /** 2631 * Kicks one or more clients from their current channels. 2632 * This will move the kicked clients into the default channel and 2633 * won't do anything if the clients are already in the default channel. 2634 * 2635 * @param clientIds 2636 * the IDs of the clients to kick 2637 * 2638 * @return whether the command succeeded or not 2639 * 2640 * @querycommands 1 2641 * @see #kickClientFromChannel(Client...) 2642 * @see #kickClientFromChannel(String, int...) 2643 */ 2644 public CommandFuture<Boolean> kickClientFromChannel(int... clientIds) { 2645 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, null, clientIds); 2646 } 2647 2648 /** 2649 * Kicks one or more clients from their current channels. 2650 * This will move the kicked clients into the default channel and 2651 * won't do anything if the clients are already in the default channel. 2652 * 2653 * @param clients 2654 * the clients to kick 2655 * 2656 * @return whether the command succeeded or not 2657 * 2658 * @querycommands 1 2659 * @see #kickClientFromChannel(int...) 2660 * @see #kickClientFromChannel(String, Client...) 2661 */ 2662 public CommandFuture<Boolean> kickClientFromChannel(Client... clients) { 2663 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, null, clients); 2664 } 2665 2666 /** 2667 * Kicks one or more clients from their current channels for the specified reason. 2668 * This will move the kicked clients into the default channel and 2669 * won't do anything if the clients are already in the default channel. 2670 * 2671 * @param message 2672 * the reason message to display to the clients 2673 * @param clientIds 2674 * the IDs of the clients to kick 2675 * 2676 * @return whether the command succeeded or not 2677 * 2678 * @querycommands 1 2679 * @see Client#getId() 2680 * @see #kickClientFromChannel(int...) 2681 * @see #kickClientFromChannel(String, Client...) 2682 */ 2683 public CommandFuture<Boolean> kickClientFromChannel(String message, int... clientIds) { 2684 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, message, clientIds); 2685 } 2686 2687 /** 2688 * Kicks one or more clients from their current channels for the specified reason. 2689 * This will move the kicked clients into the default channel and 2690 * won't do anything if the clients are already in the default channel. 2691 * 2692 * @param message 2693 * the reason message to display to the clients 2694 * @param clients 2695 * the clients to kick 2696 * 2697 * @return whether the command succeeded or not 2698 * 2699 * @querycommands 1 2700 * @see #kickClientFromChannel(Client...) 2701 * @see #kickClientFromChannel(String, int...) 2702 */ 2703 public CommandFuture<Boolean> kickClientFromChannel(String message, Client... clients) { 2704 return kickClients(ReasonIdentifier.REASON_KICK_CHANNEL, message, clients); 2705 } 2706 2707 /** 2708 * Kicks one or more clients from the server. 2709 * 2710 * @param clientIds 2711 * the IDs of the clients to kick 2712 * 2713 * @return whether the command succeeded or not 2714 * 2715 * @querycommands 1 2716 * @see Client#getId() 2717 * @see #kickClientFromServer(Client...) 2718 * @see #kickClientFromServer(String, int...) 2719 */ 2720 public CommandFuture<Boolean> kickClientFromServer(int... clientIds) { 2721 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, null, clientIds); 2722 } 2723 2724 /** 2725 * Kicks one or more clients from the server. 2726 * 2727 * @param clients 2728 * the clients to kick 2729 * 2730 * @return whether the command succeeded or not 2731 * 2732 * @querycommands 1 2733 * @see #kickClientFromServer(int...) 2734 * @see #kickClientFromServer(String, Client...) 2735 */ 2736 public CommandFuture<Boolean> kickClientFromServer(Client... clients) { 2737 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, null, clients); 2738 } 2739 2740 /** 2741 * Kicks one or more clients from the server for the specified reason. 2742 * 2743 * @param message 2744 * the reason message to display to the clients 2745 * @param clientIds 2746 * the IDs of the clients to kick 2747 * 2748 * @return whether the command succeeded or not 2749 * 2750 * @querycommands 1 2751 * @see Client#getId() 2752 * @see #kickClientFromServer(int...) 2753 * @see #kickClientFromServer(String, Client...) 2754 */ 2755 public CommandFuture<Boolean> kickClientFromServer(String message, int... clientIds) { 2756 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, message, clientIds); 2757 } 2758 2759 /** 2760 * Kicks one or more clients from the server for the specified reason. 2761 * 2762 * @param message 2763 * the reason message to display to the clients 2764 * @param clients 2765 * the clients to kick 2766 * 2767 * @return whether the command succeeded or not 2768 * 2769 * @querycommands 1 2770 * @see #kickClientFromServer(Client...) 2771 * @see #kickClientFromServer(String, int...) 2772 */ 2773 public CommandFuture<Boolean> kickClientFromServer(String message, Client... clients) { 2774 return kickClients(ReasonIdentifier.REASON_KICK_SERVER, message, clients); 2775 } 2776 2777 /** 2778 * Kicks a list of clients from either the channel or the server for a given reason. 2779 * 2780 * @param reason 2781 * where to kick the clients from 2782 * @param message 2783 * the reason message to display to the clients 2784 * @param clients 2785 * the clients to kick 2786 * 2787 * @return whether the command succeeded or not 2788 * 2789 * @querycommands 1 2790 */ 2791 private CommandFuture<Boolean> kickClients(ReasonIdentifier reason, String message, Client... clients) { 2792 int[] clientIds = new int[clients.length]; 2793 for (int i = 0; i < clients.length; ++i) { 2794 clientIds[i] = clients[i].getId(); 2795 } 2796 return kickClients(reason, message, clientIds); 2797 } 2798 2799 /** 2800 * Kicks a list of clients from either the channel or the server for a given reason. 2801 * 2802 * @param reason 2803 * where to kick the clients from 2804 * @param message 2805 * the reason message to display to the clients 2806 * @param clientIds 2807 * the IDs of the clients to kick 2808 * 2809 * @return whether the command succeeded or not 2810 * 2811 * @querycommands 1 2812 * @see Client#getId() 2813 */ 2814 private CommandFuture<Boolean> kickClients(ReasonIdentifier reason, String message, int... clientIds) { 2815 final CClientKick kick = new CClientKick(reason, message, clientIds); 2816 return executeAndReturnError(kick); 2817 } 2818 2819 /** 2820 * Logs the server query in using the specified username and password. 2821 * <p> 2822 * Note that you can also set the login in the {@link TS3Config}, 2823 * so that you will be logged in right after the connection is established. 2824 * </p> 2825 * 2826 * @param username 2827 * the username of the server query 2828 * @param password 2829 * the password to use 2830 * 2831 * @return whether the command succeeded or not 2832 * 2833 * @querycommands 1 2834 * @see TS3Config#setLoginCredentials(String, String) 2835 * @see #logout() 2836 */ 2837 public CommandFuture<Boolean> login(String username, String password) { 2838 final CLogin login = new CLogin(username, password); 2839 return executeAndReturnError(login); 2840 } 2841 2842 /** 2843 * Logs the server query out and deselects the current virtual server. 2844 * 2845 * @return whether the command succeeded or not 2846 * 2847 * @querycommands 1 2848 * @see #login(String, String) 2849 */ 2850 public CommandFuture<Boolean> logout() { 2851 final CLogout logout = new CLogout(); 2852 return executeAndReturnError(logout); 2853 } 2854 2855 /** 2856 * Moves a channel to a new parent channel specified by its ID. 2857 * To move a channel to root level, set {@code channelTargetId} to {@code 0}. 2858 * <p> 2859 * This will move the channel right below the specified parent channel, above all other child channels. 2860 * This command will fail if the channel already has the specified target channel as the parent channel. 2861 * </p> 2862 * 2863 * @param channelId 2864 * the channel to move 2865 * @param channelTargetId 2866 * the new parent channel for the specified channel 2867 * 2868 * @return whether the command succeeded or not 2869 * 2870 * @querycommands 1 2871 * @see Channel#getId() 2872 * @see #moveChannel(int, int, int) 2873 */ 2874 public CommandFuture<Boolean> moveChannel(int channelId, int channelTargetId) { 2875 return moveChannel(channelId, channelTargetId, 0); 2876 } 2877 2878 /** 2879 * Moves a channel to a new parent channel specified by its ID. 2880 * To move a channel to root level, set {@code channelTargetId} to {@code 0}. 2881 * <p> 2882 * The channel will be ordered below the channel with the ID specified by {@code order}. 2883 * To move the channel right below the parent channel, set {@code order} to {@code 0}. 2884 * Also note that a channel cannot be re-ordered without also changing its parent channel. 2885 * </p> 2886 * 2887 * @param channelId 2888 * the channel to move 2889 * @param channelTargetId 2890 * the new parent channel for the specified channel 2891 * @param order 2892 * the channel to sort the specified channel below 2893 * 2894 * @return whether the command succeeded or not 2895 * 2896 * @querycommands 1 2897 * @see Channel#getId() 2898 * @see #moveChannel(int, int) 2899 */ 2900 public CommandFuture<Boolean> moveChannel(int channelId, int channelTargetId, int order) { 2901 final CChannelMove move = new CChannelMove(channelId, channelTargetId, order); 2902 return executeAndReturnError(move); 2903 } 2904 2905 /** 2906 * Moves the server query into the specified channel. 2907 * 2908 * @param channelId 2909 * the ID of the channel to move the client into 2910 * 2911 * @return whether the command succeeded or not 2912 * 2913 * @querycommands 1 2914 * @see Channel#getId() 2915 */ 2916 public CommandFuture<Boolean> moveClient(int channelId) { 2917 return moveClient(channelId, null); 2918 } 2919 2920 /** 2921 * Moves the server query into the specified channel. 2922 * 2923 * @param channel 2924 * the channel to move the client into 2925 * 2926 * @return whether the command succeeded or not 2927 * 2928 * @querycommands 1 2929 */ 2930 public CommandFuture<Boolean> moveClient(ChannelBase channel) { 2931 return moveClient(channel.getId(), null); 2932 } 2933 2934 /** 2935 * Moves the server query into the specified channel using the specified password. 2936 * 2937 * @param channelId 2938 * the ID of the channel to move the client into 2939 * @param channelPassword 2940 * the password of the channel 2941 * 2942 * @return whether the command succeeded or not 2943 * 2944 * @querycommands 1 2945 * @see Channel#getId() 2946 */ 2947 public CommandFuture<Boolean> moveClient(int channelId, String channelPassword) { 2948 return moveClient(0, channelId, channelPassword); 2949 } 2950 2951 /** 2952 * Moves the server query into the specified channel using the specified password. 2953 * 2954 * @param channel 2955 * the channel to move the client into 2956 * @param channelPassword 2957 * the password of the channel 2958 * 2959 * @return whether the command succeeded or not 2960 * 2961 * @querycommands 1 2962 */ 2963 public CommandFuture<Boolean> moveClient(ChannelBase channel, String channelPassword) { 2964 return moveClient(0, channel.getId(), channelPassword); 2965 } 2966 2967 /** 2968 * Moves a client into the specified channel. 2969 * 2970 * @param clientId 2971 * the ID of the client to move 2972 * @param channelId 2973 * the ID of the channel to move the client into 2974 * 2975 * @return whether the command succeeded or not 2976 * 2977 * @querycommands 1 2978 * @see Client#getId() 2979 * @see Channel#getId() 2980 */ 2981 public CommandFuture<Boolean> moveClient(int clientId, int channelId) { 2982 return moveClient(clientId, channelId, null); 2983 } 2984 2985 /** 2986 * Moves a client into the specified channel. 2987 * 2988 * @param client 2989 * the client to move 2990 * @param channel 2991 * the channel to move the client into 2992 * 2993 * @return whether the command succeeded or not 2994 * 2995 * @querycommands 1 2996 */ 2997 public CommandFuture<Boolean> moveClient(Client client, ChannelBase channel) { 2998 return moveClient(client.getId(), channel.getId(), null); 2999 } 3000 3001 /** 3002 * Moves a client into the specified channel using the specified password. 3003 * 3004 * @param clientId 3005 * the ID of the client to move 3006 * @param channelId 3007 * the ID of the channel to move the client into 3008 * @param channelPassword 3009 * the password of the channel 3010 * 3011 * @return whether the command succeeded or not 3012 * 3013 * @querycommands 1 3014 * @see Client#getId() 3015 * @see Channel#getId() 3016 */ 3017 public CommandFuture<Boolean> moveClient(int clientId, int channelId, String channelPassword) { 3018 final CClientMove move = new CClientMove(clientId, channelId, channelPassword); 3019 return executeAndReturnError(move); 3020 } 3021 3022 /** 3023 * Moves a client into the specified channel using the specified password. 3024 * 3025 * @param client 3026 * the client to move 3027 * @param channel 3028 * the channel to move the client into 3029 * @param channelPassword 3030 * the password of the channel 3031 * 3032 * @return whether the command succeeded or not 3033 * 3034 * @querycommands 1 3035 */ 3036 public CommandFuture<Boolean> moveClient(Client client, ChannelBase channel, String channelPassword) { 3037 return moveClient(client.getId(), channel.getId(), channelPassword); 3038 } 3039 3040 /** 3041 * Pokes the client with the specified client ID. 3042 * This opens up a small popup window for the client containing your message and plays a sound. 3043 * The displayed message will be formatted like this: <br> 3044 * {@code hh:mm:ss - "Your Nickname" poked you: <your message in green color>} 3045 * <p> 3046 * The displayed message length is limited to 100 UTF-8 bytes. 3047 * If a client has already received a poke message, all subsequent pokes will simply add a line 3048 * to the already opened popup window and will still play a sound. 3049 * </p> 3050 * 3051 * @param clientId 3052 * the ID of the client to poke 3053 * @param message 3054 * the message to send, may contain BB codes 3055 * 3056 * @return whether the command succeeded or not 3057 * 3058 * @querycommands 1 3059 * @see Client#getId() 3060 */ 3061 public CommandFuture<Boolean> pokeClient(int clientId, String message) { 3062 final CClientPoke poke = new CClientPoke(clientId, message); 3063 return executeAndReturnError(poke); 3064 } 3065 3066 /** 3067 * Terminates the connection with the TeamSpeak3 server. 3068 * This command should never be executed manually. 3069 * 3070 * @return whether the command succeeded or not 3071 * 3072 * @querycommands 1 3073 * @deprecated This command leaves the query in an undefined state, 3074 * where the connection is closed without the socket being closed and no more command can be executed. 3075 * To terminate a connection, use {@link TS3Query#exit()}. 3076 */ 3077 @Deprecated 3078 public CommandFuture<Boolean> quit() { 3079 final CQuit quit = new CQuit(); 3080 return executeAndReturnError(quit); 3081 } 3082 3083 /** 3084 * Registers the server query to receive notifications about all server events. 3085 * <p> 3086 * This means that the following actions will trigger event notifications: 3087 * </p> 3088 * <ul> 3089 * <li>A client joins the server or disconnects from it</li> 3090 * <li>A client switches channels</li> 3091 * <li>A client sends a server message</li> 3092 * <li>A client sends a channel message <b>in the channel the query is in</b></li> 3093 * <li>A client sends <b>the server query</b> a private message or a response to a private message</li> 3094 * </ul> 3095 * <p> 3096 * The limitations to when the query receives notifications about chat events cannot be circumvented. 3097 * </p> 3098 * To be able to process these events in your application, register an event listener. 3099 * 3100 * @return whether all commands succeeded or not 3101 * 3102 * @querycommands 5 3103 * @see #addTS3Listeners(TS3Listener...) 3104 */ 3105 public CommandFuture<Boolean> registerAllEvents() { 3106 final CommandFuture<Boolean> future = new CommandFuture<>(); 3107 final Collection<CommandFuture<Boolean>> eventFutures = new ArrayList<>(5); 3108 3109 eventFutures.add(registerEvent(TS3EventType.SERVER)); 3110 eventFutures.add(registerEvent(TS3EventType.TEXT_SERVER)); 3111 eventFutures.add(registerEvent(TS3EventType.CHANNEL, 0)); 3112 eventFutures.add(registerEvent(TS3EventType.TEXT_CHANNEL, 0)); 3113 eventFutures.add(registerEvent(TS3EventType.TEXT_PRIVATE)); 3114 3115 CommandFuture.ofAll(eventFutures).onSuccess(new CommandFuture.SuccessListener<List<Boolean>>() { 3116 @Override 3117 public void handleSuccess(List<Boolean> result) { 3118 future.set(true); 3119 } 3120 }).forwardFailure(future); 3121 return future; 3122 } 3123 3124 /** 3125 * Registers the server query to receive notifications about a given event type. 3126 * <p> 3127 * If used with {@link TS3EventType#TEXT_CHANNEL}, this will listen to chat events in the current channel. 3128 * If used with {@link TS3EventType#CHANNEL}, this will listen to <b>all</b> channel events. 3129 * To specify a different channel for channel events, use {@link #registerEvent(TS3EventType, int)}. 3130 * </p> 3131 * 3132 * @param eventType 3133 * the event type to be notified about 3134 * 3135 * @return whether the command succeeded or not 3136 * 3137 * @querycommands 1 3138 * @see #addTS3Listeners(TS3Listener...) 3139 * @see #registerEvent(TS3EventType, int) 3140 * @see #registerAllEvents() 3141 */ 3142 public CommandFuture<Boolean> registerEvent(TS3EventType eventType) { 3143 if (eventType == TS3EventType.CHANNEL || eventType == TS3EventType.TEXT_CHANNEL) { 3144 return registerEvent(eventType, 0); 3145 } 3146 return registerEvent(eventType, -1); 3147 } 3148 3149 /** 3150 * Registers the server query to receive notifications about a given event type. 3151 * 3152 * @param eventType 3153 * the event type to be notified about 3154 * @param channelId 3155 * the ID of the channel to listen to, will be ignored if set to {@code -1}. 3156 * Can be set to {@code 0} for {@link TS3EventType#CHANNEL} to receive notifications about all channel switches. 3157 * 3158 * @return whether the command succeeded or not 3159 * 3160 * @querycommands 1 3161 * @see Channel#getId() 3162 * @see #addTS3Listeners(TS3Listener...) 3163 * @see #registerAllEvents() 3164 */ 3165 public CommandFuture<Boolean> registerEvent(TS3EventType eventType, int channelId) { 3166 final CServerNotifyRegister register = new CServerNotifyRegister(eventType, channelId); 3167 return executeAndReturnError(register); 3168 } 3169 3170 /** 3171 * Registers the server query to receive notifications about multiple given event types. 3172 * <p> 3173 * If used with {@link TS3EventType#TEXT_CHANNEL}, this will listen to chat events in the current channel. 3174 * If used with {@link TS3EventType#CHANNEL}, this will listen to <b>all</b> channel events. 3175 * To specify a different channel for channel events, use {@link #registerEvent(TS3EventType, int)}. 3176 * </p> 3177 * 3178 * @param eventTypes 3179 * the event types to be notified about 3180 * 3181 * @return whether the command succeeded or not 3182 * 3183 * @querycommands n, one command per TS3EventType 3184 * @see #addTS3Listeners(TS3Listener...) 3185 * @see #registerEvent(TS3EventType, int) 3186 * @see #registerAllEvents() 3187 */ 3188 public CommandFuture<Boolean> registerEvents(TS3EventType... eventTypes) { 3189 final CommandFuture<Boolean> future = new CommandFuture<>(); 3190 if (eventTypes.length == 0) { 3191 future.set(true); 3192 return future; 3193 } 3194 3195 final Collection<CommandFuture<Boolean>> registerFutures = new ArrayList<>(eventTypes.length); 3196 for (final TS3EventType type : eventTypes) { 3197 registerFutures.add(registerEvent(type)); 3198 } 3199 3200 CommandFuture.ofAll(registerFutures).onSuccess(new CommandFuture.SuccessListener<List<Boolean>>() { 3201 @Override 3202 public void handleSuccess(List<Boolean> result) { 3203 future.set(true); 3204 } 3205 }).forwardFailure(future); 3206 return future; 3207 } 3208 3209 /** 3210 * Removes the client specified by its database ID from the specified server group. 3211 * 3212 * @param serverGroupId 3213 * the ID of the server group 3214 * @param clientDatabaseId 3215 * the database ID of the client 3216 * 3217 * @return whether the command succeeded or not 3218 * 3219 * @querycommands 1 3220 * @see ServerGroup#getId() 3221 * @see Client#getDatabaseId() 3222 * @see #removeClientFromServerGroup(ServerGroup, Client) 3223 */ 3224 public CommandFuture<Boolean> removeClientFromServerGroup(int serverGroupId, int clientDatabaseId) { 3225 final CServerGroupDelClient del = new CServerGroupDelClient(serverGroupId, clientDatabaseId); 3226 return executeAndReturnError(del); 3227 } 3228 3229 /** 3230 * Removes the specified client from the specified server group. 3231 * 3232 * @param serverGroup 3233 * the server group to remove the client from 3234 * @param client 3235 * the client to remove from the server group 3236 * 3237 * @return whether the command succeeded or not 3238 * 3239 * @querycommands 1 3240 * @see #removeClientFromServerGroup(int, int) 3241 */ 3242 public CommandFuture<Boolean> removeClientFromServerGroup(ServerGroup serverGroup, Client client) { 3243 return removeClientFromServerGroup(serverGroup.getId(), client.getDatabaseId()); 3244 } 3245 3246 /** 3247 * Removes one or more {@link TS3Listener}s to the event manager of the query. 3248 * <p> 3249 * If a listener was not actually registered, it will be ignored and no exception will be thrown. 3250 * </p> 3251 * 3252 * @param listeners 3253 * one or more listeners to remove 3254 * 3255 * @see #addTS3Listeners(TS3Listener...) 3256 * @see TS3Listener 3257 * @see TS3EventType 3258 */ 3259 public void removeTS3Listeners(TS3Listener... listeners) { 3260 query.getEventManager().removeListeners(listeners); 3261 } 3262 3263 /** 3264 * Renames the channel group with the specified ID. 3265 * 3266 * @param channelGroupId 3267 * the ID of the channel group to rename 3268 * @param name 3269 * the new name for the channel group 3270 * 3271 * @return whether the command succeeded or not 3272 * 3273 * @querycommands 1 3274 * @see ChannelGroup#getId() 3275 * @see #renameChannelGroup(ChannelGroup, String) 3276 */ 3277 public CommandFuture<Boolean> renameChannelGroup(int channelGroupId, String name) { 3278 final CChannelGroupRename rename = new CChannelGroupRename(channelGroupId, name); 3279 return executeAndReturnError(rename); 3280 } 3281 3282 /** 3283 * Renames the specified channel group. 3284 * 3285 * @param channelGroup 3286 * the channel group to rename 3287 * @param name 3288 * the new name for the channel group 3289 * 3290 * @return whether the command succeeded or not 3291 * 3292 * @querycommands 1 3293 * @see #renameChannelGroup(int, String) 3294 */ 3295 public CommandFuture<Boolean> renameChannelGroup(ChannelGroup channelGroup, String name) { 3296 return renameChannelGroup(channelGroup.getId(), name); 3297 } 3298 3299 /** 3300 * Renames the server group with the specified ID. 3301 * 3302 * @param serverGroupId 3303 * the ID of the server group to rename 3304 * @param name 3305 * the new name for the server group 3306 * 3307 * @return whether the command succeeded or not 3308 * 3309 * @querycommands 1 3310 * @see ServerGroup#getId() 3311 * @see #renameServerGroup(ServerGroup, String) 3312 */ 3313 public CommandFuture<Boolean> renameServerGroup(int serverGroupId, String name) { 3314 final CServerGroupRename rename = new CServerGroupRename(serverGroupId, name); 3315 return executeAndReturnError(rename); 3316 } 3317 3318 /** 3319 * Renames the specified server group. 3320 * 3321 * @param serverGroup 3322 * the server group to rename 3323 * @param name 3324 * the new name for the server group 3325 * 3326 * @return whether the command succeeded or not 3327 * 3328 * @querycommands 1 3329 * @see #renameServerGroup(int, String) 3330 */ 3331 public CommandFuture<Boolean> renameServerGroup(ServerGroup serverGroup, String name) { 3332 return renameChannelGroup(serverGroup.getId(), name); 3333 } 3334 3335 /** 3336 * Resets all permissions and deletes all server / channel groups. Use carefully. 3337 * 3338 * @return a token for a new administrator account 3339 * 3340 * @querycommands 1 3341 */ 3342 public CommandFuture<String> resetPermissions() { 3343 final CPermReset reset = new CPermReset(); 3344 return executeAndReturnStringProperty(reset, "token"); 3345 } 3346 3347 /** 3348 * Moves the server query into the virtual server with the specified ID. 3349 * 3350 * @param id 3351 * the ID of the virtual server 3352 * 3353 * @return whether the command succeeded or not 3354 * 3355 * @querycommands 1 3356 * @see VirtualServer#getId() 3357 * @see #selectVirtualServerByPort(int) 3358 * @see #selectVirtualServer(VirtualServer) 3359 */ 3360 public CommandFuture<Boolean> selectVirtualServerById(int id) { 3361 final CUse use = new CUse(id, -1); 3362 return executeAndReturnError(use); 3363 } 3364 3365 /** 3366 * Moves the server query into the virtual server with the specified voice port. 3367 * 3368 * @param port 3369 * the voice port of the virtual server 3370 * 3371 * @return whether the command succeeded or not 3372 * 3373 * @querycommands 1 3374 * @see VirtualServer#getPort() 3375 * @see #selectVirtualServerById(int) 3376 * @see #selectVirtualServer(VirtualServer) 3377 */ 3378 public CommandFuture<Boolean> selectVirtualServerByPort(int port) { 3379 final CUse use = new CUse(-1, port); 3380 return executeAndReturnError(use); 3381 } 3382 3383 /** 3384 * Moves the server query into the specified virtual server. 3385 * 3386 * @param server 3387 * the virtual server to move into 3388 * 3389 * @return whether the command succeeded or not 3390 * 3391 * @querycommands 1 3392 * @see #selectVirtualServerById(int) 3393 * @see #selectVirtualServerByPort(int) 3394 */ 3395 public CommandFuture<Boolean> selectVirtualServer(VirtualServer server) { 3396 return selectVirtualServerById(server.getId()); 3397 } 3398 3399 /** 3400 * Sends an offline message to the client with the given unique identifier. 3401 * <p> 3402 * The message subject's length is limited to 200 UTF-8 bytes and BB codes in it will be ignored. 3403 * The message body's length is limited to 4096 UTF-8 bytes and accepts BB codes 3404 * </p> 3405 * 3406 * @param clientUId 3407 * the unique identifier of the client to send the message to 3408 * @param subject 3409 * the subject for the message, may not contain BB codes 3410 * @param message 3411 * the actual message body, may contain BB codes 3412 * 3413 * @return whether the command succeeded or not 3414 * 3415 * @querycommands 1 3416 * @see Client#getUniqueIdentifier() 3417 * @see Message 3418 */ 3419 public CommandFuture<Boolean> sendOfflineMessage(String clientUId, String subject, String message) { 3420 final CMessageAdd add = new CMessageAdd(clientUId, subject, message); 3421 return executeAndReturnError(add); 3422 } 3423 3424 /** 3425 * Sends a text message either to the whole virtual server, a channel or specific client. 3426 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 3427 * <p> 3428 * To send a message to all virtual servers, use {@link #broadcast(String)}. 3429 * To send an offline message, use {@link #sendOfflineMessage(String, String, String)}. 3430 * </p> 3431 * 3432 * @param targetMode 3433 * where the message should be sent to 3434 * @param targetId 3435 * the client ID of the recipient of this message. This value is ignored unless {@code targetMode} is {@code CLIENT} 3436 * @param message 3437 * the text message to send 3438 * 3439 * @return whether the command succeeded or not 3440 * 3441 * @querycommands 1 3442 * @see Client#getId() 3443 */ 3444 public CommandFuture<Boolean> sendTextMessage(TextMessageTargetMode targetMode, int targetId, String message) { 3445 final CSendTextMessage msg = new CSendTextMessage(targetMode.getIndex(), targetId, message); 3446 return executeAndReturnError(msg); 3447 } 3448 3449 /** 3450 * Sends a text message to the channel with the specified ID. 3451 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 3452 * <p> 3453 * This will move the client into the channel with the specified channel ID, 3454 * <b>but will not move it back to the original channel!</b> 3455 * </p> 3456 * 3457 * @param channelId 3458 * the ID of the channel to which the message should be sent to 3459 * @param message 3460 * the text message to send 3461 * 3462 * @return whether the command succeeded or not 3463 * 3464 * @querycommands 1 3465 * @see #sendChannelMessage(String) 3466 * @see Channel#getId() 3467 */ 3468 public CommandFuture<Boolean> sendChannelMessage(int channelId, final String message) { 3469 final CommandFuture<Boolean> future = new CommandFuture<>(); 3470 3471 moveClient(channelId).onSuccess(new CommandFuture.SuccessListener<Boolean>() { 3472 @Override 3473 public void handleSuccess(Boolean result) { 3474 sendTextMessage(TextMessageTargetMode.CHANNEL, 0, message).forwardResult(future); 3475 } 3476 }).forwardFailure(future); 3477 3478 return future; 3479 } 3480 3481 /** 3482 * Sends a text message to the channel the server query is currently in. 3483 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 3484 * 3485 * @param message 3486 * the text message to send 3487 * 3488 * @return whether the command succeeded or not 3489 * 3490 * @querycommands 1 3491 */ 3492 public CommandFuture<Boolean> sendChannelMessage(String message) { 3493 return sendTextMessage(TextMessageTargetMode.CHANNEL, 0, message); 3494 } 3495 3496 /** 3497 * Sends a text message to the virtual server with the specified ID. 3498 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 3499 * <p> 3500 * This will move the client to the virtual server with the specified server ID, 3501 * <b>but will not move it back to the original virtual server!</b> 3502 * </p> 3503 * 3504 * @param serverId 3505 * the ID of the virtual server to which the message should be sent to 3506 * @param message 3507 * the text message to send 3508 * 3509 * @return whether the command succeeded or not 3510 * 3511 * @querycommands 1 3512 * @see #sendServerMessage(String) 3513 * @see VirtualServer#getId() 3514 */ 3515 public CommandFuture<Boolean> sendServerMessage(int serverId, final String message) { 3516 final CommandFuture<Boolean> future = new CommandFuture<>(); 3517 3518 selectVirtualServerById(serverId).onSuccess(new CommandFuture.SuccessListener<Boolean>() { 3519 @Override 3520 public void handleSuccess(Boolean result) { 3521 sendTextMessage(TextMessageTargetMode.SERVER, 0, message).forwardResult(future); 3522 } 3523 }).forwardFailure(future); 3524 3525 return future; 3526 } 3527 3528 /** 3529 * Sends a text message to the virtual server the server query is currently in. 3530 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 3531 * 3532 * @param message 3533 * the text message to send 3534 * 3535 * @return whether the command succeeded or not 3536 * 3537 * @querycommands 1 3538 */ 3539 public CommandFuture<Boolean> sendServerMessage(String message) { 3540 return sendTextMessage(TextMessageTargetMode.SERVER, 0, message); 3541 } 3542 3543 /** 3544 * Sends a private message to the client with the specified client ID. 3545 * Your message may contain BB codes, but its length is limited to 1024 UTF-8 bytes. 3546 * 3547 * @param clientId 3548 * the ID of the client to send the message to 3549 * @param message 3550 * the text message to send 3551 * 3552 * @return whether the command succeeded or not 3553 * 3554 * @querycommands 1 3555 * @see Client#getId() 3556 */ 3557 public CommandFuture<Boolean> sendPrivateMessage(int clientId, String message) { 3558 return sendTextMessage(TextMessageTargetMode.CLIENT, clientId, message); 3559 } 3560 3561 /** 3562 * Sets a channel group for a client in a specific channel. 3563 * 3564 * @param groupId 3565 * the ID of the group the client should join 3566 * @param channelId 3567 * the ID of the channel where the channel group should be assigned 3568 * @param clientDBId 3569 * the database ID of the client for which the channel group should be set 3570 * 3571 * @return whether the command succeeded or not 3572 * 3573 * @querycommands 1 3574 * @see ChannelGroup#getId() 3575 * @see Channel#getId() 3576 * @see Client#getDatabaseId() 3577 */ 3578 public CommandFuture<Boolean> setClientChannelGroup(int groupId, int channelId, int clientDBId) { 3579 final CSetClientChannelGroup group = new CSetClientChannelGroup(groupId, channelId, clientDBId); 3580 return executeAndReturnError(group); 3581 } 3582 3583 /** 3584 * Sets the read flag to true for a given message. This will not delete the message. 3585 * 3586 * @param messageId 3587 * the ID of the message for which the read flag should be set 3588 * 3589 * @return whether the command succeeded or not 3590 * 3591 * @querycommands 1 3592 * @see #setMessageReadFlag(int, boolean) 3593 */ 3594 public CommandFuture<Boolean> setMessageRead(int messageId) { 3595 return setMessageReadFlag(messageId, true); 3596 } 3597 3598 /** 3599 * Sets the read flag to true for a given message. This will not delete the message. 3600 * 3601 * @param message 3602 * the message for which the read flag should be set 3603 * 3604 * @return whether the command succeeded or not 3605 * 3606 * @querycommands 1 3607 * @see #setMessageRead(int) 3608 * @see #setMessageReadFlag(Message, boolean) 3609 * @see #deleteOfflineMessage(int) 3610 */ 3611 public CommandFuture<Boolean> setMessageRead(Message message) { 3612 return setMessageReadFlag(message.getId(), true); 3613 } 3614 3615 /** 3616 * Sets the read flag for a given message. This will not delete the message. 3617 * 3618 * @param messageId 3619 * the ID of the message for which the read flag should be set 3620 * @param read 3621 * the boolean value to which the read flag should be set 3622 * 3623 * @return whether the command succeeded or not 3624 * 3625 * @querycommands 1 3626 * @see #setMessageRead(int) 3627 * @see #setMessageReadFlag(Message, boolean) 3628 * @see #deleteOfflineMessage(int) 3629 */ 3630 public CommandFuture<Boolean> setMessageReadFlag(int messageId, boolean read) { 3631 final CMessageUpdateFlag flag = new CMessageUpdateFlag(messageId, read); 3632 return executeAndReturnError(flag); 3633 } 3634 3635 /** 3636 * Sets the read flag for a given message. This will not delete the message. 3637 * 3638 * @param message 3639 * the message for which the read flag should be set 3640 * @param read 3641 * the boolean value to which the read flag should be set 3642 * 3643 * @return whether the command succeeded or not 3644 * 3645 * @querycommands 1 3646 * @see #setMessageRead(Message) 3647 * @see #setMessageReadFlag(int, boolean) 3648 * @see #deleteOfflineMessage(int) 3649 */ 3650 public CommandFuture<Boolean> setMessageReadFlag(Message message, boolean read) { 3651 return setMessageReadFlag(message.getId(), read); 3652 } 3653 3654 /** 3655 * Sets the nickname of the server query client. 3656 * The nickname must be between 3 and 30 UTF-8 bytes long and BB codes will be ignored. 3657 * 3658 * @param nickname 3659 * the new nickname, may not contain any BB codes and may not be {@code null} 3660 * 3661 * @return whether the command succeeded or not 3662 * 3663 * @querycommands 1 3664 * @see #updateClient(Map) 3665 */ 3666 public CommandFuture<Boolean> setNickname(String nickname) { 3667 final Map<ClientProperty, String> options = Collections.singletonMap(ClientProperty.CLIENT_NICKNAME, nickname); 3668 return updateClient(options); 3669 } 3670 3671 /** 3672 * Starts the virtual server with the specified ID. 3673 * 3674 * @param serverId 3675 * the ID of the virtual server 3676 * 3677 * @return whether the command succeeded or not 3678 * 3679 * @querycommands 1 3680 */ 3681 public CommandFuture<Boolean> startServer(int serverId) { 3682 final CServerStart start = new CServerStart(serverId); 3683 return executeAndReturnError(start); 3684 } 3685 3686 /** 3687 * Starts the specified virtual server. 3688 * 3689 * @param virtualServer 3690 * the virtual server to start 3691 * 3692 * @return whether the command succeeded or not 3693 * 3694 * @querycommands 1 3695 */ 3696 public CommandFuture<Boolean> startServer(VirtualServer virtualServer) { 3697 return startServer(virtualServer.getId()); 3698 } 3699 3700 /** 3701 * Stops the virtual server with the specified ID. 3702 * 3703 * @param serverId 3704 * the ID of the virtual server 3705 * 3706 * @return whether the command succeeded or not 3707 * 3708 * @querycommands 1 3709 */ 3710 public CommandFuture<Boolean> stopServer(int serverId) { 3711 final CServerStop stop = new CServerStop(serverId); 3712 return executeAndReturnError(stop); 3713 } 3714 3715 /** 3716 * Stops the specified virtual server. 3717 * 3718 * @param virtualServer 3719 * the virtual server to stop 3720 * 3721 * @return whether the command succeeded or not 3722 * 3723 * @querycommands 1 3724 */ 3725 public CommandFuture<Boolean> stopServer(VirtualServer virtualServer) { 3726 return stopServer(virtualServer.getId()); 3727 } 3728 3729 /** 3730 * Stops the entire TeamSpeak 3 Server instance by shutting down the process. 3731 * <p> 3732 * To have permission to use this command, you need to use the server query admin login. 3733 * </p> 3734 * 3735 * @return whether the command succeeded or not 3736 * 3737 * @querycommands 1 3738 */ 3739 public CommandFuture<Boolean> stopServerProcess() { 3740 final CServerProcessStop stop = new CServerProcessStop(); 3741 return executeAndReturnError(stop); 3742 } 3743 3744 /** 3745 * Unregisters the server query from receiving any event notifications. 3746 * 3747 * @return whether the command succeeded or not 3748 * 3749 * @querycommands 1 3750 */ 3751 public CommandFuture<Boolean> unregisterAllEvents() { 3752 final CServerNotifyUnregister unr = new CServerNotifyUnregister(); 3753 return executeAndReturnError(unr); 3754 } 3755 3756 /** 3757 * Updates several client properties for this server query instance. 3758 * 3759 * @param options 3760 * the map of properties to update 3761 * 3762 * @return whether the command succeeded or not 3763 * 3764 * @querycommands 1 3765 * @see #editClient(int, Map) 3766 */ 3767 public CommandFuture<Boolean> updateClient(Map<ClientProperty, String> options) { 3768 final CClientUpdate update = new CClientUpdate(options); 3769 return executeAndReturnError(update); 3770 } 3771 3772 /** 3773 * Generates new login credentials for the currently connected server query instance, using the given name. 3774 * <p> 3775 * <b>This will remove the current login credentials!</b> You won't be logged out, but after disconnecting, 3776 * the old credentials will no longer work. Make sure to not lock yourselves out! 3777 * </p> 3778 * 3779 * @param loginName 3780 * the name for the server query login 3781 * 3782 * @return the generated password for the server query login 3783 * 3784 * @querycommands 1 3785 */ 3786 public CommandFuture<String> updateServerQueryLogin(String loginName) { 3787 final CClientSetServerQueryLogin login = new CClientSetServerQueryLogin(loginName); 3788 return executeAndReturnStringProperty(login, "client_login_password"); 3789 } 3790 3791 /** 3792 * Uses an existing privilege key to join a server or channel group. 3793 * 3794 * @param token 3795 * the privilege key to use 3796 * 3797 * @return whether the command succeeded or not 3798 * 3799 * @querycommands 1 3800 * @see PrivilegeKey 3801 * @see #addPrivilegeKey(TokenType, int, int, String) 3802 * @see #usePrivilegeKey(PrivilegeKey) 3803 */ 3804 public CommandFuture<Boolean> usePrivilegeKey(String token) { 3805 final CPrivilegeKeyUse use = new CPrivilegeKeyUse(token); 3806 return executeAndReturnError(use); 3807 } 3808 3809 /** 3810 * Uses an existing privilege key to join a server or channel group. 3811 * 3812 * @param privilegeKey 3813 * the privilege key to use 3814 * 3815 * @return whether the command succeeded or not 3816 * 3817 * @querycommands 1 3818 * @see PrivilegeKey 3819 * @see #addPrivilegeKey(TokenType, int, int, String) 3820 * @see #usePrivilegeKey(String) 3821 */ 3822 public CommandFuture<Boolean> usePrivilegeKey(PrivilegeKey privilegeKey) { 3823 return usePrivilegeKey(privilegeKey.getToken()); 3824 } 3825 3826 /** 3827 * Gets information about the current server query instance. 3828 * 3829 * @return information about the server query instance 3830 * 3831 * @querycommands 1 3832 * @see #getClientInfo(int) 3833 */ 3834 public CommandFuture<ServerQueryInfo> whoAmI() { 3835 final CWhoAmI whoAmI = new CWhoAmI(); 3836 final CommandFuture<ServerQueryInfo> future = new CommandFuture<>(); 3837 3838 query.doCommandAsync(whoAmI, new Callback() { 3839 @Override 3840 public void handle() { 3841 if (hasFailed(whoAmI, future)) return; 3842 future.set(new ServerQueryInfo(whoAmI.getFirstResponse().getMap())); 3843 } 3844 }); 3845 return future; 3846 } 3847 3848 /** 3849 * Executes a command, checking for failure and returning true if the command succeeded. 3850 * 3851 * @param command 3852 * the command to execute 3853 * 3854 * @return whether the command succeeded or not 3855 */ 3856 private CommandFuture<Boolean> executeAndReturnError(final Command command) { 3857 final CommandFuture<Boolean> future = new CommandFuture<>(); 3858 3859 query.doCommandAsync(command, new Callback() { 3860 @Override 3861 public void handle() { 3862 if (hasFailed(command, future)) return; 3863 future.set(true); 3864 } 3865 }); 3866 return future; 3867 } 3868 3869 /** 3870 * Executes a command, checking for failure and returning a single 3871 * {@code String} property from the first response map. 3872 * 3873 * @param command 3874 * the command to execute 3875 * @param property 3876 * the name of the property to return 3877 * 3878 * @return the value of the specified {@code String} property 3879 */ 3880 private CommandFuture<String> executeAndReturnStringProperty(final Command command, final String property) { 3881 final CommandFuture<String> future = new CommandFuture<>(); 3882 3883 query.doCommandAsync(command, new Callback() { 3884 @Override 3885 public void handle() { 3886 if (hasFailed(command, future)) return; 3887 future.set(command.getFirstResponse().get(property)); 3888 } 3889 }); 3890 return future; 3891 } 3892 3893 /** 3894 * Executes a command, checking for failure and returning a single 3895 * {@code Integer} property from the first response map. 3896 * 3897 * @param command 3898 * the command to execute 3899 * @param property 3900 * the name of the property to return 3901 * 3902 * @return the value of the specified {@code Integer} property 3903 */ 3904 private CommandFuture<Integer> executeAndReturnIntProperty(final Command command, final String property) { 3905 final CommandFuture<Integer> future = new CommandFuture<>(); 3906 3907 query.doCommandAsync(command, new Callback() { 3908 @Override 3909 public void handle() { 3910 if (hasFailed(command, future)) return; 3911 future.set(command.getFirstResponse().getInt(property)); 3912 } 3913 }); 3914 return future; 3915 } 3916 3917 /** 3918 * If a command has failed (i.e. the error ID is not 0), 3919 * the future will be marked as failed and true will be returned. 3920 * 3921 * @param command 3922 * the command to be checked for failure 3923 * @param future 3924 * the future to be notified in case of a failure 3925 * 3926 * @return true if the command has failed 3927 * 3928 * @see Command 3929 */ 3930 private boolean hasFailed(Command command, CommandFuture<?> future) { 3931 final QueryError error = command.getError(); 3932 if (error.isSuccessful()) return false; 3933 3934 future.fail(error); 3935 return true; 3936 } 3937}