/**
   * Updates the write state for the user. This is useful to see which users are currently writing.
   *
   * <p>If the user is the application user, messages will be sent to the other clients to notify of
   * changes.
   *
   * @param code The user code for the user to update.
   * @param writing True if the user is writing.
   */
  public void changeWriting(final int code, final boolean writing) {
    userListController.changeWriting(code, writing);

    if (code == me.getCode()) {
      chatState.setWrote(writing);

      if (writing) {
        messages.sendWritingMessage();
      } else {
        messages.sendStoppedWritingMessage();
      }
    }
  }
 /**
  * Sends a private chat message over the network, to the specified user.
  *
  * @param privmsg The private message to send.
  * @param user The user to send the private message to.
  * @throws CommandException If there is no connection to the network, or the application user is
  *     away, or the private message is empty, or the private message is too long, or the specified
  *     user has no port to send the private message to, or the specified user is away or offline.
  */
 public void sendPrivateMessage(final String privmsg, final User user) throws CommandException {
   if (!isConnected()) {
     throw new CommandException("You can not send a private chat message without being connected");
   } else if (me.isAway()) {
     throw new CommandException("You can not send a private chat message while away");
   } else if (privmsg.trim().length() == 0) {
     throw new CommandException("You can not send an empty private chat message");
   } else if (Tools.getBytes(privmsg) > Constants.MESSAGE_MAX_BYTES) {
     throw new CommandException(
         "You can not send a private chat message with more than "
             + Constants.MESSAGE_MAX_BYTES
             + " bytes");
   } else if (user.getPrivateChatPort() == 0) {
     throw new CommandException(
         "You can not send a private chat message to a user with no available port number");
   } else if (user.isAway()) {
     throw new CommandException("You can not send a private chat message to a user that is away");
   } else if (!user.isOnline()) {
     throw new CommandException(
         "You can not send a private chat message to a user that is offline");
   } else if (settings.isNoPrivateChat()) {
     throw new CommandException(
         "You can not send a private chat message when private chat is disabled");
   } else {
     messages.sendPrivateMessage(privmsg, user);
   }
 }
  /**
   * Changes the nick for the application user, sends a message over the network to notify the other
   * clients of the change, and saves the changes.
   *
   * @param newNick The new nick for the application user.
   * @throws CommandException If the user is away.
   */
  public void changeMyNick(final String newNick) throws CommandException {
    if (me.isAway()) {
      throw new CommandException("You can not change nick while away");
    }

    messages.sendNickMessage(newNick);
    changeNick(me.getCode(), newNick);
    settings.saveSettings();
  }
 /**
  * Logs this client off the network. <br>
  * <br>
  * <strong>Note:</strong> removeUsers should not be true when called from a ShutdownHook, as that
  * will lead to a deadlock. See http://bugs.sun.com/bugdatabase/view_bug.do;?bug_id=6261550 for
  * details.
  *
  * @param removeUsers Set to true to remove users from the user list.
  */
 public void logOff(final boolean removeUsers) {
   messages.sendLogoffMessage();
   chatState.setLoggedOn(false);
   chatState.setLogonCompleted(false);
   networkService.disconnect();
   getTopic().resetTopic();
   if (removeUsers) {
     removeAllUsers();
   }
   me.reset();
 }
  /**
   * Updates the away status and the away message for the user.
   *
   * @param code The user code for the user to update.
   * @param away If the user is away or not.
   * @param awaymsg The away message for that user.
   * @throws CommandException If there is no connection to the network, or the user tries to set an
   *     away message that is to long.
   */
  public void changeAwayStatus(final int code, final boolean away, final String awaymsg)
      throws CommandException {
    if (code == me.getCode() && !isLoggedOn()) {
      throw new CommandException("You can not change away mode without being connected");
    } else if (Tools.getBytes(awaymsg) > Constants.MESSAGE_MAX_BYTES) {
      throw new CommandException(
          "You can not set an away message with more than "
              + Constants.MESSAGE_MAX_BYTES
              + " bytes");
    }

    if (code == me.getCode()) {
      if (away) {
        messages.sendAwayMessage(awaymsg);
      } else {
        messages.sendBackMessage();
      }
    }

    userListController.changeAwayStatus(code, away, awaymsg);
  }
  /**
   * Makes sure the application reacts when the network is available.
   *
   * @param silent If true, wont show the "you are connected..." message to the user.
   */
  @Override
  public void networkCameUp(final boolean silent) {
    // Network came up after a logon
    if (!isLoggedOn()) {
      runDelayedLogon();
      sendLogOn();
    }

    // Network came up after a timeout
    else {
      ui.showTopic();

      if (!silent) {
        msgController.showSystemMessage("You are connected to the network again");
      }

      messages.sendTopicRequestedMessage(getTopic());
      messages.sendExposingMessage();
      messages.sendGetTopicMessage();
      messages.sendExposeMessage();
      messages.sendIdleMessage();
    }
  }
  /**
   * Changes the topic, and sends a notification to the other clients.
   *
   * @param newTopic The new topic to set.
   * @throws CommandException If there is no connection to the network, or the application user is
   *     away, or the topic is too long.
   */
  public void changeTopic(final String newTopic) throws CommandException {
    if (!isLoggedOn()) {
      throw new CommandException("You can not change the topic without being connected");
    } else if (me.isAway()) {
      throw new CommandException("You can not change the topic while away");
    } else if (Tools.getBytes(newTopic) > Constants.MESSAGE_MAX_BYTES) {
      throw new CommandException(
          "You can not set a topic with more than " + Constants.MESSAGE_MAX_BYTES + " bytes");
    }

    final long time = System.currentTimeMillis();
    final Topic newTopicObj = new Topic(newTopic, me.getNick(), time);
    messages.sendTopicChangeMessage(newTopicObj);
    final Topic topic = getTopic();
    topic.changeTopic(newTopicObj);
  }
 /**
  * Sends a chat message over the network, to all the other users.
  *
  * @param msg The message to send.
  * @throws CommandException If there is no connection to the network, or the application user is
  *     away, or the message is empty, or the message is too long.
  */
 public void sendChatMessage(final String msg) throws CommandException {
   if (!isConnected()) {
     throw new CommandException("You can not send a chat message without being connected");
   } else if (me.isAway()) {
     throw new CommandException("You can not send a chat message while away");
   } else if (msg.trim().length() == 0) {
     throw new CommandException("You can not send an empty chat message");
   } else if (Tools.getBytes(msg) > Constants.MESSAGE_MAX_BYTES) {
     throw new CommandException(
         "You can not send a chat message with more than "
             + Constants.MESSAGE_MAX_BYTES
             + " bytes");
   } else {
     messages.sendChatMessage(msg);
   }
 }
  /**
   * Sends a message over the network to notify another user that the application user wants to send
   * a file.
   *
   * @param user The user asked to receive a file.
   * @param file The file to send.
   * @throws CommandException If the specified user is the application user, or there is no
   *     connection to the network, or the application user is away, or the specified user is away,
   *     or the file name is too long.
   */
  public void sendFile(final User user, final File file) throws CommandException {
    Validate.notNull(user, "User can not be null");
    Validate.notNull(file, "File can not be null");

    if (user.isMe()) {
      throw new CommandException("You can not send a file to yourself");
    } else if (!isConnected()) {
      throw new CommandException("You can not send a file without being connected");
    } else if (me.isAway()) {
      throw new CommandException("You can not send a file while away");
    } else if (user.isAway()) {
      throw new CommandException("You can not send a file to a user that is away");
    } else if (Tools.getBytes(file.getName()) > Constants.MESSAGE_MAX_BYTES) {
      throw new CommandException(
          "You can not send a file with a name with more than "
              + Constants.MESSAGE_MAX_BYTES
              + " bytes");
    } else {
      messages.sendFile(user, file);
    }
  }
 /** Sends a message over the network with the current topic. */
 public void sendTopicRequestedMessage() {
   messages.sendTopicRequestedMessage(getTopic());
 }
 /**
  * Sends the necessary network messages to log the user onto the network and query for the users
  * and state.
  */
 private void sendLogOn() {
   messages.sendLogonMessage();
   messages.sendClient();
   messages.sendExposeMessage();
   messages.sendGetTopicMessage();
 }
 /** Sends a message over the network with more information about this client. */
 public void sendClientInfo() {
   messages.sendClient();
 }
 /**
  * If any users have timed out because of missed idle messages, then send a message over the
  * network to ask all clients to identify themselves again.
  */
 public void updateAfterTimeout() {
   if (userListController.isTimeoutUsers()) {
     messages.sendExposeMessage();
   }
 }
 /**
  * Sends a message over the network to notify the file sender that you accepted the file transfer.
  *
  * @param user The user sending a file.
  * @param port The port the file sender can connect to on this client to start the file transfer.
  * @param fileHash The unique hash code of the file.
  * @param fileName The name of the file.
  * @throws CommandException If the message was not sent successfully.
  */
 public void sendFileAccept(
     final User user, final int port, final int fileHash, final String fileName)
     throws CommandException {
   messages.sendFileAccept(user, port, fileHash, fileName);
 }
 /**
  * Sends a message over the network to notify the file sender that you aborted the file transfer.
  *
  * @param user The user sending a file.
  * @param fileHash The unique hash code of the file.
  * @param fileName The name of the file.
  */
 public void sendFileAbort(final User user, final int fileHash, final String fileName) {
   messages.sendFileAbort(user, fileHash, fileName);
 }
 /**
  * Sends a message over the network to notify the other clients that a client has tried to logon
  * using the nick name of the application user.
  *
  * @param nick The nick that is already in use by the application user.
  */
 public void sendNickCrashMessage(final String nick) {
   messages.sendNickCrashMessage(nick);
 }
 /** Sends a message over the network to identify this client. */
 public void sendExposingMessage() {
   messages.sendExposingMessage();
 }
 /** Sends a message over the network to notify other clients that this client is still alive. */
 public void sendIdleMessage() {
   if (isConnected()) {
     messages.sendIdleMessage();
   }
 }
 /** Sends a message over the network to ask for the current topic. */
 public void sendGetTopicMessage() {
   messages.sendGetTopicMessage();
 }