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