]>
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 /*{{{*/
18 #include <apt-pkg/acquire-method.h>
19 #include <apt-pkg/error.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/fileutl.h>
23 #include <apt-pkg/hashes.h>
27 #include <sys/signal.h>
32 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
33 // ---------------------------------------------------------------------
34 /* This constructs the initialization text */
35 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
37 std::cout
<< "100 Capabilities\n"
38 << "Version: " << Ver
<< "\n";
40 if ((Flags
& SingleInstance
) == SingleInstance
)
41 std::cout
<< "Single-Instance: true\n";
43 if ((Flags
& Pipeline
) == Pipeline
)
44 std::cout
<< "Pipeline: true\n";
46 if ((Flags
& SendConfig
) == SendConfig
)
47 std::cout
<< "Send-Config: true\n";
49 if ((Flags
& LocalOnly
) == LocalOnly
)
50 std::cout
<<"Local-Only: true\n";
52 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
53 std::cout
<< "Needs-Cleanup: true\n";
55 if ((Flags
& Removable
) == Removable
)
56 std::cout
<< "Removable: true\n";
58 std::cout
<< "\n" << std::flush
;
60 SetNonBlock(STDIN_FILENO
,true);
66 // AcqMethod::Fail - A fetch has failed /*{{{*/
67 // ---------------------------------------------------------------------
69 void pkgAcqMethod::Fail(bool Transient
)
71 string Err
= "Undetermined Error";
72 if (_error
->empty() == false)
73 _error
->PopMessage(Err
);
78 // AcqMethod::Fail - A fetch has failed /*{{{*/
79 // ---------------------------------------------------------------------
81 void pkgAcqMethod::Fail(string Err
,bool Transient
)
83 // Strip out junk from the error messages
84 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); I
++)
94 std::cout
<< "400 URI Failure\nURI: " << Queue
->Uri
<< "\n"
95 << "Message: " << Err
<< " " << IP
<< "\n";
97 FetchItem
*Tmp
= Queue
;
100 if (Tmp
== QueueBack
)
104 std::cout
<< "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err
<< "\n";
106 if(FailReason
.empty() == false)
107 std::cout
<< "FailReason: " << FailReason
<< "\n";
108 if (UsedMirror
.empty() == false)
109 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
110 // Set the transient flag
111 if (Transient
== true)
112 std::cout
<< "Transient-Failure: true\n";
114 std::cout
<< "\n" << std::flush
;
117 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
118 // ---------------------------------------------------------------------
120 void pkgAcqMethod::URIStart(FetchResult
&Res
)
125 std::cout
<< "200 URI Start\n"
126 << "URI: " << Queue
->Uri
<< "\n";
128 std::cout
<< "Size: " << Res
.Size
<< "\n";
130 if (Res
.LastModified
!= 0)
131 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
133 if (Res
.ResumePoint
!= 0)
134 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
136 if (UsedMirror
.empty() == false)
137 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
139 std::cout
<< "\n" << std::flush
;
142 // AcqMethod::URIDone - A URI is finished /*{{{*/
143 // ---------------------------------------------------------------------
145 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
150 std::cout
<< "201 URI Done\n"
151 << "URI: " << Queue
->Uri
<< "\n";
153 if (Res
.Filename
.empty() == false)
154 std::cout
<< "Filename: " << Res
.Filename
<< "\n";
157 std::cout
<< "Size: " << Res
.Size
<< "\n";
159 if (Res
.LastModified
!= 0)
160 std::cout
<< "Last-Modified: " << TimeRFC1123(Res
.LastModified
) << "\n";
162 if (Res
.MD5Sum
.empty() == false)
163 std::cout
<< "MD5-Hash: " << Res
.MD5Sum
<< "\n"
164 << "MD5Sum-Hash: " << Res
.MD5Sum
<< "\n";
165 if (Res
.SHA1Sum
.empty() == false)
166 std::cout
<< "SHA1-Hash: " << Res
.SHA1Sum
<< "\n";
167 if (Res
.SHA256Sum
.empty() == false)
168 std::cout
<< "SHA256-Hash: " << Res
.SHA256Sum
<< "\n";
169 if (Res
.SHA512Sum
.empty() == false)
170 std::cout
<< "SHA512-Hash: " << Res
.SHA512Sum
<< "\n";
171 if (UsedMirror
.empty() == false)
172 std::cout
<< "UsedMirror: " << UsedMirror
<< "\n";
173 if (Res
.GPGVOutput
.empty() == false)
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";
181 if (Res
.ResumePoint
!= 0)
182 std::cout
<< "Resume-Point: " << Res
.ResumePoint
<< "\n";
184 if (Res
.IMSHit
== true)
185 std::cout
<< "IMS-Hit: true\n";
189 if (Alt
->Filename
.empty() == false)
190 std::cout
<< "Alt-Filename: " << Alt
->Filename
<< "\n";
193 std::cout
<< "Alt-Size: " << Alt
->Size
<< "\n";
195 if (Alt
->LastModified
!= 0)
196 std::cout
<< "Alt-Last-Modified: " << TimeRFC1123(Alt
->LastModified
) << "\n";
198 if (Alt
->MD5Sum
.empty() == false)
199 std::cout
<< "Alt-MD5-Hash: " << Alt
->MD5Sum
<< "\n";
200 if (Alt
->SHA1Sum
.empty() == false)
201 std::cout
<< "Alt-SHA1-Hash: " << Alt
->SHA1Sum
<< "\n";
202 if (Alt
->SHA256Sum
.empty() == false)
203 std::cout
<< "Alt-SHA256-Hash: " << Alt
->SHA256Sum
<< "\n";
204 if (Alt
->SHA512Sum
.empty() == false)
205 std::cout
<< "Alt-SHA512-Hash: " << Alt
->SHA512Sum
<< "\n";
207 if (Alt
->IMSHit
== true)
208 std::cout
<< "Alt-IMS-Hit: true\n";
211 std::cout
<< "\n" << std::flush
;
214 FetchItem
*Tmp
= Queue
;
217 if (Tmp
== QueueBack
)
221 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
222 // ---------------------------------------------------------------------
223 /* This sends a 403 Media Failure message to the APT and waits for it
225 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
227 fprintf(stdout
, "403 Media Failure\nMedia: %s\nDrive: %s\n",
228 Required
.c_str(),Drive
.c_str());
229 std::cout
<< "\n" << std::flush
;
231 vector
<string
> MyMessages
;
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 */
237 if (WaitFd(STDIN_FILENO
) == false)
240 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
243 string Message
= MyMessages
.front();
244 MyMessages
.erase(MyMessages
.begin());
246 // Fetch the message number
248 int Number
= strtol(Message
.c_str(),&End
,10);
249 if (End
== Message
.c_str())
251 cerr
<< "Malformed message!" << endl
;
258 while (MyMessages
.empty() == false)
260 Messages
.push_back(MyMessages
.front());
261 MyMessages
.erase(MyMessages
.begin());
264 return !StringToBool(LookupTag(Message
,"Failed"),false);
267 Messages
.push_back(Message
);
271 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
272 // ---------------------------------------------------------------------
273 /* This parses each configuration entry and puts it into the _config
274 Configuration class. */
275 bool pkgAcqMethod::Configuration(string Message
)
277 ::Configuration
&Cnf
= *_config
;
279 const char *I
= Message
.c_str();
280 const char *MsgEnd
= I
+ Message
.length();
282 unsigned int Length
= strlen("Config-Item");
283 for (; I
+ Length
< MsgEnd
; I
++)
286 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
291 for (; I
< MsgEnd
&& *I
== ' '; I
++);
292 const char *Equals
= I
;
293 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
294 const char *End
= Equals
;
295 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
299 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
300 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
307 // AcqMethod::Run - Run the message engine /*{{{*/
308 // ---------------------------------------------------------------------
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! */
312 int pkgAcqMethod::Run(bool Single
)
316 // Block if the message queue is empty
317 if (Messages
.empty() == true)
320 if (WaitFd(STDIN_FILENO
) == false)
322 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
326 // Single mode exits if the message queue is empty
327 if (Single
== true && Messages
.empty() == true)
330 string Message
= Messages
.front();
331 Messages
.erase(Messages
.begin());
333 // Fetch the message number
335 int Number
= strtol(Message
.c_str(),&End
,10);
336 if (End
== Message
.c_str())
338 cerr
<< "Malformed message!" << endl
;
345 if (Configuration(Message
) == false)
351 FetchItem
*Tmp
= new FetchItem
;
353 Tmp
->Uri
= LookupTag(Message
,"URI");
354 Tmp
->DestFile
= LookupTag(Message
,"FileName");
355 if (RFC1123StrToTime(LookupTag(Message
,"Last-Modified").c_str(),Tmp
->LastModified
) == false)
356 Tmp
->LastModified
= 0;
357 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
358 Tmp
->FailIgnore
= StringToBool(LookupTag(Message
,"Fail-Ignore"),false);
361 // Append it to the list
362 FetchItem
**I
= &Queue
;
363 for (; *I
!= 0; I
= &(*I
)->Next
);
368 // Notify that this item is to be fetched.
369 if (Fetch(Tmp
) == false)
381 // AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
382 // ---------------------------------------------------------------------
384 void pkgAcqMethod::PrintStatus(char const * const header
, const char* Format
,
387 string CurrentURI
= "<UNKNOWN>";
389 CurrentURI
= Queue
->Uri
;
390 if (UsedMirror
.empty() == true)
391 fprintf(stdout
, "%s\nURI: %s\nMessage: ",
392 header
, CurrentURI
.c_str());
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
;
400 // AcqMethod::Log - Send a log message /*{{{*/
401 // ---------------------------------------------------------------------
403 void pkgAcqMethod::Log(const char *Format
,...)
406 va_start(args
,Format
);
407 PrintStatus("101 Log", Format
, args
);
411 // AcqMethod::Status - Send a status message /*{{{*/
412 // ---------------------------------------------------------------------
414 void pkgAcqMethod::Status(const char *Format
,...)
417 va_start(args
,Format
);
418 PrintStatus("102 Status", Format
, args
);
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. */
426 void pkgAcqMethod::Redirect(const string
&NewURI
)
428 std::cout
<< "103 Redirect\nURI: ";
430 std::cout
<< Queue
->Uri
<< "\n";
432 std::cout
<< "<UNKNOWN>\n";
433 std::cout
<< "New-URI: " << NewURI
<< "\n"
434 << "\n" << std::flush
;
436 // Change the URI for the request.
439 /* To keep the pipeline synchronized, move the current request to
440 the end of the queue, past the end of the current pipeline. */
442 for (I
= Queue
; I
->Next
!= 0; I
= I
->Next
) ;
450 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
451 // ---------------------------------------------------------------------
453 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
454 IMSHit(false), Size(0), ResumePoint(0)
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. */
462 void pkgAcqMethod::FetchResult::TakeHashes(Hashes
&Hash
)
464 MD5Sum
= Hash
.MD5
.Result();
465 SHA1Sum
= Hash
.SHA1
.Result();
466 SHA256Sum
= Hash
.SHA256
.Result();
467 SHA512Sum
= Hash
.SHA512
.Result();