<commit_before>#include "TelegramServerUser.hpp"

#include "ApiUtils.hpp"
#include "ServerApi.hpp"
#include "ServerRpcLayer.hpp"
#include "ServerUtils.hpp"
#include "Session.hpp"
#include "Utils.hpp"

#include <QLoggingCategory>

namespace Telegram {

namespace Server {

TLPeer MessageRecipient::toTLPeer() const
{
    const Peer p = toPeer();
    if (Q_UNLIKELY(!p.isValid())) {
        qCritical() << Q_FUNC_INFO << "Invalid peer" << this;
        return TLPeer();
    }
    TLPeer result;
    switch (p.type) {
    case Peer::User:
        result.tlType = TLValue::PeerUser;
        result.userId = p.id;
        break;
    case Peer::Chat:
        result.tlType = TLValue::PeerChat;
        result.chatId = p.id;
        break;
    case Peer::Channel:
        result.tlType = TLValue::PeerChannel;
        result.channelId = p.id;
        break;
    }
    return result;
}

UserContact AbstractUser::toContact() const
{
    UserContact contact;
    contact.id = id();
    contact.phone = phoneNumber();
    contact.firstName = firstName();
    contact.lastName = lastName();
    return contact;
}

LocalUser::LocalUser(QObject *parent) :
    QObject(parent)
{
}

void LocalUser::setPhoneNumber(const QString &phoneNumber)
{
    m_phoneNumber = phoneNumber;
    m_id = qHash(m_phoneNumber);
}

void LocalUser::setFirstName(const QString &firstName)
{
    m_firstName = firstName;
}

void LocalUser::setLastName(const QString &lastName)
{
    m_lastName = lastName;
}

bool LocalUser::isOnline() const
{
    return true;
}

void LocalUser::setDcId(quint32 id)
{
    m_dcId = id;
}

Session *LocalUser::getSession(quint64 authId) const
{
    for (Session *s : m_sessions) {
        if (s->authId == authId) {
            return s;
        }
    }
    return nullptr;
}

QVector<Session *> LocalUser::activeSessions() const
{
    QVector<Session *> result;
    for (Session *s : m_sessions) {
        if (s->isActive()) {
            result.append(s);
        }
    }
    return result;
}

bool LocalUser::hasActiveSession() const
{
    for (Session *s : m_sessions) {
        if (s->isActive()) {
            return true;
        }
    }
    return false;
}

void LocalUser::addSession(Session *session)
{
    m_sessions.append(session);
    session->setUser(this);
    emit sessionAdded(session);
}

void LocalUser::setPlainPassword(const QString &password)
{
    if (password.isEmpty()) {
        m_passwordSalt.clear();
        m_passwordHash.clear();
        return;
    }
    QByteArray pwdSalt(8, Qt::Uninitialized);
    Telegram::Utils::randomBytes(&pwdSalt);
    const QByteArray pwdData = pwdSalt + password.toUtf8() + pwdSalt;
    const QByteArray pwdHash = Telegram::Utils::sha256(pwdData);
    setPassword(pwdSalt, pwdHash);
}

void LocalUser::setPassword(const QByteArray &salt, const QByteArray &hash)
{
    m_passwordSalt = salt;
    m_passwordHash = hash;
}

quint32 LocalUser::addMessage(const TLMessage &message, Session *excludeSession)
{
    m_messages.append(message);
    m_messages.last().id = addPts();
    const Telegram::Peer messagePeer = Telegram::Utils::getMessagePeer(message, id());
    UserDialog *dialog = ensureDialog(messagePeer);
    dialog->topMessage = message.id;

    // Post update to other sessions
    bool needUpdates = false;
    for (Session *s : activeSessions()) {
        if (s == excludeSession) {
            continue;
        }
        needUpdates = true;
        break;
    }
    if (!needUpdates) {
        return m_messages.last().id;
    }

    ServerApi *api = activeSessions().first()->rpcLayer()->api();
    AbstractUser *sender = api->getAbstractUser(message.fromId);

    TLUpdate newMessageUpdate;
    newMessageUpdate.tlType = TLValue::UpdateNewMessage;
    newMessageUpdate.message = m_messages.last();
    newMessageUpdate.pts = pts();
    newMessageUpdate.ptsCount = 1;

    TLUpdates updates;
    updates.tlType = TLValue::Updates;
    updates.updates = { newMessageUpdate };
    updates.chats = {};

    if (sender) {
        updates.users = { TLUser() }; // Sender
        Utils::setupTLUser(&updates.users[0], sender, this);
    }

    updates.date = message.date;
    //updates.seq = 0;

    for (Session *s : activeSessions()) {
        if (s == excludeSession) {
            continue;
        }
        s->rpcLayer()->sendUpdates(updates);
    }

    return m_messages.last().id;
}

TLVector<TLMessage> LocalUser::getHistory(const Peer &peer,
                                     quint32 offsetId,
                                     quint32 offsetDate,
                                     quint32 addOffset,
                                     quint32 limit,
                                     quint32 maxId,
                                     quint32 minId,
                                     quint32 hash) const
{
    if (offsetId || offsetDate || addOffset || minId || maxId || hash) {
        qWarning() << Q_FUNC_INFO << "Unsupported request";
        return {};
    }<commit_msg>Server: Fix Dialogs update on User::addMessage()<commit_after>#include "TelegramServerUser.hpp"

#include "ApiUtils.hpp"
#include "ServerApi.hpp"
#include "ServerRpcLayer.hpp"
#include "ServerUtils.hpp"
#include "Session.hpp"
#include "Utils.hpp"

#include <QLoggingCategory>

namespace Telegram {

namespace Server {

TLPeer MessageRecipient::toTLPeer() const
{
    const Peer p = toPeer();
    if (Q_UNLIKELY(!p.isValid())) {
        qCritical() << Q_FUNC_INFO << "Invalid peer" << this;
        return TLPeer();
    }
    TLPeer result;
    switch (p.type) {
    case Peer::User:
        result.tlType = TLValue::PeerUser;
        result.userId = p.id;
        break;
    case Peer::Chat:
        result.tlType = TLValue::PeerChat;
        result.chatId = p.id;
        break;
    case Peer::Channel:
        result.tlType = TLValue::PeerChannel;
        result.channelId = p.id;
        break;
    }
    return result;
}

UserContact AbstractUser::toContact() const
{
    UserContact contact;
    contact.id = id();
    contact.phone = phoneNumber();
    contact.firstName = firstName();
    contact.lastName = lastName();
    return contact;
}

LocalUser::LocalUser(QObject *parent) :
    QObject(parent)
{
}

void LocalUser::setPhoneNumber(const QString &phoneNumber)
{
    m_phoneNumber = phoneNumber;
    m_id = qHash(m_phoneNumber);
}

void LocalUser::setFirstName(const QString &firstName)
{
    m_firstName = firstName;
}

void LocalUser::setLastName(const QString &lastName)
{
    m_lastName = lastName;
}

bool LocalUser::isOnline() const
{
    return true;
}

void LocalUser::setDcId(quint32 id)
{
    m_dcId = id;
}

Session *LocalUser::getSession(quint64 authId) const
{
    for (Session *s : m_sessions) {
        if (s->authId == authId) {
            return s;
        }
    }
    return nullptr;
}

QVector<Session *> LocalUser::activeSessions() const
{
    QVector<Session *> result;
    for (Session *s : m_sessions) {
        if (s->isActive()) {
            result.append(s);
        }
    }
    return result;
}

bool LocalUser::hasActiveSession() const
{
    for (Session *s : m_sessions) {
        if (s->isActive()) {
            return true;
        }
    }
    return false;
}

void LocalUser::addSession(Session *session)
{
    m_sessions.append(session);
    session->setUser(this);
    emit sessionAdded(session);
}

void LocalUser::setPlainPassword(const QString &password)
{
    if (password.isEmpty()) {
        m_passwordSalt.clear();
        m_passwordHash.clear();
        return;
    }
    QByteArray pwdSalt(8, Qt::Uninitialized);
    Telegram::Utils::randomBytes(&pwdSalt);
    const QByteArray pwdData = pwdSalt + password.toUtf8() + pwdSalt;
    const QByteArray pwdHash = Telegram::Utils::sha256(pwdData);
    setPassword(pwdSalt, pwdHash);
}

void LocalUser::setPassword(const QByteArray &salt, const QByteArray &hash)
{
    m_passwordSalt = salt;
    m_passwordHash = hash;
}

quint32 LocalUser::addMessage(const TLMessage &message, Session *excludeSession)
{
    m_messages.append(message);
    TLMessage *addedMessage = &m_messages.last();
    addedMessage->id = addPts();
    const Telegram::Peer messagePeer = Telegram::Utils::getMessagePeer(message, id());
    UserDialog *dialog = ensureDialog(messagePeer);
    dialog->topMessage = addedMessage->id;

    // Post update to other sessions
    bool needUpdates = false;
    for (Session *s : activeSessions()) {
        if (s == excludeSession) {
            continue;
        }
        needUpdates = true;
        break;
    }
    if (!needUpdates) {
        return addedMessage->id;
    }

    ServerApi *api = activeSessions().first()->rpcLayer()->api();
    AbstractUser *sender = api->getAbstractUser(message.fromId);

    TLUpdate newMessageUpdate;
    newMessageUpdate.tlType = TLValue::UpdateNewMessage;
    newMessageUpdate.message = *addedMessage;
    newMessageUpdate.pts = pts();
    newMessageUpdate.ptsCount = 1;

    TLUpdates updates;
    updates.tlType = TLValue::Updates;
    updates.updates = { newMessageUpdate };
    updates.chats = {};

    if (sender) {
        updates.users = { TLUser() }; // Sender
        Utils::setupTLUser(&updates.users[0], sender, this);
    }

    updates.date = message.date;
    //updates.seq = 0;

    for (Session *s : activeSessions()) {
        if (s == excludeSession) {
            continue;
        }
        s->rpcLayer()->sendUpdates(updates);
    }

    return addedMessage->id;
}

TLVector<TLMessage> LocalUser::getHistory(const Peer &peer,
                                     quint32 offsetId,
                                     quint32 offsetDate,
                                     quint32 addOffset,
                                     quint32 limit,
                                     quint32 maxId,
                                     quint32 minId,
                                     quint32 hash) const
{
    if (offsetId || offsetDate || addOffset || minId || maxId || hash) {
        qWarning() << Q_FUNC_INFO << "Unsupported request";
        return {};
    }
{'fraction_non_alphanumeric': 0.12111832251622566, 'fraction_numerical': 0.005591612581128308, 'mean_word_length': 2.508231173380035, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '494117', 'n_tokens_mistral': 3165, 'n_tokens_neox': 3085, 'n_words': 638}