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