]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-method.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-method.cc,v 1.27.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
8 This is a skeleton class that implements most of the functionality
9 of a method and some useful functions to make method implementation
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
15 ##################################################################### */
17 // Include Files /*{{{*/
20 #include <apt-pkg/acquire-method.h>
21 #include <apt-pkg/error.h>
22 #include <apt-pkg/configuration.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/hashes.h>
26 #include <apt-pkg/md5.h>
27 #include <apt-pkg/sha1.h>
28 #include <apt-pkg/sha2.h>
42 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
43 // ---------------------------------------------------------------------
44 /* This constructs the initialization text */
45 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
47 std::cout
<< "100 Capabilities\n"
48 << "Version: " << Ver
<< "\n";
50 if ((Flags
& SingleInstance
) == SingleInstance
)
51 std::cout
<< "Single-Instance: true\n";
53 if ((Flags
& Pipeline
) == Pipeline
)
54 std::cout
<< "Pipeline: true\n";
56 if ((Flags
& SendConfig
) == SendConfig
)
57 std::cout
<< "Send-Config: true\n";
59 if ((Flags
& LocalOnly
) == LocalOnly
)
60 std::cout
<<"Local-Only: true\n";
62 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
63 std::cout
<< "Needs-Cleanup: true\n";
65 if ((Flags
& Removable
) == Removable
)
66 std::cout
<< "Removable: true\n";
68 std::cout
<< "\n" << std::flush
;
70 SetNonBlock(STDIN_FILENO
,true);
76 // AcqMethod::Fail - A fetch has failed /*{{{*/
77 // ---------------------------------------------------------------------
79 void pkgAcqMethod::Fail(bool Transient
)
81 string Err
= "Undetermined Error";
82 if (_error
->empty() == false)
83 _error
->PopMessage(Err
);
88 // AcqMethod::Fail - A fetch has failed /*{{{*/
89 // ---------------------------------------------------------------------
91 void pkgAcqMethod::Fail(string Err
,bool Transient
)
93 // Strip out junk from the error messages
94 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); ++I
)
104 std::cout
<< "400 URI Failure\nURI: " << Queue
->Uri
<< "\n"
105 << "Message: " << Err
<< " " << IP
<< "\n";
109 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
111 if(FailReason
.empty() == false)
112 std::cout
<< "FailReason: " << FailReason
<< "\n";
113 if (UsedMirror
.empty() == false)
114 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
115 // Set the transient flag
116 if (Transient
== true)
117 std::cout
<< "Transient-Failure: true\n";
119 std::cout
<< "\n" << std::flush
;
122 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
123 // ---------------------------------------------------------------------
125 void pkgAcqMethod::URIStart(FetchResult
&Res
)
130 std::cout
<< "200 URI Start\n"
131 << "URI: " << Queue
->Uri
<< "\n";
133 std::cout
<< "Size: " << Res
.Size
<< "\n";
135 if (Res
.LastModified
!= 0)
136 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
138 if (Res
.ResumePoint
!= 0)
139 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
141 if (UsedMirror
.empty() == false)
142 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
144 std::cout
<< "\n" << std::flush
;
147 // AcqMethod::URIDone - A URI is finished /*{{{*/
148 // ---------------------------------------------------------------------
150 static void printHashStringList(HashStringList
const * const list
)
152 for (HashStringList::const_iterator hash
= list
->begin(); hash
!= list
->end(); ++hash
)
154 // very old compatibility name for MD5Sum
155 if (hash
->HashType() == "MD5Sum")
156 std::cout
<< "MD5-Hash: " << hash
->HashValue() << "\n";
157 std::cout
<< hash
->HashType() << "-Hash: " << hash
->HashValue() << "\n";
160 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
165 std::cout
<< "201 URI Done\n"
166 << "URI: " << Queue
->Uri
<< "\n";
168 if (Res
.Filename
.empty() == false)
169 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
172 std::cout
<< "Size: " << Res
.Size
<< "\n";
174 if (Res
.LastModified
!= 0)
175 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
177 printHashStringList(&Res
.Hashes
);
179 if (UsedMirror
.empty() == false)
180 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
181 if (Res
.GPGVOutput
.empty() == false)
183 std::cout
<< "GPGVOutput:\n";
184 for (vector
<string
>::const_iterator I
= Res
.GPGVOutput
.begin();
185 I
!= Res
.GPGVOutput
.end(); ++I
)
186 std::cout
<< " " << *I
<< "\n";
189 if (Res
.ResumePoint
!= 0)
190 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
192 if (Res
.IMSHit
== true)
193 std::cout
<< "IMS-Hit: true\n";
197 if (Alt
->Filename
.empty() == false)
198 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
201 std::cout
<< "Alt-Size: " << Alt
->Size
<< "\n";
203 if (Alt
->LastModified
!= 0)
204 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n";
206 printHashStringList(&Alt
->Hashes
);
208 if (Alt
->IMSHit
== true)
209 std::cout
<< "Alt-IMS-Hit: true\n";
212 std::cout
<< "\n" << std::flush
;
216 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
217 // ---------------------------------------------------------------------
218 /* This sends a 403 Media Failure message to the APT and waits for it
220 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
222 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
223 Required
.c_str(),Drive
.c_str());
224 std::cout
<< "\n" << std::flush
;
226 vector
<string
> MyMessages
;
228 /* Here we read messages until we find a 603, each non 603 message is
229 appended to the main message list for later processing */
232 if (WaitFd(STDIN_FILENO
) == false)
235 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
238 string Message
= MyMessages
.front();
239 MyMessages
.erase(MyMessages
.begin());
241 // Fetch the message number
243 int Number
= strtol(Message
.c_str(),&End
,10);
244 if (End
== Message
.c_str())
246 cerr
<< "Malformed message!" << endl
;
253 while (MyMessages
.empty() == false)
255 Messages
.push_back(MyMessages
.front());
256 MyMessages
.erase(MyMessages
.begin());
259 return !StringToBool(LookupTag(Message
,"Failed"),false);
262 Messages
.push_back(Message
);
266 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
267 // ---------------------------------------------------------------------
268 /* This parses each configuration entry and puts it into the _config
269 Configuration class. */
270 bool pkgAcqMethod::Configuration(string Message
)
272 ::Configuration
&Cnf
= *_config
;
274 const char *I
= Message
.c_str();
275 const char *MsgEnd
= I
+ Message
.length();
277 unsigned int Length
= strlen("Config-Item");
278 for (; I
+ Length
< MsgEnd
; I
++)
281 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
286 for (; I
< MsgEnd
&& *I
== ' '; I
++);
287 const char *Equals
= (const char*) memchr(I
, '=', MsgEnd
- I
);
290 const char *End
= (const char*) memchr(Equals
, '\n', MsgEnd
- Equals
);
294 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
295 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
302 // AcqMethod::Run - Run the message engine /*{{{*/
303 // ---------------------------------------------------------------------
304 /* Fetch any messages and execute them. In single mode it returns 1 if
305 there are no more available messages - any other result is a
306 fatal failure code! */
307 int pkgAcqMethod::Run(bool Single
)
311 // Block if the message queue is empty
312 if (Messages
.empty() == true)
315 if (WaitFd(STDIN_FILENO
) == false)
317 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
321 // Single mode exits if the message queue is empty
322 if (Single
== true && Messages
.empty() == true)
325 string Message
= Messages
.front();
326 Messages
.erase(Messages
.begin());
328 // Fetch the message number
330 int Number
= strtol(Message
.c_str(),&End
,10);
331 if (End
== Message
.c_str())
333 cerr
<< "Malformed message!" << endl
;
340 if (Configuration(Message
) == false)
346 FetchItem
*Tmp
= new FetchItem
;
348 Tmp
->Uri
= LookupTag(Message
,"URI");
349 Tmp
->DestFile
= LookupTag(Message
,"FileName");
350 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
351 Tmp
->LastModified
= 0;
352 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
353 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
354 Tmp
->ExpectedHashes
= HashStringList();
355 for (char const * const * t
= HashString::SupportedHashes(); *t
!= NULL
; ++t
)
357 std::string tag
= "Expected-";
359 std::string
const hash
= LookupTag(Message
, tag
.c_str());
360 if (hash
.empty() == false)
361 Tmp
->ExpectedHashes
.push_back(HashString(*t
, hash
));
365 // Append it to the list
366 FetchItem
**I
= &Queue
;
367 for (; *I
!= 0; I
= &(*I
)->Next
);
372 // Notify that this item is to be fetched.
373 if (Fetch(Tmp
) == false)
385 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
386 // ---------------------------------------------------------------------
388 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
391 string CurrentURI
= "<UNKNOWN>";
393 CurrentURI
= Queue
->Uri
;
394 if (UsedMirror
.empty() == true)
395 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
396 header
, CurrentURI
.c_str());
398 fprintf(stdout
, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
399 header
, CurrentURI
.c_str(), UsedMirror
.c_str());
400 vfprintf(stdout
,Format
,args
);
401 std::cout
<< "\n\n" << std::flush
;
404 // AcqMethod::Log - Send a log message /*{{{*/
405 // ---------------------------------------------------------------------
407 void pkgAcqMethod::Log(const char *Format
,...)
410 va_start(args
,Format
);
411 PrintStatus("101 Log", Format
, args
);
415 // AcqMethod::Status - Send a status message /*{{{*/
416 // ---------------------------------------------------------------------
418 void pkgAcqMethod::Status(const char *Format
,...)
421 va_start(args
,Format
);
422 PrintStatus("102 Status", Format
, args
);
426 // AcqMethod::Redirect - Send a redirect message /*{{{*/
427 // ---------------------------------------------------------------------
428 /* This method sends the redirect message and dequeues the item as
429 * the worker will enqueue again later on to the right queue */
430 void pkgAcqMethod::Redirect(const string
&NewURI
)
432 std::cout
<< "103 Redirect\nURI: " << Queue
->Uri
<< "\n"
433 << "New-URI: " << NewURI
<< "\n"
434 << "\n" << std::flush
;
438 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
439 // ---------------------------------------------------------------------
441 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
442 IMSHit(false), Size(0), ResumePoint(0)
446 // AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
447 // ---------------------------------------------------------------------
448 /* This hides the number of hashes we are supporting from the caller.
449 It just deals with the hash class. */
450 void pkgAcqMethod::FetchResult::TakeHashes(class Hashes
&Hash
)
452 Hashes
= Hash
.GetHashStringList();
455 void pkgAcqMethod::Dequeue() { /*{{{*/
456 FetchItem
const * const Tmp
= Queue
;
458 if (Tmp
== QueueBack
)