imapsync_runner.pl 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #!/usr/bin/perl
  2. use DBI;
  3. use LockFile::Simple qw(lock trylock unlock);
  4. use Proc::ProcessTable;
  5. use Data::Dumper qw(Dumper);
  6. use IPC::Run 'run';
  7. use File::Temp;
  8. use Try::Tiny;
  9. use sigtrap 'handler' => \&sig_handler, qw(INT TERM KILL QUIT);
  10. sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
  11. my $t = Proc::ProcessTable->new;
  12. my $imapsync_running = grep { $_->{cmndline} =~ /imapsync\s/i } @{$t->table};
  13. if ($imapsync_running ge 1)
  14. {
  15. print "imapsync is active, exiting...";
  16. exit;
  17. }
  18. sub qqw($) {
  19. my @params = ();
  20. my @values = split(/(?=--)/, $_[0]);
  21. foreach my $val (@values) {
  22. my @tmpparam = split(/ /, $val, 2);
  23. foreach my $tmpval (@tmpparam) {
  24. if ($tmpval ne '') {
  25. push @params, $tmpval;
  26. }
  27. }
  28. }
  29. foreach my $val (@params) {
  30. $val=trim($val);
  31. }
  32. return @params;
  33. }
  34. $run_dir="/tmp";
  35. $dsn = 'DBI:mysql:database=' . $ENV{'DBNAME'} . ';mysql_socket=/var/run/mysqld/mysqld.sock';
  36. $lock_file = $run_dir . "/imapsync_busy";
  37. $lockmgr = LockFile::Simple->make(-autoclean => 1, -max => 1);
  38. $lockmgr->lock($lock_file) || die "can't lock ${lock_file}";
  39. $dbh = DBI->connect($dsn, $ENV{'DBUSER'}, $ENV{'DBPASS'}, {
  40. mysql_auto_reconnect => 1,
  41. mysql_enable_utf8mb4 => 1
  42. });
  43. $dbh->do("UPDATE imapsync SET is_running = 0");
  44. sub sig_handler {
  45. # Send die to force exception in "run"
  46. die "sig_handler received signal, preparing to exit...\n";
  47. };
  48. open my $file, '<', "/etc/sogo/sieve.creds";
  49. my $creds = <$file>;
  50. close $file;
  51. my ($master_user, $master_pass) = split /:/, $creds;
  52. my $sth = $dbh->prepare("SELECT id,
  53. user1,
  54. user2,
  55. host1,
  56. authmech1,
  57. password1,
  58. exclude,
  59. port1,
  60. enc1,
  61. delete2duplicates,
  62. maxage,
  63. subfolder2,
  64. delete1,
  65. delete2,
  66. automap,
  67. skipcrossduplicates,
  68. maxbytespersecond,
  69. custom_params,
  70. subscribeall,
  71. timeout1,
  72. timeout2,
  73. dry
  74. FROM imapsync
  75. WHERE active = 1
  76. AND is_running = 0
  77. AND (
  78. UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(last_run) > mins_interval * 60
  79. OR
  80. last_run IS NULL)
  81. ORDER BY last_run");
  82. $sth->execute();
  83. my $row;
  84. while ($row = $sth->fetchrow_arrayref()) {
  85. $id = @$row[0];
  86. $user1 = @$row[1];
  87. $user2 = @$row[2];
  88. $host1 = @$row[3];
  89. $authmech1 = @$row[4];
  90. $password1 = @$row[5];
  91. $exclude = @$row[6];
  92. $port1 = @$row[7];
  93. $enc1 = @$row[8];
  94. $delete2duplicates = @$row[9];
  95. $maxage = @$row[10];
  96. $subfolder2 = @$row[11];
  97. $delete1 = @$row[12];
  98. $delete2 = @$row[13];
  99. $automap = @$row[14];
  100. $skipcrossduplicates = @$row[15];
  101. $maxbytespersecond = @$row[16];
  102. $custom_params = @$row[17];
  103. $subscribeall = @$row[18];
  104. $timeout1 = @$row[19];
  105. $timeout2 = @$row[20];
  106. $dry = @$row[21];
  107. if ($enc1 eq "TLS") { $enc1 = "--tls1"; } elsif ($enc1 eq "SSL") { $enc1 = "--ssl1"; } else { undef $enc1; }
  108. my $template = $run_dir . '/imapsync.XXXXXXX';
  109. my $passfile1 = File::Temp->new(TEMPLATE => $template);
  110. my $passfile2 = File::Temp->new(TEMPLATE => $template);
  111. binmode( $passfile1, ":utf8" );
  112. print $passfile1 "$password1\n";
  113. print $passfile2 trim($master_pass) . "\n";
  114. my @custom_params_a = qqw($custom_params);
  115. my $custom_params_ref = \@custom_params_a;
  116. my $generated_cmds = [ "/usr/local/bin/imapsync",
  117. "--tmpdir", "/tmp",
  118. "--nofoldersizes",
  119. "--addheader",
  120. ($timeout1 gt "0" ? () : ('--timeout1', $timeout1)),
  121. ($timeout2 gt "0" ? () : ('--timeout2', $timeout2)),
  122. ($exclude eq "" ? () : ("--exclude", $exclude)),
  123. ($subfolder2 eq "" ? () : ('--subfolder2', $subfolder2)),
  124. ($maxage eq "0" ? () : ('--maxage', $maxage)),
  125. ($maxbytespersecond eq "0" ? () : ('--maxbytespersecond', $maxbytespersecond)),
  126. ($delete2duplicates ne "1" ? () : ('--delete2duplicates')),
  127. ($subscribeall ne "1" ? () : ('--subscribeall')),
  128. ($delete1 ne "1" ? () : ('--delete')),
  129. ($delete2 ne "1" ? () : ('--delete2')),
  130. ($automap ne "1" ? () : ('--automap')),
  131. ($skipcrossduplicates ne "1" ? () : ('--skipcrossduplicates')),
  132. (!defined($enc1) ? () : ($enc1)),
  133. "--host1", $host1,
  134. "--user1", $user1,
  135. "--passfile1", $passfile1->filename,
  136. "--port1", $port1,
  137. "--host2", "localhost",
  138. "--user2", $user2 . '*' . trim($master_user),
  139. "--passfile2", $passfile2->filename,
  140. ($dry eq "1" ? ('--dry') : ()),
  141. '--no-modulesversion',
  142. '--noreleasecheck'];
  143. try {
  144. $is_running = $dbh->prepare("UPDATE imapsync SET is_running = 1, success = NULL, exit_status = NULL WHERE id = ?");
  145. $is_running->bind_param( 1, ${id} );
  146. $is_running->execute();
  147. run [@$generated_cmds, @$custom_params_ref], '&>', \my $stdout;
  148. # check exit code and status
  149. ($exit_code, $exit_status) = ($stdout =~ m/Exiting\swith\sreturn\svalue\s(\d+)\s\(([^:)]+)/);
  150. $success = 0;
  151. if (defined $exit_code && $exit_code == 0) {
  152. $success = 1;
  153. }
  154. $update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ? WHERE id = ?");
  155. $update->bind_param( 1, ${stdout} );
  156. $update->bind_param( 2, ${success} );
  157. $update->bind_param( 3, ${exit_status} );
  158. $update->bind_param( 4, ${id} );
  159. $update->execute();
  160. } catch {
  161. $update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");
  162. $update->bind_param( 1, ${id} );
  163. $update->execute();
  164. } finally {
  165. $update = $dbh->prepare("UPDATE imapsync SET last_run = NOW(), is_running = 0 WHERE id = ?");
  166. $update->bind_param( 1, ${id} );
  167. $update->execute();
  168. };
  169. }
  170. $sth->finish();
  171. $dbh->disconnect();
  172. $lockmgr->unlock($lock_file);