1 /* 2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler <axeld@pinc-software.de> 7 * Rene Gollent <rene@gollent.com> 8 * Oliver Tappe <zooey@hirschkaefer.de> 9 */ 10 11 12 #include <package/FetchFileJob.h> 13 14 #include <stdio.h> 15 #ifndef HAIKU_BOOTSTRAP_BUILD 16 #include <curl/curl.h> 17 #endif 18 #include <sys/wait.h> 19 20 #include <Path.h> 21 22 23 namespace BPackageKit { 24 25 namespace BPrivate { 26 27 28 FetchFileJob::FetchFileJob(const BContext& context, const BString& title, 29 const BString& fileURL, const BEntry& targetEntry) 30 : 31 inherited(context, title), 32 fFileURL(fileURL), 33 fTargetEntry(targetEntry), 34 fTargetFile(&targetEntry, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY), 35 fDownloadProgress(0.0) 36 { 37 } 38 39 40 FetchFileJob::~FetchFileJob() 41 { 42 } 43 44 45 float 46 FetchFileJob::DownloadProgress() const 47 { 48 return fDownloadProgress; 49 } 50 51 52 const char* 53 FetchFileJob::DownloadURL() const 54 { 55 return fFileURL.String(); 56 } 57 58 59 const char* 60 FetchFileJob::DownloadFileName() const 61 { 62 return fTargetEntry.Name(); 63 } 64 65 66 off_t 67 FetchFileJob::DownloadBytes() const 68 { 69 return fBytes; 70 } 71 72 73 off_t 74 FetchFileJob::DownloadTotalBytes() const 75 { 76 return fTotalBytes; 77 } 78 79 80 status_t 81 FetchFileJob::Execute() 82 { 83 status_t result = fTargetFile.InitCheck(); 84 if (result != B_OK) 85 return result; 86 87 #ifndef HAIKU_BOOTSTRAP_BUILD 88 CURL* handle = curl_easy_init(); 89 90 if (handle == NULL) 91 return B_NO_MEMORY; 92 93 result = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0); 94 95 result = curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, 96 &_TransferCallback); 97 if (result != CURLE_OK) 98 return B_BAD_VALUE; 99 100 result = curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); 101 if (result != CURLE_OK) 102 return B_ERROR; 103 104 result = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, 105 &_WriteCallback); 106 if (result != CURLE_OK) 107 return B_ERROR; 108 109 result = curl_easy_setopt(handle, CURLOPT_WRITEDATA, this); 110 if (result != CURLE_OK) 111 return B_ERROR; 112 113 result = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 114 if (result != CURLE_OK) 115 return B_ERROR; 116 117 result = curl_easy_setopt(handle, CURLOPT_URL, fFileURL.String()); 118 if (result != CURLE_OK) 119 return B_ERROR; 120 121 result = curl_easy_perform(handle); 122 curl_easy_cleanup(handle); 123 124 switch (result) { 125 case CURLE_OK: 126 return B_OK; 127 case CURLE_UNSUPPORTED_PROTOCOL: 128 return EPROTONOSUPPORT; 129 case CURLE_FAILED_INIT: 130 return B_NO_INIT; 131 case CURLE_URL_MALFORMAT: 132 return B_BAD_VALUE; 133 case CURLE_NOT_BUILT_IN: 134 return B_NOT_SUPPORTED; 135 case CURLE_COULDNT_RESOLVE_PROXY: 136 case CURLE_COULDNT_RESOLVE_HOST: 137 return B_NAME_NOT_FOUND; 138 case CURLE_COULDNT_CONNECT: 139 return ECONNREFUSED; 140 case CURLE_FTP_WEIRD_SERVER_REPLY: 141 return B_BAD_DATA; 142 case CURLE_REMOTE_ACCESS_DENIED: 143 return B_NOT_ALLOWED; 144 case CURLE_PARTIAL_FILE: 145 return B_PARTIAL_READ; 146 case CURLE_OUT_OF_MEMORY: 147 return B_NO_MEMORY; 148 case CURLE_OPERATION_TIMEDOUT: 149 return B_TIMED_OUT; 150 case CURLE_SSL_CONNECT_ERROR: 151 return B_BAD_REPLY; 152 default: 153 // TODO: map more curl error codes to ours for more 154 // precise error reporting 155 return B_ERROR; 156 } 157 158 #endif /* !HAIKU_BOOTSTRAP_BUILD */ 159 160 return B_OK; 161 } 162 163 164 int 165 FetchFileJob::_TransferCallback(void* _job, off_t downloadTotal, 166 off_t downloaded, off_t uploadTotal, off_t uploaded) 167 { 168 FetchFileJob* job = reinterpret_cast<FetchFileJob*>(_job); 169 if (downloadTotal != 0) { 170 job->fBytes = downloaded; 171 job->fTotalBytes = downloadTotal; 172 job->fDownloadProgress = (float)downloaded / downloadTotal; 173 job->NotifyStateListeners(); 174 } 175 return 0; 176 } 177 178 179 size_t 180 FetchFileJob::_WriteCallback(void *buffer, size_t size, size_t nmemb, 181 void *userp) 182 { 183 FetchFileJob* job = reinterpret_cast<FetchFileJob*>(userp); 184 ssize_t dataWritten = job->fTargetFile.Write(buffer, size * nmemb); 185 return size_t(dataWritten); 186 } 187 188 189 void 190 FetchFileJob::Cleanup(status_t jobResult) 191 { 192 if (jobResult != B_OK) 193 fTargetEntry.Remove(); 194 } 195 196 197 } // namespace BPrivate 198 199 } // namespace BPackageKit 200