<commit_before>
#include "connection.h"
#include "room.h"
#include "user.h"
#include "csapi/room_send.h"
#include "csapi/joining.h"
#include "csapi/leaving.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
#include <iostream>
#include <functional>

using namespace QMatrixClient;
using std::cout;
using std::endl;
using namespace std::placeholders;

class QMCTest : public QObject
{
    public:
        QMCTest(Connection* conn, QString targetRoomName, QString source);

    private slots:
        void setupAndRun();
        void onNewRoom(Room* r);
        void run();
        void doTests();
            void loadMembers();
            void sendMessage();
            void addAndRemoveTag();
            void sendAndRedact();
                void checkRedactionOutcome(const QString& evtIdToRedact,
                                   RoomEventsRange events);
            void markDirectChat();
                void checkDirectChatOutcome(
                        const Connection::DirectChatsMap& added);
        void leave();
        void finalize();

    private:
        QScopedPointer<Connection, QScopedPointerDeleteLater> c;
        QStringList running;
        QStringList succeeded;
        QStringList failed;
        QString origin;
        QString targetRoomName;
        Room* targetRoom = nullptr;
};

#define QMC_CHECK(description, condition) \
{ \
    Q_ASSERT(running.removeOne(description)); \
    if (!!(condition)) \
    { \
        succeeded.push_back(description); \
        cout << (description) << " successful" << endl; \
        if (targetRoom) \
            targetRoom->postMessage( \
                origin % ": " % (description) % " successful", \
                MessageEventType::Notice); \
    } else { \
        failed.push_back(description); \
        cout << (description) << " FAILED" << endl; \
        if (targetRoom) \
            targetRoom->postPlainText( \
                origin % ": " % (description) % " FAILED"); \
    } \
}

QMCTest::QMCTest(Connection* conn, QString testRoomName, QString source)
    : c(conn), origin(std::move(source)), targetRoomName(std::move(testRoomName))
{
    if (!origin.isEmpty())
        cout << "Origin for the test message: " << origin.toStdString() << endl;
    if (!targetRoomName.isEmpty())
        cout << "Test room name: " << targetRoomName.toStdString() << endl;

    connect(c.data(), &Connection::connected, this, &QMCTest::setupAndRun);
    connect(c.data(), &Connection::loadedRoomState, this, &QMCTest::onNewRoom);
    // Big countdown watchdog
    QTimer::singleShot(180000, this, &QMCTest::leave);
}

void QMCTest::setupAndRun()
{
    cout << "Connected, server: "
         << c->homeserver().toDisplayString().toStdString() << endl;
    cout << "Access token: " << c->accessToken().toStdString() << endl;

    if (!targetRoomName.isEmpty())
    {
        cout << "Joining " << targetRoomName.toStdString() << endl;
        running.push_back("Join room");
        auto joinJob = c->joinRoom(targetRoomName);
        connect(joinJob, &BaseJob::failure, this,
            [this] { QMC_CHECK("Join room", false); finalize(); });
        // Connection::joinRoom() creates a Room object upon JoinRoomJob::success
        // but this object is empty until the first sync is done.
        connect(joinJob, &BaseJob::success, this, [this,joinJob] {
            targetRoom = c->room(joinJob->roomId(), JoinState::Join);
            QMC_CHECK("Join room", targetRoom != nullptr);

            run();
        });
    } else
        run();
}

void QMCTest::onNewRoom(Room* r)
{
    cout << "New room: " << r->id().toStdString() << endl
         << "  Name: " << r->name().toStdString() << endl
         << "  Canonical alias: " << r->canonicalAlias().toStdString() << endl
         << endl;
    connect(r, &Room::aboutToAddNewMessages, r, [r] (RoomEventsRange timeline) {
        cout << timeline.size() << " new event(s) in room "
             << r->canonicalAlias().toStdString() << endl;
//        for (const auto& item: timeline)
//        {
//            cout << "From: "
//                 << r->roomMembername(item->senderId()).toStdString()
//                 << endl << "Timestamp:"
//                 << item->timestamp().toString().toStdString() << endl
//                 << "JSON:" << endl << item->originalJson().toStdString() << endl;
//        }
    });
}

void QMCTest::run()
{
    c->setLazyLoading(true);
    c->sync();
    connectSingleShot(c.data(), &Connection::syncDone, this, &QMCTest::doTests);
    connect(c.data(), &Connection::syncDone, c.data(), [this] {
        cout << "Sync complete, "
             << running.size() << " tests in the air" << endl;
        if (!running.isEmpty())
            c->sync(10000);
        else if (targetRoom)
        {
            targetRoom->postPlainText(origin % ": All tests finished");
            connect(targetRoom, &Room::messageSent, this, &QMCTest::leave);
        }
        else
            finalize();
    });
}

void QMCTest::doTests()
{
    cout << "Starting tests" << endl;

    loadMembers();
    // Add here tests not requiring the test room
    if (targetRoomName.isEmpty())
        return;

    sendMessage();
    addAndRemoveTag();
    sendAndRedact();
    markDirectChat();
    // Add here tests with the test room
}

void QMCTest::loadMembers()
{
    running.push_back("Loading members");
    // The dedicated qmc-test room is too small to test
    // lazy-loading-then-full-loading; use #qmatrixclient:matrix.org instead.
    // TODO: #264
    auto* r = c->room(QStringLiteral("!PCzUtxtOjUySxSelof:matrix.org"));
    if (!r)
    {
        cout << "#test:matrix.org is not found in the test user's rooms" << endl;
        QMC_CHECK("Loading members", false);
        return;
    }
    // It's not exactly correct because an arbitrary server might not support
    // lazy loading; but in the absence of capabilities framework we assume
    // it does.
    if (r->memberNames().size() >= r->joinedCount())
    {
        cout << "Lazy loading doesn't seem to be enabled" << endl;
        QMC_CHECK("Loading members", false);
        return;
    }
    r->setDisplayed();
    connect(r, &Room::allMembersLoaded, [this,r] {
        QMC_CHECK("Loading members",
                  r->memberNames().size() >= r->joinedCount());
    });
}

void QMCTest::sendMessage()
{
    running.push_back("Message sending");
    cout << "Sending a message" << endl;
    auto txnId = targetRoom->postPlainText("Hello, " % origin % " is here");
    auto& pending = targetRoom->pendingEvents();
    if (pending.empty())
    {
        QMC_CHECK("Message sending", false);
        return;
    }
    auto it = std::find_if(pending.begin(), pending.end(),
                [&txnId] (const auto& e) {
                    return e->transactionId() == txnId;
                });
    QMC_CHECK("Message sending", it != pending.end());
    // TODO: Wait when it actually gets sent; check that it obtained an id
    // Independently, check when it shows up in the timeline.
}

void QMCTest::addAndRemoveTag()
{
    running.push_back("Tagging test");
    static const auto TestTag = QStringLiteral("org.qmatrixclient.test");
    // Pre-requisite
    if (targetRoom->tags().contains(TestTag))
        targetRoom->removeTag(TestTag);

    // Connect first because the signal is emitted synchronously.
    connect(targetRoom, &Room::tagsChanged, targetRoom, [=] {
        cout << "Room " << targetRoom->id().toStdString()
             << ", tag(s) changed:" << endl
             << "  " << targetRoom->tagNames().join(", ").toStdString() << endl;
        if (targetRoom->tags().contains(TestTag))
        {
            cout << "Test tag set, removing it now" << endl;
            targetRoom->removeTag(TestTag);
            QMC_CHECK("Tagging test", !targetRoom->tags().contains(TestTag));
            QObject::disconnect(targetRoom, &Room::tagsChanged, nullptr, nullptr);
        }
    });
    cout << "Adding a tag" << endl;
    targetRoom->addTag(TestTag);
}

void QMCTest::sendAndRedact()
{
    running.push_back("Redaction");
    cout << "Sending a message to redact" << endl;
    if (auto* job = targetRoom->connection()->sendMessage(targetRoom->id(),
            RoomMessageEvent(origin % ": message to redact")))
    {
        connect(job, &BaseJob::success, targetRoom, [job,this] {
            cout << "Redacting the message" << endl;
            targetRoom->redactEvent(job->eventId(), origin);
            // Make sure to save the event id because the job is about to end.
            connect(targetRoom, &Room::aboutToAddNewMessages, this,
                    std::bind(&QMCTest::checkRedactionOutcome,
                              this, job->eventId(), _1));
        });
    } else
        QMC_CHECK("Redaction", false);
}

void QMCTest::checkRedactionOutcome(const QString& evtIdToRedact,
                                    RoomEventsRange events)
{
    static bool checkSucceeded = false;
    // There are two possible (correct) outcomes: either the event comes already
    // redacted at the next sync, or the nearest sync completes with
    // the unredacted event but the next one brings redaction.
    auto it = std::find_if(events.begin(), events.end(),
                [=] (const RoomEventPtr& e) {
                    return e->id() == evtIdToRedact;
                });
    if (it == events.end())
        return; // Waiting for the next sync

    if ((*it)->isRedacted())
    {
        if (checkSucceeded)
        {
            const auto msg =
                    "The redacted event came in with the sync again, ignoring";
            cout << msg << endl;
            targetRoom->postPlainText(msg);
            return;
        }
        cout << "The sync brought already redacted message" << endl;
        QMC_CHECK("Redaction", true);
        // Not disconnecting because there are other connections from this class
        // to aboutToAddNewMessages
        checkSucceeded = true;
        return;
    }
    // The event is not redacted
    if (checkSucceeded)
    {
        const auto msg =
                "Warning: the redacted event came non-redacted with the sync!";
        cout << msg << endl;
        targetRoom->postPlainText(msg);
    }
    cout << "Message came non-redacted with the sync, waiting for redaction" << endl;
    connect(targetRoom, &Room::replacedEvent, targetRoom,
        [=] (const RoomEvent* newEvent, const RoomEvent* oldEvent) {
            QMC_CHECK("Redaction", oldEvent->id() == evtIdToRedact &&
                      newEvent->isRedacted() &&
                      newEvent->redactionReason() == origin);
            checkSucceeded = true;
            disconnect(targetRoom, &Room::replacedEvent, nullptr, nullptr);
        });

}

void QMCTest::markDirectChat()
{
    if (targetRoom->directChatUsers().contains(c->user()))
    {
        cout << "Warning: the room is already a direct chat,"
                " only unmarking will be tested" << endl;
        checkDirectChatOutcome({{ c->user(), targetRoom->id() }});
        return;
    }
    // Connect first because the signal is emitted synchronously.
    connect(c.data(), &Connection::directChatsListChanged,
            this, &QMCTest::checkDirectChatOutcome);
    cout << "Marking the room as a direct chat" << endl;
    c->addToDirectChats(targetRoom, c->user());
}

void QMCTest::checkDirectChatOutcome(const Connection::DirectChatsMap& added)
{
    running.push_back("Direct chat test");
    disconnect(c.data(), &Connection::directChatsListChanged, nullptr, nullptr);
    if (!targetRoom->isDirectChat())
    {
        cout << "The room has not been marked as a direct chat" << endl;
        QMC_CHECK("Direct chat test", false);
        return;
    }
    if (!added.contains(c->user(), targetRoom->id()))
    {
        cout << "The room has not been listed in new direct chats" << endl;
        QMC_CHECK("Direct chat test", false);
        return;
    }

    cout << "Unmarking the direct chat" << endl;
    c->removeFromDirectChats(targetRoom->id(), c->user());
    QMC_CHECK("Direct chat test", !c->isDirectChat(targetRoom->id()));
}

void QMCTest::leave()
{
    if (targetRoom)
    {
        cout << "Leaving the room" << endl;
        connect(targetRoom->leaveRoom(), &BaseJob::finished,
                this, &QMCTest::finalize);
    }
    else
        finalize();
}

void QMCTest::finalize()
{
    cout << "Logging out" << endl;
    c->logout();
    connect(c.data(), &Connection::loggedOut, qApp,
        [this] {
            if (!failed.isEmpty())
                cout << "FAILED: " << failed.join(", ").toStdString() << endl;
            if (!running.isEmpty())
                cout << "DID NOT FINISH: "
                     << running.join(", ").toStdString() << endl;
            QCoreApplication::processEvents();
            QCoreApplication::exit(failed.size() + running.size());
        });
}

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);
    if (argc < 4)
    {
        cout << "Usage: qmc-example <user> <passwd> <device_name> [<room_alias> [origin]]" << endl;
        return -1;
    }

    cout << "Connecting to the server as " << argv[1] << endl;
    auto conn = new Connection;
    conn->connectToServer(argv[1], argv[2], argv[3]);
    QMCTest test { conn, argc >= 5 ? argv[4] : nullptr,
                         argc >= 6 ? argv[5] : nullptr };
    return app.exec();
}
<commit_msg>qmc-example: check Room::messageSent() more carefully<commit_after>
#include "connection.h"
#include "room.h"
#include "user.h"
#include "csapi/room_send.h"
#include "csapi/joining.h"
#include "csapi/leaving.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
#include <iostream>
#include <functional>

using namespace QMatrixClient;
using std::cout;
using std::endl;
using namespace std::placeholders;

class QMCTest : public QObject
{
    public:
        QMCTest(Connection* conn, QString targetRoomName, QString source);

    private slots:
        void setupAndRun();
        void onNewRoom(Room* r);
        void run();
        void doTests();
            void loadMembers();
            void sendMessage();
            void addAndRemoveTag();
            void sendAndRedact();
                void checkRedactionOutcome(const QString& evtIdToRedact,
                                   RoomEventsRange events);
            void markDirectChat();
                void checkDirectChatOutcome(
                        const Connection::DirectChatsMap& added);
        void leave();
        void finalize();

    private:
        QScopedPointer<Connection, QScopedPointerDeleteLater> c;
        QStringList running;
        QStringList succeeded;
        QStringList failed;
        QString origin;
        QString targetRoomName;
        Room* targetRoom = nullptr;
};

#define QMC_CHECK(description, condition) \
{ \
    Q_ASSERT(running.removeOne(description)); \
    if (!!(condition)) \
    { \
        succeeded.push_back(description); \
        cout << (description) << " successful" << endl; \
        if (targetRoom) \
            targetRoom->postMessage( \
                origin % ": " % (description) % " successful", \
                MessageEventType::Notice); \
    } else { \
        failed.push_back(description); \
        cout << (description) << " FAILED" << endl; \
        if (targetRoom) \
            targetRoom->postPlainText( \
                origin % ": " % (description) % " FAILED"); \
    } \
}

QMCTest::QMCTest(Connection* conn, QString testRoomName, QString source)
    : c(conn), origin(std::move(source)), targetRoomName(std::move(testRoomName))
{
    if (!origin.isEmpty())
        cout << "Origin for the test message: " << origin.toStdString() << endl;
    if (!targetRoomName.isEmpty())
        cout << "Test room name: " << targetRoomName.toStdString() << endl;

    connect(c.data(), &Connection::connected, this, &QMCTest::setupAndRun);
    connect(c.data(), &Connection::loadedRoomState, this, &QMCTest::onNewRoom);
    // Big countdown watchdog
    QTimer::singleShot(180000, this, &QMCTest::leave);
}

void QMCTest::setupAndRun()
{
    cout << "Connected, server: "
         << c->homeserver().toDisplayString().toStdString() << endl;
    cout << "Access token: " << c->accessToken().toStdString() << endl;

    if (!targetRoomName.isEmpty())
    {
        cout << "Joining " << targetRoomName.toStdString() << endl;
        running.push_back("Join room");
        auto joinJob = c->joinRoom(targetRoomName);
        connect(joinJob, &BaseJob::failure, this,
            [this] { QMC_CHECK("Join room", false); finalize(); });
        // Connection::joinRoom() creates a Room object upon JoinRoomJob::success
        // but this object is empty until the first sync is done.
        connect(joinJob, &BaseJob::success, this, [this,joinJob] {
            targetRoom = c->room(joinJob->roomId(), JoinState::Join);
            QMC_CHECK("Join room", targetRoom != nullptr);

            run();
        });
    } else
        run();
}

void QMCTest::onNewRoom(Room* r)
{
    cout << "New room: " << r->id().toStdString() << endl
         << "  Name: " << r->name().toStdString() << endl
         << "  Canonical alias: " << r->canonicalAlias().toStdString() << endl
         << endl;
    connect(r, &Room::aboutToAddNewMessages, r, [r] (RoomEventsRange timeline) {
        cout << timeline.size() << " new event(s) in room "
             << r->canonicalAlias().toStdString() << endl;
//        for (const auto& item: timeline)
//        {
//            cout << "From: "
//                 << r->roomMembername(item->senderId()).toStdString()
//                 << endl << "Timestamp:"
//                 << item->timestamp().toString().toStdString() << endl
//                 << "JSON:" << endl << item->originalJson().toStdString() << endl;
//        }
    });
}

void QMCTest::run()
{
    c->setLazyLoading(true);
    c->sync();
    connectSingleShot(c.data(), &Connection::syncDone, this, &QMCTest::doTests);
    connect(c.data(), &Connection::syncDone, c.data(), [this] {
        cout << "Sync complete, "
             << running.size() << " tests in the air" << endl;
        if (!running.isEmpty())
            c->sync(10000);
        else if (targetRoom)
        {
            // TODO: Waiting for proper futures to come so that it could be:
//            targetRoom->postPlainText(origin % ": All tests finished")
//            .then(this, &QMCTest::leave);
            auto txnId =
                    targetRoom->postPlainText(origin % ": All tests finished");
            connect(targetRoom, &Room::messageSent, this,
                    [this,txnId] (QString serverTxnId) {
                if (txnId == serverTxnId)
                    leave();
            });
        }
        else
            finalize();
    });
}

void QMCTest::doTests()
{
    cout << "Starting tests" << endl;

    loadMembers();
    // Add here tests not requiring the test room
    if (targetRoomName.isEmpty())
        return;

    sendMessage();
    addAndRemoveTag();
    sendAndRedact();
    markDirectChat();
    // Add here tests with the test room
}

void QMCTest::loadMembers()
{
    running.push_back("Loading members");
    // The dedicated qmc-test room is too small to test
    // lazy-loading-then-full-loading; use #qmatrixclient:matrix.org instead.
    // TODO: #264
    auto* r = c->room(QStringLiteral("!PCzUtxtOjUySxSelof:matrix.org"));
    if (!r)
    {
        cout << "#test:matrix.org is not found in the test user's rooms" << endl;
        QMC_CHECK("Loading members", false);
        return;
    }
    // It's not exactly correct because an arbitrary server might not support
    // lazy loading; but in the absence of capabilities framework we assume
    // it does.
    if (r->memberNames().size() >= r->joinedCount())
    {
        cout << "Lazy loading doesn't seem to be enabled" << endl;
        QMC_CHECK("Loading members", false);
        return;
    }
    r->setDisplayed();
    connect(r, &Room::allMembersLoaded, [this,r] {
        QMC_CHECK("Loading members",
                  r->memberNames().size() >= r->joinedCount());
    });
}

void QMCTest::sendMessage()
{
    running.push_back("Message sending");
    cout << "Sending a message" << endl;
    auto txnId = targetRoom->postPlainText("Hello, " % origin % " is here");
    auto& pending = targetRoom->pendingEvents();
    if (pending.empty())
    {
        QMC_CHECK("Message sending", false);
        return;
    }
    auto it = std::find_if(pending.begin(), pending.end(),
                [&txnId] (const auto& e) {
                    return e->transactionId() == txnId;
                });
    QMC_CHECK("Message sending", it != pending.end());
    // TODO: Wait when it actually gets sent; check that it obtained an id
    // Independently, check when it shows up in the timeline.
}

void QMCTest::addAndRemoveTag()
{
    running.push_back("Tagging test");
    static const auto TestTag = QStringLiteral("org.qmatrixclient.test");
    // Pre-requisite
    if (targetRoom->tags().contains(TestTag))
        targetRoom->removeTag(TestTag);

    // Connect first because the signal is emitted synchronously.
    connect(targetRoom, &Room::tagsChanged, targetRoom, [=] {
        cout << "Room " << targetRoom->id().toStdString()
             << ", tag(s) changed:" << endl
             << "  " << targetRoom->tagNames().join(", ").toStdString() << endl;
        if (targetRoom->tags().contains(TestTag))
        {
            cout << "Test tag set, removing it now" << endl;
            targetRoom->removeTag(TestTag);
            QMC_CHECK("Tagging test", !targetRoom->tags().contains(TestTag));
            QObject::disconnect(targetRoom, &Room::tagsChanged, nullptr, nullptr);
        }
    });
    cout << "Adding a tag" << endl;
    targetRoom->addTag(TestTag);
}

void QMCTest::sendAndRedact()
{
    running.push_back("Redaction");
    cout << "Sending a message to redact" << endl;
    if (auto* job = targetRoom->connection()->sendMessage(targetRoom->id(),
            RoomMessageEvent(origin % ": message to redact")))
    {
        connect(job, &BaseJob::success, targetRoom, [job,this] {
            cout << "Redacting the message" << endl;
            targetRoom->redactEvent(job->eventId(), origin);
            // Make sure to save the event id because the job is about to end.
            connect(targetRoom, &Room::aboutToAddNewMessages, this,
                    std::bind(&QMCTest::checkRedactionOutcome,
                              this, job->eventId(), _1));
        });
    } else
        QMC_CHECK("Redaction", false);
}

void QMCTest::checkRedactionOutcome(const QString& evtIdToRedact,
                                    RoomEventsRange events)
{
    static bool checkSucceeded = false;
    // There are two possible (correct) outcomes: either the event comes already
    // redacted at the next sync, or the nearest sync completes with
    // the unredacted event but the next one brings redaction.
    auto it = std::find_if(events.begin(), events.end(),
                [=] (const RoomEventPtr& e) {
                    return e->id() == evtIdToRedact;
                });
    if (it == events.end())
        return; // Waiting for the next sync

    if ((*it)->isRedacted())
    {
        if (checkSucceeded)
        {
            const auto msg =
                    "The redacted event came in with the sync again, ignoring";
            cout << msg << endl;
            targetRoom->postPlainText(msg);
            return;
        }
        cout << "The sync brought already redacted message" << endl;
        QMC_CHECK("Redaction", true);
        // Not disconnecting because there are other connections from this class
        // to aboutToAddNewMessages
        checkSucceeded = true;
        return;
    }
    // The event is not redacted
    if (checkSucceeded)
    {
        const auto msg =
                "Warning: the redacted event came non-redacted with the sync!";
        cout << msg << endl;
        targetRoom->postPlainText(msg);
    }
    cout << "Message came non-redacted with the sync, waiting for redaction" << endl;
    connect(targetRoom, &Room::replacedEvent, targetRoom,
        [=] (const RoomEvent* newEvent, const RoomEvent* oldEvent) {
            QMC_CHECK("Redaction", oldEvent->id() == evtIdToRedact &&
                      newEvent->isRedacted() &&
                      newEvent->redactionReason() == origin);
            checkSucceeded = true;
            disconnect(targetRoom, &Room::replacedEvent, nullptr, nullptr);
        });

}

void QMCTest::markDirectChat()
{
    if (targetRoom->directChatUsers().contains(c->user()))
    {
        cout << "Warning: the room is already a direct chat,"
                " only unmarking will be tested" << endl;
        checkDirectChatOutcome({{ c->user(), targetRoom->id() }});
        return;
    }
    // Connect first because the signal is emitted synchronously.
    connect(c.data(), &Connection::directChatsListChanged,
            this, &QMCTest::checkDirectChatOutcome);
    cout << "Marking the room as a direct chat" << endl;
    c->addToDirectChats(targetRoom, c->user());
}

void QMCTest::checkDirectChatOutcome(const Connection::DirectChatsMap& added)
{
    running.push_back("Direct chat test");
    disconnect(c.data(), &Connection::directChatsListChanged, nullptr, nullptr);
    if (!targetRoom->isDirectChat())
    {
        cout << "The room has not been marked as a direct chat" << endl;
        QMC_CHECK("Direct chat test", false);
        return;
    }
    if (!added.contains(c->user(), targetRoom->id()))
    {
        cout << "The room has not been listed in new direct chats" << endl;
        QMC_CHECK("Direct chat test", false);
        return;
    }

    cout << "Unmarking the direct chat" << endl;
    c->removeFromDirectChats(targetRoom->id(), c->user());
    QMC_CHECK("Direct chat test", !c->isDirectChat(targetRoom->id()));
}

void QMCTest::leave()
{
    if (targetRoom)
    {
        cout << "Leaving the room" << endl;
        connect(targetRoom->leaveRoom(), &BaseJob::finished,
                this, &QMCTest::finalize);
    }
    else
        finalize();
}

void QMCTest::finalize()
{
    cout << "Logging out" << endl;
    c->logout();
    connect(c.data(), &Connection::loggedOut, qApp,
        [this] {
            if (!failed.isEmpty())
                cout << "FAILED: " << failed.join(", ").toStdString() << endl;
            if (!running.isEmpty())
                cout << "DID NOT FINISH: "
                     << running.join(", ").toStdString() << endl;
            QCoreApplication::processEvents();
            QCoreApplication::exit(failed.size() + running.size());
        });
}

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);
    if (argc < 4)
    {
        cout << "Usage: qmc-example <user> <passwd> <device_name> [<room_alias> [origin]]" << endl;
        return -1;
    }

    cout << "Connecting to the server as " << argv[1] << endl;
    auto conn = new Connection;
    conn->connectToServer(argv[1], argv[2], argv[3]);
    QMCTest test { conn, argc >= 5 ? argv[4] : nullptr,
                         argc >= 6 ? argv[5] : nullptr };
    return app.exec();
}
<|endoftext|>


<commit_before>// Microsoft
#include <Windows.h>		// Required for XInput.h
#include <Xinput.h>			// obvious

// Standard
#include <limits>			// for min(), max(), SHRT_MAX

// Other crap
#include <SADXModLoader.h>
#include "typedefs.h"		// includes cstdint as used by _ControllerData

// This namespace
#include "UpdateControllersXInput.h"

// TODO: Figure out how to determine if a player is AI controlled or not, then enable per-controller rumble.

// From the SA2 Mod Loader
// Using this until it or PDS_PERIPHERAL gets implemented into the SADX Mod Loader.
// Aside from having all of its members named, it's otherwise exactly the same.
struct _ControllerData
{
	uint32_t ID;
	uint32_t Support;
	uint32_t HeldButtons;
	uint32_t NotHeldButtons;
	uint32_t PressedButtons;
	uint32_t ReleasedButtons;
	uint16_t RTriggerPressure;
	uint16_t LTriggerPressure;
	int16_t LeftStickX;
	int16_t LeftStickY;
	int16_t RightStickX;
	int16_t RightStickY;
	char* Name;
	void* Extend;
	uint32_t Old;
	void* Info;
};

DataArray(_ControllerData, Controller_Data_0, 0x03B0E9C8, 8);	// Yes, there are in fact *8* controller structures in SADX PC.
DataPointer(int, isCutscenePlaying, 0x3B2A2E4);					// Fun fact: Freeze at 0 to avoid cutscenes. 4 bytes from here is the cutscene to play.
DataPointer(char, rumbleEnabled, 0x00913B10);					// Not sure why this is a char and ^ is an int.

#define clamp(value, low, high) min(max(low, value), high)

namespace xinput
{
	namespace deadzone
	{
		short stickL[4] = {
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE
		};

		short stickR[4] = {
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE
		};

		short triggers[4] = {
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD
		};
	}

	const uint rumble_l_timer = 250;
	const uint rumble_r_timer = 1000;

	XINPUT_VIBRATION vibration[4];
	Motor rumble[4];
	uint rumble_l_elapsed[4];
	uint rumble_r_elapsed[4];

	bool multi_gate = false;
	float rumble_multi = 255.0;

	// TODO: Keyboard & Mouse
	void __cdecl UpdateControllersXInput()
	{
		for (uint8 i = 0; i < 4; i++)
		{
			_ControllerData* pad = &Controller_Data_0[i];
			XINPUT_STATE state = {};
			XInputGetState(i, &state);
			XINPUT_GAMEPAD* xpad = &state.Gamepad;

			// Gotta get that enum set up for this.
			pad->Support = 0x3F07FEu;

			// L Analog
			pad->LeftStickX = GetWithinDeadzone(xpad->sThumbLX, deadzone::stickL[i]);
			pad->LeftStickY = GetWithinDeadzone(-xpad->sThumbLY, deadzone::stickL[i]);

			// R Analog
			pad->RightStickX = GetWithinDeadzone(xpad->sThumbRX, deadzone::stickR[i]);
			pad->RightStickY = GetWithinDeadzone(-xpad->sThumbRY, deadzone::stickR[i]);

			// Trigger pressure
			pad->LTriggerPressure = xpad->bLeftTrigger;
			pad->RTriggerPressure = xpad->bRightTrigger;

			// Now, get the new buttons from the XInput xpad
			pad->HeldButtons = XInputToDreamcast(xpad, i);
			pad->NotHeldButtons = ~pad->HeldButtons;

			// Now set the released buttons to the difference between
			// the last and currently held buttons
			pad->ReleasedButtons = pad->HeldButtons ^ pad->Old;

			// Do some fancy math to "press" only the necessary buttons
			pad->PressedButtons = pad->HeldButtons;
			pad->PressedButtons &= ~pad->Old;

			// Set the "last held" to held
			pad->Old = pad->HeldButtons;

			// Disable rumble if the timer says it's a good idea.
			if (rumble[i] != Motor::None)
			{
				Motor result = Motor::None;
				uint64 now = GetTickCount();

				if ((now - rumble_l_elapsed[i]) >= rumble_l_timer)
				{
					result = (Motor)(result | Motor::Left);
					rumble[i] = (Motor)(rumble[i] & ~Motor::Left);
				}
				if ((now - rumble_r_elapsed[i]) >= rumble_r_timer)
				{
					result = (Motor)(result | Motor::Right);
					rumble[i] = (Motor)(rumble[i] & ~Motor::Right);
				}

				if (result != Motor::None)
					Rumble(i, 0, result);
			}

#ifdef _DEBUG
			if (xpad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)
			{
				DisplayDebugStringFormatted(8 + (3 * i), "P%d  B: %08X LT/RT: %03d/%03d V: %d%d", (i + 1),
					pad->HeldButtons, pad->LTriggerPressure, pad->RTriggerPressure, (rumble[i] & Motor::Left), ((rumble[i] & Motor::Right) >> 1));
				DisplayDebugStringFormatted(9 + (3 * i), "   LS: %04d/%04d RS: %04d/%04d",
					pad->LeftStickX, pad->LeftStickY, pad->RightStickX, pad->RightStickY);

				if (i == 0 && xpad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
				{
					if (xpad->wButtons & XINPUT_GAMEPAD_DPAD_UP)
					{
						if (multi_gate == false)
							rumble_multi += 8.0;

						multi_gate = true;
					}
					else if (xpad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
					{
						if (multi_gate == false)
							rumble_multi -= 8.0;

						multi_gate = true;
					}
					else
					{
						multi_gate = false;
					}

					DisplayDebugStringFormatted(6, "Rumble multiplier (U/D): %f", rumble_multi);
				}
			}
#endif
		}
	}

	inline void SetMotor(short id, Motor motor, short intensity)
	{
		if (motor & Motor::Left)
		{
			vibration[id].wLeftMotorSpeed = intensity;
			rumble_l_elapsed[id] = GetTickCount();
		}
		if (motor & Motor::Right)
		{
			// This is doubled because it's never strong enough.
			vibration[id].wRightMotorSpeed = intensity * 2;
			rumble_r_elapsed[id] = GetTickCount();
		}
	}
	void Rumble(short id, int a1, Motor motor)
	{
		short intensity = 4 * a1;

		bool isWithinRange = (id >= 0 && id < 4);
		Motor resultMotor = (isWithinRange) ? rumble[id] : Motor::None;

		if (a1 > 0)
		{
			float m = 0;

			// RumbleLarge only ever passes in a value in that is <= 10,
			// and scaling that to 2 bytes is super annoying, so here's
			// some arbitrary values to increase the intensity.
			if (a1 >= 1 && a1 <= 10)
				m = max(0.2375f, intensity / 25.0f);
			else
				m = intensity / rumble_multi;

			intensity = (short)(SHRT_MAX * max(0.0, min(1.0f, m)));

			resultMotor = (Motor)(resultMotor | motor);
		}

		// TODO: Check if the player ID is currently AI controlled (or if intensity is 0).
		// This will avoid vibrating the second controller when Tails does something stupid.
		if (isWithinRange)
		{
			SetMotor(id, motor, intensity);
			rumble[id] = (Motor)(rumble[id] | resultMotor);
			XInputSetState(id, &vibration[id]);
		}
		else
		{
			for (uint8 i = 0; i < 4; i++)
			{
				SetMotor(i, motor, intensity);
				rumble[i] = (Motor)(rumble[i] | resultMotor);
				XInputSetState(i, &vibration[i]);
			}
		}
	}

	void __cdecl RumbleLarge(int playerNumber, signed int intensity)
	{
		if (!isCutscenePlaying && rumbleEnabled)
		{
			// Only continue if the calling player is Player 1 (0)
			// Vanilla SADX only rumbles for P1.
			if (!playerNumber)
				Rumble(playerNumber, clamp(intensity, 1, 255), Motor::Left);
		}
	}
	void __cdecl RumbleSmall(int playerNumber, signed int a2, signed int a3, int a4)
	{
		if (!isCutscenePlaying && rumbleEnabled)
		{
			// Only continue if the calling player is Player 1 (0)
			// Vanilla SADX only rumbles for P1.
			if (!playerNumber)
			{
				int _a2 = clamp(a2, -4, 4);

				// Could be inline if'd, but it'd look borderline unreadable.
				if (_a2 == 1)
					_a2 = 2;
				else if (_a2 == -1)
					_a2 = -2;

				int _a3 = clamp(a3, 7, 59);

				Rumble(playerNumber, max(1, a4 * _a3 / (4 * _a2)), Motor::Right);
			}
		}
	}

	// If analog exceeds deadzone, return SADX-friendly
	// version of the value; else 0.
	short GetWithinDeadzone(int analog, short deadzone)
	{
		// tl;dr: if analog exceeds the deadzone, convert to SADX-friendly
		// value, then make sure it's not < -127 or > 127 and return it; else 0.
		if (analog < -deadzone || analog > deadzone)
			return clamp((analog / 256), -127, 127);
		else
			return 0;
	}
	void SetDeadzone(short* array, uint id, int value)
	{
		if (value >= 0)
			array[id] = min(SHRT_MAX, value);
	}

	// Converts wButtons in XINPUT_GAMEPAD to Sonic Adventure compatible buttons and returns the value.
	int XInputToDreamcast(XINPUT_GAMEPAD* xpad, ushort id)
	{
		int result = 0;
		int buttons = xpad->wButtons;

		if (buttons & XINPUT_GAMEPAD_A)
			result |= Buttons_A;
		if (buttons & XINPUT_GAMEPAD_B)
			result |= Buttons_B;
		if (buttons & XINPUT_GAMEPAD_X)
			result |= Buttons_X;
		if (buttons & XINPUT_GAMEPAD_Y)
			result |= Buttons_Y;
		if (buttons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
			result |= Buttons_Z;

		if (xpad->bLeftTrigger > deadzone::triggers[id])
			result |= Buttons_L;
		if (xpad->bRightTrigger > deadzone::triggers[id])
			result |= Buttons_R;

		if (buttons & XINPUT_GAMEPAD_START)
			result |= Buttons_Start;

		if (buttons & XINPUT_GAMEPAD_DPAD_UP)
			result |= Buttons_Up;
		if (buttons & XINPUT_GAMEPAD_DPAD_DOWN)
			result |= Buttons_Down;
		if (buttons & XINPUT_GAMEPAD_DPAD_LEFT)
			result |= Buttons_Left;
		if (buttons & XINPUT_GAMEPAD_DPAD_RIGHT)
			result |= Buttons_Right;

		return result;
	}
}<commit_msg>Minor cleanup.<commit_after>// Microsoft
#include <Windows.h>		// Required for XInput.h
#include <Xinput.h>			// obvious

// Standard
#include <limits>			// for min(), max(), SHRT_MAX

// Other crap
#include <SADXModLoader.h>
#include "typedefs.h"		// includes cstdint as used by _ControllerData

// This namespace
#include "UpdateControllersXInput.h"

// TODO: Figure out how to determine if a player is AI controlled or not, then enable per-controller rumble.

// From the SA2 Mod Loader
// Using this until it or PDS_PERIPHERAL gets implemented into the SADX Mod Loader.
// Aside from having all of its members named, it's otherwise exactly the same.
struct _ControllerData
{
	uint32_t ID;
	uint32_t Support;
	uint32_t HeldButtons;
	uint32_t NotHeldButtons;
	uint32_t PressedButtons;
	uint32_t ReleasedButtons;
	uint16_t RTriggerPressure;
	uint16_t LTriggerPressure;
	int16_t LeftStickX;
	int16_t LeftStickY;
	int16_t RightStickX;
	int16_t RightStickY;
	char* Name;
	void* Extend;
	uint32_t Old;
	void* Info;
};

DataArray(_ControllerData, Controller_Data_0, 0x03B0E9C8, 8);	// Yes, there are in fact *8* controller structures in SADX PC.
DataPointer(int, isCutscenePlaying, 0x3B2A2E4);					// Fun fact: Freeze at 0 to avoid cutscenes. 4 bytes from here is the cutscene to play.
DataPointer(char, rumbleEnabled, 0x00913B10);					// Not sure why this is a char and ^ is an int.

#define clamp(value, low, high) min(max(low, value), high)

namespace xinput
{
	namespace deadzone
	{
		short stickL[4] = {
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE
		};

		short stickR[4] = {
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
			XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE
		};

		short triggers[4] = {
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
			XINPUT_GAMEPAD_TRIGGER_THRESHOLD
		};
	}

	const uint rumble_l_timer = 250;
	const uint rumble_r_timer = 1000;

	XINPUT_VIBRATION vibration[4];
	Motor rumble[4];
	uint rumble_l_elapsed[4];
	uint rumble_r_elapsed[4];

	float rumble_multi = 255.0;

	// TODO: Keyboard & Mouse
	void __cdecl UpdateControllersXInput()
	{
		for (uint8 i = 0; i < 4; i++)
		{
			_ControllerData* pad = &Controller_Data_0[i];
			XINPUT_STATE state = {};
			XInputGetState(i, &state);
			XINPUT_GAMEPAD* xpad = &state.Gamepad;

			// Gotta get that enum set up for this.
			pad->Support = 0x3F07FEu;

			// L Analog
			pad->LeftStickX = GetWithinDeadzone(xpad->sThumbLX, deadzone::stickL[i]);
			pad->LeftStickY = GetWithinDeadzone(-xpad->sThumbLY, deadzone::stickL[i]);

			// R Analog
			pad->RightStickX = GetWithinDeadzone(xpad->sThumbRX, deadzone::stickR[i]);
			pad->RightStickY = GetWithinDeadzone(-xpad->sThumbRY, deadzone::stickR[i]);

			// Trigger pressure
			pad->LTriggerPressure = xpad->bLeftTrigger;
			pad->RTriggerPressure = xpad->bRightTrigger;

			// Now, get the new buttons from the XInput xpad
			pad->HeldButtons = XInputToDreamcast(xpad, i);
			pad->NotHeldButtons = ~pad->HeldButtons;

			// Now set the released buttons to the difference between
			// the last and currently held buttons
			pad->ReleasedButtons = pad->HeldButtons ^ pad->Old;

			// Do some fancy math to "press" only the necessary buttons
			pad->PressedButtons = pad->HeldButtons & ~pad->Old;

			// Set the "last held" to held
			pad->Old = pad->HeldButtons;

			// Disable rumble if the timer says it's a good idea.
			if (rumble[i] != Motor::None)
			{
				Motor result = Motor::None;
				uint now = GetTickCount();

				if ((now - rumble_l_elapsed[i]) >= rumble_l_timer)
				{
					result = (Motor)(result | Motor::Left);
					rumble[i] = (Motor)(rumble[i] & ~Motor::Left);
				}
				if ((now - rumble_r_elapsed[i]) >= rumble_r_timer)
				{
					result = (Motor)(result | Motor::Right);
					rumble[i] = (Motor)(rumble[i] & ~Motor::Right);
				}

				if (result != Motor::None)
					Rumble(i, 0, result);
			}

#ifdef _DEBUG
			if (xpad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)
			{
				DisplayDebugStringFormatted(8 + (3 * i), "P%d  B: %08X LT/RT: %03d/%03d V: %d%d", (i + 1),
					pad->HeldButtons, pad->LTriggerPressure, pad->RTriggerPressure, (rumble[i] & Motor::Left), ((rumble[i] & Motor::Right) >> 1));
				DisplayDebugStringFormatted(9 + (3 * i), "   LS: %04d/%04d RS: %04d/%04d",
					pad->LeftStickX, pad->LeftStickY, pad->RightStickX, pad->RightStickY);

				if (i == 0 && xpad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
				{
					if (pad->PressedButtons & Buttons_Up)
						rumble_multi += 8.0;
					else if (pad->PressedButtons & Buttons_Down)
						rumble_multi -= 8.0;

					DisplayDebugStringFormatted(6, "Rumble multiplier (U/D): %f", rumble_multi);
				}
			}
#endif
		}
	}

	inline void SetMotor(short id, Motor motor, short intensity)
	{
		if (motor & Motor::Left)
		{
			vibration[id].wLeftMotorSpeed = intensity;
			rumble_l_elapsed[id] = GetTickCount();
		}
		if (motor & Motor::Right)
		{
			// This is doubled because it's never strong enough.
			vibration[id].wRightMotorSpeed = intensity * 2;
			rumble_r_elapsed[id] = GetTickCount();
		}
	}
	void Rumble(short id, int a1, Motor motor)
	{
		short intensity = 4 * a1;

		bool isWithinRange = (id >= 0 && id < 4);
		Motor resultMotor = (isWithinRange) ? rumble[id] : Motor::None;

		if (a1 > 0)
		{
			float m = 0;

			// RumbleLarge only ever passes in a value in that is <= 10,
			// and scaling that to 2 bytes is super annoying, so here's
			// some arbitrary values to increase the intensity.
			if (a1 >= 1 && a1 <= 10)
				m = max(0.2375f, intensity / 25.0f);
			else
				m = intensity / rumble_multi;

			intensity = (short)(SHRT_MAX * max(0.0, min(1.0f, m)));

			resultMotor = (Motor)(resultMotor | motor);
		}

		// TODO: Check if the player ID is currently AI controlled (or if intensity is 0).
		// This will avoid vibrating the second controller when Tails does something stupid.
		if (isWithinRange)
		{
			SetMotor(id, motor, intensity);
			rumble[id] = (Motor)(rumble[id] | resultMotor);
			XInputSetState(id, &vibration[id]);
		}
		else
		{
			for (uint8 i = 0; i < 4; i++)
			{
				SetMotor(i, motor, intensity);
				rumble[i] = (Motor)(rumble[i] | resultMotor);
				XInputSetState(i, &vibration[i]);
			}
		}
	}

	void __cdecl RumbleLarge(int playerNumber, signed int intensity)
	{
		if (!isCutscenePlaying && rumbleEnabled)
		{
			// Only continue if the calling player is Player 1 (0)
			// Vanilla SADX only rumbles for P1.
			if (!playerNumber)
				Rumble(playerNumber, clamp(intensity, 1, 255), Motor::Left);
		}
	}
	void __cdecl RumbleSmall(int playerNumber, signed int a2, signed int a3, int a4)
	{
		if (!isCutscenePlaying && rumbleEnabled)
		{
			// Only continue if the calling player is Player 1 (0)
			// Vanilla SADX only rumbles for P1.
			if (!playerNumber)
			{
				int _a2 = clamp(a2, -4, 4);

				// Could be inline if'd, but it'd look borderline unreadable.
				if (_a2 == 1)
					_a2 = 2;
				else if (_a2 == -1)
					_a2 = -2;

				int _a3 = clamp(a3, 7, 59);

				Rumble(playerNumber, max(1, a4 * _a3 / (4 * _a2)), Motor::Right);
			}
		}
	}

	// If analog exceeds deadzone, return SADX-friendly
	// version of the value; else 0.
	short GetWithinDeadzone(int analog, short deadzone)
	{
		// tl;dr: if analog exceeds the deadzone, convert to SADX-friendly
		// value, then make sure it's not < -127 or > 127 and return it; else 0.
		if (analog < -deadzone || analog > deadzone)
			return clamp((analog / 256), -127, 127);
		else
			return 0;
	}
	void SetDeadzone(short* array, uint id, int value)
	{
		if (value >= 0)
			array[id] = min(SHRT_MAX, value);
	}

	// Converts wButtons in XINPUT_GAMEPAD to Sonic Adventure compatible buttons and returns the value.
	int XInputToDreamcast(XINPUT_GAMEPAD* xpad, ushort id)
	{
		int result = 0;
		int buttons = xpad->wButtons;

		if (buttons & XINPUT_GAMEPAD_A)
			result |= Buttons_A;
		if (buttons & XINPUT_GAMEPAD_B)
			result |= Buttons_B;
		if (buttons & XINPUT_GAMEPAD_X)
			result |= Buttons_X;
		if (buttons & XINPUT_GAMEPAD_Y)
			result |= Buttons_Y;
		if (buttons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
			result |= Buttons_Z;

		if (xpad->bLeftTrigger > deadzone::triggers[id])
			result |= Buttons_L;
		if (xpad->bRightTrigger > deadzone::triggers[id])
			result |= Buttons_R;

		if (buttons & XINPUT_GAMEPAD_START)
			result |= Buttons_Start;

		if (buttons & XINPUT_GAMEPAD_DPAD_UP)
			result |= Buttons_Up;
		if (buttons & XINPUT_GAMEPAD_DPAD_DOWN)
			result |= Buttons_Down;
		if (buttons & XINPUT_GAMEPAD_DPAD_LEFT)
			result |= Buttons_Left;
		if (buttons & XINPUT_GAMEPAD_DPAD_RIGHT)
			result |= Buttons_Right;

		return result;
	}
}<|endoftext|>


<commit_before>// This is the main DLL file.

#include "Stdafx.h"

#include "MT5Connector.h"
#include "MT5Handler.h"

#include "Windows.h"
#include < vcclr.h >

using namespace System;
using namespace MTApiService;
using namespace System::Runtime::InteropServices;
using namespace System::Reflection;
using namespace System::Text;
using namespace  System::Collections::Generic;
using namespace System::Diagnostics;
using namespace System::Security::Cryptography;
using namespace System::Security;

#pragma pack(push, 1)
public struct CMqlRates
{
    __int64    time;         // Period start time
    double  open;         // Open price
    double  high;         // The highest price of the period
    double  low;          // The lowest price of the period
    double  close;        // Close price
    __int64 tick_volume;  // Tick volume
    int     spread;       // Spread
    __int64 real_volume;  // Trade volume
};

public struct CMqlTick
{
    __int64                time;          // Time of the last prices update
    double                bid;           // Current Bid price
    double                ask;           // Current Ask price
    double                last;          // Price of the last deal (Last)
    unsigned __int64    volume;        // Volume for the current Last price
};

public struct CMqlBookInfo
{
    int        type;       // Order type from ENUM_BOOK_TYPE enumeration
    double    price;      // Price
    __int64    volume;     // Volume
};
#pragma pack(pop)

void convertSystemString(wchar_t* dest, String^ src)
{
    pin_ptr<const wchar_t> wch = PtrToStringChars(src);
    memcpy(dest, wch, wcslen(wch) * sizeof(wchar_t));
    dest[wcslen(wch)] = '\0';
}

bool VerifySignature(System::String^ inputData, System::String^ signature, System::String^ publicKey)
{
    bool verifyResult = false;

    try
    {
        DSACryptoServiceProvider^ dsa = gcnew DSACryptoServiceProvider();
        dsa->FromXmlString(publicKey);
        array<System::Byte>^ data = UTF8Encoding::ASCII->GetBytes(inputData);
        array<System::Byte>^ signatureData = Convert::FromBase64String(signature);
        verifyResult = dsa->VerifyData(data, signatureData);
    }
    catch(Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:VerifySignature(): failed. " + e->Message);
        verifyResult = false;
    }

    return verifyResult;
}

bool g_IsVerified = true;

void _stdcall verify(int isDemo, wchar_t* accountName, long accountNumber)
{
    if (isDemo != 0)
    {
        g_IsVerified = true;
        return;
    }

    System::String^ signature = MtRegistryManager::ReadSignatureKey(gcnew String(accountName), accountNumber.ToString());
    Resources::ResourceManager^ rm = gcnew Resources::ResourceManager(L"MT5Connector.cl", Assembly::GetExecutingAssembly());
    System::String^ inputData = gcnew System::String(accountName);
    inputData += accountNumber.ToString();
    System::String^ publicKey = rm->GetString(L"cl");
    g_IsVerified = VerifySignature(inputData, gcnew System::String(signature), publicKey);
}

int _stdcall initExpert(int expertHandle, int port, wchar_t* symbol, double bid, double ask, wchar_t* err)
{
    if (g_IsVerified == false)
    {
        System::String^ errorVerified = "Verification is failed!\nPlease contact with support.";
        convertSystemString(err, errorVerified);
        Debug::WriteLine("[ERROR] MT5Connector:initExpert(): not verified");
        return 0;
    }

    try
    {
        MT5Handler^ mtHander = gcnew MT5Handler();
        MtServerInstance::GetInstance()->InitExpert(expertHandle, port, gcnew String(symbol), bid, ask, mtHander);
    }
    catch (Exception^ e)
    {
        convertSystemString(err, e->Message);
        Debug::WriteLine("[ERROR] MT5Connector:initExpert(): " + e->Message);

        return 0;
    }
    return 1;
}

int _stdcall deinitExpert(int expertHandle, wchar_t* err)
{
    try
    {
        MtServerInstance::GetInstance()->DeinitExpert(expertHandle);
    }
    catch (Exception^ e)
    {
        convertSystemString(err, e->Message);
        Debug::WriteLine("[ERROR] MT5Connector:deinitExpert(): " + e->Message);

        return 0;
    }
    return 1;
}

int _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid, double ask, wchar_t* err)
{
    try
    {
        MtServerInstance::GetInstance()->SendQuote(expertHandle, gcnew String(symbol), bid, ask);
    }
    catch (Exception^ e)
    {
        convertSystemString(err, e->Message);
        Debug::WriteLine("[ERROR] MT5Connector:updateQuote(): " + e->Message);

        return 0;
    }
    return 1;
}

int _stdcall sendIntResponse(int expertHandle, int response)
{
    try
    {
        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseInt(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendIntResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendLongResponse(int expertHandle, __int64 response)
{
    try
    {
        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLong(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendULongResponse(int expertHandle, unsigned __int64 response)
{
    try
    {
        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseULong(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendBooleanResponse(int expertHandle, int response)
{
    try
    {
        bool value = (response != 0) ? true : false;

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseBool(value));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendBooleanResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendDoubleResponse(int expertHandle, double response)
{
    try
    {
        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDouble(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendDoubleResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendStringResponse(int expertHandle, wchar_t* response)
{
    try
    {
        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseString(gcnew String(response)));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendStringResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendVoidResponse(int expertHandle)
{
    try
    {
        MtServerInstance::GetInstance()->SendResponse(expertHandle, nullptr);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendVoidResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendDoubleArrayResponse(int expertHandle, double* values, int size)
{
    try
    {
        array<double>^ list = gcnew array<double>(size);

        for(int i = 0; i < size; i++)
        {
            list[i] = values[i];
        }

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDoubleArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendDoubleArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendIntArrayResponse(int expertHandle, int* values, int size)
{
    try
    {
        array<int>^ list = gcnew array<int>(size);

        for(int i = 0; i < size; i++)
        {
            list[i] = values[i];
        }

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseIntArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendIntArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendLongArrayResponse(int expertHandle, __int64* values, int size)
{
    try
    {
        array<System::Int64>^ list = gcnew array<System::Int64>(size);

        for(int i = 0; i < size; i++)
        {
            list[i] = values[i];
        }

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLongArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendLongArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendMqlRatesArrayResponse(int expertHandle, CMqlRates values[], int size)
{
    try
    {
        array<MtMqlRates^>^ list = gcnew array<MtMqlRates^>(size);

        for(int i = 0; i < size; i++)
        {
            MtMqlRates^ rates = gcnew MtMqlRates();
            rates->time = values[i].time;
            rates->open = values[i].open;
            rates->high = values[i].high;
            rates->low = values[i].low;
            rates->close = values[i].close;
            rates->tick_volume = values[i].tick_volume;
            rates->spread = values[i].spread;
            rates->real_volume = values[i].real_volume;

            list[i] = rates;
        }

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlRatesArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendMqlTickResponse(int expertHandle, CMqlTick* response, int size)
{
    try
    {
        MtMqlTick^ mtResponse = gcnew MtMqlTick();

        mtResponse->time = response->time;
        mtResponse->bid = response->bid;
        mtResponse->ask = response->ask;
        mtResponse->last = response->last;
        mtResponse->volume = response->volume;

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlTick(mtResponse));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendMqlTickResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendMqlBookInfoArrayResponse(int expertHandle, CMqlBookInfo values[], int size)
{
    try
    {
        array<MtMqlBookInfo^>^ list = gcnew array<MtMqlBookInfo^>(size);

        for(int i = 0; i < size; i++)
        {
            MtMqlBookInfo^ info = gcnew MtMqlBookInfo();

            info->type = values[i].type;
            info->price = values[i].price;
            info->volume = values[i].volume;

            list[i] = info;
        }

        MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlBookInfoArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

//----------- get values -------------------------------

int _stdcall getCommandType(int expertHandle, int* res)
{
    try
    {
        *res = MtServerInstance::GetInstance()->GetCommandType(expertHandle);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getCommandType(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getIntValue(int expertHandle, int paramIndex, int* res)
{
    try
    {
        *res = (int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getIntValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getDoubleValue(int expertHandle, int paramIndex, double* res)
{
    try
    {
        *res = (double)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getDoubleValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res)
{
    try
    {
        convertSystemString(res, (String^)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getStringValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getULongValue(int expertHandle, int paramIndex, unsigned __int64* res)
{
    try
    {
        *res = (unsigned long)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getULongValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getLongValue(int expertHandle, int paramIndex, __int64* res)
{
    try
    {
        *res = (long)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getLongValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res)
{
    try
    {
        bool val = (bool)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
        *res = val == true ? 1 : 0;
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getBooleanValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getUIntValue(int expertHandle, int paramIndex, unsigned int* res)
{
    try
    {
        *res = (unsigned int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getUIntValue(): " + e->Message);
        return 0;
    }
    return 1;
}<commit_msg>Issue #44: Fixed MT5Connector project for using MtAdapter<commit_after>// This is the main DLL file.

#include "Stdafx.h"

#include "MT5Connector.h"
#include "MT5Handler.h"

#include "Windows.h"
#include < vcclr.h >

using namespace System;
using namespace MTApiService;
using namespace System::Runtime::InteropServices;
using namespace System::Reflection;
using namespace System::Text;
using namespace  System::Collections::Generic;
using namespace System::Diagnostics;
using namespace System::Security::Cryptography;
using namespace System::Security;

#pragma pack(push, 1)
public struct CMqlRates
{
    __int64    time;         // Period start time
    double  open;         // Open price
    double  high;         // The highest price of the period
    double  low;          // The lowest price of the period
    double  close;        // Close price
    __int64 tick_volume;  // Tick volume
    int     spread;       // Spread
    __int64 real_volume;  // Trade volume
};

public struct CMqlTick
{
    __int64                time;          // Time of the last prices update
    double                bid;           // Current Bid price
    double                ask;           // Current Ask price
    double                last;          // Price of the last deal (Last)
    unsigned __int64    volume;        // Volume for the current Last price
};

public struct CMqlBookInfo
{
    int        type;       // Order type from ENUM_BOOK_TYPE enumeration
    double    price;      // Price
    __int64    volume;     // Volume
};
#pragma pack(pop)

void convertSystemString(wchar_t* dest, String^ src)
{
    pin_ptr<const wchar_t> wch = PtrToStringChars(src);
    memcpy(dest, wch, wcslen(wch) * sizeof(wchar_t));
    dest[wcslen(wch)] = '\0';
}

bool VerifySignature(System::String^ inputData, System::String^ signature, System::String^ publicKey)
{
    bool verifyResult = false;

    try
    {
        DSACryptoServiceProvider^ dsa = gcnew DSACryptoServiceProvider();
        dsa->FromXmlString(publicKey);
        array<System::Byte>^ data = UTF8Encoding::ASCII->GetBytes(inputData);
        array<System::Byte>^ signatureData = Convert::FromBase64String(signature);
        verifyResult = dsa->VerifyData(data, signatureData);
    }
    catch(Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:VerifySignature(): failed. " + e->Message);
        verifyResult = false;
    }

    return verifyResult;
}

bool g_IsVerified = true;

void _stdcall verify(int isDemo, wchar_t* accountName, long accountNumber)
{
    if (isDemo != 0)
    {
        g_IsVerified = true;
        return;
    }

    System::String^ signature = MtRegistryManager::ReadSignatureKey(gcnew String(accountName), accountNumber.ToString());
    Resources::ResourceManager^ rm = gcnew Resources::ResourceManager(L"MT5Connector.cl", Assembly::GetExecutingAssembly());
    System::String^ inputData = gcnew System::String(accountName);
    inputData += accountNumber.ToString();
    System::String^ publicKey = rm->GetString(L"cl");
    g_IsVerified = VerifySignature(inputData, gcnew System::String(signature), publicKey);
}

int _stdcall initExpert(int expertHandle, int port, wchar_t* symbol, double bid, double ask, wchar_t* err)
{
    if (g_IsVerified == false)
    {
        System::String^ errorVerified = "Verification is failed!\nPlease contact with support.";
        convertSystemString(err, errorVerified);
        Debug::WriteLine("[ERROR] MT5Connector:initExpert(): not verified");
        return 0;
    }

    try
    {
        MT5Handler^ mtHander = gcnew MT5Handler();
        MtAdapter::GetInstance()->InitExpert(expertHandle, port, gcnew String(symbol), bid, ask, mtHander);
    }
    catch (Exception^ e)
    {
        convertSystemString(err, e->Message);
        Debug::WriteLine("[ERROR] MT5Connector:initExpert(): " + e->Message);

        return 0;
    }
    return 1;
}

int _stdcall deinitExpert(int expertHandle, wchar_t* err)
{
    try
    {
        MtAdapter::GetInstance()->DeinitExpert(expertHandle);
    }
    catch (Exception^ e)
    {
        convertSystemString(err, e->Message);
        Debug::WriteLine("[ERROR] MT5Connector:deinitExpert(): " + e->Message);

        return 0;
    }
    return 1;
}

int _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid, double ask, wchar_t* err)
{
    try
    {
        MtAdapter::GetInstance()->SendQuote(expertHandle, gcnew String(symbol), bid, ask);
    }
    catch (Exception^ e)
    {
        convertSystemString(err, e->Message);
        Debug::WriteLine("[ERROR] MT5Connector:updateQuote(): " + e->Message);

        return 0;
    }
    return 1;
}

int _stdcall sendIntResponse(int expertHandle, int response)
{
    try
    {
        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseInt(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendIntResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendLongResponse(int expertHandle, __int64 response)
{
    try
    {
        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLong(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendULongResponse(int expertHandle, unsigned __int64 response)
{
    try
    {
        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseULong(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendBooleanResponse(int expertHandle, int response)
{
    try
    {
        bool value = (response != 0) ? true : false;

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseBool(value));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendBooleanResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendDoubleResponse(int expertHandle, double response)
{
    try
    {
        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDouble(response));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendDoubleResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendStringResponse(int expertHandle, wchar_t* response)
{
    try
    {
        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseString(gcnew String(response)));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendStringResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendVoidResponse(int expertHandle)
{
    try
    {
        MtAdapter::GetInstance()->SendResponse(expertHandle, nullptr);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendVoidResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendDoubleArrayResponse(int expertHandle, double* values, int size)
{
    try
    {
        array<double>^ list = gcnew array<double>(size);

        for(int i = 0; i < size; i++)
        {
            list[i] = values[i];
        }

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDoubleArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendDoubleArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendIntArrayResponse(int expertHandle, int* values, int size)
{
    try
    {
        array<int>^ list = gcnew array<int>(size);

        for(int i = 0; i < size; i++)
        {
            list[i] = values[i];
        }

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseIntArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendIntArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendLongArrayResponse(int expertHandle, __int64* values, int size)
{
    try
    {
        array<System::Int64>^ list = gcnew array<System::Int64>(size);

        for(int i = 0; i < size; i++)
        {
            list[i] = values[i];
        }

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLongArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendLongArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendMqlRatesArrayResponse(int expertHandle, CMqlRates values[], int size)
{
    try
    {
        array<MtMqlRates^>^ list = gcnew array<MtMqlRates^>(size);

        for(int i = 0; i < size; i++)
        {
            MtMqlRates^ rates = gcnew MtMqlRates();
            rates->time = values[i].time;
            rates->open = values[i].open;
            rates->high = values[i].high;
            rates->low = values[i].low;
            rates->close = values[i].close;
            rates->tick_volume = values[i].tick_volume;
            rates->spread = values[i].spread;
            rates->real_volume = values[i].real_volume;

            list[i] = rates;
        }

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlRatesArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendMqlTickResponse(int expertHandle, CMqlTick* response, int size)
{
    try
    {
        MtMqlTick^ mtResponse = gcnew MtMqlTick();

        mtResponse->time = response->time;
        mtResponse->bid = response->bid;
        mtResponse->ask = response->ask;
        mtResponse->last = response->last;
        mtResponse->volume = response->volume;

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlTick(mtResponse));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendMqlTickResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall sendMqlBookInfoArrayResponse(int expertHandle, CMqlBookInfo values[], int size)
{
    try
    {
        array<MtMqlBookInfo^>^ list = gcnew array<MtMqlBookInfo^>(size);

        for(int i = 0; i < size; i++)
        {
            MtMqlBookInfo^ info = gcnew MtMqlBookInfo();

            info->type = values[i].type;
            info->price = values[i].price;
            info->volume = values[i].volume;

            list[i] = info;
        }

        MtAdapter::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlBookInfoArray(list));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
        return 0;
    }
    return 1;
}

//----------- get values -------------------------------

int _stdcall getCommandType(int expertHandle, int* res)
{
    try
    {
        *res = MtAdapter::GetInstance()->GetCommandType(expertHandle);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getCommandType(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getIntValue(int expertHandle, int paramIndex, int* res)
{
    try
    {
        *res = (int)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getIntValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getDoubleValue(int expertHandle, int paramIndex, double* res)
{
    try
    {
        *res = (double)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getDoubleValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res)
{
    try
    {
        convertSystemString(res, (String^)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getStringValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getULongValue(int expertHandle, int paramIndex, unsigned __int64* res)
{
    try
    {
        *res = (unsigned long)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getULongValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getLongValue(int expertHandle, int paramIndex, __int64* res)
{
    try
    {
        *res = (long)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getLongValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res)
{
    try
    {
        bool val = (bool)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
        *res = val == true ? 1 : 0;
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getBooleanValue(): " + e->Message);
        return 0;
    }
    return 1;
}

int _stdcall getUIntValue(int expertHandle, int paramIndex, unsigned int* res)
{
    try
    {
        *res = (unsigned int)MtAdapter::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
    }
    catch (Exception^ e)
    {
        Debug::WriteLine("[ERROR] MT5Connector:getUIntValue(): " + e->Message);
        return 0;
    }
    return 1;
}<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/importer/external_process_importer_bridge.h"

#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/profile_import/profile_import_thread.h"
#include "webkit/glue/password_form.h"

#if defined(OS_WIN)
#include "chrome/browser/password_manager/ie7_password.h"
#endif

ExternalProcessImporterBridge::ExternalProcessImporterBridge(
    ProfileImportThread* profile_import_thread,
    const DictionaryValue& localized_strings)
    : profile_import_thread_(profile_import_thread) {
  // Bridge needs to make its own copy because OS 10.6 autoreleases the
  // localized_strings value that is passed in (see http://crbug.com/46003 ).
  localized_strings_.reset(localized_strings.DeepCopy());
}

void ExternalProcessImporterBridge::AddBookmarkEntries(
    const std::vector<ProfileWriter::BookmarkEntry>& bookmarks,
    const std::wstring& first_folder_name,
    int options) {
  profile_import_thread_->NotifyBookmarksImportReady(
      bookmarks, first_folder_name, options);
}

void ExternalProcessImporterBridge::AddHomePage(const GURL &home_page) {
  // TODO(mirandac): remove home page import from code base.
  // http://crbug.com/45678 :-)
  NOTIMPLEMENTED();
}

#if defined(OS_WIN)
void ExternalProcessImporterBridge::AddIE7PasswordInfo(
    const IE7PasswordInfo password_info) {
  NOTIMPLEMENTED();
}
#endif

void ExternalProcessImporterBridge::SetFavicons(
    const std::vector<history::ImportedFaviconUsage>& favicons) {
  profile_import_thread_->NotifyFaviconsImportReady(favicons);
}

void ExternalProcessImporterBridge::SetHistoryItems(
    const std::vector<history::URLRow>& rows,
    history::VisitSource visit_source) {
  profile_import_thread_->NotifyHistoryImportReady(rows, visit_source);
}

void ExternalProcessImporterBridge::SetKeywords(
    const std::vector<TemplateURL*>& template_urls,
    int default_keyword_index,
    bool unique_on_host_and_path) {
  profile_import_thread_->NotifyKeywordsReady(
      template_urls, default_keyword_index, unique_on_host_and_path);
}

void ExternalProcessImporterBridge::SetPasswordForm(
    const webkit_glue::PasswordForm& form) {
  profile_import_thread_->NotifyPasswordFormReady(form);
}

void ExternalProcessImporterBridge::NotifyStarted() {
  profile_import_thread_->NotifyStarted();
}

void ExternalProcessImporterBridge::NotifyItemStarted(
    importer::ImportItem item) {
  profile_import_thread_->NotifyItemStarted(item);
}

void ExternalProcessImporterBridge::NotifyItemEnded(importer::ImportItem item) {
  profile_import_thread_->NotifyItemEnded(item);
}

void ExternalProcessImporterBridge::NotifyEnded() {
  // The internal process detects import end when all items have been received.
}

// TODO(viettrungluu): convert to string16.
std::wstring ExternalProcessImporterBridge::GetLocalizedString(int message_id) {
  string16 message;
  localized_strings_->GetString(base::IntToString(message_id), &message);
  return UTF16ToWideHack(message);
}

ExternalProcessImporterBridge::~ExternalProcessImporterBridge() {}
<commit_msg>importer: Remove an obsolete TODO comment.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/importer/external_process_importer_bridge.h"

#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/profile_import/profile_import_thread.h"
#include "webkit/glue/password_form.h"

#if defined(OS_WIN)
#include "chrome/browser/password_manager/ie7_password.h"
#endif

ExternalProcessImporterBridge::ExternalProcessImporterBridge(
    ProfileImportThread* profile_import_thread,
    const DictionaryValue& localized_strings)
    : profile_import_thread_(profile_import_thread) {
  // Bridge needs to make its own copy because OS 10.6 autoreleases the
  // localized_strings value that is passed in (see http://crbug.com/46003 ).
  localized_strings_.reset(localized_strings.DeepCopy());
}

void ExternalProcessImporterBridge::AddBookmarkEntries(
    const std::vector<ProfileWriter::BookmarkEntry>& bookmarks,
    const std::wstring& first_folder_name,
    int options) {
  profile_import_thread_->NotifyBookmarksImportReady(
      bookmarks, first_folder_name, options);
}

void ExternalProcessImporterBridge::AddHomePage(const GURL& home_page) {
  NOTIMPLEMENTED();
}

#if defined(OS_WIN)
void ExternalProcessImporterBridge::AddIE7PasswordInfo(
    const IE7PasswordInfo password_info) {
  NOTIMPLEMENTED();
}
#endif

void ExternalProcessImporterBridge::SetFavicons(
    const std::vector<history::ImportedFaviconUsage>& favicons) {
  profile_import_thread_->NotifyFaviconsImportReady(favicons);
}

void ExternalProcessImporterBridge::SetHistoryItems(
    const std::vector<history::URLRow>& rows,
    history::VisitSource visit_source) {
  profile_import_thread_->NotifyHistoryImportReady(rows, visit_source);
}

void ExternalProcessImporterBridge::SetKeywords(
    const std::vector<TemplateURL*>& template_urls,
    int default_keyword_index,
    bool unique_on_host_and_path) {
  profile_import_thread_->NotifyKeywordsReady(
      template_urls, default_keyword_index, unique_on_host_and_path);
}

void ExternalProcessImporterBridge::SetPasswordForm(
    const webkit_glue::PasswordForm& form) {
  profile_import_thread_->NotifyPasswordFormReady(form);
}

void ExternalProcessImporterBridge::NotifyStarted() {
  profile_import_thread_->NotifyStarted();
}

void ExternalProcessImporterBridge::NotifyItemStarted(
    importer::ImportItem item) {
  profile_import_thread_->NotifyItemStarted(item);
}

void ExternalProcessImporterBridge::NotifyItemEnded(importer::ImportItem item) {
  profile_import_thread_->NotifyItemEnded(item);
}

void ExternalProcessImporterBridge::NotifyEnded() {
  // The internal process detects import end when all items have been received.
}

// TODO(viettrungluu): convert to string16.
std::wstring ExternalProcessImporterBridge::GetLocalizedString(int message_id) {
  string16 message;
  localized_strings_->GetString(base::IntToString(message_id), &message);
  return UTF16ToWideHack(message);
}

ExternalProcessImporterBridge::~ExternalProcessImporterBridge() {}
<|endoftext|>


<commit_before><commit_msg>GTK: render view: grab focus *before* forwarding mouse event to renderer.<commit_after><|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Contains all the operators and functions to build expressions.
*/

#pragma once

#include "etl/expression_helpers.hpp"

namespace etl {

/*!
 * \brief Creates an expression representing the Inverse of the given expression
 * \param a The input expression
 * \return an expression representing the 1D FFT of a
 */
template <typename A>
inv_expr<A> inv(A&& a) {
    static_assert(is_etl_expr<A>::value, "Inverse only supported for ETL expressions");

    return inv_expr<A>{a};
}

} //end of namespace etl
<commit_msg>Remove empty file<commit_after><|endoftext|>