You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

virtualmaildel.php 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <?php
  2. /*
  3. Virtual Mail Delete
  4. by George Vieira <george at citadelcomputer dot com dot au>
  5. You can run this from your crontab with something like
  6. 0 4 * * * * vmail php -q virtualmaildel.php >/dev/null
  7. Changes:
  8. 2017.08.31 updated to use PHP mysqli extension.
  9. 2018.02.23 removing Sieve filters if exists.
  10. Tadas Ustinavičius <tadas at ring dot lt> ( https://github.com/postfixadmin/postfixadmin/pull/70 )
  11. */
  12. $CONF = [];
  13. // Either, uncomment this (and change to work)
  14. //require_once('/path/to/postfixadmin/config.inc.php');
  15. // OR uncomment this.
  16. /*
  17. $CONF = [
  18. 'database_host' => 'localhost',
  19. 'database_user' => 'someone',
  20. 'database_password' => 'something',
  21. 'database_name' => 'mydb'
  22. ];
  23. */
  24. $MAKE_CHANGES = false; // change to true when you're happy this isn't going to trash your server.
  25. if (empty($CONF)) {
  26. die("\nPlease configure me\n\n");
  27. }
  28. // Where's the homedir accounts stored. (GET THIS RIGHT OTHERWISE IT THINK NONE EXIST AND DELETES ALL)
  29. $homedir = '/home/virtual';
  30. if (! is_dir($homedir)) {
  31. die("Cannot find home directory for virtual mailboxes in $homedir\n");
  32. }
  33. //
  34. // Recursive Delete Function
  35. //
  36. function deldir($dir) {
  37. $current_dir = opendir($dir);
  38. while ($entryname = readdir($current_dir)) {
  39. if (is_dir("$dir/$entryname") and ($entryname != "." and $entryname!="..")) {
  40. deldir("${dir}/${entryname}");
  41. } elseif ($entryname != "." and $entryname!="..") {
  42. unlink("${dir}/${entryname}");
  43. }
  44. }
  45. closedir($current_dir);
  46. @rmdir(${dir});
  47. }
  48. // --- Main Start ---
  49. $dir = [];
  50. //
  51. // Get list of directories
  52. //
  53. $fr = opendir($homedir);
  54. // TODO: Would glob($homedir . '/**/*/new') be somewhat quicker/shorter/less effort?
  55. while (($domain = readdir($fr)) !== false) {
  56. //
  57. // Check if it's a dir
  58. //
  59. if ($domain == "." || $domain == ".." || filetype($homedir .'/'. $domain) != "dir") {
  60. continue;
  61. }
  62. //
  63. // Open the (assumed) DOMAIN directory
  64. //
  65. $ff = opendir($homedir .'/'. $domain);
  66. while (($user = readdir($ff)) !== false) {
  67. //
  68. // Check for directories assuming it's a user account
  69. //
  70. if ($user == "." || $user == ".." || filetype($homedir .'/'. $domain .'/'. $user) != "dir") {
  71. continue;
  72. }
  73. //
  74. // if the dir 'new' exists inside then it's an account
  75. //
  76. if (file_exists($homedir .'/'. $domain .'/'. $user .'/'. "new")) {
  77. $dir[$domain][$user] = "";
  78. } else {
  79. //
  80. // Alert that the dir doesn't have a 'new' dir, possibly not an account. Leave it.
  81. //
  82. echo "UNKNOWN : " . $homedir ."/". $domain ."/". $user ."/new NOT FOUND. Possibly not an account. Leaving untouched\n";
  83. }
  84. }
  85. }
  86. //
  87. // OK, got an array of accounts from the dir, Now connect to the DB and check them
  88. //
  89. $conx = mysqli_connect($CONF['database_host'], $CONF['database_user'], $CONF['database_password'], $CONF['database_name']);
  90. //
  91. // Is there a problem connecting?
  92. //
  93. if (! $conx || mysqli_connect_errno()) {
  94. var_dump("DB connection failed." . mysqli_connect_error());
  95. die("Problem connecting to the database. ");
  96. }
  97. //
  98. // Select all mailboxes to verify against dirs listed in array
  99. //
  100. $query = "SELECT * FROM mailbox";
  101. $result = mysqli_query($conx, $query);
  102. //
  103. // Query the mailbox table
  104. //
  105. if (! $result) {
  106. die("Failed to query mailbox table.");
  107. }
  108. //
  109. // Fetch the list of results
  110. //
  111. while ($row = mysqli_fetch_assoc($result)) {
  112. //
  113. // Pull apart the maildir field, needed to figure out the directory structure to compare
  114. //
  115. $strip = explode("/", $row['maildir']);
  116. //
  117. // Unset the array if it exists. This stops it being erased later.
  118. //
  119. unset($dir[ $strip[0] ][ $strip[1] ]);
  120. }
  121. //
  122. // If there are results. unset the domain too.
  123. //
  124. if (count($dir[$strip[0]])==0 and mysqli_num_rows($result)>0) {
  125. unset($dir[$strip[0]]);
  126. }
  127. //
  128. // OK, time to clean up. All known users/domains have been removed from the list.
  129. //
  130. //
  131. // If the array still exists (incase nothing there)
  132. //
  133. if (is_array($dir)) {
  134. //
  135. // Go through each dir
  136. //
  137. foreach ($dir as $key => $value) {
  138. //
  139. // Is this a user array?
  140. //
  141. if (!is_array($value)) {
  142. continue;
  143. }
  144. //
  145. // Go through and nuke the folders
  146. //
  147. foreach ($value as $user => $value2) {
  148. // Nuke.. need any more explanations?
  149. $path = $homedir . '/' . $key . '/' . $user;
  150. $sieve_path = $homedir . '/.sieve/' . $key . '/' . $user;
  151. $sieve_exists = file_exists($sieve_path);
  152. // check if user has Sieve filters created
  153. if ($MAKE_CHANGES) {
  154. deldir($path);
  155. if ($sieve_exists) {
  156. deldir($sieve_path);
  157. }
  158. } else {
  159. echo " - Would recursively delete : $path \n";
  160. if ($sieve_exists) {
  161. echo " - Would recursively delete Sieve filters : $sieve_path \n";
  162. }
  163. }
  164. }
  165. }
  166. }
  167. echo "Cleanup process completed\n";