/*
 * otrinternal.h - Manages the OTR connection
 *
 * Off-the-Record Messaging plugin for Psi
 * Copyright (C) 2007-2011  Timo Engel (timo-e@freenet.de)
 *                    2011  Florian Fieber
 *               2013-2014  Boris Pek (tehnick-8@mail.ru)
 *
 * This program was originally written as part of a diplom thesis
 * advised by Prof. Dr. Ruediger Weis (PST Labor)
 * at the Technical University of Applied Sciences Berlin.
 *
 * 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 OTRINTERNAL_H_
#define OTRINTERNAL_H_

#include "otrmessaging.h"

#include <QHash>
#include <QList>

extern "C" {
// clang-format off
#include <libotr/privkey.h>
#include <libotr/proto.h>
#include <libotr/message.h>
// clang-format on
#ifndef OTRL_PRIVKEY_FPRINT_HUMAN_LEN
#define OTRL_PRIVKEY_FPRINT_HUMAN_LEN 45
#endif
#include "otrlextensions.h"
#include <libotr/instag.h>
}

class QString;

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

/**
 * Handles all libotr calls and callbacks.
 */
class OtrInternal {
public:
    OtrInternal(psiotr::OtrCallback *callback, psiotr::OtrPolicy &policy);

    ~OtrInternal();

    QString encryptMessage(const QString &account, const QString &contact, const QString &message);

    psiotr::OtrMessageType decryptMessage(const QString &account, const QString &contact, const QString &message,
                                          QString &decrypted);

    QList<psiotr::Fingerprint> getFingerprints();

    void verifyFingerprint(const psiotr::Fingerprint &fingerprint, bool verified);

    void deleteFingerprint(const psiotr::Fingerprint &fingerprint);

    QHash<QString, QString> getPrivateKeys();

    void deleteKey(const QString &account);

    void startSession(const QString &account, const QString &contact);

    void endSession(const QString &account, const QString &contact);

    void expireSession(const QString &account, const QString &contact);

    void startSMP(const QString &account, const QString &contact, const QString &question, const QString &secret);

    void continueSMP(const QString &account, const QString &contact, const QString &secret);

    void abortSMP(const QString &account, const QString &contact);
    void abortSMP(ConnContext *context);

    psiotr::OtrMessageState getMessageState(const QString &account, const QString &contact);

    QString getMessageStateString(const QString &account, const QString &contact);

    QString getSessionId(const QString &account, const QString &contact);

    psiotr::Fingerprint getActiveFingerprint(const QString &account, const QString &contact);

    bool isVerified(const QString &account, const QString &contact);
    bool isVerified(ConnContext *context);

    bool smpSucceeded(const QString &account, const QString &contact);

    void generateKey(const QString &account);

    static QString humanFingerprint(const unsigned char *fingerprint);

    /*** otr callback functions ***/
    OtrlPolicy policy(ConnContext *context);
    void       create_privkey(const char *accountname, const char *protocol);
    int        is_logged_in(const char *accountname, const char *protocol, const char *recipient);
    void inject_message(const char *accountname, const char *protocol, const char *recipient, const char *message);
    void update_context_list();
    void new_fingerprint(OtrlUserState us, const char *accountname, const char *protocol, const char *username,
                         unsigned char fingerprint[20]);
    void write_fingerprints();
    void gone_secure(ConnContext *context);
    void gone_insecure(ConnContext *context);
    void still_secure(ConnContext *context, int is_reply);
    void handle_msg_event(OtrlMessageEvent msg_event, ConnContext *context, const char *message, gcry_error_t err);
    void handle_smp_event(OtrlSMPEvent smp_event, ConnContext *context, unsigned short progress_percent,
                          char *question);
    void create_instag(const char *accountname, const char *protocol);

    const char *account_name(const char *account, const char *protocol);
    void        account_name_free(const char *account_name);

    /*** static otr callback wrapper-functions ***/
    static OtrlPolicy cb_policy(void *opdata, ConnContext *context);
    static void       cb_create_privkey(void *opdata, const char *accountname, const char *protocol);
    static int  cb_is_logged_in(void *opdata, const char *accountname, const char *protocol, const char *recipient);
    static void cb_inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient,
                                  const char *message);
    static void cb_update_context_list(void *opdata);
    static void cb_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, const char *protocol,
                                   const char *username, unsigned char fingerprint[20]);
    static void cb_write_fingerprints(void *opdata);
    static void cb_gone_secure(void *opdata, ConnContext *context);
    static void cb_gone_insecure(void *opdata, ConnContext *context);
    static void cb_still_secure(void *opdata, ConnContext *context, int is_reply);
    static void cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event, ConnContext *context, const char *message,
                                    gcry_error_t err);
    static void cb_handle_smp_event(void *opdata, OtrlSMPEvent smp_event, ConnContext *context,
                                    unsigned short progress_percent, char *question);
    static void cb_create_instag(void *opdata, const char *accountname, const char *protocol);

    static const char *cb_account_name(void *opdata, const char *account, const char *protocol);
    static void        cb_account_name_free(void *opdata, const char *account_name);

private:
    /**
     * The userstate contains keys and known fingerprints.
     */
    OtrlUserState m_userstate;

    /**
     * Pointers to callback functions.
     */
    OtrlMessageAppOps m_uiOps;

    /**
     * Pointer to a class for callbacks from OTR to application.
     */
    psiotr::OtrCallback *m_callback;

    /**
     * Name of the file storing dsa-keys.
     */
    QString m_keysFile;

    /**
     * Name of the file storing instance tags.
     */
    QString m_instagsFile;

    /**
     * Name of the file storing known fingerprints.
     */
    QString m_fingerprintFile;

    /**
     * Reference to the default OTR policy
     */
    psiotr::OtrPolicy &m_otrPolicy;

    /**
     * Variable used during generating of private key.
     */
    bool is_generating;
};

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

#endif
