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