void AddFriendForm::onSendTriggered() { QString id = toxId.text().trimmed(); if (!ToxId::isToxId(id)) { ToxId toxId = Toxme::lookup(id); // Try Toxme if (toxId.toString().isEmpty()) { GUI::showWarning(tr("Couldn't add friend"), tr("This Tox ID does not exist", "Toxme error")); return; } id = toxId.toString(); } deleteFriendRequest(id); if (id.toUpper() == Core::getInstance()->getSelfId().toString().toUpper()) GUI::showWarning(tr("Couldn't add friend"), tr("You can't add yourself as a friend!", "When trying to add your own Tox ID as friend")); else emit friendRequested(id, getMessage()); this->toxId.clear(); this->message.clear(); }
void Core::requestFriendship(const ToxId& friendId, const QString& message) { ToxPk friendPk = friendId.getPublicKey(); QString errorMessage = getFriendRequestErrorMessage(friendId, message); if (!errorMessage.isNull()) { emit failedToAddFriend(friendPk, errorMessage); profile.saveToxSave(); } ToxString cMessage(message); uint32_t friendNumber = tox_friend_add(tox, friendId.getBytes(), cMessage.data(), cMessage.size(), nullptr); if (friendNumber == std::numeric_limits<uint32_t>::max()) { qDebug() << "Failed to request friendship"; emit failedToAddFriend(friendPk); } else { qDebug() << "Requested friendship of " << friendNumber; Settings::getInstance().updateFriendAddress(friendId.toString()); emit friendAdded(friendNumber, friendPk); emit requestSent(friendPk, message); } profile.saveToxSave(); }
void ProfileForm::setToxId(const ToxId& id) { toxId->setText(id.toString()); toxId->setCursorPosition(0); delete qr; qr = new QRWidget(); qr->setQRData("tox:" + id.toString()); bodyUI->qrCode->setPixmap(QPixmap::fromImage(qr->getImage()->scaledToWidth(150))); }
QString Toxme::createAddress(ExecCode &code, QString server, ToxId id, QString address, bool keepPrivate, QString bio) { int privacy = keepPrivate ? 0 : 2; // JSON injection ? bio.replace('\\',"\\\\"); bio.replace('"',"\""); address.replace('\\',"\\\\"); address.replace('"',"\""); bio = bio.trimmed(); address = address.trimmed(); server = server.trimmed(); if (!server.contains("://")) server = "https://" + server; const QString payload{"{\"tox_id\":\""+id.toString()+"\"," "\"name\":\""+address+"\"," "\"privacy\":"+QString().setNum(privacy)+"," "\"bio\":\""+bio+"\"," "\"timestamp\":"+QString().setNum(time(0))+"}"}; QString pubkeyUrl = server + "/pk"; QString apiUrl = server + "/api"; QNetworkReply::NetworkError error = QNetworkReply::NoError; QByteArray encrypted = prepareEncryptedJson(pubkeyUrl, 1, payload); QByteArray response = makeJsonRequest(apiUrl, encrypted, error); code = extractError(response); if ((code != Ok && code != Updated) || error != QNetworkReply::NoError) return QString(); return getPass(response, code); }
QString Core::getPeerName(const ToxId& id) const { QString name; CUserId cid(id.toString()); uint32_t friendId = tox_friend_by_public_key(tox, (uint8_t*)cid.data(), nullptr); if (friendId == std::numeric_limits<uint32_t>::max()) { qWarning() << "getPeerName: No such peer"; return name; } const size_t nameSize = tox_friend_get_name_size(tox, friendId, nullptr); if (nameSize == SIZE_MAX) return name; uint8_t* cname = new uint8_t[nameSize<TOX_MAX_NAME_LENGTH ? TOX_MAX_NAME_LENGTH : nameSize]; if (!tox_friend_get_name(tox, friendId, cname, nullptr)) { qWarning() << "getPeerName: Can't get name of friend "+QString().setNum(friendId); delete[] cname; return name; } name = CString::toString(cname, nameSize); delete[] cname; return name; }
/** * @brief Checks that sending friendship request is correct and returns error message accordingly * @param friendId Id of a friend which request is destined to * @param message Friendship request message * @return Returns empty string if sending request is correct, according error message otherwise */ QString Core::getFriendRequestErrorMessage(const ToxId& friendId, const QString& message) const { if (!friendId.isValid()) { return tr("Invalid Tox ID", "Error while sending friendship request"); } if (message.isEmpty()) { return tr("You need to write a message with your request", "Error while sending friendship request"); } if (message.length() > TOX_MAX_FRIEND_REQUEST_LENGTH) { return tr("Your message is too long!", "Error while sending friendship request"); } if (hasFriendWithPublicKey(friendId.getPublicKey())) { return tr("Friend is already added", "Error while sending friendship request"); } return QString{}; }
int Toxme::deleteAddress(QString server, ToxId id) { const QString payload{"{\"public_key\":\""+id.toString().left(64)+"\"," "\"timestamp\":"+QString().setNum(time(0))+"}"}; server = server.trimmed(); if (!server.contains("://")) server = "https://" + server; QString pubkeyUrl = server + "/pk"; QString apiUrl = server + "/api"; QNetworkReply::NetworkError error = QNetworkReply::NoError; QByteArray response = makeJsonRequest(apiUrl, prepareEncryptedJson(pubkeyUrl, 2, payload), error); return extractError(response); }
void Settings::setContactNote(const ToxId &id, const QString& note) { QMutexLocker locker{&bigLock}; auto it = friendLst.find(id.publicKey); if (it != friendLst.end()) { qDebug() << note; it->note = note; } else { updateFriendAdress(id.toString()); setContactNote(id, note); } }
void Settings::setAutoAcceptDir(const ToxId &id, const QString& dir) { QMutexLocker locker{&bigLock}; QString key = id.publicKey; auto it = friendLst.find(key); if (it != friendLst.end()) { it->autoAcceptDir = dir; } else { updateFriendAdress(id.toString()); setAutoAcceptDir(id, dir); } }
void ChatForm::loadHistory(QDateTime since, bool processUndelivered) { QDateTime now = historyBaselineDate.addMSecs(-1); if (since > now) return; if (!earliestMessage.isNull()) { if (earliestMessage < since) return; if (earliestMessage < now) { now = earliestMessage; now = now.addMSecs(-1); } } auto msgs = HistoryKeeper::getInstance()->getChatHistory(HistoryKeeper::ctSingle, f->getToxID().publicKey, since, now); ToxId storedPrevId = previousId; ToxId prevId; QList<ChatLine::Ptr> historyMessages; QDate lastDate(1,0,0); for (const auto &it : msgs) { // Show the date every new day QDateTime msgDateTime = it.timestamp.toLocalTime(); QDate msgDate = msgDateTime.date(); if (msgDate > lastDate) { lastDate = msgDate; historyMessages.append(ChatMessage::createChatInfoMessage(msgDate.toString(Settings::getInstance().getDateFormat()), ChatMessage::INFO, QDateTime())); } // Show each messages ToxId authorId = ToxId(it.sender); QString authorStr = authorId.isActiveProfile() ? Core::getInstance()->getUsername() : resolveToxID(authorId); bool isAction = it.message.startsWith("/me ", Qt::CaseInsensitive); ChatMessage::Ptr msg = ChatMessage::createChatMessage(authorStr, isAction ? it.message.right(it.message.length() - 4) : it.message, isAction ? ChatMessage::ACTION : ChatMessage::NORMAL, authorId.isActiveProfile(), QDateTime()); if (!isAction && (prevId == authorId) && (prevMsgDateTime.secsTo(msgDateTime) < getChatLog()->repNameAfter) ) msg->hideSender(); prevId = authorId; prevMsgDateTime = msgDateTime; if (it.isSent || !authorId.isActiveProfile()) { msg->markAsSent(msgDateTime); } else { if (processUndelivered) { int rec; if (!isAction) rec = Core::getInstance()->sendMessage(f->getFriendID(), msg->toString()); else rec = Core::getInstance()->sendAction(f->getFriendID(), msg->toString()); getOfflineMsgEngine()->registerReceipt(rec, it.id, msg); } } historyMessages.append(msg); } previousId = storedPrevId; int savedSliderPos = chatWidget->verticalScrollBar()->maximum() - chatWidget->verticalScrollBar()->value(); earliestMessage = since; chatWidget->insertChatlineOnTop(historyMessages); savedSliderPos = chatWidget->verticalScrollBar()->maximum() - savedSliderPos; chatWidget->verticalScrollBar()->setValue(savedSliderPos); }
/** * @brief Compares the inequality of the Public Key. * @param other Tox ID to compare. * @return True if both Tox IDs have different public keys, false otherwise. */ bool ToxId::operator!=(const ToxId& other) const { return getPublicKey() != other.getPublicKey(); }
/** * @brief Initializes the core, must be called before anything else */ void Core::start(const QByteArray& savedata) { bool isNewProfile = profile.isNewProfile(); if (isNewProfile) { qDebug() << "Creating a new profile"; makeTox(QByteArray()); makeAv(); setStatusMessage(tr("Toxing on qTox")); setUsername(profile.getName()); } else { qDebug() << "Loading user profile"; if (savedata.isEmpty()) { emit failedToStart(); return; } makeTox(savedata); makeAv(); } qsrand(time(nullptr)); if (!tox) { ready = true; GUI::setEnabled(true); return; } // set GUI with user and statusmsg QString name = getUsername(); if (!name.isEmpty()) { emit usernameSet(name); } QString msg = getStatusMessage(); if (!msg.isEmpty()) { emit statusMessageSet(msg); } ToxId id = getSelfId(); // TODO: probably useless check, comes basically directly from toxcore if (id.isValid()) { emit idSet(id); } loadFriends(); tox_callback_friend_request(tox, onFriendRequest); tox_callback_friend_message(tox, onFriendMessage); tox_callback_friend_name(tox, onFriendNameChange); tox_callback_friend_typing(tox, onFriendTypingChange); tox_callback_friend_status_message(tox, onStatusMessageChanged); tox_callback_friend_status(tox, onUserStatusChanged); tox_callback_friend_connection_status(tox, onConnectionStatusChanged); tox_callback_friend_read_receipt(tox, onReadReceiptCallback); tox_callback_conference_invite(tox, onGroupInvite); tox_callback_conference_message(tox, onGroupMessage); tox_callback_conference_namelist_change(tox, onGroupNamelistChange); tox_callback_conference_title(tox, onGroupTitleChange); tox_callback_file_chunk_request(tox, CoreFile::onFileDataCallback); tox_callback_file_recv(tox, CoreFile::onFileReceiveCallback); tox_callback_file_recv_chunk(tox, CoreFile::onFileRecvChunkCallback); tox_callback_file_recv_control(tox, CoreFile::onFileControlCallback); QByteArray data = profile.loadAvatarData(getSelfPublicKey().toString()); if (data.isEmpty()) { qDebug() << "Self avatar not found, will broadcast empty avatar to friends"; } setAvatar(data); ready = true; if (isNewProfile) { profile.saveToxSave(); } if (isReady()) { GUI::setEnabled(true); } process(); // starts its own timer av->start(); }
void Core::requestFriendship(const ToxId& friendAddress, const QString& message) { ToxPk friendPk = friendAddress.getPublicKey(); if (!friendAddress.isValid()) { emit failedToAddFriend(friendPk, tr("Invalid Tox ID")); } else if (message.isEmpty()) { emit failedToAddFriend(friendPk, tr("You need to write a message with your request")); } else if (message.size() > TOX_MAX_FRIEND_REQUEST_LENGTH) { emit failedToAddFriend(friendPk, tr("Your message is too long!")); } else if (hasFriendWithPublicKey(friendPk)) { emit failedToAddFriend(friendPk, tr("Friend is already added")); } else { CString cMessage(message); uint32_t friendId = tox_friend_add(tox, friendAddress.getBytes(), cMessage.data(), cMessage.size(), nullptr); if (friendId == std::numeric_limits<uint32_t>::max()) { qDebug() << "Failed to request friendship"; emit failedToAddFriend(friendPk); } else { qDebug() << "Requested friendship of " << friendId; // Update our friendAddresses Settings::getInstance().updateFriendAddress(friendAddress.toString()); // TODO: start: this really shouldn't be in Core QString inviteStr = tr("/me offers friendship."); if (message.length()) inviteStr = tr("/me offers friendship, \"%1\"").arg(message); Profile* profile = Nexus::getProfile(); if (profile->isHistoryEnabled()) { profile->getHistory()->addNewMessage(friendAddress.toString(), inviteStr, getSelfId().getPublicKey().toString(), QDateTime::currentDateTime(), true, QString()); } // TODO: end emit friendAdded(friendId, friendAddress.getPublicKey()); emit friendshipChanged(friendId); } } profile.saveToxSave(); }
/** * @brief Initializes the core, must be called before anything else */ void Core::start() { bool isNewProfile = profile.isNewProfile(); if (isNewProfile) { qDebug() << "Creating a new profile"; makeTox(QByteArray()); setStatusMessage(tr("Toxing on qTox")); setUsername(profile.getName()); } else { qDebug() << "Loading user profile"; QByteArray savedata = profile.loadToxSave(); if (savedata.isEmpty()) { emit failedToStart(); return; } makeTox(savedata); } qsrand(time(nullptr)); if (!tox) { ready = true; GUI::setEnabled(true); return; } // set GUI with user and statusmsg QString name = getUsername(); if (!name.isEmpty()) emit usernameSet(name); QString msg = getStatusMessage(); if (!msg.isEmpty()) emit statusMessageSet(msg); ToxId id = getSelfId(); if (id.isValid()) // TODO: probably useless check, comes basically directly from toxcore emit idSet(id); // TODO: This is a backwards compatibility check, // once most people have been upgraded away from the old HistoryKeeper, remove this if (Nexus::getProfile()->isEncrypted()) checkEncryptedHistory(); loadFriends(); tox_callback_friend_request(tox, onFriendRequest); tox_callback_friend_message(tox, onFriendMessage); tox_callback_friend_name(tox, onFriendNameChange); tox_callback_friend_typing(tox, onFriendTypingChange); tox_callback_friend_status_message(tox, onStatusMessageChanged); tox_callback_friend_status(tox, onUserStatusChanged); tox_callback_friend_connection_status(tox, onConnectionStatusChanged); tox_callback_friend_read_receipt(tox, onReadReceiptCallback); tox_callback_conference_invite(tox, onGroupInvite); tox_callback_conference_message(tox, onGroupMessage); tox_callback_conference_namelist_change(tox, onGroupNamelistChange); tox_callback_conference_title(tox, onGroupTitleChange); tox_callback_file_chunk_request(tox, CoreFile::onFileDataCallback); tox_callback_file_recv(tox, CoreFile::onFileReceiveCallback); tox_callback_file_recv_chunk(tox, CoreFile::onFileRecvChunkCallback); tox_callback_file_recv_control(tox, CoreFile::onFileControlCallback); QPixmap pic = profile.loadAvatar(); if (!pic.isNull() && !pic.size().isEmpty()) { QByteArray data; QBuffer buffer(&data); buffer.open(QIODevice::WriteOnly); pic.save(&buffer, "PNG"); buffer.close(); setAvatar(data); } else { qDebug() << "Self avatar not found, will broadcast empty avatar to friends"; setAvatar({}); } ready = true; if (isNewProfile) { profile.saveToxSave(); } if (isReady()) GUI::setEnabled(true); process(); // starts its own timer av->start(); }