git-svn-id: svn://db.shs.com.ru/libs@297 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 +=
|
||||
@@ -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)));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user