xref: /haiku/src/kits/package/FetchFileJob.cpp (revision b2acee1cb986b696adfad7daabfe9279949a3e54)
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 	#if LIBCURL_VERSION_MAJOR > 7 \
94 		|| (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 32)
95 		result = curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0);
96 
97 		result = curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION,
98 			&_TransferCallback);
99 		if (result != CURLE_OK)
100 			return B_BAD_VALUE;
101 	#endif
102 
103 	result = curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this);
104 	if (result != CURLE_OK)
105 		return B_ERROR;
106 
107 	result = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION,
108 		&_WriteCallback);
109 	if (result != CURLE_OK)
110 		return B_ERROR;
111 
112 	result = curl_easy_setopt(handle, CURLOPT_WRITEDATA, this);
113 	if (result != CURLE_OK)
114 		return B_ERROR;
115 
116 	result = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
117 	if (result != CURLE_OK)
118 		return B_ERROR;
119 
120 	result = curl_easy_setopt(handle, CURLOPT_URL, fFileURL.String());
121 	if (result != CURLE_OK)
122 		return B_ERROR;
123 
124 	result = curl_easy_perform(handle);
125 	curl_easy_cleanup(handle);
126 
127 	switch (result) {
128 		case CURLE_OK:
129 			return B_OK;
130 		case CURLE_UNSUPPORTED_PROTOCOL:
131 			return EPROTONOSUPPORT;
132 		case CURLE_FAILED_INIT:
133 			return B_NO_INIT;
134 		case CURLE_URL_MALFORMAT:
135 			return B_BAD_VALUE;
136 		case CURLE_NOT_BUILT_IN:
137 			return B_NOT_SUPPORTED;
138 		case CURLE_COULDNT_RESOLVE_PROXY:
139 		case CURLE_COULDNT_RESOLVE_HOST:
140 			return B_NAME_NOT_FOUND;
141 		case CURLE_COULDNT_CONNECT:
142 			return ECONNREFUSED;
143 		case CURLE_FTP_WEIRD_SERVER_REPLY:
144 			return B_BAD_DATA;
145 		case CURLE_REMOTE_ACCESS_DENIED:
146 			return B_NOT_ALLOWED;
147 		case CURLE_PARTIAL_FILE:
148 			return B_PARTIAL_READ;
149 		case CURLE_OUT_OF_MEMORY:
150 			return B_NO_MEMORY;
151 		case CURLE_OPERATION_TIMEDOUT:
152 			return B_TIMED_OUT;
153 		case CURLE_SSL_CONNECT_ERROR:
154 			return B_BAD_REPLY;
155 		default:
156 			// TODO: map more curl error codes to ours for more
157 			// precise error reporting
158 			return B_ERROR;
159 	}
160 
161 	#endif /* !HAIKU_BOOTSTRAP_BUILD */
162 
163 	return B_OK;
164 }
165 
166 
167 int
168 FetchFileJob::_TransferCallback(void* _job, off_t downloadTotal,
169 	off_t downloaded, off_t uploadTotal, off_t uploaded)
170 {
171 	FetchFileJob* job = reinterpret_cast<FetchFileJob*>(_job);
172 	if (downloadTotal != 0) {
173 		job->fBytes = downloaded;
174 		job->fTotalBytes = downloadTotal;
175 		job->fDownloadProgress = (float)downloaded / downloadTotal;
176 		job->NotifyStateListeners();
177 	}
178 	return 0;
179 }
180 
181 
182 size_t
183 FetchFileJob::_WriteCallback(void *buffer, size_t size, size_t nmemb,
184 	void *userp)
185 {
186 	FetchFileJob* job = reinterpret_cast<FetchFileJob*>(userp);
187 	ssize_t dataWritten = job->fTargetFile.Write(buffer, size * nmemb);
188 	return size_t(dataWritten);
189 }
190 
191 
192 void
193 FetchFileJob::Cleanup(status_t jobResult)
194 {
195 	if (jobResult != B_OK)
196 		fTargetEntry.Remove();
197 }
198 
199 
200 }	// namespace BPrivate
201 
202 }	// namespace BPackageKit
203