Working acquire code
[ntk/apt.git] / apt-pkg / acquire-method.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: acquire-method.cc,v 1.4 1998/11/05 07:21:38 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 <strutl.h>
18 #include <apt-pkg/fileutl.h>
19
20 #include <stdio.h>
21 /*}}}*/
22
23 // AcqMethod::pkgAcqMethod - Constructor /*{{{*/
24 // ---------------------------------------------------------------------
25 /* This constructs the initialization text */
26 pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
27 {
28 char S[300] = "";
29 char *End = S;
30 strcat(End,"100 Capabilities\n");
31 sprintf(End+strlen(End),"Version: %s\n",Ver);
32
33 if ((Flags & SingleInstance) == SingleInstance)
34 strcat(End,"Single-Instance: true\n");
35
36 if ((Flags & PreScan) == PreScan)
37 strcat(End,"Pre-Scan: true\n");
38
39 if ((Flags & Pipeline) == Pipeline)
40 strcat(End,"Pipeline: true\n");
41
42 if ((Flags & SendConfig) == SendConfig)
43 strcat(End,"Send-Config: true\n");
44 strcat(End,"\n");
45
46 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
47 exit(100);
48
49 SetNonBlock(STDIN_FILENO,true);
50
51 Queue = 0;
52 }
53 /*}}}*/
54 // AcqMethod::Fail - A fetch has failed /*{{{*/
55 // ---------------------------------------------------------------------
56 /* */
57 void pkgAcqMethod::Fail()
58 {
59 string Err = "Undetermined Error";
60 if (_error->empty() == false)
61 _error->PopMessage(Err);
62 _error->Discard();
63 Fail(Err);
64 }
65 /*}}}*/
66 // AcqMethod::Fail - A fetch has failed /*{{{*/
67 // ---------------------------------------------------------------------
68 /* */
69 void pkgAcqMethod::Fail(string Err)
70 {
71 char S[1024];
72 if (Queue != 0)
73 {
74 snprintf(S,sizeof(S),"400 URI Failure\nURI: %s\n"
75 "Message: %s\n\n",Queue->Uri.c_str(),Err.c_str());
76
77 // Dequeue
78 FetchItem *Tmp = Queue;
79 Queue = Queue->Next;
80 delete Tmp;
81 }
82 else
83 snprintf(S,sizeof(S),"400 URI Failure\nURI: <UNKNOWN>\n"
84 "Message: %s\n\n",Err.c_str());
85
86 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
87 exit(100);
88 }
89 /*}}}*/
90 // AcqMethod::URIStart - Indicate a download is starting /*{{{*/
91 // ---------------------------------------------------------------------
92 /* */
93 void pkgAcqMethod::URIStart(FetchResult &Res)
94 {
95 if (Queue == 0)
96 abort();
97
98 char S[1024] = "";
99 char *End = S;
100
101 End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
102 if (Res.Size != 0)
103 End += snprintf(End,sizeof(S) - (End - S),"Size: %u\n",Res.Size);
104
105 if (Res.LastModified != 0)
106 End += snprintf(End,sizeof(S) - (End - S),"Last-Modified: %s\n",
107 TimeRFC1123(Res.LastModified).c_str());
108
109 if (Res.ResumePoint != 0)
110 End += snprintf(End,sizeof(S) - (End - S),"Resume-Point: %u\n",
111 Res.ResumePoint);
112
113 strcat(End,"\n");
114 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
115 exit(100);
116 }
117 /*}}}*/
118 // AcqMethod::URIDone - A URI is finished /*{{{*/
119 // ---------------------------------------------------------------------
120 /* */
121 void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
122 {
123 if (Queue == 0)
124 abort();
125
126 char S[1024] = "";
127 char *End = S;
128
129 End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
130
131 if (Res.Filename.empty() == false)
132 End += snprintf(End,sizeof(S) - (End - S),"Filename: %s\n",Res.Filename.c_str());
133
134 if (Res.Size != 0)
135 End += snprintf(End,sizeof(S) - (End - S),"Size: %u\n",Res.Size);
136
137 if (Res.LastModified != 0)
138 End += snprintf(End,sizeof(S) - (End - S),"Last-Modified: %s\n",
139 TimeRFC1123(Res.LastModified).c_str());
140
141 if (Res.MD5Sum.empty() == false)
142 End += snprintf(End,sizeof(S) - (End - S),"MD5Sum: %s\n",Res.MD5Sum.c_str());
143
144 if (Res.IMSHit == true)
145 strcat(End,"IMS-Hit: true\n");
146 End = S + strlen(S);
147
148 if (Alt != 0)
149 {
150 if (Alt->Filename.empty() == false)
151 End += snprintf(End,sizeof(S) - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
152
153 if (Alt->Size != 0)
154 End += snprintf(End,sizeof(S) - (End - S),"Alt-Size: %u\n",Alt->Size);
155
156 if (Alt->LastModified != 0)
157 End += snprintf(End,sizeof(S) - (End - S),"Alt-Last-Modified: %s\n",
158 TimeRFC1123(Alt->LastModified).c_str());
159
160 if (Alt->MD5Sum.empty() == false)
161 End += snprintf(End,sizeof(S) - (End - S),"Alt-MD5Sum: %s\n",
162 Alt->MD5Sum.c_str());
163
164 if (Alt->IMSHit == true)
165 strcat(End,"Alt-IMS-Hit: true\n");
166 }
167
168 strcat(End,"\n");
169 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
170 exit(100);
171
172 // Dequeue
173 FetchItem *Tmp = Queue;
174 Queue = Queue->Next;
175 delete Tmp;
176 }
177 /*}}}*/
178 // AcqMethod::Configuration - Handle the configuration message /*{{{*/
179 // ---------------------------------------------------------------------
180 /* This parses each configuration entry and puts it into the _config
181 Configuration class. */
182 bool pkgAcqMethod::Configuration(string Message)
183 {
184 ::Configuration &Cnf = *_config;
185
186 const char *I = Message.begin();
187
188 unsigned int Length = strlen("Config-Item");
189 for (; I + Length < Message.end(); I++)
190 {
191 // Not a config item
192 if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
193 continue;
194
195 I += Length + 1;
196
197 for (; I < Message.end() && *I == ' '; I++);
198 const char *Equals = I;
199 for (; Equals < Message.end() && *Equals != '='; Equals++);
200 const char *End = Equals;
201 for (; End < Message.end() && *End != '\n'; End++);
202 if (End == Equals)
203 return false;
204
205 Cnf.Set(string(I,Equals-I),string(Equals+1,End-Equals-1));
206 I = End;
207 }
208
209 return true;
210 }
211 /*}}}*/
212 // AcqMethod::Run - Run the message engine /*{{{*/
213 // ---------------------------------------------------------------------
214 /* */
215 int pkgAcqMethod::Run(bool Single)
216 {
217 while (1)
218 {
219 // Block if the message queue is empty
220 if (Messages.empty() == true)
221 {
222 if (Single == false)
223 if (WaitFd(STDIN_FILENO) == false)
224 return 0;
225
226 if (ReadMessages(STDIN_FILENO,Messages) == false)
227 return 0;
228 }
229
230 // Single mode exits if the message queue is empty
231 if (Single == true && Messages.empty() == true)
232 return 0;
233
234 string Message = Messages.front();
235 Messages.erase(Messages.begin());
236
237 // Fetch the message number
238 char *End;
239 int Number = strtol(Message.c_str(),&End,10);
240 if (End == Message.c_str())
241 {
242 cerr << "Malformed message!" << endl;
243 return 100;
244 }
245
246 switch (Number)
247 {
248 case 601:
249 if (Configuration(Message) == false)
250 return 100;
251 break;
252
253 case 600:
254 {
255 FetchItem *Tmp = new FetchItem;
256
257 Tmp->Uri = LookupTag(Message,"URI");
258 Tmp->DestFile = LookupTag(Message,"FileName");
259 StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified);
260 Tmp->Next = 0;
261
262 // Append it to the list
263 FetchItem **I = &Queue;
264 for (; *I != 0; I = &(*I)->Next);
265 *I = Tmp;
266
267 // Notify that this item is to be fetched.
268 if (Fetch(Tmp) == false)
269 Fail();
270
271 break;
272 }
273 }
274 }
275
276 return 0;
277 }
278 /*}}}*/
279 // AcqMethod::Log - Send a log message /*{{{*/
280 // ---------------------------------------------------------------------
281 /* */
282 void pkgAcqMethod::Log(const char *Format,...)
283 {
284 string CurrentURI = "<UNKNOWN>";
285 if (Queue != 0)
286 CurrentURI = Queue->Uri;
287
288 va_list args;
289 va_start(args,Format);
290
291 // sprintf the description
292 char S[1024];
293 unsigned int Len = snprintf(S,sizeof(S),"101 Log\nURI: %s\n"
294 "Message: ",CurrentURI.c_str());
295
296 vsnprintf(S+Len,sizeof(S)-Len,Format,args);
297 strcat(S,"\n\n");
298
299 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
300 exit(100);
301 }
302 /*}}}*/
303 // AcqMethod::Status - Send a status message /*{{{*/
304 // ---------------------------------------------------------------------
305 /* */
306 void pkgAcqMethod::Status(const char *Format,...)
307 {
308 string CurrentURI = "<UNKNOWN>";
309 if (Queue != 0)
310 CurrentURI = Queue->Uri;
311
312 va_list args;
313 va_start(args,Format);
314
315 // sprintf the description
316 char S[1024];
317 unsigned int Len = snprintf(S,sizeof(S),"101 Status\nURI: %s\n"
318 "Message: ",CurrentURI.c_str());
319
320 vsnprintf(S+Len,sizeof(S)-Len,Format,args);
321 strcat(S,"\n\n");
322
323 if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
324 exit(100);
325 }
326 /*}}}*/
327
328 // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
329 // ---------------------------------------------------------------------
330 /* */
331 pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
332 IMSHit(false), Size(0)
333 {
334 }
335 /*}}}*/
336