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