/* * Kontalk Java client * Copyright (C) 2016 Kontalk Devteam <devteam@kontalk.org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.model.message; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.logging.Logger; import org.kontalk.crypto.Coder; import org.kontalk.misc.JID; import org.kontalk.model.Contact; import org.kontalk.model.chat.Chat; import org.kontalk.util.EncodingUtils; /** * Model for an XMPP message from the user to a contact. * @author Alexander Bikadorov {@literal <bikaejkb@mail.tu-berlin.de>} */ public final class OutMessage extends KonMessage { private static final Logger LOGGER = Logger.getLogger(OutMessage.class.getName()); private final Set<Transmission> mTransmissions; public OutMessage(Chat chat, List<Contact> contacts, MessageContent content, boolean encrypted) { super( chat, "Kon_" + EncodingUtils.randomString(8), content, Optional.empty(), Status.PENDING, encrypted ? CoderStatus.createToEncrypt() : CoderStatus.createInsecure()); Set<Transmission> ts = new HashSet<>(); contacts.forEach(contact -> { boolean succ = ts.add(new Transmission(contact, contact.getJID(), mID)); if (!succ) LOGGER.warning("duplicate contact: " + contact); }); mTransmissions = Collections.unmodifiableSet(ts); } // used when loading from database OutMessage(KonMessage.Builder builder) { super(builder); mTransmissions = Collections.unmodifiableSet(builder.mTransmissions); } public void setReceived(JID jid, Date date) { Transmission transmission = mTransmissions.stream() .filter(t -> t.getContact().getJID().equals(jid)) .findFirst().orElse(null); if (transmission == null) { LOGGER.warning("can't find transmission for received status, IDs: "+jid); return; } if (transmission.isReceived()) // probably already received by another client return; transmission.setReceived(date); this.changed(ViewChange.STATUS); } public void setStatus(Status status) { if (status == Status.IN || status == Status.RECEIVED) { LOGGER.warning("wrong status argument: "+status); return; } if (status == Status.SENT && mStatus != Status.PENDING) LOGGER.warning("unexpected new status of sent message: "+status); mStatus = status; if (status != Status.PENDING) mServerDate = new Date(); this.save(); this.changed(ViewChange.STATUS); } // Note: only one error per message (not transmission) possible public void setServerError(String condition, String text) { if (mStatus != Status.SENT) LOGGER.warning("unexpected status of message with error: "+mStatus); mServerError = new KonMessage.ServerError(condition, text); this.setStatus(Status.ERROR); } public boolean isSendEncrypted() { return mCoderStatus.getEncryption() != Coder.Encryption.NOT || mCoderStatus.getSigning() != Coder.Signing.NOT; } @Override public Set<Transmission> getTransmissions() { return mTransmissions; } @Override public final boolean equals(Object o) { if (o == this) return true; if (!(o instanceof OutMessage)) return false; return this.abstractEquals((KonMessage) o); } @Override public int hashCode() { return Objects.hash(mTransmissions); } }