/*
 * otrmessaging.h - Interface to libotr
 *
 * Off-the-Record Messaging plugin for Psi
 * Copyright (C) 2007-2011  Timo Engel (timo-e@freenet.de)
 *                    2011  Florian Fieber
 *                    2014  Boris Pek (tehnick-8@mail.ru)
 *
 * 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 2
 * 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 <https://www.gnu.org/licenses/>.
 *
 */

#ifndef OTRMESSAGING_H_
#define OTRMESSAGING_H_

#include <QHash>
#include <QList>
#include <QString>

class OtrInternal;

// ---------------------------------------------------------------------------

namespace psiotr {

// ---------------------------------------------------------------------------

enum OtrPolicy { OTR_POLICY_OFF, OTR_POLICY_ENABLED, OTR_POLICY_AUTO, OTR_POLICY_REQUIRE };

// ---------------------------------------------------------------------------

enum OtrMessageType { OTR_MESSAGETYPE_NONE, OTR_MESSAGETYPE_IGNORE, OTR_MESSAGETYPE_OTR };

// ---------------------------------------------------------------------------

enum OtrMessageState {
    OTR_MESSAGESTATE_UNKNOWN,
    OTR_MESSAGESTATE_PLAINTEXT,
    OTR_MESSAGESTATE_ENCRYPTED,
    OTR_MESSAGESTATE_FINISHED
};

// ---------------------------------------------------------------------------

enum OtrStateChange {
    OTR_STATECHANGE_GOINGSECURE,
    OTR_STATECHANGE_GONESECURE,
    OTR_STATECHANGE_GONEINSECURE,
    OTR_STATECHANGE_STILLSECURE,
    OTR_STATECHANGE_CLOSE,
    OTR_STATECHANGE_REMOTECLOSE,
    OTR_STATECHANGE_TRUST
};

// ---------------------------------------------------------------------------

enum OtrNotifyType { OTR_NOTIFY_INFO, OTR_NOTIFY_WARNING, OTR_NOTIFY_ERROR };

// ---------------------------------------------------------------------------

/**
 * Interface for callbacks from libotr to application
 */
class OtrCallback {
public:
    virtual QString dataDir() = 0;

    /**
     * Sends a message from the Account account to the user contact.
     * The method is called from the OtrConnection to send messages
     * during key-exchange.
     */
    virtual void sendMessage(const QString &account, const QString &contact, const QString &message) = 0;

    virtual bool isLoggedIn(const QString &account, const QString &contact) = 0;

    virtual void notifyUser(const QString &account, const QString &contact, const QString &message,
                            const OtrNotifyType &type)
        = 0;

    virtual bool displayOtrMessage(const QString &account, const QString &contact, const QString &message) = 0;

    virtual void stateChange(const QString &account, const QString &contact, OtrStateChange change) = 0;

    virtual void receivedSMP(const QString &account, const QString &contact, const QString &question) = 0;

    virtual void updateSMP(const QString &account, const QString &contact, int progress) = 0;

    virtual void stopMessages()  = 0;
    virtual void startMessages() = 0;

    virtual QString humanAccount(const QString &accountId)                         = 0;
    virtual QString humanAccountPublic(const QString &accountId)                   = 0;
    virtual QString humanContact(const QString &accountId, const QString &contact) = 0;
};

// ---------------------------------------------------------------------------

/**
 * This struct contains all data shown in the table of 'Known Fingerprints'.
 */
struct Fingerprint {
    /**
     * Pointer to fingerprint in libotr struct. Binary format.
     */
    unsigned char *fingerprint;

    /**
     * own account
     */
    QString account;

    /**
     * owner of the fingerprint
     */
    QString username;

    /**
     * The fingerprint in a human-readable format
     */
    QString fingerprintHuman;

    /**
     * the level of trust
     */
    QString trust;

    Fingerprint();
    Fingerprint(const Fingerprint &fp);
    Fingerprint(unsigned char *fingerprint, const QString &account, const QString &username, const QString &trust);
};

// ---------------------------------------------------------------------------

/**
 * This class is the interface to the Off the Record Messaging library.
 * See the libotr documentation for more information.
 */
class OtrMessaging {
public:
    /**
     * Constructor
     *
     * @param plugin Pointer to the plugin, used for sending messages.
     * @param policy The default OTR policy
     */
    OtrMessaging(OtrCallback *callback, OtrPolicy policy);

    /**
     * Copy constructor
     */
    OtrMessaging(const OtrMessaging &) = delete;

    /**
     * operator=
     */
    OtrMessaging &operator=(const OtrMessaging &) = delete;

    /**
     * Deconstructor
     */
    ~OtrMessaging();

    /**
     * Process an outgoing message.
     *
     * @param account Account the message is send from
     * @param contact Recipient of the message
     * @param message The message itself
     *
     * @return The encrypted message
     */
    QString encryptMessage(const QString &account, const QString &contact, const QString &message);

    /**
     * Decrypt an incoming message.
     *
     * @param account Account the message is send to
     * @param contact Sender of the message
     * @param message The message itself
     * @param decrypted The decrypted message if the original message was
     *                  encrypted
     * @return Type of incoming message
     */
    OtrMessageType decryptMessage(const QString &account, const QString &contact, const QString &message,
                                  QString &decrypted);

    /**
     * Returns a list of known fingerprints.
     */
    QList<Fingerprint> getFingerprints();

    /**
     * Set fingerprint verified/not verified.
     */
    void verifyFingerprint(const Fingerprint &fingerprint, bool verified);

    /**
     * Delete a known fingerprint.
     */
    void deleteFingerprint(const Fingerprint &fingerprint);

    /**
     * Get hash of fingerprints of own private keys.
     * Account -> KeyFingerprint
     */
    QHash<QString, QString> getPrivateKeys();

    /**
     * Delete a private key.
     */
    void deleteKey(const QString &account);

    /**
     * Send an OTR query message from account to contact.
     */
    void startSession(const QString &account, const QString &contact);

    /**
     * Send otr-finished message to user.
     */
    void endSession(const QString &account, const QString &contact);

    /**
     * Force a session to expire.
     */
    void expireSession(const QString &account, const QString &contact);

    /**
     * Start the SMP with an optional question.
     */
    void startSMP(const QString &account, const QString &contact, const QString &question, const QString &secret);

    /**
     * Continue the SMP.
     */
    void continueSMP(const QString &account, const QString &contact, const QString &secret);

    /**
     * Abort the SMP.
     */
    void abortSMP(const QString &account, const QString &contact);

    /**
     * Return the messageState of a context,
     * i.e. plaintext, encrypted, finished.
     */
    OtrMessageState getMessageState(const QString &account, const QString &contact);

    /**
     * Return the messageState as human-readable string.
     */
    QString getMessageStateString(const QString &account, const QString &contact);

    /**
     * Return the secure session id (ssid) for a context.
     */
    QString getSessionId(const QString &account, const QString &contact);

    /**
     * Return the active fingerprint for a context.
     */
    psiotr::Fingerprint getActiveFingerprint(const QString &account, const QString &contact);

    /**
     * Return true if the active fingerprint has been verified.
     */
    bool isVerified(const QString &account, const QString &contact);

    /**
     * Return true if Socialist Millionaires' Protocol succeeded.
     */
    bool smpSucceeded(const QString &account, const QString &contact);

    /**
     * Set the default OTR policy.
     */
    void setPolicy(OtrPolicy policy);

    /**
     * Return the default OTR policy.
     */
    OtrPolicy getPolicy();

    /**
     * Generate own keys.
     * This function blocks until keys are available.
     */
    void generateKey(const QString &account);

    /**
     * Display OTR message.
     */
    bool displayOtrMessage(const QString &account, const QString &contact, const QString &message);

    /**
     * Report a change of state.
     */
    void stateChange(const QString &account, const QString &contact, OtrStateChange change);

    /**
     * Return a human-readable representation
     * of an account identified by accountId.
     */
    QString humanAccount(const QString &accountId);

    /**
     * Return the name of a contact.
     */
    QString humanContact(const QString &accountId, const QString &contact);

private:
    OtrPolicy    m_otrPolicy;
    OtrInternal *m_impl;
    OtrCallback *m_callback;
};

// ---------------------------------------------------------------------------

} // namespace psiotr

#endif
