Minimal CD swaps
[ntk/apt.git] / apt-pkg / acquire-method.cc
CommitLineData
93bf083d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
2c206aa4 3// $Id: acquire-method.cc,v 1.23 1999/12/09 21:18:01 jgg Exp $
93bf083d
AL
4/* ######################################################################
5
6 Acquire Method
7
8384ebdf
AL
8 This is a skeleton class that implements most of the functionality
9 of a method and some usefull 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
13 downloading files..
14
93bf083d
AL
15 ##################################################################### */
16 /*}}}*/
17// Include Files /*{{{*/
18#ifdef __GNUG__
19#pragma implementation "apt-pkg/acquire-method.h"
20#endif
21#include <apt-pkg/acquire-method.h>
22#include <apt-pkg/error.h>
23#include <apt-pkg/configuration.h>
cdcc6d34 24#include <apt-pkg/strutl.h>
93bf083d
AL
25#include <apt-pkg/fileutl.h>
26
2c206aa4 27#include <stdarg.h>
93bf083d 28#include <stdio.h>
65a1e968 29#include <unistd.h>
93bf083d
AL
30 /*}}}*/
31
32// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
33// ---------------------------------------------------------------------
34/* This constructs the initialization text */
35pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
36{
37 char S[300] = "";
38 char *End = S;
39 strcat(End,"100 Capabilities\n");
40 sprintf(End+strlen(End),"Version: %s\n",Ver);
41
42 if ((Flags & SingleInstance) == SingleInstance)
43 strcat(End,"Single-Instance: true\n");
44
93bf083d
AL
45 if ((Flags & Pipeline) == Pipeline)
46 strcat(End,"Pipeline: true\n");
47
48 if ((Flags & SendConfig) == SendConfig)
49 strcat(End,"Send-Config: true\n");
e331f6ed
AL
50
51 if ((Flags & LocalOnly) == LocalOnly)
52 strcat(End,"Local-Only: true\n");
8e5fc8f5
AL
53
54 if ((Flags & NeedsCleanup) == NeedsCleanup)
55 strcat(End,"Needs-Cleanup: true\n");
93bf083d
AL
56 strcat(End,"\n");
57
58 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
59 exit(100);
be4401bf
AL
60
61 SetNonBlock(STDIN_FILENO,true);
5cb5d8dc 62
92e889c8 63 Queue = 0;
5cb5d8dc 64 QueueBack = 0;
93bf083d
AL
65}
66 /*}}}*/
67// AcqMethod::Fail - A fetch has failed /*{{{*/
68// ---------------------------------------------------------------------
69/* */
a72ace20 70void pkgAcqMethod::Fail(bool Transient)
93bf083d
AL
71{
72 string Err = "Undetermined Error";
73 if (_error->empty() == false)
74 _error->PopMessage(Err);
75 _error->Discard();
a72ace20 76 Fail(Err,Transient);
93bf083d
AL
77}
78 /*}}}*/
79// AcqMethod::Fail - A fetch has failed /*{{{*/
80// ---------------------------------------------------------------------
81/* */
a72ace20 82void pkgAcqMethod::Fail(string Err,bool Transient)
6d5dd02a
AL
83{
84 // Strip out junk from the error messages
85 for (char *I = Err.begin(); I != Err.end(); I++)
86 {
87 if (*I == '\r')
88 *I = ' ';
89 if (*I == '\n')
90 *I = ' ';
91 }
92
93bf083d 93 char S[1024];
be4401bf
AL
94 if (Queue != 0)
95 {
8b067c22 96 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
a72ace20
AL
97 "Message: %s\n",Queue->Uri.c_str(),Err.c_str());
98
be4401bf
AL
99 // Dequeue
100 FetchItem *Tmp = Queue;
101 Queue = Queue->Next;
102 delete Tmp;
5cb5d8dc
AL
103 if (Tmp == QueueBack)
104 QueueBack = Queue;
be4401bf
AL
105 }
106 else
8b067c22 107 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
a72ace20 108 "Message: %s\n",Err.c_str());
be4401bf 109
a72ace20
AL
110 // Set the transient flag
111 if (Transient == true)
112 strcat(S,"Transient-Failure: true\n\n");
113 else
114 strcat(S,"\n");
115
93bf083d
AL
116 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
117 exit(100);
118}
119 /*}}}*/
120// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
121// ---------------------------------------------------------------------
122/* */
be4401bf 123void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 124{
be4401bf
AL
125 if (Queue == 0)
126 abort();
127
93bf083d
AL
128 char S[1024] = "";
129 char *End = S;
130
be4401bf 131 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
93bf083d 132 if (Res.Size != 0)
8b067c22 133 End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
134
135 if (Res.LastModified != 0)
8b067c22 136 End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
137 TimeRFC1123(Res.LastModified).c_str());
138
be4401bf 139 if (Res.ResumePoint != 0)
8b067c22 140 End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
be4401bf 141 Res.ResumePoint);
93bf083d
AL
142
143 strcat(End,"\n");
144 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
145 exit(100);
146}
147 /*}}}*/
148// AcqMethod::URIDone - A URI is finished /*{{{*/
149// ---------------------------------------------------------------------
150/* */
151void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
152{
be4401bf
AL
153 if (Queue == 0)
154 abort();
155
93bf083d
AL
156 char S[1024] = "";
157 char *End = S;
158
be4401bf 159 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
93bf083d
AL
160
161 if (Res.Filename.empty() == false)
8b067c22 162 End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
93bf083d
AL
163
164 if (Res.Size != 0)
8b067c22 165 End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
166
167 if (Res.LastModified != 0)
8b067c22 168 End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
169 TimeRFC1123(Res.LastModified).c_str());
170
171 if (Res.MD5Sum.empty() == false)
8b067c22 172 End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
93bf083d 173
b98f2859 174 if (Res.ResumePoint != 0)
8b067c22 175 End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
b98f2859
AL
176 Res.ResumePoint);
177
93bf083d
AL
178 if (Res.IMSHit == true)
179 strcat(End,"IMS-Hit: true\n");
180 End = S + strlen(S);
181
182 if (Alt != 0)
183 {
184 if (Alt->Filename.empty() == false)
8b067c22 185 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
93bf083d
AL
186
187 if (Alt->Size != 0)
8b067c22 188 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
93bf083d
AL
189
190 if (Alt->LastModified != 0)
8b067c22 191 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
93bf083d
AL
192 TimeRFC1123(Alt->LastModified).c_str());
193
194 if (Alt->MD5Sum.empty() == false)
8b067c22 195 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
93bf083d
AL
196 Alt->MD5Sum.c_str());
197
198 if (Alt->IMSHit == true)
199 strcat(End,"Alt-IMS-Hit: true\n");
200 }
201
202 strcat(End,"\n");
203 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
204 exit(100);
be4401bf
AL
205
206 // Dequeue
207 FetchItem *Tmp = Queue;
208 Queue = Queue->Next;
209 delete Tmp;
5cb5d8dc
AL
210 if (Tmp == QueueBack)
211 QueueBack = Queue;
93bf083d
AL
212}
213 /*}}}*/
f46e7681
AL
214// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
215// ---------------------------------------------------------------------
216/* This sends a 403 Media Failure message to the APT and waits for it
217 to be ackd */
018f1533 218bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681
AL
219{
220 char S[1024];
221 snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
222 Required.c_str(),Drive.c_str());
223
224 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
225 exit(100);
226
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
76d97c26 260 return !StringToBool(LookupTag(Message,"Fail"),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
275 const char *I = Message.begin();
276
277 unsigned int Length = strlen("Config-Item");
278 for (; I + Length < Message.end(); I++)
279 {
280 // Not a config item
281 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
282 continue;
283
284 I += Length + 1;
285
286 for (; I < Message.end() && *I == ' '; I++);
287 const char *Equals = I;
288 for (; Equals < Message.end() && *Equals != '='; Equals++);
289 const char *End = Equals;
290 for (; End < Message.end() && *End != '\n'; End++);
291 if (End == Equals)
292 return false;
293
6d5dd02a
AL
294 Cnf.Set(DeQuoteString(string(I,Equals-I)),
295 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
296 I = End;
297 }
298
299 return true;
300}
301 /*}}}*/
302// AcqMethod::Run - Run the message engine /*{{{*/
303// ---------------------------------------------------------------------
8384ebdf
AL
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! */
be4401bf 307int pkgAcqMethod::Run(bool Single)
93bf083d 308{
93bf083d
AL
309 while (1)
310 {
be4401bf 311 // Block if the message queue is empty
93bf083d 312 if (Messages.empty() == true)
be4401bf
AL
313 {
314 if (Single == false)
315 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 316 break;
92e889c8 317 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 318 break;
92e889c8
AL
319 }
320
be4401bf
AL
321 // Single mode exits if the message queue is empty
322 if (Single == true && Messages.empty() == true)
8384ebdf 323 return -1;
be4401bf 324
93bf083d
AL
325 string Message = Messages.front();
326 Messages.erase(Messages.begin());
327
328 // Fetch the message number
329 char *End;
330 int Number = strtol(Message.c_str(),&End,10);
331 if (End == Message.c_str())
332 {
333 cerr << "Malformed message!" << endl;
334 return 100;
335 }
336
337 switch (Number)
8e5fc8f5 338 {
93bf083d
AL
339 case 601:
340 if (Configuration(Message) == false)
341 return 100;
342 break;
343
344 case 600:
be4401bf
AL
345 {
346 FetchItem *Tmp = new FetchItem;
347
348 Tmp->Uri = LookupTag(Message,"URI");
349 Tmp->DestFile = LookupTag(Message,"FileName");
b98f2859
AL
350 if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
351 Tmp->LastModified = 0;
a72ace20 352 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
be4401bf
AL
353 Tmp->Next = 0;
354
355 // Append it to the list
356 FetchItem **I = &Queue;
92e889c8 357 for (; *I != 0; I = &(*I)->Next);
be4401bf 358 *I = Tmp;
5cb5d8dc
AL
359 if (QueueBack == 0)
360 QueueBack = Tmp;
361
bfd22fc0 362 // Notify that this item is to be fetched.
be4401bf 363 if (Fetch(Tmp) == false)
93bf083d 364 Fail();
bfd22fc0 365
93bf083d
AL
366 break;
367 }
368 }
369 }
370
8e5fc8f5 371 Exit();
93bf083d
AL
372 return 0;
373}
374 /*}}}*/
be4401bf
AL
375// AcqMethod::Log - Send a log message /*{{{*/
376// ---------------------------------------------------------------------
377/* */
378void pkgAcqMethod::Log(const char *Format,...)
379{
380 string CurrentURI = "<UNKNOWN>";
381 if (Queue != 0)
382 CurrentURI = Queue->Uri;
383
384 va_list args;
385 va_start(args,Format);
386
387 // sprintf the description
388 char S[1024];
8b067c22 389 unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
be4401bf
AL
390 "Message: ",CurrentURI.c_str());
391
8b067c22 392 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
393 strcat(S,"\n\n");
394
395 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
396 exit(100);
397}
398 /*}}}*/
399// AcqMethod::Status - Send a status message /*{{{*/
400// ---------------------------------------------------------------------
401/* */
402void pkgAcqMethod::Status(const char *Format,...)
403{
404 string CurrentURI = "<UNKNOWN>";
405 if (Queue != 0)
406 CurrentURI = Queue->Uri;
407
408 va_list args;
409 va_start(args,Format);
410
411 // sprintf the description
412 char S[1024];
8b067c22 413 unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
be4401bf
AL
414 "Message: ",CurrentURI.c_str());
415
8b067c22 416 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
417 strcat(S,"\n\n");
418
419 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
420 exit(100);
421}
422 /*}}}*/
423
93bf083d
AL
424// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
425// ---------------------------------------------------------------------
426/* */
93274b8d
AL
427pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
428 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
429{
430}
431 /*}}}*/