/*
(c) Copyright 2012 - 2018 Anton Sviridenko
https://picapica.im
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, version 3.
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 .
*/
#include "skynet.h"
#include "globals.h"
#include
//#include "dialogs/viewcertdialog.h"
#include "contacts.h"
#include "openssltool.h"
//#include //debug
//#include "dialogs/forgedcertdialog.h"
#include
#include "history.h"
#include "dhparam.h"
#include "askpassword.h"
#include "settings.h"
#include "../PICA_netconf.h"
#include
SkyNet::SkyNet()
: nodes(config_dbname), QObject(0), active_filetransfers(0)
{
self_aware = false;
PICA_client_callbacks cbs =
{
newmsg_cb,
msgok_cb,
c2c_established_cb,
c2c_failed,
accept_cb,
notfound_cb,
c2c_closed_cb,
nodelist_cb,
peer_cert_verify_cb,
accept_file_cb,
accepted_file_cb,
denied_file_cb,
file_progress,
file_control,
file_finished,
c2n_established_cb,
c2n_failed_cb,
c2n_closed_cb,
listener_error_cb,
multilogin_cb,
direct_c2c_established_cb
};
PICA_client_init(&cbs);
this->active_nodelink = NULL;
this->acc = NULL;
this->listener = NULL;
connect(this, SIGNAL(PeerCertificateReceived(QByteArray, QString, bool*)), this, SLOT(verify_peer_cert(QByteArray, QString, bool*)), Qt::DirectConnection);
connect(this, SIGNAL(MultiloginMessageReceived(quint64,QString,quint16)), this, SLOT(multilogin_event(quint64,QString,quint16)), Qt::QueuedConnection);
event_loop_timer_id = startTimer(100);
c2c_reconnect_timer_id = startTimer(1000);
file_transfer_timer_id = 0;
}
void SkyNet::active_filetransfers_up()
{
active_filetransfers++;
if (active_filetransfers > 0 && file_transfer_timer_id == 0)
{
file_transfer_timer_id = startTimer(0);
}
}
void SkyNet::active_filetransfers_down()
{
active_filetransfers--;
Q_ASSERT(active_filetransfers >= 0);
if (active_filetransfers == 0 && file_transfer_timer_id != 0)
{
killTimer(file_transfer_timer_id);
file_transfer_timer_id = 0;
}
}
void SkyNet::active_filetransfers_reset()
{
active_filetransfers = 0;
if (file_transfer_timer_id != 0)
{
killTimer(file_transfer_timer_id);
file_transfer_timer_id = 0;
}
}
void SkyNet::nodelink_activated(PICA_c2n *c2n)
{
for (int i = 0; i < connecting_nodes.size(); i++)
{
if (connecting_nodes[i].first == c2n)
{
node_status_changed(connecting_nodes[i].second, true);
connecting_nodes.removeAt(i);
break;
}
}
if (self_aware)
{
connected_nodes_to_close.append(c2n);
}
else
{
self_aware = true;
active_nodelink = c2n;
nodes.MakeClean();
emit BecameSelfAware();
//load undelivered messages from history
if (msgqueues.isEmpty())
{
History h(config_dbname, Accounts::GetCurrentAccount().id);
msgqueues = h.GetUndeliveredMessages();
}
//load file transfers to be completed
// sndfilequeues = ...
c2c_reconnect_timeouts.clear();
reconnect_c2c();
}
}
void SkyNet::nodelink_closed(PICA_c2n *c2n, int error)
{
if (self_aware && c2n == active_nodelink)
{
active_nodelink = NULL;
self_aware = false;
emit LostSelfAwareness();
nodelink_reconnect_timer_id = startTimer(10000);
}
else
{
for (int i = 0; i < connecting_nodes.size(); i++)
{
if (connecting_nodes[i].first == c2n)
{
connecting_nodes.removeAt(i);
break;
}
}
}
}
void SkyNet::nodelink_failed(PICA_c2n *c2n, int error)
{
for (int i = 0; i < connecting_nodes.size(); i++)
{
if (connecting_nodes[i].first == c2n)
{
switch(error)
{
case PICA_ERRPROTONEW:
emit StatusMsg(QString("Node %1:%2 has newer protocol version. Please check if update for pica-client is available")
.arg(connecting_nodes[i].second.address)
.arg(connecting_nodes[i].second.port),
true);
break;
case PICA_ERRPROTOOLD:
emit StatusMsg(QString("Node %1:%2 has older protocol. Disconnected.")
.arg(connecting_nodes[i].second.address)
.arg(connecting_nodes[i].second.port),
false);
break;
}
node_status_changed(connecting_nodes[i].second, false);
connecting_nodes.removeAt(i);
break;
}
}
if (connecting_nodes.empty())
{
self_aware = false;
emit LostSelfAwareness();
nodelink_reconnect_timer_id = startTimer(10000);
}
}
void SkyNet::multilogin_event(quint64 timestamp, QString node_addr, quint16 node_port)
{
emit StatusMsg(QString("%3 Detected new login of your account at node %1:%2")
.arg(node_addr).arg(node_port).arg(QDateTime::fromTime_t(timestamp).toString("yyyy-MM-dd hh:mm:ss")),
true);
if (active_nodelink->multilogin_policy == PICA_MULTILOGIN_REPLACE)
{
emit StatusMsg(QString("Multilogin policy is set to \"replace\". Going offline..."), true);
SkyNet::Exit();
}
}
void SkyNet::node_status_changed(Nodes::NodeRecord nr, bool alive)
{
nodes.UpdateStatus(nr, alive);
}
void SkyNet::verify_peer_cert(QByteArray peer_id, QString cert_pem, bool *verified)
{
// ViewCertDialog vcd;
// vcd.SetCert(cert_pem);
// vcd.exec();
Contacts cnt(config_dbname, Accounts::GetCurrentAccount().id);
QString stored_cert;
if (!cnt.Exists(peer_id) && cnt.isOK())
{
cnt.Add(peer_id, Contacts::temporary);
}
if ((stored_cert = cnt.GetContactCert(peer_id)).isEmpty())
{
cnt.SetContactCert(peer_id, cert_pem);
QString name = OpenSSLTool::NameFromCertString(cert_pem);
cnt.SetContactName(peer_id, name);
emit ContactsUpdated();
}
else
{
//compare certificates
QString strip_pem[4] =
{
"-----BEGIN CERTIFICATE-----",
"-----END CERTIFICATE-----",
"-----BEGIN X509 CERTIFICATE-----",
"-----END X509 CERTIFICATE-----"
};
QString stripped_stored_cert = stored_cert;
QString stripped_received_cert = cert_pem;
for (int i = 0; i < 4; i++)
{
stripped_stored_cert.replace(strip_pem[i], "");
stripped_received_cert.replace(strip_pem[i], "");
}
QByteArray stored_DER, received_DER;
stored_DER = QByteArray::fromBase64(stripped_stored_cert.toLatin1().constData());
received_DER = QByteArray::fromBase64(stripped_received_cert.toLatin1().constData());
if (stored_DER.size() != received_DER.size() ||
memcmp(stored_DER.constData(), received_DER.constData(), stored_DER.size()) != 0)
{
//put scary message here
*verified = false;
emit CertificateForged(peer_id, cert_pem, stored_cert);
}
}
}
void SkyNet::update_c2c_reconnect_timeout(QByteArray peer_id)
{
if (c2c_reconnect_timeouts.contains(QByteArray((const char*)peer_id, PICA_ID_SIZE)))
c2c_reconnect_timeouts[QByteArray((const char*)peer_id, PICA_ID_SIZE)] *= 2;
else
c2c_reconnect_timeouts[QByteArray((const char*)peer_id, PICA_ID_SIZE)] = 1;
if (c2c_reconnect_timeouts[QByteArray((const char*)peer_id, PICA_ID_SIZE)] >= 64)
c2c_reconnect_timeouts[QByteArray((const char*)peer_id, PICA_ID_SIZE)] = 64;
}
void SkyNet::reset_c2c_reconnect_timeout(QByteArray peer_id)
{
c2c_reconnect_timeouts.remove(peer_id);
}
void SkyNet::reconnect_c2c()
{
if (msgqueues.empty() && sndfilequeues.empty())
return;
if (self_aware)
{
QMap > queues = msgqueues;
queues.unite(sndfilequeues);
time_t t = time(NULL);
QList c2c_peer_ids = queues.uniqueKeys();
c2c_peer_ids = filter_existing_chans(c2c_peer_ids);
for (int i = 0; i < c2c_peer_ids.size(); i++)
{
int ret;
struct PICA_c2c *chan = NULL;
if (c2c_reconnect_timeouts.contains(c2c_peer_ids[i]))
{
if (t % c2c_reconnect_timeouts[c2c_peer_ids[i]] != 0)
continue;
}
ret = PICA_new_c2c(active_nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), NULL, &chan);
qDebug() << "restoring c2c to " << c2c_peer_ids[i].toBase64() << " ret =" << ret << " in timer event\n";
}
}
}
void SkyNet::timerEvent(QTimerEvent *e)
{
if (e->timerId() == file_transfer_timer_id || e->timerId() == event_loop_timer_id)
{
if (connecting_nodes.size() > 0 || self_aware)
{
int ret;
QVector nodelinks;
nodelinks.reserve(connecting_nodes.size() + 1);
for (int i = 0; i < connecting_nodes.size(); i++)
nodelinks.append(connecting_nodes[i].first);
if (self_aware)
nodelinks.append(active_nodelink);
nodelinks.append(NULL);
ret = PICA_event_loop(nodelinks.data(), 25);
while(!connected_nodes_to_close.empty())
{
PICA_close_c2n(connected_nodes_to_close.takeFirst());
}
if (ret != PICA_OK)
emit StatusMsg("event loop error!", true);//show some error message
}
return;
}
if (self_aware && e->timerId() == c2c_reconnect_timer_id)
reconnect_c2c();
if (!self_aware && e->timerId() == nodelink_reconnect_timer_id)
{
killTimer(nodelink_reconnect_timer_id);
Accounts::AccountRecord acc = this->CurrentAccount();
Join(acc);
}
}
bool SkyNet::open_account()
{
int ret;
AskPassword::clear();
do
{
ret = PICA_open_acc(skynet_account.cert_file.toUtf8().constData(),
skynet_account.pkey_file.toUtf8().constData(),
DHParam::GetDHParamFilename().toUtf8().constData(),
AskPassword::ask_password_cb,
&acc);
if (ret == PICA_ERRINVPKEYPASSPHRASE)
AskPassword::setInvalidPassword();
}
while (ret == PICA_ERRINVPKEYPASSPHRASE);
qDebug() << "PICA_open_acc() returned " << ret;
if (ret != PICA_OK)
return false;
return true;
}
void SkyNet::Join(Accounts::AccountRecord &accrec)
{
PICA_directc2c_config directc2c_cfg = PICA_DIRECTC2C_CFG_DISABLED;
int multilogin = PICA_MULTILOGIN_PROHIBIT;
Settings st(config_dbname);
skynet_account = accrec;
QList noderecords = nodes.GetNodes();
if (!acc)
{
if (!open_account())
return;
}
if (noderecords.count() == 0)
{
emit StatusMsg(QString(tr("No known Pica Pica nodes")), true);
return;
}
directc2c_cfg = (PICA_directc2c_config)st.loadValue("direct_c2c.state", 1).toInt();
multilogin = st.loadValue("multiple_logins.state", PICA_MULTILOGIN_PROHIBIT).toInt();
if (!listener && directc2c_cfg == PICA_DIRECTC2C_CFG_ALLOWINCOMING)
{
int pub_port = st.loadValue("direct_c2c.public_port", 2298).toInt();
int loc_port = st.loadValue("direct_c2c.local_port", 2298).toInt();
QString public_addr = st.loadValue("direct_c2c.public_addr", "autoconfigure").toString();
if (public_addr.contains("autoconfigure"))
{
in_addr_t guess;
struct in_addr in;
guess = PICA_guess_listening_addr_ipv4();
in.s_addr = guess;
public_addr = QString(inet_ntoa(in));
#ifdef HAVE_LIBMINIUPNPC
if (st.loadValue("direct_c2c.upnp_enabled", 1).toBool() && PICA_is_reserved_addr_ipv4(guess))
{
int ret;
char public_ip[64];
ret = PICA_upnp_autoconfigure_ipv4(pub_port, loc_port, public_ip);
if (ret)
{
public_addr = QString(public_ip);
}
}
#endif
emit StatusMsg(QString(tr("Using autoconfigured address %1 port %2 for incoming direct connections")).arg(public_addr).arg(pub_port), false);
}
int ret = PICA_new_listener(acc,
public_addr.toLatin1().constData(),
pub_port,
loc_port, &listener);
if (ret != PICA_OK)
{
emit StatusMsg(QString(tr("Failed to open port %1 for incoming direct connections")).arg(loc_port), true);
directc2c_cfg = PICA_DIRECTC2C_CFG_CONNECTONLY;
}
}
if (!connecting_nodes.empty())
{
for (int i = 0; i < connecting_nodes.size(); i++)
PICA_close_c2n(connecting_nodes[i].first);
connecting_nodes.clear();
}
for (int i = 0; i < noderecords.size(); i++)
{
int ret;
struct PICA_c2n *c2n = NULL;
ret = PICA_new_c2n(acc, noderecords[i].address.toUtf8().constData(), noderecords[i].port,
directc2c_cfg, multilogin, listener, &c2n);
if (ret == PICA_OK)
{
connecting_nodes.append(QPair(c2n, noderecords[i]));
}
else
{
node_status_changed(noderecords[i], false);
}
}
/*
for (int i=0;i l;
l.append(filepath);
sndfilequeues[to] = l;
}
if (ret != PICA_OK)
{
//report error
}
}
void SkyNet::AcceptFile(QByteArray from, QString filepath)
{
int ret = PICA_OK;
struct PICA_c2c *iptr;
if ( (iptr = find_active_chan(from)) )
{
ret = PICA_accept_file(iptr, filepath.toUtf8().data(), filepath.toUtf8().size());
qDebug() << "PICA_accept_file(" << filepath.toUtf8().data() << ", " << filepath.toUtf8().size() << ") returned " << ret << "\n";
if (ret != PICA_OK)
{
//show error somewhere somehow
}
else
active_filetransfers_up();
}
}
void SkyNet::DenyFile(QByteArray from)
{
int ret = PICA_OK;
struct PICA_c2c *iptr;
if ( (iptr = find_active_chan(from)) )
{
ret = PICA_deny_file(iptr);
qDebug() << "PICA_deny_file() returned " << ret << "\n";
if (ret != PICA_OK)
{
//show error somewhere somehow
}
}
}
void SkyNet::PauseFile(QByteArray peer_id, bool pause_sending)
{
int ret = PICA_OK;
struct PICA_c2c *iptr;
if ( (iptr = find_active_chan(peer_id)) )
{
qDebug() << "calling PICA_pause_file(" << iptr << "," << pause_sending << ")\n";
ret = PICA_pause_file(iptr, (int)pause_sending );
if (ret != PICA_OK)
{
qDebug() << "PICA_pause_file() returned " << ret << "\n";
}
}
}
void SkyNet::ResumeFile(QByteArray peer_id, bool resume_sending)
{
int ret = PICA_OK;
struct PICA_c2c *iptr;
if ( (iptr = find_active_chan(peer_id)) )
{
ret = PICA_resume_file(iptr, (int)resume_sending );
if (ret != PICA_OK)
{
//show error somewhere somehow
}
}
}
void SkyNet::CancelFile(QByteArray peer_id, bool cancel_sending)
{
int ret = PICA_OK;
struct PICA_c2c *iptr;
if ( (iptr = find_active_chan(peer_id)) )
{
ret = PICA_cancel_file(iptr, (int)cancel_sending );
if (ret != PICA_OK)
{
//show error somewhere somehow
}
}
}
void SkyNet::SendMessage(QByteArray to, QString msg)
{
int ret = PICA_OK;
struct PICA_c2c *iptr;
if ( (iptr = find_active_chan(to)) )
{
//write_mutex.lock();//<<
ret = PICA_send_msg(iptr, msg.toUtf8().data(), msg.toUtf8().size());
//write_mutex.unlock();//>>
if (ret != PICA_OK)
emit UnableToDeliver(to, msg);
return;
}
if (msgqueues.contains(to))
{
msgqueues[to].append(msg);
}
else
{
struct PICA_c2c *chan = NULL;
ret = PICA_new_c2c(active_nodelink, (const unsigned char*)to.constData(), NULL, &chan);
QList l;
l.append(msg);
msgqueues[to] = l;
}
if (ret != PICA_OK)
emit UnableToDeliver(to, msg);
}
void SkyNet::flush_queues(QByteArray to)
{
struct PICA_c2c *chan;
int ret;
if (self_aware && (msgqueues.contains(to) || sndfilequeues.contains(to)))
{
qDebug() << "flushing " << to << " message queue\n";
if ((chan = find_active_chan(to)))
{
/////// messages
while( !msgqueues[to].empty() )
{
ret = PICA_send_msg(chan, msgqueues[to].first().toUtf8().data(), msgqueues[to].first().toUtf8().size());
if (ret != PICA_OK)
{
emit UnableToDeliver(to, msgqueues[to].first());
break;
}
msgqueues[to].removeFirst();
}
if (msgqueues[to].empty())
msgqueues.remove(to);
///////// files
while (!sndfilequeues[to].empty())
{
ret = PICA_send_file(chan, sndfilequeues[to].first().toUtf8().data());
if (ret != PICA_OK)
{
//report error somehow
break;
}
sndfilequeues[to].removeFirst();
}
if (sndfilequeues[to].empty())
sndfilequeues.remove(to);
}
}
}
struct PICA_c2c * SkyNet::find_active_chan(QByteArray peer_id)
{
if (!active_nodelink)
return NULL;
struct PICA_c2c *iptr = active_nodelink->chan_list_head;
while(iptr)
{
if (iptr->state == PICA_C2C_STATE_ACTIVE && QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE) == peer_id)
break;
iptr = iptr->next;
}
return iptr;
}
QList SkyNet::filter_existing_chans(QList peer_ids)
{
QList ret = peer_ids;
if (!active_nodelink)
return ret;
struct PICA_c2c *iptr = active_nodelink->chan_list_head;
while(iptr)
{
if (peer_ids.contains(QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE)))
ret.removeOne(QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE));
iptr = iptr->next;
}
return ret;
}
void SkyNet::emit_Delivered(QByteArray to)
{
emit Delivered(to);
}
void SkyNet::emit_MessageReceived(QByteArray from, QString msg)
{
emit MessageReceived(from, msg);
}
void SkyNet::emit_UnableToDeliver(QByteArray to, QString msg)
{
emit UnableToDeliver(to, msg);
}
void SkyNet::emit_PeerCertificateReceived(QByteArray peer_id, QString cert_pem, bool *verified)
{
emit PeerCertificateReceived(peer_id, cert_pem, verified);
}
void SkyNet::emit_IncomingFileRequestReceived(QByteArray peer_id, quint64 file_size, QString filename)
{
emit IncomingFileRequestReceived(peer_id, file_size, filename);
}
void SkyNet::emit_OutgoingFileRequestAccepted(QByteArray peer_id)
{
emit OutgoingFileRequestAccepted(peer_id);
}
void SkyNet::emit_OutgoingFileRequestDenied(QByteArray peer_id)
{
emit OutgoingFileRequestDenied(peer_id);
}
void SkyNet::emit_FileProgress(QByteArray peer_id, quint64 bytes_sent, quint64 bytes_received)
{
emit FileProgress(peer_id, bytes_sent, bytes_received);
}
void SkyNet::emit_IncomingFilePaused(QByteArray peer_id)
{
emit IncomingFilePaused(peer_id);
}
void SkyNet::emit_IncomingFileCancelled(QByteArray peer_id)
{
emit IncomingFileCancelled(peer_id);
}
void SkyNet::emit_IncomingFileIoError(QByteArray peer_id)
{
emit IncomingFileIoError(peer_id);
}
void SkyNet::emit_IncomingFileResumed(QByteArray peer_id)
{
emit IncomingFileResumed(peer_id);
}
void SkyNet::emit_OutgoingFilePaused(QByteArray peer_id)
{
emit OutgoingFilePaused(peer_id);
}
void SkyNet::emit_OutgoingFileCancelled(QByteArray peer_id)
{
emit OutgoingFileCancelled(peer_id);
}
void SkyNet::emit_OutgoingFileIoError(QByteArray peer_id)
{
emit OutgoingFileIoError(peer_id);
}
void SkyNet::emit_OutgoingFileResumed(QByteArray peer_id)
{
emit OutgoingFileResumed(peer_id);
}
void SkyNet::emit_OutgoingFileFinished(QByteArray peer_id)
{
emit OutgoingFileFinished(peer_id);
}
void SkyNet::emit_IncomingFileFinished(QByteArray peer_id)
{
emit IncomingFileFinished(peer_id);
}
void SkyNet::emit_c2cClosed(QByteArray peer_id)
{
emit c2cClosed(peer_id);
}
void SkyNet::emit_MultiloginMessageReceived(quint64 timestamp, QString node_addr, quint16 node_port)
{
emit MultiloginMessageReceived(timestamp, node_addr, node_port);
}
void SkyNet::emit_ConnectionStatusUpdated(QByteArray peer_id, QString status)
{
emit ConnectionStatusUpdated(peer_id, status);
}
//callbacks
void SkyNet::newmsg_cb(const unsigned char *peer_id, const char *msgbuf, unsigned int nb, int type)
{
QString msg = QString::fromUtf8(msgbuf, nb);
skynet->emit_MessageReceived(QByteArray((const char*)peer_id, PICA_ID_SIZE), msg);
}
void SkyNet::msgok_cb(const unsigned char *peer_id)
{
skynet->emit_Delivered(QByteArray((const char*)peer_id, PICA_ID_SIZE));
}
void SkyNet::c2c_established_cb(const unsigned char *peer_id, const char *ciphersuitename)
{
skynet->reset_c2c_reconnect_timeout(QByteArray((const char*)peer_id, PICA_ID_SIZE));
skynet->emit_ConnectionStatusUpdated(QByteArray((const char*)peer_id, PICA_ID_SIZE), QString("🔐: %1 c2c").arg(ciphersuitename));
skynet->flush_queues(QByteArray((const char*)peer_id, PICA_ID_SIZE));
}
void SkyNet::c2c_failed(const unsigned char *peer_id)
{
skynet->update_c2c_reconnect_timeout(QByteArray((const char*)peer_id, PICA_ID_SIZE));
qDebug() << "c2c failed (" << QByteArray((const char*)peer_id, PICA_ID_SIZE).toBase64() << ")\n";
skynet->emit_ConnectionStatusUpdated(QByteArray((const char*)peer_id, PICA_ID_SIZE), QString(tr("Failed to connect")));
}
int SkyNet::accept_cb(const unsigned char *caller_id)
{
return 1; //implement black list
}
void SkyNet::notfound_cb(const unsigned char *callee_id)
{
skynet->update_c2c_reconnect_timeout(QByteArray((const char*)callee_id, PICA_ID_SIZE));
qDebug() << "not found (" << QByteArray((const char*)callee_id, PICA_ID_SIZE).toBase64() << ")\n";
/*
if (skynet->msgqueues.contains(callee_id))
{
while ( ! skynet->msgqueues[callee_id].empty())
{
skynet->emit_UnableToDeliver(callee_id, skynet->msgqueues[callee_id].last());
skynet->msgqueues[callee_id].removeLast();
}
// msgqueues.remove(callee_id) was forgotten
}
*/
}
void SkyNet::c2c_closed_cb(const unsigned char *peer_id, int reason)
{
qDebug() << "c2c closed (" << QByteArray((const char*)peer_id, PICA_ID_SIZE).toBase64()
<< ", error_code =" << reason << ")\n";
skynet->emit_c2cClosed(QByteArray((const char*)peer_id, PICA_ID_SIZE));
skynet->emit_ConnectionStatusUpdated(QByteArray((const char*)peer_id, PICA_ID_SIZE), QString(tr("Disconnected")));
}
void SkyNet::nodelist_cb(int type, void *addr_bin, const char *addr_str, unsigned int port)
{
Nodes::NodeRecord nr = {addr_str, static_cast(port)};
skynet->nodes.Add(nr);
}
int SkyNet::peer_cert_verify_cb(const unsigned char *peer_id, const char *cert_pem, unsigned int nb)
{
bool verified = true;
skynet->emit_PeerCertificateReceived(QByteArray((const char*)peer_id, PICA_ID_SIZE), QString::fromLatin1(cert_pem, nb), &verified);
if (!verified)
return 0;
return 1;
}
int SkyNet::accept_file_cb(const unsigned char *peer_id, uint64_t file_size, const char *filename, unsigned int filename_size)
{
skynet->emit_IncomingFileRequestReceived(QByteArray((const char*)peer_id, PICA_ID_SIZE),
file_size, QString::fromUtf8(filename, filename_size));
return 2;//??? accept later code
}
void SkyNet::accepted_file_cb(const unsigned char *peer_id)
{
qDebug() << "FILE: file was accepted by remote side\n";
skynet->active_filetransfers_up();
skynet->emit_OutgoingFileRequestAccepted(QByteArray((const char *)peer_id, PICA_ID_SIZE));
}
void SkyNet::denied_file_cb(const unsigned char *peer_id)
{
skynet->emit_OutgoingFileRequestDenied(QByteArray((const char *)peer_id, PICA_ID_SIZE));
}
void SkyNet::file_progress(const unsigned char *peer_id, uint64_t sent, uint64_t received)
{
qDebug() << "FILE: file progress" << sent << " sent " << received << "received\n";
skynet->emit_FileProgress(QByteArray((const char *)peer_id, PICA_ID_SIZE), sent, received);
}
void SkyNet::file_control(const unsigned char *peer_id, unsigned int sender_cmd, unsigned int receiver_cmd)
{
qDebug() << "file_control callback: sender_cmd=" << sender_cmd << ", receiver_cmd=" << receiver_cmd << "\n";
if (sender_cmd != PICA_PROTO_FILECONTROL_VOID && receiver_cmd == PICA_PROTO_FILECONTROL_VOID)
{
switch(sender_cmd)
{
case PICA_PROTO_FILECONTROL_PAUSE:
skynet->active_filetransfers_down();
skynet->emit_IncomingFilePaused(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
case PICA_PROTO_FILECONTROL_RESUME:
skynet->active_filetransfers_up();
skynet->emit_IncomingFileResumed(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
case PICA_PROTO_FILECONTROL_CANCEL:
skynet->active_filetransfers_down();
skynet->emit_IncomingFileCancelled(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
case PICA_PROTO_FILECONTROL_IOERROR:
skynet->active_filetransfers_down();
skynet->emit_IncomingFileIoError(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
}
}
else if (sender_cmd == PICA_PROTO_FILECONTROL_VOID && receiver_cmd != PICA_PROTO_FILECONTROL_VOID)
{
switch(receiver_cmd)
{
case PICA_PROTO_FILECONTROL_PAUSE:
skynet->active_filetransfers_down();
skynet->emit_OutgoingFilePaused(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
case PICA_PROTO_FILECONTROL_RESUME:
skynet->active_filetransfers_up();
skynet->emit_OutgoingFileResumed(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
case PICA_PROTO_FILECONTROL_CANCEL:
skynet->active_filetransfers_down();
skynet->emit_OutgoingFileCancelled(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
case PICA_PROTO_FILECONTROL_IOERROR:
skynet->active_filetransfers_down();
skynet->emit_OutgoingFileIoError(QByteArray((const char *)peer_id, PICA_ID_SIZE));
break;
}
}
}
void SkyNet::file_finished(const unsigned char *peer_id, int sending)
{
qDebug() << "file_finished callback\n";
skynet->active_filetransfers_down();
if (sending)
skynet->emit_OutgoingFileFinished(QByteArray((const char *)peer_id, PICA_ID_SIZE));
else
skynet->emit_IncomingFileFinished(QByteArray((const char *)peer_id, PICA_ID_SIZE));
}
void SkyNet::c2n_established_cb(struct PICA_c2n *c2n)
{
skynet->nodelink_activated(c2n);
}
void SkyNet::c2n_failed_cb(struct PICA_c2n *c2n, int error)
{
skynet->nodelink_failed(c2n, error);
}
void SkyNet::c2n_closed_cb(struct PICA_c2n *c2n, int error)
{
skynet->nodelink_closed(c2n, error);
}
void SkyNet::listener_error_cb(struct PICA_listener *lst, int errorcode)
{
}
void SkyNet::multilogin_cb(uint64_t timestamp, void *addr_bin, const char *addr_str, uint16_t port)
{
skynet->emit_MultiloginMessageReceived(timestamp, QString(addr_str), port);
}
void SkyNet::direct_c2c_established_cb(const unsigned char *peer_id, const char *ciphersuitename)
{
skynet->emit_ConnectionStatusUpdated(QByteArray((const char*)peer_id, PICA_ID_SIZE), QString("🔐: %1 direct c2c").arg(ciphersuitename));
}