Friday, January 30, 2009

Perl script for breaking apart large ICS files for a Zimbra migration

A migration can be really confusing and time-constrained. Since we look at the world through the soda straw of converting calendar data it's easy to sometimes forget there's this whole business of bringing in a new system on (possibly) new hardware, configuring it, provisioning users, training users.... You get the idea.

Sometimes your system is not perfectly tuned and you need to simply get the data in.

Michigan Technical University was having time-outs when trying to load large ICS files into their Zimbra calendars. By large we mean 130,000 to 150,000 lines of iCalendar data.

For a quick fix they produced a Perl script to break the ICS files into smaller chunks. Thanks to Cynthia at MTU we can publish this here for those of you who may need it.

The "splitics.pl" script:
  • Splits large calendar ICS files into smaller parts.

  • Adds a tag (mm) to all meetings.
To run this:
Step 1 - collect the files
Make the ICS files and the zcs script. Some of the ICS files are large.
Put the ics files into a directory, perhaps called "calendar-migration"

Step 2 - Use the splitics.pl script
cd calendar-migration
for i in *.ics; do ../splitics.pl $i; done

Step 3 - create the zcs file to use later
cat *.zcs > /tmp/whole.zcs

Step 4 -
move the "whole.zcs" file to the Zimbra server
suppress resource responses with this command:
zmprov mcr zimbraCalResAutoAcceptDecline FALSE
zmprov -f whole.zcs

Step 5 - undo the suppress responses when ready

NOTE: This script also inserts the tag "mm" to all migrated appointments and meetings.



#!/usr/bin/perl

# for i in *.ics; do ../splitics.pl $i; done

# cat *.zcs > TODO

$base_name=$ARGV[0];

$base_name =~ s/.ics$//;
print "$base_name.zcs\n";

open(ZCS,">$base_name.zcs") die "Couldn't open $base_name.zcs : $!\n";
print ZCS "SelectMailbox $base_name\n";

print ZCS "emptyFolder Calendar\n";
open(ICS,"<$ARGV[0]") die "Couldn't open $ARGV[0] : $!\n"; while () {

last if (/BEGIN:VEVENT/);

$headers .= $_;

}
$event_count=0;

$file_number=1;

$event=$_;

while() {

if (/BEGIN:VEVENT/) { # It's a new event! Yay!

if ($event_count > 50) { # See if we should dump the output

open(OUTPUT,">$ARGV[0].$file_number") die "Couldn't open $ARGV[0].$file_number for output : $!\n";

print OUTPUT $headers;

print OUTPUT $event;

print OUTPUT "END:VCALENDAR\n";

close(OUTPUT);
print ZCS "importURLIntoFolder Calendar http://yourserver/ZIMBRA/USERID/$ARGV[0].$file_number/n";

# print ZCS "postRestURL Calendar $ARGV[0].$file_number\n";

$file_number++;

$event_count=0;

$event="BEGIN:VEVENT\n";

} else { # Just keep adding it on

$event .= $_;

$event_count++;

}

} else { # It's either the end, or it's another line

if (/^SUMMARY:/) { # Tag so we know it's a mm meeting

$_ =~ s/$/ \(MM\)/;

}

$event .= $_;

}

}

# We're at the end of our run... dump what is left over

open(OUTPUT,">$ARGV[0].$file_number") die "Couldn't open $ARGV[0].$file_number for output : $!\n";

print OUTPUT $headers;

print OUTPUT $event;

close(OUTPUT);

#print ZCS "postRestURL Calendar $ARGV[0].$file_number\n";

print ZCS "importURLIntoFolder Calendar http://yourserver/ZIMBRA/USERID/$ARGV[0].$file_number/n";

print ZCS "\n";

close(ZCS);

1 comment:

zyg said...

One university had to make some script changes. They may have just been a perl version difference but here they are:

open(ICS,"<$ARGV[0]") || die "Couldn't open $ARGV[0] : $!\n";

all open statements needed "||" (or) before die

while() changed to while(ICS)

print ZCS "importURLIntoFolder Calendar http://yourserver/ZIMBRA/USERID/$ARGV[0].$file_number/n";

changed ending newline to "\n"