MediaCurl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <iostream>
00014 #include <list>
00015 
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/ExternalProgram.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/Sysconfig.h"
00020 #include "zypp/base/Gettext.h"
00021 
00022 #include "zypp/media/MediaCurl.h"
00023 #include "zypp/media/proxyinfo/ProxyInfos.h"
00024 #include "zypp/media/ProxyInfo.h"
00025 #include "zypp/media/MediaUserAuth.h"
00026 #include "zypp/media/CurlConfig.h"
00027 #include "zypp/thread/Once.h"
00028 #include <cstdlib>
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 #include <sys/mount.h>
00032 #include <errno.h>
00033 #include <dirent.h>
00034 #include <unistd.h>
00035 #include <boost/format.hpp>
00036 
00037 #define  DETECT_DIR_INDEX       0
00038 #define  CONNECT_TIMEOUT        60
00039 #define  TRANSFER_TIMEOUT       60 * 3
00040 #define  TRANSFER_TIMEOUT_MAX   60 * 60
00041 
00042 
00043 using namespace std;
00044 using namespace zypp::base;
00045 
00046 namespace
00047 {
00048   zypp::thread::OnceFlag g_InitOnceFlag = PTHREAD_ONCE_INIT;
00049   zypp::thread::OnceFlag g_FreeOnceFlag = PTHREAD_ONCE_INIT;
00050 
00051   extern "C" void _do_free_once()
00052   {
00053     curl_global_cleanup();
00054   }
00055 
00056   extern "C" void globalFreeOnce()
00057   {
00058     zypp::thread::callOnce(g_FreeOnceFlag, _do_free_once);
00059   }
00060 
00061   extern "C" void _do_init_once()
00062   {
00063     CURLcode ret = curl_global_init( CURL_GLOBAL_ALL );
00064     if ( ret != 0 )
00065     {
00066       WAR << "curl global init failed" << endl;
00067     }
00068 
00069     //
00070     // register at exit handler ?
00071     // this may cause trouble, because we can protect it
00072     // against ourself only.
00073     // if the app sets an atexit handler as well, it will
00074     // cause a double free while the second of them runs.
00075     //
00076     //std::atexit( globalFreeOnce);
00077   }
00078 
00079   inline void globalInitOnce()
00080   {
00081     zypp::thread::callOnce(g_InitOnceFlag, _do_init_once);
00082   }
00083 
00084   int log_curl(CURL *curl, curl_infotype info,
00085                char *ptr, size_t len, void *max_lvl)
00086   {
00087     std::string pfx(" ");
00088     long        lvl = 0;
00089     switch( info)
00090     {
00091       case CURLINFO_TEXT:       lvl = 1; pfx = "*"; break;
00092       case CURLINFO_HEADER_IN:  lvl = 2; pfx = "<"; break;
00093       case CURLINFO_HEADER_OUT: lvl = 2; pfx = ">"; break;
00094       default:                                      break;
00095     }
00096     if( lvl > 0 && max_lvl != NULL && lvl <= *((long *)max_lvl))
00097     {
00098       std::string                            msg(ptr, len);
00099       std::list<std::string>                 lines;
00100       std::list<std::string>::const_iterator line;
00101       zypp::str::split(msg, std::back_inserter(lines), "\r\n");
00102       for(line = lines.begin(); line != lines.end(); ++line)
00103       {
00104         DBG << pfx << " " << *line << endl;
00105       }
00106     }
00107     return 0;
00108   }
00109 }
00110 
00111 namespace zypp {
00112   namespace media {
00113 
00114   namespace {
00115     struct ProgressData
00116     {
00117       ProgressData(const long _timeout, const zypp::Url &_url = zypp::Url(),
00118                    callback::SendReport<DownloadProgressReport> *_report=NULL)
00119         : timeout(_timeout)
00120         , reached(false)
00121         , report(_report)
00122         , ltime( time(NULL))
00123         , dload( 0)
00124         , uload( 0)
00125         , url(_url)
00126       {}
00127       long                                          timeout;
00128       bool                                          reached;
00129       callback::SendReport<DownloadProgressReport> *report;
00130       time_t                                        ltime;
00131       double                                        dload;
00132       double                                        uload;
00133       zypp::Url                                     url;
00134     };
00135   }
00136 
00137 Pathname    MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
00138 std::string MediaCurl::_agent = "Novell ZYPP Installer";
00139 
00141 
00142 static inline void escape( string & str_r,
00143                            const char char_r, const string & escaped_r ) {
00144   for ( string::size_type pos = str_r.find( char_r );
00145         pos != string::npos; pos = str_r.find( char_r, pos ) ) {
00146     str_r.replace( pos, 1, escaped_r );
00147   }
00148 }
00149 
00150 static inline string escapedPath( string path_r ) {
00151   escape( path_r, ' ', "%20" );
00152   return path_r;
00153 }
00154 
00155 static inline string unEscape( string text_r ) {
00156   char * tmp = curl_unescape( text_r.c_str(), 0 );
00157   string ret( tmp );
00158   curl_free( tmp );
00159   return ret;
00160 }
00161 
00163 //
00164 //        CLASS NAME : MediaCurl
00165 //
00167 
00168 MediaCurl::MediaCurl( const Url &      url_r,
00169                       const Pathname & attach_point_hint_r )
00170     : MediaHandler( url_r, attach_point_hint_r,
00171                     "/", // urlpath at attachpoint
00172                     true ), // does_download
00173       _curl( NULL )
00174 {
00175   _curlError[0] = '\0';
00176   _curlDebug = 0L;
00177 
00178   MIL << "MediaCurl::MediaCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00179 
00180   globalInitOnce();
00181 
00182   if( !attachPoint().empty())
00183   {
00184     PathInfo ainfo(attachPoint());
00185     Pathname apath(attachPoint() + "XXXXXX");
00186     char    *atemp = ::strdup( apath.asString().c_str());
00187     char    *atest = NULL;
00188     if( !ainfo.isDir() || !ainfo.userMayRWX() ||
00189          atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
00190     {
00191       WAR << "attach point " << ainfo.path()
00192           << " is not useable for " << url_r.getScheme() << endl;
00193       setAttachPoint("", true);
00194     }
00195     else if( atest != NULL)
00196       ::rmdir(atest);
00197 
00198     if( atemp != NULL)
00199       ::free(atemp);
00200   }
00201 }
00202 
00203 void MediaCurl::setCookieFile( const Pathname &fileName )
00204 {
00205   _cookieFile = fileName;
00206 }
00207 
00209 //
00210 //
00211 //        METHOD NAME : MediaCurl::attachTo
00212 //        METHOD TYPE : PMError
00213 //
00214 //        DESCRIPTION : Asserted that not already attached, and attachPoint is a directory.
00215 //
00216 void MediaCurl::attachTo (bool next)
00217 {
00218   if ( next )
00219     ZYPP_THROW(MediaNotSupportedException(_url));
00220 
00221   if ( !_url.isValid() )
00222     ZYPP_THROW(MediaBadUrlException(_url));
00223 
00224   CurlConfig curlconf;
00225   CurlConfig::parseConfig(curlconf); // parse ~/.curlrc
00226 
00227   curl_version_info_data *curl_info = NULL;
00228   curl_info = curl_version_info(CURLVERSION_NOW);
00229   // curl_info does not need any free (is static)
00230   if (curl_info->protocols)
00231   {
00232     const char * const *proto;
00233     std::string        scheme( _url.getScheme());
00234     bool               found = false;
00235     for(proto=curl_info->protocols; !found && *proto; ++proto)
00236     {
00237       if( scheme == std::string((const char *)*proto))
00238         found = true;
00239     }
00240     if( !found)
00241     {
00242       std::string msg("Unsupported protocol '");
00243       msg += scheme;
00244       msg += "'";
00245       ZYPP_THROW(MediaBadUrlException(_url, msg));
00246     }
00247   }
00248 
00249   if( !isUseableAttachPoint(attachPoint()))
00250   {
00251     std::string mountpoint = createAttachPoint().asString();
00252 
00253     if( mountpoint.empty())
00254       ZYPP_THROW( MediaBadAttachPointException(url()));
00255 
00256     setAttachPoint( mountpoint, true);
00257   }
00258 
00259   disconnectFrom(); // clean _curl if needed
00260   _curl = curl_easy_init();
00261   if ( !_curl ) {
00262     ZYPP_THROW(MediaCurlInitException(_url));
00263   }
00264 
00265   {
00266     char *ptr = getenv("ZYPP_MEDIA_CURL_DEBUG");
00267     _curlDebug = (ptr && *ptr) ? str::strtonum<long>( ptr) : 0L;
00268     if( _curlDebug > 0)
00269     {
00270       curl_easy_setopt( _curl, CURLOPT_VERBOSE, 1);
00271       curl_easy_setopt( _curl, CURLOPT_DEBUGFUNCTION, log_curl);
00272       curl_easy_setopt( _curl, CURLOPT_DEBUGDATA, &_curlDebug);
00273     }
00274   }
00275 
00276   CURLcode ret = curl_easy_setopt( _curl, CURLOPT_ERRORBUFFER, _curlError );
00277   if ( ret != 0 ) {
00278     disconnectFrom();
00279     ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer"));
00280   }
00281 
00282   ret = curl_easy_setopt( _curl, CURLOPT_FAILONERROR, true );
00283   if ( ret != 0 ) {
00284     disconnectFrom();
00285     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00286   }
00287 
00288   ret = curl_easy_setopt( _curl, CURLOPT_NOSIGNAL, 1 );
00289   if ( ret != 0 ) {
00290     disconnectFrom();
00291     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00292   }
00293 
00297   {
00298     _xfer_timeout = TRANSFER_TIMEOUT;
00299 
00300     std::string param(_url.getQueryParam("timeout"));
00301     if( !param.empty())
00302     {
00303       long num = str::strtonum<long>( param);
00304       if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX)
00305         _xfer_timeout = num;
00306     }
00307   }
00308 
00309   /*
00310   ** Connect timeout
00311   */
00312   ret = curl_easy_setopt( _curl, CURLOPT_CONNECTTIMEOUT, CONNECT_TIMEOUT);
00313   if ( ret != 0 ) {
00314     disconnectFrom();
00315     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00316   }
00317 
00318   if ( _url.getScheme() == "http" ) {
00319     // follow any Location: header that the server sends as part of
00320     // an HTTP header (#113275)
00321     ret = curl_easy_setopt ( _curl, CURLOPT_FOLLOWLOCATION, true );
00322     if ( ret != 0) {
00323       disconnectFrom();
00324       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00325     }
00326     ret = curl_easy_setopt ( _curl, CURLOPT_MAXREDIRS, 3L );
00327     if ( ret != 0) {
00328       disconnectFrom();
00329       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00330     }
00331     ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, _agent.c_str() );
00332     if ( ret != 0) {
00333       disconnectFrom();
00334       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00335     }
00336   }
00337 
00338   if ( _url.getScheme() == "https" )
00339   {
00340     bool verify_peer = false;
00341     bool verify_host = false;
00342 
00343     std::string verify( _url.getQueryParam("ssl_verify"));
00344     if( verify.empty() ||
00345         verify == "yes")
00346     {
00347       verify_peer = true;
00348       verify_host = true;
00349     }
00350     else
00351     if( verify == "no")
00352     {
00353       verify_peer = false;
00354       verify_host = false;
00355     }
00356     else
00357     {
00358       std::vector<std::string>                 flags;
00359       std::vector<std::string>::const_iterator flag;
00360       str::split( verify, std::back_inserter(flags), ",");
00361       for(flag = flags.begin(); flag != flags.end(); ++flag)
00362       {
00363         if( *flag == "host")
00364         {
00365           verify_host = true;
00366         }
00367         else
00368         if( *flag == "peer")
00369         {
00370           verify_peer = true;
00371         }
00372         else
00373         {
00374                 disconnectFrom();
00375           ZYPP_THROW(MediaBadUrlException(_url, "Unknown ssl_verify flag"));
00376         }
00377       }
00378     }
00379 
00380     _ca_path = Pathname(_url.getQueryParam("ssl_capath")).asString();
00381     if( _ca_path.empty())
00382     {
00383         _ca_path = "/etc/ssl/certs/";
00384     }
00385     else
00386     if( !PathInfo(_ca_path).isDir() || !Pathname(_ca_path).absolute())
00387     {
00388         disconnectFrom();
00389         ZYPP_THROW(MediaBadUrlException(_url, "Invalid ssl_capath path"));
00390     }
00391 
00392     if( verify_peer || verify_host)
00393     {
00394       ret = curl_easy_setopt( _curl, CURLOPT_CAPATH, _ca_path.c_str());
00395       if ( ret != 0 ) {
00396         disconnectFrom();
00397         ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00398       }
00399     }
00400 
00401     ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYPEER, verify_peer ? 1L : 0L);
00402     if ( ret != 0 ) {
00403       disconnectFrom();
00404       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00405     }
00406     ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L);
00407     if ( ret != 0 ) {
00408       disconnectFrom();
00409       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00410     }
00411 
00412     ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, _agent.c_str() );
00413     if ( ret != 0) {
00414       disconnectFrom();
00415       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00416     }
00417   }
00418 
00419 
00420   /*---------------------------------------------------------------*
00421    CURLOPT_USERPWD: [user name]:[password]
00422 
00423    Url::username/password -> CURLOPT_USERPWD
00424    If not provided, anonymous FTP identification
00425    *---------------------------------------------------------------*/
00426 
00427   if ( _url.getUsername().empty() ) {
00428     if ( _url.getScheme() == "ftp" ) {
00429       string id = "yast2@";
00430       id += VERSION;
00431       DBG << "Anonymous FTP identification: '" << id << "'" << endl;
00432       _userpwd = "anonymous:" + id;
00433     }
00434   } else {
00435     _userpwd = _url.getUsername();
00436     if ( _url.getPassword().size() ) {
00437       _userpwd += ":" + _url.getPassword();
00438     }
00439   }
00440 
00441   if ( _userpwd.size() ) {
00442     _userpwd = unEscape( _userpwd );
00443     ret = curl_easy_setopt( _curl, CURLOPT_USERPWD, _userpwd.c_str() );
00444     if ( ret != 0 ) {
00445       disconnectFrom();
00446       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00447     }
00448 
00449     // HTTP authentication type
00450     if(_url.getScheme() == "http" || _url.getScheme() == "https")
00451     {
00452       string use_auth = _url.getQueryParam("auth");
00453       if( use_auth.empty())
00454         use_auth = "digest,basic";
00455 
00456       try
00457       {
00458         long auth = CurlAuthData::auth_type_str2long(use_auth);
00459         if( auth != CURLAUTH_NONE)
00460         {
00461           DBG << "Enabling HTTP authentication methods: " << use_auth
00462               << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
00463 
00464           ret = curl_easy_setopt( _curl, CURLOPT_HTTPAUTH, auth);
00465           if ( ret != 0 ) {
00466             disconnectFrom();
00467             ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00468           }
00469         }
00470       }
00471       catch (MediaException & ex_r)
00472       {
00473         string auth_hint = getAuthHint();
00474 
00475         DBG << "Rethrowing as MediaUnauthorizedException. auth hint: '"
00476             << auth_hint << "'" << endl;
00477 
00478         ZYPP_THROW(MediaUnauthorizedException(
00479           _url, ex_r.msg(), _curlError, auth_hint
00480         ));
00481       }
00482     }
00483   }
00484 
00485   /*---------------------------------------------------------------*
00486    CURLOPT_PROXY: host[:port]
00487 
00488    Url::option(proxy and proxyport) -> CURLOPT_PROXY
00489    If not provided, /etc/sysconfig/proxy is evaluated
00490    *---------------------------------------------------------------*/
00491 
00492   _proxy = _url.getQueryParam( "proxy" );
00493 
00494   if ( ! _proxy.empty() ) {
00495     string proxyport( _url.getQueryParam( "proxyport" ) );
00496     if ( ! proxyport.empty() ) {
00497       _proxy += ":" + proxyport;
00498     }
00499   } else {
00500 
00501     ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy")));
00502 
00503     if ( proxy_info.enabled())
00504     {
00505       bool useproxy = true;
00506 
00507       std::list<std::string> nope = proxy_info.noProxy();
00508       for (ProxyInfo::NoProxyIterator it = proxy_info.noProxyBegin();
00509            it != proxy_info.noProxyEnd();
00510            it++)
00511       {
00512         std::string host( str::toLower(_url.getHost()));
00513         std::string temp( str::toLower(*it));
00514 
00515         // no proxy if it points to a suffix
00516         // preceeded by a '.', that maches
00517         // the trailing portion of the host.
00518         if( temp.size() > 1 && temp.at(0) == '.')
00519         {
00520           if(host.size() > temp.size() &&
00521              host.compare(host.size() - temp.size(), temp.size(), temp) == 0)
00522           {
00523             DBG << "NO_PROXY: '" << *it  << "' matches host '"
00524                                  << host << "'" << endl;
00525             useproxy = false;
00526             break;
00527           }
00528         }
00529         else
00530         // no proxy if we have an exact match
00531         if( host == temp)
00532         {
00533           DBG << "NO_PROXY: '" << *it  << "' matches host '"
00534                                << host << "'" << endl;
00535           useproxy = false;
00536           break;
00537         }
00538       }
00539 
00540       if ( useproxy ) {
00541         _proxy = proxy_info.proxy(_url.getScheme());
00542       }
00543     }
00544   }
00545 
00546 
00547   DBG << "Proxy: " << (_proxy.empty() ? "-none-" : _proxy) << endl;
00548 
00549   if ( ! _proxy.empty() ) {
00550 
00551     ret = curl_easy_setopt( _curl, CURLOPT_PROXY, _proxy.c_str() );
00552     if ( ret != 0 ) {
00553       disconnectFrom();
00554       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00555     }
00556 
00557     /*---------------------------------------------------------------*
00558      CURLOPT_PROXYUSERPWD: [user name]:[password]
00559 
00560      Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
00561      If not provided, $HOME/.curlrc is evaluated
00562      *---------------------------------------------------------------*/
00563 
00564     _proxyuserpwd = _url.getQueryParam( "proxyuser" );
00565 
00566     if ( ! _proxyuserpwd.empty() ) {
00567       string proxypassword( _url.getQueryParam( "proxypassword" ) );
00568       if ( ! proxypassword.empty() ) {
00569         _proxyuserpwd += ":" + proxypassword;
00570       }
00571     } else {
00572       if (curlconf.proxyuserpwd.empty())
00573         DBG << "~/.curlrc does not contain the proxy-user option" << endl;
00574       else
00575       {
00576         _proxyuserpwd = curlconf.proxyuserpwd;
00577         DBG << "using proxy-user from ~/.curlrc" << endl;
00578       }
00579     }
00580 
00581     _proxyuserpwd = unEscape( _proxyuserpwd );
00582     ret = curl_easy_setopt( _curl, CURLOPT_PROXYUSERPWD, _proxyuserpwd.c_str() );
00583     if ( ret != 0 ) {
00584       disconnectFrom();
00585       ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00586     }
00587   }
00588 
00589   /*---------------------------------------------------------------*
00590    *---------------------------------------------------------------*/
00591 
00592   _currentCookieFile = _cookieFile.asString();
00593 
00594   ret = curl_easy_setopt( _curl, CURLOPT_COOKIEFILE,
00595                           _currentCookieFile.c_str() );
00596   if ( ret != 0 ) {
00597     disconnectFrom();
00598     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00599   }
00600 
00601   ret = curl_easy_setopt( _curl, CURLOPT_COOKIEJAR,
00602                           _currentCookieFile.c_str() );
00603   if ( ret != 0 ) {
00604     disconnectFrom();
00605     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00606   }
00607 
00608   ret = curl_easy_setopt( _curl, CURLOPT_PROGRESSFUNCTION,
00609                           &progressCallback );
00610   if ( ret != 0 ) {
00611     disconnectFrom();
00612     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00613   }
00614 
00615   ret = curl_easy_setopt( _curl, CURLOPT_NOPROGRESS, false );
00616   if ( ret != 0 ) {
00617     disconnectFrom();
00618     ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00619   }
00620 
00621   // FIXME: need a derived class to propelly compare url's
00622   MediaSourceRef media( new MediaSource(_url.getScheme(), _url.asString()));
00623   setMediaSource(media);
00624 }
00625 
00626 bool
00627 MediaCurl::checkAttachPoint(const Pathname &apoint) const
00628 {
00629   return MediaHandler::checkAttachPoint( apoint, true, true);
00630 }
00631 
00633 //
00634 //
00635 //        METHOD NAME : MediaCurl::disconnectFrom
00636 //        METHOD TYPE : PMError
00637 //
00638 void MediaCurl::disconnectFrom()
00639 {
00640   if ( _curl )
00641   {
00642     curl_easy_cleanup( _curl );
00643     _curl = NULL;
00644   }
00645 }
00646 
00648 //
00649 //
00650 //        METHOD NAME : MediaCurl::releaseFrom
00651 //        METHOD TYPE : PMError
00652 //
00653 //        DESCRIPTION : Asserted that media is attached.
00654 //
00655 void MediaCurl::releaseFrom( bool eject )
00656 {
00657   disconnect();
00658 }
00659 
00660 
00662 //
00663 //        METHOD NAME : MediaCurl::getFile
00664 //        METHOD TYPE : PMError
00665 //
00666 
00667 void MediaCurl::getFile( const Pathname & filename ) const
00668 {
00669     // Use absolute file name to prevent access of files outside of the
00670     // hierarchy below the attach point.
00671     getFileCopy(filename, localPath(filename).absolutename());
00672 }
00673 
00674 
00675 void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target) const
00676 {
00677   callback::SendReport<DownloadProgressReport> report;
00678 
00679   Url url( _url );
00680 
00681   bool retry = false;
00682   CurlAuthData auth_data;
00683 
00684   do
00685   {
00686     try
00687     {
00688       doGetFileCopy(filename, target, report);
00689       retry = false;
00690     }
00691     // retry with proper authentication data
00692     catch (MediaUnauthorizedException & ex_r)
00693     {
00694       callback::SendReport<AuthenticationReport> auth_report;
00695 
00696       if (!_url.getUsername().empty() && !retry)
00697         auth_data.setUserName(_url.getUsername());
00698 
00699       string prompt_msg;
00700       if (retry || !_url.getUsername().empty())
00701         prompt_msg = _("Invalid user name or password.");
00702       else // first prompt
00703         prompt_msg = boost::str(boost::format(
00704           _("Authentication required for '%s'")) % _url.asString());
00705 
00706       // set available authentication types from the exception
00707       auth_data.setAuthType(ex_r.hint());
00708 
00709       if (auth_report->prompt(_url, prompt_msg, auth_data))
00710       {
00711         DBG << "callback answer: retry" << endl
00712             << "CurlAuthData: " << auth_data << endl;
00713 
00714         if (auth_data.valid()) {
00715           _userpwd = auth_data.getUserPwd();
00716 
00717           // set username and password
00718           CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _userpwd.c_str());
00719           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00720 
00721           // set auth type
00722           ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, auth_data.authType());
00723           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00724         }
00725 
00726         retry = true;
00727       }
00728       else
00729       {
00730         DBG << "callback answer: cancel" << endl;
00731         report->finish(url, zypp::media::DownloadProgressReport::ACCESS_DENIED, ex_r.asUserString());
00732         ZYPP_RETHROW(ex_r);
00733       }
00734     }
00735     // unexpected exception
00736     catch (MediaException & excpt_r)
00737     {
00738       // FIXME: this will not match the first URL
00739       // FIXME: error number fix
00740       report->finish(url, zypp::media::DownloadProgressReport::ERROR, excpt_r.asUserString());
00741       ZYPP_RETHROW(excpt_r);
00742     }
00743   }
00744   while (retry);
00745 
00746   report->finish(url, zypp::media::DownloadProgressReport::NO_ERROR, "");
00747 }
00748 
00749 bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
00750 {
00751   bool retry = false;
00752   CurlAuthData auth_data;
00753 
00754   do
00755   {
00756     try
00757     {
00758       return doGetDoesFileExist( filename );
00759     }
00760     // authentication problem, retry with proper authentication data
00761     catch (MediaUnauthorizedException & ex_r)
00762     {
00763       callback::SendReport<AuthenticationReport> auth_report;
00764 
00765       if (!_url.getUsername().empty() && !retry)
00766         auth_data.setUserName(_url.getUsername());
00767 
00768       string prompt_msg;
00769       if (retry || !_url.getUsername().empty())
00770         prompt_msg = _("Invalid user name or password.");
00771       else // first prompt
00772         prompt_msg = boost::str(boost::format(
00773           _("Authentication required for '%s'")) % _url.asString());
00774 
00775       // set available authentication types from the exception
00776       auth_data.setAuthType(ex_r.hint());
00777 
00778       if (auth_report->prompt(_url, prompt_msg, auth_data))
00779       {
00780         DBG << "callback answer: retry" << endl
00781             << "CurlAuthData: " << auth_data << endl;
00782 
00783         if (auth_data.valid()) {
00784           _userpwd = auth_data.getUserPwd();
00785 
00786           // set username and password
00787           CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _userpwd.c_str());
00788           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00789 
00790           // set auth type
00791           ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, auth_data.authType());
00792           if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
00793         }
00794 
00795         retry = true;
00796       }
00797       else
00798       {
00799         DBG << "callback answer: cancel" << endl;
00800         ZYPP_RETHROW(ex_r);
00801       }
00802     }
00803     // unexpected exception
00804     catch (MediaException & excpt_r)
00805     {
00806       ZYPP_RETHROW(excpt_r);
00807     }
00808   }
00809   while (retry);
00810 
00811   return false;
00812 }
00813 
00814 bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
00815 {
00816   DBG << filename.asString() << endl;
00817 
00818   if(!_url.isValid())
00819     ZYPP_THROW(MediaBadUrlException(_url));
00820 
00821   if(_url.getHost().empty())
00822     ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
00823 
00824   string path = _url.getPathName();
00825   if ( !path.empty() && path != "/" && *path.rbegin() == '/' &&
00826         filename.absolute() ) {
00827       // If url has a path with trailing slash, remove the leading slash from
00828       // the absolute file name
00829     path += filename.asString().substr( 1, filename.asString().size() - 1 );
00830   } else if ( filename.relative() ) {
00831       // Add trailing slash to path, if not already there
00832     if ( !path.empty() && *path.rbegin() != '/' ) path += "/";
00833     // Remove "./" from begin of relative file name
00834     path += filename.asString().substr( 2, filename.asString().size() - 2 );
00835   } else {
00836     path += filename.asString();
00837   }
00838 
00839   Url url( _url );
00840   url.setPathName( path );
00841 
00842   DBG << "URL: " << url.asString() << endl;
00843     // Use URL without options and without username and passwd
00844     // (some proxies dislike them in the URL).
00845     // Curl seems to need the just scheme, hostname and a path;
00846     // the rest was already passed as curl options (in attachTo).
00847   Url curlUrl( url );
00848 
00849     // Use asString + url::ViewOptions instead?
00850   curlUrl.setUsername( "" );
00851   curlUrl.setPassword( "" );
00852   curlUrl.setPathParams( "" );
00853   curlUrl.setQueryString( "" );
00854   curlUrl.setFragment( "" );
00855 
00856   //
00857     // See also Bug #154197 and ftp url definition in RFC 1738:
00858     // The url "ftp://user@host/foo/bar/file" contains a path,
00859     // that is relative to the user's home.
00860     // The url "ftp://user@host//foo/bar/file" (or also with
00861     // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
00862     // contains an absolute path.
00863   //
00864   string urlBuffer( curlUrl.asString());
00865   CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
00866                                    urlBuffer.c_str() );
00867   if ( ret != 0 ) {
00868     ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00869   }
00870 
00871   // set no data, because we only want to check if the file exists
00872   //ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1 );
00873   //if ( ret != 0 ) {
00874   //    ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00875   //}
00876 
00877   // instead of returning no data with NOBODY, we return
00878   // little data, that works with broken servers, and
00879   // works for ftp as well, because retrieving only headers
00880   // ftp will return always OK code ?
00881   ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
00882   if ( ret != 0 ) {
00883       ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00884   }
00885 
00886   FILE *file = ::fopen( "/dev/null", "w" );
00887   if ( !file ) {
00888       ::fclose(file);
00889       ERR << "fopen failed for /dev/null" << endl;
00890       curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
00891       if ( ret != 0 ) {
00892           ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00893       }
00894       ZYPP_THROW(MediaWriteException("/dev/null"));
00895   }
00896 
00897   ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
00898   if ( ret != 0 ) {
00899       ::fclose(file);
00900       std::string err( _curlError);
00901       curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
00902       if ( ret != 0 ) {
00903           ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00904       }
00905       ZYPP_THROW(MediaCurlSetOptException(url, err));
00906   }
00907     // Set callback and perform.
00908   //ProgressData progressData(_xfer_timeout, url, &report);
00909   //report->start(url, dest);
00910   //if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
00911   //  WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
00912   //}
00913 
00914   CURLcode ok = curl_easy_perform( _curl );
00915   MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
00916 
00917   // reset curl settings
00918   ret = curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
00919   if ( ret != 0 )
00920   {
00921     ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
00922   }
00923 
00924   if ( ok != 0 )
00925   {
00926     ::fclose( file );
00927 
00928     std::string err;
00929     try
00930     {
00931       bool err_file_not_found = false;
00932       switch ( ok )
00933       {
00934       case CURLE_FTP_COULDNT_RETR_FILE:
00935       case CURLE_FTP_ACCESS_DENIED:
00936         err_file_not_found = true;
00937         break;
00938       case CURLE_HTTP_RETURNED_ERROR:
00939         {
00940           long httpReturnCode = 0;
00941           CURLcode infoRet = curl_easy_getinfo( _curl,
00942                                                 CURLINFO_RESPONSE_CODE,
00943                                                 &httpReturnCode );
00944           if ( infoRet == CURLE_OK )
00945           {
00946             string msg = "HTTP response: " +
00947                           str::numstring( httpReturnCode );
00948             if ( httpReturnCode == 401 )
00949             {
00950               std::string auth_hint = getAuthHint();
00951 
00952               DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
00953               DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
00954 
00955               ZYPP_THROW(MediaUnauthorizedException(
00956                 url, "Login failed.", _curlError, auth_hint
00957               ));
00958             }
00959             else
00960             if ( httpReturnCode == 404)
00961             {
00962                err_file_not_found = true;
00963                break;
00964             }
00965 
00966             msg += err;
00967             DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00968             ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00969           }
00970           else
00971           {
00972             string msg = "Unable to retrieve HTTP response:";
00973             msg += err;
00974             DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00975             ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00976           }
00977         }
00978         break;
00979       case CURLE_UNSUPPORTED_PROTOCOL:
00980       case CURLE_URL_MALFORMAT:
00981       case CURLE_URL_MALFORMAT_USER:
00982       case CURLE_BAD_PASSWORD_ENTERED:
00983       case CURLE_FTP_USER_PASSWORD_INCORRECT:
00984       case CURLE_COULDNT_RESOLVE_PROXY:
00985       case CURLE_COULDNT_RESOLVE_HOST:
00986       case CURLE_COULDNT_CONNECT:
00987       case CURLE_FTP_CANT_GET_HOST:
00988       case CURLE_WRITE_ERROR:
00989       case CURLE_ABORTED_BY_CALLBACK:
00990       case CURLE_SSL_PEER_CERTIFICATE:
00991       default:
00992         err = curl_easy_strerror(ok);
00993         if (err.empty())
00994           err = "Unrecognized error";
00995         break;
00996       }
00997 
00998       if( err_file_not_found)
00999       {
01000         // file does not exists
01001         return false;
01002       }
01003       else
01004       {
01005         // there was an error
01006         ZYPP_THROW(MediaCurlException(url, string(), _curlError));
01007       }
01008     }
01009     catch (const MediaException & excpt_r)
01010     {
01011       ZYPP_RETHROW(excpt_r);
01012     }
01013   }
01014 
01015   // exists
01016   return ( ok == CURLE_OK );
01017   //if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
01018   //  WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01019   //}
01020 }
01021 
01022 void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport<DownloadProgressReport> & report) const
01023 {
01024     DBG << filename.asString() << endl;
01025 
01026     if(!_url.isValid())
01027       ZYPP_THROW(MediaBadUrlException(_url));
01028 
01029     if(_url.getHost().empty())
01030       ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
01031 
01032     string path = _url.getPathName();
01033     if ( !path.empty() && path != "/" && *path.rbegin() == '/' &&
01034          filename.absolute() ) {
01035       // If url has a path with trailing slash, remove the leading slash from
01036       // the absolute file name
01037       path += filename.asString().substr( 1, filename.asString().size() - 1 );
01038     } else if ( filename.relative() ) {
01039       // Add trailing slash to path, if not already there
01040       if (path.empty()) path = "/";
01041       else if (*path.rbegin() != '/' ) path += "/";
01042       // Remove "./" from begin of relative file name
01043       path += filename.asString().substr( 2, filename.asString().size() - 2 );
01044     } else {
01045       path += filename.asString();
01046     }
01047 
01048     Url url( _url );
01049     url.setPathName( path );
01050 
01051     Pathname dest = target.absolutename();
01052     if( assert_dir( dest.dirname() ) )
01053     {
01054       DBG << "assert_dir " << dest.dirname() << " failed" << endl;
01055       ZYPP_THROW( MediaSystemException(url, "System error on " + dest.dirname().asString()) );
01056     }
01057 
01058     DBG << "URL: " << url.asString() << endl;
01059     // Use URL without options and without username and passwd
01060     // (some proxies dislike them in the URL).
01061     // Curl seems to need the just scheme, hostname and a path;
01062     // the rest was already passed as curl options (in attachTo).
01063     Url curlUrl( url );
01064 
01065     // Use asString + url::ViewOptions instead?
01066     curlUrl.setUsername( "" );
01067     curlUrl.setPassword( "" );
01068     curlUrl.setPathParams( "" );
01069     curlUrl.setQueryString( "" );
01070     curlUrl.setFragment( "" );
01071 
01072     //
01073     // See also Bug #154197 and ftp url definition in RFC 1738:
01074     // The url "ftp://user@host/foo/bar/file" contains a path,
01075     // that is relative to the user's home.
01076     // The url "ftp://user@host//foo/bar/file" (or also with
01077     // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
01078     // contains an absolute path.
01079     //
01080     string urlBuffer( curlUrl.asString());
01081     CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
01082                                      urlBuffer.c_str() );
01083     if ( ret != 0 ) {
01084       ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01085     }
01086 
01087     string destNew = target.asString() + ".new.zypp.XXXXXX";
01088     char *buf = ::strdup( destNew.c_str());
01089     if( !buf)
01090     {
01091       ERR << "out of memory for temp file name" << endl;
01092       ZYPP_THROW(MediaSystemException(
01093         url, "out of memory for temp file name"
01094       ));
01095     }
01096 
01097     int tmp_fd = ::mkstemp( buf );
01098     if( tmp_fd == -1)
01099     {
01100       free( buf);
01101       ERR << "mkstemp failed for file '" << destNew << "'" << endl;
01102       ZYPP_THROW(MediaWriteException(destNew));
01103     }
01104     destNew = buf;
01105     free( buf);
01106 
01107     FILE *file = ::fdopen( tmp_fd, "w" );
01108     if ( !file ) {
01109       ::close( tmp_fd);
01110       filesystem::unlink( destNew );
01111       ERR << "fopen failed for file '" << destNew << "'" << endl;
01112       ZYPP_THROW(MediaWriteException(destNew));
01113     }
01114 
01115     DBG << "dest: " << dest << endl;
01116     DBG << "temp: " << destNew << endl;
01117 
01118     ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
01119     if ( ret != 0 ) {
01120       ::fclose( file );
01121       filesystem::unlink( destNew );
01122       ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01123     }
01124 
01125     // Set callback and perform.
01126     ProgressData progressData(_xfer_timeout, url, &report);
01127     report->start(url, dest);
01128     if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
01129       WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01130     }
01131 
01132     ret = curl_easy_perform( _curl );
01133 
01134     if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
01135       WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01136     }
01137 
01138     if ( ret != 0 ) {
01139       ERR << "curl error: " << ret << ": " << _curlError
01140           << ", temp file size " << PathInfo(destNew).size()
01141           << " byte." << endl;
01142 
01143       ::fclose( file );
01144       filesystem::unlink( destNew );
01145 
01146       std::string err;
01147       try {
01148        bool err_file_not_found = false;
01149        switch ( ret ) {
01150         case CURLE_UNSUPPORTED_PROTOCOL:
01151         case CURLE_URL_MALFORMAT:
01152         case CURLE_URL_MALFORMAT_USER:
01153           err = " Bad URL";
01154         case CURLE_HTTP_RETURNED_ERROR:
01155           {
01156             long httpReturnCode = 0;
01157             CURLcode infoRet = curl_easy_getinfo( _curl,
01158                                                   CURLINFO_RESPONSE_CODE,
01159                                                   &httpReturnCode );
01160             if ( infoRet == CURLE_OK ) {
01161               string msg = "HTTP response: " +
01162                            str::numstring( httpReturnCode );
01163               if ( httpReturnCode == 401 )
01164               {
01165                 std::string auth_hint = getAuthHint();
01166 
01167                 DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
01168                 DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
01169 
01170                 ZYPP_THROW(MediaUnauthorizedException(
01171                   url, "Login failed.", _curlError, auth_hint
01172                 ));
01173               }
01174               else
01175               if ( httpReturnCode == 404)
01176               {
01177                  ZYPP_THROW(MediaFileNotFoundException(_url, filename));
01178               }
01179 
01180               msg += err;
01181               DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
01182               ZYPP_THROW(MediaCurlException(url, msg, _curlError));
01183             }
01184             else
01185             {
01186               string msg = "Unable to retrieve HTTP response:";
01187               msg += err;
01188               DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
01189               ZYPP_THROW(MediaCurlException(url, msg, _curlError));
01190             }
01191           }
01192           break;
01193         case CURLE_FTP_COULDNT_RETR_FILE:
01194         case CURLE_FTP_ACCESS_DENIED:
01195           err = "File not found";
01196           err_file_not_found = true;
01197           break;
01198         case CURLE_BAD_PASSWORD_ENTERED:
01199         case CURLE_FTP_USER_PASSWORD_INCORRECT:
01200           err = "Login failed";
01201           break;
01202         case CURLE_COULDNT_RESOLVE_PROXY:
01203         case CURLE_COULDNT_RESOLVE_HOST:
01204         case CURLE_COULDNT_CONNECT:
01205         case CURLE_FTP_CANT_GET_HOST:
01206           err = "Connection failed";
01207           break;
01208         case CURLE_WRITE_ERROR:
01209           err = "Write error";
01210           break;
01211         case CURLE_ABORTED_BY_CALLBACK:
01212           if( progressData.reached)
01213           {
01214             err  = "Timeout reached";
01215           }
01216           else
01217           {
01218             err = "User abort";
01219           }
01220           break;
01221         case CURLE_SSL_PEER_CERTIFICATE:
01222         default:
01223           err = "Unrecognized error";
01224           break;
01225        }
01226        if( err_file_not_found)
01227        {
01228          ZYPP_THROW(MediaFileNotFoundException(_url, filename));
01229        }
01230        else
01231        {
01232          ZYPP_THROW(MediaCurlException(url, err, _curlError));
01233        }
01234       }
01235       catch (const MediaException & excpt_r)
01236       {
01237         ZYPP_RETHROW(excpt_r);
01238       }
01239     }
01240 #if DETECT_DIR_INDEX
01241     else
01242     if(curlUrl.getScheme() == "http" ||
01243        curlUrl.getScheme() == "https")
01244     {
01245       //
01246       // try to check the effective url and set the not_a_file flag
01247       // if the url path ends with a "/", what usually means, that
01248       // we've received a directory index (index.html content).
01249       //
01250       // Note: This may be dangerous and break file retrieving in
01251       //       case of some server redirections ... ?
01252       //
01253       bool      not_a_file = false;
01254       char     *ptr = NULL;
01255       CURLcode  ret = curl_easy_getinfo( _curl,
01256                                          CURLINFO_EFFECTIVE_URL,
01257                                          &ptr);
01258       if ( ret == CURLE_OK && ptr != NULL)
01259       {
01260         try
01261         {
01262           Url         eurl( ptr);
01263           std::string path( eurl.getPathName());
01264           if( !path.empty() && path != "/" && *path.rbegin() == '/')
01265           {
01266             DBG << "Effective url ("
01267                 << eurl
01268                 << ") seems to provide the index of a directory"
01269                 << endl;
01270             not_a_file = true;
01271           }
01272         }
01273         catch( ... )
01274         {}
01275       }
01276 
01277       if( not_a_file)
01278       {
01279         ::fclose( file );
01280         filesystem::unlink( destNew );
01281         ZYPP_THROW(MediaNotAFileException(_url, filename));
01282       }
01283     }
01284 #endif // DETECT_DIR_INDEX
01285 
01286     if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
01287     {
01288       ERR << "Failed to chmod file " << destNew << endl;
01289     }
01290     ::fclose( file );
01291 
01292     if ( rename( destNew, dest ) != 0 ) {
01293       ERR << "Rename failed" << endl;
01294       ZYPP_THROW(MediaWriteException(dest));
01295     }
01296     DBG << "done: " << PathInfo(dest) << endl;
01297 }
01298 
01299 
01301 //
01302 //
01303 //        METHOD NAME : MediaCurl::getDir
01304 //        METHOD TYPE : PMError
01305 //
01306 //        DESCRIPTION : Asserted that media is attached
01307 //
01308 void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
01309 {
01310   filesystem::DirContent content;
01311   getDirInfo( content, dirname, /*dots*/false );
01312 
01313   for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
01314       Pathname filename = dirname + it->name;
01315       int res = 0;
01316 
01317       switch ( it->type ) {
01318       case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
01319       case filesystem::FT_FILE:
01320         getFile( filename );
01321         break;
01322       case filesystem::FT_DIR: // newer directory.yast contain at least directory info
01323         if ( recurse_r ) {
01324           getDir( filename, recurse_r );
01325         } else {
01326           res = assert_dir( localPath( filename ) );
01327           if ( res ) {
01328             WAR << "Ignore error (" << res <<  ") on creating local directory '" << localPath( filename ) << "'" << endl;
01329           }
01330         }
01331         break;
01332       default:
01333         // don't provide devices, sockets, etc.
01334         break;
01335       }
01336   }
01337 }
01338 
01340 //
01341 //
01342 //        METHOD NAME : MediaCurl::getDirInfo
01343 //        METHOD TYPE : PMError
01344 //
01345 //        DESCRIPTION : Asserted that media is attached and retlist is empty.
01346 //
01347 void MediaCurl::getDirInfo( std::list<std::string> & retlist,
01348                                const Pathname & dirname, bool dots ) const
01349 {
01350   getDirectoryYast( retlist, dirname, dots );
01351 }
01352 
01354 //
01355 //
01356 //        METHOD NAME : MediaCurl::getDirInfo
01357 //        METHOD TYPE : PMError
01358 //
01359 //        DESCRIPTION : Asserted that media is attached and retlist is empty.
01360 //
01361 void MediaCurl::getDirInfo( filesystem::DirContent & retlist,
01362                             const Pathname & dirname, bool dots ) const
01363 {
01364   getDirectoryYast( retlist, dirname, dots );
01365 }
01366 
01368 //
01369 //
01370 //        METHOD NAME : MediaCurl::progressCallback
01371 //        METHOD TYPE : int
01372 //
01373 //        DESCRIPTION : Progress callback triggered from MediaCurl::getFile
01374 //
01375 int MediaCurl::progressCallback( void *clientp, double dltotal, double dlnow,
01376                                  double ultotal, double ulnow )
01377 {
01378   ProgressData *pdata = reinterpret_cast<ProgressData *>(clientp);
01379   if( pdata)
01380   {
01381     // send progress report first, abort transfer if requested
01382     if( pdata->report)
01383     {
01384       if (! (*(pdata->report))->progress(int( dlnow * 100 / dltotal ), pdata->url))
01385       {
01386         return 1; // abort transfer
01387       }
01388     }
01389 
01390     // check if we there is a timeout set
01391     if( pdata->timeout > 0)
01392     {
01393       time_t now = time(NULL);
01394       if( now > 0)
01395       {
01396         bool progress = false;
01397 
01398         // reset time of last change in case initial time()
01399         // failed or the time was adjusted (goes backward)
01400         if( pdata->ltime <= 0 || pdata->ltime > now)
01401           pdata->ltime = now;
01402 
01403         // update download data if changed, mark progress
01404         if( dlnow != pdata->dload)
01405         {
01406           progress     = true;
01407           pdata->dload = dlnow;
01408           pdata->ltime = now;
01409         }
01410         // update upload data if changed, mark progress
01411         if( ulnow != pdata->uload)
01412         {
01413           progress     = true;
01414           pdata->uload = ulnow;
01415           pdata->ltime = now;
01416         }
01417 
01418         if( !progress && (now >= (pdata->ltime + pdata->timeout)))
01419         {
01420           pdata->reached = true;
01421           return 1; // aborts transfer
01422         }
01423       }
01424     }
01425   }
01426   return 0;
01427 }
01428 
01429 string MediaCurl::getAuthHint() const
01430 {
01431   long auth_info = CURLAUTH_NONE;
01432 
01433   CURLcode infoRet =
01434     curl_easy_getinfo(_curl, CURLINFO_HTTPAUTH_AVAIL, &auth_info);
01435 
01436   if(infoRet == CURLE_OK)
01437   {
01438     return CurlAuthData::auth_type_long2str(auth_info);
01439   }
01440 
01441   return "";
01442 }
01443 
01444   } // namespace media
01445 } // namespace zypp
01446 //

Generated on Tue Oct 21 02:32:57 2008 for libzypp by  doxygen 1.5.3