2010-03-10 16:38:26 -05: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 <QStringList>
2010-03-22 15:46:58 -04:00
# include <QRegExp>
# include <QApplication>
# include <QMimeData>
# include <QClipboard>
2010-07-15 07:25:34 -04:00
# include <QDesktopServices>
# include <QMessageBox>
# include <QIcon>
# include <QObject>
2010-03-10 16:38:26 -05:00
# include "RetroShareLink.h"
2010-07-15 07:25:34 -04:00
# include "rsiface/rsfiles.h"
# include "rsiface/rspeers.h"
2010-03-10 16:38:26 -05:00
# define DEBUG_RSLINK 1
2010-07-15 07:25:34 -04:00
# define HEADER_FILE "retroshare: //file"
# define HEADER_PERSON "retroshare: //person"
2010-03-10 16:38:26 -05:00
2010-03-10 18:09:35 -05:00
RetroShareLink : : RetroShareLink ( const QUrl & url )
2010-03-10 16:38:26 -05:00
{
2010-07-15 07:25:34 -04:00
const QString stringurl = url . toString ( ) ;
fromString ( stringurl ) ;
}
RetroShareLink : : RetroShareLink ( const QString & url )
{
fromString ( url ) ;
}
void RetroShareLink : : fromString ( const QString & url )
{
_valid = false ;
// parse
2010-03-10 16:38:26 -05:00
# ifdef DEBUG_RSLINK
2010-07-15 07:25:34 -04:00
std : : cerr < < " got new RS link \" " < < url . toStdString ( ) < < " \" " < < std : : endl ;
2010-03-10 16:38:26 -05:00
# endif
2010-07-15 07:25:34 -04:00
QStringList list = url . split ( " | " ) ;
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
if ( list . size ( ) > = 1 ) {
if ( list . size ( ) = = 4 & & list [ 0 ] = = HEADER_FILE ) {
bool ok ;
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
_type = TYPE_FILE ;
_name = list [ 1 ] ;
_size = list [ 2 ] . toULongLong ( & ok ) ;
_hash = list [ 3 ] . left ( 40 ) ; // normally not necessary, but it's a security.
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
if ( ok ) {
2010-03-10 16:38:26 -05:00
# ifdef DEBUG_RSLINK
2010-07-15 07:25:34 -04:00
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 ;
2010-03-10 16:38:26 -05:00
# endif
2010-07-15 07:25:34 -04:00
check ( ) ;
return ;
}
} else if ( list . size ( ) = = 3 & & list [ 0 ] = = HEADER_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
}
2010-03-10 16:38:26 -05:00
# ifdef DEBUG_RSLINK
2010-07-15 07:25:34 -04:00
std : : cerr < < " Wrongly formed RS link. Can't process. " < < std : : endl ;
2010-03-10 16:38:26 -05:00
# endif
2010-07-15 07:25:34 -04:00
_type = TYPE_UNKNOWN ;
_hash = " " ;
_size = 0 ;
_name = " " ;
2010-03-10 16:38:26 -05:00
}
RetroShareLink : : RetroShareLink ( const QString & name , uint64_t size , const QString & hash )
2010-07-15 07:25:34 -04:00
: _name ( name ) , _size ( size ) , _hash ( hash )
2010-03-10 16:38:26 -05:00
{
2010-07-15 07:25:34 -04:00
_valid = false ;
_type = TYPE_FILE ;
check ( ) ;
2010-03-10 16:38:26 -05:00
}
2010-07-15 07:25:34 -04:00
RetroShareLink : : RetroShareLink ( const QString & name , const QString & hash )
: _name ( name ) , _size ( 0 ) , _hash ( hash )
2010-03-10 16:38:26 -05:00
{
2010-07-15 07:25:34 -04:00
_valid = false ;
_type = TYPE_PERSON ;
check ( ) ;
}
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
void RetroShareLink : : check ( )
{
_valid = true ;
switch ( _type ) {
case TYPE_UNKNOWN :
_valid = false ;
break ;
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_PERSON :
if ( _size ! = 0 )
_valid = false ;
if ( _name . isEmpty ( ) )
_valid = false ;
if ( _hash . isEmpty ( ) )
_valid = false ;
break ;
}
if ( ! _valid ) // we should throw an exception instead of this crap, but drbob doesn't like exceptions. Why ???
{
_type = TYPE_UNKNOWN ;
_hash = " " ;
_name = " " ;
_size = 0 ;
}
2010-03-10 16:38:26 -05:00
}
QString RetroShareLink : : toString ( ) const
{
2010-07-15 07:25:34 -04:00
switch ( _type ) {
case TYPE_UNKNOWN :
break ;
case TYPE_FILE :
return QString ( HEADER_FILE ) + " | " + _name + " | " + QString : : number ( _size ) + " | " + _hash ;
case TYPE_PERSON :
return QString ( HEADER_PERSON ) + " | " + _name + " | " + _hash ;
}
return " " ;
2010-03-10 16:38:26 -05:00
}
2010-07-15 07:25:34 -04:00
QString RetroShareLink : : niceName ( ) const
{
if ( type ( ) = = TYPE_PERSON ) {
return name ( ) + " @ " + hash ( ) ;
}
return name ( ) ;
}
2010-03-15 08:57:08 -04:00
QString RetroShareLink : : toHtml ( ) const
2010-03-22 15:46:58 -04:00
{
2010-07-15 07:25:34 -04:00
return QString ( " <a href=' " ) + toString ( ) + " '> " + niceName ( ) + " </a> " ;
2010-03-22 15:46:58 -04:00
}
2010-07-15 07:25:34 -04:00
2010-03-22 15:46:58 -04:00
QString RetroShareLink : : toHtmlFull ( ) const
2010-03-15 08:57:08 -04:00
{
2010-07-15 07:25:34 -04:00
return QString ( " <a href=' " ) + toString ( ) + " '> " + toString ( ) + " </a> " ;
2010-03-15 08:57:08 -04:00
}
2010-03-10 16:38:26 -05:00
bool RetroShareLink : : checkName ( const QString & name )
{
2010-07-15 07:25:34 -04:00
if ( name = = " " )
return false ;
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
for ( int i = 0 ; i < name . length ( ) ; + + i )
{
QChar : : Category cat ( name [ i ] . category ( ) ) ;
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
if ( cat = = QChar : : Separator_Line
| | cat = = QChar : : Other_NotAssigned
)
{
2010-03-10 16:38:26 -05:00
# ifdef DEBUG_RSLINK
2010-07-15 07:25:34 -04:00
std : : cerr < < " Unwanted category " < < cat < < " at place " < < i < < " in string \" " < < name . toStdString ( ) < < " \" " < < std : : endl ;
2010-03-10 16:38:26 -05:00
# endif
2010-07-15 07:25:34 -04:00
return false ;
}
}
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
return true ;
2010-03-10 16:38:26 -05:00
}
2010-03-10 18:09:35 -05:00
QUrl RetroShareLink : : toUrl ( ) const
{
2010-07-15 07:25:34 -04:00
return QUrl ( toString ( ) ) ;
2010-03-10 18:09:35 -05:00
}
2010-03-10 16:38:26 -05:00
bool RetroShareLink : : checkHash ( const QString & hash )
{
2010-07-15 07:25:34 -04:00
if ( hash . length ( ) ! = 40 )
return false ;
QByteArray qb ( hash . toAscii ( ) ) ;
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
for ( int i = 0 ; i < qb . length ( ) ; + + i )
{
unsigned char b ( qb [ i ] ) ;
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
if ( ! ( ( b > 47 & & b < 58 ) | | ( b > 96 & & b < 103 ) ) )
return false ;
}
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
return true ;
}
2010-03-10 16:38:26 -05:00
2010-07-15 07:25:34 -04:00
bool RetroShareLink : : process ( std : : list < std : : string > * psrcIds , int flag )
{
if ( valid ( ) = = false ) {
std : : cerr < < " RetroShareLink::process invalid request " < < std : : endl ;
return false ;
}
switch ( type ( ) ) {
case TYPE_UNKNOWN :
break ;
case TYPE_FILE :
{
std : : cerr < < " RetroShareLink::process FileRequest : fileName : " < < name ( ) . toStdString ( ) < < " . fileHash : " < < hash ( ) . toStdString ( ) < < " . fileSize : " < < size ( ) < < std : : endl ;
std : : list < std : : string > srcIds ;
if ( psrcIds ) {
srcIds = * psrcIds ;
}
// I removed the NETWORK WIDE flag. Indeed, somebody can capture the turtle tunnel requests and ask for downloading the file while
// it's being downloaded (as partial files are always sources).
//
if ( rsFiles - > FileRequest ( name ( ) . toStdString ( ) , hash ( ) . toStdString ( ) , size ( ) , " " , 0 /*RS_FILE_HINTS_NETWORK_WIDE*/ , srcIds ) ) {
if ( flag & RSLINK_PROCESS_NOTIFY_SUCCESS ) {
QMessageBox mb ( QObject : : tr ( " File Request Confirmation " ) , QObject : : tr ( " The file has been added to your download list. " ) , QMessageBox : : Information , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return true ;
}
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
QMessageBox mb ( QObject : : tr ( " File Request canceled " ) , QObject : : tr ( " The file has not been added to your download list, because you already have it. " ) , QMessageBox : : Critical , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return false ;
}
case TYPE_PERSON :
{
std : : cerr < < " RetroShareLink::process FriendRequest : name : " < < name ( ) . toStdString ( ) < < " . id : " < < hash ( ) . toStdString ( ) < < std : : endl ;
RsPeerDetails detail ;
if ( rsPeers - > getPeerDetails ( hash ( ) . toStdString ( ) , detail ) ) {
if ( detail . gpg_id = = rsPeers - > getGPGOwnId ( ) ) {
// it's me, do nothing
return true ;
}
if ( detail . accept_connection ) {
// peer connection is already accepted
if ( flag & RSLINK_PROCESS_NOTIFY_SUCCESS ) {
QMessageBox mb ( QObject : : tr ( " Friend Request Confirmation " ) , QObject : : tr ( " The friend is already in your list. " ) , QMessageBox : : Information , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return true ;
}
if ( rsPeers - > setAcceptToConnectGPGCertificate ( hash ( ) . toStdString ( ) , true ) ) {
if ( flag & RSLINK_PROCESS_NOTIFY_SUCCESS ) {
QMessageBox mb ( QObject : : tr ( " Friend Request Confirmation " ) , QObject : : tr ( " The friend has been added to your list. " ) , QMessageBox : : Information , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return true ;
}
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
QMessageBox mb ( QObject : : tr ( " Friend Request canceled " ) , QObject : : tr ( " The friend could not be added to your list. " ) , QMessageBox : : Critical , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return false ;
}
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
QMessageBox mb ( QObject : : tr ( " Friend Request canceled " ) , QObject : : tr ( " The friend could not be found. " ) , QMessageBox : : Critical , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return false ;
}
}
std : : cerr < < " RetroShareLink::process unknown type: " < < type ( ) < < std : : endl ;
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
QMessageBox mb ( QObject : : tr ( " File Request Error " ) , QObject : : tr ( " The file link is malformed. " ) , QMessageBox : : Critical , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
return false ;
2010-03-10 16:38:26 -05:00
}
2010-07-15 07:25:34 -04:00
/*static*/ bool RetroShareLink : : processUrl ( const QUrl & url , std : : list < std : : string > * psrcIds , int flag )
{
if ( url . scheme ( ) = = " http " ) {
QDesktopServices : : openUrl ( url ) ;
return true ;
}
if ( url . scheme ( ) = = " retroshare " ) {
// QUrl can't handle the RetroShare link format properly
if ( flag & RSLINK_PROCESS_NOTIFY_ERROR ) {
QMessageBox mb ( QObject : : tr ( " File Request " ) , QObject : : tr ( " Process of RetroShare links is not implemented. Please use copy instead. " ) , QMessageBox : : Critical , QMessageBox : : Ok , 0 , 0 ) ;
mb . setButtonText ( QMessageBox : : Ok , " OK " ) ;
mb . setWindowIcon ( QIcon ( QString : : fromUtf8 ( " :/images/rstray3.png " ) ) ) ;
mb . exec ( ) ;
}
// RetroShareLink link(url);
//
// if (link.valid()) {
// return link.process(psrcId, flag);
// }
//
// if (flag & RSLINK_PROCESS_NOTIFY_ERROR) {
// QMessageBox mb(QObject::tr("File Request Error"), QObject::tr("The file link is malformed."),QMessageBox::Information,QMessageBox::Ok,0,0);
//second version: QMessageBox mb(QObject::tr("Badly formed RS link"), QObject::tr("This RetroShare link is malformed. This is bug. Please contact the developers.\n\nNote: this possibly comes from a bug in Qt4.6. Try to right-click + copy link location, and paste in Transfer Tab."),QMessageBox::Critical,QMessageBox::Ok,0,0);
// mb.setButtonText( QMessageBox::Ok, "OK" );
// mb.setWindowIcon(QIcon(QString::fromUtf8(":/images/rstray3.png")));
// mb.exec();
// }
return false ;
}
if ( url . scheme ( ) . isEmpty ( ) ) {
//it's probably a web adress, let's add http:// at the beginning of the link
QString newAddress = " http:// " + url . toString ( ) ;
QDesktopServices : : openUrl ( QUrl ( newAddress ) ) ;
return true ;
}
return false ;
}
2010-03-22 15:46:58 -04:00
void RSLinkClipboard : : copyLinks ( const std : : vector < RetroShareLink > & links )
{
2010-07-15 07:25:34 -04:00
QString res ;
for ( uint32_t i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toString ( ) + " \n " ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
QApplication : : clipboard ( ) - > setText ( res ) ;
2010-03-22 15:46:58 -04:00
}
2010-07-15 07:25:34 -04:00
void RSLinkClipboard : : pasteLinks ( std : : vector < RetroShareLink > & links )
2010-03-22 15:46:58 -04:00
{
2010-07-15 07:25:34 -04:00
return parseClipboard ( links ) ;
2010-03-22 15:46:58 -04:00
}
2010-07-15 07:25:34 -04:00
void RSLinkClipboard : : parseClipboard ( std : : vector < RetroShareLink > & links )
2010-03-22 15:46:58 -04:00
{
2010-07-15 07:25:34 -04:00
// parse clipboard for links.
//
links . clear ( ) ;
QString text = QApplication : : clipboard ( ) - > text ( ) ;
std : : cerr < < " Parsing clipboard: " < < text . toStdString ( ) < < std : : endl ;
QRegExp rx ( " retroshare://(file|person) [ ^ \ r \ n ] + " ) ;
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 ( uint32_t i = 0 ; i < links . size ( ) ; + + i )
if ( links [ i ] = = link )
{
already = true ;
break ;
}
if ( ! already )
{
links . push_back ( link ) ;
std : : cerr < < " captured link: " < < link . toString ( ) . toStdString ( ) < < std : : endl ;
}
}
else
std : : cerr < < " invalid link " < < std : : endl ;
pos + = rx . matchedLength ( ) ;
}
2010-03-22 15:46:58 -04:00
}
QString RSLinkClipboard : : toString ( )
{
2010-07-15 07:25:34 -04:00
std : : vector < RetroShareLink > links ;
parseClipboard ( links ) ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
QString res ;
for ( uint32_t i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toString ( ) + " \n " ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
return res ;
2010-03-22 15:46:58 -04:00
}
QString RSLinkClipboard : : toHtml ( )
{
2010-07-15 07:25:34 -04:00
std : : vector < RetroShareLink > links ;
parseClipboard ( links ) ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
QString res ;
for ( uint32_t i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toHtml ( ) + " <br/> " ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
return res ;
2010-03-22 15:46:58 -04:00
}
2010-07-15 07:25:34 -04:00
2010-03-22 15:46:58 -04:00
QString RSLinkClipboard : : toHtmlFull ( )
{
2010-07-15 07:25:34 -04:00
std : : vector < RetroShareLink > links ;
parseClipboard ( links ) ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
QString res ;
for ( uint32_t i = 0 ; i < links . size ( ) ; + + i )
res + = links [ i ] . toHtmlFull ( ) + " <br/> " ;
2010-03-22 15:46:58 -04:00
2010-07-15 07:25:34 -04:00
return res ;
2010-03-22 15:46:58 -04:00
}
2010-07-15 07:25:34 -04:00
bool RSLinkClipboard : : empty ( RetroShareLink : : enumType type /*= RetroShareLink::TYPE_UNKNOWN*/ )
2010-03-22 15:46:58 -04:00
{
2010-07-15 07:25:34 -04:00
std : : vector < RetroShareLink > links ;
parseClipboard ( links ) ;
if ( type = = RetroShareLink : : TYPE_UNKNOWN ) {
return links . empty ( ) ;
}
for ( std : : vector < RetroShareLink > : : iterator link = links . begin ( ) ; link ! = links . end ( ) ; link + + ) {
if ( link - > type ( ) = = type ) {
return false ;
}
}
return true ;
2010-03-22 15:46:58 -04:00
}
2010-07-15 07:25:34 -04:00
/*static*/ int RSLinkClipboard : : process ( RetroShareLink : : enumType type /*= RetroShareLink::TYPE_UNKNOWN*/ , int flag /*= RSLINK_PROCESS_NOTIFY_ALL*/ )
{
std : : vector < RetroShareLink > links ;
pasteLinks ( links ) ;
int count = 0 ;
for ( uint32_t i = 0 ; i < links . size ( ) ; i + + ) {
if ( links [ i ] . valid ( ) & & ( type = = RetroShareLink : : TYPE_UNKNOWN | | links [ i ] . type ( ) = = type ) ) {
if ( links [ i ] . process ( NULL , flag ) ) {
count + + ;
}
}
}
return count ;
}