acquire-method.cc 11 KB

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