acquire-method.cc 11 KB

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