uiconsole.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. static bool AnyMessageDisplayed=false; // For console -idn switch.
  2. // Purely user interface function. Gets and returns user input.
  3. UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags)
  4. {
  5. wchar SizeText1[20],DateStr1[50],SizeText2[20],DateStr2[50];
  6. FindData ExistingFD;
  7. memset(&ExistingFD,0,sizeof(ExistingFD)); // In case find fails.
  8. FindFile::FastFind(Name,&ExistingFD);
  9. itoa(ExistingFD.Size,SizeText1,ASIZE(SizeText1));
  10. ExistingFD.mtime.GetText(DateStr1,ASIZE(DateStr1),false);
  11. if (FileSize==INT64NDF || FileTime==NULL)
  12. {
  13. eprintf(L"\n");
  14. eprintf(St(MAskOverwrite),Name);
  15. }
  16. else
  17. {
  18. itoa(FileSize,SizeText2,ASIZE(SizeText2));
  19. FileTime->GetText(DateStr2,ASIZE(DateStr2),false);
  20. if ((Flags & UIASKREP_F_EXCHSRCDEST)==0)
  21. eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2);
  22. else
  23. eprintf(St(MAskReplace),Name,SizeText2,DateStr2,SizeText1,DateStr1);
  24. }
  25. bool AllowRename=(Flags & UIASKREP_F_NORENAME)==0;
  26. int Choice=0;
  27. do
  28. {
  29. Choice=Ask(St(AllowRename ? MYesNoAllRenQ : MYesNoAllQ));
  30. } while (Choice==0); // 0 means invalid input.
  31. switch(Choice)
  32. {
  33. case 1:
  34. return UIASKREP_R_REPLACE;
  35. case 2:
  36. return UIASKREP_R_SKIP;
  37. case 3:
  38. return UIASKREP_R_REPLACEALL;
  39. case 4:
  40. return UIASKREP_R_SKIPALL;
  41. }
  42. if (AllowRename && Choice==5)
  43. {
  44. mprintf(St(MAskNewName));
  45. if (getwstr(Name,MaxNameSize))
  46. return UIASKREP_R_RENAME;
  47. else
  48. return UIASKREP_R_SKIP; // Process fwgets failure as if user answered 'No'.
  49. }
  50. return UIASKREP_R_CANCEL;
  51. }
  52. void uiStartArchiveExtract(bool Extract,const wchar *ArcName)
  53. {
  54. mprintf(St(Extract ? MExtracting : MExtrTest), ArcName);
  55. }
  56. bool uiStartFileExtract(const wchar *FileName,bool Extract,bool Test,bool Skip)
  57. {
  58. return true;
  59. }
  60. void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64 TotalSize)
  61. {
  62. // We set the total size to 0 to update only the current progress and keep
  63. // the total progress intact in WinRAR. Unlike WinRAR, console RAR has only
  64. // the total progress and updates it with current values in such case.
  65. int CurPercent=TotalSize!=0 ? ToPercent(CurSize,TotalSize) : ToPercent(CurFileSize,TotalFileSize);
  66. mprintf(L"\b\b\b\b%3d%%",CurPercent);
  67. }
  68. void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize)
  69. {
  70. int CurPercent=ToPercent(CurSize,TotalSize);
  71. mprintf(L"\b\b\b\b%3d%%",CurPercent);
  72. }
  73. void uiMsgStore::Msg()
  74. {
  75. // When creating volumes, AnyMessageDisplayed must be reset for UIEVENT_NEWARCHIVE,
  76. // so it ignores this and all earlier messages like UIEVENT_PROTECTEND
  77. // and UIEVENT_PROTECTEND, because they precede "Creating archive" message
  78. // and do not interfere with -idn and file names. If we do not ignore them,
  79. // uiEolAfterMsg() in uiStartFileAddit() can cause unneeded carriage return
  80. // in archiving percent after creating a new volume with -v -idn (and -rr
  81. // for UIEVENT_PROTECT*) switches. AnyMessageDisplayed is set for messages
  82. // after UIEVENT_NEWARCHIVE, so archiving percent with -idn is moved to
  83. // next line and does not delete their last characters.
  84. // Similarly we ignore UIEVENT_RRTESTINGEND for volumes, because it is issued
  85. // before "Testing archive" and would add an excessive \n otherwise.
  86. AnyMessageDisplayed=(Code!=UIEVENT_NEWARCHIVE && Code!=UIEVENT_RRTESTINGEND);
  87. switch(Code)
  88. {
  89. case UIERROR_SYSERRMSG:
  90. case UIERROR_GENERALERRMSG:
  91. Log(NULL,L"\n%ls",Str[0]);
  92. break;
  93. case UIERROR_CHECKSUM:
  94. Log(Str[0],St(MCRCFailed),Str[1]);
  95. break;
  96. case UIERROR_CHECKSUMENC:
  97. Log(Str[0],St(MEncrBadCRC),Str[1]);
  98. break;
  99. case UIERROR_CHECKSUMPACKED:
  100. Log(Str[0],St(MDataBadCRC),Str[1],Str[0]);
  101. break;
  102. case UIERROR_BADPSW:
  103. Log(Str[0],St(MWrongFilePassword),Str[1]);
  104. break;
  105. case UIWAIT_BADPSW:
  106. Log(Str[0],St(MWrongPassword));
  107. break;
  108. case UIERROR_MEMORY:
  109. mprintf(L"\n");
  110. Log(NULL,St(MErrOutMem));
  111. break;
  112. case UIERROR_FILEOPEN:
  113. Log(Str[0],St(MCannotOpen),Str[1]);
  114. break;
  115. case UIERROR_FILECREATE:
  116. Log(Str[0],St(MCannotCreate),Str[1]);
  117. break;
  118. case UIERROR_FILECLOSE:
  119. Log(NULL,St(MErrFClose),Str[0]);
  120. break;
  121. case UIERROR_FILESEEK:
  122. Log(NULL,St(MErrSeek),Str[0]);
  123. break;
  124. case UIERROR_FILEREAD:
  125. mprintf(L"\n");
  126. Log(Str[0],St(MErrRead),Str[1]);
  127. break;
  128. case UIERROR_FILEWRITE:
  129. Log(Str[0],St(MErrWrite),Str[1]);
  130. break;
  131. #ifndef SFX_MODULE
  132. case UIERROR_FILEDELETE:
  133. Log(Str[0],St(MCannotDelete),Str[1]);
  134. break;
  135. case UIERROR_RECYCLEFAILED:
  136. Log(Str[0],St(MRecycleFailed));
  137. break;
  138. case UIERROR_FILERENAME:
  139. Log(Str[0],St(MErrRename),Str[1],Str[2]);
  140. break;
  141. #endif
  142. case UIERROR_FILEATTR:
  143. Log(Str[0],St(MErrChangeAttr),Str[1]);
  144. break;
  145. case UIERROR_FILECOPY:
  146. Log(Str[0],St(MCopyError),Str[1],Str[2]);
  147. break;
  148. case UIERROR_FILECOPYHINT:
  149. Log(Str[0],St(MCopyErrorHint));
  150. mprintf(L" "); // For progress percent.
  151. break;
  152. case UIERROR_DIRCREATE:
  153. Log(Str[0],St(MExtrErrMkDir),Str[1]);
  154. break;
  155. case UIERROR_SLINKCREATE:
  156. Log(Str[0],St(MErrCreateLnkS),Str[1]);
  157. break;
  158. case UIERROR_HLINKCREATE:
  159. Log(NULL,St(MErrCreateLnkH),Str[0]);
  160. break;
  161. case UIERROR_NOLINKTARGET:
  162. Log(NULL,St(MErrLnkTarget));
  163. mprintf(L" "); // For progress percent.
  164. break;
  165. case UIERROR_NEEDADMIN:
  166. Log(NULL,St(MNeedAdmin));
  167. break;
  168. case UIERROR_ARCBROKEN:
  169. Log(Str[0],St(MErrBrokenArc));
  170. break;
  171. case UIERROR_HEADERBROKEN:
  172. Log(Str[0],St(MHeaderBroken));
  173. break;
  174. case UIERROR_MHEADERBROKEN:
  175. Log(Str[0],St(MMainHeaderBroken));
  176. break;
  177. case UIERROR_FHEADERBROKEN:
  178. Log(Str[0],St(MLogFileHead),Str[1]);
  179. break;
  180. case UIERROR_SUBHEADERBROKEN:
  181. Log(Str[0],St(MSubHeadCorrupt));
  182. break;
  183. case UIERROR_SUBHEADERUNKNOWN:
  184. Log(Str[0],St(MSubHeadUnknown));
  185. break;
  186. case UIERROR_SUBHEADERDATABROKEN:
  187. Log(Str[0],St(MSubHeadDataCRC),Str[1]);
  188. break;
  189. case UIERROR_RRDAMAGED:
  190. Log(Str[0],St(MRRDamaged));
  191. break;
  192. case UIERROR_UNKNOWNMETHOD:
  193. Log(Str[0],St(MUnknownMeth),Str[1]);
  194. break;
  195. case UIERROR_UNKNOWNENCMETHOD:
  196. {
  197. wchar Msg[256];
  198. swprintf(Msg,ASIZE(Msg),St(MUnkEncMethod),Str[1]);
  199. Log(Str[0],L"%s: %s",Msg,Str[2]);
  200. }
  201. break;
  202. #ifndef SFX_MODULE
  203. case UIERROR_RENAMING:
  204. Log(Str[0],St(MRenaming),Str[1],Str[2]);
  205. break;
  206. case UIERROR_NEWERRAR:
  207. Log(Str[0],St(MNewerRAR));
  208. break;
  209. #endif
  210. case UIERROR_RECVOLDIFFSETS:
  211. Log(NULL,St(MRecVolDiffSets),Str[0],Str[1]);
  212. break;
  213. case UIERROR_RECVOLALLEXIST:
  214. mprintf(St(MRecVolAllExist));
  215. break;
  216. case UIERROR_RECONSTRUCTING:
  217. mprintf(St(MReconstructing));
  218. break;
  219. case UIERROR_RECVOLCANNOTFIX:
  220. mprintf(St(MRecVolCannotFix));
  221. break;
  222. case UIERROR_UNEXPEOF:
  223. Log(Str[0],St(MLogUnexpEOF));
  224. break;
  225. case UIERROR_BADARCHIVE:
  226. Log(Str[0],St(MBadArc),Str[0]);
  227. break;
  228. case UIERROR_CMTBROKEN:
  229. Log(Str[0],St(MLogCommBrk));
  230. break;
  231. case UIERROR_INVALIDNAME:
  232. Log(Str[0],St(MInvalidName),Str[1]);
  233. mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile.
  234. break;
  235. #ifndef SFX_MODULE
  236. case UIERROR_OPFAILED:
  237. Log(NULL,St(MOpFailed));
  238. break;
  239. case UIERROR_NEWRARFORMAT:
  240. Log(Str[0],St(MNewRarFormat));
  241. break;
  242. #endif
  243. case UIERROR_NOFILESTOEXTRACT:
  244. mprintf(St(MExtrNoFiles));
  245. break;
  246. case UIERROR_MISSINGVOL:
  247. Log(Str[0],St(MAbsNextVol),Str[0]);
  248. break;
  249. #ifndef SFX_MODULE
  250. case UIERROR_NEEDPREVVOL:
  251. Log(Str[0],St(MUnpCannotMerge),Str[1]);
  252. break;
  253. case UIERROR_UNKNOWNEXTRA:
  254. Log(Str[0],St(MUnknownExtra),Str[1]);
  255. break;
  256. case UIERROR_CORRUPTEXTRA:
  257. Log(Str[0],St(MCorruptExtra),Str[1],Str[2]);
  258. break;
  259. #endif
  260. #if !defined(SFX_MODULE) && defined(_WIN_ALL)
  261. case UIERROR_NTFSREQUIRED:
  262. Log(NULL,St(MNTFSRequired),Str[0]);
  263. break;
  264. #endif
  265. #if !defined(SFX_MODULE) && defined(_WIN_ALL)
  266. case UIERROR_ACLBROKEN:
  267. Log(Str[0],St(MACLBroken),Str[1]);
  268. break;
  269. case UIERROR_ACLUNKNOWN:
  270. Log(Str[0],St(MACLUnknown),Str[1]);
  271. break;
  272. case UIERROR_ACLSET:
  273. Log(Str[0],St(MACLSetError),Str[1]);
  274. break;
  275. case UIERROR_STREAMBROKEN:
  276. Log(Str[0],St(MStreamBroken),Str[1]);
  277. break;
  278. case UIERROR_STREAMUNKNOWN:
  279. Log(Str[0],St(MStreamUnknown),Str[1]);
  280. break;
  281. #endif
  282. case UIERROR_INCOMPATSWITCH:
  283. mprintf(St(MIncompatSwitch),Str[0],Num[0]);
  284. break;
  285. case UIERROR_PATHTOOLONG:
  286. Log(NULL,L"\n%ls%ls%ls",Str[0],Str[1],Str[2]);
  287. Log(NULL,St(MPathTooLong));
  288. break;
  289. #ifndef SFX_MODULE
  290. case UIERROR_DIRSCAN:
  291. Log(NULL,St(MScanError),Str[0]);
  292. break;
  293. #endif
  294. case UIERROR_UOWNERBROKEN:
  295. Log(Str[0],St(MOwnersBroken),Str[1]);
  296. break;
  297. case UIERROR_UOWNERGETOWNERID:
  298. Log(Str[0],St(MErrGetOwnerID),Str[1]);
  299. break;
  300. case UIERROR_UOWNERGETGROUPID:
  301. Log(Str[0],St(MErrGetGroupID),Str[1]);
  302. break;
  303. case UIERROR_UOWNERSET:
  304. Log(Str[0],St(MSetOwnersError),Str[1]);
  305. break;
  306. case UIERROR_ULINKREAD:
  307. Log(NULL,St(MErrLnkRead),Str[0]);
  308. break;
  309. case UIERROR_ULINKEXIST:
  310. Log(NULL,St(MSymLinkExists),Str[0]);
  311. break;
  312. case UIERROR_READERRTRUNCATED:
  313. Log(NULL,St(MErrReadTrunc),Str[0]);
  314. break;
  315. case UIERROR_READERRCOUNT:
  316. Log(NULL,St(MErrReadCount),Num[0]);
  317. break;
  318. case UIERROR_DIRNAMEEXISTS:
  319. Log(NULL,St(MDirNameExists));
  320. break;
  321. case UIERROR_TRUNCPSW:
  322. eprintf(St(MTruncPsw),Num[0]);
  323. eprintf(L"\n");
  324. break;
  325. case UIERROR_ADJUSTVALUE:
  326. Log(NULL,St(MAdjustValue),Str[0],Str[1]);
  327. break;
  328. #ifndef SFX_MODULE
  329. case UIMSG_STRING:
  330. mprintf(L"\n%s",Str[0]);
  331. break;
  332. #endif
  333. case UIMSG_CORRECTINGNAME:
  334. Log(Str[0],St(MCorrectingName));
  335. break;
  336. case UIMSG_BADARCHIVE:
  337. mprintf(St(MBadArc),Str[0]);
  338. break;
  339. case UIMSG_CREATING:
  340. mprintf(St(MCreating),Str[0]);
  341. break;
  342. case UIMSG_RENAMING:
  343. mprintf(St(MRenaming),Str[0],Str[1]);
  344. break;
  345. case UIMSG_RECVOLCALCCHECKSUM:
  346. mprintf(St(MCalcCRCAllVol));
  347. break;
  348. case UIMSG_RECVOLFOUND:
  349. mprintf(St(MRecVolFound),Num[0]);
  350. break;
  351. case UIMSG_RECVOLMISSING:
  352. mprintf(St(MRecVolMissing),Num[0]);
  353. break;
  354. case UIMSG_MISSINGVOL:
  355. mprintf(St(MAbsNextVol),Str[0]);
  356. break;
  357. case UIMSG_RECONSTRUCTING:
  358. mprintf(St(MReconstructing));
  359. break;
  360. case UIMSG_CHECKSUM:
  361. mprintf(St(MCRCFailed),Str[0]);
  362. break;
  363. case UIMSG_FAT32SIZE:
  364. mprintf(St(MFAT32Size));
  365. mprintf(L" "); // For progress percent.
  366. break;
  367. case UIMSG_SKIPENCARC:
  368. Log(NULL,St(MSkipEncArc),Str[0]);
  369. break;
  370. case UIEVENT_RRTESTINGSTART:
  371. mprintf(L"%s ",St(MTestingRR));
  372. break;
  373. }
  374. }
  375. bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
  376. {
  377. // Unlike GUI we cannot provide Cancel button here, so we use the empty
  378. // password to abort. Otherwise user not knowing a password would need to
  379. // press Ctrl+C multiple times to quit from infinite password request loop.
  380. return GetConsolePassword(Type,FileName,Password) && Password->IsSet();
  381. }
  382. bool uiIsGlobalPasswordSet()
  383. {
  384. return false;
  385. }
  386. void uiAlarm(UIALARM_TYPE Type)
  387. {
  388. if (uiSoundNotify==SOUND_NOTIFY_ON)
  389. {
  390. static clock_t LastTime=-10; // Negative to always beep first time.
  391. if ((MonoClock()-LastTime)/CLOCKS_PER_SEC>5)
  392. {
  393. #ifdef _WIN_ALL
  394. MessageBeep(-1);
  395. #else
  396. putwchar('\007');
  397. #endif
  398. LastTime=MonoClock();
  399. }
  400. }
  401. }
  402. bool uiAskNextVolume(wchar *VolName,size_t MaxSize)
  403. {
  404. eprintf(St(MAskNextVol),VolName);
  405. return Ask(St(MContinueQuit))!=2;
  406. }
  407. void uiAskRepeatRead(const wchar *FileName,bool &Ignore,bool &All,bool &Retry,bool &Quit)
  408. {
  409. eprintf(St(MErrReadInfo));
  410. int Code=Ask(St(MIgnoreAllRetryQuit));
  411. Ignore=(Code==1);
  412. All=(Code==2);
  413. Quit=(Code==4);
  414. Retry=!Ignore && !All && !Quit; // Default also for invalid input, not just for 'Retry'.
  415. }
  416. bool uiAskRepeatWrite(const wchar *FileName,bool DiskFull)
  417. {
  418. mprintf(L"\n");
  419. Log(NULL,St(DiskFull ? MNotEnoughDisk:MErrWrite),FileName);
  420. return Ask(St(MRetryAbort))==1;
  421. }
  422. #ifndef SFX_MODULE
  423. const wchar *uiGetMonthName(int Month)
  424. {
  425. static MSGID MonthID[12]={
  426. MMonthJan,MMonthFeb,MMonthMar,MMonthApr,MMonthMay,MMonthJun,
  427. MMonthJul,MMonthAug,MMonthSep,MMonthOct,MMonthNov,MMonthDec
  428. };
  429. return St(MonthID[Month]);
  430. }
  431. #endif
  432. void uiEolAfterMsg()
  433. {
  434. if (AnyMessageDisplayed)
  435. {
  436. // Avoid deleting several last characters of any previous error message
  437. // with percentage indicator in -idn mode.
  438. AnyMessageDisplayed=false;
  439. mprintf(L"\n");
  440. }
  441. }