/**
  * Replaces the message with ID <tt>correctedMessageUID</tt> sent to the contact <tt>to</tt> with
  * the message <tt>message</tt>
  *
  * @param to The contact to send the message to.
  * @param message The new message.
  * @param correctedMessageUID The ID of the message being replaced.
  */
 public void correctMessage(
     Contact to, ContactResource resource, Message message, String correctedMessageUID) {
   PacketExtension[] exts = new PacketExtension[1];
   exts[0] = new MessageCorrectionExtension(correctedMessageUID);
   MessageDeliveredEvent msgDelivered = sendMessage(to, resource, message, exts);
   msgDelivered.setCorrectedMessageUID(correctedMessageUID);
   fireMessageEvent(msgDelivered);
 }
  /**
   * Helper function used to send a message to a contact, with the given extensions attached.
   *
   * @param to The contact to send the message to.
   * @param toResource The resource to send the message to or null if no resource has been specified
   * @param message The message to send.
   * @param extensions The XMPP extensions that should be attached to the message before sending.
   * @return The MessageDeliveryEvent that resulted after attempting to send this message, so the
   *     calling function can modify it if needed.
   */
  private MessageDeliveredEvent sendMessage(
      Contact to, ContactResource toResource, Message message, PacketExtension[] extensions) {
    if (!(to instanceof ContactJabberImpl))
      throw new IllegalArgumentException("The specified contact is not a Jabber contact." + to);

    assertConnected();

    org.jivesoftware.smack.packet.Message msg = new org.jivesoftware.smack.packet.Message();

    String toJID = null;

    if (toResource != null) {
      if (toResource.equals(ContactResource.BASE_RESOURCE)) {
        toJID = to.getAddress();
      } else toJID = ((ContactResourceJabberImpl) toResource).getFullJid();
    }

    if (toJID == null) {
      toJID = to.getAddress();
    }

    msg.setPacketID(message.getMessageUID());
    msg.setTo(toJID);

    for (PacketExtension ext : extensions) {
      msg.addExtension(ext);
    }

    if (logger.isTraceEnabled())
      logger.trace("Will send a message to:" + toJID + " chat.jid=" + toJID);

    MessageDeliveredEvent msgDeliveryPendingEvt =
        new MessageDeliveredEvent(message, to, toResource);

    MessageDeliveredEvent[] transformedEvents =
        messageDeliveryPendingTransform(msgDeliveryPendingEvt);

    if (transformedEvents == null || transformedEvents.length == 0) return null;

    for (MessageDeliveredEvent event : transformedEvents) {
      String content = event.getSourceMessage().getContent();

      if (message.getContentType().equals(HTML_MIME_TYPE)) {
        msg.setBody(Html2Text.extractText(content));

        // Check if the other user supports XHTML messages
        // make sure we use our discovery manager as it caches calls
        if (jabberProvider.isFeatureListSupported(toJID, HTML_NAMESPACE)) {
          // Add the XHTML text to the message
          XHTMLManager.addBody(msg, OPEN_BODY_TAG + content + CLOSE_BODY_TAG);
        }
      } else {
        // this is plain text so keep it as it is.
        msg.setBody(content);
      }

      // msg.addExtension(new Version());

      if (event.isMessageEncrypted() && isCarbonEnabled) {
        msg.addExtension(new CarbonPacketExtension.PrivateExtension());
      }

      MessageEventManager.addNotificationsRequests(msg, true, false, false, true);

      String threadID = getThreadIDForAddress(toJID);
      if (threadID == null) threadID = nextThreadID();

      msg.setThread(threadID);
      msg.setType(org.jivesoftware.smack.packet.Message.Type.chat);
      msg.setFrom(jabberProvider.getConnection().getUser());

      jabberProvider.getConnection().sendPacket(msg);

      putJidForAddress(toJID, threadID);
    }

    return new MessageDeliveredEvent(message, to, toResource);
  }