diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index d92ea17ce..8669f307d 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1,5 +1,40 @@ retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low + 0dc43c3 csoler Sat, 23 Apr 2016 08:29:53 -0400 Merge pull request #338 from Nyfor/master + 5e94c77 Nyfor Mon, 4 Apr 2016 12:07:09 +0200 Fixed compilation for Clang. + d696f72 csoler Fri, 22 Apr 2016 20:38:07 -0400 fixed compilation + acd059b csoler Fri, 22 Apr 2016 18:49:42 -0400 removed potential memory leak in TransfersDialog + 52cf66a csoler Fri, 22 Apr 2016 17:55:15 -0400 fixed memory leak in SubscribeToolButton menu + 55e8087 csoler Fri, 22 Apr 2016 17:30:55 -0400 added missing free for public keys used in envelop encryption + 10230df csoler Fri, 22 Apr 2016 16:50:43 -0400 added missing SSL shutdown when replacing existing connection + 5261c3c csoler Thu, 21 Apr 2016 22:23:07 -0400 prevented turtle to not deleting a config item when it is not cast + e9fa9eb csoler Thu, 21 Apr 2016 22:07:50 -0400 removed tricky memory leak in chat lobbies due to handling of partial messages + 7aea6e5 csoler Thu, 21 Apr 2016 22:07:10 -0400 removed some debug info + eca83fd csoler Thu, 21 Apr 2016 19:54:50 -0400 removed some debug info + fba3d37 csoler Thu, 21 Apr 2016 19:47:34 -0400 fixed memory leak after receiving RsNxsItem deserialised from decrypted memory + 0d3ff0e csoler Thu, 21 Apr 2016 19:46:47 -0400 fixed possible uninitialised memory read in memory decryption return + 0c711a4 csoler Thu, 21 Apr 2016 19:41:21 -0400 added missing calls to EVP_CIPHER_CTX_cleanup() to release memory after decryption, causing memory + 3fae108 csoler Thu, 21 Apr 2016 12:58:48 -0400 removed div by zero in transfers dialog + 0572492 csoler Wed, 20 Apr 2016 21:20:47 -0400 severely reduced packet grouping, which limited the effectiveness of QoS + d6ae71e csoler Wed, 20 Apr 2016 20:21:29 -0400 removed pointer to QStringList in QHash, causing memory loss + aba3d2f csoler Wed, 20 Apr 2016 18:24:02 -0400 removed memory leak due to zeroing (on purpose!) a data chunk in GRouter before deleting it + d017771 csoler Wed, 20 Apr 2016 18:08:26 -0400 fixed missing sendTime in distant chat, causing inconsistent display in GUI + 80a9fec csoler Tue, 19 Apr 2016 22:18:25 -0400 Merge pull request #353 from crhode/master + 39553a6 csoler Tue, 19 Apr 2016 21:58:30 -0400 removed debug info + 5645e44 Manuel Davis Tue, 19 Apr 2016 11:32:56 -0500 Change regular expression(s) for identifying hotlinks in feral text. + 8be53dd Manuel Davis Tue, 19 Apr 2016 11:11:58 -0500 Improve inserting placemark in ChatLobby. + 26af7c9 csoler Sun, 17 Apr 2016 22:58:48 -0400 changed heart beat limit to a larger value. Apparently too tight a value causes disconnections due + c14c240 csoler Sun, 17 Apr 2016 00:51:45 -0400 fixed update of circles GUI using a timer. This is not optimal, and should be replaced by a proper + 3000f94 csoler Sat, 16 Apr 2016 22:44:06 -0400 separated subscribe status from wether we are part of a circle or not. Still needs update of GUI + b861aa9 csoler Sat, 16 Apr 2016 17:10:36 -0400 Merge pull request #352 from AsamK/trailing_semicolon + e7ec204 AsamK Sat, 16 Apr 2016 20:40:24 +0200 Add trailing semi-colon to MimeType in .desktop files + fa8a585 csoler Fri, 15 Apr 2016 18:25:53 -0400 removed some debug info + d642934 csoler Fri, 15 Apr 2016 18:25:41 -0400 increased frequency of update for banned PGP nodes + + -- Cyril Soler Sun, 24 Apr 2016 12:00:00 -0500 + +retroshare06 (0.6.0-1.20160415.26574fd9~trusty) trusty; urgency=low + 2552b55 defnax Fri, 15 Apr 2016 20:32:00 +0200 Merge branch 'master' of https://github.com/RetroShare/RetroShare 85942f4 defnax Fri, 15 Apr 2016 20:30:32 +0200 improving the create circle layout cb6c2c9 csoler Thu, 14 Apr 2016 23:49:55 -0400 Merge pull request #350 from csoler/v0.6-Circles diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index 03acb6ff8..805728905 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -264,9 +264,12 @@ bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id, RsChatMsgItem *item = new RsChatMsgItem; item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; item->chatFlags = RS_CHAT_FLAG_PRIVATE ; + item->sendTime = time(NULL) ; item->PeerId(RsPeerId(tunnel_id)) ; handleRecvChatMsgItem(item) ; + delete item ; // item is replaced by NULL if partial, but this is not the case here. + return true ; } diff --git a/libretroshare/src/chat/distantchat.h b/libretroshare/src/chat/distantchat.h index 5dc21e1d6..444817c06 100644 --- a/libretroshare/src/chat/distantchat.h +++ b/libretroshare/src/chat/distantchat.h @@ -63,7 +63,7 @@ public: // derived in p3ChatService, so as to pass down some info virtual void handleIncomingItem(RsItem *) = 0; - virtual bool handleRecvChatMsgItem(RsChatMsgItem *ci)=0 ; + virtual bool handleRecvChatMsgItem(RsChatMsgItem *& ci)=0 ; bool handleOutgoingItem(RsChatItem *) ; bool handleRecvItem(RsChatItem *) ; diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index f77fb3718..88460f1f7 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -424,11 +424,6 @@ void DistributedChatService::checkSizeAndSendLobbyMessage(RsChatItem *msg) sendChatItem(msg) ; } -bool DistributedChatService::locked_checkAndRebuildPartialLobbyMessage(RsChatLobbyMsgItem *ci) -{ - return true ; -} - bool DistributedChatService::handleRecvItem(RsChatItem *item) { switch(item->PacketSubType()) diff --git a/libretroshare/src/chat/distributedchat.h b/libretroshare/src/chat/distributedchat.h index c311727b1..89160a850 100644 --- a/libretroshare/src/chat/distributedchat.h +++ b/libretroshare/src/chat/distributedchat.h @@ -90,7 +90,6 @@ class DistributedChatService void addToSaveList(std::list& list) const ; bool processLoadListItem(const RsItem *item) ; - bool locked_checkAndRebuildPartialLobbyMessage(RsChatLobbyMsgItem *) ; void checkSizeAndSendLobbyMessage(RsChatItem *) ; bool sendLobbyChat(const ChatLobbyId &lobby_id, const std::string&) ; diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index 3f0c87f3d..bafdb575c 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -428,7 +428,14 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg) return true; } -bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *ci) +// This method might take control over the memory, or modify it, possibly adding missing parts. +// This function looks weird because it cannot duplicate the message since it does not know +// what type of object it is and the duplicate method of lobby messages is reserved for +// ChatLobby bouncing objects. +// +// Returns false if the item shouldn't be used (and replaced to NULL) + +bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *& ci) { // Check is the item is ending an incomplete item. // @@ -445,13 +452,16 @@ bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *ci) ci->message = it->second->message + ci->message ; ci->chatFlags |= it->second->chatFlags ; - + + // always remove existing partial. The compound message is in ci now. + delete it->second ; - - if(!ci_is_incomplete) - _pendingPartialMessages.erase(it) ; + _pendingPartialMessages.erase(it) ; } + // now decide what to do: if ci is incomplete, store it and replace the pointer with NULL + // if complete, return it. + if(ci_is_incomplete) { #ifdef CHAT_DEBUG @@ -459,7 +469,8 @@ bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *ci) #endif // The item is a partial message. Push it, and wait for the rest. // - _pendingPartialMessages[ci->PeerId()] = ci ; + _pendingPartialMessages[ci->PeerId()] = ci ; // cannot use duplicate() here + ci = NULL ; // takes memory ownership over ci return false ; } else @@ -503,8 +514,10 @@ void p3ChatService::handleIncomingItem(RsItem *item) // RsChatMsgItem *ci = dynamic_cast(item) ; if(ci != NULL) - { - if(! handleRecvChatMsgItem(ci)) + { + handleRecvChatMsgItem(ci); + + if(ci) delete ci ; return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only. @@ -665,7 +678,7 @@ bool p3ChatService::checkForMessageSecurity(RsChatMsgItem *ci) return true ; } -bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *ci) +bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *& ci) { time_t now = time(NULL); std::string name; @@ -674,15 +687,8 @@ bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *ci) { RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ - // This crap is because chat lobby messages use a different method for chunking messages using an additional - // subpacket ID, and a list of lobbies. We cannot just collapse the two because it would make the normal chat - // (and chat lobbies) not backward compatible. - - if(!DistributedChatService::locked_checkAndRebuildPartialLobbyMessage(dynamic_cast(ci))) - return true ; - - if(!locked_checkAndRebuildPartialMessage(ci)) - return true ; + if(!locked_checkAndRebuildPartialMessage(ci)) // we make sure this call does not take control over the memory + return true ; // message is a subpart of an existing message. So everything ok, but we need to return. } // Check for security. This avoids bombing messages, and so on. diff --git a/libretroshare/src/chat/p3chatservice.h b/libretroshare/src/chat/p3chatservice.h index 4fc9e1baf..3096309b0 100644 --- a/libretroshare/src/chat/p3chatservice.h +++ b/libretroshare/src/chat/p3chatservice.h @@ -205,7 +205,8 @@ private: void receiveStateString(const RsPeerId& id,const std::string& s) ; /// methods for handling various Chat items. - bool handleRecvChatMsgItem(RsChatMsgItem *item) ; // returns false if the item should be deleted. + virtual bool handleRecvChatMsgItem(RsChatMsgItem *&item) ; // NULL-ifies the item if memory ownership is taken + void handleRecvChatStatusItem(RsChatStatusItem *item) ; void handleRecvChatAvatarItem(RsChatAvatarItem *item) ; @@ -220,7 +221,8 @@ private: void checkSizeAndSendMessage(RsChatMsgItem *item) ; // keep for compatibility for a few weeks. /// Called when a RsChatMsgItem is received. The item may be collapsed with any waiting partial chat item from the same peer. - bool locked_checkAndRebuildPartialMessage(RsChatMsgItem *) ; + /// if so, the chat item will be turned to NULL + bool locked_checkAndRebuildPartialMessage(RsChatMsgItem *&) ; RsChatAvatarItem *makeOwnAvatarItem() ; RsChatStatusItem *makeOwnCustomStateStringItem() ; diff --git a/libretroshare/src/grouter/p3grouter.cc b/libretroshare/src/grouter/p3grouter.cc index 2770b52dd..306f72d74 100644 --- a/libretroshare/src/grouter/p3grouter.cc +++ b/libretroshare/src/grouter/p3grouter.cc @@ -613,7 +613,6 @@ RsGRouterAbstractMsgItem *GRouterDataInfo::addDataChunk(RsGRouterTransactionChun { RsItem *data_item = RsGRouterSerialiser().deserialise(incoming_data_buffer->chunk_data,&incoming_data_buffer->chunk_size) ; - incoming_data_buffer->chunk_data = NULL; delete incoming_data_buffer; incoming_data_buffer = NULL ; diff --git a/libretroshare/src/grouter/p3grouter.h b/libretroshare/src/grouter/p3grouter.h index 1626da7d7..8c6fbab5c 100644 --- a/libretroshare/src/grouter/p3grouter.h +++ b/libretroshare/src/grouter/p3grouter.h @@ -225,20 +225,13 @@ private: void handleLowLevelTransactionAckItem(RsGRouterTransactionAcknItem*) ; static Sha1CheckSum computeDataItemHash(RsGRouterGenericDataItem *data_item); -#ifdef __APPLE__ -public: -#endif - class nullstream: public std::ostream {}; std::ostream& grouter_debug() const { - static nullstream null ; - + static std::ostream null(0); return _debug_enabled?(std::cerr):null; } -#ifdef __APPLE__ -private: -#endif + void routePendingObjects() ; void handleTunnels() ; void autoWash() ; @@ -364,5 +357,3 @@ private: uint64_t _random_salt ; }; - -template p3GRouter::nullstream& operator<<(p3GRouter::nullstream& ns,const T&) { return ns ; } diff --git a/libretroshare/src/gxs/gxssecurity.cc b/libretroshare/src/gxs/gxssecurity.cc index 248ceaeac..e9dfc5567 100644 --- a/libretroshare/src/gxs/gxssecurity.cc +++ b/libretroshare/src/gxs/gxssecurity.cc @@ -425,6 +425,8 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u // [--- Encrypted session key length ---|--- Encrypted session key ---|--- IV ---|---- Encrypted data ---] // + out = NULL ; + RSA *tmpkey = ::extractPublicKey(key) ; RSA *rsa_publish_pub = RSAPublicKey_dup(tmpkey) ; RSA_free(tmpkey) ; @@ -509,7 +511,7 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u // move to end out_offset += out_currOffset; - + // make sure offset has not gone passed valid memory bounds if(out_offset > max_outlen) { @@ -521,6 +523,8 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u // free encrypted key data free(ek); + EVP_CIPHER_CTX_cleanup(&ctx); + outlen = out_offset; return true; } @@ -538,11 +542,12 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u // out = NULL ; + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + std::vector public_keys(keys.size(),NULL); try { - std::vector public_keys(keys.size(),NULL); - for(uint32_t i=0;i ek(keys.size(),NULL) ; std::vector eklen(keys.size(),0) ; @@ -587,6 +590,11 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u if(!EVP_SealInit(&ctx, EVP_aes_128_cbc(), ek.data(), eklen.data(), iv, public_keys.data(), keys.size())) return false; + // now we can release the encryption keys + for(uint32_t i=0;iPeerId()) << " decrypted item " << std::endl; #endif } +#ifdef NXS_NET_DEBUG_7 else - std::cerr << "(EE) Could not decrypt incoming encrypted NXS item. Probably a friend subscribed to a circle-restricted group." << std::endl; + GXSNETDEBUG_P_(item->PeerId()) << " (EE) Could not decrypt incoming encrypted NXS item. Probably a friend subscribed to a circle-restricted group." << std::endl; +#endif } switch(ni->PacketSubType()) @@ -1638,7 +1640,8 @@ void RsGxsNetService::recvNxsItemQueue() case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM:handleRecvPublishKeys (dynamic_cast(ni)) ; break ; default: - std::cerr << "Unhandled item subtype " << (uint32_t) ni->PacketSubType() << " in RsGxsNetService: " << std::endl; break; + if(ni->PacketSubType() != RS_PKT_SUBTYPE_NXS_ENCRYPTED_DATA_ITEM) + std::cerr << "Unhandled item subtype " << (uint32_t) ni->PacketSubType() << " in RsGxsNetService: " << std::endl; break; } delete item ; } @@ -3861,7 +3864,9 @@ bool RsGxsNetService::decryptSingleNxsItem(const RsNxsEncryptedDataItem *encrypt if(!GxsSecurity::decrypt(decrypted_mem,decrypted_len, (uint8_t*)encrypted_item->encrypted_data.bin_data,encrypted_item->encrypted_data.bin_len,private_keys)) { - std::cerr << "Failed! Cannot decrypt this item." << std::endl; +#ifdef NXS_NET_DEBUG_7 + GXSNETDEBUG_P_(encrypted_item->PeerId()) << " Failed! Cannot decrypt this item." << std::endl; +#endif decrypted_mem = NULL ; // for safety return false ; } @@ -3876,6 +3881,7 @@ bool RsGxsNetService::decryptSingleNxsItem(const RsNxsEncryptedDataItem *encrypt if(decrypted_mem!=NULL) { ditem = RsNxsSerialiser(mServType).deserialise(decrypted_mem,&decrypted_len) ; + free(decrypted_mem) ; if(ditem != NULL) { diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 2ec0f7ad8..15c088627 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1074,6 +1074,12 @@ int pqissl::Initiate_SSL_Connection() "pqissl::Initiate_SSL_Connection() SSL Connection Okay"); #endif + if(ssl_connection != NULL) + { + SSL_shutdown(ssl_connection); + SSL_free(ssl_connection) ; + } + ssl_connection = ssl; net_internal_SSL_set_fd(ssl, sockfd); diff --git a/libretroshare/src/pqi/pqistreamer.cc b/libretroshare/src/pqi/pqistreamer.cc index 1922cb823..c04c2ea9a 100644 --- a/libretroshare/src/pqi/pqistreamer.cc +++ b/libretroshare/src/pqi/pqistreamer.cc @@ -491,7 +491,7 @@ int pqistreamer::handleoutgoing_locked() // send a out_pkt., else send out_data. unless there is a pending packet. The strategy is to // - grab as many packets as possible while below the optimal packet size, so as to allow some packing and decrease encryption padding overhead (suposeddly) // - limit packets size to OPTIMAL_PACKET_SIZE when sending big packets so as to keep as much QoS as possible. - + if (!mPkt_wpending) { void *dta; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index d064dabf9..dce5a3c97 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -366,11 +366,7 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck #ifdef LOCALNET_TESTING >> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction" ,false) #endif -#ifdef __APPLE__ >> help('h',"help","Display this Help") ; -#else - >> help() ; -#endif as.defaultErrorHandling(true) ; diff --git a/libretroshare/src/turtle/p3turtle.cc b/libretroshare/src/turtle/p3turtle.cc index 6d0536b0e..cd0d94238 100644 --- a/libretroshare/src/turtle/p3turtle.cc +++ b/libretroshare/src/turtle/p3turtle.cc @@ -726,7 +726,7 @@ bool p3turtle::loadList(std::list& load) } } - delete vitem ; + delete *it ; } load.clear() ; return true ; diff --git a/libretroshare/src/util/argstream.h b/libretroshare/src/util/argstream.h index 83fb30f0a..325d76fd5 100644 --- a/libretroshare/src/util/argstream.h +++ b/libretroshare/src/util/argstream.h @@ -140,16 +140,11 @@ namespace protected: inline OptionHolder(char s, const char* l, - const char* desc); -#ifdef __APPLE__ + const char* desc); friend OptionHolder help(char s, const char* l, const char* desc); -#else - friend OptionHolder help(char s='h', - const char* l="help", - const char* desc="Display this help"); -#endif + private: std::string shortName_; std::string longName_; diff --git a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp index 0a7b7cb45..96ea76bce 100644 --- a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp +++ b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp @@ -219,8 +219,8 @@ TransfersDialog::TransfersDialog(QWidget *parent) // workaround for Qt bug, should be solved in next Qt release 4.7.0 // http://bugreports.qt.nokia.com/browse/QTBUG-8270 - QShortcut *Shortcut = new QShortcut(QKeySequence (Qt::Key_Delete), ui.downloadList, 0, 0, Qt::WidgetShortcut); - connect(Shortcut, SIGNAL(activated()), this, SLOT( cancel ())); + mShortcut = new QShortcut(QKeySequence (Qt::Key_Delete), ui.downloadList, 0, 0, Qt::WidgetShortcut); + connect(mShortcut, SIGNAL(activated()), this, SLOT( cancel ())); //Selection Setup selection = ui.downloadList->selectionModel(); @@ -942,7 +942,8 @@ int TransfersDialog::addItem(int row, const FileInfo &fileInfo) qlonglong completed = fileInfo.transfered; qlonglong remaining = fileInfo.size - fileInfo.transfered; - qlonglong downloadtime = (fileInfo.size - fileInfo.transfered) / (fileInfo.tfRate * 1024.0); + + qlonglong downloadtime = (fileInfo.tfRate > 0)?( (fileInfo.size - fileInfo.transfered) / (fileInfo.tfRate * 1024.0) ) : 0 ; qint64 qi64LastDL = fileInfo.lastTS ; //std::numeric_limits::max(); if (qi64LastDL == 0) // file is complete, or any raison why the time has not been set properly @@ -1355,7 +1356,7 @@ void TransfersDialog::insertTransfers() qlonglong fileSize = info.size; qlonglong completed = pit->transfered; // double progress = (info.size > 0)?(pit->transfered * 100.0 / info.size):0.0; - qlonglong remaining = (info.size - pit->transfered) / (pit->tfRate * 1024.0); + qlonglong remaining = (pit->tfRate>0)?((info.size - pit->transfered) / (pit->tfRate * 1024.0)):0; // Estimate the completion. We need something more accurate, meaning that we need to // transmit the completion info. diff --git a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h index 617974fa4..0e6e9ad4b 100644 --- a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h +++ b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h @@ -31,6 +31,7 @@ #define IMAGE_TRANSFERS ":/icons/ktorrent_128.png" +class QShortcut; class DLListDelegate; class ULListDelegate; class QStandardItemModel; @@ -243,6 +244,8 @@ private: QString downloads; QString uploads; + QShortcut *mShortcut ; + /** Qt Designer generated object */ Ui::TransfersDialog ui; diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index d3613a3c5..cd9353b65 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -1725,7 +1725,11 @@ void ChatWidget::quote() void ChatWidget::dropPlacemark() { - ui->textBrowser->append("----------"); + ui->textBrowser->moveCursor(QTextCursor::End); // *append* inserts text at end but with formatting in effect at + ui->textBrowser->append("----------"); // current cursor position, such as in the middle of a hotlink, + // which would be strange. This OTOH inserts text with + // formatting in effect on the last line, which may be strange + // or not. } void ChatWidget::saveImage() diff --git a/retroshare-gui/src/gui/common/SubscribeToolButton.cpp b/retroshare-gui/src/gui/common/SubscribeToolButton.cpp index 69de79e47..d263b6f14 100644 --- a/retroshare-gui/src/gui/common/SubscribeToolButton.cpp +++ b/retroshare-gui/src/gui/common/SubscribeToolButton.cpp @@ -10,6 +10,7 @@ SubscribeToolButton::SubscribeToolButton(QWidget *parent) : { mSubscribed = false; + mMenu = NULL ; setToolButtonStyle(Qt::ToolButtonTextBesideIcon); #ifdef USE_MENUBUTTONPOPUP @@ -46,14 +47,18 @@ void SubscribeToolButton::updateUi() setIcon(QIcon(":/images/accepted16.png")); setText(tr("Subscribed")); - QMenu *menu = new QMenu; - menu->addAction(QIcon(":/images/cancel.png"), tr("Unsubscribe"), this, SLOT(unsubscribePrivate())); + if(mMenu != NULL) // that's because setMenu does not give away memory ownership + delete mMenu ; + + mMenu = new QMenu; + mMenu->addAction(QIcon(":/images/cancel.png"), tr("Unsubscribe"), this, SLOT(unsubscribePrivate())); if (!mSubscribedActions.empty()) { - menu->addSeparator(); - menu->addActions(mSubscribedActions); + mMenu->addSeparator(); + mMenu->addActions(mSubscribedActions); } - setMenu(menu); + + setMenu(mMenu); #ifndef USE_MENUBUTTONPOPUP disconnect(this, SIGNAL(clicked()), this, SLOT(subscribePrivate())); diff --git a/retroshare-gui/src/gui/common/SubscribeToolButton.h b/retroshare-gui/src/gui/common/SubscribeToolButton.h index 38056923d..a2903893c 100644 --- a/retroshare-gui/src/gui/common/SubscribeToolButton.h +++ b/retroshare-gui/src/gui/common/SubscribeToolButton.h @@ -26,6 +26,7 @@ private: private: bool mSubscribed; QList mSubscribedActions; + QMenu *mMenu ; }; #endif // SUBSCRIBETOOLBUTTON_H diff --git a/retroshare-gui/src/gui/elastic/graphwidget.cpp b/retroshare-gui/src/gui/elastic/graphwidget.cpp index 571cdc828..dd32051da 100644 --- a/retroshare-gui/src/gui/elastic/graphwidget.cpp +++ b/retroshare-gui/src/gui/elastic/graphwidget.cpp @@ -259,7 +259,7 @@ void GraphWidget::keyPressEvent(QKeyEvent *event) } } -static void convolveWithGaussian(double *forceMap,int S,int /*s*/) +static void convolveWithGaussian(double *forceMap,unsigned int S,int /*s*/) { static double *bf = NULL ; @@ -267,8 +267,8 @@ static void convolveWithGaussian(double *forceMap,int S,int /*s*/) { bf = new double[S*S*2] ; - for(int i=0;i"; //out << trow(tcol("-"ARG_HELP) + // tcol(tr("Displays this usage message and exits."))); - out << trow(tcol("-"ARG_RESET) + + out << trow(tcol("-" ARG_RESET) + tcol(tr("Resets ALL stored RetroShare settings."))); - out << trow(tcol("-"ARG_DATADIR" <dir>") + + out << trow(tcol("-" ARG_DATADIR" <dir>") + tcol(tr("Sets the directory RetroShare uses for data files."))); - out << trow(tcol("-"ARG_LOGFILE" <file>") + + out << trow(tcol("-" ARG_LOGFILE" <file>") + tcol(tr("Sets the name and location of RetroShare's logfile."))); - out << trow(tcol("-"ARG_LOGLEVEL" <level>") + + out << trow(tcol("-" ARG_LOGLEVEL" <level>") + tcol(tr("Sets the verbosity of RetroShare's logging.") + "
[" + Log::logLevels().join("|") +"]")); - out << trow(tcol("-"ARG_GUISTYLE" <style>") + + out << trow(tcol("-" ARG_GUISTYLE" <style>") + tcol(tr("Sets RetroShare's interface style.") + "
[" + QStyleFactory::keys().join("|") + "]")); - out << trow(tcol("-"ARG_GUISTYLESHEET" <stylesheet>") + + out << trow(tcol("-" ARG_GUISTYLESHEET" <stylesheet>") + tcol(tr("Sets RetroShare's interface stylesheets."))); - out << trow(tcol("-"ARG_LANGUAGE" <language>") + + out << trow(tcol("-" ARG_LANGUAGE" <language>") + tcol(tr("Sets RetroShare's language.") + "
[" + LanguageSupport::languageCodes().join("|") + "]")); out << ""; diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index 0c059f048..0e9a278dd 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -17,6 +17,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. + * + * ccr . 2016 Jan 30 . Change regular expression(s) for identifying + * . . hotlinks in feral text. + * ****************************************************************/ #include @@ -56,7 +60,7 @@ protected: public: const EmbeddedType myType; - QRegExp myRE; + QList myREs; }; /** @@ -67,10 +71,42 @@ class EmbedInHtmlAhref : public EmbedInHtml public: EmbedInHtmlAhref() : EmbedInHtml(Ahref) { - myRE.setPattern("(\\bretroshare://[^\\s]*)|(\\bhttps?://[^\\s]*)|(\\bfile://[^\\s]*)|(\\bwww\\.[^\\s]*)"); - } -}; + // myRE.setPattern("(\\bretroshare://[^\\s]*)|(\\bhttps?://[^\\s]*)|(\\bfile://[^\\s]*)|(\\bwww\\.[^\\s]*)"); + // The following regular expressions for finding URLs in + // plain text are borrowed from *gnome-terminal*: + + QString regPassCharset = "[-\\w,?;\\.:/!%$^*&~\\\"#']"; + QString regHost = "[-\\w]+(\\.[-\\w]+)*"; + QString regPort = "(?:\\:\\d{1,5})?"; + QString regPathCharset = "[-\\w_$\\.+!*,;@&=?/~#%]"; + QString regPathTermSet = "[^\\]'.}<>) \\t\\r\\n,\\\"]"; + QStringList regSchemes; +// regSchemes.append("news:"); +// regSchemes.append("telnet:"); +// regSchemes.append("nntp:"); +// regSchemes.append("file:/"); + regSchemes.append("https?:"); +// regSchemes.append("ftps?:"); +// regSchemes.append("sftp:"); +// regSchemes.append("webcal:"); + regSchemes.append("retroshare:"); + QString regScheme = "((?:" + regSchemes.join(")|(?:") + "))"; + QString regUserPass = "[-\\w]+(?:%s+)?" % regPassCharset; + QString regUrlPath = "(?:(/" + regPathCharset + "+(?:[(]" + regPathCharset +"*[)])*" + regPathCharset + "*)*" + regPathTermSet + ")?"; + QStringList regHotLinkFinders; + regHotLinkFinders.append(regScheme + "//(?:" + regUserPass + "@)?"+ regHost + regPort + regUrlPath); +// regHotLinkFinders.append("(?:(?:www)|(?:ftp))[-\\w]*\\." + regHost + regPort + regUrlPath); +// regHotLinkFinders.append("(?:(?:callto:)|(?:h323:)|(?:sip:))[-\\w][-\\w\\.]*(?:" + regPort + "/[a-z0-9]+)?@" + regHost); +// regHotLinkFinders.append("(?:mailto:)?[-\\w][-\\w\\.]*@[-\\w]+\\." + regHost); +// regHotLinkFinders.append("news:[\\w^_{|}~!\\\"#$%&'()*+,\\./;:=?`]+"); + while (!regHotLinkFinders.isEmpty()) { + myREs.append(QRegExp(regHotLinkFinders.takeFirst(), Qt::CaseInsensitive)); + }; + } +}; + + /** * This class is used to store information for embedding smileys into tags. * @@ -134,7 +170,7 @@ void RsHtml::initEmoticons(const QHash< QString, QString >& hash) */ } newRE.chop(1); // remove last | - defEmbedImg.myRE.setPattern(newRE); + defEmbedImg.myREs.append(QRegExp(newRE)); } bool RsHtml::canReplaceAnchor(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link) @@ -243,7 +279,7 @@ void RsHtml::replaceAnchorWithImg(QDomDocument &doc, QDomElement &element, QText * nodes. Any other kind of node is terminal. * * If the node is of type Text, its data is checked against the user-provided - * regular expression. If there is a match, the text is cut in three parts: the + * regular expression(s). If there is a match, the text is cut in three parts: the * preceding part that will be inserted before, the part to be replaced, and the * following part which will be itself checked against the regular expression. * @@ -252,13 +288,10 @@ void RsHtml::replaceAnchorWithImg(QDomDocument &doc, QDomElement &element, QText * * @param[in] doc The whole DOM tree, necessary to create new nodes * @param[in,out] currentElement The current node (which is of type Element) - * @param[in] embedInfos The regular expression and the type of embedding to use + * @param[in] embedInfos The regular expression(s) and the type of embedding to use */ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomElement& currentElement, EmbedInHtml& embedInfos, ulong flag) { - if(embedInfos.myRE.pattern().length() == 0) // we'll get stuck with an empty regexp - return; - QDomNodeList children = currentElement.childNodes(); for(uint index = 0; index < (uint)children.length(); index++) { QDomNode node = children.item(index); @@ -298,15 +331,20 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme } } else if(node.isText()) { - // child is a text, we parse it - QString tempText = node.toText().data(); - if(embedInfos.myRE.indexIn(tempText) == -1) + // child is a text, we parse it + QString tempText = node.toText().data(); + for (int patNdx = 0; patNdx < embedInfos.myREs.size(); ++patNdx) { + QRegExp myRE = embedInfos.myREs.at(patNdx); + if(myRE.pattern().length() == 0) // we'll get stuck with an empty regexp + return; + + if(myRE.indexIn(tempText) == -1) continue; // there is at least one link inside, we start replacing int currentPos = 0; int nextPos = 0; - while((nextPos = embedInfos.myRE.indexIn(tempText, currentPos)) != -1) { + while((nextPos = myRE.indexIn(tempText, currentPos)) != -1) { // if nextPos == 0 it means the text begins by a link if(nextPos > 0) { QDomText textPart = doc.createTextNode(tempText.mid(currentPos, nextPos - currentPos)); @@ -320,10 +358,10 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme case Ahref: { insertedTag = doc.createElement("a"); - insertedTag.setAttribute("href", embedInfos.myRE.cap(0)); - insertedTag.appendChild(doc.createTextNode(embedInfos.myRE.cap(0))); + insertedTag.setAttribute("href", myRE.cap(0)); + insertedTag.appendChild(doc.createTextNode(myRE.cap(0))); - RetroShareLink link(embedInfos.myRE.cap(0)); + RetroShareLink link(myRE.cap(0)); if (link.valid()) { QString title = link.title(); if (!title.isEmpty()) { @@ -340,11 +378,11 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme { insertedTag = doc.createElement("img"); const EmbedInHtmlImg& embedImg = static_cast(embedInfos); - // embedInfos.myRE.cap(0) may include spaces at the end/beginning -> trim! - insertedTag.setAttribute("src", embedImg.smileys[embedInfos.myRE.cap(0).trimmed()]); + // myRE.cap(0) may include spaces at the end/beginning -> trim! + insertedTag.setAttribute("src", embedImg.smileys[myRE.cap(0).trimmed()]); /* * NOTE - * Trailing spaces are matched, too. This leads to embedInfos.myRE.matchedLength() being incorrect. + * Trailing spaces are matched, too. This leads to myRE.matchedLength() being incorrect. * This hack reduces nextPos by one so that the new value of currentPos is calculated corretly. * This is needed to match multiple smileys since the leading whitespace in front of a smiley is required! * @@ -353,7 +391,7 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme * NOTE * Preceding spaces are also matched and removed. */ - if(embedInfos.myRE.cap(0).endsWith(' ')) + if(myRE.cap(0).endsWith(' ')) nextPos--; } break; @@ -362,7 +400,7 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme currentElement.insertBefore(insertedTag, node); index++; - currentPos = nextPos + embedInfos.myRE.matchedLength(); + currentPos = nextPos + myRE.matchedLength(); } // text after the last link, only if there's one, don't touch the index @@ -375,10 +413,18 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme index--; currentElement.removeChild(node); + break; + // We'd better not expect that + // subsequent hotlink patterns + // wouldn't also match replacements + // we've already made. They might, so + // skip 'em to be safe. + }; } } } + /** * Save space and tab out of bracket that XML loose. * @@ -612,7 +658,7 @@ static void findBestColor(QString &val, qreal bglum, qreal desiredContrast) */ static void optimizeHtml(QDomDocument& doc , QDomElement& currentElement - , QHash &stylesList + , QHash &stylesList , QHash &knownStyle) { if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) { @@ -631,10 +677,10 @@ static void optimizeHtml(QDomDocument& doc QString keyvalue = pair.at(1); keyvalue.replace(";",""); QStringList classUsingIt(pair.at(0).split(',')); - QStringList* exported = new QStringList(); + QStringList exported ; foreach (QString keyVal, classUsingIt) { if(!keyVal.trimmed().isEmpty()) { - exported->append(keyVal.trimmed().replace(".","")); + exported.append(keyVal.trimmed().replace(".","")); } } @@ -759,14 +805,10 @@ static void optimizeHtml(QDomDocument& doc foreach (QString pair, styles) { pair.replace(" ",""); if (!pair.isEmpty()) { - QStringList* stylesListItem = stylesList.value(pair); - if(!stylesListItem){ - // If value doesn't exist create it - stylesListItem = new QStringList(); - stylesList.insert(pair, stylesListItem); - } + QStringList& stylesListItem = stylesList[pair]; + //Add the new class to this value - stylesListItem->push_back(className); + stylesListItem.push_back(className); } } } @@ -800,7 +842,7 @@ static void optimizeHtml(QDomDocument& doc * @param desiredMinimumFontSize: Minimum font size. */ static void styleCreate(QDomDocument& doc - , QHash stylesList + , QHash& stylesList , unsigned int flag , qreal bglum , qreal desiredContrast @@ -840,12 +882,12 @@ static void styleCreate(QDomDocument& doc QString style = ""; - QHashIterator it(stylesList); + QHashIterator it(stylesList); while(it.hasNext()) { it.next(); - QStringList* classUsingIt = it.value(); + const QStringList& classUsingIt ( it.value()) ; bool first = true; - foreach(QString className, *classUsingIt) { + foreach(QString className, classUsingIt) { if (!className.trimmed().isEmpty()) { style += QString(first?".":",.") + className;// + " "; first = false; @@ -961,7 +1003,8 @@ void RsHtml::optimizeHtml(QString &text, unsigned int flag /*= 0*/ } QDomElement body = doc.documentElement(); - QHash stylesList; + + QHash stylesList; QHash knownStyle; ::optimizeHtml(doc, body, stylesList, knownStyle); diff --git a/retroshare-nogui/src/retroshare.cc b/retroshare-nogui/src/retroshare.cc index 59a1bf1b4..7ad45b0eb 100644 --- a/retroshare-nogui/src/retroshare.cc +++ b/retroshare-nogui/src/retroshare.cc @@ -85,12 +85,9 @@ int main(int argc, char **argv) args >> parameter("docroot", docroot, "path", "Serve static files from this path.", false); // unfinished //args >> parameter("http-listen", listenAddress, "ipv6 address", "Listen only on the specified address.", false); - args >> option("http-allow-all", allowAllIps, "allow connections from all IP adresses (default= localhost only)"); -#ifdef __APPLE__ + args >> option("http-allow-all", allowAllIps, "allow connections from all IP adresses (default= localhost only)"); args >> help('h',"help","Display this Help"); -#else - args >> help(); -#endif + if (args.helpRequested()) { std::cerr << args.usage() << std::endl;