/******************************************************************************* * retroshare-gui/src/: main.cpp * * * * libretroshare: retroshare core library * * * * Copyright 2006 by Crypton * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Affero General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Affero General Public License for more details. * * * * You should have received a copy of the GNU Affero General Public License * * along with this program. If not, see . * * * *******************************************************************************/ #include "util/stacktrace.h" #include "util/argstream.h" #include "retroshare/rswebui.h" CrashStackTrace gCrashStackTrace; #include #include #include #include #include #include #include #include #include "gui/common/FilesDefs.h" #include "gui/FriendsDialog.h" #include "gui/GenCertDialog.h" #include "gui/MainWindow.h" #include "gui/NetworkDialog.h" #include "gui/NetworkView.h" #include "gui/QuickStartWizard.h" #include "gui/RetroShareLink.h" #include "gui/SoundManager.h" #include "gui/StartDialog.h" #include "gui/chat/ChatDialog.h" #include "gui/connect/ConfCertDialog.h" #include "gui/common/AvatarDialog.h" #include "gui/common/Emoticons.h" #include "gui/FileTransfer/SearchDialog.h" #include "gui/FileTransfer/TransfersDialog.h" #include "gui/settings/RsharePeerSettings.h" #include "gui/settings/rsharesettings.h" #include "idle/idle.h" #include "lang/languagesupport.h" #include "util/RsGxsUpdateBroadcast.h" #include "util/rsdir.h" #include "util/rstime.h" #include "retroshare/rsinit.h" #ifdef MESSENGER_WINDOW #include "gui/MessengerWindow.h" #endif #ifdef RS_WEBUI # include "gui/settings/WebuiPage.h" #endif #ifdef RS_JSONAPI # include "gui/settings/JsonApiPage.h" #endif // RS_JSONAPI #include "retroshare/rstor.h" #include "TorControl/TorControlWindow.h" #include "retroshare/rsidentity.h" #include "retroshare/rspeers.h" #ifdef SIGFPE_DEBUG #include #endif #if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0) #ifdef WINDOWS_SYS #include #endif #endif #ifdef Q_OS_WIN #if QT_VERSION >= QT_VERSION_CHECK (5, 7, 0) // see INSTALL.W32 in openssl // Needed as workaround for gcc 5.3.0 because the call to GetProcAddress in cryptlib.c finds an function pointer // to the not existing function _OPENSSL_isservice in the executable running on Windows 7. extern "C" { __declspec(dllexport) __cdecl BOOL _OPENSSL_isservice(void) { DWORD sess; if (ProcessIdToSessionId(GetCurrentProcessId(),&sess)) return sess==0; return FALSE; } } #endif #endif #include #include #include #include "gui/notifyqt.h" #include static void showHelp(const argstream& as) { RsInfo() << "\n" << "+================================================================+\n" "| o---o o |\n" "| \\ / - Retroshare GUI - / \\ |\n" "| o o---o |\n" "+================================================================+" << std::endl ; std::cerr << as.usage(false) << std::endl; char *argv[1]; int argc=0; QApplication dummyApp (argc, argv); // needed for QMessageBox QMessageBox box; QString text = QString::fromUtf8(as.usage(false,false).c_str()); QFont font("Courier New",10,50,false); font.setStyleHint(QFont::TypeWriter,QFont::PreferMatch); font.setStyle(QFont::StyleNormal); font.setBold(true); box.setFont(font); box.setInformativeText(text); box.setWindowTitle(QObject::tr("Retroshare commandline arguments")); // now compute the size of text and set the size of the box. For the record, this doesn't work... box.setBaseSize( QSize(QFontMetricsF(font).width(text),QFontMetricsF(font).height()*text.count('\n')) ); box.exec(); } static bool notifyRunningInstance() { // Connect to the Local Server of the main process to notify it // that a new process had been started RsInfo() << "Trying to contact running instance through socket \"" << TARGET << "\""; QLocalSocket localSocket; localSocket.connectToServer(QString(TARGET)); #ifdef DEBUG std::cerr << "RsApplication::RsApplication waitForConnected to other instance." << std::endl; #endif if( localSocket.waitForConnected(100) ) { #ifdef DEBUG std::cerr << "RsApplication::RsApplication Connection etablished. Waiting for disconnection." << std::endl; #endif localSocket.waitForDisconnected(1000); return true; } else { #ifdef DEBUG std::cerr << "RsApplication::RsApplication failed to connect to other instance." << std::endl; #endif return false; } } static void sendArgsToRunningInstance(const QStringList& args) { QString serverName = QString(TARGET); // load into shared memory QBuffer buffer; buffer.open(QBuffer::ReadWrite); QDataStream out(&buffer); out << args; int size = buffer.size(); QSharedMemory newArgs; newArgs.setKey(serverName + "_newArgs"); if (newArgs.isAttached()) newArgs.detach(); if (!newArgs.create(size)) { std::cerr << "(EE) RsApplication::RsApplication Unable to create shared memory segment of size:" << size << " error:" << newArgs.errorString().toStdString() << "." << std::endl; #ifdef Q_OS_UNIX std::cerr << "Look with `ipcs -m` for nattch==0 segment. And remove it with `ipcrm -m 'shmid'`." << std::endl; //No need for windows, as it removes shared segment directly even when crash. #endif newArgs.detach(); ::exit(EXIT_FAILURE); } newArgs.lock(); char *to = (char*)newArgs.data(); const char *from = buffer.data().data(); memcpy(to, from, qMin(newArgs.size(), size)); newArgs.unlock(); std::cerr << "RsApplication::RsApplication waitForConnected to other instance." << std::endl; if(notifyRunningInstance()) { newArgs.detach(); std::cerr << "RsApplication::RsApplication Arguments was sended." << std::endl << " To disable it, in Options - General - Misc," << std::endl << " uncheck \"Use Local Server to get new Arguments\"." << std::endl; ::exit(EXIT_SUCCESS); // Terminate the program using STDLib's exit function } else std::cerr << "RsApplication::RsApplication failed to connect to other instance." << std::endl; newArgs.detach(); } static bool setLanguage(const std::string& language) { if(!language.empty()) { if(!LanguageSupport::translate(QString::fromStdString(language))) { RsErr() << "Language \"" << language << "\" is not supported." ; QString s; for(QString ss:LanguageSupport::languageCodes()) s += ss + ", " ; RsErr() << "Possible choices are: " << s.toStdString(); return false; } return true; } else { LanguageSupport::translate(LanguageSupport::defaultLanguageCode()); return true; } } static void displayWarningAboutDSAKeys() { std::map > unsupported_keys; RsAccounts::GetUnsupportedKeys(unsupported_keys); if(unsupported_keys.empty()) return ; QMessageBox msgBox; QString txt = QObject::tr("You appear to have nodes associated to DSA keys:"); txt += "
    " ; for(std::map >::const_iterator it(unsupported_keys.begin());it!=unsupported_keys.end();++it) { txt += "
  • " + QString::fromStdString(it->first) ; txt += "
      " ; for(uint32_t i=0;isecond.size();++i) txt += "
    • " + QString::fromStdString(it->second[i]) + "
    • " ; txt += "
    " ; txt += "
  • " ; } txt += "
" ; msgBox.setText(txt) ; msgBox.setInformativeText(QObject::tr("DSA keys are not yet supported by this version of RetroShare. All these nodes will be unusable. We're very sorry for that.")); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setWindowIcon(FilesDefs::getIconFromQtResourcePath(":/icons/logo_128.png")); msgBox.exec(); } #ifdef WINDOWS_SYS #if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0) && QT_VERSION < QT_VERSION_CHECK (5, 3, 0) QStringList filedialog_open_filenames_hook(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options | QFileDialog::DontUseNativeDialog); } QString filedialog_open_filename_hook(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options | QFileDialog::DontUseNativeDialog); } QString filedialog_save_filename_hook(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { return QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options | QFileDialog::DontUseNativeDialog); } QString filedialog_existing_directory_hook(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options) { return QFileDialog::getExistingDirectory(parent, caption, dir, options | QFileDialog::DontUseNativeDialog); } #endif #endif int main(int argc, char *argv[]) { #ifdef WINDOWS_SYS // The current directory of the application is changed when using the native dialog on Windows // This is a quick fix until libretroshare is using a absolute path in the portable Version #if QT_VERSION >= QT_VERSION_CHECK (5, 3, 0) // Do we need a solution in v0.6? #endif #if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0) && QT_VERSION < QT_VERSION_CHECK (5, 3, 0) typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); typedef QString (*_qt_filedialog_open_filename_hook) (QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); typedef QString (*_qt_filedialog_save_filename_hook) (QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options); extern Q_GUI_EXPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook; extern Q_GUI_EXPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook; extern Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook; extern Q_GUI_EXPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook; qt_filedialog_open_filename_hook = filedialog_open_filename_hook; qt_filedialog_open_filenames_hook = filedialog_open_filenames_hook; qt_filedialog_save_filename_hook = filedialog_save_filename_hook; qt_filedialog_existing_directory_hook = filedialog_existing_directory_hook; #endif #if QT_VERSION < QT_VERSION_CHECK (5, 0, 0) extern bool Q_GUI_EXPORT qt_use_native_dialogs; qt_use_native_dialogs = false; #endif { /* Set the current directory to the application dir, because the start dir with autostart from the registry run key is not the exe dir */ QApplication app(argc, argv); QDir::setCurrent(QCoreApplication::applicationDirPath()); } #endif #ifdef SIGFPE_DEBUG feenableexcept(FE_INVALID | FE_DIVBYZERO); #endif QStringList args = char_array_to_stringlist(argv+1, argc-1); Q_INIT_RESOURCE(images); Q_INIT_RESOURCE(icons); // This is needed to allocate rsNotify, so that it can be used to ask for PGP passphrase // RsControl::earlyInitNotificationSystem() ; NotifyQt *notify = NotifyQt::Create(); rsNotify->registerNotifyClient(notify); /* RetroShare Core Objects */ RsInit::InitRsConfig(); RsGUIConfigOptions conf; std::string rslink,rsfile; std::list links_and_files; std::string loglevel="off"; std::string logfilename,language,guistyle,guistylesheetfile; argstream as(argc,argv); as >> option( 's',"stderr" ,conf.outStderr ,"output to stderr instead of log file " ) >> option( 'u',"udp" ,conf.udpListenerOnly ,"Only listen to UDP " ) >> option( 'R',"reset" ,conf.optResetParams ,"reset retroshare parameters " ) >> parameter('c',"base-dir" ,conf.optBaseDir ,"directory" ,"Set base directory " ,false) >> parameter('l',"log-file" ,logfilename ,"logfile" ,"Set Log filename " ,false) >> parameter('d',"debug-level" ,loglevel ,"level (debug,info,notice,warn,error,off)","Set debug level " ,false) >> parameter('i',"ip-address" ,conf.forcedInetAddress ,"nnn.nnn.nnn.nnn" ,"Force IP address " ,false) >> parameter('p',"port" ,conf.forcedPort ,"port" ,"Set listenning port " ,false) >> parameter('o',"opmode" ,conf.opModeStr ,"opmode (Full, NoTurtle, Gaming, Minimal)","Set mode" ,false) >> parameter('t',"tor" ,conf.userSuppliedTorExecutable,"path" ,"supply full tor executable path " ,false) >> parameter('g',"style" ,guistyle ,"style (fusion,windows,gtk2,breeze)" ,"set GUI style" ,false) >> parameter('k',"style" ,guistylesheetfile ,"file" ,"gui stylesheet file" ,false) >> parameter('L',"lang" ,language ,"langage (fr,cn,...)" ,"set language" ,false) >> parameter('r',"link" ,rslink ,"retroshare link" ,"retroshare link to open (passed to running server)" ,false) >> parameter('f',"rsfile" ,rsfile ,"rsfile" ,"rscollection file to open (passed to running server)" ,false); #ifdef RS_JSONAPI as >> parameter('J', "jsonApiPort" ,conf.jsonApiPort ,"jsonApiPort" ,"Enable JSON API on the specified port" ,false) >> parameter('P', "jsonApiBindAddress",conf.jsonApiBindAddress ,"jsonApiBindAddress" ,"JSON API Bind Address " ,false); #endif // ifdef RS_JSONAPI #ifdef LOCALNET_TESTING as >> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction " ,false); #endif // ifdef LOCALNET_TESTING #ifdef RS_AUTOLOGIN as >> option('a',"auto-login" ,conf.autoLogin ,"AutoLogin (Windows Only) + StartMinimised"); #endif // ifdef RS_AUTOLOGIN as >> values(std::back_inserter(links_and_files),"links and rscollection files") >> help('h',"help",QObject::tr("Display this help").toStdString().c_str()); if(!as.isOk()) { std::cerr << "Incorrect arguments." << std::endl; std::cerr << as.usage() << std::endl; return 0; } conf.logFileName = QString::fromStdString(logfilename); conf.logLevel = QString::fromStdString(loglevel); // these will be checked when used in RsApplication conf.guiStyle = QString::fromStdString(guistyle); // these will be checked when used in RsApplication conf.guiStyleSheetFile = QString::fromUtf8(guistylesheetfile.c_str());// these will be checked when used in RsApplication if(as.helpRequested()) { showHelp(as); return 0; } // Look for parameters to be transmitted to running server if((!rslink.empty() || !rsfile.empty() || !links_and_files.empty() || !conf.opModeStr.empty()) && notifyRunningInstance()) { QStringList args; RsErr() << "Sending rscollection files, retroshare links and opmode parameters to the runnning retroshare server." ; if(!rslink.empty()) { args.push_back("-l"); args.push_back(QString::fromUtf8(rslink.c_str())); } if(!rsfile.empty()) { args.push_back("-f"); args.push_back(QString::fromUtf8(rsfile.c_str())); } for(auto s:links_and_files) args.push_back(QString::fromUtf8(s.c_str())); if(!conf.opModeStr.empty()) { args.push_back("-o"); args.push_back(QString::fromStdString(conf.opModeStr)); } sendArgsToRunningInstance(args); return 0; } // Now start RS login system conf.main_executable_path = argv[0]; int initResult = RsInit::InitRetroShare(conf); if(initResult == RS_INIT_NO_KEYRING) // happens when we already have accounts, but no pgp key. This is when switching to the openpgp-sdk version. { QApplication dummyApp (argc, argv); // needed for QMessageBox /* Translate into the desired language */ if(!setLanguage(language)) return 1; QMessageBox msgBox; msgBox.setText(QObject::tr("This version of RetroShare is using OpenPGP-SDK. As a side effect, it's not using the system shared PGP keyring, but has it's own keyring shared by all RetroShare instances.

You do not appear to have such a keyring, although PGP keys are mentioned by existing RetroShare accounts, probably because you just changed to this new version of the software.")); msgBox.setInformativeText(QObject::tr("Choose between:
  • Ok to copy the existing keyring from gnupg (safest bet), or
  • Close without saving to start fresh with an empty keyring (you will be asked to create a new PGP key to work with RetroShare, or import a previously saved pgp keypair).
  • Cancel to quit and forge a keyring by yourself (needs some PGP skills)
")); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setWindowIcon(FilesDefs::getIconFromQtResourcePath(":/icons/logo_128.png")); int ret = msgBox.exec(); if(ret == QMessageBox::Cancel) return 0 ; if(ret == QMessageBox::Ok) { if(!RsAccounts::CopyGnuPGKeyrings()) return 0 ; initResult = RsInit::InitRetroShare(conf); displayWarningAboutDSAKeys() ; } else initResult = RS_INIT_OK ; } if (initResult < 0) { /* Error occured */ QApplication dummyApp (argc, argv); // needed for QMessageBox /* Translate into the desired language */ if(!setLanguage(language)) return 1; displayWarningAboutDSAKeys(); QMessageBox mb(QMessageBox::Critical, QObject::tr("RetroShare"), "", QMessageBox::Ok); mb.setWindowIcon(FilesDefs::getIconFromQtResourcePath(":/icons/logo_128.png")); switch (initResult) { case RS_INIT_AUTH_FAILED: std::cerr << "RsInit::InitRetroShare AuthGPG::InitAuth failed" << std::endl; mb.setText(QObject::tr("Initialization failed. Wrong or missing installation of PGP.")); break; default: /* Unexpected return code */ std::cerr << "RsInit::InitRetroShare unexpected return code " << initResult << std::endl; mb.setText(QObject::tr("An unexpected error occurred. Please report 'RsInit::InitRetroShare unexpected return code %1'.").arg(initResult)); break; } mb.exec(); return 1; } /* create global settings object path maybe wrong, when no profile exist in this case it can be use only for default values */ RshareSettings::Create (); if(LanguageSupport::isValidLanguageCode(QString::fromStdString(language))) conf.language = QString::fromStdString(language); /* Setup The GUI Stuff */ //Rshare rshare(args, argc, argv, QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); RsApplication rshare(conf); if(!setLanguage(language)) return 1; /* Start RetroShare */ QString sDefaultGXSIdToCreate = ""; switch (initResult) { case RS_INIT_OK: { /* Login Dialog */ /* check for existing Certificate */ bool genCert = false; std::list accountIds; if (RsAccounts::GetAccountIds(accountIds) && (accountIds.size() > 0)) { StartDialog sd; if (sd.exec() == QDialog::Rejected) { return 1; } /* if we're logged in */ genCert = sd.requestedNewCert(); } else { genCert = true; } if (genCert) { GenCertDialog gd(false); if (gd.exec () == QDialog::Rejected) return 1; sDefaultGXSIdToCreate = gd.getGXSNickname(); } //splashScreen.show(); } break; case RS_INIT_HAVE_ACCOUNT: { //splashScreen.show(); //splashScreen.showMessage(rshare.translate("SplashScreen", "Load profile"), Qt::AlignHCenter | Qt::AlignBottom); RsPeerId preferredId; RsAccounts::GetPreferredAccountId(preferredId); // true: note auto-login is active if(!RsApplication::loadCertificate(preferredId, true)) { RsErr() << "Retroshare auto-login startup failed." ; return 1; } } break; default: /* Unexpected return code */ std::cerr << "RsInit::InitRetroShare unexpected return code " << initResult << std::endl; QMessageBox::warning(0, QObject::tr("RetroShare"), QObject::tr("An unexpected error occured. Please report 'RsInit::InitRetroShare unexpected return code %1'.").arg(initResult)); return 1; } /* recreate global settings object, now with correct path, specific to the selected node */ RshareSettings::Create(true); RsApplication::resetLanguageAndStyle(); SoundManager::create(); bool is_hidden_node = false; bool is_auto_tor = false ; bool is_first_time = false ; RsAccounts::getCurrentAccountOptions(is_hidden_node,is_auto_tor,is_first_time); if(is_auto_tor) { if(!conf.userSuppliedTorExecutable.empty()) RsTor::setTorExecutablePath(conf.userSuppliedTorExecutable); // Now that we know the Tor service running, and we know the SSL id, we can make sure it provides a viable hidden service std::string tor_hidden_service_dir = RsAccounts::AccountDirectory() + "/hidden_service/" ; RsTor::setTorDataDirectory(RsApplication::dataDirectory().toStdString() + "/tor/"); RsTor::setHiddenServiceDirectory(tor_hidden_service_dir); // re-set it, because now it's changed to the specific location that is run RsDirUtil::checkCreateDirectory(std::string(tor_hidden_service_dir)) ; //RsTor::setupHiddenService(); if(! RsTor::start() || RsTor::hasError()) { QMessageBox::critical(NULL,QObject::tr("Cannot start Tor Manager!"),QObject::tr("Tor cannot be started on your system: \n\n")+QString::fromStdString(RsTor::errorMessage())) ; return 1 ; } { TorControlDialog tcd; QString error_msg ; tcd.show(); while(tcd.checkForTor(error_msg) != TorControlDialog::TOR_STATUS_OK || tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) // runs until some status is reached: either tor works, or it fails. { QCoreApplication::processEvents(); rstime::rs_usleep(0.2*1000*1000) ; if(!error_msg.isNull()) { QMessageBox::critical(NULL,QObject::tr("Cannot start Tor"),QObject::tr("Sorry but Tor cannot be started on your system!\n\nThe error reported is:\"")+error_msg+"\"") ; return 1; } } tcd.hide(); if(tcd.checkForHiddenService() != TorControlDialog::HIDDEN_SERVICE_STATUS_OK) { QMessageBox::critical(NULL,QObject::tr("Cannot start a hidden tor service!"),QObject::tr("It was not possible to start a hidden service.")) ; return 1 ; } } } QSplashScreen splashScreen(FilesDefs::getPixmapFromQtResourcePath(":/images/logo/logo_splash.png")/* , Qt::WindowStaysOnTopHint*/); splashScreen.show(); splashScreen.showMessage(rshare.translate("SplashScreen", "Load configuration"), Qt::AlignHCenter | Qt::AlignBottom); QCoreApplication::processEvents(); /* stop Retroshare if startup fails */ if (!RsControl::instance()->StartupRetroShare()) { std::cerr << "libretroshare failed to startup!" << std::endl; return 1; } if(is_auto_tor) { // Tor works with viable hidden service. Let's use it! std::string service_id ; std::string onion_address ; uint16_t service_port ; uint16_t service_target_port ; uint16_t proxy_server_port ; std::string service_target_address ; std::string proxy_server_address ; RsTor::getHiddenServiceInfo(service_id,onion_address,service_port,service_target_address,service_target_port); RsTor::getProxyServerInfo(proxy_server_address,proxy_server_port) ; std::cerr << "Got hidden service info: " << std::endl; std::cerr << " onion address : " << onion_address << std::endl; std::cerr << " service_id : " << service_id << std::endl; std::cerr << " service port : " << service_port << std::endl; std::cerr << " target port : " << service_target_port << std::endl; std::cerr << " target address : " << service_target_address << std::endl; std::cerr << "Setting proxy server to " << service_target_address << ":" << service_target_port << std::endl; rsPeers->setLocalAddress(rsPeers->getOwnId(), service_target_address, service_target_port); rsPeers->setHiddenNode(rsPeers->getOwnId(), onion_address, service_port); rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, proxy_server_address,proxy_server_port) ; } RsApplication::initPlugins(); splashScreen.showMessage(rshare.translate("SplashScreen", "Create interface"), Qt::AlignHCenter | Qt::AlignBottom); QCoreApplication::processEvents(); // forces splashscreen to show up RsharePeerSettings::Create(); Emoticons::load(); AvatarDialog::load(); if (Settings->value(QString::fromUtf8("FirstRun"), true).toBool()) { splashScreen.hide(); Settings->setValue(QString::fromUtf8("FirstRun"), false); SoundManager::initDefault(); #ifdef __APPLE__ /* For OSX, we set the default to "cleanlooks", as the AQUA style hides some input boxes * only on the first run - as the user might want to change it ;) */ QString osx_style("cleanlooks"); RsApplication::setStyle(osx_style); Settings->setInterfaceStyle(osx_style); #endif // This is now disabled - as it doesn't add very much. // Need to make sure that defaults are sensible! #ifdef ENABLE_QUICKSTART_WIZARD QuickStartWizard qstartWizard; qstartWizard.exec(); #endif } MainWindow *w = MainWindow::Create (); splashScreen.finish(w); if (!sDefaultGXSIdToCreate.isEmpty()) { RsIdentityParameters params; params.nickname = sDefaultGXSIdToCreate.toUtf8().constData(); params.isPgpLinked = true; params.mImage.clear(); uint32_t token = 0; rsIdentity->createIdentity(token, params); } // I'm using a signal to transfer the hashing info to the mainwindow, because Qt schedules signals properly to // avoid clashes between infos from threads. // qRegisterMetaType("RsPeerId") ; #ifdef DEBUG std::cerr << "connecting signals and slots" << std::endl ; #endif QObject::connect(notify,SIGNAL(deferredSignatureHandlingRequested()),notify,SLOT(handleSignatureEvent()),Qt::QueuedConnection) ; QObject::connect(notify,SIGNAL(chatLobbyTimeShift(int)),notify,SLOT(handleChatLobbyTimeShift(int)),Qt::QueuedConnection) ; QObject::connect(notify,SIGNAL(diskFull(int,int)) ,w ,SLOT(displayDiskSpaceWarning(int,int))) ; QObject::connect(notify,SIGNAL(filesPostModChanged(bool)) ,w ,SLOT(postModDirectories(bool)) ,Qt::QueuedConnection ) ; QObject::connect(notify,SIGNAL(transfersChanged()) ,w->transfersDialog ,SLOT(insertTransfers() )) ; QObject::connect(notify,SIGNAL(publicChatChanged(int)) ,w->friendsDialog ,SLOT(publicChatChanged(int) )); QObject::connect(notify,SIGNAL(neighboursChanged()) ,w->friendsDialog->networkDialog ,SLOT(securedUpdateDisplay())) ; QObject::connect(notify,SIGNAL(chatStatusChanged(const QString&,const QString&,bool)),w->friendsDialog,SLOT(updatePeerStatusString(const QString&,const QString&,bool))); QObject::connect(notify,SIGNAL(ownStatusMessageChanged()),w->friendsDialog,SLOT(loadmypersonalstatus())); // QObject::connect(notify,SIGNAL(logInfoChanged(const QString&)) ,w->friendsDialog->networkDialog,SLOT(setLogInfo(QString))) ; QObject::connect(notify,SIGNAL(discInfoChanged()) ,w->friendsDialog->networkView,SLOT(update()),Qt::QueuedConnection) ; QObject::connect(notify,SIGNAL(errorOccurred(int,int,const QString&)),w,SLOT(displayErrorMessage(int,int,const QString&))) ; w->installGroupChatNotifier(); /* only show window, if not startMinimized */ if (RsInit::getStartMinimised() || Settings->getStartMinimized()) { splashScreen.close(); } else { w->show(); } /* Startup a Timer to keep the gui's updated */ QTimer *timer = new QTimer(w); timer -> connect(timer, SIGNAL(timeout()), notify, SLOT(UpdateGUI())); timer->start(1000); notify->enable() ; // enable notification system after GUI creation, to avoid data races in Qt. // Read webui params in settings. We cannot save them to some webui.cfg because cfg needs the node id and // jsonapi is started before node ID selection in retroshare-service. #ifdef RS_JSONAPI #ifdef RS_WEBUI conf.enableWebUI = Settings->getWebinterfaceEnabled(); if(!Settings->getWebinterfaceFilesDirectory().isNull()) rsWebUi->setHtmlFilesDirectory(Settings->getWebinterfaceFilesDirectory().toStdString()); #endif RsInit::startupWebServices(conf,false); #endif /* dive into the endless loop */ int ti = rshare.exec(); delete w ; #ifdef RS_JSONAPI JsonApiPage::checkShutdownJsonApi(); #endif // RS_JSONAPI /* cleanup */ ChatDialog::cleanupChat(); #ifdef RS_ENABLE_GXS RsGxsUpdateBroadcast::cleanup(); #endif if (is_auto_tor) { RsTor::stop(); } RsControl::instance()->rsGlobalShutDown(); delete(soundManager); soundManager = NULL; Settings->sync(); delete(Settings); return ti ; }