Line 22... |
Line 22... |
22 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
22 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
23 |
# GNU General Public License for more details.
|
23 |
# GNU General Public License for more details.
|
24 |
#
|
24 |
#
|
25 |
# You should have received a copy of the GNU General Public License
|
25 |
# You should have received a copy of the GNU General Public License
|
26 |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
26 |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
- |
|
27 |
#
|
- |
|
28 |
# for required libraries
|
- |
|
29 |
# apt-get -y install libnet-imap-simple-ssl-perl libyaml-tiny-perl libhash-merge-simple-perl libclone-perl
|
27 |
|
30 |
|
28 |
use strict;
|
31 |
use strict;
|
29 |
use warnings;
|
32 |
use warnings;
|
30 |
use Net::IMAP::Simple; # libnet-imap-simple-ssl-perl
|
33 |
use Net::IMAP::Simple; # libnet-imap-simple-ssl-perl
|
31 |
use POSIX; # to get floor and ceil
|
34 |
use POSIX; # to get floor and ceil
|
- |
|
35 |
use YAML::Tiny; # apt-get libyaml-tiny-perl under debian
|
- |
|
36 |
use Clone 'clone'; # libclone-perl
|
- |
|
37 |
use Hash::Merge::Simple qw/ merge clone_merge /; # libhash-merge-simple-perl
|
- |
|
38 |
|
32 |
#use Data::Dumper;
|
39 |
use Data::Dumper;
|
33 |
|
40 |
|
34 |
# globals
|
41 |
# globals
|
35 |
my $CONFIG_FILE_NAME = 'archiveIMAP.cfg';
|
42 |
my $CONFIG_FILE_NAME = 'archiveIMAP.yaml';
|
- |
|
43 |
|
36 |
my $server = 'localhost'; # used if not specified in definition
|
44 |
# the default values for everything. These are overridden
|
- |
|
45 |
# by default values in the conf file (.yaml) or by individual
|
- |
|
46 |
# accounts entries.
|
- |
|
47 |
my $config = {
|
- |
|
48 |
'default' => {
|
- |
|
49 |
# where the mail is going to
|
- |
|
50 |
'target' => {
|
- |
|
51 |
# these have no defaults. They should be in the configuration file
|
- |
|
52 |
# 'password' => 'password',
|
- |
|
53 |
# 'username' => 'username',
|
37 |
# Following are added to ignore in definition in account (%accounts)
|
54 |
# hierarchy can be any combination of <path>, <month> and <year>
|
- |
|
55 |
'hierarchy' => '<path>',
|
- |
|
56 |
# default target server
|
- |
|
57 |
'server' => 'localhost',
|
- |
|
58 |
},
|
- |
|
59 |
# where the mail is coming from
|
- |
|
60 |
'source' => {
|
38 |
my @ignore = ( 'Deleted Messages','Drafts','Junk E-mail','Junk','Trash' );
|
61 |
# these have no defaults. They should be in the configuration file
|
- |
|
62 |
# 'password' => 'password',
|
- |
|
63 |
# 'username' => 'username',
|
- |
|
64 |
# Anything older than this is archived
|
39 |
# these are folders we may want to copy, but we never want to delete
|
65 |
# number of days unless followed by 'M' or 'Y', in which case it is
|
- |
|
66 |
# multiplied by the number of days in a year (365.2425) or days in a month (30.5)
|
40 |
my @systemFolders = ('Outbox','Sent Items','INBOX','Inbox');
|
67 |
# may be a float, ie 1.25Y is the same as 15M
|
- |
|
68 |
'age' => '1Y',
|
- |
|
69 |
# if set to 1, any folders emptied out will be deleted EXCEPT system folders
|
41 |
my $deleteEmptyFolders = 1;
|
70 |
'deleteEmptyFolders' => 0,
|
- |
|
71 |
# default source server
|
- |
|
72 |
'server' => 'localhost',
|
- |
|
73 |
# these folders are considered system folders and never deleted, case insensitive
|
- |
|
74 |
'system' => [
|
- |
|
75 |
'Outbox',
|
- |
|
76 |
'Sent Items',
|
- |
|
77 |
'INBOX'
|
- |
|
78 |
],
|
- |
|
79 |
# these folders are ignored, ie not processed at all. Case insensitive
|
- |
|
80 |
'ignore' => [
|
- |
|
81 |
'Deleted Messages',
|
- |
|
82 |
'Drafts',
|
- |
|
83 |
'Junk E-mail',
|
- |
|
84 |
'Junk',
|
- |
|
85 |
'Trash'
|
- |
|
86 |
],
|
- |
|
87 |
# if 1, after successful copy to target, remove from source
|
42 |
my $deleteOnSuccess = 1;
|
88 |
'deleteOnSuccess' => 0
|
- |
|
89 |
},
|
- |
|
90 |
|
43 |
my %accounts; # this must be configured in archiveIMAP.cfg. See sample.
|
91 |
# if 1, does a dry run showing what would have happened
|
- |
|
92 |
'testing' => 0,
|
- |
|
93 |
# if 0, will not be processed
|
- |
|
94 |
'enabled' => 1,
|
- |
|
95 |
}
|
- |
|
96 |
};
|
- |
|
97 |
|
44 |
|
98 |
|
45 |
#
|
99 |
#
|
46 |
# find where the script is actually located as cfg should be there
|
100 |
# find where the script is actually located as cfg should be there
|
47 |
#
|
101 |
#
|
48 |
sub getScriptLocation {
|
102 |
sub getScriptLocation {
|
Line 56... |
Line 110... |
56 |
# Read the configuration file from current location
|
110 |
# Read the configuration file from current location
|
57 |
# and return it as a string
|
111 |
# and return it as a string
|
58 |
#
|
112 |
#
|
59 |
sub readConfig {
|
113 |
sub readConfig {
|
60 |
my $scriptLocation = &getScriptLocation();
|
114 |
my $scriptLocation = &getScriptLocation();
|
61 |
my $return = '';
|
- |
|
62 |
if ( -e "$scriptLocation/$CONFIG_FILE_NAME" ) {
|
115 |
if ( -e "$scriptLocation/$CONFIG_FILE_NAME" ) {
|
63 |
open CFG,"<$scriptLocation/$CONFIG_FILE_NAME" or die "Could not read $scriptLocation/$CONFIG_FILE_NAME: $!\n";
|
116 |
my $yaml = YAML::Tiny->read( "$scriptLocation/$CONFIG_FILE_NAME" );
|
- |
|
117 |
# use clone_merge to merge conf file into $config
|
- |
|
118 |
# overwrites anything in $config if it exists in the config file
|
64 |
$return = join ( '', <CFG> );
|
119 |
$config = clone_merge( $config, $yaml->[0] );
|
65 |
close CFG;
|
120 |
return 1;
|
66 |
}
|
121 |
}
|
- |
|
122 |
return 0;
|
- |
|
123 |
}
|
- |
|
124 |
|
- |
|
125 |
# merges default into current account, overwriting anything not defined in account with
|
- |
|
126 |
# value from default EXCEPT arrays labeled in @tags, which will be merged together.
|
- |
|
127 |
sub fixupAccount {
|
- |
|
128 |
my ( $default, $account ) = @_;
|
- |
|
129 |
|
- |
|
130 |
# these arrays, part of source, will be appended together instead of being overwritten
|
- |
|
131 |
my @tags = ( 'ignore', 'system' );
|
- |
|
132 |
# merge the tags in question. NOTE: they can only be in source
|
- |
|
133 |
foreach my $tag ( @tags) {
|
- |
|
134 |
if ( $default->{'source'}->{$tag} && $account->{'source'}->{$tag} ) {
|
- |
|
135 |
my @j = ( @{$default->{'source'}->{$tag}}, @{$account->{'source'}->{$tag}} );
|
- |
|
136 |
$account->{'source'}->{$tag} = \@j;
|
- |
|
137 |
}
|
- |
|
138 |
}
|
- |
|
139 |
# now, merge account and default, with account taking precedence.
|
- |
|
140 |
return clone_merge( $default, $account );
|
- |
|
141 |
#my $c = clone_merge( $default, $account );
|
67 |
return $return;
|
142 |
#return $c;
|
68 |
}
|
143 |
}
|
69 |
|
144 |
|
70 |
#
|
145 |
#
|
71 |
# Open an IMAP connection
|
146 |
# Open an IMAP connection
|
72 |
#
|
147 |
#
|
Line 81... |
Line 156... |
81 |
return $imap;
|
156 |
return $imap;
|
82 |
}
|
157 |
}
|
83 |
|
158 |
|
84 |
#
|
159 |
#
|
85 |
# returns a string in proper format for RFC which is $age days ago
|
160 |
# returns a string in proper format for RFC which is $age days ago
|
- |
|
161 |
# $age is a float, possibly followed by a single character modifier
|
86 |
#
|
162 |
#
|
87 |
sub getDate {
|
163 |
sub getDate {
|
88 |
my $age = shift;
|
164 |
my $age = shift;
|
- |
|
165 |
# allow modifier to age which contains 'Y' (years) or 'M' (months)
|
- |
|
166 |
# Simply set multiplier to the correct value, then multiply the value
|
- |
|
167 |
$age = lc( $age );
|
- |
|
168 |
if ( $age =~ m/([0-9.]+)([a-z])/ ) {
|
- |
|
169 |
my $multiplier = ($2 == 'y' ? 365.2425 : ( $2 == 'm' ? 30.5 : MAXINT) );
|
- |
|
170 |
$age = floor( $1 * $multiplier);
|
- |
|
171 |
}
|
89 |
my @months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
|
172 |
my @months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
|
90 |
my @now = localtime(time - 24 * 60 * 60 * $age);
|
173 |
my @now = localtime(time - 24 * 60 * 60 * $age);
|
91 |
$now[4] = @months[$now[4]];
|
174 |
$now[4] = @months[$now[4]];
|
92 |
$now[5] += 1900;
|
175 |
$now[5] += 1900;
|
93 |
my $date = sprintf( "%d-%s-%d", $now[3],$now[4],$now[5] ) ; # '1-Jan-2014';
|
176 |
my $date = sprintf( "%d-%s-%d", $now[3],$now[4],$now[5] ) ; # '1-Jan-2014';
|
Line 153... |
Line 236... |
153 |
print "\n\t\tDeleting empty folder $folder";
|
236 |
print "\n\t\tDeleting empty folder $folder";
|
154 |
$sourceAccount->folder_unsubscribe($folder);
|
237 |
$sourceAccount->folder_unsubscribe($folder);
|
155 |
$sourceAccount->delete_mailbox( $folder );
|
238 |
$sourceAccount->delete_mailbox( $folder );
|
156 |
}
|
239 |
}
|
157 |
|
240 |
|
158 |
#
|
- |
|
159 |
# If folder has messages that match the criteria, move them to target
|
- |
|
160 |
# creates the target folder if necessary
|
- |
|
161 |
#
|
- |
|
162 |
sub processFolder {
|
- |
|
163 |
my ( $sourceAccount, $targetAccount, $folder, $dateBefore, $sourceDelimiter, $targetDelimiter, $deleteOnSuccess ) = @_;
|
- |
|
164 |
my $numMessages = 0;
|
- |
|
165 |
$sourceAccount->expunge_mailbox( $folder ); # clean it up so we don't copy deleted messages
|
- |
|
166 |
$sourceAccount->select( $folder ) or die "Could not connect to folder $folder\n"; # move into the correct folder for the source
|
- |
|
167 |
my @ids = $sourceAccount->search_sent_before( $dateBefore ); # use sent_before to get the sent date from message
|
- |
|
168 |
# print join( "\n\t\t\t", @ids ) . "\n";
|
- |
|
169 |
return 0 unless @ids; # we have nothing to copy, so exit
|
- |
|
170 |
if ( $sourceDelimiter ne $targetDelimiter ) { # different delimiters, so we have to change them in the folder def
|
- |
|
171 |
# they may contain meta chars, so escape them. We can use \Q \E in the pattern to match, but the
|
- |
|
172 |
# second part of the s/// will substitute literal EXCEPT for the delimiter and the dollar sign
|
- |
|
173 |
# I'm escaping the double quote (what I'm using for the delimiter) "just in case" but I'm not doing
|
- |
|
174 |
# the dollar sign, so this will fail, fail, fail if there is an issue there.
|
- |
|
175 |
my $escapedTargetDelimiter = $targetDelimiter eq '"' ? '\\' . $targetDelimiter : $targetDelimiter;
|
- |
|
176 |
$folder =~ s"\Q$sourceDelimiter\E"$escapedTargetDelimiter"g;
|
- |
|
177 |
}
|
- |
|
178 |
if ( $targetAccount->select( $folder ) || &makeFolder( $targetAccount, $folder, $targetDelimiter ) ) {
|
- |
|
179 |
foreach my $id ( @ids ) {
|
- |
|
180 |
my @flags = $sourceAccount->msg_flags( $id );
|
- |
|
181 |
my $message = $sourceAccount->get( $id ) or die $sourceAccount->errstr;
|
- |
|
182 |
if ( $targetAccount->put( $folder, $message, @flags ) ) {
|
- |
|
183 |
$sourceAccount->delete( $id ) if ( $deleteOnSuccess ) ;
|
- |
|
184 |
$numMessages++;
|
- |
|
185 |
} else {
|
- |
|
186 |
die "Could not write to target, aborting\n$targetAccount->errstr\n";
|
- |
|
187 |
}
|
- |
|
188 |
}
|
- |
|
189 |
} else {
|
- |
|
190 |
warn "\t\t$folder not found in target and could not create it\n";
|
- |
|
191 |
}
|
- |
|
192 |
return $numMessages;
|
- |
|
193 |
}
|
- |
|
194 |
|
- |
|
195 |
# this is an alternative to maintaining the hierarchy of the original system.
|
- |
|
196 |
# instead, it will take
|
- |
|
197 |
|
- |
|
198 |
sub processFolderByDate {
|
- |
|
199 |
my ( $sourceAccount, $targetAccount, $folder, $targetFormat, $dateBefore, $sourceDelimiter, $targetDelimiter, $deleteOnSuccess ) = @_;
|
- |
|
200 |
my $numMessages = 0;
|
- |
|
201 |
$sourceAccount->expunge_mailbox( $folder ); # clean it up so we don't copy deleted messages
|
- |
|
202 |
$sourceAccount->select( $folder ) or die "Could not connect to folder $folder\n"; # move into the correct folder for the source
|
- |
|
203 |
my @ids = $sourceAccount->search_sent_before( $dateBefore ); # use sent_before to get the sent date from message
|
- |
|
204 |
# print join( "\n\t\t\t", @ids ) . "\n";
|
- |
|
205 |
return 0 unless @ids; # we have nothing to copy, so exit
|
- |
|
206 |
|
- |
|
207 |
if ( $sourceDelimiter ne $targetDelimiter ) { # different delimiters, so we have to change them in the folder def
|
- |
|
208 |
# they may contain meta chars, so escape them. We can use \Q \E in the pattern to match, but the
|
- |
|
209 |
# second part of the s/// will substitute literal EXCEPT for the delimiter and the dollar sign
|
- |
|
210 |
# I'm escaping the double quote (what I'm using for the delimiter) "just in case" but I'm not doing
|
- |
|
211 |
# the dollar sign, so this will fail, fail, fail if there is an issue there.
|
- |
|
212 |
my $escapedTargetDelimiter = $targetDelimiter eq '"' ? '\\' . $targetDelimiter : $targetDelimiter;
|
- |
|
213 |
$folder =~ s"\Q$sourceDelimiter\E"$escapedTargetDelimiter"g;
|
- |
|
214 |
}
|
- |
|
215 |
if ( $targetAccount->select( $folder ) || &makeFolder( $targetAccount, $folder, $targetDelimiter ) ) {
|
- |
|
216 |
foreach my $id ( @ids ) {
|
- |
|
217 |
my @flags = $sourceAccount->msg_flags( $id );
|
- |
|
218 |
my $message = $sourceAccount->get( $id ) or die $sourceAccount->errstr;
|
- |
|
219 |
if ( $targetAccount->put( $folder, $message, @flags ) ) {
|
- |
|
220 |
$sourceAccount->delete( $id ) if ( $deleteOnSuccess ) ;
|
- |
|
221 |
$numMessages++;
|
- |
|
222 |
} else {
|
- |
|
223 |
die "Could not write to target, aborting\n$targetAccount->errstr\n";
|
- |
|
224 |
}
|
- |
|
225 |
}
|
- |
|
226 |
} else {
|
- |
|
227 |
warn "\t\t$folder not found in target and could not create it\n";
|
- |
|
228 |
}
|
- |
|
229 |
|
- |
|
230 |
|
- |
|
231 |
return $numMessages;
|
- |
|
232 |
}
|
- |
|
233 |
|
241 |
|
234 |
#
|
- |
|
235 |
# main processing loop to handle one account
|
242 |
# main process loop to handle one account
|
236 |
#
|
243 |
#
|
237 |
sub processAccount {
|
244 |
sub processAccount {
|
238 |
my ( $source, $target, $age, $ignore, $deleteOnSuccess, $deleteEmptyFolders, $hierarchy ) = @_;
|
- |
|
239 |
$heirarchy = '' unless $hierarchy;
|
245 |
my $account = shift;
|
240 |
|
246 |
|
241 |
my $date = getDate( $age );
|
247 |
my $date = &getDate( $age );
|
242 |
print "\t" . ( $deleteOnSuccess ? 'Moving' : 'Copying' ) . " all messages before $date\n";
|
248 |
print "\t" . ( $deleteOnSuccess ? 'Moving' : 'Copying' ) . " all messages before $date\n";
|
243 |
|
249 |
|
244 |
# open and log into both source and target, and get the separator used
|
250 |
# open and log into both source and target, and get the separator used
|
245 |
my $sourceAccount = &openIMAPConnection( $$source{'server'}, $$source{'username'}, $$source{'password'} );
|
251 |
my $sourceAccount = &openIMAPConnection( $$source{'server'}, $$source{'username'}, $$source{'password'} );
|
246 |
my $targetAccount = &openIMAPConnection( $$target{'server'}, $$target{'username'}, $$target{'password'} );
|
252 |
my $targetAccount = &openIMAPConnection( $$target{'server'}, $$target{'username'}, $$target{'password'} );
|
Line 255... |
Line 261... |
255 |
my $count = 0; # count the number of messages processed
|
261 |
my $count = 0; # count the number of messages processed
|
256 |
my $processedCount = 0; # count the number of folders processed
|
262 |
my $processedCount = 0; # count the number of folders processed
|
257 |
foreach my $folder ( @$folderList ) {
|
263 |
foreach my $folder ( @$folderList ) {
|
258 |
print "\t$folder";
|
264 |
print "\t$folder";
|
259 |
my $messages;
|
265 |
my $messages;
|
260 |
if ( $heirarchy ) {
|
- |
|
261 |
$messages = &processFolderByDate( $sourceAccount, $targetAccount, $folder, $hierarchy, $date, $$source{'separator'}, $$target{'separator'}, $deleteOnSuccess );
|
- |
|
262 |
} else {
|
- |
|
263 |
$messages = &processFolder( $sourceAccount, $targetAccount, $folder, $date, $$source{'separator'}, $$target{'separator'}, $deleteOnSuccess );
|
266 |
$messages = &processFolder( $sourceAccount, $targetAccount, $folder, $date, $$source{'separator'}, $$target{'separator'}, $deleteOnSuccess );
|
264 |
}
|
- |
|
265 |
$sourceAccount->expunge_mailbox( $folder );
|
267 |
$TESTING ? print "Would expunge $folder\n" : $sourceAccount->expunge_mailbox( $folder );
|
266 |
# delete folder if empty and client has requested it.
|
268 |
# delete folder if empty and client has requested it.
|
267 |
&deleteAFolder( $sourceAccount, $folder, $$source{'separator'}, $$source{'systemfolder'} ) if ( $deleteEmptyFolders );
|
269 |
( $TESTING ? print "Would delete $folder\n" : &deleteAFolder( $sourceAccount, $folder, $$source{'separator'}, $$source{'systemfolder'} ) ) if ( $deleteEmptyFolders );
|
268 |
print "\n\t\t$messages processed\n";
|
270 |
print "\n\t\t$messages processed\n";
|
269 |
$count += $messages;
|
271 |
$count += $messages;
|
270 |
$processedCount++;
|
272 |
$processedCount++;
|
271 |
# next line used only for testing. Dies after 5 folders on first account
|
273 |
# next line used only for testing. Dies after 5 folders on first account
|
272 |
# last if $processedCount > 5;
|
274 |
# last if $processedCount > 5;
|
Line 274... |
Line 276... |
274 |
$sourceAccount->quit;
|
276 |
$sourceAccount->quit;
|
275 |
$targetAccount->quit;
|
277 |
$targetAccount->quit;
|
276 |
return $count;
|
278 |
return $count;
|
277 |
}
|
279 |
}
|
278 |
|
280 |
|
- |
|
281 |
|
- |
|
282 |
|
279 |
#######################################################################
|
283 |
#######################################################################
|
280 |
# Main #
|
284 |
# Main #
|
281 |
#######################################################################
|
285 |
#######################################################################
|
282 |
|
286 |
|
283 |
# read and evaluate configuration file
|
287 |
# read and evaluate configuration file
|
284 |
if ( my $config = readConfig() ) {
|
288 |
&readConfig() || die "could not load config file\n";
|
285 |
eval $config;
|
289 |
#print Dumper( $config ); die;
|
286 |
die "Error in configuraration file $CONFIG_FILE_NAME\n$@" if $@;
|
290 |
foreach my $account ( keys %{$config->{'accounts'}} ) {
|
287 |
} else {
|
- |
|
288 |
die "Configurastion file $CONFIG_FILE_NAME must be located in script directory\n";
|
291 |
$config->{'accounts'}->{$account} = &fixupAccount( $config->{'default'}, $config->{'accounts'}->{$account} );
|
289 |
}
|
292 |
}
|
290 |
|
293 |
|
- |
|
294 |
#print Dumper( $config ) ; die;
|
291 |
|
295 |
|
- |
|
296 |
# just a place to gather some stats
|
292 |
my %processed;
|
297 |
my %processed;
|
293 |
$processed{'Accounts'} = 0;
|
298 |
$processed{'Accounts'} = 0;
|
294 |
$processed{'Messages'} = 0;
|
299 |
$processed{'Messages'} = 0;
|
295 |
|
300 |
|
- |
|
301 |
# grab only the accounts for simplicity
|
- |
|
302 |
my $accounts = $config->{'accounts'};
|
- |
|
303 |
# now, process each in turn
|
296 |
foreach my $account ( keys %accounts ) {
|
304 |
foreach my $account ( keys %$accounts ) {
|
297 |
# talk to user
|
305 |
# talk to user
|
298 |
print "Processing account $account\n";
|
306 |
print "Processing account $account\n";
|
299 |
# Set some defaults from globals if they were not defined
|
307 |
# do the account. This is the main worker bee
|
300 |
$accounts{$account}{'source'}{'server'} = $server unless exists( $accounts{$account}{'source'}{'server'} );
|
308 |
$accounts->{$account}->{'processed'} = &processAccount( $accounts->{$account} );
|
301 |
$accounts{$account}{'target'}{'server'} = $server unless exists( $accounts{$account}{'target'}{'server'} );
|
- |
|
302 |
$accounts{$account}{'deleteOnSuccess'} = $deleteOnSuccess unless exists $accounts{$account}{'deleteOnSuccess'};
|
- |
|
303 |
$accounts{$account}{'deleteEmptyFolders'} = $deleteEmptyFolders unless exists $accounts{$account}{'deleteEmptyFolders'};
|
- |
|
304 |
if ( exists $accounts{$account}{'ignore'} ) {
|
- |
|
305 |
foreach my $element ( @ignore ) {
|
- |
|
306 |
push $accounts{$account}{'ignore'}, $element;
|
- |
|
307 |
}
|
- |
|
308 |
} else {
|
- |
|
309 |
$accounts{$account}{'ignore'} = \@ignore;
|
- |
|
310 |
}
|
- |
|
311 |
|
- |
|
312 |
if ( exists $accounts{$account}{'source'}{'systemFolders'} ) {
|
- |
|
313 |
foreach my $element ( @systemFolders ) {
|
- |
|
314 |
push $accounts{$account}{'source'}{'systemFolders'}, $element;
|
- |
|
315 |
}
|
- |
|
316 |
} else {
|
- |
|
317 |
$accounts{$account}{'source'}{'systemFolders'} = \@systemFolders;
|
- |
|
318 |
}
|
- |
|
319 |
|
- |
|
320 |
# do the account
|
- |
|
321 |
$accounts{$account}{'processed'} =
|
- |
|
322 |
&processAccount(
|
- |
|
323 |
$accounts{$account}{'source'},
|
- |
|
324 |
$accounts{$account}{'target'},
|
- |
|
325 |
$accounts{$account}{'age'},
|
- |
|
326 |
$accounts{$account}{'ignore'},
|
- |
|
327 |
$accounts{$account}{'deleteOnSuccess'},
|
- |
|
328 |
$accounts{$account}{'deleteEmptyFolders'}
|
- |
|
329 |
);
|
- |
|
330 |
print "Done, $accounts{$account}{'processed'} messages copied\n";
|
309 |
print "Done, $accounts->{$account}->{'processed'} messages copied\n";
|
331 |
$processed{'Accounts'}++;
|
310 |
$processed{'Accounts'}++;
|
332 |
$processed{'Messages'} += $accounts{$account}{'processed'};
|
311 |
$processed{'Messages'} += $accounts->{$account}->{'processed'};
|
333 |
|
- |
|
334 |
} # foreach loop
|
312 |
} # foreach loop
|
335 |
|
313 |
|
336 |
print "$processed{'Accounts'} accounts processed, $processed{'Messages'} messages\n";
|
314 |
print "$processed{'Accounts'} accounts processed, $processed{'Messages'} messages\n";
|
337 |
|
315 |
|
- |
|
316 |
|
338 |
1;
|
317 |
1;
|
339 |
|
318 |
|