main.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <iostream>
  19. #include <climits>
  20. #include <getopt.h>
  21. #include <kopano/stringutil.h>
  22. #include <kopano/archiver-common.h>
  23. #include <kopano/charset/convert.h>
  24. #include <kopano/ECConfig.h>
  25. #include <kopano/ECLogger.h>
  26. #include <kopano/ecversion.h>
  27. #include "Archiver.h"
  28. #include "UnixUtil.cpp"
  29. namespace KC {
  30. enum modes {
  31. MODE_INVALID = 0,
  32. MODE_ATTACH,
  33. MODE_DETACH,
  34. MODE_DETACH_IDX,
  35. MODE_LIST,
  36. MODE_LIST_ARCHUSER,
  37. MODE_ARCHIVE,
  38. MODE_CLEANUP,
  39. MODE_AUTO_ATTACH
  40. };
  41. static const char *modename(modes mode)
  42. {
  43. const char* retval = "";
  44. switch (mode) {
  45. case MODE_INVALID:
  46. retval = "Invalid mode";
  47. break;
  48. case MODE_ATTACH:
  49. retval = "Attach";
  50. break;
  51. case MODE_DETACH:
  52. retval = "Detach";
  53. break;
  54. case MODE_DETACH_IDX:
  55. retval = "Detach by index";
  56. break;
  57. case MODE_LIST:
  58. retval = "List";
  59. break;
  60. case MODE_LIST_ARCHUSER:
  61. retval = "List archive users";
  62. break;
  63. case MODE_ARCHIVE:
  64. retval = "Archive";
  65. break;
  66. case MODE_CLEANUP:
  67. retval = "Clean-up";
  68. break;
  69. case MODE_AUTO_ATTACH:
  70. retval = "Auto attach";
  71. break;
  72. default:
  73. retval = "Undefined mode";
  74. }
  75. return retval;
  76. }
  77. /**
  78. * Print a help message.
  79. *
  80. * @param[in] ostr
  81. * std::ostream where the message is written to.
  82. * @param[in] lpszName
  83. * The name of the application to use in the output.
  84. */
  85. static void print_help(ostream &ostr, const char *lpszName)
  86. {
  87. ostr << endl;
  88. ostr << "Usage:" << endl;
  89. ostr << lpszName << " [options]" << endl << endl;
  90. ostr << "Options:" << endl;
  91. ostr << " -u <name> : Select user" << endl;
  92. ostr << " -l|--list : List archives for the specified user" << endl;
  93. ostr << " -L|--list-archiveusers : List users that have an archived attached" << endl;
  94. ostr << " -A|--archive : Perform archive operation" << endl;
  95. ostr << " If no user is specified all user stores will" << endl;
  96. ostr << " be archived." << endl;
  97. ostr << " -C|--cleanup : Perform a cleanup of the archive stores attached" << endl;
  98. ostr << " to the user specified with -u. If no user is" << endl;
  99. ostr << " specified, all archives are cleanedup." << endl;
  100. ostr << " --local-only : Archive or cleanup only those users that have" << endl;
  101. ostr << " their store on the server on which the archiver" << endl;
  102. ostr << " is invoked." << endl;
  103. ostr << " -a|--attach-to <archive store> : Attach an archive to the specified user." << endl;
  104. ostr << " By default a subfolder will be created with" << endl;
  105. ostr << " the same name as the specified user. This" << endl;
  106. ostr << " folder will be the root of the archive." << endl;
  107. ostr << " -d|--detach-from <archive store> : Detach an archive from the specified user." << endl;
  108. ostr << " If a user has multiple archives in the same" << endl;
  109. ostr << " archive store, the folder needs to be" << endl;
  110. ostr << " specified with --archive-folder." << endl;
  111. ostr << " -D|--detach <archive no> : Detach the archive specified by archive no. This" << endl;
  112. ostr << " number can be found by running kopano-archiver -l" << endl;
  113. ostr << " --auto-attach : When no user is specified with -u, all users" << endl;
  114. ostr << " will have their archives attached or detached" << endl;
  115. ostr << " based on the LDAP/ADS settings. If a user is" << endl;
  116. ostr << " specified only that user's store will be processed." << endl;
  117. ostr << " This option can be combined with -A/--archive to" << endl;
  118. ostr << " force an auto-attach run regardless of the" << endl;
  119. ostr << " enable_auto_attach configuration option." << endl;
  120. ostr << " -f|--archive-folder <name> : Specify an alternate name for the subfolder" << endl;
  121. ostr << " that acts as the root of the archive." << endl;
  122. ostr << " -s|--archive-server <path> : Specify the server on which the archive should" << endl;
  123. ostr << " be found." << endl;
  124. ostr << " -N|--no-folder : Don't use a subfolder that acts as the root" << endl;
  125. ostr << " of the archive. This implies that only one" << endl;
  126. ostr << " archive can be made in the specified archive" << endl;
  127. ostr << " store." << endl;
  128. ostr << " -w : Grant write permissions on the archive. This will" << endl;
  129. ostr << " override the auto_attach_writable config option." << endl;
  130. ostr << " --writable <yes|no> : Enable or disable write permissions. This will" << endl;
  131. ostr << " override the auto_attach_writable config option." << endl;
  132. ostr << " -c|--config : Use alternate config file." << endl;
  133. ostr << " Default: archiver.cfg" << endl;
  134. ostr << " --help : Show this help message." << endl;
  135. ostr << endl;
  136. }
  137. /**
  138. * Print an error message when multiple operational modes are selected by the user.
  139. *
  140. * @param[in] modeSet
  141. * The currently set mode.
  142. * @param[in] modeReq
  143. * The requested mode.
  144. * @param[in] lpszName
  145. * The name of the application.
  146. *
  147. * @todo Make a nicer message about what went wrong based on modeSet and modeReq.
  148. */
  149. static void print_mode_error(modes modeSet, modes modeReq,
  150. const char *lpszName)
  151. {
  152. cerr << "Cannot select more than one mode!" << endl;
  153. print_help(cerr, lpszName);
  154. }
  155. static std::string args_to_cmdline(int argc, const char * const argv[])
  156. {
  157. if (argc <= 0)
  158. return std::string();
  159. std::string strCmdLine(argv[0]);
  160. for (int i = 1; i < argc; ++i)
  161. strCmdLine.append(" '").append(shell_escape(argv[i])).append(1, '\'');
  162. return strCmdLine;
  163. }
  164. enum cmdOptions {
  165. OPT_USER = UCHAR_MAX + 1,
  166. OPT_ATTACH,
  167. OPT_DETACH,
  168. OPT_DETACH_IDX,
  169. OPT_AUTO_ATTACH,
  170. OPT_FOLDER,
  171. OPT_ASERVER,
  172. OPT_NOFOLDER,
  173. OPT_LIST,
  174. OPT_LIST_ARCHUSER,
  175. OPT_ARCHIVE,
  176. OPT_CLEANUP,
  177. OPT_CONFIG,
  178. OPT_LOCAL,
  179. OPT_WRITABLE,
  180. OPT_FORCE_CLEANUP,
  181. OPT_HELP
  182. };
  183. static const struct option long_options[] = {
  184. { "user", required_argument, NULL, OPT_USER },
  185. { "attach-to", required_argument, NULL, OPT_ATTACH },
  186. { "detach-from", required_argument, NULL, OPT_DETACH },
  187. { "detach", required_argument, NULL, OPT_DETACH_IDX },
  188. { "auto-attach", no_argument, NULL, OPT_AUTO_ATTACH },
  189. { "archive-folder", required_argument, NULL, OPT_FOLDER },
  190. { "archive-server", required_argument, NULL, OPT_ASERVER },
  191. { "no-folder", no_argument, NULL, OPT_NOFOLDER },
  192. { "list", no_argument, NULL, OPT_LIST },
  193. { "list-archiveusers", no_argument, NULL, OPT_LIST_ARCHUSER },
  194. { "archive", no_argument, NULL, OPT_ARCHIVE },
  195. { "cleanup", no_argument, NULL, OPT_CLEANUP },
  196. { "local-only", no_argument, NULL, OPT_LOCAL },
  197. { "help", no_argument, NULL, OPT_HELP },
  198. { "config", required_argument, NULL, OPT_CONFIG },
  199. { "writable", required_argument, NULL, OPT_WRITABLE },
  200. { "force-cleanup", no_argument, NULL, OPT_FORCE_CLEANUP },
  201. { NULL, no_argument, NULL, 0 }
  202. };
  203. static inline LPTSTR toLPTST(const char* lpszString, convert_context& converter) { return lpszString ? converter.convert_to<LPTSTR>(lpszString) : NULL; }
  204. static inline const char *yesno(bool bValue) { return bValue ? "yes" : "no"; }
  205. } /* namespace */
  206. /**
  207. * Program entry point
  208. */
  209. int main(int argc, char *argv[])
  210. {
  211. eResult r = Success;
  212. modes mode = MODE_INVALID;
  213. tstring strUser;
  214. const char *lpszArchive = NULL;
  215. unsigned int ulArchive = 0;
  216. const char *lpszFolder = NULL;
  217. const char *lpszArchiveServer = NULL;
  218. bool bLocalOnly = false;
  219. bool bAutoAttach = false;
  220. bool bForceCleanup = false;
  221. unsigned ulAttachFlags = 0;
  222. ArchiverPtr ptrArchiver;
  223. convert_context converter;
  224. const std::string strCmdLine = args_to_cmdline(argc, argv);
  225. std::list<configsetting_t> lSettings;
  226. ULONG ulFlags = 0;
  227. const char *lpszConfig = Archiver::GetConfigPath();
  228. static const configsetting_t lpDefaults[] = {
  229. { "pid_file", "/var/run/kopano/archiver.pid" },
  230. { NULL, NULL }
  231. };
  232. setlocale(LC_CTYPE, "");
  233. int c;
  234. while (1) {
  235. c = getopt_long(argc, argv, "u:c:lLACwa:d:D:f:s:N", long_options, NULL);
  236. if (c == -1)
  237. break;
  238. switch (c) {
  239. case 'u':
  240. case OPT_USER:
  241. strUser = converter.convert_to<tstring>(optarg);
  242. break;
  243. case 'a':
  244. case OPT_ATTACH:
  245. if (mode != MODE_INVALID) {
  246. print_mode_error(mode, MODE_ATTACH, argv[0]);
  247. return 1;
  248. }
  249. mode = MODE_ATTACH;
  250. lpszArchive = optarg;
  251. break;
  252. case 'd':
  253. case OPT_DETACH:
  254. if (mode != MODE_INVALID) {
  255. print_mode_error(mode, MODE_DETACH, argv[0]);
  256. return 1;
  257. }
  258. mode = MODE_DETACH;
  259. lpszArchive = optarg;
  260. break;
  261. case 'D':
  262. case OPT_DETACH_IDX: {
  263. char *res = NULL;
  264. if (mode != MODE_INVALID) {
  265. print_mode_error(mode, MODE_DETACH_IDX, argv[0]);
  266. return 1;
  267. }
  268. mode = MODE_DETACH_IDX;
  269. ulArchive = strtoul(optarg, &res, 10);
  270. if (!res || *res != '\0') {
  271. cerr << "Please specify a valid archive number." << endl;
  272. return 1;
  273. }
  274. }
  275. break;
  276. case OPT_AUTO_ATTACH:
  277. if (mode == MODE_ARCHIVE)
  278. bAutoAttach = true;
  279. else if(mode != MODE_INVALID) {
  280. print_mode_error(mode, MODE_AUTO_ATTACH, argv[0]);
  281. return 1;
  282. }
  283. mode = MODE_AUTO_ATTACH;
  284. break;
  285. case 'f':
  286. case OPT_FOLDER:
  287. if ((ulAttachFlags & ArchiveManage::UseIpmSubtree)) {
  288. cerr << "You cannot mix --archive-folder and --nofolder." << endl;
  289. print_help(cerr, argv[0]);
  290. return 1;
  291. }
  292. lpszFolder = optarg;
  293. break;
  294. case 's':
  295. case OPT_ASERVER:
  296. lpszArchiveServer = optarg;
  297. break;
  298. case 'N':
  299. case OPT_NOFOLDER:
  300. if (lpszFolder) {
  301. cerr << "You cannot mix --archive-folder and --nofolder." << endl;
  302. print_help(cerr, argv[0]);
  303. return 1;
  304. }
  305. ulAttachFlags |= ArchiveManage::UseIpmSubtree;
  306. break;
  307. case 'l':
  308. case OPT_LIST:
  309. if (mode != MODE_INVALID) {
  310. print_mode_error(mode, MODE_LIST, argv[0]);
  311. return 1;
  312. }
  313. mode = MODE_LIST;
  314. break;
  315. case 'L':
  316. case OPT_LIST_ARCHUSER:
  317. if (mode != MODE_INVALID) {
  318. print_mode_error(mode, MODE_LIST_ARCHUSER, argv[0]);
  319. return 1;
  320. }
  321. mode = MODE_LIST_ARCHUSER;
  322. break;
  323. case 'A':
  324. case OPT_ARCHIVE:
  325. if (mode == MODE_AUTO_ATTACH)
  326. bAutoAttach = true;
  327. else if (mode != MODE_INVALID) {
  328. print_mode_error(mode, MODE_ARCHIVE, argv[0]);
  329. return 1;
  330. }
  331. mode = MODE_ARCHIVE;
  332. break;
  333. case 'C':
  334. case OPT_CLEANUP:
  335. if (mode != MODE_INVALID) {
  336. print_mode_error(mode, MODE_CLEANUP, argv[0]);
  337. return 1;
  338. }
  339. mode = MODE_CLEANUP;
  340. break;
  341. case OPT_LOCAL:
  342. bLocalOnly = true;
  343. break;
  344. case 'c':
  345. case OPT_CONFIG:
  346. lpszConfig = optarg;
  347. ulFlags |= Archiver::RequireConfig;
  348. break;
  349. case 'w':
  350. ulAttachFlags |= ArchiveManage::Writable;
  351. break;
  352. case OPT_WRITABLE:
  353. if (parseBool(optarg))
  354. ulAttachFlags |= ArchiveManage::Writable;
  355. else
  356. ulAttachFlags |= ArchiveManage::ReadOnly;
  357. break;
  358. case OPT_FORCE_CLEANUP:
  359. bForceCleanup = true;
  360. break;
  361. case OPT_HELP:
  362. print_help(cout, argv[0]);
  363. return 1;
  364. case '?':
  365. // Invalid option, or required argument missing
  366. // getopt_long outputs the error message.
  367. print_help(cerr, argv[0]);
  368. return 1;
  369. default:
  370. break;
  371. };
  372. }
  373. if (mode == MODE_INVALID) {
  374. cerr << "Nothing to do!" << endl;
  375. print_help(cerr, argv[0]);
  376. return 1;
  377. }
  378. else if (mode == MODE_ATTACH) {
  379. if (strUser.empty()) {
  380. cerr << "Username cannot be empty" << endl;
  381. print_help(cerr, argv[0]);
  382. return 1;
  383. }
  384. if (lpszFolder != NULL && *lpszFolder == '\0')
  385. lpszFolder = NULL;
  386. }
  387. else if (mode == MODE_DETACH) {
  388. if (strUser.empty()) {
  389. cerr << "Username cannot be empty" << endl;
  390. print_help(cerr, argv[0]);
  391. return 1;
  392. }
  393. if (lpszFolder != NULL && *lpszFolder == '\0')
  394. lpszFolder = NULL;
  395. }
  396. else if (mode == MODE_LIST) {
  397. if (strUser.empty()) {
  398. cerr << "Username cannot be empty" << endl;
  399. print_help(cerr, argv[0]);
  400. return 1;
  401. }
  402. }
  403. else if (bForceCleanup && mode != MODE_CLEANUP) {
  404. cerr << "--force-cleanup is only valid in cleanup mode." << endl;
  405. return 1;
  406. }
  407. r = Archiver::Create(&ptrArchiver);
  408. if (r != Success) {
  409. cerr << "Failed to instantiate archiver object" << endl;
  410. return 1;
  411. }
  412. ulFlags |= Archiver::AttachStdErr;
  413. r = ptrArchiver->Init(argv[0], lpszConfig, lpDefaults, ulFlags);
  414. if (r == FileNotFound) {
  415. cerr << "Unable to open configuration file " << lpszConfig << endl;
  416. return 1;
  417. } else if (r != Success) {
  418. cerr << "Failed to initialize" << endl;
  419. return 1;
  420. }
  421. ec_log_crit("Startup command: %s", strCmdLine.c_str());
  422. ptrArchiver->GetLogger(Archiver::LogOnly)->Log(EC_LOGLEVEL_FATAL, "Version: %s", PROJECT_VERSION_ARCHIVER_STR);
  423. lSettings = ptrArchiver->GetConfig()->GetAllSettings();
  424. ECLogger* filelogger = ptrArchiver->GetLogger(Archiver::LogOnly);
  425. ptrArchiver->GetLogger(Archiver::LogOnly)->Log(EC_LOGLEVEL_FATAL, "Config settings:");
  426. for (const auto &s : lSettings)
  427. if (strcmp(s.szName, "sslkey_pass") == 0 || strcmp(s.szName, "mysql_password") == 0)
  428. filelogger->Log(EC_LOGLEVEL_FATAL, "* %s = '********'", s.szName);
  429. else
  430. filelogger->Log(EC_LOGLEVEL_FATAL, "* %s = '%s'", s.szName, s.szValue);
  431. if (mode == MODE_ARCHIVE || mode == MODE_CLEANUP)
  432. if (unix_create_pidfile(argv[0], ptrArchiver->GetConfig(), false) != 0)
  433. return 1;
  434. ec_log_debug("Archiver mode: %d: (%s)", mode, modename(mode));
  435. switch (mode) {
  436. case MODE_ATTACH: {
  437. ArchiveManagePtr ptr;
  438. r = ptrArchiver->GetManage(strUser.c_str(), &ptr);
  439. if (r != Success)
  440. return 1;
  441. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Attach archive %s in server %s using folder %s", lpszArchive, lpszArchiveServer, lpszFolder);
  442. r = ptr->AttachTo(lpszArchiveServer, toLPTST(lpszArchive, converter), toLPTST(lpszFolder, converter), ulAttachFlags);
  443. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  444. }
  445. break;
  446. case MODE_DETACH_IDX:
  447. case MODE_DETACH: {
  448. ArchiveManagePtr ptr;
  449. r = ptrArchiver->GetManage(strUser.c_str(), &ptr);
  450. if (r != Success)
  451. return 1;
  452. if (mode == MODE_DETACH_IDX) {
  453. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Detach archive %u", ulArchive);
  454. r = ptr->DetachFrom(ulArchive);
  455. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  456. } else {
  457. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Detach archive %s on server %s, folder %s", lpszArchive, lpszArchiveServer, lpszFolder);
  458. r = ptr->DetachFrom(lpszArchiveServer, toLPTST(lpszArchive, converter), toLPTST(lpszFolder, converter));
  459. }
  460. }
  461. break;
  462. case MODE_AUTO_ATTACH: {
  463. if (strUser.size()) {
  464. ArchiveManagePtr ptr;
  465. r = ptrArchiver->GetManage(strUser.c_str(), &ptr);
  466. if (r != Success)
  467. return 1;
  468. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Autoattach for user %ls, flags: %u", strUser.c_str(), ulAttachFlags);
  469. r = ptr->AutoAttach(ulAttachFlags);
  470. } else {
  471. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Autoattach flags: %u", ulAttachFlags);
  472. r = ptrArchiver->AutoAttach(ulAttachFlags);
  473. }
  474. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  475. }
  476. break;
  477. case MODE_LIST: {
  478. ArchiveManagePtr ptr;
  479. r = ptrArchiver->GetManage(strUser.c_str(), &ptr);
  480. if (r != Success)
  481. return 1;
  482. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: List archives");
  483. r = ptr->ListArchives(cout);
  484. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  485. }
  486. break;
  487. case MODE_LIST_ARCHUSER: {
  488. ArchiveManagePtr ptr;
  489. r = ptrArchiver->GetManage(_T("SYSTEM"), &ptr);
  490. if (r != Success)
  491. return 1;
  492. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: List archive users");
  493. r = ptr->ListAttachedUsers(cout);
  494. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  495. }
  496. break;
  497. case MODE_ARCHIVE: {
  498. ArchiveControlPtr ptr;
  499. r = ptrArchiver->GetControl(&ptr);
  500. if (r != Success)
  501. return 1;
  502. if (strUser.size()) {
  503. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: archive user %ls (autoattach: %s, flags %u)", strUser.c_str(), yesno(bAutoAttach), ulAttachFlags);
  504. r = ptr->Archive(strUser, bAutoAttach, ulAttachFlags);
  505. } else {
  506. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: archive all users (local only: %s autoattach: %s, flags %u)", yesno(bLocalOnly), yesno(bAutoAttach), ulAttachFlags);
  507. r = ptr->ArchiveAll(bLocalOnly, bAutoAttach, ulAttachFlags);
  508. }
  509. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  510. }
  511. break;
  512. case MODE_CLEANUP: {
  513. ArchiveControlPtr ptr;
  514. r = ptrArchiver->GetControl(&ptr, bForceCleanup);
  515. if (r != Success)
  516. return 1;
  517. if (strUser.size()) {
  518. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Cleanup user %ls ", strUser.c_str());
  519. r = ptr->Cleanup(strUser);
  520. } else {
  521. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: Cleanup all (local only): %s", yesno(bLocalOnly));
  522. r = ptr->CleanupAll(bLocalOnly);
  523. }
  524. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver result %d (%s)", r, ArchiveResultString(r));
  525. }
  526. break;
  527. case MODE_INVALID:
  528. filelogger->Log(EC_LOGLEVEL_DEBUG, "Archiver action: invalid");
  529. break;
  530. }
  531. return 0;
  532. }