Search in sources :

Example 6 with ArchivedMessage

use of com.reucon.openfire.plugin.archive.model.ArchivedMessage in project Openfire by igniterealtime.

the class JdbcPersistenceManager method findMessages.

@Override
public Collection<ArchivedMessage> findMessages(Date startDate, Date endDate, String ownerJid, String withJid, XmppResultSet xmppResultSet) {
    final boolean isOracleDB = isOracleDB();
    final StringBuilder querySB;
    final StringBuilder whereSB;
    final StringBuilder limitSB;
    final TreeMap<Long, ArchivedMessage> archivedMessages = new TreeMap<Long, ArchivedMessage>();
    querySB = new StringBuilder(isOracleDB ? SELECT_MESSAGE_ORACLE : SELECT_MESSAGES);
    whereSB = new StringBuilder();
    limitSB = new StringBuilder();
    // Ignore legacy messages
    appendWhere(whereSB, MESSAGE_ID, " IS NOT NULL ");
    startDate = getAuditedStartDate(startDate);
    if (startDate != null) {
        appendWhere(whereSB, MESSAGE_SENT_DATE, " >= ?");
    }
    if (endDate != null) {
        appendWhere(whereSB, MESSAGE_SENT_DATE, " <= ?");
    }
    if (ownerJid != null) {
        if (isOracleDB) {
            appendWhere(whereSB, "ofMessageArchive.conversationID in ( ", SELECT_CONVERSATIONS_BY_OWNER, " )");
        } else {
            appendWhere(whereSB, CONVERSATION_OWNER_JID, " = ?");
        }
    }
    if (withJid != null) {
        appendWhere(whereSB, "( ", MESSAGE_TO_JID, " = ? OR ", MESSAGE_FROM_JID, " = ? )");
    }
    if (whereSB.length() != 0) {
        querySB.append(" AND ").append(whereSB);
    }
    if (DbConnectionManager.getDatabaseType() == DbConnectionManager.DatabaseType.sqlserver) {
        querySB.insert(0, "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY " + MESSAGE_SENT_DATE + ") AS RowNum FROM ( ");
        querySB.append(") ofMessageArchive ) t2 WHERE RowNum");
    } else {
        querySB.append(" ORDER BY ").append(MESSAGE_SENT_DATE);
    }
    if (xmppResultSet != null) {
        Integer firstIndex = null;
        int max = xmppResultSet.getMax() != null ? xmppResultSet.getMax() : DEFAULT_MAX;
        int count = countMessages(startDate, endDate, ownerJid, withJid, whereSB.toString());
        boolean reverse = false;
        xmppResultSet.setCount(count);
        if (xmppResultSet.getIndex() != null) {
            firstIndex = xmppResultSet.getIndex();
        } else if (xmppResultSet.getAfter() != null) {
            firstIndex = countMessagesBefore(startDate, endDate, ownerJid, withJid, xmppResultSet.getAfter(), whereSB.toString());
            firstIndex += 1;
        } else if (xmppResultSet.getBefore() != null) {
            int messagesBeforeCount = countMessagesBefore(startDate, endDate, ownerJid, withJid, xmppResultSet.getBefore(), whereSB.toString());
            firstIndex = messagesBeforeCount;
            firstIndex -= max;
            // Reduce result limit to number of results before (if less than a page remaining)
            if (messagesBeforeCount < max) {
                max = messagesBeforeCount;
            }
            reverse = true;
            if (firstIndex < 0) {
                firstIndex = 0;
            }
        }
        firstIndex = firstIndex != null ? firstIndex : 0;
        if (DbConnectionManager.getDatabaseType() == DbConnectionManager.DatabaseType.sqlserver) {
            limitSB.append(" BETWEEN ").append(firstIndex + 1);
            limitSB.append(" AND ").append(firstIndex + max);
        } else if (isOracleDB()) {
            try {
                final Statement statement = DbConnectionManager.getConnection().createStatement();
                final ResultSet resultSet = statement.executeQuery("select VERSION from PRODUCT_COMPONENT_VERSION P where P.PRODUCT like 'Oracle Database%'");
                resultSet.next();
                final String versionString = resultSet.getString("VERSION");
                final String[] versionParts = versionString.split("\\.");
                final int majorVersion = Integer.parseInt(versionParts[0]);
                final int minorVersion = Integer.parseInt(versionParts[1]);
                if ((majorVersion == 12 && minorVersion >= 1) || majorVersion > 12) {
                    limitSB.append(" LIMIT ").append(max);
                    limitSB.append(" OFFSET ").append(firstIndex);
                } else {
                    querySB.insert(0, "SELECT * FROM ( ");
                    limitSB.append(" ) WHERE rownum BETWEEN ").append(firstIndex + 1).append(" AND ").append(firstIndex + max);
                }
            } catch (SQLException e) {
                Log.warn("Unable to determine oracle database version using fallback", e);
                querySB.insert(0, "SELECT * FROM ( ");
                limitSB.append(" ) WHERE rownum BETWEEN ").append(firstIndex + 1).append(" AND ").append(firstIndex + max);
            }
        } else {
            limitSB.append(" LIMIT ").append(max);
            limitSB.append(" OFFSET ").append(firstIndex);
        }
        xmppResultSet.setFirstIndex(firstIndex);
        if (isLastPage(firstIndex, count, max, reverse)) {
            xmppResultSet.setComplete(true);
        }
    }
    querySB.append(limitSB);
    Connection con = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        con = DbConnectionManager.getConnection();
        pstmt = con.prepareStatement(querySB.toString());
        bindMessageParameters(startDate, endDate, ownerJid, withJid, pstmt);
        rs = pstmt.executeQuery();
        Log.debug("findMessages: SELECT_MESSAGES: " + pstmt.toString());
        while (rs.next()) {
            Date time = millisToDate(rs.getLong("sentDate"));
            ArchivedMessage archivedMessage = new ArchivedMessage(time, null, null, null);
            archivedMessage.setId(rs.getLong("messageID"));
            archivedMessage.setStanza(rs.getString("stanza"));
            archivedMessages.put(archivedMessage.getId(), archivedMessage);
        }
    } catch (SQLException sqle) {
        Log.error("Error selecting conversations", sqle);
    } finally {
        DbConnectionManager.closeConnection(rs, pstmt, con);
    }
    if (xmppResultSet != null && archivedMessages.size() > 0) {
        xmppResultSet.setFirst(archivedMessages.firstKey());
        xmppResultSet.setLast(archivedMessages.lastKey());
    }
    return archivedMessages.values();
}
Also used : SQLException(java.sql.SQLException) PreparedStatement(java.sql.PreparedStatement) Statement(java.sql.Statement) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) TreeMap(java.util.TreeMap) Date(java.util.Date) ArchivedMessage(com.reucon.openfire.plugin.archive.model.ArchivedMessage) XmppResultSet(com.reucon.openfire.plugin.archive.xep0059.XmppResultSet) ResultSet(java.sql.ResultSet)

Example 7 with ArchivedMessage

use of com.reucon.openfire.plugin.archive.model.ArchivedMessage in project Openfire by igniterealtime.

the class IQRetrieveHandler method handleIQ.

public IQ handleIQ(IQ packet) throws UnauthorizedException {
    final IQ reply = IQ.createResultIQ(packet);
    final RetrieveRequest retrieveRequest = new RetrieveRequest(packet.getChildElement());
    // inclusive
    int fromIndex;
    // exclusive
    int toIndex;
    int max;
    final Conversation conversation = retrieve(packet.getFrom(), retrieveRequest);
    if (conversation == null) {
        return error(packet, PacketError.Condition.item_not_found);
    }
    final Element chatElement = reply.setChildElement("chat", NAMESPACE);
    chatElement.addAttribute("with", conversation.getWithJid());
    chatElement.addAttribute("start", XmppDateUtil.formatDate(conversation.getStart()));
    max = conversation.getMessages().size();
    fromIndex = 0;
    toIndex = max > 0 ? max : 0;
    final XmppResultSet resultSet = retrieveRequest.getResultSet();
    if (resultSet != null) {
        if (resultSet.getMax() != null && resultSet.getMax() <= max) {
            max = resultSet.getMax();
            toIndex = fromIndex + max;
        }
        if (resultSet.getIndex() != null) {
            fromIndex = resultSet.getIndex();
            toIndex = fromIndex + max;
        } else if (resultSet.getAfter() != null) {
            fromIndex = resultSet.getAfter().intValue() + 1;
            toIndex = fromIndex + max;
        } else if (resultSet.getBefore() != null) {
            if (resultSet.getBefore() != Long.MAX_VALUE)
                toIndex = resultSet.getBefore().intValue();
            else
                toIndex = conversation.getMessages().size();
            fromIndex = toIndex - max;
        }
    }
    fromIndex = fromIndex < 0 ? 0 : fromIndex;
    toIndex = toIndex > conversation.getMessages().size() ? conversation.getMessages().size() : toIndex;
    toIndex = toIndex < fromIndex ? fromIndex : toIndex;
    final List<ArchivedMessage> messages = conversation.getMessages().subList(fromIndex, toIndex);
    for (int i = 0; i < messages.size(); i++) {
        if (i == 0) {
            addMessageElement(chatElement, conversation, messages.get(i), null);
        } else {
            addMessageElement(chatElement, conversation, messages.get(i), messages.get(i - 1));
        }
    }
    if (resultSet != null) {
        if (messages.size() > 0) {
            resultSet.setFirst((long) fromIndex);
            resultSet.setFirstIndex(fromIndex);
            resultSet.setLast((long) toIndex - 1);
        }
        resultSet.setCount(conversation.getMessages().size());
        chatElement.add(resultSet.createResultElement());
    }
    return reply;
}
Also used : ArchivedMessage(com.reucon.openfire.plugin.archive.model.ArchivedMessage) Element(org.dom4j.Element) IQ(org.xmpp.packet.IQ) Conversation(com.reucon.openfire.plugin.archive.model.Conversation) XmppResultSet(com.reucon.openfire.plugin.archive.xep0059.XmppResultSet)

Example 8 with ArchivedMessage

use of com.reucon.openfire.plugin.archive.model.ArchivedMessage in project Openfire by igniterealtime.

the class IQQueryHandler method handleIQ.

public IQ handleIQ(IQ packet) throws UnauthorizedException {
    Session session = sessionManager.getSession(packet.getFrom());
    // If no session was found then answer with an error (if possible)
    if (session == null) {
        Log.error("Error during resource binding. Session not found in " + sessionManager.getPreAuthenticatedKeys() + " for key " + packet.getFrom());
        return buildErrorResponse(packet);
    }
    if (packet.getType().equals(IQ.Type.get)) {
        return buildSupportedFieldsResult(packet, session);
    }
    // Default to user's own archive
    JID archiveJid = packet.getTo();
    if (archiveJid == null) {
        archiveJid = packet.getFrom().asBareJID();
    }
    Log.debug("Archive requested is {}", archiveJid);
    // Now decide the type.
    boolean muc = false;
    if (!XMPPServer.getInstance().isLocal(archiveJid)) {
        Log.debug("Archive is not local (user)");
        if (XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService(archiveJid) == null) {
            Log.debug("No chat service for this domain");
            return buildErrorResponse(packet);
        } else {
            muc = true;
            Log.debug("MUC");
        }
    }
    JID requestor = packet.getFrom().asBareJID();
    Log.debug("Requestor is {} for muc=={}", requestor, muc);
    // Auth checking.
    if (muc) {
        MultiUserChatService service = XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService(archiveJid);
        MUCRoom room = service.getChatRoom(archiveJid.getNode());
        if (room == null) {
            return buildErrorResponse(packet);
        }
        boolean pass = false;
        if (service.isSysadmin(requestor)) {
            pass = true;
        }
        MUCRole.Affiliation aff = room.getAffiliation(requestor);
        if (aff != MUCRole.Affiliation.outcast) {
            if (aff == MUCRole.Affiliation.owner || aff == MUCRole.Affiliation.admin) {
                pass = true;
            } else if (room.isMembersOnly()) {
                if (aff == MUCRole.Affiliation.member) {
                    pass = true;
                }
            } else {
                pass = true;
            }
        }
        if (!pass) {
            return buildForbiddenResponse(packet);
        }
    } else if (!archiveJid.equals(requestor)) {
        // ... disallow unless admin.
        if (!XMPPServer.getInstance().getAdmins().contains(requestor)) {
            return buildForbiddenResponse(packet);
        }
    }
    sendMidQuery(packet, session);
    final QueryRequest queryRequest = new QueryRequest(packet.getChildElement(), archiveJid);
    Collection<ArchivedMessage> archivedMessages = retrieveMessages(queryRequest);
    for (ArchivedMessage archivedMessage : archivedMessages) {
        sendMessageResult(session, queryRequest, archivedMessage);
    }
    sendEndQuery(packet, session, queryRequest);
    return null;
}
Also used : MUCRole(org.jivesoftware.openfire.muc.MUCRole) MUCRoom(org.jivesoftware.openfire.muc.MUCRoom) ArchivedMessage(com.reucon.openfire.plugin.archive.model.ArchivedMessage) MultiUserChatService(org.jivesoftware.openfire.muc.MultiUserChatService) Session(org.jivesoftware.openfire.session.Session)

Example 9 with ArchivedMessage

use of com.reucon.openfire.plugin.archive.model.ArchivedMessage in project Openfire by igniterealtime.

the class IQQueryHandler method sendMessageResult.

/**
	 * Send archived message to requesting client
	 * @param session Client session that send message to
	 * @param queryRequest Query request made by client
	 * @param archivedMessage Message to send to client
	 * @return
	 */
private void sendMessageResult(Session session, QueryRequest queryRequest, ArchivedMessage archivedMessage) {
    String stanzaText = archivedMessage.getStanza();
    if (stanzaText == null || stanzaText.equals("")) {
        // Try creating a fake one from the body.
        if (archivedMessage.getBody() != null && !archivedMessage.getBody().equals("")) {
            stanzaText = String.format("<message from=\"{}\" to=\"{}\" type=\"chat\"><body>{}</body>", archivedMessage.getWithJid(), archivedMessage.getWithJid(), archivedMessage.getBody());
        } else {
            // Don't send legacy archived messages (that have no stanza)
            return;
        }
    }
    Message messagePacket = new Message();
    messagePacket.setTo(session.getAddress());
    Forwarded fwd;
    Document stanza;
    try {
        stanza = DocumentHelper.parseText(stanzaText);
        fwd = new Forwarded(stanza.getRootElement(), archivedMessage.getTime(), null);
    } catch (DocumentException e) {
        Log.error("Failed to parse message stanza.", e);
        // If we can't parse stanza then we have no message to send to client, abort
        return;
    }
    // Shouldn't be possible.
    if (fwd == null)
        return;
    messagePacket.addExtension(new Result(fwd, NAMESPACE, queryRequest.getQueryid(), archivedMessage.getId().toString()));
    session.process(messagePacket);
}
Also used : ArchivedMessage(com.reucon.openfire.plugin.archive.model.ArchivedMessage) Forwarded(org.jivesoftware.openfire.forward.Forwarded)

Aggregations

ArchivedMessage (com.reucon.openfire.plugin.archive.model.ArchivedMessage)9 XmppResultSet (com.reucon.openfire.plugin.archive.xep0059.XmppResultSet)4 Date (java.util.Date)4 Conversation (com.reucon.openfire.plugin.archive.model.Conversation)3 Connection (java.sql.Connection)3 PreparedStatement (java.sql.PreparedStatement)3 ResultSet (java.sql.ResultSet)3 SQLException (java.sql.SQLException)3 JID (org.xmpp.packet.JID)3 MUCRoom (org.jivesoftware.openfire.muc.MUCRoom)2 MultiUserChatService (org.jivesoftware.openfire.muc.MultiUserChatService)2 Direction (com.reucon.openfire.plugin.archive.model.ArchivedMessage.Direction)1 Participant (com.reucon.openfire.plugin.archive.model.Participant)1 Statement (java.sql.Statement)1 LinkedList (java.util.LinkedList)1 TreeMap (java.util.TreeMap)1 Element (org.dom4j.Element)1 XMPPServer (org.jivesoftware.openfire.XMPPServer)1 Forwarded (org.jivesoftware.openfire.forward.Forwarded)1 MUCRole (org.jivesoftware.openfire.muc.MUCRole)1