git-svn-id: svn://db.shs.com.ru/libs@297 a8b55f48-bf90-11e4-a774-851b48703e85

This commit is contained in:
2017-10-13 18:44:19 +00:00
parent 52f492f0d6
commit 511a8a3eea
10 changed files with 0 additions and 1650 deletions

View File

@@ -1,174 +0,0 @@
#include "execbot.h"
#include <QDebug>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QTextCodec>
ExecBot::ExecBot(QObject *parent) : TelegramBotBase(parent) {
connect(getAPI(), SIGNAL(newFile(TelegramBotAPI::File)), this, SLOT(saveFile(TelegramBotAPI::File)));
}
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 == "rootpasswd") {
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; i<run_commands.size(); i++) {
if (run_commands[i].user == id) {
run_commands[i].cmd->terminate();
getAPI()->sendMessage(id, tr("Process killed"));
sessions[id] = Ready;
rm = i;
}
}
if (rm >= 0) {
run_commands[rm].cmd->deleteLater();
run_commands.remove(rm);
}
} else
getAPI()->sendMessage(id, tr("Command is running, please wait for finish"));
return;
}
if (sessions[id] == Ready) {
if (msg.startsWith("/download")) {
QFile f;
f.setFileName(msg.mid(9).trimmed());
if (f.open(QIODevice::ReadOnly)) {
QByteArray ba = f.readAll();
getAPI()->sendMessage(id, TelegramBotAPI::Document, ba, QFileInfo(f).fileName());
} else
getAPI()->sendMessage(id, tr("File not found"));
return;
}
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; i<run_commands.size(); i++) {
if (run_commands[i].cmd == p) {
int id = run_commands[i].user;
#ifdef WIN32
QTextCodec *codec = QTextCodec::codecForName("IBM 866");
#else
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#endif
QString s = codec->toUnicode(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; i<run_commands.size(); i++) {
if (run_commands[i].cmd == p) {
int id = run_commands[i].user;
#ifdef WIN32
QTextCodec *codec = QTextCodec::codecForName("IBM 866");
#else
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#endif
QString s = codec->toUnicode(p->readAll());
getAPI()->sendMessage(id, s);
rm = i;
sessions[id] = Ready;
}
}
if (rm >= 0) {
run_commands[rm].cmd->deleteLater();
getAPI()->sendMessage(run_commands[rm].user, tr("Command finished with code %1").arg(code));
run_commands.remove(rm);
}
}
void ExecBot::saveFile(TelegramBotAPI::File fl) {
if (sessions.contains(fl.chat_id)) {
if (sessions[fl.chat_id] == Ready) {
QFile f;
QDir::current().mkdir("uploads");
f.setFileName("uploads/" + fl.filename);
if (f.open(QIODevice::ReadWrite)) {
f.resize(0);
f.write(fl.data);
getAPI()->sendMessage(fl.chat_id, tr("File received"));
} else {
getAPI()->sendMessage(fl.chat_id, tr("Can't write file"));
}
} else {
getAPI()->sendMessage(fl.chat_id, loginMessage(fl.chat_id));
}
} else {
getAPI()->sendMessage(fl.chat_id, tr("Please send me /start"));
}
}

View File

@@ -1,47 +0,0 @@
#ifndef EXECBOT_H
#define EXECBOT_H
#include "telegrambotbase.h"
#include <QProcess>
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<uint, UserState> sessions;
QVector<ExecBot::UserCommand> run_commands;
private slots:
void cmdRead();
void cmdFinish(int code);
void saveFile(TelegramBotAPI::File fl);
signals:
};
#endif // EXECBOT_H

View File

@@ -1,603 +0,0 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* \file json.cpp
*/
#include <QDateTime>
#include <QStringList>
#include "json.h"
namespace QtJson {
static QString dateFormat, dateTimeFormat;
static QString sanitizeString(QString str);
static QByteArray join(const QList<QByteArray> &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<typename T>
QByteArray serializeMap(const T &map, bool &success) {
QByteArray str = "{ ";
QList<QByteArray> 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<typename T>
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<typename T>
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<QVariantMap>()) 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<QVariantList>()) 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<QByteArray> 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<qulonglong>());
} else if (data.canConvert<qlonglong>()) { // any signed number?
str = QByteArray::number(data.value<qlonglong>());
} else if (data.canConvert<long>()) { //TODO: this code is never executed because all smaller types can be converted to qlonglong
str = QString::number(data.value<long>()).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<QString>()) { // 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<QByteArray> &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

View File

@@ -1,178 +0,0 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* \file json.h
*/
#ifndef JSON_H
#define JSON_H
#include <QVariant>
#include <QString>
/**
* \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<typename T>
Object& insertKey(Object* ptr, const QString& key) {
T* p = (T*)ptr->data();
if (!p->contains(key)) p->insert(key, QVariant());
return *reinterpret_cast<Object*>(&p->operator[](key));
}
template<typename T>
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<QVariantMap>(this, key);
else if (type() == QVariant::Hash)
return insertKey<QVariantHash>(this, key);
setValue(QVariantMap());
return insertKey<QVariantMap>(this, key);
}
const Object& operator[](const QString& key) const {
return const_cast<Object*>(this)->operator[](key);
}
void remove(const QString& key) {
if (type() == QVariant::Map)
removeKey<QVariantMap>(this, key);
else if (type() == QVariant::Hash)
removeKey<QVariantHash>(this, key);
}
};
}
#endif //JSON_H

View File

@@ -1,13 +0,0 @@
//#include "mainwindow.h"
#include "execbot.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//MainWindow w;
//w.show();
ExecBot bot;
bot.setBotToken("242608352:AAFrx51P_JhmCjV8CV11Mds-LJk89bpolXE");
return a.exec();
}

View File

@@ -1,25 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2016-10-17T12:59:23
#
#-------------------------------------------------
QT += core gui network
TARGET = telegram_bot
TEMPLATE = app
SOURCES += main.cpp\
json.cpp \
telegrambotapi.cpp \
telegrambotbase.cpp \
execbot.cpp
HEADERS += \
json.h \
telegrambotapi.h \
telegrambotbase.h \
execbot.h
FORMS +=

View File

@@ -1,358 +0,0 @@
#include "telegrambotapi.h"
//#include <QMessageBox>
#include <QSslError>
#include <QDebug>
#include <QStringList>
#include <QDateTime>
#include <QHttpMultiPart>
#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>("TelegramBotAPI::Message");
qnam = new QNetworkAccessManager();
// connect(qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpFinished(QNetworkReply*)));
connect(qnam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
}
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<QSslError>)), this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
// }
// 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; i<download_list.size(); i++) {
DownloadFile & df = download_list[i];
qDebug() << df.id << df.url << df.filename;
if (df.url.isEmpty()) {
QVariantMap fm;
fm["file_id"] = df.id;
sendRequest("getFile", fm);
return true;
} else {
if (!df.downloaded) {
QNetworkRequest nr;
nr.setUrl(df.url);
reply = qnam->get(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<download_list.size(); i++) {
if (download_list[i].id == fid) {
download_list[i].url = furl;
if (download_list[i].filename.isEmpty())
download_list[i].filename = fpath.split("/").last();
}
}
}
void TelegramBotAPI::parseMessages(QString json) {
QVariant res;
if (!parseHeader(json, res)) {
emit errorOccured("can't update");
return;
}
QVariantList resm = res.toList();
foreach (QVariant v, resm) {
QVariantMap mm = v.toMap();
last_update = mm.value("update_id").toInt();
Message m = parseMessage(mm.value("message"));
if (m.id > 0 && !m.text.isEmpty()) {
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<QSslError> &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; i<download_list.size(); ++i) {
if (download_list[i].url == reply->url()) {
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<QString, QVariant> 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 file" << double(it.value().toByteArray().size()) / (1024*1024) << "Mb";
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)));
}

View File

@@ -1,119 +0,0 @@
#ifndef TELEGRAMBOTAPI_H
#define TELEGRAMBOTAPI_H
#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDateTime>
#include <QMutex>
#include <QQueue>
#include <QImage>
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<SendQuery> sendmsg_que;
QList<DownloadFile> download_list;
private slots:
void sslErrors(QNetworkReply*, const QList<QSslError> &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

View File

@@ -1,79 +0,0 @@
#include "telegrambotbase.h"
#include <QDebug>
#include <QCoreApplication>
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<uint> 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);
}

View File

@@ -1,54 +0,0 @@
#ifndef TELEGRAMBOTBASE_H
#define TELEGRAMBOTBASE_H
#include <QObject>
#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<uint, User> users;
TelegramBotAPI api;
QString m_botToken;
signals:
};
#endif // TELEGRAMBOTBASE_H