Subversion Repositories sysadmin_scripts

Rev

Rev 57 | Rev 86 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 57 Rev 58
Line 61... Line 61...
61
# the default values for everything. These are overridden
61
# the default values for everything. These are overridden
62
# by default values in the conf file (.yaml) or by individual
62
# by default values in the conf file (.yaml) or by individual
63
# accounts entries.
63
# accounts entries.
64
my $config = {
64
my $config = {
65
   'default' => {
65
   'default' => {
-
 
66
      # if set, most log stuff is sent to this file
-
 
67
      'logfile' => '',
-
 
68
      # defines the amount of crap which ends up in the logfile
-
 
69
      'loglevel' => 4,
66
      # where the mail is going to
70
      # where the mail is going to
67
      'target' => {
71
      'target' => {
68
                  # these have no defaults. They should be in the configuration file
72
                  # these have no defaults. They should be in the configuration file
69
                  # 'password' => 'password',
73
                  # 'password' => 'password',
70
                  # 'username' => 'username',
74
                  # 'username' => 'username',
Line 111... Line 115...
111
      # if 0, will not be processed
115
      # if 0, will not be processed
112
      'enabled' => 1,
116
      'enabled' => 1,
113
   }
117
   }
114
};
118
};
115
 
119
 
-
 
120
# prints to a log file, if defined. Otherwise, prints to STDOUT
-
 
121
sub logit {
-
 
122
   my $priority = shift;
-
 
123
   return unless $priority <= $config->{'default'}->{'loglevel'};
-
 
124
   if ( $config->{'default'}->{'logfile'} ) {
-
 
125
      open( my $logfile, '>>', $config->{'default'}->{'logfile'} ) || die "Could not write to $config->{default}->{logfile}: $!\n";
-
 
126
      while ( my $message = shift ) {
-
 
127
         print $logfile "$message\n";
-
 
128
      }
-
 
129
      close( $logfile );
-
 
130
   } else {
-
 
131
      print STDOUT join( "\n", @_ ) . "\n";
-
 
132
   }
-
 
133
   return;
-
 
134
} # logit
-
 
135
 
116
 
136
 
117
#
137
#
118
# find where the script is actually located as cfg should be there
138
# find where the script is actually located as cfg should be there
119
#
139
#
120
sub getScriptLocation {
140
sub getScriptLocation {
Line 227... Line 247...
227
# If folder has messages that match the criteria, move them to target
247
# If folder has messages that match the criteria, move them to target
228
# creates the target folder if necessary
248
# creates the target folder if necessary
229
#
249
#
230
sub processFolder {
250
sub processFolder {
231
   my ( $source, $target, $folder, $TESTING ) = @_;
251
   my ( $source, $target, $folder, $TESTING ) = @_;
232
   #$dateBefore, $sourceDelimiter, $targetDelimiter, $deleteOnSuccess
-
 
233
   print "\n=== Processing $folder\n";
252
   &logit( 1, '', "=== Processing $folder" );
234
   my $sourceAccount = $source->{'connection'};
253
   my $sourceAccount = $source->{'connection'};
235
   my $targetAccount = $target->{'connection'};
254
   my $targetAccount = $target->{'connection'};
236
   my $numMessages = 0;
255
   my $numMessages = 0;
237
   $sourceAccount->expunge_mailbox( $folder ); # clean it up so we don't copy deleted messages
256
   $sourceAccount->expunge_mailbox( $folder ); # clean it up so we don't copy deleted messages
238
   $sourceAccount->select( $folder ) or die "Could not connect to folder $folder\n"; # move into the correct folder for the source
257
   $sourceAccount->select( $folder ) or die "Could not connect to folder $folder\n"; # move into the correct folder for the source
239
   my @ids = $sourceAccount->search_sent_before( $source->{'before date'} ); # use sent_before to get the sent date from message
258
   my @ids = $sourceAccount->search_sent_before( $source->{'before date'} ); # use sent_before to get the sent date from message
240
   print "Found " . scalar( @ids ) . " messages to process\n";
-
 
241
   return 0 unless @ids; # we have nothing to copy, so exit
259
   return 0 unless @ids; # we have nothing to copy, so exit
-
 
260
   &logit( 3, "Found " . scalar( @ids ) . " messages to process" );
242
   # make life easier by precalculating some paths as array pointers
261
   # make life easier by precalculating some paths as array pointers
243
   my @sourceFolders = split( '\\' . $source->{'separator'}, $folder );
262
   my @sourceFolders = split( '\\' . $source->{'separator'}, $folder );
244
   my @pattern = split '\\^', $target->{'hierarchy'};
263
   my @pattern = split '\\^', $target->{'hierarchy'};
245
   $source->{'source folder list'} = \@sourceFolders;
264
   $source->{'source folder list'} = \@sourceFolders;
246
   $target->{'hierachy pattern'} = \@pattern;
265
   $target->{'hierachy pattern'} = \@pattern;
Line 248... Line 267...
248
   # process each message to be done
267
   # process each message to be done
249
   while ( my $id = shift ( @ids ) ) {
268
   while ( my $id = shift ( @ids ) ) {
250
      # get the flags
269
      # get the flags
251
      my @flags = $sourceAccount->msg_flags( $id );
270
      my @flags = $sourceAccount->msg_flags( $id );
252
      # get the message
271
      # get the message
253
      my $message = $sourceAccount->get( $id ) or die $sourceAccount->errstr;
272
      my $message = $sourceAccount->get( $id ) or die "Error getting message ID $id: $sourceAccount->errstr\n";
254
      # calculate where we are going to move this to
273
      # calculate where we are going to move this to
255
      my $targetFolder = &calculateTargetFolder( $message, $source, $target );
274
      my $targetFolder = &calculateTargetFolder( $message, $source, $target );
256
      if ( $TESTING ) {
275
      if ( $TESTING ) {
257
         print "Would have " . ( $source->{'deleteOnSuccess'} ? 'moved' : 'copied' )  . " message to $targetFolder\n";
276
         &logit( 0, "Would have " . ( $source->{'deleteOnSuccess'} ? 'moved' : 'copied' )  . " message to $targetFolder" );
258
         next;
277
         next;
259
      }
278
      }
260
      if ( $target->{'connection'}->select( $targetFolder ) || &makeFolder( $target->{'connection'}, $targetFolder, $target->{'separator'} ) ) {
279
      if ( $target->{'connection'}->select( $targetFolder ) || &makeFolder( $target->{'connection'}, $targetFolder, $target->{'separator'} ) ) {
261
         if ( $target->{'connection'}->put( $targetFolder, $message, @flags ) ) {
280
         if ( $target->{'connection'}->put( $targetFolder, $message, @flags ) ) {
262
            $source->{'connection'}->delete( $id ) if ( $source->{'deleteOnSuccess'} ) ;
281
            $source->{'connection'}->delete( $id ) if ( $source->{'deleteOnSuccess'} ) ;
Line 299... Line 318...
299
# fully qualified path with the correct delimiters
318
# fully qualified path with the correct delimiters
300
#
319
#
301
sub makeFolder {
320
sub makeFolder {
302
   my ($imap, $folder, $delimiter) = @_;
321
   my ($imap, $folder, $delimiter) = @_;
303
 
322
 
304
   #print "\n\t\tCreating folder $folder";
323
   &logit( 3,  "\n\t\tCreating folder $folder" );
305
   # you must create the parent folder before creating the children
324
   # you must create the parent folder before creating the children
306
   my $escapedDelimiter = '\\' . $delimiter;
325
   my $escapedDelimiter = '\\' . $delimiter;
307
   my @folders = split( $escapedDelimiter, $folder );
326
   my @folders = split( $escapedDelimiter, $folder );
308
   $folder = '';
327
   $folder = '';
309
   # take them from the left and, if they don't exist, create it
328
   # take them from the left and, if they don't exist, create it
310
   while ( my $subdir = shift @folders ) {
329
   while ( my $subdir = shift @folders ) {
311
      $folder .= $delimiter if $folder;
330
      $folder .= $delimiter if $folder;
312
      $folder .= $subdir;
331
      $folder .= $subdir;
313
      next if $imap->select( $folder ); # already created, so look deeper in hierachy
332
      next if $imap->select( $folder ); # already created, so look deeper in hierachy
314
      print "\n\t\t\tCreating subfolder $folder";
333
      &logit( 1, "\n\t\t\tCreating subfolder $folder" );
315
      $imap->create_mailbox( $folder ) || warn $imap->errstr();
334
      $imap->create_mailbox( $folder ) || warn $imap->errstr();
316
      $imap->folder_subscribe( $folder ) || die $imap->errstr();
335
      $imap->folder_subscribe( $folder ) || die $imap->errstr();
317
      unless ( $imap->select( $folder ) ) { # verify it was created
336
      unless ( $imap->select( $folder ) ) { # verify it was created
318
         warn "Unable to create $folder on target account\n";
337
         warn "Unable to create $folder on target account\n";
319
         return 0;
338
         return 0;
Line 331... Line 350...
331
   my $separator = $source->{'separator'};
350
   my $separator = $source->{'separator'};
332
   return 1 if $folder eq 'INBOX'; # do NOT mess with INBOX
351
   return 1 if $folder eq 'INBOX'; # do NOT mess with INBOX
333
   return 2 if $sourceAccount->select($folder) > 0; # do not mess with it if it still has messages in it
352
   return 2 if $sourceAccount->select($folder) > 0; # do not mess with it if it still has messages in it
334
   return 3 if $sourceAccount->mailboxes( $folder . $separator . '*' ); # do not mess with it if it has subfolders
353
   return 3 if $sourceAccount->mailboxes( $folder . $separator . '*' ); # do not mess with it if it has subfolders
335
   return 4 if $source->{'system folders'}->{lc $folder}; # do not mess with system folders
354
   return 4 if $source->{'system folders'}->{lc $folder}; # do not mess with system folders
336
   print "\n\t\tDeleting empty folder $folder" . ( $TESTING ? ' Dry Run' : '' );
355
   &logit( 1, "\n\t\tDeleting empty folder $folder" . ( $TESTING ? ' Dry Run' : '' ) );
337
   return if $TESTING;
356
   return 0 if $TESTING;
-
 
357
   # select something other than the folder to be deleted
-
 
358
   $sourceAccount->select( 'INBOX' );
338
   $sourceAccount->folder_unsubscribe($folder);
359
   if ( $sourceAccount->folder_unsubscribe($folder) ) {
339
   $sourceAccount->delete_mailbox( $folder );
360
      if ( $sourceAccount->delete_mailbox( $folder ) ) {
-
 
361
         return 0;
-
 
362
      } else {
-
 
363
         warn "Error trying to delete mailbox $folder: " . $sourceAccount->errstr . "\n";
-
 
364
      }
-
 
365
   } else {
-
 
366
      warn "Error trying to unsubscribe from $folder: " . $sourceAccount->errstr . "\n";
-
 
367
   }
-
 
368
   return 0;
340
}
369
}
341
 
370
 
342
 
371
 
343
# main process loop to handle one account
372
# main process loop to handle one account
344
#
373
#
Line 346... Line 375...
346
   my $account = shift;
375
   my $account = shift;
347
 
376
 
348
   return 0 unless $account->{'enabled'}; # blow it off if it is not enabled
377
   return 0 unless $account->{'enabled'}; # blow it off if it is not enabled
349
   my $TESTING = $account->{'testing'}; # create mini global if we should test this account
378
   my $TESTING = $account->{'testing'}; # create mini global if we should test this account
350
 
379
 
351
   print "========= Test Mode ========\n" if $TESTING;
380
   &logit( 0, "========= Test Mode ========\n" ) if $TESTING;
352
   
381
   
353
   # open and log into both source and target, and get the separator used
382
   # open and log into both source and target, and get the separator used
354
   foreach my $acct ( 'target','source' ) {
383
   foreach my $acct ( 'target','source' ) {
355
      $account->{$acct}->{'connection'} = &openIMAPConnection( $account->{$acct}->{'server'}, $account->{$acct}->{'username'}, $account->{$acct}->{'password'} );
384
      $account->{$acct}->{'connection'} = &openIMAPConnection( $account->{$acct}->{'server'}, $account->{$acct}->{'username'}, $account->{$acct}->{'password'} );
356
      unless ( $account->{$acct}->{'connection'} ) {
385
      unless ( $account->{$acct}->{'connection'} ) {
Line 366... Line 395...
366
 
395
 
367
   my %temp = map{ lc($_) => 1 } @{$source->{'system'}};
396
   my %temp = map{ lc($_) => 1 } @{$source->{'system'}};
368
   $source->{'system folders'} = \%temp;
397
   $source->{'system folders'} = \%temp;
369
 
398
 
370
   $source->{'before date'} = &getDate( $source->{'age'} );
399
   $source->{'before date'} = &getDate( $source->{'age'} );
371
   print "\t" . ( $source->{'deleteOnSuccess'} ? 'Moving' : 'Copying' ) . " all messages before $source->{'before date'}\n";
400
   &logit( 1, "\t" . ( $source->{'deleteOnSuccess'} ? 'Moving' : 'Copying' ) . " all messages before $source->{'before date'}" );
372
 
401
 
373
   # get a list of all folders to be processed on the source
402
   # get a list of all folders to be processed on the source
374
   $source->{'folders'} = &getFolders( $source->{'connection'}, $source->{'ignore'}, $source->{'separator'} );
403
   $source->{'folders'} = &getFolders( $source->{'connection'}, $source->{'ignore'}, $source->{'separator'} );
375
 
404
 
376
   if ( $TESTING ) {
405
   if ( $TESTING ) {
Line 387... Line 416...
387
      my $messages;
416
      my $messages;
388
      $messages = &processFolder( $source, $target, $folder, $TESTING ); #, $date, $$source{'separator'}, $$target{'separator'}, $deleteOnSuccess );
417
      $messages = &processFolder( $source, $target, $folder, $TESTING ); #, $date, $$source{'separator'}, $$target{'separator'}, $deleteOnSuccess );
389
 
418
 
390
      $TESTING ? print "Would expunge $folder\n" : $source->{'connection'}->expunge_mailbox( $folder );
419
      $TESTING ? print "Would expunge $folder\n" : $source->{'connection'}->expunge_mailbox( $folder );
391
      # delete folder if empty and client has requested it.
420
      # delete folder if empty and client has requested it.
392
      &deleteAFolder( $source, $folder, $TESTING ) if $account->{'source'}->{'deleteEmptyFolders'};
421
      if ( $account->{'source'}->{'deleteEmptyFolders'} ) {
-
 
422
         my $returnCode = &deleteAFolder( $source, $folder, $TESTING );
-
 
423
         &logit( 3, "Return code from deleteAFolder is $returnCode" );
-
 
424
      }
393
      print "\n\t\t$messages processed\n";
425
      &logit( 1,  "$messages processed" ); 
394
      $count += $messages;
426
      $count += $messages;
395
      $processedCount++;
427
      $processedCount++;
396
      # next line used only for testing. Dies after 5 folders on first account
428
      # next line used only for testing. Dies after 5 folders on first account
397
      last if $processedCount > 5 and $TESTING;
429
      last if $processedCount > 5 and $TESTING;
398
   }
430
   }
Line 408... Line 440...
408
#                   Main                                              #
440
#                   Main                                              #
409
#######################################################################
441
#######################################################################
410
 
442
 
411
# read and evaluate configuration file
443
# read and evaluate configuration file
412
&readConfig() || die "could not load config file\n";
444
&readConfig() || die "could not load config file\n";
-
 
445
 
413
#print Dumper( $config ); die;
446
#print Dumper( $config ); die;
414
foreach my $account ( keys %{$config->{'accounts'}} ) {
447
foreach my $account ( keys %{$config->{'accounts'}} ) {
415
    $config->{'accounts'}->{$account} = &fixupAccount( $config->{'default'}, $config->{'accounts'}->{$account} );
448
    $config->{'accounts'}->{$account} = &fixupAccount( $config->{'default'}, $config->{'accounts'}->{$account} );
416
}
449
}
417
 
450
 
Line 428... Line 461...
428
#die Dumper( $accounts );
461
#die Dumper( $accounts );
429
 
462
 
430
# now, process each in turn
463
# now, process each in turn
431
foreach my $account ( keys %$accounts ) {
464
foreach my $account ( keys %$accounts ) {
432
   # talk to user
465
   # talk to user
433
   print "Processing account $account\n";
466
   &logit( 1,  "Processing account $account" );
434
   # do the account. This is the main worker bee
467
   # do the account. This is the main worker bee
435
   $accounts->{$account}->{'processed'} = &processAccount( $accounts->{$account} );
468
   $accounts->{$account}->{'processed'} = &processAccount( $accounts->{$account} );
436
   print "Done, $accounts->{$account}->{'processed'} messages copied\n";
469
   &logit( 1,  "Done, $accounts->{$account}->{'processed'} messages copied" );
437
   $processed{'Accounts'}++;
470
   $processed{'Accounts'}++;
438
   $processed{'Messages'} += $accounts->{$account}->{'processed'};
471
   $processed{'Messages'} += $accounts->{$account}->{'processed'};
439
   # free up space we allocated since we stored a bunch of stuff in there, and we don't need it anymore
472
   # free up space we allocated since we stored a bunch of stuff in there, and we don't need it anymore
440
   $accounts->{$account} = undef; 
473
   $accounts->{$account} = undef; 
441
} # foreach loop
474
} # foreach loop
442
 
475
 
443
print "$processed{'Accounts'} accounts processed, $processed{'Messages'} messages\n";
476
&logit( 1, "$processed{Accounts} accounts processed, $processed{Messages} messages" );
444
 
477
 
445
 
478
 
446
1;
479
1;
447
  
480