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