nitroshare-0.3.1/src/device/device.h000664 001750 001750 00000004203 12653764154 020131 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_DEVICE_H #define NS_DEVICE_H #include #include "../util/platform.h" /** * @brief Information about another device on the network * * The members of this class are populated by the DeviceModel class when pings * are received. The information needed to transfer files to the device are * contained here. */ class Device { public: explicit Device(const QString &uuid); QString uuid() const { return mUuid; } QString name() const { return mName; } Platform::OperatingSystem operatingSystem() const { return mOperatingSystem; } QHostAddress address() const { return mAddress; } quint16 port() const { return mPort; } bool hasTimedOut() const; bool update(const QString &name, Platform::OperatingSystem operatingSystem, const QHostAddress &address, quint16 port); private: const QString mUuid; QString mName; Platform::OperatingSystem mOperatingSystem; QHostAddress mAddress; quint16 mPort; qint64 mLastPing = 0; }; #endif // NS_DEVICE_H nitroshare-0.3.1/src/dist/nitroshare.1000664 001750 001750 00000000513 12653764154 020465 0ustar00nathannathan000000 000000 .TH NITROSHARE 1 .SH NAME nitroshare \- launches the NitroShare application .SH SYNOPSIS .B nitroshare [options] .SH DESCRIPTION .B NitroShare is a cross-platform application for sharing files over a local network. Each device on the network with NitroShare installed can instantly transfer files and directories to other devices. nitroshare-0.3.1/src/settings/settingsdialog.h000664 001750 001750 00000003151 12653764154 022314 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_SETTINGSDIALOG_H #define NS_SETTINGSDIALOG_H #include #include "ui_settingsdialog.h" /** * @brief Settings dialog for configuring the application */ class SettingsDialog : public QDialog, public Ui::SettingsDialog { Q_OBJECT public: SettingsDialog(); public Q_SLOTS: virtual void accept(); private Q_SLOTS: void onResetButtonClicked(); void onTransferDirectoryButtonClicked(); private: void reload(); }; #endif // NS_SETTINGSDIALOG_H nitroshare-0.3.1/src/transfer/transferreceiver.h000664 001750 001750 00000004100 12653764154 022624 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERRECEIVER_H #define NS_TRANSFERRECEIVER_H #include #include "transfer.h" class TransferReceiver : public Transfer { Q_OBJECT public: explicit TransferReceiver(qintptr socketDescriptor); virtual void start(); private: virtual void processJsonPacket(const QJsonObject &object); virtual void processBinaryPacket(const QByteArray &data); virtual void writeNextPacket(); void processTransferHeader(const QJsonObject &object); void processItemHeader(const QJsonObject &object); void nextItem(); bool openFile(); // Information for writing files that are received const QDir mRoot; const bool mOverwrite; // Number of items remaining to be transferred qint32 mTransferItemsRemaining; // Data needed for the file currently being read QFile mFile; qint64 mFileBytesRemaining; // Error message pending QString mError; }; #endif // NS_TRANSFERRECEIVER_H nitroshare-0.3.1/src/dist/wizard-image.bmp000664 001750 001750 00000455656 12653764154 021333 0ustar00nathannathan000000 000000 BM[6(:x[NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNaaaNNNaaaNNNaaaNNNaaaNNNaaaNNNaaaNNNaaaNNNaaafffaaafffaaafffaaa)))fffaaa333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fffmmm333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff333kkkfff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333fff333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff333ffffff)))̞fffffffffffffffffffffRRRfffQQQfffQQQfffQQQfffQQQfffQQQfffQQQfffQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQnitroshare-0.3.1/src/config.h.in000664 001750 001750 00000003564 12653764154 017316 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_CONFIG_H #define NS_CONFIG_H // Project definitions #define PROJECT_NAME "${PROJECT_NAME}" #define PROJECT_DESCRIPTION "${PROJECT_DESCRIPTION}" #define PROJECT_AUTHOR "${PROJECT_AUTHOR}" #define PROJECT_DOMAIN "${PROJECT_DOMAIN}" #define PROJECT_WEBSITE "${PROJECT_WEBSITE}" // Current version broken into individual components #define PROJECT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} #define PROJECT_VERSION_MINOR ${PROJECT_VERSION_MINOR} #define PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH} // Current version as a string #define PROJECT_VERSION "${PROJECT_VERSION}" // Build options #cmakedefine Qt5WinExtras_FOUND #cmakedefine Qt5MacExtras_FOUND #cmakedefine APPINDICATOR_FOUND #cmakedefine UNITY_FOUND #endif // NS_CONFIG_H nitroshare-0.3.1/src/dist/icons/gnome/24x24/apps/nitroshare-indicator.png000664 001750 001750 00000000435 12653764154 027034 0ustar00nathannathan000000 000000 PNG  IHDRw=bKGD@ pHYs B(xtIME#+8IDATHǽQ CV_lż݌}U& JMM,/Ϻǀ|K8bH,M(wTNjOL9]}BBNV ,aTsk3YʃAɛ/gT}qA䒥zݘtAW IENDB`nitroshare-0.3.1/src/device/000775 001750 001750 00000000000 12653764154 016522 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/application/application.cpp000664 001750 001750 00000015452 12653764154 022604 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include #include #include "../device/devicedialog.h" #include "../icon/trayicon.h" #include "../settings/settings.h" #include "../settings/settingsdialog.h" #include "application.h" #include "aboutdialog.h" #include "config.h" #ifdef APPINDICATOR_FOUND #include "../icon/indicatoricon.h" #include "../util/platform.h" #endif // Enable QHostAddress to be used in a QVariant Q_DECLARE_METATYPE(QHostAddress) Application::Application() : mTransferWindow(&mTransferModel), #ifdef APPINDICATOR_FOUND mIcon(Platform::useIndicator() ? static_cast(new IndicatorIcon) : static_cast(new TrayIcon)), #else mIcon(new TrayIcon), #endif mStartTime(QDateTime::currentMSecsSinceEpoch()) { connect(&mDeviceModel, &DeviceModel::rowsInserted, this, &Application::notifyDevicesAdded); connect(&mDeviceModel, &DeviceModel::rowsAboutToBeRemoved, this, &Application::notifyDevicesRemoved); connect(&mTransferModel, &TransferModel::dataChanged, this, &Application::notifyTransfersChanged); connect(&mTransferServer, &TransferServer::error, this, &Application::notifyError); connect(&mTransferServer, &TransferServer::newTransfer, &mTransferModel, &TransferModel::addReceiver); connect(&mTransferWindow, &TransferWindow::sendDirectory, this, &Application::sendDirectory); connect(&mTransferWindow, &TransferWindow::sendFiles, this, &Application::sendFiles); mIcon->addAction(tr("Send Files..."), this, SLOT(sendFiles())); mIcon->addAction(tr("Send Directory..."), this, SLOT(sendDirectory())); mIcon->addSeparator(); mIcon->addAction(tr("View Transfers..."), &mTransferWindow, SLOT(show())); mIcon->addSeparator(); mIcon->addAction(tr("Settings"), this, SLOT(onOpenSettings())); mIcon->addSeparator(); mIcon->addAction(tr("About..."), this, SLOT(onOpenAbout())); mIcon->addAction(tr("About Qt..."), this, SLOT(onOpenAboutQt())); mIcon->addSeparator(); mIcon->addAction(tr("Exit"), QApplication::instance(), SLOT(quit())); // Start the transfer server mTransferServer.start(); } Application::~Application() { delete mIcon; } void Application::notifyError(const QString &message) { QMessageBox::critical(nullptr, tr("Error"), message); } void Application::notifyDevicesAdded(const QModelIndex &, int first, int last) { // Only display notifications if current uptime exceeds the broadcast timeout if(QDateTime::currentMSecsSinceEpoch() - mStartTime > Settings::instance()->get(Settings::Key::BroadcastTimeout).toInt()) { for(int row = first; row <= last; ++row) { mIcon->showMessage(tr("%1 has joined.").arg( mDeviceModel.data(mDeviceModel.index(row, 0), DeviceModel::NameRole).toString() )); } } } void Application::notifyDevicesRemoved(const QModelIndex &, int first, int last) { for(int row = first; row <= last; ++row) { mIcon->showMessage(tr("%1 has left.").arg( mDeviceModel.data(mDeviceModel.index(row, 0), DeviceModel::NameRole).toString() )); } } void Application::notifyTransfersChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { // Display notifications if one of the following happens: // - the device name is known (receiving only) // - transfer fails or succeeds for(int row = topLeft.row(); row <= bottomRight.row(); ++row) { QModelIndex index = mTransferModel.index(row, 0); if(roles.contains(TransferModel::DeviceNameRole)) { mIcon->showMessage(tr("Receiving transfer from %1.").arg( index.data(TransferModel::DeviceNameRole).toString() )); } else if(roles.contains(TransferModel::StateRole)) { switch(index.data(TransferModel::StateRole).toInt()) { case TransferModel::Failed: mIcon->showMessage(tr("Transfer with %1 failed.").arg( index.data(TransferModel::DeviceNameRole).toString() )); break; case TransferModel::Succeeded: mIcon->showMessage(tr("Transfer with %1 succeeded.").arg( index.data(TransferModel::DeviceNameRole).toString() )); break; } } } } void Application::sendFiles() { QStringList filenames(QFileDialog::getOpenFileNames(nullptr, tr("Select Files"))); if(filenames.count()) { Bundle *bundle = new Bundle; foreach(QString filename, filenames) { bundle->addFile(filename); } sendBundle(bundle); } } void Application::sendDirectory() { QString path(QFileDialog::getExistingDirectory(nullptr, tr("Select Directory"))); if(!path.isNull()) { Bundle *bundle = new Bundle; bundle->addDirectory(path); sendBundle(bundle); } } void Application::onOpenSettings() { SettingsDialog().exec(); } void Application::onOpenAbout() { AboutDialog().exec(); } void Application::onOpenAboutQt() { QMessageBox::aboutQt(nullptr); } void Application::sendBundle(const Bundle *bundle) { QModelIndex index = DeviceDialog::getDevice(&mDeviceModel); if(index.isValid()) { // Obtain the information needed to connect to the device QString deviceName = index.data(DeviceModel::NameRole).value(); QHostAddress address = index.data(DeviceModel::AddressRole).value(); quint16 port = index.data(DeviceModel::PortRole).value(); mTransferModel.addSender(deviceName, address, port, bundle); mTransferWindow.show(); } } nitroshare-0.3.1/src/dist/icons/gnome/24x24/000775 001750 001750 00000000000 12653764154 021231 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/ubuntu-mono-light/apps/24/nitroshare-indicator.svg000664 001750 001750 00000002600 12653764154 030775 0ustar00nathannathan000000 000000 image/svg+xml nitroshare-0.3.1/src/transfer/transferreceiver.cpp000664 001750 001750 00000017366 12653764154 023201 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "../settings/settings.h" #include "../util/json.h" #include "transferreceiver.h" TransferReceiver::TransferReceiver(qintptr socketDescriptor) : Transfer(TransferModel::Receive), mRoot(Settings::instance()->get(Settings::Key::TransferDirectory).toString()), mOverwrite(Settings::instance()->get(Settings::Key::BehaviorOverwrite).toBool()) { mSocket.setSocketDescriptor(socketDescriptor); mDeviceName = tr("[Unknown]"); } void TransferReceiver::start() { // The socket is already connected at this point } void TransferReceiver::processJsonPacket(const QJsonObject &object) { switch(mProtocolState) { case ProtocolState::TransferHeader: processTransferHeader(object); break; case ProtocolState::TransferItems: processItemHeader(object); break; default: writeErrorPacket(tr("Unexpected JSON packet received")); } } void TransferReceiver::processBinaryPacket(const QByteArray &data) { // Binary packets can only be received after the transfer header // and after a file header - for sanity, we check the amount of // data we're expecting to receive from the amount actually received if(mProtocolState == ProtocolState::TransferItems) { // The file will only be open if an item header was received prior // This error is also triggered if more data for the previous file arrives if(!mFile.isOpen()) { writeErrorPacket(tr("Binary packet received before item header")); return; } // Ensure that the size of the packet does not exceed the amount expected if(data.size() > mFileBytesRemaining) { writeErrorPacket(tr("Binary packet exceeds declared size")); return; } // Write the data to the file mFile.write(data); // Update the number of bytes remaining for the file and the total transferred mFileBytesRemaining -= data.size(); mTransferBytes += data.size(); // Provide a progress update updateProgress(); // If all of the file has been received, move on to the next item if(!mFileBytesRemaining) { mFile.close(); nextItem(); } } else { writeErrorPacket(tr("Unexpected binary packet received")); } } void TransferReceiver::writeNextPacket() { // No data is written after the success or error packet } void TransferReceiver::processTransferHeader(const QJsonObject &object) { QString deviceName; if(Json::objectContains(object, "name", deviceName) && Json::objectContains(object, "size", mTransferBytesTotal) && Json::objectContains(object, "count", mTransferItemsRemaining)) { // Indicate that the device name has changed mDeviceName = deviceName; emit dataChanged({TransferModel::DeviceNameRole}); // The next packet will be the first file header mProtocolState = ProtocolState::TransferItems; } else { writeErrorPacket(tr("Unable to read transfer header")); } } void TransferReceiver::processItemHeader(const QJsonObject &object) { // Before doing anything, ensure that the entire contents of // the previous file were received and that the file was closed if(mFile.isOpen()) { writeErrorPacket(tr("Item header received before previous file contents")); return; } QString name; bool directory; qint64 created; qint64 lastModified; qint64 lastRead; if(Json::objectContains(object, "name", name) && Json::objectContains(object, "directory", directory) && Json::objectContains(object, "created", created) && Json::objectContains(object, "last_modified", lastModified) && Json::objectContains(object, "last_read", lastRead)) { // TODO: created, lastModified, and lastRead are currently unused // Determine the absolute filename of the item QString filename = mRoot.absoluteFilePath(name); // If the item is a directory, attempt to create it // Otherwise, it's a file - open it for writing if(directory) { // Ensure the directory exists if(!QDir(filename).mkpath(".")) { writeErrorPacket(tr("Unable to create %1").arg(filename)); return; } // Move to the next item nextItem(); } else { // Ensure that the size was included if(!Json::objectContains(object, "size", mFileBytesRemaining)) { writeErrorPacket(tr("File size is missing from item header")); return; } // Abort if the file can't be opened mFile.setFileName(filename); if(!openFile()) { writeErrorPacket(tr("Unable to open %1").arg(filename)); return; } // If the file is empty, we'll never receive its contents (surprise!) // Therefore, we must immediately close the file and move to the next item if(!mFileBytesRemaining) { mFile.close(); nextItem(); } } } else { writeErrorPacket(tr("Unable to read file header")); } } void TransferReceiver::nextItem() { // Decrement the number of items remaining mTransferItemsRemaining -= 1; // If no more items remain, then write the success packet if(!mTransferItemsRemaining) { writeSuccessPacket(); } } bool TransferReceiver::openFile() { // NOTE: there is a known race-condition in the code below - it // is possible that a file could be created between checking for // the file and attempting to open it. However, this is incredibly // hard to work around and unlikely to be a problem in most normal // circumstances. // If overwrite is enabled OR the file doesn't exist, try // to open the file with the original filename if(mOverwrite || !mFile.exists()) { return mFile.open(QIODevice::WriteOnly); } // Break the filename into its components QRegularExpression re("^(.*?)((?:\\.tar)?\\.[^\\/\\\\]*)?$"); QRegularExpressionMatch match = re.match(mFile.fileName()); if(!match.hasMatch()) { return false; } // Try consecutive numbers int num = 2; while(mFile.exists()) { mFile.setFileName(QString("%1-%2%3") .arg(match.captured(1)) .arg(num++) .arg(match.captured(2))); } // One was found that doesn't exist - try opening it return mFile.open(QIODevice::WriteOnly); } nitroshare-0.3.1/src/application/aboutdialog.cpp000664 001750 001750 00000007662 12653764154 022577 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "../util/platform.h" #include "aboutdialog.h" #include "config.h" const QString Credits = "" "" "" "" "" "
Created by:Nathan Osman
Matthew Jump
Daniel San
"; const QString License = "The MIT License (MIT)\n\n" "Permission is hereby granted, free of charge, to any person obtaining a copy " "of this software and associated documentation files (the \"Software\"), to " "deal in the Software without restriction, including without limitation the " "rights to use, copy, modify, merge, publish, distribute, sublicense, and/or " "sell copies of the Software, and to permit persons to whom the Software is " "furnished to do so, subject to the following conditions:\n\n" "The above copyright notice and this permission notice shall be included in " "all copies or substantial portions of the Software.\n\n" "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR " "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, " "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE " "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER " "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING " "FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS " "IN THE SOFTWARE."; AboutDialog::AboutDialog() { setupUi(this); lblLogo->setPixmap(QPixmap(":/img/logo.svg").scaled(128, 128)); QFont font = lblProjectTitle->font(); font.setBold(true); lblProjectTitle->setFont(font); lblProjectTitle->setText(PROJECT_NAME); lblVersion->setText(QString("Version %1 - %2 %3").arg(PROJECT_VERSION) .arg(Platform::operatingSystemFriendlyName()) .arg(Platform::architectureName())); lblDescription->setText(PROJECT_DESCRIPTION); QString websiteTxt("%1"); lblWebsite->setText(websiteTxt.arg(PROJECT_WEBSITE)); lblCopyright->setText(QString("Copyright (c) 2016 - %1").arg(PROJECT_AUTHOR)); textBrowser->hide(); } void AboutDialog::onCreditsOrLicenceClicked(bool checked) { if(sender()->objectName() == "btnLicense") { textBrowser->setText(License); btnCredits->setChecked(false); } else if(sender()->objectName() == "btnCredits") { textBrowser->setText(Credits); btnLicense->setChecked(false); } textBrowser->setVisible(checked); wdtContent->setVisible(!checked); } nitroshare-0.3.1/src/dist/icons/ubuntu-mono-dark/000775 001750 001750 00000000000 12653764154 022550 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/device/devicemodel.h000664 001750 001750 00000007227 12653764154 021163 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_DEVICEMODEL_H #define NS_DEVICEMODEL_H #include class DeviceModelPrivate; /** * @brief Data model for discovered devices * * Devices continuously send out broadcast packets on all active network * interfaces. Once a packet is received, it is examined and an instance of * the Device class is created to represent the device. * * If a packet is not received from a device after a certain amount of time * has elapsed, the device is considered to have timed out and is removed. */ class DeviceModel : public QAbstractTableModel { Q_OBJECT public: /** * @brief Columns displayed in model views */ enum Column { /// Device name NameColumn = 0, /// Device operating system OperatingSystemColumn, /// Total number of columns ColumnCount }; /** * @brief Roles for retrieving device data from the model */ enum Role { /// Unique identifier UUIDRole = Qt::UserRole, /// Descriptive name NameRole, /// Operating system OperatingSystemRole, /// Transfer address AddressRole, /// Transfer port PortRole, }; /** * @brief Create a device model */ DeviceModel(); /** * @brief Retrieve the number of rows in the model * @param parent parent index * @return number of rows */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; /** * @brief Retrieve the number of columns in the model * @param parent parent index * @return number of columns */ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; /** * @brief Retrieve data for the specified index * @param index index to retrieve * @param role role to retrieve * @return retrieved data */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @brief Retrieve header data for the specified section * @param section section to retrieve * @param orientation orientation to retrieve * @param role role to retrieve * @return retrieved data */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** * @brief Retrieve names of all roles * @return hash of role names */ virtual QHash roleNames() const; private: DeviceModelPrivate * const d; friend class DeviceModelPrivate; }; #endif // NS_DEVICEMODEL_H nitroshare-0.3.1/src/transfer/000775 001750 001750 00000000000 12653764154 017107 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/transfer/transfer.h000664 001750 001750 00000007565 12653764154 021121 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFER_H #define NS_TRANSFER_H #include #include #include #include "transfermodel.h" /** * @brief A transfer between two devices * * This class facilitates the actual transfer of files and directories between * devices. Data is exchanged using "packets", which are distinct pieces of * information. Packets can contain metadata, file contents, or error message, * for example. * * At the beginning of the transfer, the device name, number of items, and * total size is sent. Then, for each item, its metadata and contents are * transferred. Once this is complete, an acknowledgement packet is sent. * * At a lower level, a packet consists of a 32-bit signed integer indicating * its size. The first byte of the packet indicates its type. Four types are * currently used - success, error, JSON, and binary packets. */ class Transfer : public QObject { Q_OBJECT public: // "explicit" is not needed here since this class is abstract Transfer(TransferModel::Direction direction); QString deviceName() const { return mDeviceName; } int progress() const { return mProgress; } TransferModel::Direction direction() const { return mDirection; } TransferModel::State state() const { return mState; } QString error() const { return mError; } virtual void start() = 0; void cancel(); void restart(); Q_SIGNALS: void dataChanged(const QVector &roles = {}); private Q_SLOTS: void onConnected(); void onReadyRead(); void onBytesWritten(); void onError(QAbstractSocket::SocketError error); protected: virtual void processJsonPacket(const QJsonObject &object) = 0; virtual void processBinaryPacket(const QByteArray &data) = 0; virtual void writeNextPacket() = 0; void writeSuccessPacket(); void writeErrorPacket(const QString &message); void writeJsonPacket(const QJsonObject &object); void writeBinaryPacket(const QByteArray &data); void updateProgress(); QTcpSocket mSocket; QString mDeviceName; enum class ProtocolState { TransferHeader, TransferItems, Acknowledgement, Finished } mProtocolState; qint64 mTransferBytes; qint64 mTransferBytesTotal; QFile mFile; qint64 mFileBytesRemaining; private: enum class PacketType : char { Success = 0, Error, Json, Binary }; void processPacket(); void writePacket(PacketType type, const QByteArray &data = QByteArray()); void reset(); void finish(TransferModel::State state); const TransferModel::Direction mDirection; TransferModel::State mState; QString mError; int mProgress; QByteArray mBuffer; qint32 mBufferSize; }; #endif // NS_TRANSFER_H nitroshare-0.3.1/src/transfer/transferserver.cpp000664 001750 001750 00000004550 12653764154 022672 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include "transferserver.h" #include "transferserver_p.h" TransferServerPrivate::TransferServerPrivate(TransferServer *transferServer) : QTcpServer(transferServer), q(transferServer) { connect(Settings::instance(), &Settings::settingsChanged, this, &TransferServerPrivate::onSettingsChanged); } void TransferServerPrivate::onSettingsChanged(const QList &keys) { Settings *settings = Settings::instance(); if(keys.empty() || keys.contains(Settings::Key::BehaviorReceive) || keys.contains(Settings::Key::TransferPort)) { close(); if(settings->get(Settings::Key::BehaviorReceive).toBool()) { quint16 port = Settings::instance()->get(Settings::Key::TransferPort).toInt(); if(!listen(QHostAddress::Any, port)) { emit q->error(tr("Unable to listen on port %1").arg(port)); } } } } void TransferServerPrivate::incomingConnection(qintptr socketDescriptor) { emit q->newTransfer(socketDescriptor); } TransferServer::TransferServer(QObject *parent) : QObject(parent), d(new TransferServerPrivate(this)) { } TransferServer::~TransferServer() { delete d; } void TransferServer::start() { d->onSettingsChanged(); } nitroshare-0.3.1/src/000775 001750 001750 00000000000 12653764154 015263 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/setup.iss.in000664 001750 001750 00000005647 12653764154 020527 0ustar00nathannathan000000 000000 ; This file is used to build setup.iss which is then fed to the Inno Setup compiler ; The variables used below come from the CMakeLists.txt #if ${CMAKE_SIZEOF_VOID_P} == 8 #define ARCH "x86_64" #else #define ARCH "x86" #endif [Setup] AppId = {{174A4547-917E-4BAF-9F25-FCE545CCD487} AppName = "${PROJECT_NAME}" AppVersion = "${PROJECT_VERSION}" AppPublisher = "${PROJECT_AUTHOR}" DefaultDirName = "{pf}\${PROJECT_NAME}" DefaultGroupName = "${PROJECT_NAME}" LicenseFile = "${CMAKE_CURRENT_SOURCE_DIR}\..\LICENSE.txt" OutputDir = "${CMAKE_BINARY_DIR}" OutputBaseFilename = "nitroshare-${PROJECT_VERSION}-windows-{#ARCH}" Compression = lzma SolidCompression = yes WizardImageFile = "${CMAKE_CURRENT_SOURCE_DIR}\dist\wizard-image.bmp" WizardSmallImageFile = "${CMAKE_CURRENT_SOURCE_DIR}\dist\wizard-small-image.bmp" ; Set two additional directives if we are building a 64-bit installer #if ARCH == "x86_64" ArchitecturesAllowed = x64 ArchitecturesInstallIn64BitMode = x64 #endif [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "${CMAKE_BINARY_DIR}\out\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] Name: "{group}\${PROJECT_NAME}"; Filename: "{app}\{#TARGET_FILE_NAME}" Name: "{group}\{cm:UninstallProgram,${PROJECT_NAME}}"; Filename: "{uninstallexe}" Name: "{commondesktop}\${PROJECT_NAME}"; Filename: "{app}\{#TARGET_FILE_NAME}"; Tasks: desktopicon [Run] Filename: "{app}\{#TARGET_FILE_NAME}"; Description: "{cm:LaunchProgram,${PROJECT_NAME}}"; Flags: nowait postinstall skipifsilent [Code] // The code below is adapted from // http://www.vincenzo.net/isxkb/index.php?title=Adding_a_rule_to_the_Windows_firewall procedure CurStepChanged(CurStep: TSetupStep); var FirewallManager: Variant; FirewallProfile: Variant; FirewallObject: Variant; begin if CurStep = ssPostInstall then try FirewallManager := CreateOleObject('HNetCfg.FwMgr'); FirewallProfile := FirewallManager.LocalPolicy.CurrentProfile; FirewallObject := CreateOleObject('HNetCfg.FwAuthorizedApplication'); FirewallObject.Name := '${PROJECT_NAME}'; FirewallObject.ProcessImageFileName := ExpandConstant('{app}\{#TARGET_FILE_NAME}'); FirewallProfile.AuthorizedApplications.Add(FirewallObject); except end; end; procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); var FirewallManager: Variant; FirewallProfile: Variant; begin if CurUninstallStep = usPostUninstall then try FirewallManager := CreateOleObject('HNetCfg.FwMgr'); FirewallProfile := FirewallManager.LocalPolicy.CurrentProfile; FireWallProfile.AuthorizedApplications.Remove(ExpandConstant('{app}\{#TARGET_FILE_NAME}')); except end; end; nitroshare-0.3.1/src/transfer/transfermodel.h000664 001750 001750 00000013364 12653764154 022134 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERMODEL_H #define NS_TRANSFERMODEL_H #include #include #include "../bundle/bundle.h" class TransferModelPrivate; /** * @brief Data model for transfers * * Transfers are created in one of two ways: in response to an incoming TCP * request or as the result of a user directive to transfer files. Once * started, they remain in the model until cleared, allowing them to be * restarted in case of error. */ class TransferModel : public QAbstractTableModel { Q_OBJECT Q_ENUMS(Direction) Q_ENUMS(State) public: /** * @brief Columns displayed in model views */ enum Column { /// Name of other device DeviceNameColumn = 0, /// Progress of transfer ProgressColumn, /// State of transfer StateColumn, /// Action that can be taken for the transfer ActionColumn, /// Total number of columns ColumnCount }; /** * @brief Roles for retrieving data from the model */ enum Role { /// Name of other device DeviceNameRole = Qt::UserRole, /// Progress of transfer ProgressRole, /// Direction of transfer DirectionRole, /// State of transfer StateRole, /// Error encountered during transfer ErrorRole }; /** * @brief Direction of transfer */ enum Direction { /// Transfer is sending files Send, /// Transfer is receiving files Receive }; /** * @brief State of transfer */ enum State { /// Connecting to remote host Connecting, /// File transfer in progress InProgress, /// Transfer failed Failed, /// Transfer succeeded Succeeded }; /** * @brief Create a transfer model * @param parent parent QObject */ explicit TransferModel(QObject *parent = nullptr); /** * @brief Destroy the transfer model */ virtual ~TransferModel(); /** * @brief Retrieve the number of rows in the model * @param parent parent index * @return number of rows */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; /** * @brief Retrieve the number of columns in the model * @param parent parent index * @return number of columns */ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; /** * @brief Retrieve data for the specified index * @param index index to retrieve * @param role role to retrieve * @return retrieved data */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @brief Retrieve header data for the specified section * @param section section to retrieve * @param orientation orientation to retrieve * @param role role to retrieve * @return retrieved data */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** * @brief Retrieve names of all roles * @return hash of role names */ virtual QHash roleNames() const; /** * @brief Calculate the combined progress of all transfers * @return progress of all transfers * * In order to avoid costly processing, the value is cached for a brief * period of time and all subsequent calls will return the cached value. */ int combinedProgress() const; public Q_SLOTS: /** * @brief Create a new transfer for receiving files * @param socketDescriptor socket descriptor * @param parent parent QObject */ void addReceiver(qintptr socketDescriptor); /** * @brief Create a new transfer for sending files * @param deviceName name of the device * @param address address of device * @param port port of device * @param bundle bundle to send to the specified device */ void addSender(const QString &deviceName, const QHostAddress &address, quint16 port, const Bundle *bundle); /** * @brief Cancel the specified transfer * @param index item index */ void cancel(int index); /** * @brief Restart the specified transfer * @param index item index */ void restart(int index); /** * @brief Dismiss the specified trasfer * @param index item index */ void dismiss(int index); /** * @brief Remove all finished transfers from the model */ void clear(); private: TransferModelPrivate *const d; friend class TransferModelPrivate; }; #endif // NS_TRANSFERMODEL_H nitroshare-0.3.1/src/dist/icons/hicolor/scalable/000775 001750 001750 00000000000 12653764154 022546 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/settings/settings.h000664 001750 001750 00000010511 12653764154 021132 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_SETTINGS_H #define NS_SETTINGS_H #include #include class SettingsPrivate; /** * @brief Interface for storing and retrieving settings * * Access to settings that control behavior of the application is done through * a global instance of this class. The global instance may be obtained * through the instance() static method. * * Settings can be retrieved by providing the appropriate key to the get() * method. To change the value of a single setting, use the set() method. The * process for changing the value of multiple settings is as follows: * * - call the beginSet() method * - call the set() method for each individual setting * - call the endSet() method * * To receive notification when a value changes, obtain the global instance * and connect to the settingsChanged() signal. * * Note: this class is not thread safe. */ class Settings : public QObject { Q_OBJECT public: /** * @brief Helpful unit constants */ enum Constant { Second = 1000, Minute = 60 * Second, Hour = 60 * Minute, KiB = 1024 }; /** * @brief Keys for individual settings */ enum class Key : int { /// Whether the splash dialog has been shown or not ApplicationSplash, /// Whether to overwrite incoming files BehaviorOverwrite, /// Whether to accept file transfers BehaviorReceive, /// Port for sending broadcast packets BroadcastPort, /// Time (in MS) between broadcast packets BroadcastInterval, /// Time (in MS) after receiving a device's last packet before considering the device offline BroadcastTimeout, /// Unique GUID used to identify the device DeviceUUID, /// Descriptive name of the device DeviceName, /// Port for receiving transfers TransferPort, /// Size (in bytes) of the buffer used for transferring file data TransferBuffer, /// Directory for storing received files and directories TransferDirectory, }; /** * @brief Retrieve the value of the specified key * @param key key to retrieve the value of * @return value for the specified key */ QVariant get(Key key); /** * @brief Begin changing a group of settings */ void beginSet(); /** * @brief Set the value of the specified key * @param key key to set the value of * @param value new value for the key */ void set(Key key, const QVariant &value); /** * @brief Finish changing a group of settings */ void endSet(); /** * @brief Reset all settings to their default values */ void reset(); /** * @brief Retrieve a pointer to the global settings instance * @return pointer to the global instance */ static Settings *instance(); Q_SIGNALS: /** * @brief Indicate that one or more settings have changed * @param keys list of keys with new values */ void settingsChanged(const QList &keys); private: // Prevent the creation or deletion of class instances Settings(); virtual ~Settings(); SettingsPrivate *const d; }; #endif // NS_SETTINGS_H nitroshare-0.3.1/src/data/icon/nitroshare.ico000775 001750 001750 00000063234 12653764154 022011 0ustar00nathannathan000000 000000  (~00 Nh ^!00 %+  Q h4b( @pppwpppppwp~~p~~p~~~~~~pppwpppp?( p~???(0`(((///222@@@VVVXXX___/-P?pQcv1Qq,/KPhp1Qq/!P7pLcyϏ1Qq/Pp",6@J[1qQq/Pp  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq                                                   ?( @&&&+++333???YYY```ssszzz-P?pQcv1Qq,/KPhp1Qq/!P7pLcyϏ1Qq/Pp",6@J[1qQq/Pp  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq                                ?(  ---888LLLUUU/-P?pQcv1Qq,/KPhp1Qq/!P7pLcyϏ1Qq/Pp",6@J[1qQq/Pp  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq        ???PNG  IHDR\rf MIDATx۱nGែɾ8`q= ."ԩ+Z kdO2kwf}|hro0{@#01VKs!3"P1(ѡru(ѡp}(M7E֍8:Zm(]7Erox58:jd(Qæ7EҶ- pt oQ]ox%:~[UޢG.J8:Ur(ѱ7EM- ptl oQ#WޢGG7E- ptܦ oQc7E- pt\- pt\- pt- pt oQ# oQ- oQ! oQ) oQ' oQ% oQ# oQ! oQޢG[/7E>ox}L8xz- p:~[y( oQoޢG(7EޯoxO8zF- p:~[y>/$ >_H@l= !11@Ba Co$@G5@BtH[}~k}/_$>g&@BH# p` !̃$yxٳ&?˫W_126ϟ?_^~|iyMFE@B\"P H C p!`@q !.l ($!0DE H&$uCF ![! p]n`zrxx^xyf`GC\0#@!n 7LLx*&Z@< )  pD` 7|2 QEC40x*u@<M2  ip`jGC05#@!$"@!\Q# 5#@!ܠd@<5JECEx#w5 @]"@!.D>|m988Pcxx ӧeKC\->. Bp`F0DC\"@!.tL >x"x&x*x.{C\0{{{iˣG|C\0=K%`#y>!n"@r7L y*f< 3k@ 1 p`fC0D!n"@7M y*f<M3j@ 1 p`FC0D!$#D!\{@5=G!ܠ<5zCEo y#w) p C/ y[< DCP<-DCR<DCQ<D!,@G RG!C@8P" p"˗/7o.>|X !̃$y80GA<@BH#: Rp@0H @{_8888P8P8P8P8P8Pp @#@/w!3R(`#:#w?s N`!:=? SN/`#:=DЉ? 5"@'bdN0 H`":Q'Ft"OA`Q?@GƏ`27":iƏ[`ЩƏ,@V?`)Ə` )Ə` 5;#:m?!:(i?#: ƏjNN?":w:s[? : й)M`h\ c`":10~`b&F`b-[RlIENDB`(0` I+`+`,`+`+`,`+`+`,`+[+y,yE3333yyyXXX///yyWWW222yy____________VVVUUU222yy333WWW222yy333WWW222yy333UUU222yy333WWW222yy333WWW222yy333UUUYYY222yy333WWWXXX222yy333YYY222yy333YYY222yy333XXX222yy333YYY222yy333ZZZ222yy333XXXVVV____________yy333YYYyy///YYYyyy3333Ey,y+[+`,`+`+`,`+`+`,`+`+I?( @ @@@@@@S&&&333??????&&&%%%%%%%%%%%%%%%'''''''''''''''&&&??????333'''S@@@@@@ ?(  # # #5X#hT qqqtttLLL ttttttUUUttttttVVVtttttt LLLtttqqq Th#X5# # #AAA?AAAAAAAAAAAAAnitroshare-0.3.1/src/util/json.cpp000664 001750 001750 00000004327 12653764154 017723 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include "json.h" bool Json::isArray(const QJsonDocument &document, QJsonArray &array) { array = document.array(); return document.isArray(); } bool Json::isObject(const QJsonDocument &document, QJsonObject &object) { object = document.object(); return document.isObject(); } bool Json::isObject(const QJsonValue &value, QJsonObject &object) { object = value.toObject(); return value.isObject(); } bool Json::objectContains(const QJsonObject &object, const QString &key, bool &value) { value = object.value(key).toBool(); return object.contains(key); } bool Json::objectContains(const QJsonObject &object, const QString &key, qint32 &value) { value = object.value(key).toString().toInt(); return object.contains(key); } bool Json::objectContains(const QJsonObject &object, const QString &key, qint64 &value) { value = object.value(key).toString().toLongLong(); return object.contains(key); } bool Json::objectContains(const QJsonObject &object, const QString &key, QString &value) { value = object.value(key).toString(); return object.contains(key); } nitroshare-0.3.1/src/dist/icons/gnome/24x24/apps/000775 001750 001750 00000000000 12653764154 022174 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/settings/settingsdialog.ui000664 001750 001750 00000030656 12653764154 022514 0ustar00nathannathan000000 000000 SettingsDialog 0 0 500 450 500 450 500 450 Settings :/img/logo.svg:/img/logo.svg General Qt::Vertical 20 40 Device name: Directory: 35 0 35 16777215 ... Behavior Receive files Overwrite files with identical names Advanced Port: <html><head/><body><p><span style=" font-weight:600;">Warning:</span> Changing the settings below may cause NitroShare to stop functioning or use excessive bandwidth. Proceed with caution.</p></body></html> true <html><head/><body><p><span style=" font-weight:600;">Transfer settings</span></p></body></html> Port: 0 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 65535 1 Buffer: 0 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter KiB 1 1024 QFrame::Sunken Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Broadcast settings</span></p></body></html> Timeout: 0 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 65535 Interval: 0 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter sec 1 999999999 Qt::Horizontal 0 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter sec 1 999999999 Qt::Vertical 20 40 Reset QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SettingsDialog accept() 194 359 236 160 buttonBox rejected() SettingsDialog reject() 194 359 236 160 resetButton clicked() SettingsDialog onResetButtonClicked() 59 359 199 124 transferDirectoryButton clicked() SettingsDialog onTransferDirectoryButtonClicked() 461 96 249 199 onResetButtonClicked() onTransferDirectoryButtonClicked() nitroshare-0.3.1/src/dist/icons/breeze-dark/apps/22/000775 001750 001750 00000000000 12653764154 022722 5ustar00nathannathan000000 000000 nitroshare-0.3.1/cmake/000775 001750 001750 00000000000 12653764154 015554 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/transfer/transfer.cpp000664 001750 001750 00000022604 12653764154 021443 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include #include "../util/json.h" #include "transfer.h" Transfer::Transfer(TransferModel::Direction direction) : mDirection(direction) { connect(&mSocket, &QTcpSocket::connected, this, &Transfer::onConnected); connect(&mSocket, &QTcpSocket::readyRead, this, &Transfer::onReadyRead); connect(&mSocket, &QTcpSocket::bytesWritten, this, &Transfer::onBytesWritten); // The error() method is overloaded (sigh) so we need to be very explicit here connect(&mSocket, static_cast(&QTcpSocket::error), this, &Transfer::onError); // Set all of the transfer members to proper initial values reset(); } void Transfer::cancel() { // Ensure that the transfer is actually in progress before trying to cancel it if(mState == TransferModel::Failed || mState == TransferModel::Succeeded) { qWarning("Cannot cancel a transfer that has completed"); return; } // Canceling a request is considered an "error" and is treated the same way // Only attempt to report the error if the transfer isn't already finished if(mProtocolState != ProtocolState::Finished) { writeErrorPacket(tr("Transfer was canceled")); } } void Transfer::restart() { // Ensure that the transfer is sending data and not receiving if(mDirection == TransferModel::Receive) { qWarning("Cannot restart a transfer that receives files"); return; } // Ensure that the transfer failed if(mState != TransferModel::Failed) { qWarning("Cannot restart a transfer that has not failed"); return; } // Reset all of the transfer variables and start again reset(); start(); } void Transfer::onConnected() { mState = TransferModel::InProgress; emit dataChanged({TransferModel::StateRole}); // Begin writing the first packet writeNextPacket(); } void Transfer::onReadyRead() { // Add all of the new data to the buffer mBuffer.append(mSocket.readAll()); // Process as many packets as can be read from the buffer forever { // If the transfer is finished, ignore any packets being received if(mProtocolState == ProtocolState::Finished) { break; } // If the size of the packet is not yet known attempt to read it if(!mBufferSize) { // See if there is enough data in the buffer to read the size if(static_cast(mBuffer.size()) >= sizeof(mBufferSize)) { // memcpy must be used in order to avoid alignment issues // Also, the integer uses little endian byte order // so convert it to the host format if necessary memcpy(&mBufferSize, mBuffer.constData(), sizeof(mBufferSize)); mBufferSize = qFromLittleEndian(mBufferSize); mBuffer.remove(0, sizeof(mBufferSize)); // A packet size of zero is an error if(!mBufferSize) { writeErrorPacket(tr("Empty packet received")); break; } } else { break; } } // If the buffer contains enough data to read the packet, then do so if(mBuffer.size() >= mBufferSize) { processPacket(); } else { break; } } } void Transfer::onBytesWritten() { // Wait until there is no more pending data to write if(!mSocket.bytesToWrite()) { // If the transfer finished, then report success or failure // Otherwise, have the child class write the next packet if(mProtocolState == ProtocolState::Finished) { finish(mError.isNull() ? TransferModel::Succeeded : TransferModel::Failed); } else { writeNextPacket(); } } } void Transfer::onError(QAbstractSocket::SocketError) { // Errors are only meaningful during the Connecting and InProgress if(mState == TransferModel::Connecting || mState == TransferModel::InProgress) { finish(TransferModel::Failed); } } void Transfer::writeSuccessPacket() { // A success packet contains absolutely no data writePacket(PacketType::Success); mProtocolState = ProtocolState::Finished; } void Transfer::writeErrorPacket(const QString &message) { // Send the error as a UTF-8 encoded string writePacket(PacketType::Error, message.toUtf8()); // Record the error message and emit the appropriate signal mError = message; emit dataChanged({TransferModel::ErrorRole}); // Indicate that the transfer has finished so that all future packets are ignored mProtocolState = ProtocolState::Finished; } void Transfer::writeJsonPacket(const QJsonObject &object) { // Convert the JSON object to a byte array and send it writePacket(PacketType::Json, QJsonDocument(object).toJson(QJsonDocument::Compact)); } void Transfer::writeBinaryPacket(const QByteArray &data) { // Pass the data along unmodified writePacket(PacketType::Binary, data); } void Transfer::updateProgress() { // Store the old value to avoid emiting the dataChanged signal more often than necessary int oldProgress = mProgress; // Calculate the current progress in the range 0-100, // being careful to avoid a division by 0 error if(mTransferBytesTotal) { double n = static_cast(mTransferBytes), d = static_cast(mTransferBytesTotal); mProgress = static_cast((n / d) * 100.0); } else { mProgress = 0; } // Ensure that the value falls within range mProgress = qMin(qMax(mProgress, 0), 100); // Only emit a signal if the value changes if(mProgress != oldProgress) { emit dataChanged({TransferModel::ProgressRole}); } } void Transfer::processPacket() { // Grab the data from the front of the buffer const char type = mBuffer.at(0); QByteArray data = mBuffer.mid(1, mBufferSize - 1); mBuffer.remove(0, mBufferSize); mBufferSize = 0; // Process the data based on the type switch(static_cast(type)) { case PacketType::Success: { finish(TransferModel::Succeeded); break; } case PacketType::Error: { // An error occurred - grab the error message mError = QString::fromUtf8(data); emit dataChanged({TransferModel::ErrorRole}); finish(TransferModel::Failed); break; } case PacketType::Json: { // Verify the JSON is valid and pass it along QJsonDocument document = QJsonDocument::fromJson(data); if(document.isObject()) { processJsonPacket(document.object()); } else { writeErrorPacket(tr("Unable to read JSON packet")); } break; } case PacketType::Binary: { // Pass the packet along unmodified processBinaryPacket(data); break; } default: // Any other type of packet is an error writeErrorPacket(tr("Unrecognized packet received")); } } void Transfer::writePacket(PacketType type, const QByteArray &data) { // Write the size of the packet including its type qint32 packetSize = qToLittleEndian(data.length() + 1); mSocket.write(reinterpret_cast(&packetSize), sizeof(packetSize)); // Write the packet type and the data (if provided) mSocket.write(reinterpret_cast(&type), 1); if(data.length()) { mSocket.write(data); } } void Transfer::reset() { // Reset all of the state variables to their initial values mProtocolState = ProtocolState::TransferHeader; mTransferBytes = 0; mTransferBytesTotal = 0; // The state is already in progress for a receiving transfer mState = mDirection == TransferModel::Send ? TransferModel::Connecting : TransferModel::InProgress; mError.clear(); mProgress = 0; mBuffer.clear(); mBufferSize = 0; // For simplicity, signal that all roles have changed emit dataChanged(); } void Transfer::finish(TransferModel::State state) { // Change the state and emit the signal indicating the change mState = state; emit dataChanged({TransferModel::StateRole}); // Close the socket and any open file mSocket.abort(); mFile.close(); } nitroshare-0.3.1/src/bundle/bundle_p.h000664 001750 001750 00000002525 12653764154 020501 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_BUNDLEPRIVATE_H #define NS_BUNDLEPRIVATE_H #include #include "bundleitem.h" class BundlePrivate { public: QList items; qint64 totalSize = 0; }; #endif // NS_BUNDLEPRIVATE_H nitroshare-0.3.1/src/util/platform.cpp000664 001750 001750 00000011706 12653764154 020575 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include "platform.h" Platform::OperatingSystem Platform::currentOperatingSystem() { #if defined(Q_OS_WIN32) return OperatingSystem::Windows; #elif defined(Q_OS_MACX) return OperatingSystem::OSX; #elif defined(Q_OS_LINUX) return OperatingSystem::Linux; #else return OperatingSystem::Unknown; #endif } Platform::Architecture Platform::currentArchitecture() { // Note: Qt doesn't provide the definitions we need to accurately // determine the CPU architecture - in order to do that, we'll need // to check a few preprocessor definitions ourselves #if defined(__i386__) || defined(_M_IX86) return Architecture::x86; #elif defined(__x86_64__) || defined(_M_X64) return Architecture::x64; #else return Architecture::Unknown; #endif } Platform::DesktopEnvironment Platform::currentDesktopEnvironment() { QString desktop = QProcessEnvironment::systemEnvironment().value("XDG_CURRENT_DESKTOP").toLower(); if(desktop == "unity") { return DesktopEnvironment::Unity; } else if(desktop.startsWith("gnome")) { return DesktopEnvironment::Gnome; } else if(desktop.endsWith("plasma")) { return DesktopEnvironment::KDE; } else if(desktop == "xfce") { return DesktopEnvironment::XFCE; } else if(desktop == "mate") { return DesktopEnvironment::MATE; } else if(desktop.endsWith("cinnamon")) { return DesktopEnvironment::Cinnamon; } else if(desktop == "pantheon") { return DesktopEnvironment::Pantheon; } else { return DesktopEnvironment::Unknown; } } QString Platform::operatingSystemName(OperatingSystem operatingSystem) { switch(operatingSystem) { case OperatingSystem::Windows: return "windows"; case OperatingSystem::OSX: return "osx"; case OperatingSystem::Linux: return "linux"; default: return "unknown"; } } QString Platform::operatingSystemFriendlyName(OperatingSystem operatingSystem) { switch(operatingSystem) { case OperatingSystem::Windows: return QObject::tr("Windows"); case OperatingSystem::OSX: return QObject::tr("OS X"); case OperatingSystem::Linux: return QObject::tr("Linux"); default: return QObject::tr("Unknown"); } } Platform::OperatingSystem Platform::operatingSystemForName(const QString &name) { if(name == "windows") { return OperatingSystem::Windows; } else if(name == "osx") { return OperatingSystem::OSX; } else if(name == "linux") { return OperatingSystem::Linux; } else { return OperatingSystem::Unknown; } } QString Platform::architectureName(Architecture architecture) { switch(architecture) { case Architecture::x86: return "x86"; case Architecture::x64: return "x86_64"; default: return "unknown"; } } bool Platform::useIndicator() { // Detecting the correct icon to display is incredibly difficult - the // algorithm currently being used goes something like this: // - Windows: use QSystemTrayIcon // - OS X: use QSystemTrayIcon // - Linux: // - Unity: use AppIndicator // - Gnome: use AppIndicator // - KDE: use QSystemTrayIcon // - MATE: use AppIndicator // - Cinnamon: use AppIndicator // - Pantheon: use AppIndicator if(currentOperatingSystem() == OperatingSystem::Linux) { switch(currentDesktopEnvironment()) { case DesktopEnvironment::Unity: case DesktopEnvironment::Gnome: case DesktopEnvironment::MATE: case DesktopEnvironment::Cinnamon: case DesktopEnvironment::Pantheon: return true; default: return false; } } // For everything else, use QSystemTrayIcon return false; } nitroshare-0.3.1/000775 001750 001750 00000000000 12653764161 014472 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/icon/icon.h000664 001750 001750 00000002713 12653764154 017317 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_ICON_H #define NS_ICON_H #include class Icon : public QObject { Q_OBJECT public: virtual void addAction(const QString &text, QObject *object, const char *slot) = 0; virtual void addSeparator() = 0; public Q_SLOTS: virtual void showMessage(const QString &message) = 0; }; #endif // NS_ICON_H nitroshare-0.3.1/src/transfer/transfermodel_p.h000664 001750 001750 00000003166 12653764154 022452 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERMODELPRIVATE_H #define NS_TRANSFERMODELPRIVATE_H #include #include "transfer.h" #include "transfermodel.h" class TransferModelPrivate { public: explicit TransferModelPrivate(TransferModel *transferModel); virtual ~TransferModelPrivate(); void add(Transfer *transfer); void remove(Transfer *transfer); TransferModel *const q; QList transfers; int cachedProgress; qint64 cachedProgressAge; }; #endif // NS_TRANSFERMODELPRIVATE_H nitroshare-0.3.1/src/settings/settings.cpp000664 001750 001750 00000011633 12653764154 021473 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include #include "settings.h" #include "settings_p.h" // For each individual key, store its name and an initialization function struct KeyInfo { QString name; QVariant (*initialize)(); }; // Macro used for generating the initialization list for a map #define DEFINE_SETTING(x,y) \ { \ Settings::Key::x, { #x, []() -> QVariant y } \ } // Map keys to the appropriate KeyInfo instance const QMap KeyMap = { DEFINE_SETTING(ApplicationSplash, { return false; }), DEFINE_SETTING(BehaviorOverwrite, { return false; }), DEFINE_SETTING(BehaviorReceive, { return true; }), DEFINE_SETTING(BroadcastPort, { return 40816; }), DEFINE_SETTING(BroadcastInterval, { return 5 * Settings::Constant::Second; }), DEFINE_SETTING(BroadcastTimeout, { return 30 * Settings::Constant::Second; }), DEFINE_SETTING(DeviceUUID, { return QUuid::createUuid().toString(); }), DEFINE_SETTING(DeviceName, { return QHostInfo::localHostName(); }), DEFINE_SETTING(TransferPort, { return 40818; }), DEFINE_SETTING(TransferBuffer, { return 64 * Settings::Constant::KiB; }), DEFINE_SETTING(TransferDirectory, { return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); }), }; SettingsPrivate::SettingsPrivate(Settings *settings) : q(settings) { } QVariant SettingsPrivate::get(Settings::Key key, Flag flag) { // Retrieve the name and initialization function for the key KeyInfo keyInfo = KeyMap.value(key); QVariant value = settings.value(keyInfo.name); // If no value was set and initialization is permited, initialize the setting if(value.isNull() && flag == Flag::Initialize) { value = keyInfo.initialize(); set(key, value); } return value; } void SettingsPrivate::set(Settings::Key key, const QVariant &value, Flag flag) { settings.setValue(KeyMap.value(key).name, value); // Take care of emitting the signal only if the appropriate flag was set if(flag == Flag::EmitSignal) { // If multiSet is set, add the setting to the list // Otherwise, emit the signal indicating a change if(multiSet) { multiSetKeys.append(key); } else { emit q->settingsChanged({key}); } } } QVariant Settings::get(Key key) { return d->get(key, SettingsPrivate::Flag::Initialize); } void Settings::beginSet() { if(d->multiSet) { qWarning("beginSet() already invoked"); return; } d->multiSet = true; } void Settings::set(Key key, const QVariant &value) { // Retrieve the current value but don't initialize QVariant currentValue = d->get(key); // Set the value only if it has actually changed and emit the signal if(currentValue != value) { d->set(key, value, SettingsPrivate::Flag::EmitSignal); } } void Settings::endSet() { if(!d->multiSet) { qWarning("beginSet() must be invoked before endSet()"); return; } // If any keys were modified, emit the signal // with the list of keys and clear the list if(d->multiSetKeys.count()) { emit settingsChanged(d->multiSetKeys); d->multiSetKeys.clear(); } d->multiSet = false; } void Settings::reset() { beginSet(); for(QMap::const_iterator i = KeyMap.constBegin(); i != KeyMap.constEnd(); ++i) { set(i.key(), i.value().initialize()); } endSet(); } Settings *Settings::instance() { // By using a static variable here, we allow the constructor and destructor // to be private, which prevents other instances and accidental deletion static Settings settings; return &settings; } Settings::Settings() : d(new SettingsPrivate(this)) { } Settings::~Settings() { delete d; } nitroshare-0.3.1/README.md000664 001750 001750 00000011051 12653764154 015751 0ustar00nathannathan000000 000000 ## NitroShare [![](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](http://opensource.org/licenses/MIT) [![Join the chat at https://gitter.im/nitroshare/nitroshare-desktop](http://img.shields.io/badge/gitter-JOIN_CHAT-green.svg?style=flat)](https://gitter.im/nitroshare/nitroshare-desktop?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) A cross-platform network file transfer application designed to make transferring any file to any device as painless as possible. ### Features * Runs on Windows / Mac OS X / Linux * Automatic discovery of devices on the local network * Simple and intuitive user interface * Transfer entire directories * Completely free and open-source ### Build Requirements The requirements for building NitroShare are as follows: * CMake 3.2.0+ * C++ compiler with support for C++11: * Microsoft Visual C++ 2013+ * GCC 4.7+ * Clang 3.1+ * Qt 5.1+ (Qt 5.3+ required for building installers) On supported Linux platforms, NitroShare can be built with support for [application indicators](https://unity.ubuntu.com/projects/appindicators/) and Unity integration. These features are enabled when the following development packages are installed: * GTK+ 2 * libappindicator * libnotify * libunity ### Building the Application The instructions below describe the build process for each of the supported platforms. #### Ubuntu 14.04, 14.10, 15.04, & 15.10 1. Versions of Ubuntu prior to 15.10 (Wily Werewolf) include an outdated version of CMake and therefore you will need to add the following PPA before installing CMake: sudo add-apt-repository ppa:george-edison55/cmake-3.x sudo apt-get update 2. Install GCC, CMake, and the Qt 5 development files: sudo apt-get install build-essential cmake qtbase5-dev To enable support for application indicators and Unity integration, you will need to install the following packages: sudo apt-get install libgtk2.0-dev libappindicator-dev libnotify-dev libunity-dev 2. Change to the root of the source directory and build the project: mkdir build && cd build cmake .. make 3. The NitroShare binary will be in the `out/` directory and can be run with: out/nitroshare #### Windows 7, 8, 8.1, and 10 1. Download and install the following tools: - [Visual Studio Express 2013 for Windows Desktop](http://go.microsoft.com/?linkid=9832280&clcid=0x409) [requires sign-in] - [CMake](https://cmake.org/download/) - [Qt Online Installer for Windows](http://www.qt.io/download-open-source/) 2. Ensure that the `bin` directory for Qt has been added to the `PATH` environment variable. 3. Open the appropriate command prompt for Visual C++. In Visual C++ 2013, these shortcuts are labeled as follows: - VS2013 x86 Native Tools Command Prompt - VS2013 x64 Cross Tools Command Prompt 4. Change to the root of the source directory and build the project mkdir build && cd build cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release .. nmake 5. The NitroShare binary will be in the `out\` directory and can be run with: out\nitroshare.exe > **Note:** if you receive an error similar to "The program can't start because [...].dll is missing from your computer.", then you will need to manually copy the Qt DLLs to the same directory as the executable. (This is done automatically for Qt 5.2+.) #### OS X 10.7, 10.8, 10.9, 10.10, & 10.11 1. Download and install the following tools: - [Xcode](https://itunes.apple.com/ca/app/xcode/id497799835?mt=12) - [CMake](https://cmake.org/download/) - [Qt Online Installer for Mac](http://www.qt.io/download-open-source/) 2. Ensure that the `bin` directory for CMake and Qt have been added to `/etc/paths`. 3. Open the terminal app, change to the root source directory, and build the project: mkdir build && cd build cmake .. make 4. The NitroShare bundle will be in the `out/` directory and can be run with: open out/nitroshare.app ### Building the Installers and Packages The instructions below describe the steps necessary to create installers or packages on each of the supported platforms. #### Ubuntu Debian packaging for NitroShare can be found here: https://github.com/nitroshare/nitroshare-desktop-debian #### Windows Building the installers for 32 and 64-bit editions of Windows requires [Inno Setup](http://www.jrsoftware.org/isinfo.php). Run the following command to build a Windows EXE installer: nmake exe #### OS X Run the following command to build a compressed disk image: make dmg nitroshare-0.3.1/src/dist/icons/breeze/apps/22/000775 001750 001750 00000000000 12653764154 022003 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/device/devicemodel.cpp000664 001750 001750 00000013565 12653764154 021520 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include "../util/platform.h" #include "devicemodel.h" #include "devicemodel_p.h" // Enable QHostAddress and OperatingSystem to be used in a QVariant Q_DECLARE_METATYPE(QHostAddress) Q_DECLARE_METATYPE(Platform::OperatingSystem) DeviceModelPrivate::DeviceModelPrivate(DeviceModel *deviceModel) : QObject(deviceModel), q(deviceModel) { connect(&timer, &QTimer::timeout, this, &DeviceModelPrivate::update); connect(&listener, &DeviceListener::pingReceived, this, &DeviceModelPrivate::processPing); connect(Settings::instance(), &Settings::settingsChanged, this, &DeviceModelPrivate::onSettingsChanged); onSettingsChanged(); timer.start(); } DeviceModelPrivate::~DeviceModelPrivate() { qDeleteAll(devices); } void DeviceModelPrivate::processPing(const QString &uuid, const QString &name, Platform::OperatingSystem operatingSystem, const QHostAddress &address, quint16 port) { // Ensure that the UUID does not match this device // since we will receive our own broadcast packets if(uuid == Settings::instance()->get(Settings::Key::DeviceUUID).toString()) { return; } // Attempt to find an existing device with the UUID Device *device = nullptr; int row = 0; for(; row < devices.count(); ++row) { if(devices.at(row)->uuid() == uuid) { device = devices.at(row); } } // Create a new device if one does not yet exist with the UUID bool created = static_cast(!device); if(created) { device = new Device(uuid); } // Update the device and check to see if anything important has changed bool changed = device->update(name, operatingSystem, address, port); // Add the device if it was created, and otherwise, check to see // if something changed and emit the appropriate signal if so if(created) { q->beginInsertRows(QModelIndex(), devices.count(), devices.count()); devices.append(device); q->endInsertRows(); } else if(changed) { emit q->dataChanged(q->index(row, 0), q->index(row, DeviceModel::ColumnCount)); } } void DeviceModelPrivate::update() { // Iterate over the list in reverse to preserve indices when items are removed for(int row = devices.count() - 1; row >= 0; --row) { Device *device = devices.at(row); // Remove the device if it has timed out if(device->hasTimedOut()) { q->beginRemoveRows(QModelIndex(), row, row); devices.removeAt(row); q->endRemoveRows(); delete device; } } } void DeviceModelPrivate::onSettingsChanged(const QList &keys) { if(keys.empty() || keys.contains(Settings::Key::BroadcastTimeout)) { timer.setInterval(Settings::instance()->get(Settings::Key::BroadcastTimeout).toInt()); } } DeviceModel::DeviceModel() : d(new DeviceModelPrivate(this)) { } int DeviceModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : d->devices.count(); } int DeviceModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : ColumnCount; } QVariant DeviceModel::data(const QModelIndex &index, int role) const { if(!index.isValid() || index.model() != this) { return QVariant(); } Device *device = d->devices.at(index.row()); switch(role) { case Qt::DisplayRole: switch(index.column()) { case NameColumn: return device->name(); case OperatingSystemColumn: return Platform::operatingSystemFriendlyName(device->operatingSystem()); } break; case Qt::DecorationRole: if(index.column() == NameColumn) { return QIcon(":/img/desktop.svg"); } break; case UUIDRole: return device->uuid(); case NameRole: return device->name(); case OperatingSystemRole: return QVariant::fromValue(device->operatingSystem()); case AddressRole: return QVariant::fromValue(device->address()); case PortRole: return device->port(); } return QVariant(); } QVariant DeviceModel::headerData(int section, Qt::Orientation orientation, int role) const { if(orientation != Qt::Horizontal || role != Qt::DisplayRole) { return QAbstractItemModel::headerData(section, orientation, role); } switch(section) { case NameColumn: return tr("Device Name"); case OperatingSystemColumn: return tr("Operating System"); } return QVariant(); } QHash DeviceModel::roleNames() const { return { {UUIDRole, "uuid"}, {NameRole, "name"}, {OperatingSystemRole, "operating_system"}, {AddressRole, "address"}, {PortRole, "port"} }; } nitroshare-0.3.1/src/transfer/transferwindow.h000664 001750 001750 00000005205 12653764154 022336 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERWINDOW_H #define NS_TRANSFERWINDOW_H #include #include "config.h" #include "transfermodel.h" #include "ui_transferwindow.h" #ifdef Qt5WinExtras_FOUND #include #endif #ifdef UNITY_FOUND #include #endif /** * @brief Displays a list of all transfers in the model * * Given a TransferModel, this class will present a window that allows the * user to view the transfers that are currently in progress. In addition, * the user can cancel transfers in progress and restart failed transfers. * * The window listens for changes to the model and inserts the appropriate * widgets into cells in the table. The progress bar is updated as necessary. */ class TransferWindow : public QMainWindow, public Ui::TransferWindow { Q_OBJECT public: explicit TransferWindow(TransferModel *model); Q_SIGNALS: void sendFiles(); void sendDirectory(); public Q_SLOTS: void onRowsInserted(const QModelIndex &parent, int first, int last); void onDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector &roles); private: #ifdef Qt5WinExtras_FOUND virtual void showEvent(QShowEvent *); virtual void hideEvent(QHideEvent *); #endif void updateProgressBar(int row); void updateButton(int row); TransferModel *const mModel; #ifdef Qt5WinExtras_FOUND QWinTaskbarButton *mTaskbarButton; #endif #ifdef UNITY_FOUND UnityLauncherEntry *mLauncherEntry; #endif }; #endif // NS_TRANSFERDIALOG_H nitroshare-0.3.1/src/application/splashdialog.h000664 001750 001750 00000002650 12653764154 022414 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_SPLASHDIALOG_H #define NS_SPLASHDIALOG_H #include #include "ui_splashdialog.h" /** * @brief Simple dialog describing the application */ class SplashDialog : public QDialog, public Ui::SplashDialog { Q_OBJECT public: SplashDialog(); }; #endif // NS_SPLASHDIALOG_H nitroshare-0.3.1/src/data/img/splash.png000664 001750 001750 00000125610 12653764154 020755 0ustar00nathannathan000000 000000 PNG  IHDR5 pHYs B(xtIME&C IDATx{\.rPDBVo"'/VA4Rci^ff /( (, PFYv_/^/vvvg~w% B!RB!PH!B($B!B! !BB!@B!B !BB!PH!B($B!B! !BB!B! !BB!@B!ҨR۳3lGS.) !ԓV֐ȾP($^}fPH!SK,wB!X9٠k[9**xRZGEy!APPAO{p>/BE!R/̞0&Bls ;=IB<o݃OK1h jzbmaQ}N-ծ)N=Ź+tTԎ.у^:51xۑ7-akcw&EvTԗu2`tiͱ~zOƬ񃕂2y9 i)q[XY ,NMjEuoN0 XL,^ 89"N.*ebzi҆kL3o̽>vù+p_&&ж<ݜnxR"Is !"<::QAzk;>[9Ҿ 7iTԗuһpkM.m9ˡ~\WPK>Ү\׳z}9|mZ¥=P&(C0$&&B ˩ 7 ;K=a0L[:ʟ9 Z4Fi)vJN# I~ =#Qn`=aanؾ/A($']ş) gG{*˕ɋT @B!7L&i@-_\}7N !Hl( %7Bi " 1fqn6搕qSdŕ{JP2:ENNI)Χ@ #;} KXqS=~+7)>@/"tsmgG{طEOJpC\~e&Ӗڵ[{G@ + R#n.=2d mZu NΤ8U5cks = ^6B]#l-WB!;S+[ fbSQXTw>D׺ ޹-la fbS=E^A1_FaqI+y !1(x>ѣ!r/,U~I ~3~:yN׆)]Yf=Ez]pi|j2M+[he[R~Oa篧P" S^@PL#)m1\@4|u&xש`G~O=&K!mZPnAѳ'q3nrG ?~/n#u0/ |~w$8`+=umZL0ax`"Sqahikکxggwlt/HUȰl{yyaA6V(kc8A`}y+K k''unS}yEJdrXI }1YJ0a#¼O徴 -=.91L{eV(-CoSWCTtAEOKe0չ5\džbP77z9' \\#?) &&BE* غ(6屲0{aX_/ʳ%c(.D(L̕~X;qqtzj#/6r6iqEء{goqGdEK cdxwh:(FWT s3\-%f0\Aވ]_Uum&aND1=-σX@..7I_jGΛDXm[٢K6<.f(aD>c &&Bwh`߮;f`1͸r^4s (-{0?ZkpC.yy;d| WG| lL}%{}=9|I_GP(pF/WD􅧛3=>\ѷ)WXkJ?N]BʥL<+DEm ~]r8w mG[F/P}PVo?i.[-O4 ՞cxՁ' [~`$ZY%oMwCASąkq]d}tϱe z!*\ 6-akc5'!:Kd}6 }u + ..~OƱ \ɼgm /y` Czwqј﯍>lࣂbCG.gEg;kèP ]߸&c?'­#"S,y/JOjܯiőg^[5p*:{^wp7y\4wGGX**yG E\,¤}a.2ŧkL3O.PmUΣ`A^!"4E`hߗpQQ6ly\4lm,<; {pZߺ=I];9qsvQm> Q  )78QC{b6/έ18S_ Aͯx^D Ċw^C- WO]q_jVH ?3G#į",~3Sl2x]=k'Ұj^<vY*ɿא/ 3Ύ޹fOguM*ક:v?:|-lI0{7έy.~ \321oy?gћҍ;f^#g1_si:z\v= &EzEL]%8>L,§sߩ똶ds6UPd4@껍4ƾ˹>OpsSһLMspHnts6h_}XPxIɱ\ ^O~:%2L_{A~ک-&++Wl'Ocr#ؼ)!}߼RY Fc_l\**%f6Q8V l??ކG>^Xk\}=LWeer| U^ KbA~l@ P? >PUT|CՇ|ronK.>j(yP r >fM?Jm$bLrV":])olGs1&˽^F5Di}1s}I׈>ڮ6֪|s,[9xu?شt*BչOn VJJ˴BUd! 'L&w#'%2tA=)&Kж%{-oNpƯ:ˡ*O+]s:MnIl;/qK*om!Hc틍  i)bQHX[돫 ~97EדxX+O7gx5lp wY/.`u ==:xv˱ge.ЯzE5vmއ{VU[VBbÂ"ܾ?PV^y8ygW5yXǧ[dSzWo(]-j,_z'u?h6Xbc/gC{\/? WnT}|\μYƑtn.Wl ntߛ3tvnޞ1Ow 獈> \@eb"4L]u}rFV15orOyC^NV۹ZS6n%ndz_:"5buݯ@VvFv<ݜS.f6~m)Xߓ1-M3twcZ[Ɛr1)3ޡ x9C,2"!<;Mkߛ .pT덧|m]v}Բeb"Bhߦ&r%/NkZ-υO{L,Yws30U+ ry^ycSZ&7#FB_l\/BOÆ%ob?4~ں˶ #1s#k5nӐ}D=1>,ۅ>0ųbU .sm+yj|\VAmٵF\T?em_쨏 ۗo#M/6rFlg*"B|0TꅟřKHyckuQQ?CVhK^oکtF7;Gx_%Q&/ǖӸ&L29"S˵9Mq!~`c%czQ7կna#߂] խs[] Kg_8xA͇P(nq0#f},-!HgN,_\tAtK=WuRԠZyjۘs˹)wo.5MM⎀n𲴔a;qߞg0nZ|}(;[طltWS،TO3`mvt~1t/ &jRA)_"!sGɘEFwJch#G9t,dmZRYWTpyLu;ա;7)ZC{> BtpjF,ޞ>UsFUi3x-UZOzmAm_Uy);mHOKeHU:We zk0Gg%rxtm[N/u|Ssks-cl; Fc_n|9.?բzXkd'%23)L, 93J}LIraA/QH4ªr[dZG$_n:mord쏇Ψԝ|wbx?oP0$ГeerdqI.ZIq{{vKmi6rs.u=:lnpE4Iw`r^K e_;G{5g.QӮG \^ WEwxwܴv}{偾=𛟏ךXbP:Ӫ<[y|jji Ž^V$-%4Di}9sѓNGdk~y1>#ŭÜ0_4f@.<` ݁S)#`gc@T}VlէHԇ燬l?w1\_ڮ_o#n$fb|XPZcF E;G{~[ нs;lm,cZ9c{ Gi6rs._~EKan&2ilDȝ&}cdH/yI TRZD5=Y x{ TZnci+puqZ5׸+.q ?NL D ys SߑeeݨP@,2 һvlM˦9#J:gor_"S|:w_v6,v"Yn>]pq^|78Nt} +zwim9\ά"SX0KX;+yMX*p4/5k rk C 4Twj-|QR0Ɣ~6\@Vs^]\u4 ;3k1fRb=ֺ-\)딦O^8wL^kK ^rwL o83'[0 /{8|:;5l-7G0q1de489bXߗ;e$"r h 7n?@_7E>^!PD]~=:ፗF8Z½hlm,qyX6˙w1"LBXbDWB<}~&Pnb,19@./Gr K l,%HDR< ^Fggqq feٶkm><b@4+zo;ZbSnsW4T_ԕ.P}WM?D\ԜԦ 7v٬W`gcY$K LM {bQ P(@ig'g_xwl,Op/+ Z({}ڵ1o݇?S.cXgf\~n1>>AʥLzw 6V /w+8xttB_WLOǨƆM?A ==:QX\yy-!❕ە&ӧBt {= #{B(b@Ч;7p=)- t!n(i/~!) >)V?vK؍'(+{q+ss:ܼgV"SXbazJdeJt||\..g]k;GG'Aŵ[1y̛<^ xɍ;5P(PX\P Ƒsn8m!Hs͹7~zt~sk|ޙ4 =-Hd KY;#\Ċ?suLYކ'չ5ڵYcqr_ٿ6_QQ^]r%N]<5La*- `anV}mFo)Q o F8B{pdR7LJhO_N ]6/B\mwrqDvz/kbܰ Np/ٿp6o >}[V94 _`A]31$UB~A>vL'+8v \^n*=-Œ/vcˏG1~x =po>?YhH1f ЙZ6Di6rs-'%2~òXcfd`ƿB7g`pyqOd jQ--NFFr 1y>/^6*B9|;NŖr]psK=ݤ 脨p)^r[m㿬L|; ',|I;G{v{K{\ٸ_B(agc s1 q1dޫ}4qv{6ka kK d29Rb^: l$ˑ_|~Gub;:!#ZX[psQa~ny*jnbGLLݵ\ZJ "\T]ڷRYUB]:AIO IDAT{9xZ"Cn~vN^EB! ]L!B !BB!PH!B($B!B! !BB!@B!B !BB!PH!B($B!B!PH!B($B!B! !BB!@B!B !BB! //Q1bggJB7t44 !zB!B!@B!B !BB!PH!B($B!B! !BB!@B!B !BB!PH!B($BB!PH!B($B!B! W#Fȑ#U7qD$&& ܰo>ÇvZ楬 1Я_?_Fqq1 $$)))FQnˣ!;X~޶ QƪzYUe}SJ}1V֧)$εk߫oB!VZ3̚5 8r;SNO?ujڋ zwUeYmːJ})i aٲe2dlllj]oGbb"^ S]sF[n.|b>i Zlsbj ¹sX?Dhh(|}}QQQHHH? & ++KiݻwǡCx7DGG#//{D@@部(rזm۶!((R3gwYSyŋ[)YMTqqq޽;]v\WhBY2Lm瀀ddd &&R={Dpp0;j*7%U+HRB*_~HJJҘ_ueY= > L8Qԥivu~:ooolذg!((|1ؠAXRR^TT}e1ƒXhhhsqV\BCCYNN,11[nqYn؂ W f~~~,991ƘB`qqql:/_fr{xb6n8gѬ1XEE[|9ڵ+[nV.\gee?sV|_~,((>}[vRRRt*7^ղPUqqq,,,LiX~~>VU[RGmP<裿նmUR) `gϞe1VRR&MĖ-[ c5kְpyԞu/mʀO^4omy믿X@@@4'Mvءu.*:L?'Nĉ'NjC" <<M ^z5вeKnQFƍXt)6mڵ+RRR7^5wMZXx1P(  ᡔٹ`HKKɳCB!-ZݻGA.LMMѦMkguGbb"222 b+Ww799o6nM= BJ>˖-Þ={\n|K*`˖-HOOG-vvvug]U$!::ZmЖM"QQQիӦMҥKm6n3g⣏>B~~>xAU{g߼h*Jajjcǎ_~ܸ[jWmeSE~:\]] tp|駈ۼPtɓ'4HT_|o&|M={K 8/Jb[FNNڶm2|8pݻǝƒd033SNѣG U?֭޲e ƌ#Gbƌ54峺4Ջ * ޽۶mCRR\\\4ٔ)St.7ۮk*wJkjҵigϞJѡCe&&&ܹ3`gg+g}}M.Opݺu9s&pm̵kꫯ"55 CG ,@@@Ǝ[mXZZ%/>>>Ν;P }u泪 |w4֭[6l֮]+W꽝X3rm>I$ck=J] S~e=CmY_Ekxx8.\tӧ鋯.;#9r$rrr0@,?f̘v=H]@?UND駟1OЩS',Xe2JKKOKD5jߏ%K5x"wj쏺;ذan߾ŋk{mɓ5;qwj^rm>빸͛*d9oӗ &jk/(_>yỿU `޼yǎ;+BG ߿OG!!!pttTK7oTfΜc*Sbb"֮] 믕LZ SNo\tf͂ =볿Z|iu8z(V^Yf).Ɋ޽{k}χT*-;jJ庋-3Fd2z聃rb .]}fffŗ_~^yJF߾}! `*T 0j(TTT0l0xzzjL777Ɂ%푐|Z 1z DHI&aƌJд?;wDDD$ }ZO=WOO?aɒ%()))>c7?[n|gA!==Æ Ò%K+V`ӦM\.D"V\+|6Zem룮K۾=볿ZirƼD" uοۥ1̸ Eի 1^/GkX}lېy ͫ=7}Ƒ#Gta#t䏐fD"@"PAjύB@LL }] tDs)#Bӧ1dxzz"&& DGt?B!b֭I49F@B!:l$!BB!PH!B 0@S!*;;'OFhh(}&B(ÇXvQ䥰cƌUpa,\P/..FXXfϞCa޽ AJJJϦw=B777۷1}濾 !RG T扉F#44]vbnΝ Mn? \(ĪU>~B Hѣlt`ۿz*ܚ~FM@$YLL bccqyDFF"22Ǐxxx 33EEEfϞ OOOO>Bnn.=wwwddd`ĉ ǭsENM>7nDBB"##}f۶m T*?̙b}Uyn…صk6okdd$qM)I}HHH? & ++Ki~:ooolذg!((}Xrr2c1Bucrv=8'(#>>EGG"clljʜ9sغu딖yxxLc\޵I_>j?Uʕ+Yhh(%&&2WWWv-r`gϞe1VRR&MĖ-[ c5kְpy&MMuͧjӧ3LcL&uU4mСC,"".]V^co߾,550}c:Om}oY7tn|/!ƄNӑ&K" <<\i:χ3Z$!::~~~@ŋ B=\.M6桠7oFZZLLLv h"tŰRW}6ķ>|իW#-- -[5jnܸKbӦM\GEEW^sssL6 K.Ŷm۸Μ9}U>EF4uaa!HLLDFF77R,cʕ?b޼yDN2 ;v@rrR999زe ѢE nye9m |iS֪tJҴitn꿄5YB+oŁ=~2 fff!b1Znm[l1c0rH̘1YUN£GltMe^o>y$+EDD/PZֳgO׎С2tYYY*@mTWiiiʮ4իƅ1@b u3{l]~)wsѰTZ?%%{V Ҷӵ/={V  ?RGU$KKK1p@9+V@<{8cL鋺:H2СCq/7nbbb0}t闔VygIIkOڇ宪*KKK>յ6uWUEEUWyI?~KY/j>1/!RGꊛ7ojpppK <5k,ɓ'so޼R}2e Ǝtjyy9.\;v,ˎO_9s&Ǝ_vZ,^X4ZwZѣ1w\HBUpΝ:m?&&6mի1w\:99!::ƍS X PPPS[Tt)k}Em;Fn߾-:L_gkkC*}ZjUc=Th"b ,)n߾r.QuENN,--aoodž 0j(TTT0l0xzz, t 6 K,APPO|-Z1bcdѣ<7}Y׺[j>c"&MŒ3G;88W^˃{X6mBdd$r9 rJyjcu-k}Em6k. ,,ibyyy8?333n2tsj"?!B NIG!B B!RG!B B!RG!B B!`W\ADDrss$}B={贍ÇC$QeB!Vtʑ,FBt tڗB!RG!B B!RG!B B!RG!bd}ܹ:^&>hB!PSNaԩTkB!:B!PH!BF,֭[㥗^r9= ixBQ ?6KPH!fٟ~7n:j B@B! )$B@BKjj*"""0`|z~vv6&OPcTb3rrr' J9bڵF3f VZÇc…z~qq10{l:t{~HHNOiljV( a߾}Fg4Θݱl21 6jmڴǕZh~MiY^Ƶkאh~k׮XܹX[[ۻٶ/c{> bժU7r'xڻ#GK.HHHB5>bJ; ncjjlFǎ W͍ hmє'Ҥmܸ3gĖ-[cС:>Uk̙c#u333!!!󃗗&L,All,Ο?HDFFdff"44ٳ鉀QQQ L8Att4u.^0X~=`ظq#X3۶mCPPR)1gsku .Į]yfn_###amm7o-'M׶O|vӓ˛44QǏ7ިfe~:ooolذg!((Ytt4lljʜ9sغu딖yxxLc\޵I_>*]ѣ7uiɣ6uc]ӔJ, ={1XII 8p 4i[lS(1֬YõJOS֪ۗ-7yk}b5O4رCOu>UO5)V^fϞcnݚݿ_iU.eʷ=N<\넞Ҹ<|WFZZZlƍXt)6mڤv% Õyxx(3|8;;sE"_/# B!=z\6mԚl޼iii011yvH_(ĢEн{wJe^oS]ՖM_}GmǴ4ٳkGGGtAi :w,ܿwzڟhS?@.O> ֭[3gDc ~?˯k2j*>P^^޽{sˢ[o)lq@ ^q IDATXZZrb9r$VXlmmڊ"eeeCʕ+_0n8`*/))7~7ZW%%%Z>"QZZZcyՋjKC2҆z5ۮmrehǧB-W>T]Ҕ_m1ԛ.c>oƍ(++S`1l6X_Ǹ6q@ELd'W$|{t ,"LVN$aԨQؿ?,YRz>>>8}4rrr,]\\.&}3_2UiRF|뾡E-km˭Dy;vW^c>ʕOR_M5z˧<),,ݻ_ȑ#ߟŋkFFFb͚5x1WSLANCiRF|뾡Ei*k>T[}>?Gի1k֬:-(WcDmYc7}l߾5 <NNN5ޛ:u*ۇFA @E#Fc 2 =z_!JakkZT*Ett4 HX oV9O\"''GBBcÆ 5j***`mm 6l<==Z Bzz: %K ((Hc)%%+/_^kt+++X[[>@JJ 2226ߺozgzʚϜʭDGQVV:-(WcDmYc7}o׮]pqqAXXʼlܸ*kժ"##}vۍ/M{nL:{=zh /A ,,,eeeeq1v"0iZ 0w\l޼ 9[G125T NNR7?S4B"xhl@B!/^DӧOcȐ!DLL ɡ9z H_ %[[[lݺ..._? S~4:l NB!@  !B(4u˿6Ag}FA !B(4&'Oʕ+ 9sБ@ldggc Epp0oNB]jj*"""0`|T P `oÇXv2B777۷`*]C'#,, gơCw^xyyK]m뺆H 1fZ … $oXjLRH\v N(ĪU_Ν; 54P;϶6Ghh(v  ZڸGcG@ll@nC=°z*ܨrI67~N:X-#ŋׯWz۶m T*?̙b󹯾 RJׯX?AAA8wgĉDGG#//KD޽ѢE X[[c*.]x1xZӪKy-\v͛4###amm7oTƚ궪QFa59s~~~넄^^^0a>S"OOZ)88'OTZ|r*-<=XXXٳgӧ˭}homrfDhh(|}}QQQkӧOƍHڙ:Tׯ_GTT 6>3۷m ##111Jٳ'q1Xj _ߦMoLǏW^ߊ+!_ fcc$R޳XcS}bϟg1&ٽ{Ytt4+**b1VQQ/_&O̭̒sqqq,,,pX~~>c$Z#}e1ƤR)ӧB`qqqlCe_}c0vZˣtڴ*sa֭SZ233u*cuu[_j,4i۱cc+WP:KLLd֭[jcуۧXe baaaܲ?71˗\.[x1Q[}k66c `Νcյ8'hTUױz?`gϞe1VRR&MĖ-[ c5kְpncAAAܲ+W0OOORk{Xj,_cE-ZPm۶egΜhܽ{+((z ̾Keg㤨ν뮮{fXFuAA/.j K.+ŝ~n11711Q|5Wychp\ew}1T{y@SNU9>DQd]]] {^h!cWs q˙ ְ'?aW<<0a~c={g5kְzKͲb>gq_fϞ6o}9hD:=Z>-[XyyyP ,??_̙Þ|Mv 7D^ Ce,M/U9x`6nݺs3***cޱclzo4Fv0SHݞ}ݻOb=7m$֯_g<Ӹ;q>SL:a߻__TXXlFTqƎSN!33իW^ci 0pwX`wpuСCx뭷rJ]k֬AUUy睨߷X,xl޼ nFXV3k׮IobΜ9#GرcAtwwr77T߲eo`˖-ַؾ};ƌx@C>OSx?om?Q51t_ϾXqP{a(8$H (^yI3PRRիWcŊAu `߾}+V2hBZ +W 0:::'Of\wum۶.}om4n&|x'qw*幹;b 455)[nSO=G}T)[t)~S9WƘ1cqEEEy7o7T+'O*?ܹ8p|>;rܷom?5џk駟#_~9}]*};pfϞ ÁGywÇ[|9^z%*eYYY0LXhRV[[UVa֬YyF< Ξ=9';ҶK5kzx(am ?8|Mlذ?񏃒Lk_ Cu,M/YѵLV_v~ٲe>׷cǎ^)lܸ1Dj sq)MDﴷw~wqS4| '{ZΝ͛7)@7K ++ sn6w@$]s}{ H" Ǐ+sDQĞ={dQsN\{ڵkC>ã>4ѽ@ 4"9ĥ̟x <A0|˿ uLxP\\LA BA H +Wʕ+#z!ZjHE>\ &  @  $  H$/ 7܀*h $^3$>Ipe3unimmSO=mbMWW/_M6ǃ>xIuܹؽ{w^2R2j;cIc&H7^M6-D$Gb֭ v ?l۶ Cyy9h4cJm.DЁ (EPcٲe Ār̙M@L8HOƿt}wྈ@< ࡇ„ PSSs^_D]]jkk1c [Nxb NKK !W_)Emm-LZ̞=|ILbɒ%x?@_~e̘1SNĉq7ԩSA߉^ɓ'5?g|Ae?я0o޼2 Յ q-Ev8|0ob̙^ؿ?.\+UUUp͚5_~K. zZjkى|;K;Əcǎ[n̙3QUUg}ӟuuu5\g\Hg̹{>tQ[[ɓ'cx뭷>RcRoƍlX,A:uKs֭[֬Y|>c1ǾrO+m޼Zuww3EG?bce7pCX?ؓO>cl֬Y/d1C Fevv…Ŏ;XMMMX^yc=7o^~nJKKӧ9s]vu嗳'Nh[~}P… YssR{ﱕ+W2;x g>cֲӧ+m$=C즛nROؼyb:ߑ_sԩ쪫b_}R8q"cР|C<\KZmX̙æNݱ԰/1ƘaW_}5[C&IcglѢE\':\eH=ƙHc1O>Jّ#G؄ g}uG ]666QF)$Ilʔ)`|VQQABXǕϼ^/`N3hkhh`C]O:cyy9B'lϟg&LP޽w}cL&:h?FyyyhllDQQQ^:K7˱xb~(++؆X%Kvݻ7kzҤIAcԨQAeaر8u233/ٹ;p@Lc`#Q|"9sfX٬Yoc)$SQ!g񠪪 Nn&lܸ?aOOSv10ƢkeZ,Z> QZZ?عsgFxްrI~x eqZZZk.\wu8^W_}5/^7@btay~?1O^wu8tz-\k׮Ś5k}->Kvӎzv89}?CX,xNpy,--ɓ'c!6~q(^yI3&َ?:/1g0?{>+V}*ӂ1صkRv %K@E8 PYY#Q]]v?>~7n܈{K.E dxPSS"Y -Zߏܠ~a9_=c|*V g>ԁ0{lv8<#ؽ{7>uK/T)ʂd¢EZZ f0x`0pYyZZdddGmm-222ꫯ"'''mc?҂ף6 YYYx嗣~?Rz џ\'zu6~eǂ aii?O<֭[׋4'?)S.Y4_mFg- NRnT y| h 5&$C$]s AA$Ν;qעk׮!b@9Dddd^@qq1uA4~$Wv:2tBAApn:%2  b 9I"%%  H   ?H.Kp ꪫ!A$ A$\veZ[[SO H[#=w\޽;/]]]X|96mڄ>`\3w}7yy HK XǦM0cƌwQlݺu@:u_8 IDATa۶m7oF.V $I<˖-NH2Μ9ѣGSGA$))eq>@~z@]]+=y>o~9s&&OUV]~Xp!JTUU)kb믱tR,]wu*++QSSӧ[nAKKRgoVw(K,믿Vcԩ߉VYYN8yaʔ)E׬Y_x嗱tR_^΋/:bƌXnNV[bK:R =F 6زe ĴHuϝ;7oV{|Ivַh"?f?Dڴip8OO~|ᇑOiO<{⩧n$I/;v /BĶjRw ǃ_0x? ֭wu T\$g455a׮]łE))QO?vtt޽{q?0&L ݮвXr\غu+>?4x{эB @CFyyyhllDQQ~`Xx1n01ǖ-[}v444:;;`2bo<_?"~iq^:Nӏ}0o<Ϝ9 ͶR׹sP]]|0DA Dt2]w:z +Wڵkf͚y^\}Xx16n܈= 3bo$, <OP٢E;wOl6['~x<;W[bA󳾈h !7,yK,mۂJ1f<X|zq3n(..ɓ'D}݇͛7W^7ڧCIDP&O;w.L+.j5{ $(^yI3Fy_ZZ'O\8p>@;rżo`Ŋ&n&|x'qwPq,,YQp8 ,@eee\16mڄǘ6m, xǭފo]k . a!7$" PEDBA 0?" $ k׮=C  Hܹ^{-*++vZ "@D^xA @p` AĀB.`AA$HAA GA @AA$IAA$GAAAA @AA$IAA$GAAAA @AA$IAA$GA @AA$IAA$GAAAA @AAI |0Lt֓L  + ?  JCAA   HAA$  HAA$  AA @   AA1` bp\`gEIzzvl6XVz  XVF455ԩS0ͰX,00L00Lt@[[APD"c (B`0@jnp2A @b N(*Vtdee1I cطooܹsAf ;;#FQ0bb(hZ$ O b n0@Cp ==iii8N"A0FΨ"333%ĞDgg'c`Al6h4B)%N$@ v,\@_=xt:ntww9N|!//9999r$JJJ0b*M&z=8lF @ww7 &OLb  Atݸpb+ٚ@_3?~K,}2}㐝塬 gr0w\ &5^$ 1<ժX>(>yqO׋cǏY,K&ewuWWmۆ_Wn {ĉb  HC@ y{:FQ{z^vyur:W~/oqDQTx6^GZZ"n}v?ҥK  HCI҂v%VE% A\IҲEZElS[DQT5mk;wj  AkmmEss3|>Ah8F@On>[W-E$i Bٺ(t:(N  A$58{Yi BvPaHA$? Ascx<{g^k:P+DŠ`I`4+v[A$ "! 0}o# Pa+/:'PKʁ *LA R`xZi @?PK8Y# HA RBc qZV<꧶Q?@utp2[}HA$?3ԪUH.`u @rA$!/"Y" u}q3F.` r0t.`o/O+#RG$,B y>i1tmc 7^ӧOǾ}1/Z  1kt:dggLԯ{Yzb3ҟ^$HPKE /d%t;?#kiHpݻ7LpWq Hy^]?3Th}&~Ġ$I4DJ @-W˟H{siK<$ډ>ڃ_Ѩ*+ocR6&>7\.E^jϴz$ B-b~ZPh4Uğ/(/n~0Ɨ`cచcRT^^^^7]u~'!q81;<}?8V ADQIj-#?:CKo$$Dɞl1L;3'CN:&<6 r ~?e>4$RR"B/TE iHKE@H4$a3);2:&Ezu: "x(0 pI`4!H׏8_q#1gZr31I"!Ƈf=:$`RD $ޫT 6DV(I^W_}EtQėO˃'1~t!fMJcQc^O) Лʑ1~ 7__?Ԃ/Q`vjeM"zc\Dr ?~Ey5i+FS @E  )7Gx(,oIi`"FMɢL X' YCנtABO,^U>kjy3}TǂK4,Sm|Z)UHnHh").`wCZQZzq z"S11hpb㝏􉥘= v+uI508NX,8O "P'#AH_p+8V `!Hv\y}K0o(I@@XR mm())q$ "KmrݰZap\V}6?.HA C-Xdws,"P=ћ RA{q{ #0wZFR$i`\!e]d$WkdVAw_pa P7pbeT?^۾ "iþgQR+cZX InoVd}#HZd+,~zT+%(^/Vkc qXX(  nhwo_b O+SJ 2~?e50$P6 Y$L:ffm[j*νPכPLNk> ejZ20$C PIFQyzR{+_f &b Ԛ*{j/ >h 8>l5טzX,BanuLz@DAA @r2jl3Zj#h7)!Z d^'d$"(=Gpe#0DL[D јyBTW A;2LA@ szSt::KD Tg ?y7Ł,Đ/ׇ`3(.53+Q[5  3;ūz@G2$RH_'ƕ͟kj.O:!T3CN=s='5K[e&Vr˃ٳgz>h`GGrssqjjj^/E ((t1%Fl|OOWVlJ*.`4cJc U;P+$BxCx\}mHKK Gm9r$cQ(F"0pWȑ#y^9>yɹ.Z G~N5_3}F.j#cp$ B}SIJMT&&"}fìYbr_,@*OA N^xug;^? GJ[B-CUrߟ!j Aff& @'2J+C^7#vfS=ؾk̼2XPic/iP-qT*z< @b PI K{*ZAH b(3U@&H p:HOOOJav$> X`z`ҴcNma :Nj d$$, &i[ҒdA@T񸜣 >XI!qzH:􌁗$$A%%I" A$+]9 ˯ @y5dCIDET_e_]͑>Ay/??66!% 6V(B5,1e&e0:;;,Т,q @Tot:zt hw{w쀯 bL49$$C-( 7<Fvv6ۑ!0AQD%k^^ f3"|:cpxO\e6E\/VH !K^+ԠINq8 @Y\| LIU fc^M6m!꫁V`/>UgXB8̞Ri&J 4ېۇl`CAA>;wĨQPTT'N@#77Wl6 ͆"dffh4"776-hAss3 Esaɨ\3UaϞ=Jԯ@YYlt7]]]AA11tuu!===h[9l*DZZZP3x<0LauOEx<r{C|v:X,ʜh IR "]]]p8A-I5OFCCÀsDʉT^˅4pՊBn#??yv@]]]444n#HKKCZZn7~?V+V2"-- 1& z= SD?dqȑ#Äɓ'QRR&t:FTV (..w(\ 2jGkkkXMMMHOON 󡽽AD Zux^tuufĉ3f @` @Rm~n. MMM<:::mf6 l6Śt:Asrr`0p9dee!==`azX,BanuH/ڵf6 !(/.\d33;;>0 lu󡻻1PR:Ntzr ˅:~?:::wu)Bj:sİGpQϻKOOGZZ, ł\ddd8<Nߏv8pFl6F8dffvCEX,id2)V?PPPIH YV3fV' n׋Cj@HOO= C]@e#\iFt:dmmmxv=zr4-^<χZv ~Xlj… Gaj(7G%9n&s񚚚B~BZp:HKKS\ fEqv*nLX, ł+wtt(@baPW=;䫯) qTkZՅNp

^`f( YY=k'[,tvvZ[[,?NvdeeA`0v J.>QڊLE$IRt:Egg'chkkCnnnԾhllTjaAqBvv6v;˕y}555JJٳg+TWW+"8''Gt. >ǏLj#áCPZZ ݋ &`ĈBv*)HrLf!5W aA('7EjQ4~EKi:Ns~i yx, V+xW{ J DjaGݤ2̘8<v Gb(|0@]]]`ɓJ F–KOOG^^!܌BXV%hΝ;"t:l6JJ,tBddd1cĈHOOWĞ^Ѩ|v]-)rssQXXoBihh);"V >jR$IpسgPXX?(**B}}=PPPKL& -- 6 J,r(HAvܬD544CC'daD~fM18qR|ˋ{\z---M!5(]T"ڇ3d2}bhha4UԈۭYlAnn.=Fz"h9B.==& yyyJ,e yx2Fʁ@@هI\sVmmm'%O'f3N:O .Qd& ---A*d2d2l6#''G뗛X`QkjjR666*www)sqL$q#1gZr3!'O(BSYRz3&Lx^,;ϟWrCihh@aaa\ꠏXʣ K=:VͺQTTLQo#"݋QFE-Ъ… 9É'fU :$`sX`(k25')Pl"֎lX,JVMӦz~t:eZh0t:FQI2OHAVeeeZ02ebT8j(EܙL&%s pi8;v 8˜1c`0pQ)AĂb1[M!I<-$TLӟUbAI"'mG|Qf̘1cJF"V\БRTCN}P~ %/Dv:Ne@p8Ჵ+[Jwy{rd,<Ϝ9tXV9r999l8t":#FpܹslA雴4fp޽U̙첻eikiTJ6 Z6р $I(14i!5H1ACKD#ZhbZjE!ݝe~1|>3._dzt{sQ:V(r3OjӺUڸv0_7==XšsV'Q%Ѩb;}1W&%5%bu: 4;+ BEQWFf~c XuG"WxԂ \Ta߷[o)jٲeΖBJ$nLvcndҽ|>b '&&NFUVl6][+`]3+Dq9ǩֱ2t}n},J$1a|%z K:V*7&$ )Lk&uZvL&]gZXD"JӪjR>wa.A̩%͟100H$Zl,JVSXT.sc&&&TJX=nKY0q 1/GW0.Ů/ʗ]PXu>zFjIF+BM[!zPp8D"~j=:zTTP fffXϿT>wUU7Bju!X"pXwM g;+ ZTApd21CCCmd2n"}zݕ2@S({v+fZ,)`+%@bNnϞ99doXǢG;$bQ>+avZ5 r9>}ZgΜQX$/c]VH$l6L&zy†oelX,jz$g716 $˹08==P(n ߍ[bk֭s_j>66殧R)9}q +r_"JoСC@,ճP[H۝%LƴsNJ%7ŸM.[{]!1k-Dz٬+]*wWV4U$-[ A=[왙8qBGSO=B˗KS\։'ȍ]xE MbWl7[-HmXʳ.p86Ϻeg}nc9.YPh4\W]vXt岊b[B__yvm* nL$q>, ѣG]I),NJр%oǮ-v n>Mڀ~bx܍ֻ jiMOO6lpA~KHRFGG522믿^+WvUF" FX6lؠ 6EQc`Z IDAT"}5HVٰ1~6~ i 6vp8V<ڮj%.cvܹs @TL&J&m9 )L*JnKuu_bQxu+jpp._?H NPh;&@2BnnvvG]PC[f![B~%v_纘}L-׹\gѰ7I OrJ%溭2b]j5y;wN|H$x<~A깶us{ů3vXhĕuӣ&/6Vm3Dm+v];m wZ pJO,|n}uv n va^F;2\1Юw%JnKn{9c? *>2Q      @@@@@@@      @@@@@@@ s=zWI=mϙR"MIںuxKzmڴI ;zd2fu]Ѩbd@p8˗E@,5w޽{u!ܹS;wԟgI9;qF?P۔3g_nVmڴITwӧ Ò O蓟fffN/^}˖-D"ӟo]W X~K_o߮zAtb1ԩSWRs=_|Q'O6.ˊs7MMM鳟lkݺul}޽~3FU;v[nM74k6;⋺kcJMt:ug\7gBڳg߯|3d2^蒺 YFu=z~t^6{?eIq|?ʕ+}M{N8jz7紿|]vW_Տc=mWґ#G%E@,9LFӖ-[dVW]u{|bbB{թSJ444f~me=\c=H$'Nhxxm{~;v^_twk_ZgFڶm*FFFjU>qF~` (+ %.`Nݻo@K݁t]wiڽ{7_,atc^p;vL}}}Zb_ K ]@@@@@@@       c||{_{7hǯIENDB`nitroshare-0.3.1/src/dist/icons/hicolor/scalable/apps/nitroshare-indicator.svg000777 001750 001750 00000000000 12653764154 033254 2nitroshare.svgustar00nathannathan000000 000000 nitroshare-0.3.1/src/transfer/transfersender.cpp000664 001750 001750 00000013443 12653764154 022645 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "../bundle/bundle_p.h" #include "../settings/settings.h" #include "../util/json.h" #include "transfersender.h" TransferSender::TransferSender(const QString &deviceName, const QHostAddress &address, quint16 port, const Bundle *bundle) : Transfer(TransferModel::Send), mAddress(address), mPort(port), mBundle(bundle), mBufferSize(Settings::instance()->get(Settings::Key::TransferBuffer).toInt()) { mDeviceName = deviceName; } TransferSender::~TransferSender() { delete mBundle; } void TransferSender::start() { mTransferBytesTotal = mBundle->totalSize(); mCurrentItem = mBundle->d->items.constBegin(); // Attempt to connect to the other device mSocket.connectToHost(mAddress, mPort); } void TransferSender::processJsonPacket(const QJsonObject &) { // JSON packets should never be received by the sender writeErrorPacket(tr("Unexpected JSON packet received")); } void TransferSender::processBinaryPacket(const QByteArray &) { // Binary packets should never be received by the sender writeErrorPacket(tr("Unexpected binary packet received")); } void TransferSender::writeNextPacket() { // Write the next packet according to the current state switch(mProtocolState) { case ProtocolState::TransferHeader: writeTransferHeader(); break; case ProtocolState::TransferItems: if(mFile.isOpen()) { writeItemData(); } else { writeItemHeader(); } break; case ProtocolState::Acknowledgement: case ProtocolState::Finished: break; } } void TransferSender::writeTransferHeader() { // Due to poor translation between 64-bit integers in C++ and JSON, // it is necessary to send integers as strings writeJsonPacket(QJsonObject::fromVariantMap({ { "name", Settings::instance()->get(Settings::Key::DeviceName).toString() }, { "size", QString::number(mTransferBytesTotal) }, { "count", QString::number(mBundle->count()) } })); mProtocolState = ProtocolState::TransferItems; } void TransferSender::writeItemHeader() { // Build the header describing the item QJsonObject header = QJsonObject::fromVariantMap({ { "name", mCurrentItem->relativeFilename() }, { "directory", mCurrentItem->isDir() }, { "created", QString::number(mCurrentItem->created()) }, { "last_modified", QString::number(mCurrentItem->lastModified()) }, { "last_read", QString::number(mCurrentItem->lastRead()) } }); if(mCurrentItem->isDir()) { // If the item is a directory, write the // header and move to the next item writeJsonPacket(header); nextItem(); } else { // Set the filename and attempt to open the file mFile.setFileName(mCurrentItem->absoluteFilename()); if(!mFile.open(QIODevice::ReadOnly)) { writeErrorPacket(tr("Unable to open %1").arg(mCurrentItem->absoluteFilename())); return; } // Obtain the file size, add it to the header, and send it mFileBytesRemaining = mFile.size(); header.insert("size", QString::number(mFileBytesRemaining)); writeJsonPacket(header); // If the file is empty, there's no need to send its contents if(!mFileBytesRemaining) { mFile.close(); nextItem(); } } } void TransferSender::writeItemData() { // Read the next chunk of data from the file - no more than either the size // of the buffer or the amount of data remaining in the file QByteArray buffer; buffer.resize(mBufferSize); qint64 bytesRead = mFile.read(buffer.data(), qMin(mFileBytesRemaining, static_cast(mBufferSize))); // Ensure that a valid number of bytes were read if(bytesRead < 0 && mFileBytesRemaining) { writeErrorPacket(tr("Unable to read from %1").arg(mFile.fileName())); return; } // Write a packet containing the data that was just read writeBinaryPacket(buffer.left(bytesRead)); // Update the number of bytes remaining in the file and the total transferred mFileBytesRemaining -= bytesRead; mTransferBytes += bytesRead; // Provide a progress update updateProgress(); // If there are no bytes remaining in the file close it and move on if(!mFileBytesRemaining) { mFile.close(); nextItem(); } } void TransferSender::nextItem() { // Move to the next item ++mCurrentItem; // Check to see if the "next item" actually exists or if we're done if(mCurrentItem == mBundle->d->items.constEnd()) { mProtocolState = ProtocolState::Acknowledgement; } } nitroshare-0.3.1/src/transfer/transferwindow.cpp000664 001750 001750 00000015016 12653764154 022672 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include "transferwindow.h" #ifdef Qt5WinExtras_FOUND #include #include #endif #ifdef Qt5MacExtras_FOUND #include #endif TransferWindow::TransferWindow(TransferModel *model) : mModel(model) #ifdef Qt5WinExtras_FOUND , mTaskbarButton(nullptr) #endif #ifdef UNITY_FOUND , mLauncherEntry(nullptr) #endif { setupUi(this); transferView->setModel(mModel); transferView->setColumnWidth(TransferModel::DeviceNameColumn, 150); transferView->setColumnWidth(TransferModel::ProgressColumn, 150); transferView->setColumnWidth(TransferModel::StateColumn, 200); connect(sendDirectoryBtn, &QPushButton::clicked, this, &TransferWindow::sendDirectory); connect(sendFilesBtn, &QPushButton::clicked, this, &TransferWindow::sendFiles); connect(clear, &QPushButton::clicked, mModel, &TransferModel::clear); connect(mModel, &TransferModel::rowsInserted, this, &TransferWindow::onRowsInserted); connect(mModel, &TransferModel::dataChanged, this, &TransferWindow::onDataChanged); #ifdef UNITY_FOUND mLauncherEntry = unity_launcher_entry_get_for_desktop_id("nitroshare.desktop"); #endif } void TransferWindow::onRowsInserted(const QModelIndex &, int first, int last) { for(int row = first; row <= last; ++row) { // Create a progress box for (surprise!) displaying progress // It will remain in place as long as the row does QProgressBar *progressBar = new QProgressBar; progressBar->setMinimum(0); progressBar->setMaximum(100); progressBar->setAutoFillBackground(true); transferView->setIndexWidget(mModel->index(row, TransferModel::ProgressColumn), progressBar); // Update the button displayed in the action column updateButton(row); } } void TransferWindow::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { for(int row = topLeft.row(); row <= bottomRight.row(); ++row) { // Update the progress box if its value has changed if(roles.contains(TransferModel::ProgressRole) || roles.empty()) { updateProgressBar(row); } // Update the button if the state has changed if(roles.contains(TransferModel::StateRole) || roles.isEmpty()) { updateButton(row); } } #ifdef Qt5WinExtras_FOUND if(mTaskbarButton) { int progress = mModel->combinedProgress(); mTaskbarButton->progress()->setValue(progress); mTaskbarButton->progress()->setVisible(progress > 0 && progress < 100); } #endif #ifdef Qt5MacExtras_FOUND int progress = mModel->combinedProgress(); if(progress > 0 && progress < 100) { QtMac::setBadgeLabelText(QString("%1%").arg(progress)); } else { QtMac::setBadgeLabelText(""); } #endif #ifdef UNITY_FOUND if(mLauncherEntry) { int progress = mModel->combinedProgress(); unity_launcher_entry_set_progress(mLauncherEntry, static_cast(progress) / 100.0f); unity_launcher_entry_set_progress_visible(mLauncherEntry, progress > 0 && progress < 100); } #endif } #ifdef Qt5WinExtras_FOUND void TransferWindow::showEvent(QShowEvent *) { if(!mTaskbarButton && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) { mTaskbarButton = new QWinTaskbarButton(this); mTaskbarButton->setWindow(windowHandle()); } } void TransferWindow::hideEvent(QHideEvent *) { if(mTaskbarButton) { delete mTaskbarButton; mTaskbarButton = nullptr; } } #endif void TransferWindow::updateProgressBar(int row) { // Retrieve a pointer to the progress bar widget QModelIndex index = mModel->index(row, TransferModel::ProgressColumn); QProgressBar *progressBar = qobject_cast(transferView->indexWidget(index)); // Retrieve the value from the model and update the control int progress = index.data(TransferModel::ProgressRole).toInt(); progressBar->setValue(progress); } void TransferWindow::updateButton(int row) { // Create the button and persistent model index used to reference the row QPushButton *button = new QPushButton; QPersistentModelIndex index(mModel->index(row, 0)); // The title and action for the button depend on the direction and state int direction = index.data(TransferModel::DirectionRole).toInt(); int state = index.data(TransferModel::StateRole).toInt(); // Display: // - a cancel button for transfers in progress // - a restart button for failed and canceled transfers being sent // - a dismiss button for everything else if(state == TransferModel::Connecting || state == TransferModel::InProgress) { button->setText(tr("Cancel")); connect(button, &QPushButton::clicked, [this, index]() { mModel->cancel(index.row()); }); } else if(direction == TransferModel::Send && state == TransferModel::Failed) { button->setText(tr("Restart")); connect(button, &QPushButton::clicked, [this, index]() { mModel->restart(index.row()); }); } else { button->setText(tr("Dismiss")); connect(button, &QPushButton::clicked, [this, index]() { mModel->dismiss(index.row()); }); } // Insert the button into the table transferView->setIndexWidget(mModel->index(row, TransferModel::ActionColumn), button); } nitroshare-0.3.1/src/bundle/000775 001750 001750 00000000000 12653764154 016534 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/hicolor/000775 001750 001750 00000000000 12653764154 021000 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/ubuntu-mono-light/apps/22/nitroshare-indicator.png000664 001750 001750 00000000744 12653764154 030767 0ustar00nathannathan000000 000000 PNG  IHDRĴl;bKGDC pHYsLLi9tIME0;ԝqIDAT8˭MNA_5 DVF@tq1/#{x fÆYKo`͔d`NO՗ׯTENFQl6ۙg@䚢P74SCYAyHD(^si3^ZZMsI7iϔJ`WUNoc^1Meaq-sv;hbmRe8%/12y @؎<p2h%g "~׸l.ˣVU_-x<0O-3J0Xxʚr^^ $nA[OAZUUXkzf#^cxi']\ \y:IENDB`nitroshare-0.3.1/src/application/aboutdialog.ui000664 001750 001750 00000012144 12653764154 022421 0ustar00nathannathan000000 000000 AboutDialog 0 0 450 400 450 400 450 400 NitroShare - About :/img/logo.svg:/img/logo.svg false Qt::RichText true Qt::LinksAccessibleByMouse Qt::Vertical 20 40 true true 5 Credits true false License true false Qt::Horizontal 40 20 Close false false btnClose clicked() AboutDialog accept() 438 338 249 224 btnCredits clicked(bool) AboutDialog onCreditsOrLicenceClicked(bool) 52 326 224 174 btnLicense clicked(bool) AboutDialog onCreditsOrLicenceClicked(bool) 142 326 224 174 onCreditsOrLicenceClicked(bool) nitroshare-0.3.1/src/application/000775 001750 001750 00000000000 12653764154 017566 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/bundle/bundle.h000664 001750 001750 00000005147 12653764154 020165 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_BUNDLE_H #define NS_BUNDLE_H #include class BundlePrivate; /** * @brief Collection of items for sending in a transfer * * A bundle maintains the file and directory metadata required to send files * in a transfer. If a directory is added, its contents are added recursively * as well. As items are added, their size is added to the total. */ class Bundle : public QObject { Q_OBJECT Q_PROPERTY(int count READ count) Q_PROPERTY(qint64 totalSize READ totalSize) public: /** * @brief Create an empty bundle * @param parent parent QObject */ explicit Bundle(QObject *parent = nullptr); /** * @brief Destroy the bundle */ virtual ~Bundle(); /** * @brief Retrieve the number of items in the bundle * @return item count */ int count() const; /** * @brief Retrieve the total size of the items in the bundle * @return size in bytes */ qint64 totalSize() const; public Q_SLOTS: /** * @brief Add a file to the bundle * @param filename name of the file to add * @return true if the file was added */ void addFile(const QString &filename); /** * @brief Add a directory and its contents to the bundle * @param directory name of the directory to add * @return true if the directory was added */ void addDirectory(const QString &directory); private: BundlePrivate *const d; friend class TransferSender; }; #endif // NS_BUNDLE_H nitroshare-0.3.1/src/transfer/transferserver_p.h000664 001750 001750 00000003341 12653764154 022653 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERSERVERPRIVATE_H #define NS_TRANSFERSERVERPRIVATE_H #include #include "../settings/settings.h" #include "transferserver.h" // We must derive from QTcpServer in order to override the incomingConnection method class TransferServerPrivate : public QTcpServer { Q_OBJECT public: explicit TransferServerPrivate(TransferServer *transferServer); public Q_SLOTS: void onSettingsChanged(const QList &keys = {}); private: virtual void incomingConnection(qintptr socketDescriptor); TransferServer *const q; }; #endif // NS_TRANSFERSERVERPRIVATE_H nitroshare-0.3.1/cmake/FindInnoSetup.cmake000664 001750 001750 00000003005 12653764154 021301 0ustar00nathannathan000000 000000 # The MIT License (MIT) # # Copyright (c) 2016 Nathan Osman # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. include(FindPackageHandleStandardArgs) # Find the Inno Setup CLI compiler find_program(INNOSETUP_EXECUTABLE NAMES iscc PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 5_is1;InstallLocation]" ) # Process the arguments passed to find_package find_package_handle_standard_args(InnoSetup REQUIRED_VARS INNOSETUP_EXECUTABLE ) mark_as_advanced(INNOSETUP_EXECUTABLE) nitroshare-0.3.1/src/data/img/000775 001750 001750 00000000000 12653764154 016750 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/icon/indicatoricon.h000664 001750 001750 00000003227 12653764154 021215 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_INDICATORICON_H #define NS_INDICATORICON_H #include #include #include "icon.h" class IndicatorIcon : public Icon { Q_OBJECT public: IndicatorIcon(); virtual ~IndicatorIcon(); virtual void addAction(const QString &text, QObject *receiver, const char *member); virtual void addSeparator(); public Q_SLOTS: virtual void showMessage(const QString &message); private: AppIndicator *mIndicator; GtkWidget *mMenu; }; #endif // NS_INDICATORICON_H nitroshare-0.3.1/.gitignore000664 001750 001750 00000000204 12653764154 016460 0ustar00nathannathan000000 000000 # Files generated by the OS that should always be ignored .DS_Store Thumbs.db # Files generated by Qt Creator /CMakeLists.txt.user nitroshare-0.3.1/src/transfer/transferwindow.ui000664 001750 001750 00000005234 12653764154 022526 0ustar00nathannathan000000 000000 TransferWindow 0 0 800 400 Transfers :/img/logo.svg:/img/logo.svg QAbstractItemView::NoSelection QAbstractItemView::SelectRows Qt::NoPen 150 false true false Send Files... Send Directory... Qt::Horizontal Clear Qt::Vertical 20 40 nitroshare-0.3.1/src/dist/icons/ubuntu-mono-dark/apps/22/nitroshare-indicator.png000664 001750 001750 00000000774 12653764154 030604 0ustar00nathannathan000000 000000 PNG  IHDRĴl;bKGDC pHYsLLi9tIME 7%IDAT8˭.Q3? [AE¼}mH=< 0cQ3YHEҙcQt$w{sg=^\2URY\tFf9kgPUeɑa5N6Gd?4xRvi*[~x8ݓEQ4EdǛ\|^یeIݾM-%"&pkv^9B_l5osg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o |IDATx?oM`ׂPƍqZ"vZ|"?pMfa7jRKZ?.53;9E{󈄼<|      ИE-A X/AkS4$p3 4$@@+?"m]m XHASO-h[@~Rؚdž&n=3$,e %O[R,~؊'[ ~94#O[з;8g `l~87#-v ϶C`'sRp/;r `mZ[?M}t&b sC` VOkp ~XJD\@'=:i5$"Ё@'z?Mu4&@P-{ ?I54$@`-=𱄼@#kY"e ஔ@_Ex4hђ ph;R D~h%x@'5<qؖCmчNlH [ Yn'4QA`"m E`#6 2c:02?lp,1.O]Ic20* ?q:jOa$Pq `apX?uu@ %osɮ55 kMG{ =`G܊nfS2ᏙK ^?^&e+"XXyDld1L%#j# #7g0lo_Nÿ{;& 8~?jɿ[s ?͗>C>?X$@'x~:D$8 '@3!' Wh޼W_=z扆z??pK#_y/|uϏ_rFߞ .~)Gs~QRL=4SL p$8"@ I x@#@HI#$A%+FJR*$ L!-;AގKI V6 dI9$ko#@QI $ +`0%e.bz({ ] (@ tkE>P#w wpp/@NXw߉#O!lY$hW!lVv dKOЇs]H D Pq/3δdJkZI`#!!iPwtvG$0U l#y^EU] ,UR(vH`-@66řb1HS"I;@@iX4yiȜ `>$@fZ-.  u;P3&]@.JpgϞ>|!3ȝߦՓ8S,F)bW$ ca'BH X !p3/Mӛ_;g5ܕ$P?rYYL#ڿ@?V@+%bnjڤ+hբA|y >?+)kGp bdao .b3:Ku {E`j`)1@>@ HUBI v>#Sd< ,F { $wj5V(m=C3{LP.[Fj؋@ ~F+$}sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o"zIDATx=ǕN"ȩA+p<(ȁH+ph'DN ЄDVǀ :8-\ @ @ @ @ @ @ @ @ @ @ @ l@x=" @ N @@w- !@ <yV&@!  DkA5sJ <5Q8^7"*d S[ds p/n5 0M` @8_8J @`/LiM  @1[pU @p=_. @{V @CЖٌ8j m 0L/ k @v$@Cلl8k - p_8}6 @x*0b  @`/닧  @i#pZ-L x"0c Ң @`/,돧 @3px;-H y*a b @i(_xO%@ Dam-m { p@/Z @Qp_>%@"`w{-@>>{ K v @},_xo~"@2 `sH d$q Z% @/ @`@/ll @@/NO* `CB} vrX)Pi +q)Pm =S @ _XqwI  @@/ܹ &@݆^;%'NNR/C/]qj0 ̯ @} ~_% }_(k%`@%@@z/Up0@'%@@j/uP<zS @ J( P  R?w )-U߷= <]mF@Ylk_B  p]Sv ;NDD\K. tUu(" ic0KabEU} wrC6#$/ 8R@8RZ I`W,` j9 TZ<Tsl!.i5lDɧ#6ەLۜەLۜەLۜەLۜەLۜەL_kgϞ]~:i_~rr z ˧w_O|7zY3#N!___?WX" ,QL{!@Ptpu ! PgZ! mN#  @.1% "@`o$@Ʈ9 !@` EL@ C^@" H@xG[r#@`0Cݞeu0r-uB؟%%X) 86" ts) 웪IL MwBXo L@X)]|^&@TK& \SYm) lC) l* lyzBB@f: @);N@ {jO/ oH+ m«U:r ڢB@:@(p\˫W׿8$+_HP @:]B! aӔL iJ/ - nCC-B!W pnB@)@R iK@o%0B@l Z__(@|! ~TH S$* pp5 ێ@A`SУNI,,Y  @@:V!O"0I@o[S:ww5{=!H$ $jR L&7@;:Us!p| H!Q@55' BprH# iB ly@uz X@x,gEu,p^#Q@558G@8ժ a[0C6#C@U) Է7BD|[ hfۗ|`~T@`0 mL *!0J@%m RA-G {j'N@Xi-v@? .@9\K1B1V!U@u h$ kYU*t {+BH. $o FIۇ`]J!( Vqy@X lkF 7*#T@X*9t@)@! N/TB`V' i4R(B@ި- X% 0(@!/<Ρ@Qhc,??YX( ,V$0K@%o_ v@:B@ި#;OpK s@/ˏ/^$6fB@̾лNP￿|!`!ؕDŽ+(>"0Q@o\B~  @((IYohGG(ZB~C++ ~K!`ۅV G@أB  @`U{@oh[-j!? F`ϫo$]nM[-j!pE@#!`% vyc!f E@آOO,JX1;x^%pK@%s!`' ly!`ҝG;@&C@؁U{By`wV`xTc;x^%T@X*u9!ඍoly!`ڣWG ~$C@؁Ukb>/|h[-j!C@؁B~C+B~C+z' V+ 7Aoh@Ͼ;u !`3V' 7Eoh^@~;m`!˗]ڛg.Tuo//^x󑿯x={-' 7HyEZt]Q!5 @LL]k) :74 C@U& TJաLۜr!`' / 70B@V(@z } ЭKW8U@8Z-]u&qv"pp8 ڴA U;\:!Bf(% jt:w ֛y@X! lkF % "O@m].vVB@v;,M&6//  fۛB'X@H<X" ,Q ~@;qC!a Tt9# h)mR$!f# Jfۛ$!`m 5C)F #E '*"0L@Fm#p-QBXo" D:L&ۚ$`m DuD=:TB@v).` ԉ\@s!p@6;$Bz3o$ dZ ێ@` d2vM =zwqP\-&|_׫ _7"Wބ/^\GFۏ@c!q=% "P[@_# J ʴA tS{B@R! i]B@(F W@;rOJ%d S.B@:WT jgEаe4rIENDB`ic10miPNG  IHDR+ iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o@IDATxݻYy&U-|Hw줒C@HcGp}$DHvKMR N;+ ^c; @ 0Q_0ݣ  @ @Ix @$hWLX @ p_pUC @&l]= @\!gW\w @ @{< @8+f @ @`_00"@ @3, x6 @$pvW c @ @,˿`V:K @Z @ 0C`g @ @@N @F XS< @ pB`8[  @ @H˿`dRE @ ^q @%p @ @W- ḅ @rWH3 @ @N΀\N @ XgSs? @!jWɥ @ @_p&9 @ @Ơ\F @ DXGs @ eWl% @ @@_p$A @ @і|L @ D\{St= @#uW G @ @`@_'I @ @w/ wg @ U ؚ @ @ ,˿FxD @dZ[u  @x%mW Я @ @@_(U @ @gYH @ d^ @A U&@ @*, ! @z TYǦ'@ @;}D @}- e @ @;;a3 @+z~MM @7*/  @+}ML @:, W @z tYצ%@ @gH @}- >m @ @? @+Z} K @@  @ FhU7( @ X}&'@ @@ ˿ݐ @)`+z h hD @=o??w @@v@8#`?^H%H @,1= (g @xxSO$@ 9 0\?  @  CJHH'H @,F55r4 p_ǧ @@ d# @_ @  @rf#@] ]\.&@ X 0_@0 @,כ{#P @dn @ )ڤ S@ @@Xh"("  @YYA @@y@ H XGl@! @**y%@t t90 WPr) F& !@, ,I9' QQ?  @, @,#p*Țs @~~ (bz 0M?փ  @K$@y,ysr$ @o,oHPss 0_? @QF%@,rT!ȑS @NNi.P\FE @$ @# #j!@fXgz&A@@DGH @t#@),)brH.Ȟ @9=$P$ Q  @@1@Cq: PU_5Ys @@X@h` Y@9g#@,25$P$ 1  @@@yysr I)-g%@ a @k&@Xq P@ @AA8 @ IX} @@0@@ PO@P/S @M(%`b pZoo#@U,U5P  @` @ V$@ Xߚ )C @19$^@@QsX(X @ ?ipM7=+`+z D@$ @ , BrD ='@ Xk$P$ ͑  @PPL PG_'K @@s@/  @ @l l9/F @Q{H#`O @ V$@,R6#P @ঀ&? @ 9t?. @ , {X-X @N.P\FE @ ?\$D (z2,` @  I Xx @``g @8* @ ?TCP\m @` @  A8(` @  KRI XP@ @ @)` @aa:7 @8X'Xg @`g @ ! `U @PK J*.%@ (7F 0Z?Z @@A@PD,6,8.8nN Z:'@rT L Ï @cc#W @hh8H H# @gg~$@ ([N  @@b@Z X[mX 0^@0  @hhQ#@  C72a  @@\@lX} @a aD Xrz  @,2q" ^@>B @@1@C($ @[@LPL` K @^^1 @HP+X1 @ ɛ"X#  @I$@pp8- @ ?f.NEJ (Jk8(`# @ )X$ @aF&@%%^J|P|O 0O?֓  @ P.#@,FP4 \\ @RR~/'@dPdL͙  @ ?zBG (nd*` @QQ9 @&BP 1 @ ?} @5\#`[ @ xn%@, @@ @ XX @[[!@[,[\CPA @ ?QXJ|/M @,\MP 1 @ ?ELIPR7 V_ @D Da9*,/b @`` @@UdE (n\%`b @  r:F+,+.N P@_ D# @//=F, @@I@X E,FP  @5B,P,Z%` @33T=2 X3 @aa:7 @@@lPlsrD @ @@Yh F'xO  @j"@ ( Xj @``+  @ ?w~NOPt;!  @ M,Rp @``y@,q=%ȕ @vv+W @  B6" Xnd @ྀྏO  @ ?_fNL\ + @2e^DdPdKy  @={2N 5 @  )* pd @ (ghtwN @... @@ 0/ @[[!@P! ő @_? @OO~ @'?xG&@pp8 I@)-g%@@_MN P &`F @@'@J||91 T@4"@'˿/ @`` G @00J"@|/M @hh8 PB@P"FC @L!@ (%<+`  @  {<?$r @  @ༀ' @ (& X'z4 @เๆ  @JEP @v/%@: (:ovqV @X1 @> (>J'| @ @00J"@Psslor% @`` @˿ @  HA+ț @ ?r:FP*` @c cn"@.JX.X @L!@* (*j&\/`  @\L7,7P M@-!@@.h,h  pR @+Wj{Xdi @I$@@@L"@\%J{ PC_#GS @  C72 X¹ A@!g @@| pW@pLJ Ak@( ( 0Q?ף  @W (.i  @wwy|H* p\Ν @ 8X{) @``7 @ ?KRI8 8 H @ ~&@@OMM4P4 ܸx%`W @@U@dEF @P %`b @@~@ M@b'@P!`߁R @@%@4B>>%@Pp$`D @@O@MM@/MK)(#`/A @M8 @b]>#@ p-O??L @ ? z3&@ @  x@G @F(F(z @. @ @ A @ (x @ @``g @ @ 9 @! @ @  x@G @F(F(z @. @ @ A @ (x @ @``g @ @ 9 @! @ @  x@G @F(F(z @. @ @ A @ (x @ @``g @ @ 9 @! @ @  x@G @FhC<#~=?Gzd?OO9-O pF@pFϽLק7Ss׿>WzS  @N WNz?}/ @@P@`s^ @[%@D%D\&@Pt;P @  JABJBa(#(A K@ +!@(| @`` @v (v(h 0O@0֓  @% @``}N@J1, @Z!@2 (2( ( @ 94r (r @@N@ܜ#4 L@,0%@@%%@4BDPDO P\@ P<` @aapP @u 묽( 0@@0# @`` @n (n,P,b @x#@@FoK?O_}U;3 @  d,E?M @$1 0^@ 0  @ ٛ))brH @  AHHJ @##= ({ P\@P<` @Rf!@P\-} pJ@ p @@c@NJ97 R@R߻  @ఀ0  @ R4 p*i!@)J)JP H&薸y  @# #j!@pJp8 L@,!@Jv$@ (glBP۰ @, @@%@V@p @EJH#H @^%^1 @5<)|  @ (| @|$@6(6  (gh @  @  QXJ P '@, @33u=B (BP @dd`'@J8 0O@0֓  @  x@G P 0&Ȗ @GGGee4 pG@pG G@ 'k @ ɛ(ސ PH@P(L @y%yCO @b (bT P@ ߫  @i iLӫw$2_h" (Gh%% @  u$@4J4Q9( @@ @@ ;@TPTH  0]@ 0  @ Ouu4 (蘺  @ఀ0  @ x=P̉  @'o8 8 @``) @@f%@P 0P@ 0ӣ @ NR6#/ȟ  @  @@P!.nJ @zH5H.H @@<%@LxzR @ J IPs3x_@ O @כ{#4P4 ۨ @  x@G34  @  |DH (Gl@"s @  ({- w\-Z @o7| @%t$@Ϳ'@uJuL: (:nf# @  ('| @F @J:>H H# @@%@MIV (V{/!O @F!@,=,l' F@ & !@ee4TPTK< @`` @J<>$@v(v`PPN PO@P/S @@A%@PD.P\ u @਀ਜ @o @  QXJ (8 @  @[ [*F (x @  `(D(((( @  ahL ({-%%9 @v#@&J&APs+$ @x x88,8LF P^@P>b @@7%@K (9Pa  @% K\/  @@d@tPt;($(Q @-%-#@2714P4  @_  @@U%@dE (9P @ @@^%@윜Ps/H*Hc @ xn%@sv _@ @L!@\@j (jk: Q@Q?  @@c%@Nmm6(/S ]@=A'@1=P q @j%PqT Z@ :>'@77YP @Z Zy P 0 T@  @@|%@lPlQr h.h0>P @``7 @ M (jh%ha  @y%yCO @++Խ$P$  @e&@ =\)Rۻ @@1%@@C5/o  @``g @J_ @@ @P  @w'@CC9= P 0 @@ ;@b (bT @  u|OEE5X-X @ ~#@ (bz8)8 v @ྀྏO  @U 4P4 F@& !@5P  @@%@( B  Csd Y@ 9=g'@ 9;H*Hc @@j@P  @  gnNMJ(JhH"Hc @Jɚ (%< @aF&@{! pK@ pK @88KO"@N (NP pzso$@ 9Pa  @  IPI (%n^-- @a%a:7 @7 7$@DPDJY @  szN(mL* @(%(I!@ ɛ$P$ ͑  @  LBlPlQr x+xk/ @@p%@B (BP @#%#! @ ~#@ ( \@< @(蹗: (:mVLIOX-?<}nph(h  0Z׿7|3G`O~?O_}ծ\L($mNL__R 0أ 9z (znj P 'Jpn#@  (J>>%@ h=x`'  @|$@Jͽඋ @@O@MMJ^Q@ e P^@P>b @``7PPL@ p=P<1P؀X/X|/M @ 雝 (.J<>$@ {%@MN 雝  н&? @@a@pFJ;_&&@@g@NJ^B@ / PX@P8\ @  zB}Χ蓵I  Y@9} @  @ ('l>$P$M6& (olDPDKy}79 ('l>$P$ Q6 (olDPDM߹271 ('l>$P$ 葕E5 (olDPDO}6) ('l>$P$ѕ5 (oldPdI936! ('l>PJ"AMM76 (%VJٚ6 ( |%@MM76 (&WJz6 ( t$%@MM76 ('XJ:Y6 ( l4%@MM76($%@ M@   BN2 IPI ; ovNN > x@G UU7 _fNL   C: h0E 3 OVNJ 6 X C ]]? ~FNH QQpPh'hy؁aq0P؀ Q@ Q?W (V')虻  V@ 6p+E@(/(  @ീൈW (V{/z (znjP PA P^@P>b @{Jdj%G ~P*DPDI9 PW@P7[ @F%F(MPL'P Q@ Q?W (V'+ @``'˧ (z0Z (Zoxx-x-UJUK ٚ (¹m`8 @u'@-_o{;K-~]./!@ N|O?ϟOq+p!@ @ @L Li9+,P,aR @``0 @@M%@\ME: (:mV8%8f @``q^OrZ @ೀ೅ @&%&& @q!ȑS @-Dv (vqX,X @@n%@tPtJ۬ 0E@ 0C  @ G==s75$Ȕ @@h%@xP @JEP, A@ k@DPDLř @  } @"5DPDI9 @o @``"G @\L (/o @ ? @ (.:+蛽  @@@(DmP N@."@J Pũ @x#@Cq$!葳)  @@@$Z (Znh D@K  @g%g ? @l=lPlr! pP@pm @`` @5L ( @pF#@J95. @@K%@ M (z88.8nN @ୀ୉ @0J0Q8H/H @z#@(q pJ@ p @H"Hc @ 8%o @% @@J@a8 H$H @JIlPlr& @ 9'3 @เๆ  @@B%@,P,@J 0Z@ 0Z @@=@LMDMM76(2 A@ !%g$@kkܽLPL` Z@:>'@]tPtN PZ@ P:^ @ dn @yyrR 0[@0[  @b%P 1 @L%L]&@99rrJ pZ@ p @@j@Pr5$Y @%$ @ <P<9' @&%&& @2 2QP7s*Țs @AJAC (x @ %A ({;# @) )Jr (r @``k @@#%@J6,&* I@)-g%@ (.* pd @YYsn V@_ @gJg~$@st p*i!@l=P0 P@0t# @Jr#@3p J@ *.%@(@lPlr# @TJTq9,xR @H.P\N @V!@ ٚBr)IDAT\&ڋ @aa:7 @5L (eD @  mtN  B6"R@ pw @ V$@6 (6B\(۫ @@'%@JRrF T@ 48&@ PI @w'@(.a pW@pLJ @(%(I!@EP@s $1 @6%6'W @ ѢG<P<$r.N @%% @q qDPs98!8V @ༀ༡' @- -J!@ (z8N@@P! @pF#@s^$Ȕ @J!({) pO@ pOg @ @JO"70#ȓ @@|@P 0P@0ӣ @9J9J6-H+H @@@ x,xl  ='@B (BP @@ $G$@^ (^zlPlQr  N@ ."@ 9 } @ "~'@R (R P@߫  @1J1B5o Id?9w͡k (ji/o @"%"x%@ 19$ U@ Uu M@-q @J!v (v Ȑ3 @ +T@ p) @@p@8'8n#I @w3P۰ @o&'@  @@%@ J77P+ @ྀྏO  @J (( @ @J^ (^%蕷i  Y@9} @ (| @Cf$@ ( ( @8%8KO"@x x8 P@ ߫  @``* @Ssfx$x$s @e&@@i@x GPs/DPDKy @PJPq8 Ps+ C@ #gS @z#@(0z,P,j @  W^NK//=F+C, @11sq*/S @M%M$@ 8 [@ ;#@ ~#@Pr1,P,j @F @@u@G\"K @[  @5Lq @  u|O X!X H@H @Jhn!@ NtPtN' @4  ( @@|%@R6# \@ < @@{@ @*%UCT 0I@ 0 c  @ࡀ!  @cc== (9 0T@ 0 @``K @33T=P' @  {|'E @,P,  D@$hc @q:TPTH  @@ %@ A 8 Q@ 1u3 @5B,LB!؁R @UJ}}6) L@ ,0%@@p? @Z |[x! Mhr 's0 W?>}79[+[\G @ ( @ @`` @ @@b@ @lPlr @H,H @ @ R#@ @st @ U@Uu @ @  qxN @ (J @$P$  @ @VV) @ @ 9: @**: @ X@8 @@@ @P @+  pJm"@ũ 0T@0 @,"s`Pss @Bf @FF( @ Xj<P<9 @^&"@CC" @J XKilPlr% @ ?{O xn%@$' Q  0C@0C3  @,p,P,aR @e˨q: @= @X!@ `U @ ~!@+i @ x? (X @hn!@@@ITWO|8)8 v @@r> @}} @ _ @@^윜 (.'B @F!@@@MJ$L@p @X0z (enb @ ?ovNN 8 @` @={2N#` @  mtN47 ژ-- @v$@W W ~%@ 1 PE@P%Is @,4 ( @,  0E@0C  @,D[[\C/`o h-h  @  A8* (*k6 @ ?CJH !H+`O @  _fNLH#H @,4 ($ @@$Ad d9. Z:>'@@n@#`ϓ @d"@ X8(蘺  @+,Wj{+x @ӄ@$= Ro X@8'@J XKj(P  @xx8|P @ XYz P 8 @m'@@@-` @ @  @"E^CP) @@,"@Xu!PJ_*N @@MI$P@p!W @,#4 (for @`  @  X Cš @``k  @C5 0L?҃ @``uODGMƹ @ @S73 pOOg V@6:'@&X'z$P) @8LPLh @ ?MTJGGGTWI pW@pLJ @@qG-D۴h/h@Z X[nhP @cf&@'/ I)m @   @,5<P<6r _?C @II@ @,#r@B@pw @,佗 (E@ @  H!@ 9x)`7 w('`/ @`E @X$ N@."@ X¹z(zlJ P]_=a @iiB @ X C@#'$@n Xo+x#xC @@b(b @>>/W @'/ M-1%@ 18 Qe @ീൈ  @8P!  @@{8+8+~ @` @@ @ I XF M@-!@> X?J'  @ppR$@  @xx8P @PF!@X Xy8 ,`  @``: @,\B(蹗!` @  @N> (>[V @@s@/  @""x%@ ٛ^h-h  @ɽ|/M @_%= @? @,I=Pr5 _ @``8 @,0HV (V{7-` @  Y`KX G@'k @,WI{!؁R @ࡀ!  @wo%@,S5P  @`) @ F @ XP! @@Z (%n^ 0N?ғ @ttb/ @%,%c5TPTNl @` @ N XEj "蒴9  @yyCO @轘a  @[[!@^ X_zP͡  @e˨Pt Y9=g'@@J|'`E @5 ` @  Z"C X{;&F @ ?]dL ([TWNl @׀ @ !$Y @>>/W @ 9<8,`?LF S@37&@g,gK ( @ࠀ  @@v@lor%('( @MM$@}}6) @ @@IX E (dgI9  @ ,/@J Y@9g#@,EJ (Jk8h(`o  @% @99%X"X @`8 @Z Zyz X{nj K@ @ ?\$Db (bT @`k @ @ ?gnNM ({18,`?LF W@7{ @@Nܜ,P, @ff* @ENb XcT @  MTJ,7:%%9 @` @v v X @  zBG],]77$ @[  @ .JV XW{/(.( @ ?U\Kr (r PW_7[ @ 1847\!B; @m|B P ( S @qq;w @33z%@v (v& @``  @99?w @FX#) @  @ N" @#p(.`/ @@@2 X3 @h"@8 \@\ @` @1=| @!!cq(H*`Oc @ )_ @aa:7 @OO~ @ (&\ E%)$@Ϳ'@SS|n&@P\] 7(?""HL@BJn? : ^] @GvE\@  @ ¾On/> @``C&\" _# @  ug @@jf&@B>? @ E@R$@S)y @ (.1h& 7{P!@_  @33?#@qOf` o@v W@i P_@F&$@P< @@[Ӻ  @M@  @@k@u9xP@ʯ @ ܷ39\# _+ @@q@2,8 PI@P5B;"@ (? @ݑ @YY @~  @ `& ov PM@PECUK @G~ϛWp @ H@ @ @@%+mY @ @`@_V>J @&m4 @,ZVʇ  @ @@f"@ @ :8 @TTU\ @ \`J /_% @ @@e _yF @[5r @T\շ| @ Mk o[! @ @@@@O<3 @ @Vnu}F @) ?eI @q  @$ t(3+ @H/#kP @HH.m3/ @H-c+` @HH,M33 @H+p @HH*-37 @H)b @HH( 3; @^% @ .Pӷ @ PFj Y @ @@a܁ @J T+Ra @"Pl{ @ @@9*_n5 D @*r @()pK @ @@MC @eNٕ0 @t8Q7ɝ @ @@/#@ @;  @UW @ Y`G w w#@ @$@ @+  @*0( @LXQ6  @ @ J@z~ @ @+ ָ' @ \UqOo` @$pE Ow%@ @H @ |m @ @@'@ @Mqg @j G?  @ @`W ꖸ7 @ sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`oIDATX WMKQTD tSڶuoqY/VtFܶp4 Bqe*LN98^Ӆy{}ȾkBnk7y^]"`- /`Em6yj5V+p9 x$[`f㸴3&!B-: NCR)<cj!\pSP(h}_.9C$ d|3Kp=X%gx Bl6)N3珌YD$o_P1<{\" H\,Swg||"'yi <3+$ 1r(yT@Kn/oŲ#V["לc\ 7IENDB`ic12!PNG  IHDR@@iq iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`oIDATx=AF !r s2p 5 'pHfGkacZ~oz@(qB-Sn~ L&jR^i4Qɨ|!QX,**bg+< -t]bIC%3PVnvfIfUSz=y?ߥT@ YAH0 #B$,KӉTHt:XKP33d$s*^4r@vz=G꜠"qW ֨*$PTHtVZm*%V$kprh4aA?UI<HJ$@`&E N0.LcGd8LHO~ )Ȏ_q9ƾ1j>" |,rPL=x<歒J-kp# .n9;%/)Wޱ{t.?oi %!ENktT' Ւ 7@/Q0G` o-Rx P5@k /hv7&ZIENDB`ic13։PNG  IHDR\rf iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o |IDATx?oM`ׂPƍqZ"vZ|"?pMfa7jRKZ?.53;9E{󈄼<|      ИE-A X/AkS4$p3 4$@@+?"m]m XHASO-h[@~Rؚdž&n=3$,e %O[R,~؊'[ ~94#O[з;8g `l~87#-v ϶C`'sRp/;r `mZ[?M}t&b sC` VOkp ~XJD\@'=:i5$"Ё@'z?Mu4&@P-{ ?I54$@`-=𱄼@#kY"e ஔ@_Ex4hђ ph;R D~h%x@'5<qؖCmчNlH [ Yn'4QA`"m E`#6 2c:02?lp,1.O]Ic20* ?q:jOa$Pq `apX?uu@ %osɮ55 kMG{ =`G܊nfS2ᏙK ^?^&e+"XXyDld1L%#j# #7g0lo_Nÿ{;& 8~?jɿ[s ?͗>C>?X$@'x~:D$8 '@3!' Wh޼W_=z扆z??pK#_y/|uϏ_rFߞ .~)Gs~QRL=4SL p$8"@ I x@#@HI#$A%+FJR*$ L!-;AގKI V6 dI9$ko#@QI $ +`0%e.bz({ ] (@ tkE>P#w wpp/@NXw߉#O!lY$hW!lVv dKOЇs]H D Pq/3δdJkZI`#!!iPwtvG$0U l#y^EU] ,UR(vH`-@66řb1HS"I;@@iX4yiȜ `>$@fZ-.  u;P3&]@.JpgϞ>|!3ȝߦՓ8S,F)bW$ ca'BH X !p3/Mӛ_;g5ܕ$P?rYYL#ڿ@?V@+%bnjڤ+hբA|y >?+)kGp bdao .b3:Ku {E`j`)1@>@ HUBI v>#Sd< ,F { $wj5V(m=C3{LP.[Fj؋@ ~F+$}sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o"zIDATx=ǕN"ȩA+p<(ȁH+ph'DN ЄDVǀ :8-\ @ @ @ @ @ @ @ @ @ @ @ l@x=" @ N @@w- !@ <yV&@!  DkA5sJ <5Q8^7"*d S[ds p/n5 0M` @8_8J @`/LiM  @1[pU @p=_. @{V @CЖٌ8j m 0L/ k @v$@Cلl8k - p_8}6 @x*0b  @`/닧  @i#pZ-L x"0c Ң @`/,돧 @3px;-H y*a b @i(_xO%@ Dam-m { p@/Z @Qp_>%@"`w{-@>>{ K v @},_xo~"@2 `sH d$q Z% @/ @`@/ll @@/NO* `CB} vrX)Pi +q)Pm =S @ _XqwI  @@/ܹ &@݆^;%'NNR/C/]qj0 ̯ @} ~_% }_(k%`@%@@z/Up0@'%@@j/uP<zS @ J( P  R?w )-U߷= <]mF@Ylk_B  p]Sv ;NDD\K. tUu(" ic0KabEU} wrC6#$/ 8R@8RZ I`W,` j9 TZ<Tsl!.i5lDɧ#6ەLۜەLۜەLۜەLۜەLۜەL_kgϞ]~:i_~rr z ˧w_O|7zY3#N!___?WX" ,QL{!@Ptpu ! PgZ! mN#  @.1% "@`o$@Ʈ9 !@` EL@ C^@" H@xG[r#@`0Cݞeu0r-uB؟%%X) 86" ts) 웪IL MwBXo L@X)]|^&@TK& \SYm) lC) l* lyzBB@f: @);N@ {jO/ oH+ m«U:r ڢB@:@(p\˫W׿8$+_HP @:]B! aӔL iJ/ - nCC-B!W pnB@)@R iK@o%0B@l Z__(@|! ~TH S$* pp5 ێ@A`SУNI,,Y  @@:V!O"0I@o[S:ww5{=!H$ $jR L&7@;:Us!p| H!Q@55' BprH# iB ly@uz X@x,gEu,p^#Q@558G@8ժ a[0C6#C@U) Է7BD|[ hfۗ|`~T@`0 mL *!0J@%m RA-G {j'N@Xi-v@? .@9\K1B1V!U@u h$ kYU*t {+BH. $o FIۇ`]J!( Vqy@X lkF 7*#T@X*9t@)@! N/TB`V' i4R(B@ި- X% 0(@!/<Ρ@Qhc,??YX( ,V$0K@%o_ v@:B@ި#;OpK s@/ˏ/^$6fB@̾лNP￿|!`!ؕDŽ+(>"0Q@o\B~  @((IYohGG(ZB~C++ ~K!`ۅV G@أB  @`U{@oh[-j!? F`ϫo$]nM[-j!pE@#!`% vyc!f E@آOO,JX1;x^%pK@%s!`' ly!`ҝG;@&C@؁U{By`wV`xTc;x^%T@X*u9!ඍoly!`ڣWG ~$C@؁Ukb>/|h[-j!C@؁B~C+B~C+z' V+ 7Aoh@Ͼ;u !`3V' 7Eoh^@~;m`!˗]ڛg.Tuo//^x󑿯x={-' 7HyEZt]Q!5 @LL]k) :74 C@U& TJաLۜr!`' / 70B@V(@z } ЭKW8U@8Z-]u&qv"pp8 ڴA U;\:!Bf(% jt:w ֛y@X! lkF % "O@m].vVB@v;,M&6//  fۛB'X@H<X" ,Q ~@;qC!a Tt9# h)mR$!f# Jfۛ$!`m 5C)F #E '*"0L@Fm#p-QBXo" D:L&ۚ$`m DuD=:TB@v).` ԉ\@s!p@6;$Bz3o$ dZ ێ@` d2vM =zwqP\-&|_׫ _7"Wބ/^\GFۏ@c!q=% "P[@_# J ʴA tS{B@R! i]B@(F W@;rOJ%d S.B@:WT jgEаe4rIENDB`il32*'̀')DD6́*̏̂*̏̃*̏&̏&̏%̏%̏%̏6DD)'̘''̀')DD6́*̏̂*̏̃*̏&̏&̏%̏%̏%̏6DD)'̘''̀')DD6́*̏̂*̏̃*̏&̏&̏%̏%̏%̏6DD)'̘'is32r "r MrrVrrVrrM r" rr "r MrrVrrVrrM r" rr "r MrrVrrVrrM r" rit32 )3333333f33f33f33f33f33f33f33f33f33f33f33f33f33f33kf33ff33ff33ff33ff33fm33f33f33f33f33f33f33f33f33f33f33f33f33f33f3333333))3333333f33f33f33f33f33f33f33f33f33f33f33f33f33f33kf33ff33ff33ff33ff33fm33f33f33f33f33f33f33f33f33f33f33f33f33f33f3333333))3333333f33f33f33f33f33f33f33f33f33f33f33f33f33f33kf33ff33ff33ff33ff33fm33f33f33f33f33f33f33f33f33f33f33f33f33f33f3333333)l8mk @@@@@@wwM̄X@@@@@@ name icons8mk#  #[8ThhT8[# # ##t8mk@33333333333333333333333333nitroshare-0.3.1/src/dist/wizard-small-image.bmp000664 001750 001750 00000023106 12653764154 022416 0ustar00nathannathan000000 000000 BMF&6(7:&  333333333333333   qqq zzz zzz zzz zzz zzz zzz}}} |||zzz zzz zzz zzz zzz zzz qqq   333333333333333nitroshare-0.3.1/src/dist/icons/ubuntu-mono-dark/apps/22/000775 001750 001750 00000000000 12653764154 023736 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/ubuntu-mono-light/apps/24/000775 001750 001750 00000000000 12653764154 024126 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/data/000775 001750 001750 00000000000 12653764154 016174 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/hicolor/scalable/apps/000775 001750 001750 00000000000 12653764154 023511 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/ubuntu-mono-light/apps/22/000775 001750 001750 00000000000 12653764154 024124 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/data/resource.rc000664 001750 001750 00000001762 12653764154 020357 0ustar00nathannathan000000 000000 #include #include "config.h" APP_ICON ICON DISCARDABLE "icon/nitroshare.ico" // Build a comma-separated version #define PROJECT_VERSION_RC \ PROJECT_VERSION_MAJOR, \ PROJECT_VERSION_MINOR, \ PROJECT_VERSION_PATCH, \ 0 VS_VERSION_INFO VERSIONINFO FILEVERSION PROJECT_VERSION_RC PRODUCTVERSION PROJECT_VERSION_RC { BLOCK "StringFileInfo" { BLOCK "040904b0" { VALUE "CompanyName", PROJECT_AUTHOR "\0" VALUE "FileDescription", PROJECT_DESCRIPTION "\0" VALUE "FileVersion", PROJECT_VERSION "\0" VALUE "InternalName", PROJECT_NAME "\0" VALUE "LegalCopyright", "Copyright (c) 2016 " PROJECT_AUTHOR "\0" VALUE "OriginalFilename", PROJECT_NAME ".exe\0" VALUE "ProductName", PROJECT_NAME "\0" VALUE "ProductVersion", PROJECT_VERSION "\0" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x409, 1252 } } nitroshare-0.3.1/src/device/devicedialog.h000664 001750 001750 00000003732 12653764154 021317 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_DEVICEDIALOG_H #define NS_DEVICEDIALOG_H #include #include #include "devicemodel.h" #include "ui_devicedialog.h" /** * @brief Dialog for selecting a device * * Given a DeviceModel instance, this dialog will display the devices * currently in the model and allow the user to select one. It is not * necessary to create an instance of the dialog in order to obtain a * selection from the user - simply use the getDevice() static method. */ class DeviceDialog : public QDialog, public Ui::DeviceDialog { Q_OBJECT public: explicit DeviceDialog(DeviceModel *model); QModelIndex selectedDeviceIndex() const; static QModelIndex getDevice(DeviceModel *model); private Q_SLOTS: void toggleOkButton(const QItemSelection &selected, const QItemSelection &deselected); }; #endif // NS_DEVICEDIALOG_H nitroshare-0.3.1/src/settings/settings_p.h000664 001750 001750 00000003257 12653764154 021462 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_SETTINGSPRIVATE_H #define NS_SETTINGSPRIVATE_H #include #include "settings.h" class SettingsPrivate { public: enum class Flag { None, Initialize, EmitSignal }; explicit SettingsPrivate(Settings *settings); QVariant get(Settings::Key key, Flag flag = Flag::None); void set(Settings::Key key, const QVariant &value, Flag flag = Flag::None); Settings *const q; QSettings settings; bool multiSet = false; QList multiSetKeys; }; #endif // NS_SETTINGSPRIVATE_H nitroshare-0.3.1/src/device/devicelistener.h000664 001750 001750 00000004102 12653764154 021675 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_DEVICELISTENER_H #define NS_DEVICELISTENER_H #include #include #include #include "../settings/settings.h" #include "../util/platform.h" /** * @brief Device broadcast emitter and receiver * * This class listens for incoming broadcast packets and sends them out over * all active network interfaces at a configurable interval. When receiving * packets, the address is captured for later use when sending transfers. */ class DeviceListener : public QObject { Q_OBJECT public: DeviceListener(); Q_SIGNALS: void pingReceived(const QString &uuid, const QString &name, Platform::OperatingSystem operatingSystem, const QHostAddress &address, quint16 port); private Q_SLOTS: void processPings(); void sendPings(); void onSettingsChanged(const QList &keys = {}); private: QTimer mTimer; QUdpSocket mSocket; }; #endif // NS_DEVICELISTENER_H nitroshare-0.3.1/src/device/devicemodel_p.h000664 001750 001750 00000003652 12653764154 021500 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_DEVICEMODELPRIVATE_H #define NS_DEVICEMODELPRIVATE_H #include #include #include #include "../settings/settings.h" #include "device.h" #include "devicelistener.h" #include "devicemodel.h" class DeviceModelPrivate : public QObject { Q_OBJECT public: explicit DeviceModelPrivate(DeviceModel *deviceModel); virtual ~DeviceModelPrivate(); DeviceModel * const q; QTimer timer; DeviceListener listener; QList devices; private Q_SLOTS: void processPing(const QString &uuid, const QString &name, Platform::OperatingSystem operatingSystem, const QHostAddress &address, quint16 port); void update(); void onSettingsChanged(const QList &keys = {}); }; #endif // NS_DEVICEMODELPRIVATE_H nitroshare-0.3.1/src/device/devicelistener.cpp000664 001750 001750 00000011272 12653764154 022236 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "../util/json.h" #include "devicelistener.h" DeviceListener::DeviceListener() { connect(&mTimer, &QTimer::timeout, this, &DeviceListener::sendPings); connect(&mSocket, &QUdpSocket::readyRead, this, &DeviceListener::processPings); connect(Settings::instance(), &Settings::settingsChanged, this, &DeviceListener::onSettingsChanged); // Load the initial settings onSettingsChanged(); // Immediately announce the device on the network and start the timer sendPings(); mTimer.start(); } void DeviceListener::processPings() { while(mSocket.hasPendingDatagrams()) { // Capture both the data and the address QByteArray data; QHostAddress address; data.resize(mSocket.pendingDatagramSize()); mSocket.readDatagram(data.data(), data.size(), &address); // Extract the data from the packet QJsonDocument document = QJsonDocument::fromJson(data); QJsonObject object; QString uuid; QString name; QString operatingSystemName; int port; if(Json::isObject(document, object) && Json::objectContains(object, "uuid", uuid) && Json::objectContains(object, "name", name) && Json::objectContains(object, "operating_system", operatingSystemName) && Json::objectContains(object, "port", port)) { // Double-check that the port is valid and convert the operating system if(port > 0 && port < 65536) { Platform::OperatingSystem operatingSystem = Platform::operatingSystemForName(operatingSystemName); emit pingReceived(uuid, name, operatingSystem, address, port); } } } } void DeviceListener::sendPings() { // TODO: when switching to Qt 5.4, switch to using QJsonObject's // initializer instead of converting a QVariantMap Settings *settings = Settings::instance(); QJsonObject object(QJsonObject::fromVariantMap({ { "uuid", settings->get(Settings::Key::DeviceUUID).toString() }, { "name", settings->get(Settings::Key::DeviceName).toString() }, { "operating_system", Platform::operatingSystemName() }, { "port", QString::number(settings->get(Settings::Key::TransferPort).toInt()) } })); // Build a list of all unique addresses (since we are // sending broadcast packets, these will always be IPv4) QSet addresses; foreach(QNetworkInterface interface, QNetworkInterface::allInterfaces()) { if(interface.flags() & QNetworkInterface::CanBroadcast) { foreach(QNetworkAddressEntry entry, interface.addressEntries()) { if(!entry.broadcast().isNull()) { addresses.insert(entry.broadcast()); } } } } // Build the packet and send it on all of the addresses QByteArray data(QJsonDocument(object).toJson(QJsonDocument::Compact)); foreach(QHostAddress address, addresses) { mSocket.writeDatagram(data, address, mSocket.localPort()); } } void DeviceListener::onSettingsChanged(const QList &keys) { Settings *settings = Settings::instance(); if(keys.empty() || keys.contains(Settings::Key::BroadcastInterval)) { mTimer.setInterval(settings->get(Settings::Key::BroadcastInterval).toInt()); } if(keys.empty() || keys.contains(Settings::Key::BroadcastPort)) { mSocket.close(); mSocket.bind(settings->get(Settings::Key::BroadcastPort).toInt(), QUdpSocket::ShareAddress); } } nitroshare-0.3.1/src/dist/icons/hicolor/scalable/apps/nitroshare.svg000664 001750 001750 00000002545 12653764154 026416 0ustar00nathannathan000000 000000 image/svg+xmlnitroshare-0.3.1/src/data/icon/000775 001750 001750 00000000000 12653764154 017124 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/icon/trayicon.h000664 001750 001750 00000003110 12653764154 020207 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRAYICON_H #define NS_TRAYICON_H #include #include #include "icon.h" class TrayIcon : public Icon { Q_OBJECT public: TrayIcon(); virtual void addAction(const QString &text, QObject *receiver, const char *member); virtual void addSeparator(); public Q_SLOTS: virtual void showMessage(const QString &message); private: QSystemTrayIcon mTrayIcon; QMenu mMenu; }; #endif // NS_TRAYICON_H nitroshare-0.3.1/src/settings/000775 001750 001750 00000000000 12653764154 017123 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/data/img/desktop.svg000664 001750 001750 00000001105 12653764154 021137 0ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/ubuntu-mono-light/apps/000775 001750 001750 00000000000 12653764154 023701 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/breeze-dark/apps/22/nitroshare-indicator.svg000664 001750 001750 00000026346 12653764154 027606 0ustar00nathannathan000000 000000 image/svg+xml nitroshare-0.3.1/src/dist/icons/breeze-dark/apps/000775 001750 001750 00000000000 12653764154 022477 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/data/resource.qrc000664 001750 001750 00000000306 12653764154 020531 0ustar00nathannathan000000 000000 img/desktop.svg img/logo.svg img/splash.png img/tray.svg nitroshare-0.3.1/src/application/application.h000664 001750 001750 00000005234 12653764154 022246 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_APPLICATION_H #define NS_APPLICATION_H #include "../bundle/bundle.h" #include "../device/devicemodel.h" #include "../icon/icon.h" #include "../transfer/transfermodel.h" #include "../transfer/transferserver.h" #include "../transfer/transferwindow.h" /** * @brief An interface between the user and the transfer classes * * This class maintains the device and transfer models used for discovering * devices on the network and initiating transfers with them. The class is * also resposible for communicating events to the user using notifications. */ class Application : public QObject { Q_OBJECT public: Application(); virtual ~Application(); private Q_SLOTS: void notifyDevicesAdded(const QModelIndex &parent, int first, int last); void notifyDevicesRemoved(const QModelIndex &parent, int first, int last); void notifyTransfersChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); void notifyError(const QString &message); void sendFiles(); void sendDirectory(); void onOpenSettings(); void onOpenAbout(); void onOpenAboutQt(); private: void sendBundle(const Bundle *bundle); DeviceModel mDeviceModel; TransferModel mTransferModel; TransferServer mTransferServer; TransferWindow mTransferWindow; // A pointer must be used since the child class is determined at runtime Icon *mIcon; // Used to avoid showing notifications during the first 10 seconds after startup qint64 mStartTime; }; #endif // NS_APPLICATION_H nitroshare-0.3.1/cmake/DeployQt.cmake000664 001750 001750 00000005666 12653764154 020334 0ustar00nathannathan000000 000000 # The MIT License (MIT) # # Copyright (c) 2016 Nathan Osman # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. find_package(Qt5Core REQUIRED) # Retrieve the absolute path to qmake and then use that path to find # the windeployqt and macdeployqt binaries get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION) get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY) find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}") find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}") # Add commands that copy the required Qt files to the same directory as the # target after being built, including the system libraries function(windeployqt target) add_custom_command(TARGET ${target} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E env PATH="${_qt_bin_dir}" "${WINDEPLOYQT_EXECUTABLE}" --verbose 0 --no-compiler-runtime "$" COMMENT "Deploying Qt..." ) # windeployqt doesn't work correctly with the system runtime libraries, # so we fall back to one of CMake's own modules for copying them over include(InstallRequiredSystemLibraries) foreach(lib ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}) get_filename_component(filename "${lib}" NAME) add_custom_command(TARGET ${target} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${lib}" "$" COMMENT "Copying ${filename}..." ) endforeach() endfunction() # Add commands that copy the required Qt files to the application bundle # represented by the target. function(macdeployqt target) add_custom_command(TARGET ${target} POST_BUILD COMMAND "${MACDEPLOYQT_EXECUTABLE}" "$/../.." -always-overwrite COMMENT "Deploying Qt..." ) endfunction() mark_as_advanced(WINDEPLOYQT_EXECUTABLE MACDEPLOYQT_EXECUTABLE) nitroshare-0.3.1/src/dist/icons/breeze-dark/000775 001750 001750 00000000000 12653764154 021534 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/icon/trayicon.cpp000664 001750 001750 00000003205 12653764154 020547 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include "trayicon.h" TrayIcon::TrayIcon() { mTrayIcon.setContextMenu(&mMenu); mTrayIcon.setIcon(QIcon(":/img/tray.svg")); mTrayIcon.setToolTip(tr("NitroShare")); mTrayIcon.show(); } void TrayIcon::addAction(const QString &text, QObject *receiver, const char *member) { mMenu.addAction(text, receiver, member); } void TrayIcon::addSeparator() { mMenu.addSeparator(); } void TrayIcon::showMessage(const QString &message) { mTrayIcon.showMessage(tr("NitroShare Notification"), message); } nitroshare-0.3.1/src/icon/000775 001750 001750 00000000000 12653764154 016213 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/nitroshare.desktop000664 001750 001750 00000000301 12653764154 021771 0ustar00nathannathan000000 000000 [Desktop Entry] Version=1.0 Type=Application Name=NitroShare Comment=Network File Transfer Application Icon=nitroshare Exec=nitroshare Categories=Network;FileTransfer Keywords=network;transfer nitroshare-0.3.1/src/dist/icons/000775 001750 001750 00000000000 12653764154 017341 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/transfer/transferserver.h000664 001750 001750 00000004476 12653764154 022346 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERSERVER_H #define NS_TRANSFERSERVER_H #include class TransferServerPrivate; /** * @brief Server listening for incomming connections * * This class listens for connection requests from other clients and emits the * newTransfer signal when one is received. The port used for listening is * configurable and an error will be raised if the port is in use. The server * will not begin listening until the start() */ class TransferServer : public QObject { Q_OBJECT public: /** * @brief Create a new transfer server * @param parent parent QObject */ explicit TransferServer(QObject *parent = nullptr); /** * @brief Destroy the server */ virtual ~TransferServer(); Q_SIGNALS: /** * @brief Indicate an error * @param message description of the error */ void error(const QString &message); /** * @brief Indicate a new connection attempt * @param socketDescriptor socket descriptor */ void newTransfer(qintptr socketDescriptor); public Q_SLOTS: /** * @brief Start the server */ void start(); private: TransferServerPrivate *const d; }; #endif // NS_TRANSFERSERVER_H nitroshare-0.3.1/src/Info.plist.in000664 001750 001750 00000002052 12653764154 017637 0ustar00nathannathan000000 000000 CFBundleDevelopmentRegion en CFBundleExecutable ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier ${MACOSX_BUNDLE_GUI_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundlePackageType APPL CFBundleSignature ???? LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion 10.7.0 NSPrincipalClass NSApplication NSHighResolutionCapable True nitroshare-0.3.1/src/dist/icons/breeze/000775 001750 001750 00000000000 12653764154 020615 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/breeze/apps/22/nitroshare-indicator.svg000664 001750 001750 00000026244 12653764154 026664 0ustar00nathannathan000000 000000 image/svg+xml nitroshare-0.3.1/src/dist/icons/breeze/apps/000775 001750 001750 00000000000 12653764154 021560 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/application/aboutdialog.h000664 001750 001750 00000002754 12653764154 022241 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_ABOUTDIALOG_H #define NS_ABOUTDIALOG_H #include #include "ui_aboutdialog.h" /** * @brief Simple about dialog describing the application */ class AboutDialog : public QDialog, public Ui::AboutDialog { Q_OBJECT public: AboutDialog(); private Q_SLOTS: void onCreditsOrLicenceClicked(bool checked); }; #endif // NS_ABOUTDIALOG_H nitroshare-0.3.1/src/device/devicedialog.ui000664 001750 001750 00000005224 12653764154 021503 0ustar00nathannathan000000 000000 DeviceDialog 0 0 400 200 Select Device :/img/logo.svg:/img/logo.svg Select a device: QAbstractItemView::SingleSelection QAbstractItemView::SelectRows 150 false true false QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() DeviceDialog accept() 199 177 199 99 buttonBox rejected() DeviceDialog reject() 199 177 199 99 deviceView doubleClicked(QModelIndex) DeviceDialog accept() 199 94 199 99 nitroshare-0.3.1/LICENSE.txt000664 001750 001750 00000002067 12653764154 016324 0ustar00nathannathan000000 000000 The MIT License (MIT) Copyright (c) 2016 Nathan Osman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nitroshare-0.3.1/CMakeLists.txt000664 001750 001750 00000004060 12653764154 017234 0ustar00nathannathan000000 000000 cmake_minimum_required(VERSION 3.2.0) project(NitroShare) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(PROJECT_NAME "NitroShare") set(PROJECT_DESCRIPTION "Network File Transfer Application") set(PROJECT_AUTHOR "Nathan Osman") set(PROJECT_DOMAIN "nitroshare.net") set(PROJECT_WEBSITE "https://${PROJECT_DOMAIN}") set(PROJECT_VERSION_MAJOR 0) set(PROJECT_VERSION_MINOR 3) set(PROJECT_VERSION_PATCH 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") # In order for the Inno Setup script to work correctly, the runtime files need # to be kept separate from the source code - bonus: it then becomes possible to # run the executable directly from the directory after building. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out") find_package(Qt5Network 5.1 REQUIRED) find_package(Qt5Widgets 5.1 REQUIRED) # Qt5WinExtras is an optional dependency that allows the application to # display transfer progress in the Windows taskbar. if(WIN32) find_package(Qt5WinExtras) endif() # Qt5MacExtras is an optional dependency that allows the application to # display transfer progress as a percentage in the dock. if(APPLE) find_package(Qt5MacExtras) endif() # libappindicator is an optional dependency that enables the application to # determine at runtime if the current desktop environment supports using an # application indicator instead of a QTrayIcon and use one instead # libunity is an optional dependency that enables the application to display # transfer progress in the Unity launcher. if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") find_package(PkgConfig) if(PKG_CONFIG_FOUND) pkg_check_modules(APPINDICATOR gtk+-2.0 appindicator-0.1 libnotify) pkg_check_modules(UNITY unity) endif() endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) # Since Qt and GTK+ both define the symbol "signals", it is necessary to # ensure that it is not defined by Qt. add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS) # Add the subdirectory containing the source code. add_subdirectory(src) nitroshare-0.3.1/src/data/img/logo.svg000664 001750 001750 00000002545 12653764154 020437 0ustar00nathannathan000000 000000 image/svg+xmlnitroshare-0.3.1/src/dist/icons/ubuntu-mono-light/000775 001750 001750 00000000000 12653764154 022736 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/data/img/tray.svg000664 001750 001750 00000001251 12653764154 020447 0ustar00nathannathan000000 000000 nitroshare-0.3.1/src/transfer/transfersender.h000664 001750 001750 00000004003 12653764154 022302 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_TRANSFERSENDER_H #define NS_TRANSFERSENDER_H #include #include #include "../bundle/bundle.h" #include "../bundle/bundleitem.h" #include "transfer.h" class TransferSender : public Transfer { Q_OBJECT public: TransferSender(const QString &deviceName, const QHostAddress &address, quint16 port, const Bundle *bundle); virtual ~TransferSender(); virtual void start(); private: virtual void processJsonPacket(const QJsonObject &object); virtual void processBinaryPacket(const QByteArray &data); virtual void writeNextPacket(); void writeTransferHeader(); void writeItemHeader(); void writeItemData(); void nextItem(); const QHostAddress mAddress; const quint16 mPort; const Bundle *mBundle; const int mBufferSize; QList::const_iterator mCurrentItem; }; #endif // NS_TRANSFERSENDER_H nitroshare-0.3.1/src/application/splashdialog.cpp000664 001750 001750 00000003005 12653764154 022742 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include "splashdialog.h" SplashDialog::SplashDialog() { setupUi(this); // Remove the frame and center the window setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, size(), QApplication::desktop()->availableGeometry())); } nitroshare-0.3.1/src/device/device.cpp000664 001750 001750 00000003651 12653764154 020472 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include "../settings/settings.h" #include "device.h" Device::Device(const QString &uuid) : mUuid(uuid) { } bool Device::hasTimedOut() const { return QDateTime::currentMSecsSinceEpoch() - mLastPing > Settings::instance()->get(Settings::Key::BroadcastTimeout).toLongLong(); } bool Device::update(const QString &name, Platform::OperatingSystem operatingSystem, const QHostAddress &address, quint16 port) { // Check for any changes bool changed = name != mName || operatingSystem != mOperatingSystem || address != mAddress || port != mPort; // Store the new values mName = name; mOperatingSystem = operatingSystem; mAddress = address; mPort = port; // Update the last ping mLastPing = QDateTime::currentMSecsSinceEpoch(); return changed; } nitroshare-0.3.1/src/CMakeLists.txt000664 001750 001750 00000011572 12653764154 020031 0ustar00nathannathan000000 000000 configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h") set(SRC application/aboutdialog.cpp application/application.cpp application/splashdialog.cpp bundle/bundle.cpp device/device.cpp device/devicedialog.cpp device/devicelistener.cpp device/devicemodel.cpp icon/icon.cpp icon/trayicon.cpp settings/settings.cpp settings/settingsdialog.cpp transfer/transfer.cpp transfer/transfermodel.cpp transfer/transferreceiver.cpp transfer/transfersender.cpp transfer/transferserver.cpp transfer/transferwindow.cpp util/json.cpp util/platform.cpp main.cpp ) if(WIN32) set(SRC ${SRC} "data/resource.rc") endif() if(APPLE) set(SRC ${SRC} "data/icon/nitroshare.icns") set_source_files_properties("data/icon/nitroshare.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) endif() if(APPINDICATOR_FOUND) set(SRC ${SRC} icon/indicatoricon.cpp ) endif() qt5_wrap_ui(UI application/aboutdialog.ui application/splashdialog.ui device/devicedialog.ui settings/settingsdialog.ui transfer/transferwindow.ui ) qt5_add_resources(QRC data/resource.qrc ) add_executable(nitroshare WIN32 MACOSX_BUNDLE ${SRC} ${UI} ${QRC}) target_compile_features(nitroshare PRIVATE cxx_lambdas cxx_nullptr cxx_strong_enums cxx_uniform_initialization ) # By default, Visual C++ produces PE files with "minimum OS Required" set to # 6.0 (Windows Vista). A special linker flag is needed for XP support. if(WIN32 AND MSVC) if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) set_target_properties(nitroshare PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS,5.02") else() set_target_properties(nitroshare PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS,5.01") endif() endif() # In order to support Retina, a special tag is required in Info.plist. if(APPLE) set_target_properties(nitroshare PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "nitroshare.icns" MACOSX_BUNDLE_GUI_IDENTIFIER "com.NathanOsman.NitroShare" MACOSX_BUNDLE_BUNDLE_NAME "NitroShare" ) endif() qt5_use_modules(nitroshare Widgets Network) if(Qt5WinExtras_FOUND) qt5_use_modules(nitroshare WinExtras) endif() if(Qt5MacExtras_FOUND) qt5_use_modules(nitroshare MacExtras) endif() if(APPINDICATOR_FOUND) target_include_directories(nitroshare PRIVATE ${APPINDICATOR_INCLUDE_DIRS}) target_link_libraries(nitroshare ${APPINDICATOR_LIBRARIES}) endif() if(UNITY_FOUND) target_include_directories(nitroshare PRIVATE ${UNITY_INCLUDE_DIRS}) target_link_libraries(nitroshare ${UNITY_LIBRARIES}) endif() include(GNUInstallDirs) install(TARGETS nitroshare RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} BUNDLE DESTINATION . ) # If windeployqt is available, use it immediately after the build completes to # ensure that the dependencies are available. # If Inno Setup is available, provide a target for building an EXE installer. if(WIN32) include(DeployQt) if(WINDEPLOYQT_EXECUTABLE) windeployqt(nitroshare) endif() find_package(InnoSetup) if(INNOSETUP_EXECUTABLE) configure_file(dist/setup.iss.in "${CMAKE_CURRENT_BINARY_DIR}/setup.iss") add_custom_target(exe COMMAND "${INNOSETUP_EXECUTABLE}" /Q /DTARGET_FILE_NAME="$" "${CMAKE_CURRENT_BINARY_DIR}/setup.iss" DEPENDS nitroshare COMMENT "Building installer..." ) endif() endif() # If macdeployqt is available, use it immediately after the build completes to # copy the Qt frameworks into the application bundle. # Create a target for building a DMG that contains the application bundle and a # symlink to the /Applications folder. if(APPLE) include(DeployQt) if(MACDEPLOYQT_EXECUTABLE) macdeployqt(nitroshare) endif() set(sym "${CMAKE_BINARY_DIR}/out/Applications") set(dmg "${CMAKE_BINARY_DIR}/nitroshare-${PROJECT_VERSION}-osx.dmg") add_custom_target(dmg COMMAND rm -f "${sym}" "${dmg}" COMMAND ln -s /Applications "${sym}" COMMAND hdiutil create -srcfolder "${CMAKE_BINARY_DIR}/out" -volname "${PROJECT_NAME}" -fs HFS+ -size 30m "${dmg}" DEPENDS nitroshare COMMENT "Building disk image..." ) endif() # On Linux, include the icons, manpage, and .desktop file when installing. if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/dist/icons" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}" ) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/dist/nitroshare.1" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" ) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/dist/nitroshare.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications" ) endif() nitroshare-0.3.1/src/dist/icons/ubuntu-mono-dark/apps/000775 001750 001750 00000000000 12653764154 023513 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/settings/settingsdialog.cpp000664 001750 001750 00000010323 12653764154 022646 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "config.h" #include "settings.h" #include "settingsdialog.h" SettingsDialog::SettingsDialog() { setupUi(this); // Load the current values into the controls reload(); } void SettingsDialog::accept() { Settings *settings = Settings::instance(); settings->beginSet(); // Settings in the general tab settings->set(Settings::Key::DeviceName, deviceNameEdit->text()); settings->set(Settings::Key::TransferDirectory, transferDirectoryEdit->text()); settings->set(Settings::Key::BehaviorReceive, receiveFilesCheckBox->isChecked()); settings->set(Settings::Key::BehaviorOverwrite, overwriteCheckBox->isChecked()); // Settings in the transfer section settings->set(Settings::Key::TransferPort, transferPortSpinBox->value()); settings->set(Settings::Key::TransferBuffer, transferBufferSpinBox->value() * Settings::Constant::KiB); // Settings in the broadcast section settings->set(Settings::Key::BroadcastPort, broadcastPortSpinBox->value()); settings->set(Settings::Key::BroadcastTimeout, broadcastTimeoutSpinBox->value() * Settings::Constant::Second); settings->set(Settings::Key::BroadcastInterval, broadcastIntervalSpinBox->value() * Settings::Constant::Second); settings->endSet(); QDialog::accept(); } void SettingsDialog::onResetButtonClicked() { // Confirm that the user wants to reset all of the settings QMessageBox::StandardButton response = QMessageBox::question( this, tr("Confirm Reset"), tr("Are you sure you want to reset all settings to their default values? This cannot be undone.") ); // Perform the reset and then reload all of the settings if(response == QMessageBox::Yes) { Settings::instance()->reset(); reload(); } } void SettingsDialog::onTransferDirectoryButtonClicked() { QString path = QFileDialog::getExistingDirectory(this, tr("Select Directory"), transferDirectoryEdit->text()); if(!path.isNull()) { transferDirectoryEdit->setText(path); } } void SettingsDialog::reload() { Settings *settings = Settings::instance(); // General tab deviceNameEdit->setText(settings->get(Settings::Key::DeviceName).toString()); transferDirectoryEdit->setText(settings->get(Settings::Key::TransferDirectory).toString()); receiveFilesCheckBox->setChecked(settings->get(Settings::Key::BehaviorReceive).toBool()); overwriteCheckBox->setChecked(settings->get(Settings::Key::BehaviorOverwrite).toBool()); // Transfer section transferPortSpinBox->setValue(settings->get(Settings::Key::TransferPort).toLongLong()); transferBufferSpinBox->setValue(settings->get(Settings::Key::TransferBuffer).toInt() / Settings::Constant::KiB); // Broadcast section broadcastPortSpinBox->setValue(settings->get(Settings::Key::BroadcastPort).toLongLong()); broadcastTimeoutSpinBox->setValue(settings->get(Settings::Key::BroadcastTimeout).toInt() / Settings::Constant::Second); broadcastIntervalSpinBox->setValue(settings->get(Settings::Key::BroadcastInterval).toInt() / Settings::Constant::Second); } nitroshare-0.3.1/src/dist/icons/ubuntu-mono-dark/apps/24/nitroshare-indicator.svg000664 001750 001750 00000002470 12653764154 030614 0ustar00nathannathan000000 000000 image/svg+xml nitroshare-0.3.1/src/dist/icons/ubuntu-mono-dark/apps/24/000775 001750 001750 00000000000 12653764154 023740 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/device/devicedialog.cpp000664 001750 001750 00000004576 12653764154 021661 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include "devicedialog.h" DeviceDialog::DeviceDialog(DeviceModel *model) { setupUi(this); deviceView->setModel(model); // Disable the OK button until the user makes a selection buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); connect(deviceView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DeviceDialog::toggleOkButton); } QModelIndex DeviceDialog::selectedDeviceIndex() const { QModelIndexList selection(deviceView->selectionModel()->selectedIndexes()); return selection.count() ? selection.at(0) : QModelIndex(); } QModelIndex DeviceDialog::getDevice(DeviceModel *model) { DeviceDialog deviceDialog(model); // Check the return value since the user may have made // a valid selection but clicked the cancel button if(deviceDialog.exec() == QDialog::Accepted) { return deviceDialog.selectedDeviceIndex(); } else { return QModelIndex(); } } void DeviceDialog::toggleOkButton(const QItemSelection &, const QItemSelection &) { // The OK button is only enabled after the user has made a selection bool itemSelected(deviceView->selectionModel()->hasSelection()); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(itemSelected); } nitroshare-0.3.1/src/util/000775 001750 001750 00000000000 12653764154 016240 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/bundle/bundleitem.h000664 001750 001750 00000004231 12653764154 021035 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_BUNDLEITEM_H #define NS_BUNDLEITEM_H #include #include #include /** * @brief An item to be transferred * * This class maintains information about a file or directory to be * transferred. Currently, this includes the item's name, creation, and * modification times. */ class BundleItem { public: explicit BundleItem(const QFileInfo &info) : BundleItem(QDir(info.path()), info) {} BundleItem(const QDir &root, const QFileInfo &info) : mRoot(root), mInfo(info) {} QString relativeFilename() const { return mRoot.relativeFilePath(absoluteFilename()); } QString absoluteFilename() const { return mInfo.absoluteFilePath(); } bool isDir() const { return mInfo.isDir(); } qint64 created() const { return mInfo.created().toMSecsSinceEpoch(); } qint64 lastModified() const { return mInfo.lastModified().toMSecsSinceEpoch(); } qint64 lastRead() const { return mInfo.lastRead().toMSecsSinceEpoch(); } private: QDir mRoot; QFileInfo mInfo; }; #endif // NS_BUNDLEITEM_H nitroshare-0.3.1/src/dist/000775 001750 001750 00000000000 12653764154 016226 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/dist/icons/gnome/000775 001750 001750 00000000000 12653764154 020446 5ustar00nathannathan000000 000000 nitroshare-0.3.1/src/application/splashdialog.ui000664 001750 001750 00000003113 12653764154 022575 0ustar00nathannathan000000 000000 SplashDialog 0 0 640 480 640 480 640 480 NitroShare - Introduction :/img/logo.svg:/img/logo.svg QDialog { background-image: url(:/img/splash.png); } 510 430 100 30 Close pushButton clicked() SplashDialog accept() 559 444 319 239 nitroshare-0.3.1/src/icon/icon.cpp000664 001750 001750 00000002216 12653764154 017650 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include "icon.h" nitroshare-0.3.1/src/bundle/bundle.cpp000664 001750 001750 00000005260 12653764154 020514 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "bundle.h" #include "bundle_p.h" #include "bundleitem.h" Bundle::Bundle(QObject *parent) : QObject(parent), d(new BundlePrivate) { } Bundle::~Bundle() { delete d; } int Bundle::count() const { return d->items.count(); } qint64 Bundle::totalSize() const { return d->totalSize; } void Bundle::addFile(const QString &filename) { QFileInfo info(filename); d->items.append(BundleItem(info)); d->totalSize += info.size(); } void Bundle::addDirectory(const QString &path) { QDir root(path); QStack stack; // Ensure that the root directory is created d->items.append(BundleItem(QFileInfo(root.absolutePath()))); // Push the root path on the stack and then go up one level so that // the relative filenames will include the name of the directory stack.push(root.absolutePath()); root.cdUp(); while(stack.count()) { QString tos = stack.pop(); foreach(QFileInfo info, QDir(tos).entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { // Skip symbolic links if(info.isSymLink()) { continue; } // Add the item to the bundle d->items.append(BundleItem(root, info)); // If the item is a directory, add it to the stack // Otherwise, add its size to the total if(info.isDir()) { stack.push(info.absoluteFilePath()); } else { d->totalSize += info.size(); } } } } nitroshare-0.3.1/src/util/json.h000664 001750 001750 00000006012 12653764154 017361 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_JSON_H #define NS_JSON_H #include #include #include #include /** * @brief Validation methods for JSON documents * * There are many classes that need to ensure that JSON data received from an * external source contains the expected data. This class exists to fill that * need. * * The validation methods accept a reference to the expected type and return a * boolean indicating whether the provided data could be converted to that * type. Because a boolean is returned, multiple checks can be performed * within a single "if" statement joined with the logical and operator. For * example: * * QJsonDocument doc = ... * QJsonArray array; * QString item1; * qint64 item2; * * if(JSON::isArray(doc, array) && * array.count() && * JSON::isObject(array.at(0), object) && * JSON::objectContains(object, "item1", item1) && * JSON::objectContains(object, "item2", item2) { * * //... * } * * One of the important things to note about this class is the fact that it * attempts to perform the conversion before indicating success or failure. * Therefore, the destination variable may be modified, even after failure. */ class Json { public: static bool isArray(const QJsonDocument &document, QJsonArray &array); static bool isObject(const QJsonDocument &document, QJsonObject &object); static bool isObject(const QJsonValue &value, QJsonObject &object); static bool objectContains(const QJsonObject &object, const QString &key, bool &value); static bool objectContains(const QJsonObject &object, const QString &key, qint32 &value); static bool objectContains(const QJsonObject &object, const QString &key, qint64 &value); static bool objectContains(const QJsonObject &object, const QString &key, QString &value); }; #endif // NS_JSON_H nitroshare-0.3.1/src/main.cpp000664 001750 001750 00000005623 12653764154 016721 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "application/application.h" #include "application/splashdialog.h" #include "settings/settings.h" #include "util/platform.h" #include "config.h" int main(int argc, char **argv) { QApplication app(argc, argv); app.setQuitOnLastWindowClosed(false); // Set up application properties app.setApplicationDisplayName(PROJECT_NAME); app.setApplicationName(PROJECT_NAME); app.setApplicationVersion(PROJECT_VERSION); app.setOrganizationDomain(PROJECT_DOMAIN); app.setOrganizationName(PROJECT_AUTHOR); // Check to see if the splash screen has been displayed yet bool appSplash = Settings::instance()->get(Settings::Key::ApplicationSplash).toBool(); // If not, display it and remember that the user has seen it if(!appSplash) { SplashDialog().exec(); Settings::instance()->set(Settings::Key::ApplicationSplash, true); } #ifdef APPINDICATOR_FOUND // If the splash had not been seen and the user is running Gnome, // warn them that they need a special extension installed if(!appSplash && Platform::currentDesktopEnvironment() == Platform::DesktopEnvironment::Gnome) { QMessageBox::about(nullptr, QObject::tr("Warning"), QObject::tr( "Some versions of Gnome do not support AppIndicators. This prevents " "NitroShare from displaying an indicator in the notification area. " "Please ensure you have this extension installed before continuing:" "

%1" ).arg("https://extensions.gnome.org/extension/615/appindicator-support/")); } #endif // Create the tray icon that runs the application Application nitroshare; Q_UNUSED(nitroshare); return app.exec(); } nitroshare-0.3.1/src/transfer/transfermodel.cpp000664 001750 001750 00000017570 12653764154 022472 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include #include #include #include "transfermodel.h" #include "transfermodel_p.h" #include "transferreceiver.h" #include "transfersender.h" TransferModelPrivate::TransferModelPrivate(TransferModel *transferModel) : q(transferModel), cachedProgress(0), cachedProgressAge(0) { } TransferModelPrivate::~TransferModelPrivate() { qDeleteAll(transfers); } void TransferModelPrivate::add(Transfer *transfer) { q->beginInsertRows(QModelIndex(), transfers.count(), transfers.count()); transfers.append(transfer); q->endInsertRows(); // Whenever the transfer changes, emit the appropriate signal QObject::connect(transfer, &Transfer::dataChanged, [this, transfer](const QVector &roles) { if(!roles.contains(TransferModel::ProgressRole)) { cachedProgressAge = 0; } int index = transfers.indexOf(transfer); emit q->dataChanged(q->index(index, 0), q->index(index, TransferModel::ColumnCount - 1), roles); }); transfer->start(); } void TransferModelPrivate::remove(Transfer *transfer) { // We need the index of the transfer for the removal signals int row = transfers.indexOf(transfer); emit q->beginRemoveRows(QModelIndex(), row, row); transfers.removeAt(row); emit q->endRemoveRows(); delete transfer; } TransferModel::TransferModel(QObject *parent) : QAbstractTableModel(parent), d(new TransferModelPrivate(this)) { } TransferModel::~TransferModel() { delete d; } int TransferModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : d->transfers.count(); } int TransferModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : ColumnCount; } QVariant TransferModel::data(const QModelIndex &index, int role) const { if(!index.isValid() || index.model() != this) { return QVariant(); } Transfer *transfer = d->transfers.at(index.row()); switch(role) { case Qt::DisplayRole: switch(index.column()) { case DeviceNameColumn: return transfer->deviceName(); case ProgressColumn: return QString("%1%").arg(transfer->progress()); case StateColumn: switch(transfer->state()) { case Connecting: return tr("Connecting"); case InProgress: return tr("In Progress"); case Failed: return tr("Failed: %1").arg(transfer->error()); case Succeeded: return tr("Succeeded"); } } break; case Qt::DecorationRole: if(index.column() == DeviceNameColumn) { switch(transfer->direction()) { case Send: return QApplication::style()->standardIcon(QStyle::SP_ArrowUp); case Receive: return QApplication::style()->standardIcon(QStyle::SP_ArrowDown); } } break; case Qt::ForegroundRole: if(index.column() == StateColumn) { switch(transfer->state()) { case Failed: return QBrush(Qt::darkRed); case Succeeded: return QBrush(Qt::darkGreen); default: break; } } break; case DeviceNameRole: return transfer->deviceName(); case ProgressRole: return transfer->progress(); case DirectionRole: return transfer->direction(); case StateRole: return transfer->state(); case ErrorRole: return transfer->error(); } return QVariant(); } QVariant TransferModel::headerData(int section, Qt::Orientation orientation, int role) const { if(orientation != Qt::Horizontal || role != Qt::DisplayRole) { return QAbstractTableModel::headerData(section, orientation, role); } switch(section) { case DeviceNameColumn: return tr("Device Name"); case ProgressColumn: return tr("Progress"); case StateColumn: return tr("Status"); case ActionColumn: return tr("Action"); } return QVariant(); } QHash TransferModel::roleNames() const { return { {DeviceNameRole, "device_name"}, {ProgressRole, "progress"}, {DirectionRole, "direction"}, {StateRole, "state"}, {ErrorRole, "error"} }; } int TransferModel::combinedProgress() const { // If we're still within 200ms of the last call, return the cached value qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch(); if(d->cachedProgressAge + 200 > currentMSecs) { return d->cachedProgress; } // Sum the progress of all transfers in progress int progress = 0; int progressCount = 0; for(QList::const_iterator i = d->transfers.constBegin(); i != d->transfers.constEnd(); ++i) { if((*i)->state() == InProgress) { progress += (*i)->progress(); progressCount++; } } if(progressCount) { progress /= progressCount; } // Store the value for next time d->cachedProgressAge = currentMSecs; return d->cachedProgress = progress; } void TransferModel::addReceiver(qintptr socketDescriptor) { d->add(new TransferReceiver(socketDescriptor)); } void TransferModel::addSender(const QString &deviceName, const QHostAddress &address, quint16 port, const Bundle *bundle) { d->add(new TransferSender(deviceName, address, port, bundle)); } void TransferModel::cancel(int index) { if(index < 0 || index >= d->transfers.count()) { qWarning("Invalid index supplied."); return; } d->transfers.at(index)->cancel(); } void TransferModel::restart(int index) { if(index < 0 || index >= d->transfers.count()) { qWarning("Invalid index supplied."); return; } d->transfers.at(index)->restart(); } void TransferModel::dismiss(int index) { if(index < 0 || index >= d->transfers.count()) { qWarning("Invalid index supplied."); return; } // Retrieve the transfer and ensure it is not in progress Transfer *transfer = d->transfers.at(index); if(transfer->state() == TransferModel::Connecting || transfer->state() == TransferModel::InProgress) { qWarning("Cannot dismiss a transfer that is currently in progress."); return; } d->remove(transfer); } void TransferModel::clear() { // Iterate over the list in reverse to preserve indices when items are removed for(int i = d->transfers.count() - 1; i >= 0; --i) { Transfer *transfer = d->transfers.at(i); // Remove only items that are finished if(transfer->state() == Failed || transfer->state() == Succeeded) { d->remove(transfer); } } } nitroshare-0.3.1/src/util/platform.h000664 001750 001750 00000010652 12653764154 020241 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #ifndef NS_PLATFORM_H #define NS_PLATFORM_H #include /** * @brief Platform information methods * * Some of the application functionality depends on platform-specific code. * Rather than depending on #define statements throughout the source code, * this class provides methods that can be invoked during runtime to determine * information about the current platform. * * It is important to note that the information provided by the first two * methods is determined during compile-time. Therefore, running an x86 build * of the application on 64-bit Windows will still cause currentArchitecture() * to indicate x86. */ class Platform { public: /** * @brief Operating system definitions */ enum class OperatingSystem : int { Unknown = 0, Windows, OSX, Linux }; /** * @brief CPU architecture definitions */ enum class Architecture : int { Unknown = 0, x86, x64 }; /** * @brief Linux desktop environment * * This is needed in order to determine the correct class to use for * showing the tray icon. In addition, some environments require special * add-ons to be installed (like Gnome). */ enum class DesktopEnvironment : int { Unknown = 0, Unity, // Ubuntu Gnome, KDE, XFCE, MATE, Cinnamon, // Mint Pantheon // Elementary }; /** * @brief Retrieve the current operating system * @return one of OperatingSystem */ static OperatingSystem currentOperatingSystem(); /** * @brief Retrieve the current CPU architecture * @return one of Architecture */ static Architecture currentArchitecture(); /** * @brief Retrieve the current desktop environment * @return one of DesktopEnvironment */ static DesktopEnvironment currentDesktopEnvironment(); /** * @brief Retrieve the machine-friendly name of an OperatingSystem * @param operatingSystem one of OperatingSystem * @return operating system name * * If operatingSystem is not supplied, the name of the current operating * system is returned. */ static QString operatingSystemName(OperatingSystem operatingSystem = currentOperatingSystem()); /** * @brief Retrieve the human-friendly name of an OperatingSystem * @param operatingSystem one of OperatingSystem * @return operating system friendly name */ static QString operatingSystemFriendlyName(OperatingSystem operatingSystem = currentOperatingSystem()); /** * @brief Retrieve the machine-friendly name of an Architecture * @param architecture one of Architecture * @return architecture name */ static QString architectureName(Architecture architecture = currentArchitecture()); /** * @brief Retrieve the corresponding OperatingSystem for a name * @param name operating system name * @return one of OperatingSystem */ static OperatingSystem operatingSystemForName(const QString &name); /** * @brief Determine if the current platform is Unity * @return true if running under Unity * * This method determines the current desktop environment during runtime. */ static bool useIndicator(); }; #endif // NS_PLATFORM_H nitroshare-0.3.1/src/icon/indicatoricon.cpp000664 001750 001750 00000005363 12653764154 021553 0ustar00nathannathan000000 000000 /** * The MIT License (MIT) * * Copyright (c) 2015 Nathan Osman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. **/ #include #include #include "indicatoricon.h" // Assumes 'data' is a QAction * and triggers it void triggerQAction(GtkMenu *, gpointer data) { reinterpret_cast(data)->trigger(); } IndicatorIcon::IndicatorIcon() : mIndicator(app_indicator_new("nitroshare", "nitroshare-indicator", APP_INDICATOR_CATEGORY_APPLICATION_STATUS)), mMenu(gtk_menu_new()) { notify_init("nitroshare"); app_indicator_set_menu(mIndicator, GTK_MENU(mMenu)); app_indicator_set_status(mIndicator, APP_INDICATOR_STATUS_ACTIVE); } IndicatorIcon::~IndicatorIcon() { notify_uninit(); g_object_unref(G_OBJECT(mIndicator)); } void IndicatorIcon::addAction(const QString &text, QObject *receiver, const char *member) { GtkWidget *menuItem = gtk_menu_item_new_with_label(text.toUtf8().constData()); QAction *action = new QAction(text, this); connect(action, SIGNAL(triggered()), receiver, member); g_signal_connect(menuItem, "activate", G_CALLBACK(triggerQAction), action); gtk_widget_show(menuItem); gtk_menu_shell_append(GTK_MENU_SHELL(mMenu), menuItem); } void IndicatorIcon::addSeparator() { GtkWidget *separator = gtk_separator_menu_item_new(); gtk_widget_show(separator); gtk_menu_shell_append(GTK_MENU_SHELL(mMenu), separator); } void IndicatorIcon::showMessage(const QString &message) { NotifyNotification *notification = notify_notification_new( "NitroShare Notification", message.toUtf8().constData(), "nitroshare-indicator" ); notify_notification_show(notification, nullptr); g_object_unref(G_OBJECT(notification)); }