@ -43,13 +43,16 @@
# include "nel/misc/md5.h"
# include "nel/3d/texture_file.h"
# include "nel/misc/big_file.h"
# include <libxml/uri.h>
using namespace std ;
using namespace NLMISC ;
// Default timeout to connect a server
# define DEFAULT_RYZOM_CONNECTION_TIMEOUT (10.0)
# define DEFAULT_RYZOM_CONNECTION_TIMEOUT (30.0)
// Allow up to 10 redirects, then give up
# define DEFAULT_RYZOM_REDIRECT_LIMIT (10)
namespace NLGUI
{
@ -60,6 +63,59 @@ namespace NLGUI
CGroupHTML : : SWebOptions CGroupHTML : : options ;
// Active cURL www transfer
class CCurlWWWData
{
public :
CCurlWWWData ( CURL * curl , const std : : string & url )
: Request ( curl ) , Url ( url ) , Content ( " " ) , HeadersSent ( NULL )
{
}
~ CCurlWWWData ( )
{
if ( Request )
curl_easy_cleanup ( Request ) ;
if ( HeadersSent )
curl_slist_free_all ( HeadersSent ) ;
}
void setRecvHeader ( const std : : string & header )
{
size_t pos = header . find ( " : " ) ;
if ( pos = = std : : string : : npos )
return ;
std : : string key = toLower ( header . substr ( 0 , pos ) ) ;
if ( pos ! = std : : string : : npos )
{
HeadersRecv [ key ] = header . substr ( pos + 2 ) ;
//nlinfo(">> received header '%s' = '%s'", key.c_str(), HeadersRecv[key].c_str());
}
}
// return last received "Location: <url>" header or empty string if no header set
const std : : string getLocationHeader ( )
{
if ( HeadersRecv . count ( " location " ) > 0 )
return HeadersRecv [ " location " ] ;
return " " ;
}
public :
CURL * Request ;
std : : string Url ;
std : : string Content ;
// headers sent with curl request, must be released after transfer
curl_slist * HeadersSent ;
// headers received from curl transfer
std : : map < std : : string , std : : string > HeadersRecv ;
} ;
// Check if domain is on TrustedDomain
bool CGroupHTML : : isTrustedDomain ( const string & domain )
{
@ -285,7 +341,7 @@ namespace NLGUI
{
//nlassert(_CrtCheckMemory());
if ( RunningCurls = = 0 )
if ( Curls. empty ( ) & & _CurlWWW = = NULL )
return ;
int NewRunningCurls = 0 ;
@ -306,8 +362,82 @@ namespace NLGUI
int msgs_left ;
while ( ( msg = curl_multi_info_read ( MultiCurl , & msgs_left ) ) )
{
# ifdef LOG_DL
nlwarning ( " > (%s) msgs_left %d " , _Id . c_str ( ) , msgs_left ) ;
# endif
if ( msg - > msg = = CURLMSG_DONE )
{
if ( _CurlWWW & & _CurlWWW - > Request & & _CurlWWW - > Request = = msg - > easy_handle )
{
CURLcode res = msg - > data . result ;
long code ;
curl_easy_getinfo ( _CurlWWW - > Request , CURLINFO_RESPONSE_CODE , & code ) ;
# ifdef LOG_DL
nlwarning ( " (%s) web transfer '%p' completed with status %d, http %d, url (len %d) '%s' " , _Id . c_str ( ) , _CurlWWW - > Request , res , code , _CurlWWW - > Url . size ( ) , _CurlWWW - > Url . c_str ( ) ) ;
# endif
if ( res ! = CURLE_OK )
{
browseError ( string ( " Connection failed with curl error " + string ( curl_easy_strerror ( res ) ) ) . c_str ( ) ) ;
}
else
if ( ( code > = 301 & & code < = 303 ) | | code = = 307 | | code = = 308 )
{
if ( _RedirectsRemaining < 0 )
{
browseError ( string ( " Redirect limit reached : " + _URL ) . c_str ( ) ) ;
}
else
{
// redirect, get the location and try browse again
// we cant use curl redirection because 'addHTTPGetParams()' must be called on new destination
std : : string location ( _CurlWWW - > getLocationHeader ( ) ) ;
if ( location . size ( ) > 0 )
{
# ifdef LOG_DL
nlwarning ( " (%s) request (%d) redirected to (len %d) '%s' " , _Id . c_str ( ) , _RedirectsRemaining , location . size ( ) , location . c_str ( ) ) ;
# endif
location = getAbsoluteUrl ( location ) ;
// throw away this handle and start with new one (easier than reusing)
requestTerminated ( ) ;
_PostNextTime = false ;
_RedirectsRemaining - - ;
doBrowse ( location . c_str ( ) ) ;
}
else
{
browseError ( string ( " Request was redirected, but location was not set : " + _URL ) . c_str ( ) ) ;
}
}
}
else
{
_RedirectsRemaining = DEFAULT_RYZOM_REDIRECT_LIMIT ;
if ( ( code < 200 | | code > = 300 ) )
{
browseError ( string ( " Connection failed (curl code " + toString ( ( sint32 ) res ) + " ), http code " + toString ( code ) + " ) : " + _CurlWWW - > Url ) . c_str ( ) ) ;
}
else
{
receiveCookies ( _CurlWWW - > Request , HTTPCurrentDomain , _TrustedDomain ) ;
char * ch ;
std : : string contentType ;
res = curl_easy_getinfo ( _CurlWWW - > Request , CURLINFO_CONTENT_TYPE , & ch ) ;
if ( res = = CURLE_OK )
{
contentType = ch ;
}
htmlDownloadFinished ( _CurlWWW - > Content , contentType , code ) ;
}
requestTerminated ( ) ;
}
}
for ( vector < CDataDownload > : : iterator it = Curls . begin ( ) ; it < Curls . end ( ) ; it + + )
{
if ( msg - > easy_handle = = it - > curl )
@ -318,8 +448,9 @@ namespace NLGUI
fclose ( it - > fp ) ;
# ifdef LOG_DL
nlwarning ( " transfer %x completed with status res %d r %d - %d curls" , msg - > easy_handle , res , r , Curls . size ( ) ) ;
nlwarning ( " (%s) transfer '%p' completed with status %d, http %d, url (len %d) '%s'" , _Id . c_str ( ) , it - > curl , res , r , it - > url . size ( ) , it - > url . c_str ( ) ) ;
# endif
curl_multi_remove_handle ( MultiCurl , it - > curl ) ;
curl_easy_cleanup ( it - > curl ) ;
string file ;
@ -342,11 +473,6 @@ namespace NLGUI
{
for ( uint i = 0 ; i < it - > imgs . size ( ) ; i + + )
{
// don't display image that are not power of 2
//uint32 w, h;
//CBitmap::loadSize (file, w, h);
//if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures()))
// file.clear();
setImage ( it - > imgs [ i ] , file ) ;
}
}
@ -360,6 +486,7 @@ namespace NLGUI
}
}
}
Curls . erase ( it ) ;
break ;
}
@ -368,6 +495,10 @@ namespace NLGUI
}
}
RunningCurls = NewRunningCurls ;
# ifdef LOG_DL
if ( RunningCurls > 0 | | Curls . size ( ) > 0 )
nlwarning ( " (%s) RunningCurls %d, _Curls %d " , _Id . c_str ( ) , RunningCurls , Curls . size ( ) ) ;
# endif
}
@ -436,11 +567,12 @@ namespace NLGUI
{
if ( _Browsing )
{
nlassert ( _Connecting ) ;
_Connecting = false ;
removeContent ( ) ;
}
else
nlwarning ( " _Browsing = FALSE " ) ;
}
@ -1043,12 +1175,10 @@ namespace NLGUI
if ( present [ HTML_FORM_ACTION ] & & value [ HTML_FORM_ACTION ] )
{
form . Action = getAbsoluteUrl ( string ( value [ HTML_FORM_ACTION ] ) ) ;
nlinfo ( " (%s) form.action '%s' (converted) " , _Id . c_str ( ) , form . Action . c_str ( ) ) ;
}
else
{
form . Action = _URL ;
nlinfo ( " (%s) using _URL for form.action '%s' " , _Id . c_str ( ) , form . Action . c_str ( ) ) ;
}
_Forms . push_back ( form ) ;
}
@ -1243,7 +1373,16 @@ namespace NLGUI
// Translate the tooltip
if ( tooltip )
ctrlButton - > setDefaultContextHelp ( CI18N : : get ( tooltip ) ) ;
{
if ( CI18N : : hasTranslation ( tooltip ) )
{
ctrlButton - > setDefaultContextHelp ( CI18N : : get ( tooltip ) ) ;
}
else
{
ctrlButton - > setDefaultContextHelp ( ucstring ( tooltip ) ) ;
}
}
ctrlButton - > setText ( ucstring : : makeFromUtf8 ( text ) ) ;
}
@ -1336,24 +1475,11 @@ namespace NLGUI
if ( ! ( _Forms . empty ( ) ) )
{
// A select box
// read general property
string templateName ;
string minWidth ;
// Widget template name
if ( present [ MY_HTML_INPUT_Z_INPUT_TMPL ] & & value [ MY_HTML_INPUT_Z_INPUT_TMPL ] )
templateName = value [ MY_HTML_INPUT_Z_INPUT_TMPL ] ;
// Widget minimal width
if ( present [ MY_HTML_INPUT_Z_INPUT_WIDTH ] & & value [ MY_HTML_INPUT_Z_INPUT_WIDTH ] )
minWidth = value [ MY_HTML_INPUT_Z_INPUT_WIDTH ] ;
string name ;
if ( present [ HTML_SELECT_NAME ] & & value [ HTML_SELECT_NAME ] )
name = value [ HTML_SELECT_NAME ] ;
string formTemplate = templateName . empty ( ) ? DefaultFormSelectGroup : templateName ;
CDBGroupComboBox * cb = addComboBox ( formTemplate , name . c_str ( ) ) ;
CDBGroupComboBox * cb = addComboBox ( DefaultFormSelectGroup , name . c_str ( ) ) ;
CGroupHTML : : CForm : : CEntry entry ;
entry . Name = name ;
entry . ComboBox = cb ;
@ -1824,7 +1950,8 @@ namespace NLGUI
// ***************************************************************************
CGroupHTML : : CGroupHTML ( const TCtorParam & param )
: CGroupScrollText ( param ) ,
_TimeoutValue ( DEFAULT_RYZOM_CONNECTION_TIMEOUT )
_TimeoutValue ( DEFAULT_RYZOM_CONNECTION_TIMEOUT ) ,
_RedirectsRemaining ( DEFAULT_RYZOM_REDIRECT_LIMIT )
{
// add it to map of group html created
_GroupHtmlUID = + + _GroupHtmlUIDPool ; // valid assigned Id begin to 1!
@ -1894,9 +2021,11 @@ namespace NLGUI
MultiCurl = curl_multi_init ( ) ;
RunningCurls = 0 ;
_CurlWWW = NULL ;
initImageDownload ( ) ;
initBnpDownload ( ) ;
initLibWWW ( ) ;
}
// ***************************************************************************
@ -1921,6 +2050,8 @@ namespace NLGUI
// this is why the call to 'updateRefreshButton' has been removed from stopBrowse
clearContext ( ) ;
if ( _CurlWWW )
delete _CurlWWW ;
}
std : : string CGroupHTML : : getProperty ( const std : : string & name ) const
@ -2849,20 +2980,20 @@ namespace NLGUI
clearContext ( ) ;
_Browsing = false ;
_Connecting = false ;
updateRefreshButton ( ) ;
# ifdef LOG_DL
nlwarning ( " *** ALREADY BROWSING, break first" ) ;
nlwarning ( " (%s) *** ALREADY BROWSING, break first" , _Id . c_str ( ) ) ;
# endif
}
# ifdef LOG_DL
nlwarning ( " Browsing URL : '%s'" , url ) ;
nlwarning ( " (%s) Browsing URL : '%s'" , _Id . c_str ( ) , url ) ;
# endif
// go
_URL = url ;
_Connecting = false ;
_BrowseNextTime = true ;
// if a BrowseTree is bound to us, try to select the node that opens this URL (auto-locate)
@ -2910,13 +3041,15 @@ namespace NLGUI
void CGroupHTML : : stopBrowse ( )
{
# ifdef LOG_DL
nlwarning ( " *** STOP BROWSE " ) ;
nlwarning ( " *** STOP BROWSE (%s) " , _Id . c_str ( ) ) ;
# endif
// Clear all the context
clearContext ( ) ;
_Browsing = false ;
requestTerminated ( ) ;
}
// ***************************************************************************
@ -3539,7 +3672,6 @@ namespace NLGUI
p - > setTopSpace ( beginSpace ) ;
else
group - > setY ( - ( sint32 ) beginSpace ) ;
parentGroup - > addGroup ( group ) ;
}
@ -3703,17 +3835,64 @@ namespace NLGUI
const CWidgetManager : : SInterfaceTimes & times = CWidgetManager : : getInstance ( ) - > getInterfaceTimes ( ) ;
// handle curl downloads
checkDownloads ( ) ;
if ( _Connecting )
{
// Check timeout if needed
if ( _TimeoutValue ! = 0 & & _ConnectingTimeout < = ( times . thisFrameMs / 1000.0f ) )
{
browseError ( ( " Connection timeout : " + _URL ) . c_str ( ) ) ;
_Connecting = false ;
}
}
else
if ( _BrowseNextTime | | _PostNextTime )
{
// Set timeout
_Connecting = true ;
_ConnectingTimeout = ( times . thisFrameMs / 1000.0f ) + _TimeoutValue ;
// freeze form buttons
CButtonFreezer freezer ;
this - > visit ( & freezer ) ;
// Home ?
if ( _URL = = " home " )
_URL = home ( ) ;
string finalUrl ;
bool isLocal = lookupLocalFile ( finalUrl , _URL . c_str ( ) , true ) ;
// Save new url
_URL = finalUrl ;
// file is probably from bnp (ingame help)
if ( isLocal )
{
doBrowseLocalFile ( finalUrl ) ;
}
else
{
_TrustedDomain = isTrustedDomain ( setCurrentDomain ( finalUrl ) ) ;
SFormFields formfields ;
if ( _PostNextTime )
{
buildHTTPPostParams ( formfields ) ;
// _URL is set from form.Action
finalUrl = _URL ;
}
else
{
// Add custom get params from child classes
addHTTPGetParams ( finalUrl , _TrustedDomain ) ;
}
doBrowseRemoteUrl ( finalUrl , " " , _PostNextTime , formfields ) ;
}
_BrowseNextTime = false ;
_PostNextTime = false ;
@ -3721,8 +3900,118 @@ namespace NLGUI
}
// ***************************************************************************
void CGroupHTML : : doBrowseLocalFile( const std : : string & filename )
void CGroupHTML : : buildHTTPPostParams ( SFormFields & formfields )
{
// Add text area text
uint i ;
if ( _PostFormId > = _Forms . size ( ) )
{
nlwarning ( " (%s) invalid form index %d, _Forms %d " , _Id . c_str ( ) , _PostFormId , _Forms . size ( ) ) ;
return ;
}
// Ref the form
CForm & form = _Forms [ _PostFormId ] ;
// Save new url
_URL = form . Action ;
_TrustedDomain = isTrustedDomain ( setCurrentDomain ( _URL ) ) ;
for ( i = 0 ; i < form . Entries . size ( ) ; i + + )
{
// Text area ?
bool addEntry = false ;
ucstring entryData ;
if ( form . Entries [ i ] . TextArea )
{
// Get the edit box view
CInterfaceGroup * group = form . Entries [ i ] . TextArea - > getGroup ( " eb " ) ;
if ( group )
{
// Should be a CGroupEditBox
CGroupEditBox * editBox = dynamic_cast < CGroupEditBox * > ( group ) ;
if ( editBox )
{
entryData = editBox - > getViewText ( ) - > getText ( ) ;
addEntry = true ;
}
}
}
else if ( form . Entries [ i ] . Checkbox )
{
// todo handle unicode POST here
if ( form . Entries [ i ] . Checkbox - > getPushed ( ) )
{
entryData = ucstring ( " on " ) ;
addEntry = true ;
}
}
else if ( form . Entries [ i ] . ComboBox )
{
CDBGroupComboBox * cb = form . Entries [ i ] . ComboBox ;
entryData . fromUtf8 ( form . Entries [ i ] . SelectValues [ cb - > getSelection ( ) ] ) ;
addEntry = true ;
}
// This is a hidden value
else
{
entryData = form . Entries [ i ] . Value ;
addEntry = true ;
}
// Add this entry
if ( addEntry )
{
formfields . add ( form . Entries [ i ] . Name , CI18N : : encodeUTF8 ( entryData ) ) ;
}
}
if ( _PostFormSubmitType = = " image " )
{
// Add the button coordinates
if ( _PostFormSubmitButton . find_first_of ( " [ " ) = = string : : npos )
{
formfields . add ( _PostFormSubmitButton + " _x " , NLMISC : : toString ( _PostFormSubmitX ) ) ;
formfields . add ( _PostFormSubmitButton + " _y " , NLMISC : : toString ( _PostFormSubmitY ) ) ;
}
else
{
formfields . add ( _PostFormSubmitButton , NLMISC : : toString ( _PostFormSubmitX ) ) ;
formfields . add ( _PostFormSubmitButton , NLMISC : : toString ( _PostFormSubmitY ) ) ;
}
}
else
formfields . add ( _PostFormSubmitButton , _PostFormSubmitValue ) ;
// Add custom params from child classes
addHTTPPostParams ( formfields , _TrustedDomain ) ;
}
// ***************************************************************************
void CGroupHTML : : doBrowseLocalFile ( const std : : string & uri )
{
std : : string filename ;
if ( strlwr ( uri ) . find ( " file:/ " ) = = 0 )
{
filename = uri . substr ( 6 , uri . size ( ) - 6 ) ;
}
else
{
filename = uri ;
}
# if LOG_DL
nlwarning ( " (%s) browse local file '%s' " , filename . c_str ( ) ) ;
# endif
_TrustedDomain = true ;
// Stop previous browse, remove content
stopBrowse ( ) ;
_Browsing = true ;
updateRefreshButton ( ) ;
CIFile in ;
if ( in . open ( filename ) )
{
@ -3746,12 +4035,182 @@ namespace NLGUI
}
}
// ***************************************************************************
void CGroupHTML : : doBrowseRemoteUrl ( const std : : string & url , const std : : string & referer , bool doPost , const SFormFields & formfields )
{
// Stop previous request and remove content
stopBrowse ( ) ;
_Browsing = true ;
updateRefreshButton ( ) ;
// Reset the title
if ( _TitlePrefix . empty ( ) )
setTitle ( CI18N : : get ( " uiPleaseWait " ) ) ;
else
setTitle ( _TitlePrefix + " - " + CI18N : : get ( " uiPleaseWait " ) ) ;
# if LOG_DL
nlwarning ( " (%s) browse url (trusted=%s) '%s', referer='%s', post='%s', nb form values %d " ,
_Id . c_str ( ) , ( _TrustedDomain ? " true " : " false " ) , url . c_str ( ) , referer . c_str ( ) , ( doPost ? " true " : " false " ) , formfields . Values . size ( ) ) ;
# endif
if ( ! MultiCurl )
{
browseError ( string ( " Invalid MultCurl handle, loading url failed : " + url ) . c_str ( ) ) ;
return ;
}
CURL * curl = curl_easy_init ( ) ;
if ( ! curl )
{
nlwarning ( " (%s) failed to create curl handle " , _Id . c_str ( ) ) ;
browseError ( string ( " Failed to create cURL handle : " + url ) . c_str ( ) ) ;
return ;
}
// do not follow redirects, we have own handler
curl_easy_setopt ( curl , CURLOPT_FOLLOWLOCATION , 0 ) ;
// after redirect
curl_easy_setopt ( curl , CURLOPT_FRESH_CONNECT , 1 ) ;
// tell curl to use compression if possible (gzip, deflate)
// leaving this empty allows all encodings that curl supports
//curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
// limit curl to HTTP and HTTPS protocols only
curl_easy_setopt ( curl , CURLOPT_PROTOCOLS , CURLPROTO_HTTP | CURLPROTO_HTTPS ) ;
curl_easy_setopt ( curl , CURLOPT_REDIR_PROTOCOLS , CURLPROTO_HTTP | CURLPROTO_HTTPS ) ;
// Destination
curl_easy_setopt ( curl , CURLOPT_URL , url . c_str ( ) ) ;
// User-Agent:
std : : string userAgent = options . appName + " / " + options . appVersion ;
curl_easy_setopt ( curl , CURLOPT_USERAGENT , userAgent . c_str ( ) ) ;
// Cookies
sendCookies ( curl , HTTPCurrentDomain , _TrustedDomain ) ;
// Referer
if ( ! referer . empty ( ) )
{
curl_easy_setopt ( curl , CURLOPT_REFERER , referer . c_str ( ) ) ;
# ifdef LOG_DL
nlwarning ( " (%s) set referer '%s' " , _Id . c_str ( ) , referer . c_str ( ) ) ;
# endif
}
if ( doPost )
{
// serialize form data and add it to curl
std : : string data ;
for ( uint i = 0 ; i < formfields . Values . size ( ) ; + + i )
{
char * escapedName = curl_easy_escape ( curl , formfields . Values [ i ] . name . c_str ( ) , formfields . Values [ i ] . name . size ( ) ) ;
char * escapedValue = curl_easy_escape ( curl , formfields . Values [ i ] . value . c_str ( ) , formfields . Values [ i ] . value . size ( ) ) ;
if ( i > 0 )
data + = " & " ;
data + = std : : string ( escapedName ) + " = " + escapedValue ;
curl_free ( escapedName ) ;
curl_free ( escapedValue ) ;
}
curl_easy_setopt ( curl , CURLOPT_POST , 1 ) ;
curl_easy_setopt ( curl , CURLOPT_POSTFIELDSIZE , data . size ( ) ) ;
curl_easy_setopt ( curl , CURLOPT_COPYPOSTFIELDS , data . c_str ( ) ) ;
}
else
{
curl_easy_setopt ( curl , CURLOPT_HTTPGET , 1 ) ;
}
// transfer handle
_CurlWWW = new CCurlWWWData ( curl , url ) ;
// set the language code used by the client
std : : vector < std : : string > headers ;
headers . push_back ( " Accept-Language: " + options . languageCode ) ;
headers . push_back ( " Accept-Charset: utf-8 " ) ;
for ( uint i = 0 ; i < headers . size ( ) ; + + i )
{
_CurlWWW - > HeadersSent = curl_slist_append ( _CurlWWW - > HeadersSent , headers [ i ] . c_str ( ) ) ;
}
curl_easy_setopt ( curl , CURLOPT_HTTPHEADER , _CurlWWW - > HeadersSent ) ;
// catch headers for redirect
curl_easy_setopt ( curl , CURLOPT_HEADERFUNCTION , curlHeaderCallback ) ;
curl_easy_setopt ( curl , CURLOPT_WRITEHEADER , _CurlWWW ) ;
// catch body
curl_easy_setopt ( curl , CURLOPT_WRITEFUNCTION , curlDataCallback ) ;
curl_easy_setopt ( curl , CURLOPT_WRITEDATA , _CurlWWW ) ;
# if LOG_DL
// progress callback
curl_easy_setopt ( curl , CURLOPT_NOPROGRESS , 0 ) ;
curl_easy_setopt ( curl , CURLOPT_XFERINFOFUNCTION , curlProgressCallback ) ;
curl_easy_setopt ( curl , CURLOPT_XFERINFODATA , _CurlWWW ) ;
# else
// progress off
curl_easy_setopt ( curl , CURLOPT_NOPROGRESS , 1 ) ;
# endif
//
curl_multi_add_handle ( MultiCurl , curl ) ;
// start the transfer
int NewRunningCurls = 0 ;
curl_multi_perform ( MultiCurl , & NewRunningCurls ) ;
RunningCurls + + ;
}
// ***************************************************************************
void CGroupHTML : : htmlDownloadFinished ( const std : : string & content , const std : : string & type , long code )
{
# ifdef LOG_DL
nlwarning ( " (%s) HTML download finished, content length %d, type '%s', code %d " , _Id . c_str ( ) , content . size ( ) , type . c_str ( ) , code ) ;
# endif
// set trusted domain for parsing
_TrustedDomain = isTrustedDomain ( setCurrentDomain ( _URL ) ) ;
// create <html> markup for image downloads
if ( type . find ( " image/ " ) = = 0 & & content . size ( ) > 0 )
{
try
{
std : : string dest = localImageName ( _URL ) ;
COFile out ;
out . open ( dest ) ;
out . serialBuffer ( ( uint8 * ) ( content . c_str ( ) ) , content . size ( ) ) ;
out . close ( ) ;
# ifdef LOG_DL
nlwarning ( " (%s) image saved to '%s', url '%s' " , _Id . c_str ( ) , dest . c_str ( ) , _URL . c_str ( ) ) ;
# endif
}
catch ( . . . ) { }
// create html code with image url inside and do the request again
renderHtmlString ( " <html><head><title> " + _URL + " </title></head><body><img src= \" " + _URL + " \" ></body></html> " ) ;
}
else
{
renderHtmlString ( content ) ;
}
}
// ***************************************************************************
bool CGroupHTML : : renderHtmlString ( const std : : string & html )
{
bool success ;
//
_Browsing = true ;
// clear content
beginBuild ( ) ;
@ -3760,14 +4219,16 @@ namespace NLGUI
// invalidate coords
endBuild ( ) ;
// libwww would call requestTerminated() her e
// set the browser as complet e
_Browsing = false ;
updateRefreshButton ( ) ;
// check that the title is set, or reset it (in the case the page
// does not provide a title)
if ( _TitleString . empty ( ) )
{
setTitle ( _TitlePrefix ) ;
}
updateRefreshButton ( ) ;
return success ;
}
@ -3776,7 +4237,6 @@ namespace NLGUI
void CGroupHTML : : draw ( )
{
checkDownloads ( ) ;
CGroupScrollText : : draw ( ) ;
}
@ -3795,14 +4255,26 @@ namespace NLGUI
// ***************************************************************************
void CGroupHTML : : addHTTPPostParams ( HTAssocList * /* formfields */ , bool /*trustedDomain*/ )
void CGroupHTML : : addHTTPPostParams ( SFormFields & /* formfields */ , bool /*trustedDomain*/ )
{
}
// ***************************************************************************
void CGroupHTML : : requestTerminated ( HTRequest * request )
void CGroupHTML : : requestTerminated ( )
{
if ( _CurlWWW )
{
# if LOG_DL
nlwarning ( " (%s) stop curl, url '%s' " , _Id . c_str ( ) , _CurlWWW - > Url . c_str ( ) ) ;
# endif
if ( MultiCurl )
curl_multi_remove_handle ( MultiCurl , _CurlWWW - > Request ) ;
delete _CurlWWW ;
_CurlWWW = NULL ;
_Connecting = false ;
}
}
// ***************************************************************************
@ -3830,7 +4302,9 @@ namespace NLGUI
_GroupListAdaptor - > clearViews ( ) ;
CWidgetManager : : getInstance ( ) - > clearViewUnders ( ) ;
CWidgetManager : : getInstance ( ) - > clearCtrlsUnders ( ) ;
_Paragraph = NULL ;
// Clear all the context
clearContext ( ) ;
// Reset default background color
setBackgroundColor ( BgColor ) ;
@ -4305,10 +4779,20 @@ namespace NLGUI
// ***************************************************************************
std : : string CGroupHTML : : getAbsoluteUrl ( const std : : string & url )
{
if ( HTURL_isAbsolute( url . c_str ( ) ) )
if ( _URL. size ( ) = = 0 | | url . find ( " http:// " ) ! = std : : string : : npos | | url . find ( " https:// " ) ! = std : : string : : npos )
return url ;
return std : : string ( HTParse ( url . c_str ( ) , _URL . c_str ( ) , PARSE_ALL ) ) ;
xmlChar * uri ;
uri = xmlBuildURI ( reinterpret_cast < const xmlChar * > ( url . c_str ( ) ) , reinterpret_cast < const xmlChar * > ( _URL . c_str ( ) ) ) ;
if ( uri )
{
std : : string ret ( reinterpret_cast < char * > ( uri ) ) ;
xmlFree ( uri ) ;
return ret ;
}
return url ;
}
// ***************************************************************************
@ -4389,5 +4873,46 @@ namespace NLGUI
style . StrikeThrough = getFontStrikeThrough ( ) | | style . StrikeThrough ;
}
}
// ***************************************************************************
size_t CGroupHTML : : curlHeaderCallback ( char * buffer , size_t size , size_t nmemb , void * pCCurlWWWData )
{
CCurlWWWData * me = static_cast < CCurlWWWData * > ( pCCurlWWWData ) ;
if ( me )
{
std : : string header ;
header . append ( buffer , size * nmemb ) ;
me - > setRecvHeader ( header . substr ( 0 , header . find_first_of ( " \n \r " ) ) ) ;
}
return size * nmemb ;
}
// ***************************************************************************
size_t CGroupHTML : : curlDataCallback ( char * buffer , size_t size , size_t nmemb , void * pCCurlWWWData )
{
CCurlWWWData * me = static_cast < CCurlWWWData * > ( pCCurlWWWData ) ;
if ( me )
me - > Content . append ( buffer , size * nmemb ) ;
return size * nmemb ;
}
// ***************************************************************************
size_t CGroupHTML : : curlProgressCallback ( void * pCCurlWWWData , curl_off_t dltotal , curl_off_t dlnow , curl_off_t ultotal , curl_off_t ulnow )
{
CCurlWWWData * me = static_cast < CCurlWWWData * > ( pCCurlWWWData ) ;
if ( me )
{
if ( dltotal > 0 | | dlnow > 0 | | ultotal > 0 | | ulnow > 0 )
{
nlwarning ( " > dltotal %d, dlnow %d, ultotal %d, ulnow %d, url '%s' " , dltotal , dlnow , ultotal , ulnow , me - > Url . c_str ( ) ) ;
}
}
// return 1 to cancel download
return 0 ;
}
}