#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 && !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 &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 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))); }