dequote URL taken from Location in redirects as we will otherwise
[ntk/apt.git] / apt-pkg / acquire-method.cc
CommitLineData
93bf083d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: acquire-method.cc,v 1.27.2.1 2003/12/24 23:09:17 mdz Exp $
93bf083d
AL
4/* ######################################################################
5
6 Acquire Method
7
8384ebdf 8 This is a skeleton class that implements most of the functionality
b2e465d6 9 of a method and some useful functions to make method implementation
8384ebdf
AL
10 simpler. The methods all derive this and specialize it. The most
11 complex implementation is the http method which needs to provide
12 pipelining, it runs the message engine at the same time it is
13 downloading files..
14
93bf083d
AL
15 ##################################################################### */
16 /*}}}*/
17// Include Files /*{{{*/
93bf083d
AL
18#include <apt-pkg/acquire-method.h>
19#include <apt-pkg/error.h>
20#include <apt-pkg/configuration.h>
cdcc6d34 21#include <apt-pkg/strutl.h>
93bf083d 22#include <apt-pkg/fileutl.h>
a7c835af 23#include <apt-pkg/hashes.h>
b4fc9b6f
AL
24
25#include <iostream>
2c206aa4 26#include <stdarg.h>
93bf083d 27#include <stdio.h>
b3d44315 28#include <sys/signal.h>
93bf083d
AL
29 /*}}}*/
30
b4fc9b6f
AL
31using namespace std;
32
93bf083d
AL
33// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
34// ---------------------------------------------------------------------
35/* This constructs the initialization text */
36pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
37{
c8848ae2
DK
38 std::cout << "100 Capabilities\n"
39 << "Version: " << Ver << "\n";
93bf083d
AL
40
41 if ((Flags & SingleInstance) == SingleInstance)
c8848ae2
DK
42 std::cout << "Single-Instance: true\n";
43
93bf083d 44 if ((Flags & Pipeline) == Pipeline)
c8848ae2
DK
45 std::cout << "Pipeline: true\n";
46
93bf083d 47 if ((Flags & SendConfig) == SendConfig)
c8848ae2 48 std::cout << "Send-Config: true\n";
e331f6ed
AL
49
50 if ((Flags & LocalOnly) == LocalOnly)
c8848ae2 51 std::cout <<"Local-Only: true\n";
8e5fc8f5
AL
52
53 if ((Flags & NeedsCleanup) == NeedsCleanup)
c8848ae2 54 std::cout << "Needs-Cleanup: true\n";
459681d3
AL
55
56 if ((Flags & Removable) == Removable)
c8848ae2 57 std::cout << "Removable: true\n";
93bf083d 58
c8848ae2 59 std::cout << "\n" << std::flush;
be4401bf
AL
60
61 SetNonBlock(STDIN_FILENO,true);
5cb5d8dc 62
92e889c8 63 Queue = 0;
5cb5d8dc 64 QueueBack = 0;
93bf083d
AL
65}
66 /*}}}*/
67// AcqMethod::Fail - A fetch has failed /*{{{*/
68// ---------------------------------------------------------------------
69/* */
a72ace20 70void pkgAcqMethod::Fail(bool Transient)
93bf083d
AL
71{
72 string Err = "Undetermined Error";
73 if (_error->empty() == false)
74 _error->PopMessage(Err);
75 _error->Discard();
a72ace20 76 Fail(Err,Transient);
93bf083d
AL
77}
78 /*}}}*/
79// AcqMethod::Fail - A fetch has failed /*{{{*/
80// ---------------------------------------------------------------------
81/* */
a72ace20 82void pkgAcqMethod::Fail(string Err,bool Transient)
6d5dd02a
AL
83{
84 // Strip out junk from the error messages
b4fc9b6f 85 for (string::iterator I = Err.begin(); I != Err.end(); I++)
6d5dd02a
AL
86 {
87 if (*I == '\r')
88 *I = ' ';
89 if (*I == '\n')
90 *I = ' ';
91 }
c8848ae2 92
be4401bf
AL
93 if (Queue != 0)
94 {
c8848ae2
DK
95 std::cout << "400 URI Failure\nURI: " << Queue->Uri << "\n"
96 << "Message: " << Err << " " << IP << "\n";
be4401bf
AL
97 // Dequeue
98 FetchItem *Tmp = Queue;
99 Queue = Queue->Next;
100 delete Tmp;
5cb5d8dc
AL
101 if (Tmp == QueueBack)
102 QueueBack = Queue;
be4401bf
AL
103 }
104 else
c8848ae2
DK
105 std::cout << "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err << "\n";
106
36280399 107 if(FailReason.empty() == false)
c8848ae2 108 std::cout << "FailReason: " << FailReason << "\n";
36280399 109 if (UsedMirror.empty() == false)
c8848ae2
DK
110 std::cout << "UsedMirror: " << UsedMirror << "\n";
111 // Set the transient flag
a72ace20 112 if (Transient == true)
c8848ae2
DK
113 std::cout << "Transient-Failure: true\n";
114
115 std::cout << "\n" << std::flush;
93bf083d
AL
116}
117 /*}}}*/
118// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
119// ---------------------------------------------------------------------
120/* */
be4401bf 121void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 122{
be4401bf
AL
123 if (Queue == 0)
124 abort();
c8848ae2
DK
125
126 std::cout << "200 URI Start\n"
127 << "URI: " << Queue->Uri << "\n";
93bf083d 128 if (Res.Size != 0)
c8848ae2
DK
129 std::cout << "Size: " << Res.Size << "\n";
130
93bf083d 131 if (Res.LastModified != 0)
c8848ae2
DK
132 std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
133
be4401bf 134 if (Res.ResumePoint != 0)
c8848ae2
DK
135 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
136
196fd136 137 if (UsedMirror.empty() == false)
c8848ae2
DK
138 std::cout << "UsedMirror: " << UsedMirror << "\n";
139
140 std::cout << "\n" << std::flush;
93bf083d
AL
141}
142 /*}}}*/
143// AcqMethod::URIDone - A URI is finished /*{{{*/
144// ---------------------------------------------------------------------
145/* */
146void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
147{
be4401bf
AL
148 if (Queue == 0)
149 abort();
c8848ae2
DK
150
151 std::cout << "201 URI Done\n"
152 << "URI: " << Queue->Uri << "\n";
93bf083d
AL
153
154 if (Res.Filename.empty() == false)
c8848ae2
DK
155 std::cout << "Filename: " << Res.Filename << "\n";
156
93bf083d 157 if (Res.Size != 0)
c8848ae2
DK
158 std::cout << "Size: " << Res.Size << "\n";
159
93bf083d 160 if (Res.LastModified != 0)
c8848ae2 161 std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
93bf083d
AL
162
163 if (Res.MD5Sum.empty() == false)
c8848ae2
DK
164 std::cout << "MD5-Hash: " << Res.MD5Sum << "\n"
165 << "MD5Sum-Hash: " << Res.MD5Sum << "\n";
a7c835af 166 if (Res.SHA1Sum.empty() == false)
c8848ae2 167 std::cout << "SHA1-Hash: " << Res.SHA1Sum << "\n";
5d0d7fae 168 if (Res.SHA256Sum.empty() == false)
c8848ae2 169 std::cout << "SHA256-Hash: " << Res.SHA256Sum << "\n";
36280399 170 if (UsedMirror.empty() == false)
c8848ae2
DK
171 std::cout << "UsedMirror: " << UsedMirror << "\n";
172 if (Res.GPGVOutput.empty() == false)
173 {
174 std::cout << "GPGVOutput:\n";
175 for (vector<string>::const_iterator I = Res.GPGVOutput.begin();
176 I != Res.GPGVOutput.end(); ++I)
177 std::cout << " " << *I << "\n";
178 }
93bf083d 179
b98f2859 180 if (Res.ResumePoint != 0)
c8848ae2 181 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
b98f2859 182
93bf083d 183 if (Res.IMSHit == true)
c8848ae2
DK
184 std::cout << "IMS-Hit: true\n";
185
93bf083d
AL
186 if (Alt != 0)
187 {
188 if (Alt->Filename.empty() == false)
c8848ae2
DK
189 std::cout << "Alt-Filename: " << Alt->Filename << "\n";
190
93bf083d 191 if (Alt->Size != 0)
c8848ae2
DK
192 std::cout << "Alt-Size: " << Alt->Size << "\n";
193
93bf083d 194 if (Alt->LastModified != 0)
c8848ae2
DK
195 std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
196
93bf083d 197 if (Alt->MD5Sum.empty() == false)
c8848ae2 198 std::cout << "Alt-MD5-Hash: " << Alt->MD5Sum << "\n";
a7c835af 199 if (Alt->SHA1Sum.empty() == false)
c8848ae2 200 std::cout << "Alt-SHA1-Hash: " << Alt->SHA1Sum << "\n";
5d0d7fae 201 if (Alt->SHA256Sum.empty() == false)
c8848ae2
DK
202 std::cout << "Alt-SHA256-Hash: " << Alt->SHA256Sum << "\n";
203
93bf083d 204 if (Alt->IMSHit == true)
c8848ae2 205 std::cout << "Alt-IMS-Hit: true\n";
93bf083d 206 }
c8848ae2
DK
207
208 std::cout << "\n" << std::flush;
be4401bf
AL
209
210 // Dequeue
211 FetchItem *Tmp = Queue;
212 Queue = Queue->Next;
213 delete Tmp;
5cb5d8dc
AL
214 if (Tmp == QueueBack)
215 QueueBack = Queue;
93bf083d
AL
216}
217 /*}}}*/
f46e7681
AL
218// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
219// ---------------------------------------------------------------------
220/* This sends a 403 Media Failure message to the APT and waits for it
221 to be ackd */
018f1533 222bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681 223{
c8848ae2 224 fprintf(stdout, "403 Media Failure\nMedia: %s\nDrive: %s\n",
f46e7681 225 Required.c_str(),Drive.c_str());
c8848ae2 226 std::cout << "\n" << std::flush;
f46e7681 227
f46e7681
AL
228 vector<string> MyMessages;
229
230 /* Here we read messages until we find a 603, each non 603 message is
231 appended to the main message list for later processing */
232 while (1)
233 {
234 if (WaitFd(STDIN_FILENO) == false)
76d97c26 235 return false;
f46e7681
AL
236
237 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
238 return false;
239
f46e7681
AL
240 string Message = MyMessages.front();
241 MyMessages.erase(MyMessages.begin());
242
243 // Fetch the message number
244 char *End;
245 int Number = strtol(Message.c_str(),&End,10);
246 if (End == Message.c_str())
247 {
248 cerr << "Malformed message!" << endl;
249 exit(100);
250 }
251
252 // Change ack
253 if (Number == 603)
254 {
76d97c26 255 while (MyMessages.empty() == false)
f46e7681
AL
256 {
257 Messages.push_back(MyMessages.front());
258 MyMessages.erase(MyMessages.begin());
259 }
542ec555 260
2a749770 261 return !StringToBool(LookupTag(Message,"Failed"),false);
f46e7681
AL
262 }
263
264 Messages.push_back(Message);
265 }
266}
267 /*}}}*/
93bf083d
AL
268// AcqMethod::Configuration - Handle the configuration message /*{{{*/
269// ---------------------------------------------------------------------
270/* This parses each configuration entry and puts it into the _config
271 Configuration class. */
272bool pkgAcqMethod::Configuration(string Message)
273{
274 ::Configuration &Cnf = *_config;
275
b4fc9b6f
AL
276 const char *I = Message.c_str();
277 const char *MsgEnd = I + Message.length();
93bf083d
AL
278
279 unsigned int Length = strlen("Config-Item");
b4fc9b6f 280 for (; I + Length < MsgEnd; I++)
93bf083d
AL
281 {
282 // Not a config item
283 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
284 continue;
285
286 I += Length + 1;
287
b4fc9b6f 288 for (; I < MsgEnd && *I == ' '; I++);
93bf083d 289 const char *Equals = I;
b4fc9b6f 290 for (; Equals < MsgEnd && *Equals != '='; Equals++);
93bf083d 291 const char *End = Equals;
b4fc9b6f 292 for (; End < MsgEnd && *End != '\n'; End++);
93bf083d
AL
293 if (End == Equals)
294 return false;
295
6d5dd02a
AL
296 Cnf.Set(DeQuoteString(string(I,Equals-I)),
297 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
298 I = End;
299 }
300
301 return true;
302}
303 /*}}}*/
304// AcqMethod::Run - Run the message engine /*{{{*/
305// ---------------------------------------------------------------------
8384ebdf
AL
306/* Fetch any messages and execute them. In single mode it returns 1 if
307 there are no more available messages - any other result is a
308 fatal failure code! */
be4401bf 309int pkgAcqMethod::Run(bool Single)
93bf083d 310{
93bf083d
AL
311 while (1)
312 {
be4401bf 313 // Block if the message queue is empty
93bf083d 314 if (Messages.empty() == true)
be4401bf
AL
315 {
316 if (Single == false)
317 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 318 break;
92e889c8 319 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 320 break;
92e889c8
AL
321 }
322
be4401bf
AL
323 // Single mode exits if the message queue is empty
324 if (Single == true && Messages.empty() == true)
8384ebdf 325 return -1;
be4401bf 326
93bf083d
AL
327 string Message = Messages.front();
328 Messages.erase(Messages.begin());
329
330 // Fetch the message number
331 char *End;
332 int Number = strtol(Message.c_str(),&End,10);
333 if (End == Message.c_str())
334 {
335 cerr << "Malformed message!" << endl;
336 return 100;
337 }
338
339 switch (Number)
8e5fc8f5 340 {
93bf083d
AL
341 case 601:
342 if (Configuration(Message) == false)
343 return 100;
344 break;
345
346 case 600:
be4401bf
AL
347 {
348 FetchItem *Tmp = new FetchItem;
349
350 Tmp->Uri = LookupTag(Message,"URI");
351 Tmp->DestFile = LookupTag(Message,"FileName");
96cc64a5 352 if (RFC1123StrToTime(LookupTag(Message,"Last-Modified").c_str(),Tmp->LastModified) == false)
b98f2859 353 Tmp->LastModified = 0;
a72ace20 354 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
963b16dc 355 Tmp->FailIgnore = StringToBool(LookupTag(Message,"Fail-Ignore"),false);
be4401bf
AL
356 Tmp->Next = 0;
357
358 // Append it to the list
359 FetchItem **I = &Queue;
92e889c8 360 for (; *I != 0; I = &(*I)->Next);
be4401bf 361 *I = Tmp;
5cb5d8dc
AL
362 if (QueueBack == 0)
363 QueueBack = Tmp;
364
bfd22fc0 365 // Notify that this item is to be fetched.
be4401bf 366 if (Fetch(Tmp) == false)
93bf083d 367 Fail();
bfd22fc0 368
93bf083d
AL
369 break;
370 }
371 }
372 }
373
8e5fc8f5 374 Exit();
93bf083d
AL
375 return 0;
376}
377 /*}}}*/
be4401bf
AL
378// AcqMethod::Log - Send a log message /*{{{*/
379// ---------------------------------------------------------------------
380/* */
381void pkgAcqMethod::Log(const char *Format,...)
382{
383 string CurrentURI = "<UNKNOWN>";
384 if (Queue != 0)
385 CurrentURI = Queue->Uri;
c8848ae2
DK
386 fprintf(stdout, "101 Log\nURI: %s\nUsedMirror: %s\nMessage: ",
387 UsedMirror.c_str(), CurrentURI.c_str());
388
be4401bf
AL
389 va_list args;
390 va_start(args,Format);
c8848ae2
DK
391 vfprintf(stdout,Format,args);
392 va_end(args);
be4401bf 393
c8848ae2 394 std::cout << "\n\n" << std::flush;
be4401bf
AL
395}
396 /*}}}*/
397// AcqMethod::Status - Send a status message /*{{{*/
398// ---------------------------------------------------------------------
399/* */
400void pkgAcqMethod::Status(const char *Format,...)
401{
402 string CurrentURI = "<UNKNOWN>";
403 if (Queue != 0)
404 CurrentURI = Queue->Uri;
c8848ae2
DK
405 fprintf(stdout, "102 Status\nURI: %s\nUsedMirror: %s\nMessage: ",
406 UsedMirror.c_str(), CurrentURI.c_str());
407
be4401bf
AL
408 va_list args;
409 va_start(args,Format);
c8848ae2
DK
410 vfprintf(stdout,Format,args);
411 va_end(args);
be4401bf 412
c8848ae2 413 std::cout << "\n\n" << std::flush;
be4401bf
AL
414}
415 /*}}}*/
ebb461fd
MV
416// AcqMethod::Redirect - Send a redirect message /*{{{*/
417// ---------------------------------------------------------------------
418/* This method sends the redirect message and also manipulates the queue
419 to keep the pipeline synchronized. */
420void pkgAcqMethod::Redirect(const string &NewURI)
421{
c8848ae2 422 std::cout << "103 Redirect\nURI: ";
ebb461fd 423 if (Queue != 0)
c8848ae2
DK
424 std::cout << Queue->Uri << "\n";
425 else
426 std::cout << "<UNKNOWN>\n";
427 std::cout << "New-URI: " << NewURI << "\n"
428 << "\n" << std::flush;
ebb461fd
MV
429
430 // Change the URI for the request.
431 Queue->Uri = NewURI;
432
433 /* To keep the pipeline synchronized, move the current request to
434 the end of the queue, past the end of the current pipeline. */
435 FetchItem *I;
436 for (I = Queue; I->Next != 0; I = I->Next) ;
437 I->Next = Queue;
438 Queue = Queue->Next;
439 I->Next->Next = 0;
440 if (QueueBack == 0)
441 QueueBack = I->Next;
442}
443 /*}}}*/
93bf083d
AL
444// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
445// ---------------------------------------------------------------------
446/* */
93274b8d
AL
447pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
448 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
449{
450}
451 /*}}}*/
a7c835af
AL
452// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
453// ---------------------------------------------------------------------
454/* This hides the number of hashes we are supporting from the caller.
455 It just deals with the hash class. */
456void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
457{
458 MD5Sum = Hash.MD5.Result();
459 SHA1Sum = Hash.SHA1.Result();
5d0d7fae 460 SHA256Sum = Hash.SHA256.Result();
a7c835af
AL
461}
462 /*}}}*/