* cmdline/apt-get.cc:
[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";
36280399 169 if (UsedMirror.empty() == false)
c8848ae2
DK
170 std::cout << "UsedMirror: " << UsedMirror << "\n";
171 if (Res.GPGVOutput.empty() == false)
172 {
173 std::cout << "GPGVOutput:\n";
174 for (vector<string>::const_iterator I = Res.GPGVOutput.begin();
175 I != Res.GPGVOutput.end(); ++I)
176 std::cout << " " << *I << "\n";
177 }
93bf083d 178
b98f2859 179 if (Res.ResumePoint != 0)
c8848ae2 180 std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
b98f2859 181
93bf083d 182 if (Res.IMSHit == true)
c8848ae2
DK
183 std::cout << "IMS-Hit: true\n";
184
93bf083d
AL
185 if (Alt != 0)
186 {
187 if (Alt->Filename.empty() == false)
c8848ae2
DK
188 std::cout << "Alt-Filename: " << Alt->Filename << "\n";
189
93bf083d 190 if (Alt->Size != 0)
c8848ae2
DK
191 std::cout << "Alt-Size: " << Alt->Size << "\n";
192
93bf083d 193 if (Alt->LastModified != 0)
c8848ae2
DK
194 std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
195
93bf083d 196 if (Alt->MD5Sum.empty() == false)
c8848ae2 197 std::cout << "Alt-MD5-Hash: " << Alt->MD5Sum << "\n";
a7c835af 198 if (Alt->SHA1Sum.empty() == false)
c8848ae2 199 std::cout << "Alt-SHA1-Hash: " << Alt->SHA1Sum << "\n";
5d0d7fae 200 if (Alt->SHA256Sum.empty() == false)
c8848ae2
DK
201 std::cout << "Alt-SHA256-Hash: " << Alt->SHA256Sum << "\n";
202
93bf083d 203 if (Alt->IMSHit == true)
c8848ae2 204 std::cout << "Alt-IMS-Hit: true\n";
93bf083d 205 }
c8848ae2
DK
206
207 std::cout << "\n" << std::flush;
be4401bf
AL
208
209 // Dequeue
210 FetchItem *Tmp = Queue;
211 Queue = Queue->Next;
212 delete Tmp;
5cb5d8dc
AL
213 if (Tmp == QueueBack)
214 QueueBack = Queue;
93bf083d
AL
215}
216 /*}}}*/
f46e7681
AL
217// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
218// ---------------------------------------------------------------------
219/* This sends a 403 Media Failure message to the APT and waits for it
220 to be ackd */
018f1533 221bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681 222{
c8848ae2 223 fprintf(stdout, "403 Media Failure\nMedia: %s\nDrive: %s\n",
f46e7681 224 Required.c_str(),Drive.c_str());
c8848ae2 225 std::cout << "\n" << std::flush;
f46e7681 226
f46e7681
AL
227 vector<string> MyMessages;
228
229 /* Here we read messages until we find a 603, each non 603 message is
230 appended to the main message list for later processing */
231 while (1)
232 {
233 if (WaitFd(STDIN_FILENO) == false)
76d97c26 234 return false;
f46e7681
AL
235
236 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
237 return false;
238
f46e7681
AL
239 string Message = MyMessages.front();
240 MyMessages.erase(MyMessages.begin());
241
242 // Fetch the message number
243 char *End;
244 int Number = strtol(Message.c_str(),&End,10);
245 if (End == Message.c_str())
246 {
247 cerr << "Malformed message!" << endl;
248 exit(100);
249 }
250
251 // Change ack
252 if (Number == 603)
253 {
76d97c26 254 while (MyMessages.empty() == false)
f46e7681
AL
255 {
256 Messages.push_back(MyMessages.front());
257 MyMessages.erase(MyMessages.begin());
258 }
542ec555 259
2a749770 260 return !StringToBool(LookupTag(Message,"Failed"),false);
f46e7681
AL
261 }
262
263 Messages.push_back(Message);
264 }
265}
266 /*}}}*/
93bf083d
AL
267// AcqMethod::Configuration - Handle the configuration message /*{{{*/
268// ---------------------------------------------------------------------
269/* This parses each configuration entry and puts it into the _config
270 Configuration class. */
271bool pkgAcqMethod::Configuration(string Message)
272{
273 ::Configuration &Cnf = *_config;
274
b4fc9b6f
AL
275 const char *I = Message.c_str();
276 const char *MsgEnd = I + Message.length();
93bf083d
AL
277
278 unsigned int Length = strlen("Config-Item");
b4fc9b6f 279 for (; I + Length < MsgEnd; I++)
93bf083d
AL
280 {
281 // Not a config item
282 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
283 continue;
284
285 I += Length + 1;
286
b4fc9b6f 287 for (; I < MsgEnd && *I == ' '; I++);
93bf083d 288 const char *Equals = I;
b4fc9b6f 289 for (; Equals < MsgEnd && *Equals != '='; Equals++);
93bf083d 290 const char *End = Equals;
b4fc9b6f 291 for (; End < MsgEnd && *End != '\n'; End++);
93bf083d
AL
292 if (End == Equals)
293 return false;
294
6d5dd02a
AL
295 Cnf.Set(DeQuoteString(string(I,Equals-I)),
296 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
297 I = End;
298 }
299
300 return true;
301}
302 /*}}}*/
303// AcqMethod::Run - Run the message engine /*{{{*/
304// ---------------------------------------------------------------------
8384ebdf
AL
305/* Fetch any messages and execute them. In single mode it returns 1 if
306 there are no more available messages - any other result is a
307 fatal failure code! */
be4401bf 308int pkgAcqMethod::Run(bool Single)
93bf083d 309{
93bf083d
AL
310 while (1)
311 {
be4401bf 312 // Block if the message queue is empty
93bf083d 313 if (Messages.empty() == true)
be4401bf
AL
314 {
315 if (Single == false)
316 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 317 break;
92e889c8 318 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 319 break;
92e889c8
AL
320 }
321
be4401bf
AL
322 // Single mode exits if the message queue is empty
323 if (Single == true && Messages.empty() == true)
8384ebdf 324 return -1;
be4401bf 325
93bf083d
AL
326 string Message = Messages.front();
327 Messages.erase(Messages.begin());
328
329 // Fetch the message number
330 char *End;
331 int Number = strtol(Message.c_str(),&End,10);
332 if (End == Message.c_str())
333 {
334 cerr << "Malformed message!" << endl;
335 return 100;
336 }
337
338 switch (Number)
8e5fc8f5 339 {
93bf083d
AL
340 case 601:
341 if (Configuration(Message) == false)
342 return 100;
343 break;
344
345 case 600:
be4401bf
AL
346 {
347 FetchItem *Tmp = new FetchItem;
348
349 Tmp->Uri = LookupTag(Message,"URI");
350 Tmp->DestFile = LookupTag(Message,"FileName");
96cc64a5 351 if (RFC1123StrToTime(LookupTag(Message,"Last-Modified").c_str(),Tmp->LastModified) == false)
b98f2859 352 Tmp->LastModified = 0;
a72ace20 353 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
963b16dc 354 Tmp->FailIgnore = StringToBool(LookupTag(Message,"Fail-Ignore"),false);
be4401bf
AL
355 Tmp->Next = 0;
356
357 // Append it to the list
358 FetchItem **I = &Queue;
92e889c8 359 for (; *I != 0; I = &(*I)->Next);
be4401bf 360 *I = Tmp;
5cb5d8dc
AL
361 if (QueueBack == 0)
362 QueueBack = Tmp;
363
bfd22fc0 364 // Notify that this item is to be fetched.
be4401bf 365 if (Fetch(Tmp) == false)
93bf083d 366 Fail();
bfd22fc0 367
93bf083d
AL
368 break;
369 }
370 }
371 }
372
8e5fc8f5 373 Exit();
93bf083d
AL
374 return 0;
375}
376 /*}}}*/
f1bdfe81 377// AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
be4401bf
AL
378// ---------------------------------------------------------------------
379/* */
f1bdfe81
DK
380void pkgAcqMethod::PrintStatus(char const * const header, const char* Format,
381 va_list &args) const
be4401bf
AL
382{
383 string CurrentURI = "<UNKNOWN>";
384 if (Queue != 0)
385 CurrentURI = Queue->Uri;
f1bdfe81
DK
386 if (UsedMirror.empty() == true)
387 fprintf(stdout, "%s\nURI: %s\nMessage: ",
388 header, CurrentURI.c_str());
389 else
390 fprintf(stdout, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
391 header, CurrentURI.c_str(), UsedMirror.c_str());
392 vfprintf(stdout,Format,args);
393 std::cout << "\n\n" << std::flush;
394}
395 /*}}}*/
396// AcqMethod::Log - Send a log message /*{{{*/
397// ---------------------------------------------------------------------
398/* */
399void pkgAcqMethod::Log(const char *Format,...)
400{
be4401bf
AL
401 va_list args;
402 va_start(args,Format);
f1bdfe81 403 PrintStatus("101 Log", Format, args);
c8848ae2 404 va_end(args);
be4401bf
AL
405}
406 /*}}}*/
407// AcqMethod::Status - Send a status message /*{{{*/
408// ---------------------------------------------------------------------
409/* */
410void pkgAcqMethod::Status(const char *Format,...)
411{
be4401bf
AL
412 va_list args;
413 va_start(args,Format);
f1bdfe81 414 PrintStatus("102 Status", Format, args);
c8848ae2 415 va_end(args);
be4401bf
AL
416}
417 /*}}}*/
ebb461fd
MV
418// AcqMethod::Redirect - Send a redirect message /*{{{*/
419// ---------------------------------------------------------------------
420/* This method sends the redirect message and also manipulates the queue
421 to keep the pipeline synchronized. */
422void pkgAcqMethod::Redirect(const string &NewURI)
423{
c8848ae2 424 std::cout << "103 Redirect\nURI: ";
ebb461fd 425 if (Queue != 0)
c8848ae2
DK
426 std::cout << Queue->Uri << "\n";
427 else
428 std::cout << "<UNKNOWN>\n";
429 std::cout << "New-URI: " << NewURI << "\n"
430 << "\n" << std::flush;
ebb461fd
MV
431
432 // Change the URI for the request.
433 Queue->Uri = NewURI;
434
435 /* To keep the pipeline synchronized, move the current request to
436 the end of the queue, past the end of the current pipeline. */
437 FetchItem *I;
438 for (I = Queue; I->Next != 0; I = I->Next) ;
439 I->Next = Queue;
440 Queue = Queue->Next;
441 I->Next->Next = 0;
442 if (QueueBack == 0)
443 QueueBack = I->Next;
444}
445 /*}}}*/
93bf083d
AL
446// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
447// ---------------------------------------------------------------------
448/* */
93274b8d
AL
449pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
450 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
451{
452}
453 /*}}}*/
a7c835af
AL
454// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
455// ---------------------------------------------------------------------
456/* This hides the number of hashes we are supporting from the caller.
457 It just deals with the hash class. */
458void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
459{
460 MD5Sum = Hash.MD5.Result();
461 SHA1Sum = Hash.SHA1.Result();
5d0d7fae 462 SHA256Sum = Hash.SHA256.Result();
a7c835af
AL
463}
464 /*}}}*/