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 /*{{{*/
19 #pragma implementation "apt-pkg/acquire-method.h"
21 #include <apt-pkg/acquire-method.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/configuration.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/fileutl.h>
26 #include <apt-pkg/hashes.h>
32 #include <sys/signal.h>
37 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
38 // ---------------------------------------------------------------------
39 /* This constructs the initialization text */
40 pkgAcqMethod::pkgAcqMethod(const char *Ver
,unsigned long Flags
)
44 strcat(End
,"100 Capabilities\n");
45 sprintf(End
+strlen(End
),"Version: %s\n",Ver
);
47 if ((Flags
& SingleInstance
) == SingleInstance
)
48 strcat(End
,"Single-Instance: true\n");
50 if ((Flags
& Pipeline
) == Pipeline
)
51 strcat(End
,"Pipeline: true\n");
53 if ((Flags
& SendConfig
) == SendConfig
)
54 strcat(End
,"Send-Config: true\n");
56 if ((Flags
& LocalOnly
) == LocalOnly
)
57 strcat(End
,"Local-Only: true\n");
59 if ((Flags
& NeedsCleanup
) == NeedsCleanup
)
60 strcat(End
,"Needs-Cleanup: true\n");
62 if ((Flags
& Removable
) == Removable
)
63 strcat(End
,"Removable: true\n");
66 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
69 SetNonBlock(STDIN_FILENO
,true);
75 // AcqMethod::Fail - A fetch has failed /*{{{*/
76 // ---------------------------------------------------------------------
78 void pkgAcqMethod::Fail(bool Transient
)
80 string Err
= "Undetermined Error";
81 if (_error
->empty() == false)
82 _error
->PopMessage(Err
);
87 // AcqMethod::Fail - A fetch has failed /*{{{*/
88 // ---------------------------------------------------------------------
90 void pkgAcqMethod::Fail(string Err
,bool Transient
)
92 // Strip out junk from the error messages
93 for (string::iterator I
= Err
.begin(); I
!= Err
.end(); I
++)
105 End
+= snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: %s\n"
106 "Message: %s %s\n",Queue
->Uri
.c_str(), Err
.c_str(), IP
.c_str());
108 FetchItem
*Tmp
= Queue
;
111 if (Tmp
== QueueBack
)
116 End
+= snprintf(S
,sizeof(S
)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
117 "Message: %s\n",Err
.c_str());
119 if(FailReason
.empty() == false)
120 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"FailReason: %s\n",FailReason
.c_str());
121 if (UsedMirror
.empty() == false)
122 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
123 // Set the transient flag
124 if (Transient
== true)
125 strcat(S
,"Transient-Failure: true\n\n");
129 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
133 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
134 // ---------------------------------------------------------------------
136 void pkgAcqMethod::URIStart(FetchResult
&Res
)
144 End
+= snprintf(S
,sizeof(S
),"200 URI Start\nURI: %s\n",Queue
->Uri
.c_str());
146 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Size: %lu\n",Res
.Size
);
148 if (Res
.LastModified
!= 0)
149 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Last-Modified: %s\n",
150 TimeRFC1123(Res
.LastModified
).c_str());
152 if (Res
.ResumePoint
!= 0)
153 End
+= snprintf(End
,sizeof(S
)-4 - (End
- S
),"Resume-Point: %lu\n",
157 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
161 // AcqMethod::URIDone - A URI is finished /*{{{*/
162 // ---------------------------------------------------------------------
164 void pkgAcqMethod::URIDone(FetchResult
&Res
, FetchResult
*Alt
)
172 End
+= snprintf(S
,sizeof(S
),"201 URI Done\nURI: %s\n",Queue
->Uri
.c_str());
174 if (Res
.Filename
.empty() == false)
175 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Filename: %s\n",Res
.Filename
.c_str());
178 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Size: %lu\n",Res
.Size
);
180 if (Res
.LastModified
!= 0)
181 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Last-Modified: %s\n",
182 TimeRFC1123(Res
.LastModified
).c_str());
184 if (Res
.MD5Sum
.empty() == false)
185 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"MD5-Hash: %s\n",Res
.MD5Sum
.c_str());
186 if (Res
.SHA1Sum
.empty() == false)
187 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"SHA1-Hash: %s\n",Res
.SHA1Sum
.c_str());
188 if (UsedMirror
.empty() == false)
189 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"UsedMirror: %s\n",UsedMirror
.c_str());
190 if (Res
.GPGVOutput
.size() > 0)
191 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"GPGVOutput:\n");
192 for (vector
<string
>::iterator I
= Res
.GPGVOutput
.begin();
193 I
!= Res
.GPGVOutput
.end(); I
++)
194 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
), " %s\n", (*I
).c_str());
196 if (Res
.ResumePoint
!= 0)
197 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Resume-Point: %lu\n",
200 if (Res
.IMSHit
== true)
201 strcat(End
,"IMS-Hit: true\n");
206 if (Alt
->Filename
.empty() == false)
207 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Filename: %s\n",Alt
->Filename
.c_str());
210 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Size: %lu\n",Alt
->Size
);
212 if (Alt
->LastModified
!= 0)
213 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-Last-Modified: %s\n",
214 TimeRFC1123(Alt
->LastModified
).c_str());
216 if (Alt
->MD5Sum
.empty() == false)
217 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-MD5-Hash: %s\n",
218 Alt
->MD5Sum
.c_str());
219 if (Alt
->SHA1Sum
.empty() == false)
220 End
+= snprintf(End
,sizeof(S
)-50 - (End
- S
),"Alt-SHA1-Hash: %s\n",
221 Alt
->SHA1Sum
.c_str());
223 if (Alt
->IMSHit
== true)
224 strcat(End
,"Alt-IMS-Hit: true\n");
228 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
232 FetchItem
*Tmp
= Queue
;
235 if (Tmp
== QueueBack
)
239 // AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
240 // ---------------------------------------------------------------------
241 /* This sends a 403 Media Failure message to the APT and waits for it
243 bool pkgAcqMethod::MediaFail(string Required
,string Drive
)
246 snprintf(S
,sizeof(S
),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
247 Required
.c_str(),Drive
.c_str());
249 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
252 vector
<string
> MyMessages
;
254 /* Here we read messages until we find a 603, each non 603 message is
255 appended to the main message list for later processing */
258 if (WaitFd(STDIN_FILENO
) == false)
261 if (ReadMessages(STDIN_FILENO
,MyMessages
) == false)
264 string Message
= MyMessages
.front();
265 MyMessages
.erase(MyMessages
.begin());
267 // Fetch the message number
269 int Number
= strtol(Message
.c_str(),&End
,10);
270 if (End
== Message
.c_str())
272 cerr
<< "Malformed message!" << endl
;
279 while (MyMessages
.empty() == false)
281 Messages
.push_back(MyMessages
.front());
282 MyMessages
.erase(MyMessages
.begin());
285 return !StringToBool(LookupTag(Message
,"Failed"),false);
288 Messages
.push_back(Message
);
292 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
293 // ---------------------------------------------------------------------
294 /* This parses each configuration entry and puts it into the _config
295 Configuration class. */
296 bool pkgAcqMethod::Configuration(string Message
)
298 ::Configuration
&Cnf
= *_config
;
300 const char *I
= Message
.c_str();
301 const char *MsgEnd
= I
+ Message
.length();
303 unsigned int Length
= strlen("Config-Item");
304 for (; I
+ Length
< MsgEnd
; I
++)
307 if (I
[Length
] != ':' || stringcasecmp(I
,I
+Length
,"Config-Item") != 0)
312 for (; I
< MsgEnd
&& *I
== ' '; I
++);
313 const char *Equals
= I
;
314 for (; Equals
< MsgEnd
&& *Equals
!= '='; Equals
++);
315 const char *End
= Equals
;
316 for (; End
< MsgEnd
&& *End
!= '\n'; End
++);
320 Cnf
.Set(DeQuoteString(string(I
,Equals
-I
)),
321 DeQuoteString(string(Equals
+1,End
-Equals
-1)));
328 // AcqMethod::Run - Run the message engine /*{{{*/
329 // ---------------------------------------------------------------------
330 /* Fetch any messages and execute them. In single mode it returns 1 if
331 there are no more available messages - any other result is a
332 fatal failure code! */
333 int pkgAcqMethod::Run(bool Single
)
337 // Block if the message queue is empty
338 if (Messages
.empty() == true)
341 if (WaitFd(STDIN_FILENO
) == false)
343 if (ReadMessages(STDIN_FILENO
,Messages
) == false)
347 // Single mode exits if the message queue is empty
348 if (Single
== true && Messages
.empty() == true)
351 string Message
= Messages
.front();
352 Messages
.erase(Messages
.begin());
354 // Fetch the message number
356 int Number
= strtol(Message
.c_str(),&End
,10);
357 if (End
== Message
.c_str())
359 cerr
<< "Malformed message!" << endl
;
366 if (Configuration(Message
) == false)
372 FetchItem
*Tmp
= new FetchItem
;
374 Tmp
->Uri
= LookupTag(Message
,"URI");
375 Tmp
->DestFile
= LookupTag(Message
,"FileName");
376 if (StrToTime(LookupTag(Message
,"Last-Modified"),Tmp
->LastModified
) == false)
377 Tmp
->LastModified
= 0;
378 Tmp
->IndexFile
= StringToBool(LookupTag(Message
,"Index-File"),false);
381 // Append it to the list
382 FetchItem
**I
= &Queue
;
383 for (; *I
!= 0; I
= &(*I
)->Next
);
388 // Notify that this item is to be fetched.
389 if (Fetch(Tmp
) == false)
401 // AcqMethod::Log - Send a log message /*{{{*/
402 // ---------------------------------------------------------------------
404 void pkgAcqMethod::Log(const char *Format
,...)
406 string CurrentURI
= "<UNKNOWN>";
408 CurrentURI
= Queue
->Uri
;
411 va_start(args
,Format
);
413 // sprintf the description
415 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"101 Log\nURI: %s\n"
416 "Message: ",CurrentURI
.c_str());
418 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
421 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
425 // AcqMethod::Status - Send a status message /*{{{*/
426 // ---------------------------------------------------------------------
428 void pkgAcqMethod::Status(const char *Format
,...)
430 string CurrentURI
= "<UNKNOWN>";
432 CurrentURI
= Queue
->Uri
;
435 va_start(args
,Format
);
437 // sprintf the description
439 unsigned int Len
= snprintf(S
,sizeof(S
)-4,"102 Status\nURI: %s\n"
440 "Message: ",CurrentURI
.c_str());
442 vsnprintf(S
+Len
,sizeof(S
)-4-Len
,Format
,args
);
445 if (write(STDOUT_FILENO
,S
,strlen(S
)) != (signed)strlen(S
))
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();