From 724d9652bddecb32ae572949c2f341ac3afba299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Wed, 19 Oct 2016 13:20:53 +0000 Subject: [PATCH] git-svn-id: svn://db.shs.com.ru/libs@129 a8b55f48-bf90-11e4-a774-851b48703e85 --- telegram_test/execbot.cpp | 123 ++++++ telegram_test/execbot.h | 46 ++ telegram_test/json.cpp | 603 +++++++++++++++++++++++++++ telegram_test/json.h | 178 ++++++++ telegram_test/main.cpp | 11 + telegram_test/mainwindow.cpp | 67 +++ telegram_test/mainwindow.h | 37 ++ telegram_test/mainwindow.ui | 67 +++ telegram_test/telegram_test.pro | 26 ++ telegram_test/telegram_test.pro.user | 255 +++++++++++ telegram_test/telegrambotapi.cpp | 358 ++++++++++++++++ telegram_test/telegrambotapi.h | 119 ++++++ telegram_test/telegrambotbase.cpp | 79 ++++ telegram_test/telegrambotbase.h | 54 +++ 14 files changed, 2023 insertions(+) create mode 100644 telegram_test/execbot.cpp create mode 100644 telegram_test/execbot.h create mode 100644 telegram_test/json.cpp create mode 100644 telegram_test/json.h create mode 100644 telegram_test/main.cpp create mode 100644 telegram_test/mainwindow.cpp create mode 100644 telegram_test/mainwindow.h create mode 100644 telegram_test/mainwindow.ui create mode 100644 telegram_test/telegram_test.pro create mode 100644 telegram_test/telegram_test.pro.user create mode 100644 telegram_test/telegrambotapi.cpp create mode 100644 telegram_test/telegrambotapi.h create mode 100644 telegram_test/telegrambotbase.cpp create mode 100644 telegram_test/telegrambotbase.h diff --git a/telegram_test/execbot.cpp b/telegram_test/execbot.cpp new file mode 100644 index 0000000..7729acc --- /dev/null +++ b/telegram_test/execbot.cpp @@ -0,0 +1,123 @@ +#include "execbot.h" +#include +#include + +ExecBot::ExecBot(QObject *parent) : TelegramBotBase(parent) { +} + + +QString ExecBot::loginMessage(uint id) { + if (sessions.contains(id)) { + if (sessions[id] == Password) return tr("Enter password"); + if (sessions[id] == NotLogged) return tr("Please send me /start"); + } + return tr("Error"); +} + + +QString ExecBot::help() { + return tr("Input command for exec on server, after exec finished result will be sended to you"); +} + + +bool ExecBot::loginUser(uint id, const QString &msg) { + if (sessions.contains(id)) { + switch (sessions[id]) { + case NotLogged: + if (msg == "/start") sessions[id] = Password; + break; + case Password: + if (msg == "a") { + sessions[id] = Ready; + return true; + } + break; + case Ready: + case CommandExec: + return true; + default: + break; + return false; + } + } else { + if (msg == "/start") sessions[id] = Password; + else sessions[id] = NotLogged; + } + return false; +} + + +void ExecBot::messageFromUser(uint id, const QString &msg) { + if (sessions.contains(id)) { + if (msg == "/exit") { + sessions[id] = NotLogged; + disconnectUser(id); + getAPI()->sendMessage(id, tr("Logout")); + return; + } + if (sessions[id] == CommandExec) { + if (msg == "/kill") { + int rm = -1; + for (int i=0; ikill(); + getAPI()->sendMessage(id, tr("Process killed")); + sessions[id] = Ready; + rm = i; + } + } + if (rm >= 0) run_commands.remove(rm); + } else + getAPI()->sendMessage(id, tr("Command is running, please wait for finish")); + return; + } + if (sessions[id] == Ready) { + getAPI()->sendMessage(id, "exec: " + msg); + UserCommand uc; + uc.user = id; + uc.cmd = new QProcess(); +// uc.cmd->setProcessChannelMode(QProcess::MergedChannels); + connect(uc.cmd, SIGNAL(readyRead()), this, SLOT(cmdRead())); +// connect(uc.cmd, SIGNAL(started()), this, SLOT(cmdStart())); + connect(uc.cmd, SIGNAL(finished(int)), this, SLOT(cmdFinish(int))); + uc.cmd->start(msg); + if (uc.cmd->waitForStarted(3000)) { + sessions[id] = CommandExec; + run_commands.append(uc); + } else getAPI()->sendMessage(id, tr("Can't run command %1").arg(msg)); + } + } +} + + +void ExecBot::cmdRead() { +// qDebug() << "cmdRead()"; + QProcess * p = (QProcess *)sender(); + for (int i=0; itoUnicode(p->readAll()); + getAPI()->sendMessage(id, s); + } + } +} + +void ExecBot::cmdFinish(int code) { + qDebug() << "cmdFinish()" << code; + QProcess * p = (QProcess *)sender(); + int rm = -1; + for (int i=0; itoUnicode(p->readAll()); + getAPI()->sendMessage(id, s); + rm = i; + sessions[id] = Ready; + } + } + if (rm >= 0) run_commands.remove(rm); +} + + diff --git a/telegram_test/execbot.h b/telegram_test/execbot.h new file mode 100644 index 0000000..4c67348 --- /dev/null +++ b/telegram_test/execbot.h @@ -0,0 +1,46 @@ +#ifndef EXECBOT_H +#define EXECBOT_H + +#include "telegrambotbase.h" +#include + + +class ExecBot : public TelegramBotBase +{ + Q_OBJECT +public: + explicit ExecBot(QObject *parent = 0); + + +public slots: + +private: + enum UserState { + NotLogged, + Password, + Ready, + CommandExec + }; + struct UserCommand { + uint user; + QProcess * cmd; + }; + + virtual QString loginMessage(uint id); + virtual QString help(); + virtual bool loginUser(uint id, const QString & msg); + virtual void messageFromUser(uint id, const QString & msg); + void runCMD(UserCommand uc); + + QMap sessions; + QVector run_commands; + +private slots: + void cmdRead(); + void cmdFinish(int code); + +signals: + +}; + +#endif // EXECBOT_H diff --git a/telegram_test/json.cpp b/telegram_test/json.cpp new file mode 100644 index 0000000..1aa505b --- /dev/null +++ b/telegram_test/json.cpp @@ -0,0 +1,603 @@ +/** + * QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa. + * Copyright (C) 2011 Eeli Reilin + * + * 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 3 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 . + */ + +/** + * \file json.cpp + */ + +#include +#include +#include "json.h" + +namespace QtJson { + static QString dateFormat, dateTimeFormat; + + static QString sanitizeString(QString str); + static QByteArray join(const QList &list, const QByteArray &sep); + static QVariant parseValue(const QString &json, int &index, bool &success); + static QVariant parseObject(const QString &json, int &index, bool &success); + static QVariant parseArray(const QString &json, int &index, bool &success); + static QVariant parseString(const QString &json, int &index, bool &success); + static QVariant parseNumber(const QString &json, int &index); + static int lastIndexOfNumber(const QString &json, int index); + static void eatWhitespace(const QString &json, int &index); + static int lookAhead(const QString &json, int index); + static int nextToken(const QString &json, int &index); + + template + QByteArray serializeMap(const T &map, bool &success) { + QByteArray str = "{ "; + QList pairs; + for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) { + QByteArray serializedValue = serialize(it.value()); + if (serializedValue.isNull()) { + success = false; + break; + } + pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; + } + + str += join(pairs, ", "); + str += " }"; + return str; + } + + void insert(QVariant &v, const QString &key, const QVariant &value); + void append(QVariant &v, const QVariant &value); + + template + void cloneMap(QVariant &json, const T &map) { + for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) { + insert(json, it.key(), (*it)); + } + } + + template + void cloneList(QVariant &json, const T &list) { + for (typename T::const_iterator it = list.begin(), itend = list.end(); it != itend; ++it) { + append(json, (*it)); + } + } + + /** + * parse + */ + QVariant parse(const QString &json) { + bool success = true; + return parse(json, success); + } + + /** + * parse + */ + QVariant parse(const QString &json, bool &success) { + success = true; + + // Return an empty QVariant if the JSON data is either null or empty + if (!json.isNull() || !json.isEmpty()) { + QString data = json; + // We'll start from index 0 + int index = 0; + + // Parse the first value + QVariant value = parseValue(data, index, success); + + // Return the parsed value + return value; + } else { + // Return the empty QVariant + return QVariant(); + } + } + + /** + * clone + */ + QVariant clone(const QVariant &data) { + QVariant v; + + if (data.type() == QVariant::Map) { + cloneMap(v, data.toMap()); + } else if (data.type() == QVariant::Hash) { + cloneMap(v, data.toHash()); + } else if (data.type() == QVariant::List) { + cloneList(v, data.toList()); + } else if (data.type() == QVariant::StringList) { + cloneList(v, data.toStringList()); + } else { + v = QVariant(data); + } + + return v; + } + + /** + * insert value (map case) + */ + void insert(QVariant &v, const QString &key, const QVariant &value) { + if (!v.canConvert()) v = QVariantMap(); + QVariantMap *p = (QVariantMap *)v.data(); + p->insert(key, clone(value)); + } + + /** + * append value (list case) + */ + void append(QVariant &v, const QVariant &value) { + if (!v.canConvert()) v = QVariantList(); + QVariantList *p = (QVariantList *)v.data(); + p->append(value); + } + + QByteArray serialize(const QVariant &data) { + bool success = true; + return serialize(data, success); + } + + QByteArray serialize(const QVariant &data, bool &success) { + QByteArray str; + success = true; + + if (!data.isValid()) { // invalid or null? + str = "null"; + } else if ((data.type() == QVariant::List) || + (data.type() == QVariant::StringList)) { // variant is a list? + QList values; + const QVariantList list = data.toList(); + Q_FOREACH(const QVariant& v, list) { + QByteArray serializedValue = serialize(v); + if (serializedValue.isNull()) { + success = false; + break; + } + values << serializedValue; + } + + str = "[ " + join( values, ", " ) + " ]"; + } else if (data.type() == QVariant::Hash) { // variant is a hash? + str = serializeMap<>(data.toHash(), success); + } else if (data.type() == QVariant::Map) { // variant is a map? + str = serializeMap<>(data.toMap(), success); + } else if ((data.type() == QVariant::String) || + (data.type() == QVariant::ByteArray)) {// a string or a byte array? + str = sanitizeString(data.toString()).toUtf8(); + } else if (data.type() == QVariant::Double) { // double? + double value = data.toDouble(&success); + if (success) { + str = QByteArray::number(value, 'g'); + if (!str.contains(".") && ! str.contains("e")) { + str += ".0"; + } + } + } else if (data.type() == QVariant::Bool) { // boolean value? + str = data.toBool() ? "true" : "false"; + } else if (data.type() == QVariant::ULongLong) { // large unsigned number? + str = QByteArray::number(data.value()); + } else if (data.canConvert()) { // any signed number? + str = QByteArray::number(data.value()); + } else if (data.canConvert()) { //TODO: this code is never executed because all smaller types can be converted to qlonglong + str = QString::number(data.value()).toUtf8(); + } else if (data.type() == QVariant::DateTime) { // datetime value? + str = sanitizeString(dateTimeFormat.isEmpty() + ? data.toDateTime().toString() + : data.toDateTime().toString(dateTimeFormat)).toUtf8(); + } else if (data.type() == QVariant::Date) { // date value? + str = sanitizeString(dateTimeFormat.isEmpty() + ? data.toDate().toString() + : data.toDate().toString(dateFormat)).toUtf8(); + } else if (data.canConvert()) { // can value be converted to string? + // this will catch QUrl, ... (all other types which can be converted to string) + str = sanitizeString(data.toString()).toUtf8(); + } else { + success = false; + } + + if (success) { + return str; + } + return QByteArray(); + } + + QString serializeStr(const QVariant &data) { + return QString::fromUtf8(serialize(data)); + } + + QString serializeStr(const QVariant &data, bool &success) { + return QString::fromUtf8(serialize(data, success)); + } + + + /** + * \enum JsonToken + */ + enum JsonToken { + JsonTokenNone = 0, + JsonTokenCurlyOpen = 1, + JsonTokenCurlyClose = 2, + JsonTokenSquaredOpen = 3, + JsonTokenSquaredClose = 4, + JsonTokenColon = 5, + JsonTokenComma = 6, + JsonTokenString = 7, + JsonTokenNumber = 8, + JsonTokenTrue = 9, + JsonTokenFalse = 10, + JsonTokenNull = 11 + }; + + static QString sanitizeString(QString str) { + str.replace(QLatin1String("\\"), QLatin1String("\\\\")); + str.replace(QLatin1String("\""), QLatin1String("\\\"")); + str.replace(QLatin1String("\b"), QLatin1String("\\b")); + str.replace(QLatin1String("\f"), QLatin1String("\\f")); + str.replace(QLatin1String("\n"), QLatin1String("\\n")); + str.replace(QLatin1String("\r"), QLatin1String("\\r")); + str.replace(QLatin1String("\t"), QLatin1String("\\t")); + return QString(QLatin1String("\"%1\"")).arg(str); + } + + static QByteArray join(const QList &list, const QByteArray &sep) { + QByteArray res; + Q_FOREACH(const QByteArray &i, list) { + if (!res.isEmpty()) { + res += sep; + } + res += i; + } + return res; + } + + /** + * parseValue + */ + static QVariant parseValue(const QString &json, int &index, bool &success) { + // Determine what kind of data we should parse by + // checking out the upcoming token + switch(lookAhead(json, index)) { + case JsonTokenString: + return parseString(json, index, success); + case JsonTokenNumber: + return parseNumber(json, index); + case JsonTokenCurlyOpen: + return parseObject(json, index, success); + case JsonTokenSquaredOpen: + return parseArray(json, index, success); + case JsonTokenTrue: + nextToken(json, index); + return QVariant(true); + case JsonTokenFalse: + nextToken(json, index); + return QVariant(false); + case JsonTokenNull: + nextToken(json, index); + return QVariant(); + case JsonTokenNone: + break; + } + + // If there were no tokens, flag the failure and return an empty QVariant + success = false; + return QVariant(); + } + + /** + * parseObject + */ + static QVariant parseObject(const QString &json, int &index, bool &success) { + QVariantMap map; + int token; + + // Get rid of the whitespace and increment index + nextToken(json, index); + + // Loop through all of the key/value pairs of the object + bool done = false; + while (!done) { + // Get the upcoming token + token = lookAhead(json, index); + + if (token == JsonTokenNone) { + success = false; + return QVariantMap(); + } else if (token == JsonTokenComma) { + nextToken(json, index); + } else if (token == JsonTokenCurlyClose) { + nextToken(json, index); + return map; + } else { + // Parse the key/value pair's name + QString name = parseString(json, index, success).toString(); + + if (!success) { + return QVariantMap(); + } + + // Get the next token + token = nextToken(json, index); + + // If the next token is not a colon, flag the failure + // return an empty QVariant + if (token != JsonTokenColon) { + success = false; + return QVariant(QVariantMap()); + } + + // Parse the key/value pair's value + QVariant value = parseValue(json, index, success); + + if (!success) { + return QVariantMap(); + } + + // Assign the value to the key in the map + map[name] = value; + } + } + + // Return the map successfully + return QVariant(map); + } + + /** + * parseArray + */ + static QVariant parseArray(const QString &json, int &index, bool &success) { + QVariantList list; + + nextToken(json, index); + + bool done = false; + while(!done) { + int token = lookAhead(json, index); + + if (token == JsonTokenNone) { + success = false; + return QVariantList(); + } else if (token == JsonTokenComma) { + nextToken(json, index); + } else if (token == JsonTokenSquaredClose) { + nextToken(json, index); + break; + } else { + QVariant value = parseValue(json, index, success); + if (!success) { + return QVariantList(); + } + list.push_back(value); + } + } + + return QVariant(list); + } + + /** + * parseString + */ + static QVariant parseString(const QString &json, int &index, bool &success) { + QString s; + QChar c; + + eatWhitespace(json, index); + + c = json[index++]; + + bool complete = false; + while(!complete) { + if (index == json.size()) { + break; + } + + c = json[index++]; + + if (c == '\"') { + complete = true; + break; + } else if (c == '\\') { + if (index == json.size()) { + break; + } + + c = json[index++]; + + if (c == '\"') { + s.append('\"'); + } else if (c == '\\') { + s.append('\\'); + } else if (c == '/') { + s.append('/'); + } else if (c == 'b') { + s.append('\b'); + } else if (c == 'f') { + s.append('\f'); + } else if (c == 'n') { + s.append('\n'); + } else if (c == 'r') { + s.append('\r'); + } else if (c == 't') { + s.append('\t'); + } else if (c == 'u') { + int remainingLength = json.size() - index; + if (remainingLength >= 4) { + QString unicodeStr = json.mid(index, 4); + + int symbol = unicodeStr.toInt(0, 16); + + s.append(QChar(symbol)); + + index += 4; + } else { + break; + } + } + } else { + s.append(c); + } + } + + if (!complete) { + success = false; + return QVariant(); + } + + return QVariant(s); + } + + /** + * parseNumber + */ + static QVariant parseNumber(const QString &json, int &index) { + eatWhitespace(json, index); + + int lastIndex = lastIndexOfNumber(json, index); + int charLength = (lastIndex - index) + 1; + QString numberStr; + + numberStr = json.mid(index, charLength); + + index = lastIndex + 1; + bool ok; + + if (numberStr.contains('.')) { + return QVariant(numberStr.toDouble(NULL)); + } else if (numberStr.startsWith('-')) { + int i = numberStr.toInt(&ok); + if (!ok) { + qlonglong ll = numberStr.toLongLong(&ok); + return ok ? ll : QVariant(numberStr); + } + return i; + } else { + uint u = numberStr.toUInt(&ok); + if (!ok) { + qulonglong ull = numberStr.toULongLong(&ok); + return ok ? ull : QVariant(numberStr); + } + return u; + } + } + + /** + * lastIndexOfNumber + */ + static int lastIndexOfNumber(const QString &json, int index) { + int lastIndex; + + for(lastIndex = index; lastIndex < json.size(); lastIndex++) { + if (QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1) { + break; + } + } + + return lastIndex -1; + } + + /** + * eatWhitespace + */ + static void eatWhitespace(const QString &json, int &index) { + for(; index < json.size(); index++) { + if (QString(" \t\n\r").indexOf(json[index]) == -1) { + break; + } + } + } + + /** + * lookAhead + */ + static int lookAhead(const QString &json, int index) { + int saveIndex = index; + return nextToken(json, saveIndex); + } + + /** + * nextToken + */ + static int nextToken(const QString &json, int &index) { + eatWhitespace(json, index); + + if (index == json.size()) { + return JsonTokenNone; + } + + QChar c = json[index]; + index++; + switch(c.toLatin1()) { + case '{': return JsonTokenCurlyOpen; + case '}': return JsonTokenCurlyClose; + case '[': return JsonTokenSquaredOpen; + case ']': return JsonTokenSquaredClose; + case ',': return JsonTokenComma; + case '"': return JsonTokenString; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': return JsonTokenNumber; + case ':': return JsonTokenColon; + } + index--; // ^ WTF? + + int remainingLength = json.size() - index; + + // True + if (remainingLength >= 4) { + if (json[index] == 't' && json[index + 1] == 'r' && + json[index + 2] == 'u' && json[index + 3] == 'e') { + index += 4; + return JsonTokenTrue; + } + } + + // False + if (remainingLength >= 5) { + if (json[index] == 'f' && json[index + 1] == 'a' && + json[index + 2] == 'l' && json[index + 3] == 's' && + json[index + 4] == 'e') { + index += 5; + return JsonTokenFalse; + } + } + + // Null + if (remainingLength >= 4) { + if (json[index] == 'n' && json[index + 1] == 'u' && + json[index + 2] == 'l' && json[index + 3] == 'l') { + index += 4; + return JsonTokenNull; + } + } + + return JsonTokenNone; + } + + void setDateTimeFormat(const QString &format) { + dateTimeFormat = format; + } + + void setDateFormat(const QString &format) { + dateFormat = format; + } + + QString getDateTimeFormat() { + return dateTimeFormat; + } + + QString getDateFormat() { + return dateFormat; + } + +} //end namespace diff --git a/telegram_test/json.h b/telegram_test/json.h new file mode 100644 index 0000000..8992508 --- /dev/null +++ b/telegram_test/json.h @@ -0,0 +1,178 @@ +/** + * QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa. + * Copyright (C) 2011 Eeli Reilin + * + * 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 3 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 . + */ + +/** + * \file json.h + */ + +#ifndef JSON_H +#define JSON_H + +#include +#include + + +/** + * \namespace QtJson + * \brief A JSON data parser + * + * Json parses a JSON data into a QVariant hierarchy. + */ +namespace QtJson { + typedef QVariantMap JsonObject; + typedef QVariantList JsonArray; + + /** + * Clone a JSON object (makes a deep copy) + * + * \param data The JSON object + */ + QVariant clone(const QVariant &data); + + /** + * Insert value to JSON object (QVariantMap) + * + * \param v The JSON object + * \param key The key + * \param value The value + */ + void insert(QVariant &v, const QString &key, const QVariant &value); + + /** + * Append value to JSON array (QVariantList) + * + * \param v The JSON array + * \param value The value + */ + void append(QVariant &v, const QVariant &value); + + /** + * Parse a JSON string + * + * \param json The JSON data + */ + QVariant parse(const QString &json); + + /** + * Parse a JSON string + * + * \param json The JSON data + * \param success The success of the parsing + */ + QVariant parse(const QString &json, bool &success); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * + * \return QByteArray Textual JSON representation in UTF-8 + */ + QByteArray serialize(const QVariant &data); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * \param success The success of the serialization + * + * \return QByteArray Textual JSON representation in UTF-8 + */ + QByteArray serialize(const QVariant &data, bool &success); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * + * \return QString Textual JSON representation + */ + QString serializeStr(const QVariant &data); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * \param success The success of the serialization + * + * \return QString Textual JSON representation + */ + QString serializeStr(const QVariant &data, bool &success); + + /** + * This method sets date(time) format to be used for QDateTime::toString + * If QString is empty, Qt::TextDate is used. + * + * \param format The JSON data generated by the parser. + */ + void setDateTimeFormat(const QString& format); + void setDateFormat(const QString& format); + + /** + * This method gets date(time) format to be used for QDateTime::toString + * If QString is empty, Qt::TextDate is used. + */ + QString getDateTimeFormat(); + QString getDateFormat(); + + /** + * QVariant based Json object + */ + class Object : public QVariant { + template + Object& insertKey(Object* ptr, const QString& key) { + T* p = (T*)ptr->data(); + if (!p->contains(key)) p->insert(key, QVariant()); + return *reinterpret_cast(&p->operator[](key)); + } + template + void removeKey(Object *ptr, const QString& key) { + T* p = (T*)ptr->data(); + p->remove(key); + } + public: + Object() : QVariant() {} + Object(const Object& ref) : QVariant(ref) {} + + Object& operator=(const QVariant& rhs) { + setValue(rhs); + return *this; + } + Object& operator[](const QString& key) { + if (type() == QVariant::Map) + return insertKey(this, key); + else if (type() == QVariant::Hash) + return insertKey(this, key); + + setValue(QVariantMap()); + + return insertKey(this, key); + } + const Object& operator[](const QString& key) const { + return const_cast(this)->operator[](key); + } + void remove(const QString& key) { + if (type() == QVariant::Map) + removeKey(this, key); + else if (type() == QVariant::Hash) + removeKey(this, key); + } + }; +} + +#endif //JSON_H diff --git a/telegram_test/main.cpp b/telegram_test/main.cpp new file mode 100644 index 0000000..56da177 --- /dev/null +++ b/telegram_test/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/telegram_test/mainwindow.cpp b/telegram_test/mainwindow.cpp new file mode 100644 index 0000000..9536b37 --- /dev/null +++ b/telegram_test/mainwindow.cpp @@ -0,0 +1,67 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { + ui->setupUi(this); + connect(bot.getAPI(), SIGNAL(newMessage(TelegramBotAPI::Message)), this, SLOT(printMessage(TelegramBotAPI::Message))); + connect(bot.getAPI(), SIGNAL(newFile(TelegramBotAPI::File)), this, SLOT(printImage(TelegramBotAPI::File))); +// connect(&bot_timer, SIGNAL(timeout()), &bot, SLOT(updateBot())); +// bot_timer.start(1000); + bot.setBotToken("281218446:AAEaoS25kKZUevp98U-MKiaPGd2kS18d11g"); + ui->graphicsView->setScene(new QGraphicsScene()); + ui->graphicsView->setInteractive(false); + ui->graphicsView->setDragMode(QGraphicsView::ScrollHandDrag); +// bot.start(); +} + + +MainWindow::~MainWindow() { + delete ui; +} + + +void MainWindow::on_pushButton_1_clicked() { +// bot.setBotToken("281218446:AAEaoS25kKZUevp98U-MKiaPGd2kS18d11g"); +// bot.updateBot(); +// QImage img(800, 600, QImage::Format_ARGB32); +// img.fill(Qt::yellow); +// QByteArray ba; +// QBuffer buffer(&ba); +// buffer.open(QIODevice::WriteOnly); +// img.save(&buffer, "PNG"); +// if (!bot.sendMessageToAll(TelegramBotAPI::Photo, ba, "test.png")) ui->listWidget->addItem("send error"); +} + + +void MainWindow::on_pushButton_2_clicked() { + if (!ui->lineEdit->text().isEmpty()) { + bot.sendMessageToAll(ui->lineEdit->text()); + ui->listWidget->addItem(QDateTime::currentDateTime().toString() + " #" + bot.getAPI()->botName() + " : " + ui->lineEdit->text()); + ui->lineEdit->clear(); + } +} + + +void MainWindow::printMessage(TelegramBotAPI::Message msg) { + ui->listWidget->addItem(msg.time.toString() + " #" + msg.user_name + " : " + msg.text); + lid = msg.chat_id; +} + + +void MainWindow::printImage(TelegramBotAPI::File file) { + QImage img; + if (img.loadFromData(file.data)) { + QPixmap pix = QPixmap::fromImage(img); + QListWidgetItem * lwi = new QListWidgetItem(QIcon(pix), file.filename); + ui->listWidget->addItem(lwi); + ui->graphicsView->scene()->addPixmap(pix); + } +} + + +void MainWindow::on_lineEdit_editingFinished() { + on_pushButton_2_clicked(); +} diff --git a/telegram_test/mainwindow.h b/telegram_test/mainwindow.h new file mode 100644 index 0000000..8f8e476 --- /dev/null +++ b/telegram_test/mainwindow.h @@ -0,0 +1,37 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include "telegrambotbase.h" +#include "execbot.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_pushButton_1_clicked(); + void on_pushButton_2_clicked(); + void printMessage(TelegramBotAPI::Message msg); + void printImage(TelegramBotAPI::File file); + + void on_lineEdit_editingFinished(); + +private: + Ui::MainWindow *ui; + ExecBot bot; + uint lid; + QTimer bot_timer; +}; + +#endif // MAINWINDOW_H diff --git a/telegram_test/mainwindow.ui b/telegram_test/mainwindow.ui new file mode 100644 index 0000000..312ee66 --- /dev/null +++ b/telegram_test/mainwindow.ui @@ -0,0 +1,67 @@ + + + MainWindow + + + + 0 + 0 + 740 + 333 + + + + MainWindow + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + + Send + + + + + + + Send image + + + + + + + + + + QGraphicsView::RubberBandDrag + + + QGraphicsView::AnchorUnderMouse + + + + + + + + + + + diff --git a/telegram_test/telegram_test.pro b/telegram_test/telegram_test.pro new file mode 100644 index 0000000..54c6f94 --- /dev/null +++ b/telegram_test/telegram_test.pro @@ -0,0 +1,26 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-10-17T12:59:23 +# +#------------------------------------------------- + +QT += core gui network + +TARGET = telegram_test +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp \ + json.cpp \ + telegrambotapi.cpp \ + telegrambotbase.cpp \ + execbot.cpp + +HEADERS += mainwindow.h \ + json.h \ + telegrambotapi.h \ + telegrambotbase.h \ + execbot.h + +FORMS += mainwindow.ui diff --git a/telegram_test/telegram_test.pro.user b/telegram_test/telegram_test.pro.user new file mode 100644 index 0000000..d990533 --- /dev/null +++ b/telegram_test/telegram_test.pro.user @@ -0,0 +1,255 @@ + + + + + + EnvironmentId + {948faa78-0b50-402e-a285-1bca3b08de64} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + false + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + DesktopBuild + DesktopBuild + {3c749452-9483-442d-b011-933a1b5dac10} + 0 + 0 + 0 + + D:/Qt_projects/build-telegram_test-DesktopBuild-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + + + true + Сборка + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Отладка + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + D:/Qt_projects/build-telegram_test-DesktopBuild-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + + + true + Сборка + + Qt4ProjectManager.MakeStep + + false + + + + 2 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + true + clean + + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Выпуск + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + 0 + Установка + + ProjectExplorer.BuildSteps.Deploy + + 1 + Локальная установка + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 3 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + telegram_test + + Qt4ProjectManager.Qt4RunConfiguration:D:/Qt_projects/telegram_test/telegram_test.pro + + telegram_test.pro + false + false + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 16 + + + Version + 16 + + diff --git a/telegram_test/telegrambotapi.cpp b/telegram_test/telegrambotapi.cpp new file mode 100644 index 0000000..23bdc1f --- /dev/null +++ b/telegram_test/telegrambotapi.cpp @@ -0,0 +1,358 @@ +#include "telegrambotapi.h" +//#include +#include +#include +#include +#include +#include +#include "json.h" + + +const char * TelegramBotAPI::send_methods[] = { + "sendMessage", + "sendPhoto", + "sendDocument", + }; +const char * TelegramBotAPI::param_filename = "__filename"; + +TelegramBotAPI::TelegramBotAPI(QObject *parent) : QObject(parent) { + is_connected = false; + wait_server = false; + has_stop = false; + qRegisterMetaType("TelegramBotAPI::Message"); + qnam = new QNetworkAccessManager(); +// connect(qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpFinished(QNetworkReply*))); + connect(qnam, SIGNAL(sslErrors(QNetworkReply*,QList)), this, SLOT(sslErrors(QNetworkReply*,QList))); +} + + + TelegramBotAPI::~TelegramBotAPI() { + has_stop = true; +// msleep(60); +} + + +void TelegramBotAPI::setBotToken(QString arg) { + if (m_botToken == arg) { + checkBot(); + return; + } + is_connected = false; + m_botToken = arg; + botUrl = "https://api.telegram.org/bot"+m_botToken+"/"; + checkBot(); +} + + +bool TelegramBotAPI::sendMessage(uint chat_id, TelegramBotAPI::MessageType mtype, QByteArray data, QString filename) { + if (!is_connected || chat_id == 0 || data.isEmpty()) return false; + SendQuery sq; + sq.params["chat_id"] = chat_id; + sq.method = send_methods[mtype]; + bool ok = false; + switch (mtype) { + case Text: + sq.params["text"] = QString::fromUtf8(data.data(), data.size()); + ok = true; + break; + case Photo: + if (!filename.isEmpty()) { + sq.params[param_filename] = filename; + sq.params["photo"] = data; + ok = true; + } + break; + case Document: + if (!filename.isEmpty()) { + sq.params[param_filename] = filename; + sq.params["document"] = data; + ok = true; + } + break; + default: + break; + } + if (ok) { + sendmsg_que.enqueue(sq); + if (wait_server) { + if (reply->url().toString().split("/").last() == "getUpdates") reply->abort(); + } + } + return ok; +} + + +//void TelegramBot::run() { +// while (!has_stop) { +// mutex.lock(); +// if (qnam == 0) { +// qnam = new QNetworkAccessManager(); +// connect(qnam, SIGNAL(finished(QNetworkReply*)), +// this, SLOT(httpFinished(QNetworkReply*))); +// connect(qnam, SIGNAL(sslErrors(QNetworkReply*,QList)), this, SLOT(sslErrors(QNetworkReply*,QList))); +// } +// if (!wait_server) { +// if (!is_connected) checkBot(); +// updateBot(); +// } +// mutex.unlock(); +// msleep(50); +// } +//} + + +void TelegramBotAPI::updateBot() { + if (!is_connected) return; + QVariantMap vm; + vm["timeout"] = 50; + vm["offset"] = last_update; + sendRequest("getUpdates", vm); +} + + +bool TelegramBotAPI::fileDownload() { + if (download_list.isEmpty()) return false; + bool ok = false; + int rm = -1; + for(int i=0; iget(nr); + connect(reply, SIGNAL(finished()), this, SLOT(httpFinished())); + return true; + } else { + File f; + f.chat_id = df.chat_id; + f.filename = df.filename; + f.data = df.data; + emit newFile(f); + rm = i; + break; + } + } + } + if (rm >= 0) download_list.removeAt(rm); + return ok; +} + + +void TelegramBotAPI::checkBot() { + sendRequest("getMe", QVariantMap()); +} + + +bool TelegramBotAPI::parseHeader(QString json, QVariant & res) { + bool ok; + QVariantMap map = QtJson::parse(json, ok).toMap(); + if (!ok) { + emit errorOccured("parse JSON error"); + return false; + } + if (!map.value("ok").toBool()) { + emit errorOccured("query error"); + return false; + } + res = map.value("result"); + return !res.isNull() && res.isValid(); +} + + +void TelegramBotAPI::parseCheckBot(QString json) { + QVariant res; + if (!parseHeader(json, res)) { + is_connected = false; + emit botFail(); + return; + } + QVariantMap resm = res.toMap(); + m_botID = resm.value("id").toUInt(); + m_botName = resm.value("username").toString(); + is_connected = true; + last_update = 0; + emit botOK(); +} + + +void TelegramBotAPI::parseFile(QString json) { + QVariant res; + if (!parseHeader(json, res)) { + emit errorOccured("can't get file"); + return; + } + QVariantMap resm = res.toMap(); + QString fpath = resm["file_path"].toString(); + QString fid = resm["file_id"].toString(); + if (fpath.isEmpty()) return; + QUrl furl = QUrl("https://api.telegram.org/file/bot"+m_botToken+"/"+fpath); + qDebug() << "new file :" << furl; + for (int i=0; i 0) { + emit newMessage(m); + emit newMessage(m.chat_id, m.text); + } + } + last_update++; + //qDebug() << "update_id" << last_update; +} + + +void TelegramBotAPI::startDownloadFile(uint chat_id, QVariantMap file) { + if (!file.isEmpty()) { + DownloadFile df; + df.downloaded = false; + df.id = file["file_id"].toString(); + df.chat_id = chat_id; + df.filename = file["file_name"].toString(); + qDebug() << "new incomming file" << df.id; + download_list << df; + } +} + + +TelegramBotAPI::Message TelegramBotAPI::parseMessage(QVariant msg) { + Message ret; + QVariantMap map = msg.toMap(); + ret.id = map.value("message_id", 0).toUInt(); + QVariantMap chat = map.value("chat").toMap(); + ret.chat_id = chat.value("id", 0).toUInt(); + QVariantMap user = map.value("from").toMap(); + ret.user_id = user.value("id", 0).toUInt(); + ret.user_name = user.value("first_name").toString(); + ret.text = map.value("text").toString(); + ret.time = QDateTime::fromTime_t(map.value("date").toUInt()); + QVariantMap file; + QVariantList photo = map.value("photo").toList(); + if (!photo.isEmpty()) { + startDownloadFile(ret.chat_id, photo.last().toMap()); + } + QVariantMap docum = map.value("document").toMap(); + startDownloadFile(ret.chat_id, docum); + return ret; +} + + +void TelegramBotAPI::sslErrors(QNetworkReply*,const QList &errors) { + QString errorString; + foreach (const QSslError &error, errors) { + if (!errorString.isEmpty()) + errorString += ", "; + errorString += error.errorString(); + } + emit errorOccured(errorString); +// if (QMessageBox::warning(0, QString("HTTP"), QString("One or more SSL errors has occurred: %1").arg(errorString), +// QMessageBox::Ignore | QMessageBox::Abort, QMessageBox::Ignore) +// == QMessageBox::Ignore) { +// reply->ignoreSslErrors(); +// } +} + + +void TelegramBotAPI::httpFinished() { +// qDebug() << "reply finished"; +// mutex.lock(); + QByteArray ba = reply->readAll(); + QStringList quest_path = reply->url().toString().split("/"); +// qDebug() << "quest list =" << quest_path.size(); + QString quest = quest_path.last(); + reply->deleteLater(); + wait_server = false; +// mutex.unlock(); + if (quest_path.size() == 5) { + QString s = QString::fromUtf8(ba.data(), ba.size()); + // qDebug() << quest << s; + // if (quest.indexOf("?") > 0) + // quest.resize(quest.indexOf('?')); + QVariant tmp; + if (quest == "getMe") parseCheckBot(s); + if (quest == "getFile") parseFile(s); + if (quest == "getUpdates") parseMessages(s); + if (quest == "sendMessage") parseHeader(s, tmp); + qDebug() << "parse done" << quest << s; + } else { + for (int i=0; iurl()) { + download_list[i].data = ba; + download_list[i].downloaded = true; + break; + } + } + } + if (is_connected) { + if (!fileDownload()) { + if (sendmsg_que.isEmpty()) updateBot(); + else { + SendQuery sq = sendmsg_que.dequeue(); + sendRequest(sq.method, sq.params); + } + } + } else checkBot(); +} + + +//void TelegramBot::httpFinished(QNetworkReply *) { +// qDebug() << "get finished"; +//} + + +void TelegramBotAPI::sendRequest(QString method, QVariantMap params) { + wait_server = true; + qDebug() << "startRequest:" << method; + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + + QString filename = params.take(param_filename).toString(); + QMapIterator it(params); + while (it.hasNext()) { + it.next(); + QHttpPart part; + if (it.value().type() == QVariant::ByteArray) { + part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; filename=\""+filename+"\"; name=\""+it.key()+"\"")); + qDebug() << "sending photo" << double(it.value().toByteArray().size()) / (1024*1024); + part.setBody(it.value().toByteArray()); + } else { + part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\""+it.key()+"\"")); + part.setBody(it.value().toString().toUtf8()); + } + multiPart->append(part); + } + if (params.isEmpty()) { + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\"")); + multiPart->append(part); + } + QNetworkRequest nr; + nr.setUrl(QUrl(botUrl + method)); + reply = qnam->post(nr, multiPart); + multiPart->setParent(reply); // delete the multiPart with the reply + connect(reply, SIGNAL(finished()), this, SLOT(httpFinished())); +// connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead())); +// connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDataReadProgress(qint64,qint64))); +} diff --git a/telegram_test/telegrambotapi.h b/telegram_test/telegrambotapi.h new file mode 100644 index 0000000..055d850 --- /dev/null +++ b/telegram_test/telegrambotapi.h @@ -0,0 +1,119 @@ +#ifndef TELEGRAMBOTAPI_H +#define TELEGRAMBOTAPI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class TelegramBotAPI : public QObject +{ + Q_OBJECT + Q_PROPERTY(uint botID READ botID) + Q_PROPERTY(QString botName READ botName) + Q_PROPERTY(QString botToken READ botToken WRITE setBotToken) +public: + explicit TelegramBotAPI(QObject *parent = 0); + ~TelegramBotAPI(); + + enum MessageType { + Text, + Photo, + Document, + }; + + struct Message { + Message() { + chat_id = id = user_id = 0; + } + uint id; + uint chat_id; + uint user_id; + QString user_name; + QString text; + QDateTime time; + }; + struct File { + uint chat_id; + QString filename; + QByteArray data; + }; + + uint botID() const {return m_botID;} + QString botToken() const {return m_botToken;} + QString botName() const {return m_botName;} + bool isConnected() const {return is_connected;} + +public slots: + void setBotToken(QString arg); + bool sendMessage(uint chat_id, QString msg) {return sendMessage(chat_id, TelegramBotAPI::Text, msg.toUtf8());} + bool sendMessage(uint chat_id, MessageType mtype, QByteArray data, QString filename = QString()); + +private: + + struct SendQuery { + QString method; + QVariantMap params; + }; + + struct DownloadFile { + bool downloaded; + int chat_id; + QString id; + QString filename; + QUrl url; + QByteArray data; + }; + + static const char * send_methods[]; + static const char * param_filename; + +// void run(); + void sendRequest(QString method, QVariantMap params); + void checkBot(); + void updateBot(); + bool fileDownload(); + bool parseHeader(QString json, QVariant &res); + void parseCheckBot(QString json); + void parseMessages(QString json); + void parseFile(QString json); + Message parseMessage(QVariant msg); + void startDownloadFile(uint chat_id, QVariantMap file); + + QNetworkAccessManager * qnam; + QNetworkReply *reply; +// QMutex mutex; + uint m_botID; + QString m_botToken; + QString botUrl; + QString botUrlFile; + QString m_botName; + bool is_connected; + int last_update; + bool wait_server; + bool has_stop; + QQueue sendmsg_que; + QList download_list; + +private slots: + void sslErrors(QNetworkReply*, const QList &errors); + void httpFinished(); +// void httpFinished(QNetworkReply*); + +signals: + void botOK(); + void botFail(); + void errorOccured(QString error); + void newMessage(TelegramBotAPI::Message msg); + void newMessage(uint chat_id, QString msg); + void newFile(TelegramBotAPI::File file); +}; + +Q_DECLARE_METATYPE(TelegramBotAPI::Message) + +#endif // TELEGRAMBOTAPI_H diff --git a/telegram_test/telegrambotbase.cpp b/telegram_test/telegrambotbase.cpp new file mode 100644 index 0000000..fe0f5e8 --- /dev/null +++ b/telegram_test/telegrambotbase.cpp @@ -0,0 +1,79 @@ +#include "telegrambotbase.h" +#include +#include + +TelegramBotBase::TelegramBotBase(QObject *parent) : QObject(parent) { +// connect(&api, SIGNAL(newMessage(TelegramBotAPI::Message)), this, SLOT(processMessage(TelegramBotAPI::Message)), Qt::QueuedConnection); + connect(&api, SIGNAL(newMessage(TelegramBotAPI::Message)), this, SLOT(processMessage(TelegramBotAPI::Message))); +} + + +void TelegramBotBase::sendMessageToAll(const QString &message) { + QList keys = users.keys(); + foreach (uint cid, keys) { + if (users[cid].logged_in) + api.sendMessage(cid, message); + } +} + + +void TelegramBotBase::processMessage(TelegramBotAPI::Message msg) { +// QApplication::processEvents(); + qDebug() << "[TelegramBotBase]" << msg.text; + uint cid = msg.chat_id; + User m; + m.user_id = msg.user_id; + m.user_name = msg.user_name; + m.last_timestamp = msg.time; + if (!users.contains(cid)) users[cid] = m; + if (users[cid].logged_in) { + if (msg.text == "/help") { + api.sendMessage(cid, help()); + return; + } + messageFromUser(cid, msg.text); + } else { + if (loginUser(cid, msg.text)) { + users[cid].logged_in = true; + api.sendMessage(cid, welcome(cid)); + newUser(cid, users[cid]); + } else { + api.sendMessage(cid, loginMessage(cid)); + } + return; + } +} + + +QString TelegramBotBase::welcome(uint id) { + User user = getUser(id); + return tr("Hello %1! I am @%2.").arg(user.user_name).arg(api.botName()); +} + + +QString TelegramBotBase::loginMessage(uint) { + return tr("Please send me /start"); +} + + +QString TelegramBotBase::help() { + return tr("Sorry, /help not implemented in @%1.").arg(api.botName()); +} + + +bool TelegramBotBase::loginUser(uint , const QString &msg) { + return (msg == "/start"); +} + + +void TelegramBotBase::messageFromUser(uint id, const QString &msg) { + if (msg.toLower() == "ping") api.sendMessage(id, "pong"); +} + + +void TelegramBotBase::newUser(uint, User) {} + +void TelegramBotBase::disconnectUser(uint id) { + users.remove(id); +} + diff --git a/telegram_test/telegrambotbase.h b/telegram_test/telegrambotbase.h new file mode 100644 index 0000000..b6ecd17 --- /dev/null +++ b/telegram_test/telegrambotbase.h @@ -0,0 +1,54 @@ +#ifndef TELEGRAMBOTBASE_H +#define TELEGRAMBOTBASE_H + +#include +#include "telegrambotapi.h" + +class TelegramBotBase : public QObject +{ + Q_OBJECT +public: + explicit TelegramBotBase(QObject *parent = 0); + TelegramBotAPI * getAPI() {return &api;} + + + +public slots: + void sendMessageToAll(const QString & message); + void setBotToken(QString token) {api.setBotToken(token);} + +protected: + struct User { + User() { + user_id = 0; + logged_in = false; + } + uint user_id; + bool logged_in; + QString user_name; + QDateTime last_timestamp; + }; + + const User & getUser(uint id) {return users[id];} + virtual QString welcome(uint id); + virtual QString loginMessage(uint id); + virtual QString help(); + virtual bool loginUser(uint id, const QString & msg); + virtual void messageFromUser(uint id, const QString & msg); + virtual void newUser(uint id, User user); + void disconnectUser(uint id); + +private slots: + void processMessage(TelegramBotAPI::Message msg); + +private: + QMap users; + TelegramBotAPI api; + + QString m_botToken; + +signals: + +}; + +#endif // TELEGRAMBOTBASE_H