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