diff options
| -rwxr-xr-x | PICA_client.c | 118 | ||||
| -rwxr-xr-x | PICA_client.h | 8 | ||||
| -rw-r--r-- | pica-client/contactlistwidget.cpp | 6 | ||||
| -rw-r--r-- | pica-client/dialogs/filetransferdialog.cpp | 20 | ||||
| -rw-r--r-- | pica-client/dialogs/filetransferdialog.h | 16 | ||||
| -rw-r--r-- | pica-client/filetransfercontroller.cpp | 137 | ||||
| -rw-r--r-- | pica-client/filetransfercontroller.h | 45 | ||||
| -rw-r--r-- | pica-client/globals.h | 1 | ||||
| -rw-r--r-- | pica-client/main.cpp | 4 | ||||
| -rw-r--r-- | pica-client/pica-client.pro | 6 | ||||
| -rw-r--r-- | pica-client/skynet.cpp | 161 | ||||
| -rw-r--r-- | pica-client/skynet.h | 28 |
12 files changed, 492 insertions, 58 deletions
diff --git a/PICA_client.c b/PICA_client.c index 771730d..bc0939d 100755 --- a/PICA_client.c +++ b/PICA_client.c @@ -3,9 +3,7 @@ #include "PICA_msgproc.h" #include "PICA_common.h" #include <openssl/dh.h> -//#ifdef NO_RAND_DEV -//#include "PICA_rand_seed.h" -//#endif +#include <string.h> #define PICA_DEBUG // debug @@ -653,12 +651,60 @@ else return 1; } +int PICA_deny_file(struct PICA_chaninfo *chan) +{ +struct PICA_proto_msg *mp; + +if (chan->recvfilestate != PICA_CHANRECVFILESTATE_WAITACCEPT) + return PICA_ERRINVARG; + +chan->recvfilestate = PICA_CHANRECVFILESTATE_IDLE; + +mp = c2c_writebuf_push(chan, PICA_PROTO_DENIEDFILE, PICA_PROTO_DENIEDFILE_SIZE); + +if (mp) + { + RAND_bytes(mp->tail, 2); + } +else + return PICA_ERRNOMEM; + +return PICA_OK; +} + +int PICA_accept_file(struct PICA_chaninfo *chan, char *filename, unsigned int filenamesize) +{ +struct PICA_proto_msg *mp; +int ret; + +if (chan->recvfilestate != PICA_CHANRECVFILESTATE_WAITACCEPT) + return PICA_ERRINVARG; + +//open file +ret = PICA_recvfile_open_write(chan, filename, filenamesize); + +if (ret != PICA_OK) + return ret; + +mp = c2c_writebuf_push(chan, PICA_PROTO_ACCEPTEDFILE, PICA_PROTO_ACCEPTEDFILE_SIZE); + +if (mp) + { + RAND_bytes(mp->tail, 2); + } +else + return PICA_ERRNOMEM; + +chan->recvfilestate = PICA_CHANRECVFILESTATE_RECEIVING; + +return PICA_OK; +} + static unsigned int procmsg_SENDFILEREQUEST(unsigned char* buf, unsigned int nb, void* p) { struct PICA_chaninfo *chan = (struct PICA_chaninfo *)p; struct PICA_proto_msg *mp; -unsigned int reply; -unsigned int replysize; +int ret; char *filename = buf + 12; unsigned int filenamesize = *(uint16_t*)(buf + 2) - 8; @@ -666,32 +712,27 @@ unsigned int filenamesize = *(uint16_t*)(buf + 2) - 8; if (chan->recvfilestate != PICA_CHANRECVFILESTATE_IDLE) return 0; -reply = PICA_PROTO_DENIEDFILE; -reply = PICA_PROTO_DENIEDFILE_SIZE; +chan->recvfilestate = PICA_CHANRECVFILESTATE_WAITACCEPT; +chan->recvfile_size = *(uint64_t*)(buf + 4); +chan->recvfile_pos = 0; +ret = callbacks.accept_file_cb(chan->peer_id, *(uint64_t*)(buf + 4), filename, filenamesize); -if (callbacks.accept_file_cb(chan->peer_id, *(uint64_t*)(buf + 4), filename, filenamesize)) +if (ret > 0) { - chan->recvfilestate = PICA_CHANRECVFILESTATE_RECEIVING; - chan->recvfile_size = *(uint64_t*)(buf + 4); - chan->recvfile_pos = 0; - - //open file - if (PICA_recvfile_open_write(chan, filename, filenamesize) == PICA_OK) + if (ret == 1) { - reply = PICA_PROTO_ACCEPTEDFILE; - replysize = PICA_PROTO_ACCEPTEDFILE_SIZE; + if (PICA_accept_file(chan, filename, filenamesize) != PICA_OK) + if (PICA_deny_file(chan) != PICA_OK) + return 0; } - } - -mp = c2c_writebuf_push( chan, reply, replysize); -if (mp) + } +else { - RAND_bytes(mp->tail, 2); + if (PICA_deny_file(chan) != PICA_OK) + return 0; } -else - return 0; return 1; } @@ -743,6 +784,7 @@ if (fwrite(buf + 4, nb - 4, 1, chan->recvfile_stream) != 1) struct PICA_proto_msg *mp; fclose(chan->recvfile_stream); + chan->recvfile_stream = NULL; chan->recvfilestate = PICA_CHANRECVFILESTATE_IDLE; @@ -763,6 +805,7 @@ if (chan->recvfile_pos == chan->recvfile_size) { chan->recvfilestate = PICA_CHANRECVFILESTATE_IDLE; fclose(chan->recvfile_stream); + chan->recvfile_stream = NULL; } if (chan->recvfile_pos > chan->recvfile_size) //received more than file_size @@ -808,6 +851,7 @@ switch(sender_cmd) case PICA_PROTO_FILECONTROL_IOERROR: chan->recvfilestate = PICA_CHANRECVFILESTATE_IDLE; fclose(chan->recvfile_stream); + chan->recvfile_stream = NULL; break; case PICA_PROTO_FILECONTROL_VOID: @@ -837,6 +881,7 @@ switch(receiver_cmd) case PICA_PROTO_FILECONTROL_IOERROR: chan->sendfilestate = PICA_CHANSENDFILESTATE_IDLE; fclose(chan->sendfile_stream); + chan->sendfile_stream = NULL; break; default: @@ -1663,25 +1708,38 @@ else return PICA_OK; } -int PICA_send_file(struct PICA_chaninfo *chn, const char *filename) +int PICA_send_file(struct PICA_chaninfo *chn, const char *filepath) { struct PICA_proto_msg *mp; size_t namelen; uint64_t file_size; int ret; +const char *filename;//file name part of the filepath if (chn->sendfilestate != PICA_CHANSENDFILESTATE_IDLE) return PICA_ERRFILETRANSFERINPROGRESS; -if (filename == NULL) +if (filepath == NULL) return PICA_ERRINVFILENAME; +#ifndef WIN32 +filename = strrchr(filepath, '/'); +#else +filename = strrchr(filepath, '\\'); +#endif + +if (filename) + filename++; +else + filename = filepath; + + namelen = strlen(filename); if (namelen == 0 || namelen > PICA_PROTO_C2CMSG_MAXFILENAMESIZE) return PICA_ERRINVFILENAME; -if ((ret = PICA_sendfile_open_read(chn, filename, &file_size)) != PICA_OK) +if ((ret = PICA_sendfile_open_read(chn, filepath, &file_size)) != PICA_OK) return ret; if ((mp = c2c_writebuf_push(chn, PICA_PROTO_SENDFILEREQUEST, namelen + 12))) @@ -1689,7 +1747,7 @@ if ((mp = c2c_writebuf_push(chn, PICA_PROTO_SENDFILEREQUEST, namelen + 12))) *((uint16_t*)mp->tail) = namelen + 8; *((uint64_t*)(mp->tail + 2)) = file_size; - memcpy(mp->tail + 10, filename, namelen); + memcpy(mp->tail + 10, filename, namelen); } else return PICA_ERRNOMEM; @@ -1715,6 +1773,7 @@ fragment_size = fread(buf, 1, PICA_FILEFRAGMENTSIZE, chn->sendfile_stream); if (fragment_size == 0) { fclose(chn->sendfile_stream); + chn->sendfile_stream = NULL; chn->sendfilestate = PICA_CHANSENDFILESTATE_IDLE; if ((mp = c2c_writebuf_push(chn, PICA_PROTO_FILECONTROL, PICA_PROTO_FILECONTROL_SIZE))) @@ -1743,6 +1802,7 @@ if (chn->sendfile_pos >= chn->sendfile_size) { chn->sendfilestate = PICA_CHANSENDFILESTATE_IDLE; fclose(chn->sendfile_stream); + chn->sendfile_stream = NULL; } if (chn->sendfile_pos > chn->sendfile_size) @@ -1948,9 +2008,9 @@ if (chn->recvfile_stream == NULL) } #else -chn->sendfile_stream = fopen(filename_utf8, "rb"); +chn->recvfile_stream = fopen(filename_utf8, "wb"); -if (chn->sendfile_stream == NULL) +if (chn->recvfile_stream == NULL) return PICA_ERRFILEOPEN; #endif ///////////// diff --git a/PICA_client.h b/PICA_client.h index 1b00a57..7d1ae3e 100755 --- a/PICA_client.h +++ b/PICA_client.h @@ -107,7 +107,7 @@ typedef unsigned __int64 uint64_t; #define PICA_CHANRECVFILESTATE_IDLE 0 #define PICA_CHANRECVFILESTATE_RECEIVING 24 #define PICA_CHANRECVFILESTATE_PAUSED 25 - +#define PICA_CHANRECVFILESTATE_WAITACCEPT 26 #define PICA_CHAN_ACTIVATE_TIMEOUT 30 @@ -197,7 +197,7 @@ void (*channel_closed_cb)(const unsigned char *peer_id, int reason); void (*nodelist_cb)(int type, void *addr_bin, const char *addr_str, unsigned int port); //сертификат собеседника в формате PEM. Функция должна сравнить предъявленный сертификат с сохранённым (если есть) и вернуть 1 при успешной проверке, 0 - при неуспешной int (*peer_cert_verify_cb)(const unsigned char *peer_id, const char *cert_pem, unsigned int nb); - +// returns 0 if file is rejected, 1 if accepted, 2 if decision is postponed int (*accept_file_cb)(const unsigned char *peer_id, uint64_t file_size, const char *filename, unsigned int filename_size); void (*accepted_file_cb)(const unsigned char *peer_id); @@ -241,7 +241,9 @@ int PICA_send_msg(struct PICA_chaninfo *chn, char *buf,unsigned int len); int PICA_read_msg(struct PICA_chaninfo *chn,char *buf,unsigned int *n); //filename - ASCII or UTF-8 encoded string -int PICA_send_file(struct PICA_chaninfo *chn, const char *filename); +int PICA_send_file(struct PICA_chaninfo *chn, const char *filepath); +int PICA_accept_file(struct PICA_chaninfo *chan, char *filename, unsigned int filenamesize); +int PICA_deny_file(struct PICA_chaninfo *chan); void PICA_close_channel(struct PICA_chaninfo *chn); void PICA_close_connection(struct PICA_conninfo *cid); diff --git a/pica-client/contactlistwidget.cpp b/pica-client/contactlistwidget.cpp index 10194e8..d73a3f4 100644 --- a/pica-client/contactlistwidget.cpp +++ b/pica-client/contactlistwidget.cpp @@ -4,6 +4,7 @@ #include "dialogs/showpicaiddialog.h" #include "dialogs/filetransferdialog.h" #include "msguirouter.h" +#include "filetransfercontroller.h" #include <QMenu> #include <QMessageBox> #include <QContextMenuEvent> @@ -208,8 +209,5 @@ void ContactListWidget::Reload() void ContactListWidget::send_file() { -//FileTransferDialog *d = new FileTransferDialog("test", 138900713, FileTransferDialog::SENDING, this); - -//d->show(); - + ftctrl->send_file(wgitem_to_recs[currentItem()]->id); } diff --git a/pica-client/dialogs/filetransferdialog.cpp b/pica-client/dialogs/filetransferdialog.cpp index c7f145d..4643bb8 100644 --- a/pica-client/dialogs/filetransferdialog.cpp +++ b/pica-client/dialogs/filetransferdialog.cpp @@ -3,7 +3,9 @@ #include <QHBoxLayout> #include <stdlib.h> -FileTransferDialog::FileTransferDialog(QString filename, quint64 size, TransferDirection drct, QWidget *parent) : +FileTransferDialog::FileTransferDialog(QByteArray peer_id, QString filename, quint64 size, + TransferDirection drct, QWidget *parent) : + peer_id_(peer_id), QDialog(parent), dir_(drct), filename_(filename), @@ -72,6 +74,12 @@ void FileTransferDialog::update(quint64 progress) + bytestoHumanBase2(filesize_) + QString(" %1 %").arg((int)percents)); pgbar->setValue(percents); + + if (progress == filesize_) + { + leftbutton->setEnabled(false); + rightbutton->setEnabled(false); + } } void FileTransferDialog::leftbuttonclick() @@ -82,7 +90,7 @@ void FileTransferDialog::leftbuttonclick() { leftbutton->setText("Pause"); rightbutton->setText("Cancel"); - emit acceptedFile(); + emit acceptedFile(peer_id_); return; } } @@ -90,12 +98,12 @@ void FileTransferDialog::leftbuttonclick() if (leftbutton->text() == tr("Pause")) { leftbutton->setText(tr("Resume")); - emit pausedFile(); + emit pausedFile(peer_id_, this); } else if (leftbutton->text() == tr("Resume")) { leftbutton->setText(tr("Pause")); - emit resumedFile(); + emit resumedFile(peer_id_, this); } } @@ -105,14 +113,14 @@ void FileTransferDialog::rightbuttonclick() { if (rightbutton->text() == tr("Deny")) { - emit deniedFile(); + emit deniedFile(peer_id_); return; } } if (rightbutton->text() == tr("Cancel")) { - emit cancelledFile(); + emit cancelledFile(peer_id_, this); } } diff --git a/pica-client/dialogs/filetransferdialog.h b/pica-client/dialogs/filetransferdialog.h index a5a4783..406ea70 100644 --- a/pica-client/dialogs/filetransferdialog.h +++ b/pica-client/dialogs/filetransferdialog.h @@ -6,6 +6,7 @@ #include <QLabel> #include <QPushButton> #include <QTimer> +#include <QByteArray> class FileTransferDialog : public QDialog { @@ -17,8 +18,10 @@ public: RECEIVING }; - explicit FileTransferDialog(QString filename, quint64 size, TransferDirection drct, QWidget *parent = 0); + explicit FileTransferDialog(QByteArray peer_id, QString filename, quint64 size, + TransferDirection drct, QWidget *parent = 0); + TransferDirection getTransferDirection() {return dir_;}; private: @@ -30,6 +33,7 @@ private: QPushButton *leftbutton; QPushButton *rightbutton; + QByteArray peer_id_; TransferDirection dir_; QString filename_; quint64 filesize_; @@ -44,11 +48,11 @@ private: QTimer *timer; signals: - void pausedFile(); - void resumedFile(); - void cancelledFile(); - void acceptedFile(); - void deniedFile(); + void pausedFile(QByteArray peer_id, FileTransferDialog *sender); + void resumedFile(QByteArray peer_id, FileTransferDialog *sender); + void cancelledFile(QByteArray peer_id, FileTransferDialog *sender); + void acceptedFile(QByteArray peer_id); + void deniedFile(QByteArray peer_id); public slots: void update(quint64 progress); diff --git a/pica-client/filetransfercontroller.cpp b/pica-client/filetransfercontroller.cpp new file mode 100644 index 0000000..9b479c1 --- /dev/null +++ b/pica-client/filetransfercontroller.cpp @@ -0,0 +1,137 @@ +#include "filetransfercontroller.h" +#include "globals.h" +#include "skynet.h" +#include "mainwindow.h" +#include "msguirouter.h" +#include <QFileDialog> +#include <QFileInfo> + +FileTransferController::FileTransferController(QObject *parent) : + QObject(parent) +{ + connect(skynet, SIGNAL(IncomingFileRequestReceived(QByteArray,quint64,QString)), + this, SLOT(file_request(QByteArray,quint64,QString))); + + connect(skynet, SIGNAL(FileProgress(QByteArray,quint64,quint64)), + this, SLOT(file_progress(QByteArray,quint64,quint64))); + + connect(skynet, SIGNAL(OutgoingFileRequestAccepted(QByteArray)), this, SLOT(file_accepted_by_peer(QByteArray))); + + connect(skynet, SIGNAL(OutgoingFileRequestDenied(QByteArray)), this, SLOT(file_denied_by_peer(QByteArray))); +} + + +void FileTransferController::file_progress(QByteArray peer_id, quint64 bytes_sent, quint64 bytes_received) +{ + if (bytes_received > 0) + { + if (ftdialogs_in.contains(peer_id)) + { + ftdialogs_in[peer_id]->update(bytes_received); + } + } + else if (bytes_sent > 0) + { + if (ftdialogs_out.contains(peer_id)) + { + ftdialogs_out[peer_id]->update(bytes_sent); + } + } +} + +void FileTransferController::file_request(QByteArray peer_id, quint64 file_size, QString filename) +{ + FileTransferDialog *ftd = new FileTransferDialog(peer_id, filename, file_size, FileTransferDialog::RECEIVING); + + ftdialogs_in[peer_id] = ftd; + fsizes[peer_id] = file_size; + fnames[peer_id] = filename; + + connect(ftd, SIGNAL(acceptedFile(QByteArray)), this, SLOT(file_accepted_by_me(QByteArray))); + connect(ftd, SIGNAL(deniedFile(QByteArray)), this, SLOT(file_denied_by_me(QByteArray))); + + ftd->show(); +} + +void FileTransferController::file_accepted_by_peer(QByteArray peer_id) +{ + +} + +void FileTransferController::file_denied_by_peer(QByteArray peer_id) +{ + +} + +void FileTransferController::file_accepted_by_me(QByteArray peer_id) +{ + + + QString filePathToSave = QFileDialog::getSaveFileName(ftdialogs_in[peer_id], tr("Save received file to"), + fnames[peer_id], tr("Any file (* *.*)")); + + skynet->AcceptFile(peer_id, filePathToSave); + + connect(ftdialogs_in[peer_id], SIGNAL(cancelledFile(QByteArray,FileTransferDialog*)), this, SLOT(file_cancelled_by_me(QByteArray,FileTransferDialog*))); + connect(ftdialogs_in[peer_id], SIGNAL(pausedFile(QByteArray,FileTransferDialog*)), this, SLOT(file_paused_by_me(QByteArray,FileTransferDialog*))); + connect(ftdialogs_in[peer_id], SIGNAL(resumedFile(QByteArray,FileTransferDialog*)), this, SLOT(file_resumed_by_me(QByteArray,FileTransferDialog*))); +} + +void FileTransferController::file_denied_by_me(QByteArray peer_id) +{ +} + +void FileTransferController::file_cancelled_by_me(QByteArray peer_id, FileTransferDialog *from) +{ + +} + +void FileTransferController::file_paused_by_me(QByteArray peer_id, FileTransferDialog *from) +{ + +} + +void FileTransferController::file_resumed_by_me(QByteArray peer_id, FileTransferDialog *from) +{ + +} + +void FileTransferController::send_file(QByteArray peer_id) +{ + + if (ftdialogs_out.contains(peer_id)) + { + msguirouter->notification(tr("There is already file transfer in progress. Wait until it is finished.")); + return; + } + + QString filepath = QFileDialog::getOpenFileName(0, tr("Select file to send"), QString(), tr("Any file (* *.*)")); + + if (filepath.isNull()) + return; + + QFileInfo fi(filepath); + + if (!fi.exists()) + { + msguirouter->notification(tr("File \"%1\" does not exist.").arg(filepath)); + return; + } + + if (fi.size() == 0) + { + msguirouter->notification(tr("Cannot send empty file.")); + } + + skynet->SendFile(peer_id, filepath); + + FileTransferDialog *ftd = new FileTransferDialog(peer_id, fi.fileName(), fi.size(), FileTransferDialog::SENDING); + + ftdialogs_out[peer_id] = ftd; + + connect(ftdialogs_out[peer_id], SIGNAL(cancelledFile(QByteArray,FileTransferDialog*)), this, SLOT(file_cancelled_by_me(QByteArray,FileTransferDialog*))); + connect(ftdialogs_out[peer_id], SIGNAL(pausedFile(QByteArray,FileTransferDialog*)), this, SLOT(file_paused_by_me(QByteArray,FileTransferDialog*))); + connect(ftdialogs_out[peer_id], SIGNAL(resumedFile(QByteArray,FileTransferDialog*)), this, SLOT(file_resumed_by_me(QByteArray,FileTransferDialog*))); + + ftd->show(); +} diff --git a/pica-client/filetransfercontroller.h b/pica-client/filetransfercontroller.h new file mode 100644 index 0000000..72a989e --- /dev/null +++ b/pica-client/filetransfercontroller.h @@ -0,0 +1,45 @@ +#ifndef FILETRANSFERCONTROLLER_H +#define FILETRANSFERCONTROLLER_H + +#include <QObject> +#include <QMap> +#include "dialogs/filetransferdialog.h" + +class FileTransferController : public QObject +{ + Q_OBJECT +public: + explicit FileTransferController(QObject *parent = 0); + +signals: + +private: + + QMap<QByteArray, FileTransferDialog*> ftdialogs_in; + QMap<QByteArray, FileTransferDialog*> ftdialogs_out; + + QMap<QByteArray, quint64> fsizes; + QMap<QByteArray, QString> fnames; + + +public slots: + + // from remote peer to me + void file_progress(QByteArray peer_id, quint64 bytes_sent, quint64 bytes_received); + void file_request(QByteArray peer_id, quint64 file_size, QString filename); + void file_accepted_by_peer(QByteArray peer_id); + void file_denied_by_peer(QByteArray peer_id); + //void file_control(QByteArray peer_id, ) + + //from me (file transfer dialog shown to user) to remote peer + void file_accepted_by_me(QByteArray peer_id); + void file_denied_by_me(QByteArray peer_id); + void file_cancelled_by_me(QByteArray peer_id, FileTransferDialog *from); + void file_paused_by_me(QByteArray peer_id, FileTransferDialog *from); + void file_resumed_by_me(QByteArray peer_id, FileTransferDialog *from); + + void send_file(QByteArray peer_id); + +}; + +#endif // FILETRANSFERCONTROLLER_H diff --git a/pica-client/globals.h b/pica-client/globals.h index f60f568..48c3ec8 100644 --- a/pica-client/globals.h +++ b/pica-client/globals.h @@ -27,4 +27,5 @@ extern class QIcon picapica_ico_sit; extern class QIcon picapica_ico_fly; extern class PicaActionCenter *action_center; extern class PicaSysTray *systray; +extern class FileTransferController *ftctrl; #endif // GLOBALS_H diff --git a/pica-client/main.cpp b/pica-client/main.cpp index 40b1cb0..0139bb0 100644 --- a/pica-client/main.cpp +++ b/pica-client/main.cpp @@ -5,6 +5,7 @@ #include "contacts.h" #include "skynet.h" #include "msguirouter.h" +#include "filetransfercontroller.h" #include "picaactioncenter.h" #include "picasystray.h" #include <QDir> @@ -27,6 +28,7 @@ QIcon picapica_ico_fly; class PicaActionCenter *action_center; class PicaSysTray *systray; +class FileTransferController *ftctrl; // /usr/share/pica-client/pica-pica_CA.pem //QString config_defaultCA("/home/root_jr/files/projects/picapica_wc/localhost/project_picapica/trunk/tests/trusted_CA.pem"); @@ -475,6 +477,8 @@ int main(int argc, char *argv[]) MsgUIRouter muir; msguirouter = &muir; + FileTransferController ftc; + ftctrl = &ftc; aw.show(); diff --git a/pica-client/pica-client.pro b/pica-client/pica-client.pro index cffe5b3..df3b729 100644 --- a/pica-client/pica-client.pro +++ b/pica-client/pica-client.pro @@ -35,7 +35,8 @@ SOURCES += main.cpp\ ../PICA_id.c \ dhparam.cpp \ dialogs/showpicaiddialog.cpp \ - dialogs/filetransferdialog.cpp + dialogs/filetransferdialog.cpp \ + filetransfercontroller.cpp HEADERS += mainwindow.h \ chatwindow.h \ @@ -64,7 +65,8 @@ HEADERS += mainwindow.h \ ../PICA_id.h \ dhparam.h \ dialogs/showpicaiddialog.h \ - dialogs/filetransferdialog.h + dialogs/filetransferdialog.h \ + filetransfercontroller.h DEFINES = PICA_MULTITHREADED diff --git a/pica-client/skynet.cpp b/pica-client/skynet.cpp index e868903..1077df2 100644 --- a/pica-client/skynet.cpp +++ b/pica-client/skynet.cpp @@ -23,7 +23,12 @@ PICA_client_callbacks cbs = { notfound_cb, channel_closed_cb, nodelist_cb, - peer_cert_verify_cb + peer_cert_verify_cb, + accept_file_cb, + accepted_file_cb, + denied_file_cb, + file_progress, + file_control }; PICA_client_init(&cbs); @@ -70,7 +75,14 @@ void SkyNet::nodethread_connected(QString addr, quint16 port, NodeThread *thread msgqueues = h.GetUndeliveredMessages(); } - c2c_peer_ids = msgqueues.keys(); + //load file transfers to be completed + // sndfilequeues = ... + + QMap<QByteArray, QList<QString> > queues = msgqueues; + + queues.unite(sndfilequeues); + + c2c_peer_ids = queues.uniqueKeys(); for (int i = 0; i < c2c_peer_ids.size(); i++) { @@ -157,7 +169,10 @@ void SkyNet::timerEvent(QTimerEvent *e) { if (write_mutex.tryLock(10)) { - QList<QByteArray> c2c_peer_ids = msgqueues.keys(); + QMap<QByteArray, QList<QString> > queues = msgqueues; + queues.unite(sndfilequeues); + + QList<QByteArray> c2c_peer_ids = queues.uniqueKeys(); c2c_peer_ids = filter_existing_chans(c2c_peer_ids); @@ -221,6 +236,68 @@ bool SkyNet::isSelfAware() return self_aware; } +void SkyNet::SendFile(QByteArray to, QString filepath) +{ +int ret = PICA_OK; +struct PICA_chaninfo *iptr; + +write_mutex.lock();//<< + +if ( (iptr = find_active_chan(to)) ) + { + ret = PICA_send_file(iptr, filepath.toUtf8().data()); + + if (ret != PICA_OK) + { + //show error somewhere somehow + } + + write_mutex.unlock();//>> + return; + } + + if (sndfilequeues.contains(to)) + { + //sending multiple files is not supported yet + } + else + { + struct PICA_chaninfo *chan = NULL; + + ret = PICA_create_channel(nodelink, (const unsigned char*)to.constData(), &chan); + + QList<QString> l; + l.append(filepath); + sndfilequeues[to] = l; + } + +write_mutex.unlock();//>> + + if (ret!= PICA_OK) + { + //report error + } +} + +void SkyNet::AcceptFile(QByteArray from, QString filepath) +{ +int ret = PICA_OK; +struct PICA_chaninfo *iptr; + +write_mutex.lock();//<< +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 + } + } +write_mutex.unlock();//>> +} + void SkyNet::SendMessage(QByteArray to, QString msg) { int ret = PICA_OK; @@ -241,7 +318,6 @@ if ( (iptr = find_active_chan(to)) ) return; } - if (msgqueues.contains(to)) { msgqueues[to].append(msg); @@ -265,17 +341,18 @@ write_mutex.unlock();//>> } -void SkyNet::flush_msgqueue(QByteArray to) +void SkyNet::flush_queues(QByteArray to) { struct PICA_chaninfo *chan; int ret; - if (self_aware && msgqueues.contains(to)) + 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()); @@ -292,6 +369,24 @@ void SkyNet::flush_msgqueue(QByteArray to) 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); } } } @@ -354,6 +449,26 @@ void SkyNet::emit_PeerCertificateReceived(QByteArray peer_id, QString cert_pem, 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); +} + //callbacks //all callbacks are executed in separate thread, created in Nodethread instance, REMEMBER THAT !!! @@ -373,7 +488,7 @@ skynet->emit_Delivered(QByteArray((const char*)peer_id, PICA_ID_SIZE)); void SkyNet::channel_established_cb(const unsigned char *peer_id) { -skynet->flush_msgqueue(QByteArray((const char*)peer_id, PICA_ID_SIZE)); +skynet->flush_queues(QByteArray((const char*)peer_id, PICA_ID_SIZE)); } void SkyNet::channel_failed(const unsigned char *peer_id) @@ -426,3 +541,35 @@ int SkyNet::peer_cert_verify_cb(const unsigned char *peer_id, const char *cert_p 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->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) +{ + //implement me +} + diff --git a/pica-client/skynet.h b/pica-client/skynet.h index 6c43d6a..f512fb1 100644 --- a/pica-client/skynet.h +++ b/pica-client/skynet.h @@ -20,6 +20,8 @@ public: void Exit(); void SendMessage(QByteArray to, QString msg); + void SendFile(QByteArray to, QString filepath); + void AcceptFile(QByteArray from, QString filepath); Accounts::AccountRecord CurrentAccount() {return skynet_account;}; signals: @@ -32,6 +34,14 @@ signals: void CertificateForged(QByteArray peer_id, QString received_cert, QString stored_cert); void ErrMsgFromNode(QString msg); void ContactsUpdated(); + void IncomingFileRequestReceived(QByteArray peer_id, quint64 file_size, QString filename); + void OutgoingFileRequestAccepted(QByteArray peer_id); + void OutgoingFileRequestDenied(QByteArray peer_id); + void FileProgress(QByteArray peer_id, quint64 bytes_sent, quint64 bytes_received); + void IncomingFilePaused(QByteArray peer_id); + void IncomingFileCancelled(QByteArray peer_id); + void IncomingFileIoError(QByteArray peer_id); + void IncomingFileResumed(QByteArray peer_id); private: Nodes nodes; @@ -42,11 +52,12 @@ private: Accounts::AccountRecord skynet_account; QMutex write_mutex; QMap<QByteArray, QList<QString> > msgqueues; + QMap<QByteArray, QList<QString> > sndfilequeues; int timer_id; void timerEvent(QTimerEvent * e); - void flush_msgqueue(QByteArray to); + void flush_queues(QByteArray to); struct PICA_chaninfo *find_active_chan(QByteArray peer_id); QList<QByteArray> filter_existing_chans(QList<QByteArray> peer_ids); @@ -54,6 +65,11 @@ private: void emit_UnableToDeliver(QByteArray to, QString msg); void emit_Delivered(QByteArray to); void emit_PeerCertificateReceived(QByteArray peer_id, QString cert_pem, bool *verified); + void emit_IncomingFileRequestReceived(QByteArray peer_id, quint64 file_size, QString filename); + void emit_OutgoingFileRequestAccepted(QByteArray peer_id); + void emit_OutgoingFileRequestDenied(QByteArray peer_id); + void emit_FileProgress(QByteArray peer_id, quint64 bytes_sent, quint64 bytes_received); + //incoming/outgoing x paused, cancelled, io error //получение сообщения. static void newmsg_cb(const unsigned char *peer_id,const char* msgbuf,unsigned int nb,int type); @@ -74,6 +90,16 @@ private: static int peer_cert_verify_cb(const unsigned char *peer_id, const char *cert_pem, unsigned int nb); + static int accept_file_cb(const unsigned char *peer_id, uint64_t file_size, const char *filename, unsigned int filename_size); + + static void accepted_file_cb(const unsigned char *peer_id); + + static void denied_file_cb(const unsigned char *peer_id); + + static void file_progress(const unsigned char *peer_id, uint64_t sent, uint64_t received); + + static void file_control(const unsigned char *peer_id, unsigned int sender_cmd, unsigned int receiver_cmd); + private slots: void nodethread_finished(); void nodethread_connected(QString addr, quint16 port, NodeThread *thread); |
