2014-05-08 03:52:28 -04:00
/***************************************************************************
* Copyright ( C ) 2009 *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 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 General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the *
* Free Software Foundation , Inc . , *
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <iostream>
# include <time.h>
# include <QStringList>
# include <QRegExp>
# include <QApplication>
# include <QMimeData>
# include <QClipboard>
# include <QDesktopServices>
# include <QMessageBox>
# include <QIcon>
# include <QObject>
# include <time.h>
# if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
# include <QUrlQuery>
# endif
# include "RetroShareLink.h"
# include "MainWindow.h"
2014-05-27 17:14:05 -04:00
# include "gui/gxsforums/GxsForumsDialog.h"
2014-05-08 03:52:28 -04:00
# include "SearchDialog.h"
# include "msgs/MessageComposer.h"
# include "util/misc.h"
# include "common/PeerDefs.h"
# include "common/RsCollectionFile.h"
# include "gui/connect/ConnectFriendWizard.h"
# include "gui/connect/ConfCertDialog.h"
# include <retroshare/rsfiles.h>
# include <retroshare/rsmsgs.h>
# include <retroshare/rspeers.h>
# include <retroshare/rsidentity.h>
2014-05-27 17:14:05 -04:00
# include <retroshare/rsgxsforums.h>
2014-05-08 03:52:28 -04:00
//#define DEBUG_RSLINK 1
# define HOST_FILE "file"
# define HOST_EXTRAFILE "extra"
# define HOST_PERSON "person"
# define HOST_FORUM "forum"
# define HOST_CHANNEL "channel"
# define HOST_MESSAGE "message"
# define HOST_SEARCH "search"
# define HOST_CERTIFICATE "certificate"
# define HOST_PUBLIC_MSG "public_msg"
# define HOST_REGEXP "file|person|forum|channel|search|message|certificate|private_chat|public_msg"
# define FILE_NAME "name"
# define FILE_SIZE "size"
# define FILE_HASH "hash"
# define FILE_SOURCE "src"
# define PERSON_NAME "name"
# define PERSON_HASH "hash"
# define FORUM_NAME "name"
# define FORUM_ID "id"
# define FORUM_MSGID "msgid"
# define CHANNEL_NAME "name"
# define CHANNEL_ID "id"
# define CHANNEL_MSGID "msgid"
# define MESSAGE_ID "id"
# define MESSAGE_SUBJECT "subject"
# define SEARCH_KEYWORDS "keywords"
# define CERTIFICATE_SSLID "sslid"
# define CERTIFICATE_GPG_ID "gpgid"
# define CERTIFICATE_GPG_BASE64 "gpgbase64"
# define CERTIFICATE_GPG_CHECKSUM "gpgchecksum"
# define CERTIFICATE_LOCATION "location"
# define CERTIFICATE_NAME "name"
2014-05-06 15:04:57 -04:00
# define CERTIFICATE_EXT_IPPORT "extipp"
# define CERTIFICATE_LOC_IPPORT "locipp"
# define CERTIFICATE_DYNDNS "dyndns"
# define CERTIFICATE_RADIX "radix"
2014-05-08 03:52:28 -04:00
# define PUBLIC_MSG_TIME_STAMP "time_stamp"
# define PUBLIC_MSG_SRC_PGP_ID "gpgid"
# define PUBLIC_MSG_HASH "hash"
RetroShareLink : : RetroShareLink ( const QUrl & url )
{
fromUrl ( url ) ;
}
RetroShareLink : : RetroShareLink ( const QString & url )
{
fromString ( url ) ;
}
void RetroShareLink : : fromString ( const QString & url )
{
clear ( ) ;
// parse
# ifdef DEBUG_RSLINK
std : : cerr < < " got new RS link \" " < < url . toStdString ( ) < < " \" " < < std : : endl ;
# endif
if ( ( url . startsWith ( QString ( RSLINK_SCHEME ) + " :// " + QString ( HOST_FILE ) ) & & url . count ( " | " ) = = 3 ) | |
( url . startsWith ( QString ( RSLINK_SCHEME ) + " :// " + QString ( HOST_PERSON ) ) & & url . count ( " | " ) = = 2 ) )
{
/* Old link, we try it */
QStringList list = url . split ( " | " ) ;
if ( list . size ( ) > = 1 ) {
if ( list . size ( ) = = 4 & & list [ 0 ] = = QString ( RSLINK_SCHEME ) + " :// " + QString ( HOST_FILE ) ) {
bool ok ;
_type = TYPE_FILE ;
_name = list [ 1 ] ;
_size = list [ 2 ] . toULongLong ( & ok ) ;
_hash = list [ 3 ] . left ( 40 ) ; // normally not necessary, but it's a security.
if ( ok ) {
# ifdef DEBUG_RSLINK
std : : cerr < < " New RetroShareLink forged: " < < std : : endl ;
std : : cerr < < " name = \" " < < _name . toStdString ( ) < < " \" " < < std : : endl ;
std : : cerr < < " hash = \" " < < _hash . toStdString ( ) < < " \" " < < std : : endl ;
std : : cerr < < " size = " < < _size < < std : : endl ;
# endif
check ( ) ;
return ;
}
} else if ( list . size ( ) = = 3 & & list [ 0 ] = = QString ( RSLINK_SCHEME ) + " :// " + QString ( HOST_PERSON ) ) {
_type = TYPE_PERSON ;
_name = list [ 1 ] ;
_hash = list [ 2 ] . left ( 40 ) ; // normally not necessary, but it's a security.
_size = 0 ;
check ( ) ;
return ;
}
// bad link
}
}
/* Now try QUrl */
fromUrl ( QUrl : : fromEncoded ( url . toUtf8 ( ) . constData ( ) ) ) ;
}
void RetroShareLink : : fromUrl ( const QUrl & url )
{
# if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
const QUrlQuery urlQuery ( url ) ;
# else
const QUrl & urlQuery ( url ) ;
# endif
clear ( ) ;
// parse
# ifdef DEBUG_RSLINK
std : : cerr < < " got new RS link \" " < < url . toString ( ) . toStdString ( ) < < " \" " < < std : : endl ;
# endif
if ( url . scheme ( ) ! = RSLINK_SCHEME ) {
/* No RetroShare-Link */
std : : cerr < < " Not a RS link: scheme= " < < url . scheme ( ) . toStdString ( ) < < std : : endl ;
return ;
}
if ( url . host ( ) = = HOST_FILE ) {
bool ok ;
_type = TYPE_FILE ;
_name = urlQuery . queryItemValue ( FILE_NAME ) ;
_size = urlQuery . queryItemValue ( FILE_SIZE ) . toULongLong ( & ok ) ;
_hash = urlQuery . queryItemValue ( FILE_HASH ) . left ( 40 ) ; // normally not necessary, but it's a security.
if ( ok ) {
# ifdef DEBUG_RSLINK
std : : cerr < < " New RetroShareLink forged: " < < std : : endl ;
std : : cerr < < " name = \" " < < _name . toStdString ( ) < < " \" " < < std : : endl ;
std : : cerr < < " hash = \" " < < _hash . toStdString ( ) < < " \" " < < std : : endl ;
std : : cerr < < " size = " < < _size < < std : : endl ;
# endif
check ( ) ;
return ;
}
}
if ( url . host ( ) = = HOST_PUBLIC_MSG )
{
bool ok ;
_type = TYPE_PUBLIC_MSG ;
_hash = urlQuery . queryItemValue ( PUBLIC_MSG_HASH ) ;
_time_stamp = urlQuery . queryItemValue ( PUBLIC_MSG_TIME_STAMP ) . toUInt ( & ok ) ;
_GPGid = urlQuery . queryItemValue ( PUBLIC_MSG_SRC_PGP_ID ) ;
check ( ) ;
return ;
}
if ( url . host ( ) = = HOST_EXTRAFILE ) {
bool ok ;
_type = TYPE_EXTRAFILE ;
_name = urlQuery . queryItemValue ( FILE_NAME ) ;
_size = urlQuery . queryItemValue ( FILE_SIZE ) . toULongLong ( & ok ) ;
_hash = urlQuery . queryItemValue ( FILE_HASH ) . left ( 40 ) ; // normally not necessary, but it's a security.
_SSLid = urlQuery . queryItemValue ( FILE_SOURCE ) ;
if ( ok ) {
# ifdef DEBUG_RSLINK
std : : cerr < < " New RetroShareLink forged: " < < std : : endl ;
std : : cerr < < " name = \" " < < _name . toStdString ( ) < < " \" " < < std : : endl ;
std : : cerr < < " hash = \" " < < _hash . toStdString ( ) < < " \" " < < std : : endl ;
std : : cerr < < " size = " < < _size < < std : : endl ;
std : : cerr < < " src = " < < _SSLid . toStdString ( ) < < std : : endl ;
# endif
check ( ) ;
return ;
}
}
if ( url . host ( ) = = HOST_PERSON ) {
_type = TYPE_PERSON ;
_name = urlQuery . queryItemValue ( PERSON_NAME ) ;
_hash = urlQuery . queryItemValue ( PERSON_HASH ) . left ( 40 ) ; // normally not necessary, but it's a security.
check ( ) ;
return ;
}
if ( url . host ( ) = = HOST_FORUM ) {
_type = TYPE_FORUM ;
_name = urlQuery . queryItemValue ( FORUM_NAME ) ;
_hash = urlQuery . queryItemValue ( FORUM_ID ) ;
_msgId = urlQuery . queryItemValue ( FORUM_MSGID ) ;
check ( ) ;
return ;
}
if ( url . host ( ) = = HOST_CHANNEL ) {
_type = TYPE_CHANNEL ;
_name = urlQuery . queryItemValue ( CHANNEL_NAME ) ;
_hash = urlQuery . queryItemValue ( CHANNEL_ID ) ;
_msgId = urlQuery . queryItemValue ( CHANNEL_MSGID ) ;
check ( ) ;
return ;
}
if ( url . host ( ) = = HOST_SEARCH ) {
_type = TYPE_SEARCH ;
_name = urlQuery . queryItemValue ( SEARCH_KEYWORDS ) ;
check ( ) ;
return ;
}
if ( url . host ( ) = = HOST_MESSAGE ) {
_type = TYPE_MESSAGE ;
std : : string id = urlQuery . queryItemValue ( MESSAGE_ID ) . toStdString ( ) ;
createMessage ( RsPeerId ( id ) , urlQuery . queryItemValue ( MESSAGE_SUBJECT ) ) ;
return ;
}
if ( url . host ( ) = = HOST_CERTIFICATE ) {
_type = TYPE_CERTIFICATE ;
_radix = urlQuery . queryItemValue ( CERTIFICATE_RADIX ) ;
2014-06-28 16:15:08 -04:00
2014-05-08 03:52:28 -04:00
std : : cerr < < " Got a certificate link!! " < < std : : endl ;
check ( ) ;
return ;
}
// bad link
# ifdef DEBUG_RSLINK
std : : cerr < < " Wrongly formed RS link. Can't process. " < < std : : endl ;
# endif
clear ( ) ;
}
RetroShareLink : : RetroShareLink ( )
{
clear ( ) ;
}
bool RetroShareLink : : createExtraFile ( const QString & name , uint64_t size , const QString & hash , const QString & ssl_id )
{
clear ( ) ;
_name = name ;
_size = size ;
_hash = hash ;
_SSLid = ssl_id ;
_type = TYPE_EXTRAFILE ;
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createFile ( const QString & name , uint64_t size , const QString & hash )
{
clear ( ) ;
_name = name ;
_size = size ;
_hash = hash ;
_type = TYPE_FILE ;
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createPublicMsgInvite ( time_t time_stamp , const QString & issuer_pgp_id , const QString & hash )
{
clear ( ) ;
_type = TYPE_PUBLIC_MSG ;
_time_stamp = time_stamp ;
_hash = hash ;
_GPGid = issuer_pgp_id ;
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createPerson ( const RsPgpId & id )
{
clear ( ) ;
RsPeerDetails detail ;
if ( rsPeers - > getGPGDetails ( id , detail ) = = false ) {
std : : cerr < < " RetroShareLink::createPerson() Couldn't find peer id " < < id < < std : : endl ;
return false ;
}
_hash = QString : : fromStdString ( id . toStdString ( ) ) ;
_name = QString : : fromUtf8 ( detail . name . c_str ( ) ) ;
_type = TYPE_PERSON ;
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createCertificate ( const RsPeerId & ssl_id )
{
// This is baaaaaad code:
// - we should not need to parse and re-read a cert in old format.
//
RsPeerDetails detail ;
if ( rsPeers - > getPeerDetails ( ssl_id , detail ) = = false ) {
std : : cerr < < " RetroShareLink::createPerson() Couldn't find peer id " < < ssl_id < < std : : endl ;
return false ;
}
_type = TYPE_CERTIFICATE ;
_radix = QString : : fromUtf8 ( rsPeers - > GetRetroshareInvite ( ssl_id , false ) . c_str ( ) ) ;
2014-08-26 14:52:21 -04:00
_name = QString : : fromUtf8 ( detail . name . c_str ( ) ) ;
_location = QString : : fromUtf8 ( detail . location . c_str ( ) ) ;
2014-05-08 03:52:28 -04:00
_radix . replace ( " \n " , " " ) ;
2014-06-28 16:15:08 -04:00
2014-05-08 03:52:28 -04:00
std : : cerr < < " Found radix = " < < _radix . toStdString ( ) < < std : : endl ;
return true ;
}
bool RetroShareLink : : createUnknwonSslCertificate ( const RsPeerId & sslId , const RsPgpId & gpgId )
{
// first try ssl id
if ( createCertificate ( sslId ) ) {
if ( gpgId . isNull ( ) | | _GPGid . toStdString ( ) = = gpgId . toStdString ( ) ) {
return true ;
}
// wrong gpg id
return false ;
}
// then gpg id
if ( createCertificate ( sslId ) ) {
if ( ! _SSLid . isEmpty ( ) ) {
return false ;
}
if ( sslId . isNull ( ) ) {
return true ;
}
_SSLid = QString : : fromStdString ( sslId . toStdString ( ) ) ;
if ( _location . isEmpty ( ) ) {
_location = _name ;
}
return true ;
}
return false ;
}
2014-07-26 19:52:45 -04:00
bool RetroShareLink : : createGxsGroupLink ( const RetroShareLink : : enumType & linkType , const RsGxsGroupId & groupId , const QString & groupName )
2014-05-08 03:52:28 -04:00
{
clear ( ) ;
2014-07-26 19:52:45 -04:00
if ( ! groupId . isNull ( ) ) {
_hash = QString : : fromStdString ( groupId . toStdString ( ) ) ;
_type = linkType ;
_name = groupName ;
2014-05-08 03:52:28 -04:00
}
check ( ) ;
return valid ( ) ;
}
2014-07-26 19:52:45 -04:00
bool RetroShareLink : : createGxsMessageLink ( const RetroShareLink : : enumType & linkType , const RsGxsGroupId & groupId , const RsGxsMessageId & msgId , const QString & msgName )
2014-05-08 03:52:28 -04:00
{
clear ( ) ;
2014-07-26 19:52:45 -04:00
if ( ! groupId . isNull ( ) & & ! msgId . isNull ( ) ) {
_hash = QString : : fromStdString ( groupId . toStdString ( ) ) ;
_msgId = QString : : fromStdString ( msgId . toStdString ( ) ) ;
_type = linkType ;
_name = msgName ;
2014-05-08 03:52:28 -04:00
}
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createSearch ( const QString & keywords )
{
clear ( ) ;
_name = keywords ;
_type = TYPE_SEARCH ;
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createMessage ( const RsPeerId & peerId , const QString & subject )
{
clear ( ) ;
_hash = QString : : fromStdString ( peerId . toStdString ( ) ) ;
PeerDefs : : rsidFromId ( peerId , & _name ) ;
_subject = subject ;
_type = TYPE_MESSAGE ;
check ( ) ;
return valid ( ) ;
}
bool RetroShareLink : : createMessage ( const RsGxsId & peerId , const QString & subject )
{
clear ( ) ;
_hash = QString : : fromStdString ( peerId . toStdString ( ) ) ;
2014-05-08 04:39:04 -04:00
PeerDefs : : rsidFromId ( peerId , & _name ) ;
//_name = QString::fromStdString("GXS_id("+peerId.toStdString()+")") ;
2014-05-08 03:52:28 -04:00
// do something better here!!
_subject = subject ;
_type = TYPE_MESSAGE ;
check ( ) ;
return valid ( ) ;
}
void RetroShareLink : : clear ( )
{
_valid = false ;
_type = TYPE_UNKNOWN ;
_subType = 0 ;
_hash = " " ;
_size = 0 ;
_name = " " ;
_GPGid = " " ;
_time_stamp = 0 ;
_encrypted_chat_info = " " ;
}
void RetroShareLink : : check ( )
{
_valid = true ;
switch ( _type )
{
case TYPE_UNKNOWN :
2014-10-09 11:17:42 -04:00
case TYPE_PRIVATE_CHAT :
2014-05-08 03:52:28 -04:00
_valid = false ;
break ;
case TYPE_EXTRAFILE :
if ( ! checkSSLId ( _SSLid ) )
_valid = false ; // no break! We also test file stuff below.
case TYPE_FILE :
if ( _size > ( ( ( uint64_t ) 1 ) < < 40 ) ) // 1TB. Who has such large files?
_valid = false ;
if ( ! checkName ( _name ) )
_valid = false ;
if ( ! checkHash ( _hash ) )
_valid = false ;
break ;
case TYPE_PUBLIC_MSG :
if ( ! checkHash ( _hash ) ) _valid = false ;
if ( ! checkPGPId ( _GPGid ) ) _valid = false ;
break ;
case TYPE_PERSON :
if ( _size ! = 0 )
_valid = false ;
if ( _name . isEmpty ( ) )
_valid = false ;
if ( _hash . isEmpty ( ) )
_valid = false ;
break ;
case TYPE_FORUM :
if ( _size ! = 0 )
_valid = false ;
if ( _name . isEmpty ( ) )
_valid = false ;
if ( _hash . isEmpty ( ) )
_valid = false ;
break ;
case TYPE_CHANNEL :
if ( _size ! = 0 )
_valid = false ;
if ( _name . isEmpty ( ) )
_valid = false ;
if ( _hash . isEmpty ( ) )
_valid = false ;
break ;
case TYPE_SEARCH :
if ( _size ! = 0 )
_valid = false ;
if ( _name . isEmpty ( ) )
_valid = false ;
if ( ! _hash . isEmpty ( ) )
_valid = false ;
break ;
case TYPE_MESSAGE :
if ( _size ! = 0 )
_valid = false ;
if ( _hash . isEmpty ( ) )
_valid = false ;
break ;
case TYPE_CERTIFICATE :
break ;
}
if ( ! _valid ) {
clear ( ) ;
}
}
QString RetroShareLink : : title ( ) const
{
if ( ! valid ( ) ) {
return " " ;
}
switch ( _type ) {
case TYPE_UNKNOWN :
2014-10-09 11:17:42 -04:00
case TYPE_PRIVATE_CHAT :
2014-05-08 03:52:28 -04:00
break ;
case TYPE_PUBLIC_MSG :
{
RsPeerDetails detail ;
rsPeers - > getGPGDetails ( RsPgpId ( _GPGid . toStdString ( ) ) , detail ) ;
2014-07-10 14:37:21 -04:00
return QObject : : tr ( " Click to send a private message to %1 (%2). " ) . arg ( QString : : fromUtf8 ( detail . name . c_str ( ) ) ) . arg ( _GPGid ) ;
2014-05-08 03:52:28 -04:00
}
case TYPE_EXTRAFILE :
2014-07-10 14:37:21 -04:00
return QObject : : tr ( " %1 (%2, Extra - Source included) " ) . arg ( hash ( ) ) . arg ( misc : : friendlyUnit ( size ( ) ) ) ;
2014-05-08 03:52:28 -04:00
case TYPE_FILE :
return QString ( " %1 (%2) " ).arg(hash()).arg(misc::friendlyUnit(size())) ;
case TYPE_PERSON :
return PeerDefs : : rsidFromId ( RsPgpId ( hash ( ) . toStdString ( ) ) ) ;
case TYPE_FORUM :
case TYPE_CHANNEL :
case TYPE_SEARCH :
break ;
case TYPE_MESSAGE :
return PeerDefs : : rsidFromId ( RsPeerId ( hash ( ) . toStdString ( ) ) ) ;
case TYPE_CERTIFICATE :
2014-06-28 16:15:08 -04:00
RsPeerDetails details ;
uint32_t error_code ;
if ( ! rsPeers - > loadDetailsFromStringCert ( _radix . toStdString ( ) , details , error_code ) )
return QObject : : tr ( " This cert is malformed. Error code: " ) + QString : : number ( error_code ) ;
else
return QObject : : tr ( " Click to add this RetroShare cert to your PGP keyring \n and open the Make Friend Wizard. \n " )
+ QString ( " PGP Id = " ) + QString : : fromStdString ( details . gpg_id . toStdString ( ) ) + QString ( " \n SSLId = " ) + QString : : fromStdString ( details . id . toStdString ( ) ) ;
2014-05-08 03:52:28 -04:00
}
return " " ;
}
static QString encodeItem ( QString item )
{
return item
// .replace("{", "%"+QString::number((int)'{', 16))
// .replace("}", "%"+QString::number((int)'}', 16))
// .replace("[", "%"+QString::number((int)'[', 16))
// .replace("]", "%"+QString::number((int)']', 16))
// .replace("^", "%"+QString::number((int)'^', 16))
// .replace("~", "%"+QString::number((int)'~', 16))
// .replace(";", "%"+QString::number((int)';', 16))
// .replace(":", "%"+QString::number((int)':', 16))
// .replace("=", "%"+QString::number((int)'=', 16))
// .replace("+", "%"+QString::number((int)'+', 16))
// .replace("$", "%"+QString::number((int)'$', 16))
// .replace(",", "%"+QString::number((int)',', 16))
// .replace("\"", "%"+QString::number((int)'\"', 16))
// .replace("|", "%"+QString::number((int)'|', 16))
// .replace("?", "%"+QString::number((int)'?', 16))
// .replace("@", "%"+QString::number((int)'@', 16))
. replace ( " & " , " % " + QString : : number ( ( int ) ' & ' , 16 ) ) //Not necessary: only for text link
. replace ( " / " , " % " + QString : : number ( ( int ) ' / ' , 16 ) )
. replace ( " " , " % " + QString : : number ( ( int ) ' ' , 16 ) )
. replace ( " # " , " % " + QString : : number ( ( int ) ' # ' , 16 ) )
// .replace("£", "%"+QString::number((int)'£', 16))
// .replace("µ", "%"+QString::number((int)'µ', 16))
// .replace("§", "%"+QString::number((int)'§', 16))
// .replace("!", "%"+QString::number((int)'!', 16))
;
}
QString RetroShareLink : : toString ( ) const
{
QUrl url ;
# if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QUrlQuery urlQuery ;
# else
QUrl & urlQuery ( url ) ;
# endif
switch ( _type ) {
case TYPE_UNKNOWN :
2014-10-09 11:17:42 -04:00
case TYPE_PRIVATE_CHAT :
2014-05-08 03:52:28 -04:00
return " " ;
case TYPE_FILE :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_FILE ) ;
urlQuery . addQueryItem ( FILE_NAME , encodeItem ( _name ) ) ;
urlQuery . addQueryItem ( FILE_SIZE , QString : : number ( _size ) ) ;
urlQuery . addQueryItem ( FILE_HASH , _hash ) ;
break ;
case TYPE_PUBLIC_MSG :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_PUBLIC_MSG ) ;
urlQuery . addQueryItem ( PUBLIC_MSG_TIME_STAMP , QString : : number ( _time_stamp ) ) ;
urlQuery . addQueryItem ( PUBLIC_MSG_HASH , _hash ) ;
urlQuery . addQueryItem ( PUBLIC_MSG_SRC_PGP_ID , _GPGid ) ;
break ;
case TYPE_EXTRAFILE :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_EXTRAFILE ) ;
urlQuery . addQueryItem ( FILE_NAME , encodeItem ( _name ) ) ;
urlQuery . addQueryItem ( FILE_SIZE , QString : : number ( _size ) ) ;
urlQuery . addQueryItem ( FILE_HASH , _hash ) ;
urlQuery . addQueryItem ( FILE_SOURCE , _SSLid ) ;
break ;
case TYPE_PERSON :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_PERSON ) ;
urlQuery . addQueryItem ( PERSON_NAME , encodeItem ( _name ) ) ;
urlQuery . addQueryItem ( PERSON_HASH , _hash ) ;
break ;
case TYPE_FORUM :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_FORUM ) ;
urlQuery . addQueryItem ( FORUM_NAME , encodeItem ( _name ) ) ;
urlQuery . addQueryItem ( FORUM_ID , _hash ) ;
if ( ! _msgId . isEmpty ( ) ) {
urlQuery . addQueryItem ( FORUM_MSGID , _msgId ) ;
}
break ;
case TYPE_CHANNEL :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_CHANNEL ) ;
urlQuery . addQueryItem ( CHANNEL_NAME , encodeItem ( _name ) ) ;
urlQuery . addQueryItem ( CHANNEL_ID , _hash ) ;
if ( ! _msgId . isEmpty ( ) ) {
urlQuery . addQueryItem ( CHANNEL_MSGID , _msgId ) ;
}
break ;
case TYPE_SEARCH :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_SEARCH ) ;
urlQuery . addQueryItem ( SEARCH_KEYWORDS , encodeItem ( _name ) ) ;
break ;
case TYPE_MESSAGE :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_MESSAGE ) ;
urlQuery . addQueryItem ( MESSAGE_ID , _hash ) ;
if ( _subject . isEmpty ( ) = = false ) {
urlQuery . addQueryItem ( MESSAGE_SUBJECT , encodeItem ( _subject ) ) ;
}
break ;
case TYPE_CERTIFICATE :
url . setScheme ( RSLINK_SCHEME ) ;
url . setHost ( HOST_CERTIFICATE ) ;
urlQuery . addQueryItem ( CERTIFICATE_RADIX , _radix ) ;
2014-08-26 14:52:21 -04:00
urlQuery . addQueryItem ( CERTIFICATE_NAME , _name ) ;
urlQuery . addQueryItem ( CERTIFICATE_LOCATION , _location ) ;
2014-05-08 03:52:28 -04:00
break ;
}
# if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
url . setQuery ( urlQuery ) ;
# endif
return url . toString ( ) ;
}
QString RetroShareLink : : niceName ( ) const
{
if ( type ( ) = = TYPE_PERSON ) {
return PeerDefs : : rsid ( name ( ) . toUtf8 ( ) . constData ( ) , RsPgpId ( hash ( ) . toStdString ( ) ) ) ;
}
if ( type ( ) = = TYPE_PUBLIC_MSG ) {
RsPeerDetails detail ;
rsPeers - > getGPGDetails ( RsPgpId ( _GPGid . toStdString ( ) ) , detail ) ;
2014-07-10 14:37:21 -04:00
return QObject : : tr ( " Click this link to send a private message to %1 (%2) " ) . arg ( QString : : fromUtf8 ( detail . name . c_str ( ) ) ) . arg ( _GPGid ) ;
2014-05-08 03:52:28 -04:00
}
2014-06-28 16:15:08 -04:00
if ( type ( ) = = TYPE_CERTIFICATE )
{
RsPeerDetails details ;
uint32_t error_code ;
if ( ! rsPeers - > loadDetailsFromStringCert ( _radix . toStdString ( ) , details , error_code ) )
return QObject : : tr ( " This cert is malformed. Error code: " ) + QString : : number ( error_code ) ;
else
2014-07-10 14:37:21 -04:00
return QObject : : tr ( " RetroShare Certificate (%1, @%2) " ) . arg ( QString : : fromUtf8 ( details . name . c_str ( ) ) , QString : : fromUtf8 ( details . location . c_str ( ) ) ) ; // should add SSL id there
2014-05-08 03:52:28 -04:00
}
return name ( ) ;
}
QString RetroShareLink : : toHtml ( ) const
{
QString html = " <a href= \" " + toString ( ) + " \" " ;
QString linkTitle = title ( ) ;
if ( ! linkTitle . isEmpty ( ) ) {
html + = " title= \" " + linkTitle + " \" " ;
}
html + = " > " + niceName ( ) + " </a> " ;
return html ;
}
QString RetroShareLink : : toHtmlFull ( ) const
{
return QString ( " <a href= \" " ) + toString ( ) + " \" > " + toString ( ) + " </a> " ;
}
QString RetroShareLink : : toHtmlSize ( ) const
{
QString size = QString ( " (%1) " ) . arg ( misc : : friendlyUnit ( _size ) ) ;
if ( type ( ) = = TYPE_FILE & & RsCollectionFile : : isCollectionFile ( name ( ) ) ) {
FileInfo finfo ;
if ( rsFiles - > FileDetails ( RsFileHash ( hash ( ) . toStdString ( ) ) , RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL , finfo ) ) {
RsCollectionFile collection ;
if ( collection . load ( QString : : fromUtf8 ( finfo . path . c_str ( ) ) , false ) ) {
size + = QString ( " [%1] " ) . arg ( misc : : friendlyUnit ( collection . size ( ) ) ) ;
}
}
}
QString link = QString ( " <a href= \" %1 \" >%2</a> <font color= \" blue \" >%3</font> " ) . arg ( toString ( ) ) . arg ( name ( ) ) . arg ( size ) ;
return link ;
}
bool RetroShareLink : : checkName ( const QString & name )
{
if ( name = = " " )
return false ;
for ( int i = 0 ; i < name . length ( ) ; + + i )
{
QChar : : Category cat ( name [ i ] . category ( ) ) ;
if ( cat = = QChar : : Separator_Line
| | cat = = QChar : : Other_NotAssigned
)
{
# ifdef DEBUG_RSLINK
std : : cerr < < " Unwanted category " < < cat < < " at place " < < i < < " in string \" " < < name . toStdString ( ) < < " \" " < < std : : endl ;
# endif
return false ;
}
}
return true ;
}
QUrl RetroShareLink : : toUrl ( ) const
{
return QUrl : : fromEncoded ( toString ( ) . toUtf8 ( ) . constData ( ) ) ;
}
bool RetroShareLink : : checkSSLId ( const QString & ssl_id )
{
if ( ssl_id . length ( ) ! = 32 )
return false ;
QByteArray qb ( ssl_id . toLatin1 ( ) ) ;
for ( int i = 0 ; i < qb . length ( ) ; + + i )
{
unsigned char b ( qb [ i ] ) ;
if ( ! ( ( b > 47 & & b < 58 ) | | ( b > 96 & & b < 103 ) ) )
return false ;
}
return true ;
}
bool RetroShareLink : : checkPGPId ( const QString & pgp_id )
{
if ( pgp_id . length ( ) ! = 16 )
return false ;
QByteArray qb ( pgp_id . toLatin1 ( ) ) ;
for ( int i = 0 ; i < qb . length ( ) ; + + i )
{
unsigned char b ( qb [ i ] ) ;
if ( ! ( ( b > 47 & & b < 58 ) | | ( b > 64 & & b < 71 ) ) )
return false ;
}
return true ;
}
bool RetroShareLink : : checkRadix64 ( const QString & s )
{
QByteArray qb ( s . toLatin1 ( ) ) ;
for ( int i = 0 ; i < qb . length ( ) ; + + i )
{
unsigned char b ( qb [ i ] ) ;
if ( ! ( ( b > 46 & & b < 58 ) | | ( b > 64 & & b < 91 ) | | ( b > 96 & & b < 123 ) | | b = = ' + ' | | b = = ' = ' ) )
{
std : : cerr < < " Character not allowed in radix: " < < b < < std : : endl ;
return false ;
}
}
std : : cerr < < " Radix check: passed " < < std : : endl ;
return true ;
}
bool RetroShareLink : : checkHash ( const QString & hash )
{
if ( hash . length ( ) ! = 40 )
return false ;
QByteArray qb ( hash . toLatin1 ( ) ) ;
for ( int i = 0 ; i < qb . length ( ) ; + + i )
{
unsigned char b ( qb [ i ] ) ;
if ( ! ( ( b > 47 & & b < 58 ) | | ( b > 96 & & b < 103 ) ) )
return false ;
}
return true ;
}
static void processList ( const QStringList & list , const QString & textSingular , const QString & textPlural , QString & result )
{
2014-10-21 18:33:02 -04:00
if ( list . isEmpty ( ) ) {
2014-05-08 03:52:28 -04:00
return ;
}
if ( list . size ( ) = = 1 ) {
result + = " " + textSingular + " : " ;
} else {
result + = " " + textPlural + " : " ;
}
result + = " <p style='margin-left: 5px; margin-top: 0px'> " ;
QStringList : : const_iterator it ;
for ( it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
if ( it ! = list . begin ( ) ) {
result + = " , " ;
}
result + = * it ;
}
result + = " </p> " ;
}
/*static*/ int RetroShareLink : : process ( const QList < RetroShareLink > & linksIn , uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/ )
{
QList < RetroShareLink > : : const_iterator linkIt ;
flag & = ~ RSLINK_PROCESS_NOTIFY_BAD_CHARS ; // this will be set below when needed
/* filter dublicate links */
QList < RetroShareLink > links ;
2014-10-21 18:33:02 -04:00
for ( linkIt = linksIn . begin ( ) ; linkIt ! = linksIn . end ( ) ; + + linkIt ) {
2014-05-08 03:52:28 -04:00
if ( links . contains ( * linkIt ) ) {
continue ;
}
links . append ( * linkIt ) ;
}
if ( flag & RSLINK_PROCESS_NOTIFY_ASK ) {
/* ask for some types of link */
QStringList fileAdd ;
QStringList personAdd ;
2014-10-21 18:33:02 -04:00
for ( linkIt = links . begin ( ) ; linkIt ! = links . end ( ) ; + + linkIt ) {
2014-05-08 03:52:28 -04:00
const RetroShareLink & link = * linkIt ;
if ( link . valid ( ) = = false ) {
continue ;
}
switch ( link . type ( ) ) {
case TYPE_UNKNOWN :
case TYPE_FORUM :
case TYPE_CHANNEL :
case TYPE_SEARCH :
case TYPE_MESSAGE :
case TYPE_CERTIFICATE :
case TYPE_PUBLIC_MSG :
2014-10-09 11:17:42 -04:00
case TYPE_PRIVATE_CHAT :
2014-05-08 03:52:28 -04:00
// no need to ask
break ;
case TYPE_FILE :
case TYPE_EXTRAFILE :
fileAdd . append ( link . name ( ) ) ;
break ;
case TYPE_PERSON :
personAdd . append ( PeerDefs : : rsid ( link . name ( ) . toUtf8 ( ) . constData ( ) , RsPgpId ( link . hash ( ) . toStdString ( ) ) ) ) ;
break ;
}
}
QString content ;
if ( fileAdd . size ( ) ) {
processList ( fileAdd , QObject : : tr ( " Add file " ) , QObject : : tr ( " Add files " ) , content ) ;
}
if ( personAdd . size ( ) ) {
processList ( personAdd , QObject : : tr ( " Add friend " ) , QObject : : tr ( " Add friends " ) , content ) ;
}
if ( content . isEmpty ( ) = = false ) {
QString question = " <html><body> " ;
if ( links . size ( ) = = 1 ) {
question + = QObject : : tr ( " Do you want to process the link ? " ) ;
} else {
question + = QObject : : tr ( " Do you want to process %1 links ? " ) . arg ( links . size ( ) ) ;
}
question + = " <br><br> " + content + " </body></html> " ;
QMessageBox mb ( QObject : : tr ( " Confirmation " ) , question , QMessageBox : : Question , QMessageBox : : Yes , QMessageBox : : No , 0 ) ;
if ( mb . exec ( ) = = QMessageBox : : No ) {
return 0 ;
}
}
}
int countInvalid = 0 ;
int countUnknown = 0 ;
bool needNotifySuccess = false ;
// file
QStringList fileAdded ;
QStringList fileExist ;
// person
QStringList personAdded ;
QStringList personExist ;
QStringList personFailed ;
QStringList personNotFound ;
// forum
QStringList forumFound ;
QStringList forumMsgFound ;
QStringList forumUnknown ;
QStringList forumMsgUnknown ;
// forum
QStringList channelFound ;
QStringList channelMsgFound ;
QStringList channelUnknown ;
QStringList channelMsgUnknown ;
// search
QStringList searchStarted ;
// message
QStringList messageStarted ;
QStringList messageReceipientNotAccepted ;
QStringList messageReceipientUnknown ;
// Certificate
QStringList GPGBase64Strings ;
QStringList SSLIds ;
// summary
QList < QStringList * > processedList ;
QList < QStringList * > errorList ;
processedList < < & fileAdded < < & personAdded < < & forumFound < < & channelFound < < & searchStarted < < & messageStarted ;
errorList < < & fileExist < < & personExist < < & personFailed < < & personNotFound < < & forumUnknown < < & forumMsgUnknown < < & channelUnknown < < & channelMsgUnknown < < & messageReceipientNotAccepted < < & messageReceipientUnknown ;
// not needed: forumFound, channelFound, messageStarted
2014-10-21 18:33:02 -04:00
for ( linkIt = links . begin ( ) ; linkIt ! = links . end ( ) ; + + linkIt ) {
2014-05-08 03:52:28 -04:00
const RetroShareLink & link = * linkIt ;
if ( link . valid ( ) = = false ) {
std : : cerr < < " RetroShareLink::process invalid request " < < std : : endl ;
2014-10-21 18:33:02 -04:00
+ + countInvalid ;
2014-05-08 03:52:28 -04:00
continue ;
}
switch ( link . type ( ) )
{
case TYPE_UNKNOWN :
2014-10-21 18:33:02 -04:00
+ + countUnknown ;
2014-05-08 03:52:28 -04:00
break ;
case TYPE_CERTIFICATE :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process certificate. " < < std : : endl ;
# endif
needNotifySuccess = true ;
std : : cerr < < " Usign this certificate: " < < std : : endl ;
std : : cerr < < link . radix ( ) . toStdString ( ) < < std : : endl ;
ConnectFriendWizard connectFriendWizard ;
connectFriendWizard . setCertificate ( link . radix ( ) , ( link . subType ( ) = = RSLINK_SUBTYPE_CERTIFICATE_USER_REQUEST ) ? true : false ) ;
connectFriendWizard . exec ( ) ;
needNotifySuccess = false ;
}
break ;
case TYPE_PUBLIC_MSG :
{
std : : cerr < < " (!!) Distant messages from links is disabled for now " < < std : : endl ;
// std::cerr << "Opening a public msg window " << std::endl;
// std::cerr << " time_stamp = " << link._time_stamp << std::endl;
// std::cerr << " hash = " << link._hash.toStdString() << std::endl;
// std::cerr << " Issuer Id = " << link._GPGid.toStdString() << std::endl;
//
// if(link._time_stamp < time(NULL))
// {
// QMessageBox::information(NULL,QObject::tr("Messaging link is expired"),QObject::tr("This Messaging link is expired. The destination peer will not receive it.")) ;
// break ;
// }
//
// MessageComposer::msgDistantPeer(link._hash.toStdString(),link._GPGid.toStdString()) ;
}
break ;
2014-05-25 17:43:05 -04:00
2014-05-08 03:52:28 -04:00
case TYPE_FILE :
case TYPE_EXTRAFILE :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process FileRequest : fileName : " < < link . name ( ) . toUtf8 ( ) . constData ( ) < < " . fileHash : " < < link . hash ( ) . toStdString ( ) < < " . fileSize : " < < link . size ( ) < < std : : endl ;
# endif
needNotifySuccess = true ;
std : : list < RsPeerId > srcIds ;
// Add the link built-in source. This is needed for EXTRA files, where the source is specified in the link.
if ( link . type ( ) = = TYPE_EXTRAFILE )
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process Adding built-in source " < < link . SSLId ( ) . toStdString ( ) < < std : : endl ;
# endif
srcIds . push_back ( RsPeerId ( link . SSLId ( ) . toStdString ( ) ) ) ;
}
// Get a list of available direct sources, in case the file is browsable only.
//
FileInfo finfo ;
rsFiles - > FileDetails ( RsFileHash ( link . hash ( ) . toStdString ( ) ) , RS_FILE_HINTS_REMOTE , finfo ) ;
for ( std : : list < TransferInfo > : : const_iterator it ( finfo . peers . begin ( ) ) ; it ! = finfo . peers . end ( ) ; + + it )
{
# ifdef DEBUG_RSLINK
std : : cerr < < " adding peerid " < < ( * it ) . peerId < < std : : endl ;
# endif
srcIds . push_back ( ( * it ) . peerId ) ;
}
QString cleanname = link . name ( ) ;
static const QString bad_chars_str = " / \\ \" *:?<>| " ;
for ( int i = 0 ; i < cleanname . length ( ) ; + + i )
for ( int j = 0 ; j < bad_chars_str . length ( ) ; + + j )
if ( cleanname [ i ] = = bad_chars_str [ j ] )
{
cleanname [ i ] = ' _ ' ;
flag | = RSLINK_PROCESS_NOTIFY_BAD_CHARS ;
}
if ( rsFiles - > FileRequest ( cleanname . toUtf8 ( ) . constData ( ) , RsFileHash ( link . hash ( ) . toStdString ( ) ) , link . size ( ) , " " , RS_FILE_REQ_ANONYMOUS_ROUTING , srcIds ) ) {
fileAdded . append ( link . name ( ) ) ;
} else {
fileExist . append ( link . name ( ) ) ;
}
break ;
}
case TYPE_PERSON :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process FriendRequest : name : " < < link . name ( ) . toStdString ( ) < < " . id : " < < link . hash ( ) . toStdString ( ) < < std : : endl ;
# endif
needNotifySuccess = true ;
RsPeerDetails detail ;
if ( rsPeers - > getPeerDetails ( RsPeerId ( link . hash ( ) . toStdString ( ) ) , detail ) )
{
if ( RsPgpId ( detail . gpg_id ) = = rsPeers - > getGPGOwnId ( ) ) {
// it's me, do nothing
break ;
}
if ( detail . accept_connection ) {
// peer connection is already accepted
personExist . append ( PeerDefs : : rsid ( detail ) ) ;
break ;
}
if ( rsPeers - > addFriend ( RsPeerId ( ) , RsPgpId ( link . hash ( ) . toStdString ( ) ) ) ) {
ConfCertDialog : : loadAll ( ) ;
personAdded . append ( PeerDefs : : rsid ( detail ) ) ;
break ;
}
personFailed . append ( PeerDefs : : rsid ( link . name ( ) . toUtf8 ( ) . constData ( ) , RsPgpId ( link . hash ( ) . toStdString ( ) ) ) ) ;
break ;
}
personNotFound . append ( PeerDefs : : rsid ( link . name ( ) . toUtf8 ( ) . constData ( ) , RsPgpId ( link . hash ( ) . toStdString ( ) ) ) ) ;
break ;
}
2014-05-27 17:14:05 -04:00
2014-05-08 03:52:28 -04:00
case TYPE_FORUM :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process ForumRequest : name : " < < link . name ( ) . toStdString ( ) < < " . id : " < < link . hash ( ) . toStdString ( ) < < " . msgId : " < < link . msgId ( ) . toStdString ( ) < < std : : endl ;
# endif
2014-05-27 17:14:05 -04:00
MainWindow : : showWindow ( MainWindow : : Forums ) ;
GxsForumsDialog * forumsDialog = dynamic_cast < GxsForumsDialog * > ( MainWindow : : getPage ( MainWindow : : Forums ) ) ;
2014-05-08 03:52:28 -04:00
if ( ! forumsDialog ) {
return false ;
}
2014-05-27 17:14:05 -04:00
if ( forumsDialog - > navigate ( RsGxsGroupId ( link . id ( ) . toStdString ( ) ) , RsGxsMessageId ( link . msgId ( ) . toStdString ( ) ) ) ) {
2014-05-08 03:52:28 -04:00
if ( link . msgId ( ) . isEmpty ( ) ) {
forumFound . append ( link . name ( ) ) ;
} else {
forumMsgFound . append ( link . name ( ) ) ;
}
} else {
if ( link . msgId ( ) . isEmpty ( ) ) {
forumUnknown . append ( link . name ( ) ) ;
} else {
forumMsgUnknown . append ( link . name ( ) ) ;
}
}
break ;
}
2014-05-27 17:14:05 -04:00
#if 0
2014-05-08 03:52:28 -04:00
case TYPE_CHANNEL :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process ChannelRequest : name : " < < link . name ( ) . toStdString ( ) < < " . id : " < < link . hash ( ) . toStdString ( ) < < " . msgId : " < < link . msgId ( ) . toStdString ( ) < < std : : endl ;
# endif
ChannelInfo ci ;
if ( ! rsChannels - > getChannelInfo ( link . id ( ) . toStdString ( ) , ci ) ) {
if ( link . msgId ( ) . isEmpty ( ) ) {
channelUnknown . append ( link . name ( ) ) ;
} else {
channelMsgUnknown . append ( link . name ( ) ) ;
}
break ;
}
ChannelMsgInfo msg ;
if ( ! link . msgId ( ) . isEmpty ( ) ) {
if ( ! rsChannels - > getChannelMessage ( ci . channelId , link . msgId ( ) . toStdString ( ) , msg ) ) {
channelMsgUnknown . append ( link . name ( ) ) ;
break ;
}
}
MainWindow : : showWindow ( MainWindow : : Channels ) ;
ChannelFeed * channelFeed = dynamic_cast < ChannelFeed * > ( MainWindow : : getPage ( MainWindow : : Channels ) ) ;
if ( ! channelFeed ) {
return false ;
}
if ( channelFeed - > navigate ( ci . channelId , msg . msgId ) ) {
if ( link . msgId ( ) . isEmpty ( ) ) {
channelFound . append ( link . name ( ) ) ;
} else {
channelMsgFound . append ( link . name ( ) ) ;
}
} else {
if ( link . msgId ( ) . isEmpty ( ) ) {
channelUnknown . append ( link . name ( ) ) ;
} else {
channelMsgUnknown . append ( link . name ( ) ) ;
}
}
break ;
}
# endif
case TYPE_SEARCH :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process SearchRequest : string : " < < link . name ( ) . toStdString ( ) < < std : : endl ;
# endif
SearchDialog * searchDialog = dynamic_cast < SearchDialog * > ( MainWindow : : getPage ( MainWindow : : Search ) ) ;
if ( ! searchDialog )
{
std : : cerr < < " Retrieve of search dialog failed. Please debug! " < < std : : endl ;
break ;
}
MainWindow : : showWindow ( MainWindow : : Search ) ;
searchDialog - > searchKeywords ( link . name ( ) ) ;
searchStarted . append ( link . name ( ) ) ;
break ;
}
case TYPE_MESSAGE :
{
# ifdef DEBUG_RSLINK
std : : cerr < < " RetroShareLink::process MessageRequest : id : " < < link . hash ( ) . toStdString ( ) < < " , subject : " < < link . name ( ) . toStdString ( ) < < std : : endl ;
# endif
RsPeerDetails detail ;
DistantMsgPeerId dm_pid ;
// This is awful, but apparently the hash can be multiple different types. Let's check!
RsPeerId ssl_id ( link . hash ( ) . toStdString ( ) ) ;
if ( ! ssl_id . isNull ( ) & & rsPeers - > getPeerDetails ( ssl_id , detail ) & & detail . accept_connection )
{
MessageComposer * msg = MessageComposer : : newMsg ( ) ;
msg - > addRecipient ( MessageComposer : : TO , detail . id ) ;
if ( link . subject ( ) . isEmpty ( ) = = false ) {
msg - > setTitleText ( link . subject ( ) ) ;
}
msg - > show ( ) ;
messageStarted . append ( PeerDefs : : nameWithLocation ( detail ) ) ;
break ;
}
RsIdentityDetails gxs_details ;
RsGxsId gxs_id ( link . hash ( ) . toStdString ( ) ) ;
if ( ! gxs_id . isNull ( ) & & rsIdentity - > getIdDetails ( gxs_id , gxs_details ) )
{
2014-05-08 04:39:04 -04:00
if ( gxs_details . mIsOwnId )
{
QMessageBox : : warning ( NULL , QString ( " Cannot send message to yourself " ) , QString ( " This identity is owned by you. You wouldn't want to send yourself a message right? " ) ) ;
break ;
}
2014-05-08 03:52:28 -04:00
MessageComposer * msg = MessageComposer : : newMsg ( ) ;
msg - > addRecipient ( MessageComposer : : TO , gxs_id ) ;
if ( link . subject ( ) . isEmpty ( ) = = false )
msg - > setTitleText ( link . subject ( ) ) ;
msg - > show ( ) ;
messageStarted . append ( PeerDefs : : nameWithLocation ( gxs_details ) ) ;
break ;
}
messageReceipientUnknown . append ( PeerDefs : : rsidFromId ( RsPeerId ( link . hash ( ) . toStdString ( ) ) ) ) ;
}
break ;
default :
std : : cerr < < " RetroShareLink::process unknown type: " < < link . type ( ) < < std : : endl ;
2014-10-21 18:33:02 -04:00
+ + countUnknown ;
2014-05-08 03:52:28 -04:00
}
}
int countProcessed = 0 ;
int countError = 0 ;
QList < QStringList * > : : iterator listIt ;
for ( listIt = processedList . begin ( ) ; listIt ! = processedList . end ( ) ; + + listIt ) {
countProcessed + = ( * listIt ) - > size ( ) ;
}
for ( listIt = errorList . begin ( ) ; listIt ! = errorList . end ( ) ; + + listIt ) {
countError + = ( * listIt ) - > size ( ) ;
}
// success notify needed ?
if ( needNotifySuccess = = false ) {
flag & = ~ RSLINK_PROCESS_NOTIFY_SUCCESS ;
}
// error notify needed ?
if ( countError = = 0 ) {
flag & = ~ RSLINK_PROCESS_NOTIFY_ERROR ;
}
QString result ;
if ( flag & ( RSLINK_PROCESS_NOTIFY_SUCCESS | RSLINK_PROCESS_NOTIFY_ERROR ) ) {
result + = ( links . count ( ) = = 1 ? QObject : : tr ( " %1 of %2 RetroShare link processed. " ) : QObject : : tr ( " %1 of %2 RetroShare links processed. " ) ) . arg ( countProcessed ) . arg ( links . count ( ) ) + " <br><br> " ;
}
// file
if ( flag & RSLINK_PROCESS_NOTIFY_SUCCESS ) {
if ( fileAdded . size ( ) ) {
processList ( fileAdded , QObject : : tr ( " File added " ) , QObject : : tr ( " Files added " ) , result ) ;
}
}
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
if ( fileExist . size ( ) ) {
processList ( fileExist , QObject : : tr ( " File exist " ) , QObject : : tr ( " Files exist " ) , result ) ;
}
}
// person
if ( flag & RSLINK_PROCESS_NOTIFY_SUCCESS ) {
if ( personAdded . size ( ) ) {
processList ( personAdded , QObject : : tr ( " Friend added " ) , QObject : : tr ( " Friends added " ) , result ) ;
}
}
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
if ( personExist . size ( ) ) {
processList ( personExist , QObject : : tr ( " Friend exist " ) , QObject : : tr ( " Friends exist " ) , result ) ;
}
if ( personFailed . size ( ) ) {
processList ( personFailed , QObject : : tr ( " Friend not added " ) , QObject : : tr ( " Friends not added " ) , result ) ;
}
if ( personNotFound . size ( ) ) {
processList ( personNotFound , QObject : : tr ( " Friend not found " ) , QObject : : tr ( " Friends not found " ) , result ) ;
}
}
// forum
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
if ( forumUnknown . size ( ) ) {
processList ( forumUnknown , QObject : : tr ( " Forum not found " ) , QObject : : tr ( " Forums not found " ) , result ) ;
}
if ( forumMsgUnknown . size ( ) ) {
processList ( forumMsgUnknown , QObject : : tr ( " Forum message not found " ) , QObject : : tr ( " Forum messages not found " ) , result ) ;
}
}
// channel
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
if ( channelUnknown . size ( ) ) {
processList ( channelUnknown , QObject : : tr ( " Channel not found " ) , QObject : : tr ( " Channels not found " ) , result ) ;
}
if ( channelMsgUnknown . size ( ) ) {
processList ( channelMsgUnknown , QObject : : tr ( " Channel message not found " ) , QObject : : tr ( " Channel messages not found " ) , result ) ;
}
}
// message
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
if ( messageReceipientNotAccepted . size ( ) ) {
processList ( messageReceipientNotAccepted , QObject : : tr ( " Recipient not accepted " ) , QObject : : tr ( " Recipients not accepted " ) , result ) ;
}
if ( messageReceipientUnknown . size ( ) ) {
processList ( messageReceipientUnknown , QObject : : tr ( " Unkown recipient " ) , QObject : : tr ( " Unkown recipients " ) , result ) ;
}
}
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
if ( countUnknown ) {
result + = QString ( " <br>%1: %2 " ) . arg ( QObject : : tr ( " Malformed links " ) ) . arg ( countUnknown ) ;
}
if ( countInvalid ) {
result + = QString ( " <br>%1: %2 " ) . arg ( QObject : : tr ( " Invalid links " ) ) . arg ( countInvalid ) ;
}
}
if ( flag & RSLINK_PROCESS_NOTIFY_BAD_CHARS )
result + = QString ( " <br>%1 " ) . arg ( QObject : : tr ( " Warning: forbidden characters found in filenames. \n Characters <b> \" ,|,/, \\ ,<,>,*,?</b> will be replaced by '_'. " ) ) ;
if ( result . isEmpty ( ) = = false ) {
QMessageBox mb ( QObject : : tr ( " Result " ) , " <html><body> " + result + " </body></html> " , QMessageBox : : Information , QMessageBox : : Ok , 0 , 0 ) ;
mb . exec ( ) ;
}
return 0 ;
}
/*static*/ int RetroShareLink : : process ( const QStringList & urls , RetroShareLink : : enumType type /* = RetroShareLink::TYPE_UNKNOWN*/ , uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/ )
{
QList < RetroShareLink > links ;
2014-10-21 18:33:02 -04:00
for ( QStringList : : const_iterator it = urls . begin ( ) ; it ! = urls . end ( ) ; + + it ) {
2014-05-08 03:52:28 -04:00
RetroShareLink link ( * it ) ;
if ( link . valid ( ) & & ( type = = RetroShareLink : : TYPE_UNKNOWN | | link . type ( ) = = type ) ) {
links . append ( link ) ;
}
}
return process ( links , flag ) ;
}
void RSLinkClipboard : : copyLinks ( const QList < RetroShareLink > & links )
{
QString res ;
for ( int i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toString ( ) + " \n " ;
QApplication : : clipboard ( ) - > setText ( res ) ;
}
void RSLinkClipboard : : pasteLinks ( QList < RetroShareLink > & links )
{
return parseClipboard ( links ) ;
}
void RSLinkClipboard : : parseClipboard ( QList < RetroShareLink > & links )
{
// parse clipboard for links.
//
links . clear ( ) ;
QString text = QApplication : : clipboard ( ) - > text ( ) ;
std : : cerr < < " Parsing clipboard: " < < text . toStdString ( ) < < std : : endl ;
QRegExp rx ( QString ( " retroshare://(%1) [ ^ \ r \ n ] + " ).arg(HOST_REGEXP)) ;
int pos = 0 ;
while ( ( pos = rx . indexIn ( text , pos ) ) ! = - 1 )
{
QString url ( text . mid ( pos , rx . matchedLength ( ) ) ) ;
RetroShareLink link ( url ) ;
if ( link . valid ( ) )
{
// check that the link is not already in the list:
bool already = false ;
for ( int i = 0 ; i < links . size ( ) ; + + i )
if ( links [ i ] = = link )
{
already = true ;
break ;
}
if ( ! already )
{
links . push_back ( link ) ;
# ifdef DEBUG_RSLINK
std : : cerr < < " captured link: " < < link . toString ( ) . toStdString ( ) < < std : : endl ;
# endif
}
}
# ifdef DEBUG_RSLINK
else
std : : cerr < < " invalid link " < < std : : endl ;
# endif
pos + = rx . matchedLength ( ) ;
}
}
QString RSLinkClipboard : : toString ( )
{
QList < RetroShareLink > links ;
parseClipboard ( links ) ;
QString res ;
for ( int i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toString ( ) + " \n " ;
return res ;
}
QString RSLinkClipboard : : toHtml ( )
{
QList < RetroShareLink > links ;
parseClipboard ( links ) ;
QString res ;
for ( int i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toHtml ( ) + " <br> " ;
return res ;
}
bool RSLinkClipboard : : empty ( RetroShareLink : : enumType type /* = RetroShareLink::TYPE_UNKNOWN*/ )
{
QList < RetroShareLink > links ;
parseClipboard ( links ) ;
if ( type = = RetroShareLink : : TYPE_UNKNOWN ) {
return links . empty ( ) ;
}
2014-10-21 18:33:02 -04:00
for ( QList < RetroShareLink > : : iterator link = links . begin ( ) ; link ! = links . end ( ) ; + + link ) {
2014-05-08 03:52:28 -04:00
if ( link - > type ( ) = = type ) {
return false ;
}
}
return true ;
}
/*static*/ int RSLinkClipboard : : process ( RetroShareLink : : enumType type /* = RetroShareLink::TYPE_UNKNOWN*/ , uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/ )
{
QList < RetroShareLink > links ;
pasteLinks ( links ) ;
QList < RetroShareLink > linksToProcess ;
2014-10-21 18:33:02 -04:00
for ( int i = 0 ; i < links . size ( ) ; + + i ) {
2014-05-08 03:52:28 -04:00
if ( links [ i ] . valid ( ) & & ( type = = RetroShareLink : : TYPE_UNKNOWN | | links [ i ] . type ( ) = = type ) ) {
linksToProcess . append ( links [ i ] ) ;
}
}
2014-10-21 18:33:02 -04:00
if ( linksToProcess . isEmpty ( ) ) {
2014-05-08 03:52:28 -04:00
return 0 ;
}
return RetroShareLink : : process ( linksToProcess , flag ) ;
}