001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.workgroup.user; 018 019import org.jivesoftware.smackx.workgroup.MetaData; 020import org.jivesoftware.smackx.workgroup.WorkgroupInvitation; 021import org.jivesoftware.smackx.workgroup.WorkgroupInvitationListener; 022import org.jivesoftware.smackx.workgroup.ext.forms.WorkgroupForm; 023import org.jivesoftware.smackx.workgroup.packet.DepartQueuePacket; 024import org.jivesoftware.smackx.workgroup.packet.QueueUpdate; 025import org.jivesoftware.smackx.workgroup.packet.SessionID; 026import org.jivesoftware.smackx.workgroup.packet.UserID; 027import org.jivesoftware.smackx.workgroup.settings.*; 028import org.jivesoftware.smackx.xdata.Form; 029import org.jivesoftware.smackx.xdata.FormField; 030import org.jivesoftware.smackx.xdata.packet.DataForm; 031import org.jivesoftware.smack.*; 032import org.jivesoftware.smack.SmackException.NoResponseException; 033import org.jivesoftware.smack.SmackException.NotConnectedException; 034import org.jivesoftware.smack.XMPPException.XMPPErrorException; 035import org.jivesoftware.smack.filter.*; 036import org.jivesoftware.smack.packet.*; 037import org.jivesoftware.smack.util.StringUtils; 038import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 039import org.jivesoftware.smackx.disco.packet.DiscoverInfo; 040import org.jivesoftware.smackx.muc.MultiUserChat; 041import org.jivesoftware.smackx.muc.packet.MUCUser; 042 043import java.util.ArrayList; 044import java.util.Iterator; 045import java.util.List; 046import java.util.Map; 047 048/** 049 * Provides workgroup services for users. Users can join the workgroup queue, depart the 050 * queue, find status information about their placement in the queue, and register to 051 * be notified when they are routed to an agent.<p> 052 * <p/> 053 * This class only provides a users perspective into a workgroup and is not intended 054 * for use by agents. 055 * 056 * @author Matt Tucker 057 * @author Derek DeMoro 058 */ 059public class Workgroup { 060 061 private String workgroupJID; 062 private XMPPConnection connection; 063 private boolean inQueue; 064 private List<WorkgroupInvitationListener> invitationListeners; 065 private List<QueueListener> queueListeners; 066 067 private int queuePosition = -1; 068 private int queueRemainingTime = -1; 069 070 /** 071 * Creates a new workgroup instance using the specified workgroup JID 072 * (eg support@workgroup.example.com) and XMPP connection. The connection must have 073 * undergone a successful login before being used to construct an instance of 074 * this class. 075 * 076 * @param workgroupJID the JID of the workgroup. 077 * @param connection an XMPP connection which must have already undergone a 078 * successful login. 079 */ 080 public Workgroup(String workgroupJID, XMPPConnection connection) { 081 // Login must have been done before passing in connection. 082 if (!connection.isAuthenticated()) { 083 throw new IllegalStateException("Must login to server before creating workgroup."); 084 } 085 086 this.workgroupJID = workgroupJID; 087 this.connection = connection; 088 inQueue = false; 089 invitationListeners = new ArrayList<WorkgroupInvitationListener>(); 090 queueListeners = new ArrayList<QueueListener>(); 091 092 // Register as a queue listener for internal usage by this instance. 093 addQueueListener(new QueueListener() { 094 public void joinedQueue() { 095 inQueue = true; 096 } 097 098 public void departedQueue() { 099 inQueue = false; 100 queuePosition = -1; 101 queueRemainingTime = -1; 102 } 103 104 public void queuePositionUpdated(int currentPosition) { 105 queuePosition = currentPosition; 106 } 107 108 public void queueWaitTimeUpdated(int secondsRemaining) { 109 queueRemainingTime = secondsRemaining; 110 } 111 }); 112 113 /** 114 * Internal handling of an invitation.Recieving an invitation removes the user from the queue. 115 */ 116 MultiUserChat.addInvitationListener(connection, 117 new org.jivesoftware.smackx.muc.InvitationListener() { 118 public void invitationReceived(XMPPConnection conn, String room, String inviter, 119 String reason, String password, Message message) { 120 inQueue = false; 121 queuePosition = -1; 122 queueRemainingTime = -1; 123 } 124 }); 125 126 // Register a packet listener for all the messages sent to this client. 127 PacketFilter typeFilter = new PacketTypeFilter(Message.class); 128 129 connection.addPacketListener(new PacketListener() { 130 public void processPacket(Packet packet) { 131 handlePacket(packet); 132 } 133 }, typeFilter); 134 } 135 136 /** 137 * Returns the name of this workgroup (eg support@example.com). 138 * 139 * @return the name of the workgroup. 140 */ 141 public String getWorkgroupJID() { 142 return workgroupJID; 143 } 144 145 /** 146 * Returns true if the user is currently waiting in the workgroup queue. 147 * 148 * @return true if currently waiting in the queue. 149 */ 150 public boolean isInQueue() { 151 return inQueue; 152 } 153 154 /** 155 * Returns true if the workgroup is available for receiving new requests. The workgroup will be 156 * available only when agents are available for this workgroup. 157 * 158 * @return true if the workgroup is available for receiving new requests. 159 * @throws XMPPErrorException 160 * @throws NoResponseException 161 * @throws NotConnectedException 162 */ 163 public boolean isAvailable() throws NoResponseException, XMPPErrorException, NotConnectedException { 164 Presence directedPresence = new Presence(Presence.Type.available); 165 directedPresence.setTo(workgroupJID); 166 PacketFilter typeFilter = new PacketTypeFilter(Presence.class); 167 PacketFilter fromFilter = FromMatchesFilter.create(workgroupJID); 168 PacketCollector collector = connection.createPacketCollector(new AndFilter(fromFilter, 169 typeFilter)); 170 171 connection.sendPacket(directedPresence); 172 173 Presence response = (Presence)collector.nextResultOrThrow(); 174 return Presence.Type.available == response.getType(); 175 } 176 177 /** 178 * Returns the users current position in the workgroup queue. A value of 0 means 179 * the user is next in line to be routed; therefore, if the queue position 180 * is being displayed to the end user it is usually a good idea to add 1 to 181 * the value this method returns before display. If the user is not currently 182 * waiting in the workgroup, or no queue position information is available, -1 183 * will be returned. 184 * 185 * @return the user's current position in the workgroup queue, or -1 if the 186 * position isn't available or if the user isn't in the queue. 187 */ 188 public int getQueuePosition() { 189 return queuePosition; 190 } 191 192 /** 193 * Returns the estimated time (in seconds) that the user has to left wait in 194 * the workgroup queue before being routed. If the user is not currently waiting 195 * int he workgroup, or no queue time information is available, -1 will be 196 * returned. 197 * 198 * @return the estimated time remaining (in seconds) that the user has to 199 * wait inthe workgroupu queue, or -1 if time information isn't available 200 * or if the user isn't int the queue. 201 */ 202 public int getQueueRemainingTime() { 203 return queueRemainingTime; 204 } 205 206 /** 207 * Joins the workgroup queue to wait to be routed to an agent. After joining 208 * the queue, queue status events will be sent to indicate the user's position and 209 * estimated time left in the queue. Once joining the queue, there are three ways 210 * the user can leave the queue: <ul> 211 * <p/> 212 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 213 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 214 * <li>A server error occurs, or an administrator explicitly removes the user 215 * from the queue. 216 * </ul> 217 * <p/> 218 * A user cannot request to join the queue again if already in the queue. Therefore, 219 * this method will throw an IllegalStateException if the user is already in the queue.<p> 220 * <p/> 221 * Some servers may be configured to require certain meta-data in order to 222 * join the queue. In that case, the {@link #joinQueue(Form)} method should be 223 * used instead of this method so that meta-data may be passed in.<p> 224 * <p/> 225 * The server tracks the conversations that a user has with agents over time. By 226 * default, that tracking is done using the user's JID. However, this is not always 227 * possible. For example, when the user is logged in anonymously using a web client. 228 * In that case the user ID might be a randomly generated value put into a persistent 229 * cookie or a username obtained via the session. A userID can be explicitly 230 * passed in by using the {@link #joinQueue(Form, String)} method. When specified, 231 * that userID will be used instead of the user's JID to track conversations. The 232 * server will ignore a manually specified userID if the user's connection to the server 233 * is not anonymous. 234 * 235 * @throws XMPPException if an error occured joining the queue. An error may indicate 236 * that a connection failure occured or that the server explicitly rejected the 237 * request to join the queue. 238 * @throws SmackException 239 */ 240 public void joinQueue() throws XMPPException, SmackException { 241 joinQueue(null); 242 } 243 244 /** 245 * Joins the workgroup queue to wait to be routed to an agent. After joining 246 * the queue, queue status events will be sent to indicate the user's position and 247 * estimated time left in the queue. Once joining the queue, there are three ways 248 * the user can leave the queue: <ul> 249 * <p/> 250 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 251 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 252 * <li>A server error occurs, or an administrator explicitly removes the user 253 * from the queue. 254 * </ul> 255 * <p/> 256 * A user cannot request to join the queue again if already in the queue. Therefore, 257 * this method will throw an IllegalStateException if the user is already in the queue.<p> 258 * <p/> 259 * Some servers may be configured to require certain meta-data in order to 260 * join the queue.<p> 261 * <p/> 262 * The server tracks the conversations that a user has with agents over time. By 263 * default, that tracking is done using the user's JID. However, this is not always 264 * possible. For example, when the user is logged in anonymously using a web client. 265 * In that case the user ID might be a randomly generated value put into a persistent 266 * cookie or a username obtained via the session. A userID can be explicitly 267 * passed in by using the {@link #joinQueue(Form, String)} method. When specified, 268 * that userID will be used instead of the user's JID to track conversations. The 269 * server will ignore a manually specified userID if the user's connection to the server 270 * is not anonymous. 271 * 272 * @param answerForm the completed form the send for the join request. 273 * @throws XMPPException if an error occured joining the queue. An error may indicate 274 * that a connection failure occured or that the server explicitly rejected the 275 * request to join the queue. 276 * @throws SmackException 277 */ 278 public void joinQueue(Form answerForm) throws XMPPException, SmackException { 279 joinQueue(answerForm, null); 280 } 281 282 /** 283 * <p>Joins the workgroup queue to wait to be routed to an agent. After joining 284 * the queue, queue status events will be sent to indicate the user's position and 285 * estimated time left in the queue. Once joining the queue, there are three ways 286 * the user can leave the queue: <ul> 287 * <p/> 288 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 289 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 290 * <li>A server error occurs, or an administrator explicitly removes the user 291 * from the queue. 292 * </ul> 293 * <p/> 294 * A user cannot request to join the queue again if already in the queue. Therefore, 295 * this method will throw an IllegalStateException if the user is already in the queue.<p> 296 * <p/> 297 * Some servers may be configured to require certain meta-data in order to 298 * join the queue.<p> 299 * <p/> 300 * The server tracks the conversations that a user has with agents over time. By 301 * default, that tracking is done using the user's JID. However, this is not always 302 * possible. For example, when the user is logged in anonymously using a web client. 303 * In that case the user ID might be a randomly generated value put into a persistent 304 * cookie or a username obtained via the session. When specified, that userID will 305 * be used instead of the user's JID to track conversations. The server will ignore a 306 * manually specified userID if the user's connection to the server is not anonymous. 307 * 308 * @param answerForm the completed form associated with the join reqest. 309 * @param userID String that represents the ID of the user when using anonymous sessions 310 * or <tt>null</tt> if a userID should not be used. 311 * @throws XMPPErrorException if an error occured joining the queue. An error may indicate 312 * that a connection failure occured or that the server explicitly rejected the 313 * request to join the queue. 314 * @throws NoResponseException 315 * @throws NotConnectedException 316 */ 317 public void joinQueue(Form answerForm, String userID) throws NoResponseException, XMPPErrorException, NotConnectedException { 318 // If already in the queue ignore the join request. 319 if (inQueue) { 320 throw new IllegalStateException("Already in queue " + workgroupJID); 321 } 322 323 JoinQueuePacket joinPacket = new JoinQueuePacket(workgroupJID, answerForm, userID); 324 325 connection.createPacketCollectorAndSend(joinPacket).nextResultOrThrow(); 326 // Notify listeners that we've joined the queue. 327 fireQueueJoinedEvent(); 328 } 329 330 /** 331 * <p>Joins the workgroup queue to wait to be routed to an agent. After joining 332 * the queue, queue status events will be sent to indicate the user's position and 333 * estimated time left in the queue. Once joining the queue, there are three ways 334 * the user can leave the queue: <ul> 335 * <p/> 336 * <li>The user is routed to an agent, which triggers a GroupChat invitation. 337 * <li>The user asks to leave the queue by calling the {@link #departQueue} method. 338 * <li>A server error occurs, or an administrator explicitly removes the user 339 * from the queue. 340 * </ul> 341 * <p/> 342 * A user cannot request to join the queue again if already in the queue. Therefore, 343 * this method will throw an IllegalStateException if the user is already in the queue.<p> 344 * <p/> 345 * Some servers may be configured to require certain meta-data in order to 346 * join the queue.<p> 347 * <p/> 348 * The server tracks the conversations that a user has with agents over time. By 349 * default, that tracking is done using the user's JID. However, this is not always 350 * possible. For example, when the user is logged in anonymously using a web client. 351 * In that case the user ID might be a randomly generated value put into a persistent 352 * cookie or a username obtained via the session. When specified, that userID will 353 * be used instead of the user's JID to track conversations. The server will ignore a 354 * manually specified userID if the user's connection to the server is not anonymous. 355 * 356 * @param metadata metadata to create a dataform from. 357 * @param userID String that represents the ID of the user when using anonymous sessions 358 * or <tt>null</tt> if a userID should not be used. 359 * @throws XMPPException if an error occured joining the queue. An error may indicate 360 * that a connection failure occured or that the server explicitly rejected the 361 * request to join the queue. 362 * @throws SmackException 363 */ 364 public void joinQueue(Map<String,Object> metadata, String userID) throws XMPPException, SmackException { 365 // If already in the queue ignore the join request. 366 if (inQueue) { 367 throw new IllegalStateException("Already in queue " + workgroupJID); 368 } 369 370 // Build dataform from metadata 371 Form form = new Form(Form.TYPE_SUBMIT); 372 Iterator<String> iter = metadata.keySet().iterator(); 373 while (iter.hasNext()) { 374 String name = iter.next(); 375 String value = metadata.get(name).toString(); 376 377 FormField field = new FormField(name); 378 field.setType(FormField.TYPE_TEXT_SINGLE); 379 form.addField(field); 380 form.setAnswer(name, value); 381 } 382 joinQueue(form, userID); 383 } 384 385 /** 386 * Departs the workgroup queue. If the user is not currently in the queue, this 387 * method will do nothing.<p> 388 * <p/> 389 * Normally, the user would not manually leave the queue. However, they may wish to 390 * under certain circumstances -- for example, if they no longer wish to be routed 391 * to an agent because they've been waiting too long. 392 * 393 * @throws XMPPErrorException if an error occured trying to send the depart queue 394 * request to the server. 395 * @throws NoResponseException 396 * @throws NotConnectedException 397 */ 398 public void departQueue() throws NoResponseException, XMPPErrorException, NotConnectedException { 399 // If not in the queue ignore the depart request. 400 if (!inQueue) { 401 return; 402 } 403 404 DepartQueuePacket departPacket = new DepartQueuePacket(this.workgroupJID); 405 connection.createPacketCollectorAndSend(departPacket).nextResultOrThrow(); 406 407 // Notify listeners that we're no longer in the queue. 408 fireQueueDepartedEvent(); 409 } 410 411 /** 412 * Adds a queue listener that will be notified of queue events for the user 413 * that created this Workgroup instance. 414 * 415 * @param queueListener the queue listener. 416 */ 417 public void addQueueListener(QueueListener queueListener) { 418 synchronized (queueListeners) { 419 if (!queueListeners.contains(queueListener)) { 420 queueListeners.add(queueListener); 421 } 422 } 423 } 424 425 /** 426 * Removes a queue listener. 427 * 428 * @param queueListener the queue listener. 429 */ 430 public void removeQueueListener(QueueListener queueListener) { 431 synchronized (queueListeners) { 432 queueListeners.remove(queueListener); 433 } 434 } 435 436 /** 437 * Adds an invitation listener that will be notified of groupchat invitations 438 * from the workgroup for the the user that created this Workgroup instance. 439 * 440 * @param invitationListener the invitation listener. 441 */ 442 public void addInvitationListener(WorkgroupInvitationListener invitationListener) { 443 synchronized (invitationListeners) { 444 if (!invitationListeners.contains(invitationListener)) { 445 invitationListeners.add(invitationListener); 446 } 447 } 448 } 449 450 /** 451 * Removes an invitation listener. 452 * 453 * @param invitationListener the invitation listener. 454 */ 455 public void removeQueueListener(WorkgroupInvitationListener invitationListener) { 456 synchronized (invitationListeners) { 457 invitationListeners.remove(invitationListener); 458 } 459 } 460 461 private void fireInvitationEvent(WorkgroupInvitation invitation) { 462 synchronized (invitationListeners) { 463 for (Iterator<WorkgroupInvitationListener> i = invitationListeners.iterator(); i.hasNext();) { 464 WorkgroupInvitationListener listener = i.next(); 465 listener.invitationReceived(invitation); 466 } 467 } 468 } 469 470 private void fireQueueJoinedEvent() { 471 synchronized (queueListeners) { 472 for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) { 473 QueueListener listener = i.next(); 474 listener.joinedQueue(); 475 } 476 } 477 } 478 479 private void fireQueueDepartedEvent() { 480 synchronized (queueListeners) { 481 for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) { 482 QueueListener listener = i.next(); 483 listener.departedQueue(); 484 } 485 } 486 } 487 488 private void fireQueuePositionEvent(int currentPosition) { 489 synchronized (queueListeners) { 490 for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) { 491 QueueListener listener = i.next(); 492 listener.queuePositionUpdated(currentPosition); 493 } 494 } 495 } 496 497 private void fireQueueTimeEvent(int secondsRemaining) { 498 synchronized (queueListeners) { 499 for (Iterator<QueueListener> i = queueListeners.iterator(); i.hasNext();) { 500 QueueListener listener = i.next(); 501 listener.queueWaitTimeUpdated(secondsRemaining); 502 } 503 } 504 } 505 506 // PacketListener Implementation. 507 508 private void handlePacket(Packet packet) { 509 if (packet instanceof Message) { 510 Message msg = (Message)packet; 511 // Check to see if the user left the queue. 512 PacketExtension pe = msg.getExtension("depart-queue", "http://jabber.org/protocol/workgroup"); 513 PacketExtension queueStatus = msg.getExtension("queue-status", "http://jabber.org/protocol/workgroup"); 514 515 if (pe != null) { 516 fireQueueDepartedEvent(); 517 } 518 else if (queueStatus != null) { 519 QueueUpdate queueUpdate = (QueueUpdate)queueStatus; 520 if (queueUpdate.getPosition() != -1) { 521 fireQueuePositionEvent(queueUpdate.getPosition()); 522 } 523 if (queueUpdate.getRemaingTime() != -1) { 524 fireQueueTimeEvent(queueUpdate.getRemaingTime()); 525 } 526 } 527 528 else { 529 // Check if a room invitation was sent and if the sender is the workgroup 530 MUCUser mucUser = (MUCUser)msg.getExtension("x", "http://jabber.org/protocol/muc#user"); 531 MUCUser.Invite invite = mucUser != null ? mucUser.getInvite() : null; 532 if (invite != null && workgroupJID.equals(invite.getFrom())) { 533 String sessionID = null; 534 Map<String, List<String>> metaData = null; 535 536 pe = msg.getExtension(SessionID.ELEMENT_NAME, 537 SessionID.NAMESPACE); 538 if (pe != null) { 539 sessionID = ((SessionID)pe).getSessionID(); 540 } 541 542 pe = msg.getExtension(MetaData.ELEMENT_NAME, 543 MetaData.NAMESPACE); 544 if (pe != null) { 545 metaData = ((MetaData)pe).getMetaData(); 546 } 547 548 WorkgroupInvitation inv = new WorkgroupInvitation(connection.getUser(), msg.getFrom(), 549 workgroupJID, sessionID, msg.getBody(), 550 msg.getFrom(), metaData); 551 552 fireInvitationEvent(inv); 553 } 554 } 555 } 556 } 557 558 /** 559 * IQ packet to request joining the workgroup queue. 560 */ 561 private class JoinQueuePacket extends IQ { 562 563 private String userID = null; 564 private DataForm form; 565 566 public JoinQueuePacket(String workgroup, Form answerForm, String userID) { 567 this.userID = userID; 568 569 setTo(workgroup); 570 setType(IQ.Type.SET); 571 572 form = answerForm.getDataFormToSend(); 573 addExtension(form); 574 } 575 576 public String getChildElementXML() { 577 StringBuilder buf = new StringBuilder(); 578 579 buf.append("<join-queue xmlns=\"http://jabber.org/protocol/workgroup\">"); 580 buf.append("<queue-notifications/>"); 581 // Add the user unique identification if the session is anonymous 582 if (connection.isAnonymous()) { 583 buf.append(new UserID(userID).toXML()); 584 } 585 586 // Append data form text 587 buf.append(form.toXML()); 588 589 buf.append("</join-queue>"); 590 591 return buf.toString(); 592 } 593 } 594 595 /** 596 * Returns a single chat setting based on it's identified key. 597 * 598 * @param key the key to find. 599 * @return the ChatSetting if found, otherwise false. 600 * @throws XMPPException if an error occurs while getting information from the server. 601 * @throws SmackException 602 */ 603 public ChatSetting getChatSetting(String key) throws XMPPException, SmackException { 604 ChatSettings chatSettings = getChatSettings(key, -1); 605 return chatSettings.getFirstEntry(); 606 } 607 608 /** 609 * Returns ChatSettings based on type. 610 * 611 * @param type the type of ChatSettings to return. 612 * @return the ChatSettings of given type, otherwise null. 613 * @throws XMPPException if an error occurs while getting information from the server. 614 * @throws SmackException 615 */ 616 public ChatSettings getChatSettings(int type) throws XMPPException, SmackException { 617 return getChatSettings(null, type); 618 } 619 620 /** 621 * Returns all ChatSettings. 622 * 623 * @return all ChatSettings of a given workgroup. 624 * @throws XMPPException if an error occurs while getting information from the server. 625 * @throws SmackException 626 */ 627 public ChatSettings getChatSettings() throws XMPPException, SmackException { 628 return getChatSettings(null, -1); 629 } 630 631 632 /** 633 * Asks the workgroup for it's Chat Settings. 634 * 635 * @return key specify a key to retrieve only that settings. Otherwise for all settings, key should be null. 636 * @throws NoResponseException 637 * @throws XMPPErrorException if an error occurs while getting information from the server. 638 * @throws NotConnectedException 639 */ 640 private ChatSettings getChatSettings(String key, int type) throws NoResponseException, XMPPErrorException, NotConnectedException { 641 ChatSettings request = new ChatSettings(); 642 if (key != null) { 643 request.setKey(key); 644 } 645 if (type != -1) { 646 request.setType(type); 647 } 648 request.setType(IQ.Type.GET); 649 request.setTo(workgroupJID); 650 651 ChatSettings response = (ChatSettings) connection.createPacketCollectorAndSend(request).nextResultOrThrow(); 652 653 return response; 654 } 655 656 /** 657 * The workgroup service may be configured to send email. This queries the Workgroup Service 658 * to see if the email service has been configured and is available. 659 * 660 * @return true if the email service is available, otherwise return false. 661 * @throws SmackException 662 */ 663 public boolean isEmailAvailable() throws SmackException { 664 ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection); 665 666 try { 667 String workgroupService = StringUtils.parseServer(workgroupJID); 668 DiscoverInfo infoResult = discoManager.discoverInfo(workgroupService); 669 return infoResult.containsFeature("jive:email:provider"); 670 } 671 catch (XMPPException e) { 672 return false; 673 } 674 } 675 676 /** 677 * Asks the workgroup for it's Offline Settings. 678 * 679 * @return offlineSettings the offline settings for this workgroup. 680 * @throws XMPPErrorException 681 * @throws NoResponseException 682 * @throws NotConnectedException 683 */ 684 public OfflineSettings getOfflineSettings() throws NoResponseException, XMPPErrorException, NotConnectedException { 685 OfflineSettings request = new OfflineSettings(); 686 request.setType(IQ.Type.GET); 687 request.setTo(workgroupJID); 688 689 OfflineSettings response = (OfflineSettings) connection.createPacketCollectorAndSend( 690 request).nextResultOrThrow(); 691 return response; 692 } 693 694 /** 695 * Asks the workgroup for it's Sound Settings. 696 * 697 * @return soundSettings the sound settings for the specified workgroup. 698 * @throws XMPPErrorException 699 * @throws NoResponseException 700 * @throws NotConnectedException 701 */ 702 public SoundSettings getSoundSettings() throws NoResponseException, XMPPErrorException, NotConnectedException { 703 SoundSettings request = new SoundSettings(); 704 request.setType(IQ.Type.GET); 705 request.setTo(workgroupJID); 706 707 SoundSettings response = (SoundSettings) connection.createPacketCollectorAndSend(request).nextResultOrThrow(); 708 return response; 709 } 710 711 /** 712 * Asks the workgroup for it's Properties 713 * 714 * @return the WorkgroupProperties for the specified workgroup. 715 * @throws XMPPErrorException 716 * @throws NoResponseException 717 * @throws NotConnectedException 718 */ 719 public WorkgroupProperties getWorkgroupProperties() throws NoResponseException, XMPPErrorException, NotConnectedException { 720 WorkgroupProperties request = new WorkgroupProperties(); 721 request.setType(IQ.Type.GET); 722 request.setTo(workgroupJID); 723 724 WorkgroupProperties response = (WorkgroupProperties) connection.createPacketCollectorAndSend( 725 request).nextResultOrThrow(); 726 return response; 727 } 728 729 /** 730 * Asks the workgroup for it's Properties 731 * 732 * @param jid the jid of the user who's information you would like the workgroup to retreive. 733 * @return the WorkgroupProperties for the specified workgroup. 734 * @throws XMPPErrorException 735 * @throws NoResponseException 736 * @throws NotConnectedException 737 */ 738 public WorkgroupProperties getWorkgroupProperties(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException { 739 WorkgroupProperties request = new WorkgroupProperties(); 740 request.setJid(jid); 741 request.setType(IQ.Type.GET); 742 request.setTo(workgroupJID); 743 744 WorkgroupProperties response = (WorkgroupProperties) connection.createPacketCollectorAndSend( 745 request).nextResultOrThrow(); 746 return response; 747 } 748 749 750 /** 751 * Returns the Form to use for all clients of a workgroup. It is unlikely that the server 752 * will change the form (without a restart) so it is safe to keep the returned form 753 * for future submissions. 754 * 755 * @return the Form to use for searching transcripts. 756 * @throws XMPPErrorException 757 * @throws NoResponseException 758 * @throws NotConnectedException 759 */ 760 public Form getWorkgroupForm() throws NoResponseException, XMPPErrorException, NotConnectedException { 761 WorkgroupForm workgroupForm = new WorkgroupForm(); 762 workgroupForm.setType(IQ.Type.GET); 763 workgroupForm.setTo(workgroupJID); 764 765 WorkgroupForm response = (WorkgroupForm) connection.createPacketCollectorAndSend( 766 workgroupForm).nextResultOrThrow(); 767 return Form.getFormFrom(response); 768 } 769}