]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-method.cc
Alfredo's vendor stuff
[apt.git] / apt-pkg / acquire-method.cc
CommitLineData
93bf083d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
a7c835af 3// $Id: acquire-method.cc,v 1.26 2001/03/13 06:51:46 jgg 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 /*{{{*/
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 25#include <apt-pkg/fileutl.h>
a7c835af
AL
26#include <apt-pkg/hashes.h>
27
2c206aa4 28#include <stdarg.h>
93bf083d 29#include <stdio.h>
65a1e968 30#include <unistd.h>
93bf083d
AL
31 /*}}}*/
32
33// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
34// ---------------------------------------------------------------------
35/* This constructs the initialization text */
36pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
37{
38 char S[300] = "";
39 char *End = S;
40 strcat(End,"100 Capabilities\n");
41 sprintf(End+strlen(End),"Version: %s\n",Ver);
42
43 if ((Flags & SingleInstance) == SingleInstance)
44 strcat(End,"Single-Instance: true\n");
45
93bf083d
AL
46 if ((Flags & Pipeline) == Pipeline)
47 strcat(End,"Pipeline: true\n");
48
49 if ((Flags & SendConfig) == SendConfig)
50 strcat(End,"Send-Config: true\n");
e331f6ed
AL
51
52 if ((Flags & LocalOnly) == LocalOnly)
53 strcat(End,"Local-Only: true\n");
8e5fc8f5
AL
54
55 if ((Flags & NeedsCleanup) == NeedsCleanup)
56 strcat(End,"Needs-Cleanup: true\n");
459681d3
AL
57
58 if ((Flags & Removable) == Removable)
59 strcat(End,"Removable: true\n");
93bf083d
AL
60 strcat(End,"\n");
61
62 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
63 exit(100);
be4401bf
AL
64
65 SetNonBlock(STDIN_FILENO,true);
5cb5d8dc 66
92e889c8 67 Queue = 0;
5cb5d8dc 68 QueueBack = 0;
93bf083d
AL
69}
70 /*}}}*/
71// AcqMethod::Fail - A fetch has failed /*{{{*/
72// ---------------------------------------------------------------------
73/* */
a72ace20 74void pkgAcqMethod::Fail(bool Transient)
93bf083d
AL
75{
76 string Err = "Undetermined Error";
77 if (_error->empty() == false)
78 _error->PopMessage(Err);
79 _error->Discard();
a72ace20 80 Fail(Err,Transient);
93bf083d
AL
81}
82 /*}}}*/
83// AcqMethod::Fail - A fetch has failed /*{{{*/
84// ---------------------------------------------------------------------
85/* */
a72ace20 86void pkgAcqMethod::Fail(string Err,bool Transient)
6d5dd02a
AL
87{
88 // Strip out junk from the error messages
89 for (char *I = Err.begin(); I != Err.end(); I++)
90 {
91 if (*I == '\r')
92 *I = ' ';
93 if (*I == '\n')
94 *I = ' ';
95 }
96
93bf083d 97 char S[1024];
be4401bf
AL
98 if (Queue != 0)
99 {
8b067c22 100 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
b2e465d6
AL
101 "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(),
102 FailExtra.c_str());
a72ace20 103
be4401bf
AL
104 // Dequeue
105 FetchItem *Tmp = Queue;
106 Queue = Queue->Next;
107 delete Tmp;
5cb5d8dc
AL
108 if (Tmp == QueueBack)
109 QueueBack = Queue;
be4401bf
AL
110 }
111 else
8b067c22 112 snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
b2e465d6
AL
113 "Message: %s %s\n",Err.c_str(),
114 FailExtra.c_str());
be4401bf 115
a72ace20
AL
116 // Set the transient flag
117 if (Transient == true)
118 strcat(S,"Transient-Failure: true\n\n");
119 else
120 strcat(S,"\n");
121
93bf083d
AL
122 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
123 exit(100);
124}
125 /*}}}*/
126// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
127// ---------------------------------------------------------------------
128/* */
be4401bf 129void pkgAcqMethod::URIStart(FetchResult &Res)
93bf083d 130{
be4401bf
AL
131 if (Queue == 0)
132 abort();
133
93bf083d
AL
134 char S[1024] = "";
135 char *End = S;
136
be4401bf 137 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
93bf083d 138 if (Res.Size != 0)
8b067c22 139 End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
140
141 if (Res.LastModified != 0)
8b067c22 142 End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
143 TimeRFC1123(Res.LastModified).c_str());
144
be4401bf 145 if (Res.ResumePoint != 0)
8b067c22 146 End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
be4401bf 147 Res.ResumePoint);
93bf083d
AL
148
149 strcat(End,"\n");
150 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
151 exit(100);
152}
153 /*}}}*/
154// AcqMethod::URIDone - A URI is finished /*{{{*/
155// ---------------------------------------------------------------------
156/* */
157void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
158{
be4401bf
AL
159 if (Queue == 0)
160 abort();
161
93bf083d
AL
162 char S[1024] = "";
163 char *End = S;
164
be4401bf 165 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
93bf083d
AL
166
167 if (Res.Filename.empty() == false)
8b067c22 168 End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
93bf083d
AL
169
170 if (Res.Size != 0)
8b067c22 171 End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
93bf083d
AL
172
173 if (Res.LastModified != 0)
8b067c22 174 End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
93bf083d
AL
175 TimeRFC1123(Res.LastModified).c_str());
176
177 if (Res.MD5Sum.empty() == false)
8b067c22 178 End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
a7c835af
AL
179 if (Res.SHA1Sum.empty() == false)
180 End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
93bf083d 181
b98f2859 182 if (Res.ResumePoint != 0)
8b067c22 183 End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
b98f2859
AL
184 Res.ResumePoint);
185
93bf083d
AL
186 if (Res.IMSHit == true)
187 strcat(End,"IMS-Hit: true\n");
188 End = S + strlen(S);
189
190 if (Alt != 0)
191 {
192 if (Alt->Filename.empty() == false)
8b067c22 193 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
93bf083d
AL
194
195 if (Alt->Size != 0)
8b067c22 196 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
93bf083d
AL
197
198 if (Alt->LastModified != 0)
8b067c22 199 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
93bf083d
AL
200 TimeRFC1123(Alt->LastModified).c_str());
201
202 if (Alt->MD5Sum.empty() == false)
8b067c22 203 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
93bf083d 204 Alt->MD5Sum.c_str());
a7c835af
AL
205 if (Alt->SHA1Sum.empty() == false)
206 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
207 Alt->SHA1Sum.c_str());
93bf083d
AL
208
209 if (Alt->IMSHit == true)
210 strcat(End,"Alt-IMS-Hit: true\n");
211 }
212
213 strcat(End,"\n");
214 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
215 exit(100);
be4401bf
AL
216
217 // Dequeue
218 FetchItem *Tmp = Queue;
219 Queue = Queue->Next;
220 delete Tmp;
5cb5d8dc
AL
221 if (Tmp == QueueBack)
222 QueueBack = Queue;
93bf083d
AL
223}
224 /*}}}*/
f46e7681
AL
225// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
226// ---------------------------------------------------------------------
227/* This sends a 403 Media Failure message to the APT and waits for it
228 to be ackd */
018f1533 229bool pkgAcqMethod::MediaFail(string Required,string Drive)
f46e7681
AL
230{
231 char S[1024];
232 snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
233 Required.c_str(),Drive.c_str());
234
235 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
236 exit(100);
237
238 vector<string> MyMessages;
239
240 /* Here we read messages until we find a 603, each non 603 message is
241 appended to the main message list for later processing */
242 while (1)
243 {
244 if (WaitFd(STDIN_FILENO) == false)
76d97c26 245 return false;
f46e7681
AL
246
247 if (ReadMessages(STDIN_FILENO,MyMessages) == false)
76d97c26
AL
248 return false;
249
f46e7681
AL
250 string Message = MyMessages.front();
251 MyMessages.erase(MyMessages.begin());
252
253 // Fetch the message number
254 char *End;
255 int Number = strtol(Message.c_str(),&End,10);
256 if (End == Message.c_str())
257 {
258 cerr << "Malformed message!" << endl;
259 exit(100);
260 }
261
262 // Change ack
263 if (Number == 603)
264 {
76d97c26 265 while (MyMessages.empty() == false)
f46e7681
AL
266 {
267 Messages.push_back(MyMessages.front());
268 MyMessages.erase(MyMessages.begin());
269 }
542ec555 270
76d97c26 271 return !StringToBool(LookupTag(Message,"Fail"),false);
f46e7681
AL
272 }
273
274 Messages.push_back(Message);
275 }
276}
277 /*}}}*/
93bf083d
AL
278// AcqMethod::Configuration - Handle the configuration message /*{{{*/
279// ---------------------------------------------------------------------
280/* This parses each configuration entry and puts it into the _config
281 Configuration class. */
282bool pkgAcqMethod::Configuration(string Message)
283{
284 ::Configuration &Cnf = *_config;
285
286 const char *I = Message.begin();
287
288 unsigned int Length = strlen("Config-Item");
289 for (; I + Length < Message.end(); I++)
290 {
291 // Not a config item
292 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
293 continue;
294
295 I += Length + 1;
296
297 for (; I < Message.end() && *I == ' '; I++);
298 const char *Equals = I;
299 for (; Equals < Message.end() && *Equals != '='; Equals++);
300 const char *End = Equals;
301 for (; End < Message.end() && *End != '\n'; End++);
302 if (End == Equals)
303 return false;
304
6d5dd02a
AL
305 Cnf.Set(DeQuoteString(string(I,Equals-I)),
306 DeQuoteString(string(Equals+1,End-Equals-1)));
93bf083d
AL
307 I = End;
308 }
309
310 return true;
311}
312 /*}}}*/
313// AcqMethod::Run - Run the message engine /*{{{*/
314// ---------------------------------------------------------------------
8384ebdf
AL
315/* Fetch any messages and execute them. In single mode it returns 1 if
316 there are no more available messages - any other result is a
317 fatal failure code! */
be4401bf 318int pkgAcqMethod::Run(bool Single)
93bf083d 319{
93bf083d
AL
320 while (1)
321 {
be4401bf 322 // Block if the message queue is empty
93bf083d 323 if (Messages.empty() == true)
be4401bf
AL
324 {
325 if (Single == false)
326 if (WaitFd(STDIN_FILENO) == false)
8e5fc8f5 327 break;
92e889c8 328 if (ReadMessages(STDIN_FILENO,Messages) == false)
8e5fc8f5 329 break;
92e889c8
AL
330 }
331
be4401bf
AL
332 // Single mode exits if the message queue is empty
333 if (Single == true && Messages.empty() == true)
8384ebdf 334 return -1;
be4401bf 335
93bf083d
AL
336 string Message = Messages.front();
337 Messages.erase(Messages.begin());
338
339 // Fetch the message number
340 char *End;
341 int Number = strtol(Message.c_str(),&End,10);
342 if (End == Message.c_str())
343 {
344 cerr << "Malformed message!" << endl;
345 return 100;
346 }
347
348 switch (Number)
8e5fc8f5 349 {
93bf083d
AL
350 case 601:
351 if (Configuration(Message) == false)
352 return 100;
353 break;
354
355 case 600:
be4401bf
AL
356 {
357 FetchItem *Tmp = new FetchItem;
358
359 Tmp->Uri = LookupTag(Message,"URI");
360 Tmp->DestFile = LookupTag(Message,"FileName");
b98f2859
AL
361 if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
362 Tmp->LastModified = 0;
a72ace20 363 Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
be4401bf
AL
364 Tmp->Next = 0;
365
366 // Append it to the list
367 FetchItem **I = &Queue;
92e889c8 368 for (; *I != 0; I = &(*I)->Next);
be4401bf 369 *I = Tmp;
5cb5d8dc
AL
370 if (QueueBack == 0)
371 QueueBack = Tmp;
372
bfd22fc0 373 // Notify that this item is to be fetched.
be4401bf 374 if (Fetch(Tmp) == false)
93bf083d 375 Fail();
bfd22fc0 376
93bf083d
AL
377 break;
378 }
379 }
380 }
381
8e5fc8f5 382 Exit();
93bf083d
AL
383 return 0;
384}
385 /*}}}*/
be4401bf
AL
386// AcqMethod::Log - Send a log message /*{{{*/
387// ---------------------------------------------------------------------
388/* */
389void pkgAcqMethod::Log(const char *Format,...)
390{
391 string CurrentURI = "<UNKNOWN>";
392 if (Queue != 0)
393 CurrentURI = Queue->Uri;
394
395 va_list args;
396 va_start(args,Format);
397
398 // sprintf the description
399 char S[1024];
8b067c22 400 unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
be4401bf
AL
401 "Message: ",CurrentURI.c_str());
402
8b067c22 403 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
404 strcat(S,"\n\n");
405
406 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
407 exit(100);
408}
409 /*}}}*/
410// AcqMethod::Status - Send a status message /*{{{*/
411// ---------------------------------------------------------------------
412/* */
413void pkgAcqMethod::Status(const char *Format,...)
414{
415 string CurrentURI = "<UNKNOWN>";
416 if (Queue != 0)
417 CurrentURI = Queue->Uri;
418
419 va_list args;
420 va_start(args,Format);
421
422 // sprintf the description
423 char S[1024];
8b067c22 424 unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
be4401bf
AL
425 "Message: ",CurrentURI.c_str());
426
8b067c22 427 vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
be4401bf
AL
428 strcat(S,"\n\n");
429
430 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
431 exit(100);
432}
433 /*}}}*/
434
93bf083d
AL
435// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
436// ---------------------------------------------------------------------
437/* */
93274b8d
AL
438pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
439 IMSHit(false), Size(0), ResumePoint(0)
93bf083d
AL
440{
441}
442 /*}}}*/
a7c835af
AL
443// AcqMethod::FetchResult::TakeHashes - Load hashes /*{{{*/
444// ---------------------------------------------------------------------
445/* This hides the number of hashes we are supporting from the caller.
446 It just deals with the hash class. */
447void pkgAcqMethod::FetchResult::TakeHashes(Hashes &Hash)
448{
449 MD5Sum = Hash.MD5.Result();
450 SHA1Sum = Hash.SHA1.Result();
451}
452 /*}}}*/