sub check_data() { if ($data_storage_mode == 0 ) # flat text files { if (!(-e "$calendars_file")) {$fatal_error=1;$error_info .= "Calendars file $calendars_file not found!\n";} if (!(-e $new_calendars_file)) {$fatal_error=1;$error_info .= "New calendars file $new_calendars_file not found!\n";} if (!(-e $events_file)) {$fatal_error=1;$error_info .= "Events file $events_file not found!\n";} if ($fatal_error == 0) { if (!(-w $calendars_file)) {$fatal_error=1;$error_info .= "Calendars file $calendars_file is not writable!\n";} if (!(-w $new_calendars_file)) {$fatal_error=1;$error_info .= "New calendars file $new_calendars_file is not writable!\n";} if (!(-w $events_file)) {$fatal_error=1;$error_info .= "Events file $events_file is not writable!\n";} } } elsif ($data_storage_mode == 1 ) # DBI { my $calendars_table_exists=1; my $new_calendars_table_exists=1; my $events_table_exists=1; # if successful, check whether the calendars table exists my $query_string="select * from $calendars_table limit 0"; my $sth = $dbh->prepare($query_string) || ($error_info .= "Can't prepare $statement: $dbh->errstr\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $calendars_table_exists=0; $error_info .= $dbh->errstr."\n";; } $sth->finish(); # check whether the new_calendars table exists my $query_string="select * from $new_calendars_table limit 0"; my $sth = $dbh->prepare($query_string) || ($error_info .= "Can't prepare $statement: $dbh->errstr\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $new_calendars_table_exists=0; $error_info .= $dbh->errstr."\n";; } $sth->finish(); # check whether the events table exists my $query_string="select * from $events_table limit 0"; my $sth = $dbh->prepare($query_string) || ($error_info .= "Can't prepare $statement: $dbh->errstr\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $events_table_exists=0; $error_info .= $dbh->errstr."\n";; } $sth->finish(); if ($events_table_exists + $new_calendars_table_exists + $calendars_table_exists == 3) { # everything's ok } elsif ($events_table_exists + $new_calendars_table_exists + $calendars_table_exists > 0) { $fatal_error = 1; $error_info .= "Ok, this is a serious problem. Some of the required tables exist, but not all.\n Plans can't fix this automatically.\n"; } elsif ($events_table_exists + $new_calendars_table_exists + $calendars_table_exists == 0) { if ($q->param('create_tables') ne "1") { $fatal_error = 1; if ((-e "$calendars_file") && (-e $new_calendars_file) && (-e $events_file)) { $error_info .= <Yes, please create them (but don't import anything) \nYes, please create them, and import all all existing data from $calendars_file, $new_calendars_file, and $events_file. p1 } else { $error_info .= <Yes, please create them p1 } } else # create the tables! { $error_info .= "\nCreating calendar and event tables...\n"; # create the calendars table my $query_string="create table $calendars_table(id int(5),xml_data text,update_timestamp int(15));"; my $sth = $dbh->prepare($query_string) || ($error_info .= "Can't prepare $statement: $dbh->errstr\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "error creating table \"$calendars_table\"!\n".$dbh->errstr."\n"; } $sth->finish(); # create the new calendars table my $query_string="create table $new_calendars_table(id int(5),xml_data text,update_timestamp int(15));"; my $sth = $dbh->prepare($query_string) || ($error_info .= "Can't prepare $statement: $dbh->errstr\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "error creating table \"$new_calendars_table\"!\n".$dbh->errstr."\n"; } $sth->finish(); # create the events table my $query_string="create table $events_table(id int(5),cal_id int(5),start int(15),end int(15),xml_data text,update_timestamp int(15));"; my $sth = $dbh->prepare($query_string) || ($error_info .= "Can't prepare $statement: $dbh->errstr\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "error creating table \"$events_table\"!\n".$dbh->errstr."\n"; } $sth->finish(); # either import existing text data, or create a record for the primary calendar if ($q->param('import_data') ne "1" && $fatal_error != 1) # create primary calendar { $error_info .= "\nAdding primary calendar...\n"; $fatal_error = 0; # data for the primary calendar my %primary_cal = %default_cal; $primary_cal{id}=0; $primary_cal{title}="Main Calendar"; $primary_cal{password}=crypt("12345", substr("12345",0,2)); $primary_cal{details}=<prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "Error adding primary calendar!\n".$dbh->errstr."\n"; $error_info .= "$query_string\n"; } else { $fatal_error = 1; $error_info = < (you shouldn't ever see this message again. To prove it, refresh the page or click here.) p1 } $sth->finish(); } else # import data { $error_info .= "\nImporting data from flat files...\n"; my $temp=$data_storage_mode; $data_storage_mode = 0; &load_calendars(); &load_new_calendars(); &load_events("all"); $data_storage_mode = $temp; my @temp_cal_ids = keys %calendars; &add_calendars(\@temp_cal_ids); my @temp_new_cal_ids = keys %new_calendars; &add_new_calendars(\@temp_new_cal_ids); my @temp_event_ids = keys %events; &add_events(\@temp_event_ids); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "Error adding primary calendar!\n".$dbh->errstr."\n"; $error_info .= "$query_string\n"; } else { $fatal_error = 1; $error_info = < (you shouldn't ever see this message again. To prove it, refresh the page or click here.) p1 } } } } #$dbh->disconnect; } } sub load_calendars { my $max_update_timestamp=0; my $latest_cal_id=0; if ($data_storage_mode == 0 ) # flat text files { open (FH, "$calendars_file") || {$debug_info.= "unable to open file $calendars_file\n"}; flock FH,2; my @calendar_lines=; close FH; # For the calendars, we do "complete" xml parsing (no validation or DTD though) foreach $line (@calendar_lines) { if ($line !~ /\S/) {next;} # ignore blank lines #if ($line =~ /<\/?xml>/) {next;} # ignore and $line =~ s/<\/?calendar>//g; # remove and my ($cal_id) = &xml_quick_extract($line, "id"); my ($cal_title) = &xml_quick_extract($line, "title"); $cal_title = &decode($cal_title); my ($cal_details) = &xml_quick_extract($line, "details"); $cal_details = &decode($cal_details); my ($cal_link) = &xml_quick_extract($line, "link"); $cal_link = &decode($cal_link); my ($cal_password) = &xml_quick_extract($line, "admin_password"); $cal_password = &decode($cal_password); my $update_timestamp=0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); # extract background calendars my @temp = &xml_quick_extract($line, "background_calendar"); my %local_background_calendars; my $num_background_calendars = scalar @temp; foreach $background_calendar (@temp) { my ($type) = &xml_quick_extract($background_calendar, "type"); $type = &decode($type); if ($type eq "plans_local") { my ($id) = &xml_quick_extract($background_calendar, "id"); $local_background_calendars{$id} = 1; } } # extract selectable calendars my %selectable_calendars; @temp = &xml_quick_extract($line, "selectable_calendar"); foreach $selectable_calendar (@temp) { $selectable_calendars{$selectable_calendar} = 1; } my ($list_background_calendars_together) = &xml_quick_extract($line, "list_background_calendars_together"); $list_background_calendars_together = "no" if ($list_background_calendars_together eq ""); my ($background_events_display_style) = &xml_quick_extract($line, "background_events_display_style"); $background_events_display_style = "normal" if ($background_events_display_style eq ""); my ($background_events_fade_factor) = &xml_quick_extract($line, "background_events_fade_factor"); $background_events_fade_factor = 1 if ($background_events_fade_factor eq "" || $background_events_fade_factor < 1); my ($background_events_color) = &xml_quick_extract($line, "background_events_color"); $background_events_color = &decode($background_events_color); $background_events_color = "#ffffff" if ($background_events_color eq ""); my ($default_number_of_months) = &xml_quick_extract($line, "default_number_of_months"); $default_number_of_months = 1 if ($default_number_of_months eq ""); my ($max_number_of_months) = &xml_quick_extract($line, "max_number_of_months"); $max_number_of_months = 24 if ($max_number_of_months eq ""); my ($gmtime_diff) = &xml_quick_extract($line, "gmtime_diff"); $gmtime_diff = 0 if ($gmtime_diff eq ""); my ($date_format) = &xml_quick_extract($line, "date_format"); $date_format = &decode($date_format); $date_format = "mm/dd/yy" if ($date_format eq ""); my ($week_start_day) = &xml_quick_extract($line, "week_start_day"); $week_start_day = "0" if ($week_start_day eq ""); my ($info_window_size) = &xml_quick_extract($line, "info_window_size"); $info_window_size = "400x400" if ($info_window_size eq ""); my ($custom_template) = &xml_quick_extract($line, "custom_template"); $custom_template = &decode($custom_template); my ($custom_stylesheet) = &xml_quick_extract($line, "custom_stylesheet"); $custom_stylesheet = &decode($custom_stylesheet); if ($cal_id > $max_cal_id) { $max_cal_id = $cal_id; } $calendars{$cal_id} = {id => $cal_id, title => $cal_title, details => $cal_details, link => $cal_link, local_background_calendars => \%local_background_calendars, selectable_calendars => \%selectable_calendars, list_background_calendars_together => $list_background_calendars_together, background_events_display_style => $background_events_display_style, background_events_fade_factor => $background_events_fade_factor, background_events_color => $background_events_color, default_number_of_months => $default_number_of_months, max_number_of_months => $max_number_of_months, gmtime_diff => $gmtime_diff, date_format => $date_format, week_start_day => $week_start_day, info_window_size => $info_window_size, custom_template => $custom_template, custom_stylesheet => $custom_stylesheet, password => $cal_password, update_timestamp => $update_timestamp}; #the calendar with id 0 is assumed to be the master calendar. #its password can be used to approve/edit/delete any event #for any calendar if ($cal_id eq "0") {$master_password = $cal_password;} if ($cal_id eq "$in{cal_id}") {$current_cal_title =$cal_title;} if ($update_timestamp > $max_update_timestamp) { $max_update_timestamp = $update_timestamp; $latest_cal_id = $cal_id; } } %latest_cal = %{$calendars{$latest_cal_id}}; } elsif ($data_storage_mode == 1 ) # SQL database { my $query_string="select * from $calendars_table;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error loading calendars!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } while(@row = $sth->fetchrow_array) { my $cal_id = $row[0]; my $line = $row[1]; #$debug_info .= "cal id: $cal_id\n"; my ($cal_title) = &xml_quick_extract($line, "title"); $cal_title = &decode($cal_title); my ($cal_details) = &xml_quick_extract($line, "details"); $cal_details = &decode($cal_details); my ($cal_link) = &xml_quick_extract($line, "link"); $cal_link = &decode($cal_link); my ($cal_password) = &xml_quick_extract($line, "admin_password"); $cal_password = &decode($cal_password); my $update_timestamp=0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); # extract background calendars my @temp = &xml_quick_extract($line, "background_calendar"); my %local_background_calendars; my $num_background_calendars = scalar @temp; foreach $background_calendar (@temp) { my ($type) = &xml_quick_extract($background_calendar, "type"); $type = &decode($type); if ($type eq "plans_local") { my ($id) = &xml_quick_extract($background_calendar, "id"); $local_background_calendars{$id} = 1; } } # extract selectable calendars my %selectable_calendars; @temp = &xml_quick_extract($line, "selectable_calendar"); foreach $selectable_calendar (@temp) { $selectable_calendars{$selectable_calendar} = 1; } my ($list_background_calendars_together) = &xml_quick_extract($line, "list_background_calendars_together"); $list_background_calendars_together = "no" if ($list_background_calendars_together eq ""); my ($background_events_display_style) = &xml_quick_extract($line, "background_events_display_style"); $background_events_display_style = "normal" if ($background_events_display_style eq ""); my ($background_events_fade_factor) = &xml_quick_extract($line, "background_events_fade_factor"); $background_events_fade_factor = 1 if ($background_events_fade_factor eq "" || $background_events_fade_factor < 1); my ($background_events_color) = &xml_quick_extract($line, "background_events_color"); $background_events_color = &decode($background_events_color); $background_events_color = "#ffffff" if ($background_events_color eq ""); my ($default_number_of_months) = &xml_quick_extract($line, "default_number_of_months"); $default_number_of_months = 1 if ($default_number_of_months eq ""); my ($max_number_of_months) = &xml_quick_extract($line, "max_number_of_months"); $max_number_of_months = 24 if ($max_number_of_months eq ""); my ($gmtime_diff) = &xml_quick_extract($line, "gmtime_diff"); $gmtime_diff = 0 if ($gmtime_diff eq ""); my ($date_format) = &xml_quick_extract($line, "date_format"); $date_format = &decode($date_format); $date_format = "mm/dd/yy" if ($date_format eq ""); my ($week_start_day) = &xml_quick_extract($line, "week_start_day"); $week_start_day = "0" if ($week_start_day eq ""); my ($info_window_size) = &xml_quick_extract($line, "info_window_size"); $info_window_size = "400x400" if ($info_window_size eq ""); my ($custom_template) = &xml_quick_extract($line, "custom_template"); $custom_template = &decode($custom_template); my ($custom_stylesheet) = &xml_quick_extract($line, "custom_stylesheet"); $custom_stylesheet = &decode($custom_stylesheet); if ($cal_id > $max_cal_id) { $max_cal_id = $cal_id; } $calendars{$cal_id} = {id => $cal_id, title => $cal_title, details => $cal_details, link => $cal_link, local_background_calendars => \%local_background_calendars, selectable_calendars => \%selectable_calendars, list_background_calendars_together => $list_background_calendars_together, background_events_display_style => $background_events_display_style, background_events_fade_factor => $background_events_fade_factor, background_events_color => $background_events_color, default_number_of_months => $default_number_of_months, max_number_of_months => $max_number_of_months, gmtime_diff => $gmtime_diff, date_format => $date_format, week_start_day => $week_start_day, info_window_size => $info_window_size, custom_template => $custom_template, custom_stylesheet => $custom_stylesheet, password => $cal_password, update_timestamp => $update_timestamp}; #the calendar with id 0 is assumed to be the master calendar. #its password can be used to approve/edit/delete any event #for any calendar if ($cal_id eq "0") {$master_password = $cal_password;} if ($cal_id eq "$in{cal_id}") {$current_cal_title =$cal_title;} if ($update_timestamp > $max_update_timestamp) { $max_update_timestamp = $update_timestamp; $latest_cal_id = $cal_id; } } %latest_cal = %{$calendars{$latest_cal_id}}; $sth->finish(); } } sub load_new_calendars() { my $latest_new_cal_id=0; my $max_update_timestamp=0; if ($data_storage_mode == 0 ) # flat text files { open (FH, "$new_calendars_file") || {$debug_info.= "unable to open file $new_calendars_file\n"}; flock FH,2; my @calendar_lines=; close FH; # For the calendars, we do "complete" xml parsing (no validation or DTD though) foreach $line (@calendar_lines) { if ($line !~ /\S/) {next;} # ignore blank lines $line =~ s/<\/?calendar>//g; # remove and # extract calendar data. my ($cal_id) = &xml_quick_extract($line, "id"); my ($cal_title) = &xml_quick_extract($line, "title"); $cal_title = &decode($cal_title); my ($cal_details) = &xml_quick_extract($line, "details"); $cal_details = &decode($cal_details); my ($cal_link) = &xml_quick_extract($line, "link"); $cal_link = &decode($cal_link); my ($cal_password) = &xml_quick_extract($line, "admin_password"); $cal_password = &decode($cal_password); my ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); my @temp = &xml_quick_extract($line, "background_calendar"); my %local_background_calendars; my $num_background_calendars = scalar @temp; foreach $background_calendar (@temp) { my ($type) = &xml_quick_extract($background_calendar, "type"); $type = &decode($type); if ($type eq "plans_local") { my ($id) = &xml_quick_extract($background_calendar, "id"); $local_background_calendars{$id} = 1; } } # extract selectable calendars my %selectable_calendars; @temp = &xml_quick_extract($line, "selectable_calendar"); foreach $selectable_calendar (@temp) {$selectable_calendars{$selectable_calendar} = 1;} my ($list_background_calendars_together) = &xml_quick_extract($line, "list_background_calendars_together"); $list_background_calendars_together = "no" if ($list_background_calendars_together eq ""); my ($background_events_display_style) = &xml_quick_extract($line, "background_events_display_style"); $background_events_display_style = "normal" if ($background_events_display_style eq ""); my ($background_events_fade_factor) = &xml_quick_extract($line, "background_events_fade_factor"); $background_events_fade_factor = 1 if ($background_events_fade_factor eq "" || $background_events_fade_factor < 1); my ($background_events_color) = &xml_quick_extract($line, "background_events_color"); $background_events_color = $temp->{data}; my ($default_number_of_months) = &xml_quick_extract($line, "default_number_of_months"); $default_number_of_months = 1 if ($default_number_of_months eq ""); my ($max_number_of_months) = &xml_quick_extract($line, "max_number_of_months"); $max_number_of_months = 24 if ($max_number_of_months eq ""); my ($gmtime_diff) = &xml_quick_extract($line, "gmtime_diff"); $gmtime_diff = 0 if ($gmtime_diff eq ""); my ($date_format) = &xml_quick_extract($line, "date_format"); $date_format = &decode($date_format); $date_format = "mm/dd/yy" if ($date_format eq ""); my ($week_start_day) = &xml_quick_extract($line, "week_start_day"); $week_start_day = "0" if ($week_start_day eq ""); my ($info_window_size) = &xml_quick_extract($line, "info_window_size"); $info_window_size = "400x400" if ($info_window_size eq ""); my ($custom_template) = &xml_quick_extract($line, "custom_template"); $custom_template = &decode($custom_template); my ($custom_stylesheet) = &xml_quick_extract($line, "custom_stylesheet"); $custom_stylesheet = &decode($custom_stylesheet); if ($cal_id > $max_new_cal_id) { $max_new_cal_id = $cal_id; } $new_calendars{$cal_id} = {id => $cal_id, title => $cal_title, details => $cal_details, link => $cal_link, local_background_calendars => \%local_background_calendars, selectable_calendars => \%selectable_calendars, list_background_calendars_together => $list_background_calendars_together, background_events_display_style => $background_events_display_style, background_events_fade_factor => $background_events_fade_factor, background_events_color => $background_events_color, default_number_of_months => $default_number_of_months, max_number_of_months => $max_number_of_months, gmtime_diff => $gmtime_diff, date_format => $date_format, week_start_day => $week_start_day, info_window_size => $info_window_size, custom_template => $custom_template, custom_stylesheet => $custom_stylesheet, password => $cal_password, update_timestamp => $update_timestamp}; if ($update_timestamp > $max_update_timestamp) { $max_update_timestamp = $update_timestamp; $latest_new_cal_id = $cal_id; } } %latest_new_cal = %{$new_calendars{$latest_new_cal_id}}; } elsif ($data_storage_mode == 1 ) # SQL database { my $query_string="select * from $new_calendars_table;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error loading new calendars!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } while(@row = $sth->fetchrow_array) { my $cal_id = $row[0]; my $line = $row[1]; #$debug_info .= "cal id: $cal_id\n"; my ($cal_title) = &xml_quick_extract($line, "title"); $cal_title = &decode($cal_title); my ($cal_details) = &xml_quick_extract($line, "details"); $cal_details = &decode($cal_details); my ($cal_link) = &xml_quick_extract($line, "link"); $cal_link = &decode($cal_link); my ($cal_password) = &xml_quick_extract($line, "admin_password"); $cal_password = &decode($cal_password); my $update_timestamp=0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); # extract background calendars my @temp = &xml_quick_extract($line, "background_calendar"); my %local_background_calendars; my $num_background_calendars = scalar @temp; foreach $background_calendar (@temp) { my ($type) = &xml_quick_extract($background_calendar, "type"); $type = &decode($type); if ($type eq "plans_local") { my ($id) = &xml_quick_extract($background_calendar, "id"); $local_background_calendars{$id} = 1; } } # extract selectable calendars my %selectable_calendars; @temp = &xml_quick_extract($line, "selectable_calendar"); foreach $selectable_calendar (@temp) { $selectable_calendars{$selectable_calendar} = 1; } my ($list_background_calendars_together) = &xml_quick_extract($line, "list_background_calendars_together"); $list_background_calendars_together = "no" if ($list_background_calendars_together eq ""); my ($background_events_display_style) = &xml_quick_extract($line, "background_events_display_style"); $background_events_display_style = "normal" if ($background_events_display_style eq ""); my ($background_events_fade_factor) = &xml_quick_extract($line, "background_events_fade_factor"); $background_events_fade_factor = 1 if ($background_events_fade_factor eq "" || $background_events_fade_factor < 1); my ($background_events_color) = &xml_quick_extract($line, "background_events_color"); $background_events_color = &decode($background_events_color); $background_events_color = "#ffffff" if ($background_events_color eq ""); my ($default_number_of_months) = &xml_quick_extract($line, "default_number_of_months"); $default_number_of_months = 1 if ($default_number_of_months eq ""); my ($max_number_of_months) = &xml_quick_extract($line, "max_number_of_months"); $max_number_of_months = 24 if ($max_number_of_months eq ""); my ($gmtime_diff) = &xml_quick_extract($line, "gmtime_diff"); $gmtime_diff = 0 if ($gmtime_diff eq ""); my ($date_format) = &xml_quick_extract($line, "date_format"); $date_format = &decode($date_format); $date_format = "mm/dd/yy" if ($date_format eq ""); my ($week_start_day) = &xml_quick_extract($line, "week_start_day"); $week_start_day = "0" if ($week_start_day eq ""); my ($info_window_size) = &xml_quick_extract($line, "info_window_size"); $info_window_size = "400x400" if ($info_window_size eq ""); my ($custom_template) = &xml_quick_extract($line, "custom_template"); $custom_template = &decode($custom_template); my ($custom_stylesheet) = &xml_quick_extract($line, "custom_stylesheet"); $custom_stylesheet = &decode($custom_stylesheet); if ($cal_id > $max_cal_id) { $max_new_cal_id = $cal_id; } $new_calendars{$cal_id} = {id => $cal_id, title => $cal_title, details => $cal_details, link => $cal_link, local_background_calendars => \%local_background_calendars, selectable_calendars => \%selectable_calendars, list_background_calendars_together => $list_background_calendars_together, background_events_display_style => $background_events_display_style, background_events_fade_factor => $background_events_fade_factor, background_events_color => $background_events_color, default_number_of_months => $default_number_of_months, max_number_of_months => $max_number_of_months, gmtime_diff => $gmtime_diff, date_format => $date_format, week_start_day => $week_start_day, info_window_size => $info_window_size, custom_template => $custom_template, custom_stylesheet => $custom_stylesheet, password => $cal_password, update_timestamp => $update_timestamp}; if ($update_timestamp > $max_update_timestamp) { $max_update_timestamp = $update_timestamp; $latest_new_cal_id = $cal_id; } } $sth->finish(); } %latest_new_cal = %{$new_calendars{$latest_new_cal_id}}; } sub load_events() { # load events for a given number of calendars, within a given time range. my ($start, $end, $temp) = @_; my @calendar_ids = @{$temp}; #$debug_info .="start: $start\n"; #$debug_info .="end: $end\n"; if ($data_storage_mode == 0 ) # flat text files { open (FH, "$events_file") || {$debug_info.= "unable to open file $events_file\n"}; flock FH,2; my @event_lines=; close FH; my $max_update_timestamp = 0; my $latest_event_id = 0; my $event_loaded_count = 0; foreach $line (@event_lines) { my $temp_line = substr($line,0,120); # grab first 180 characters $temp_line =~ s///; # remove $temp_line =~ /(\d+)/; my $evt_id = $1; $temp_line =~ /(\d+)/; my $temp_cal_id = $1; $temp_line =~ /(\d+)/; my $temp_start_timestamp = $1; $temp_line =~ /(\d+)/; my $temp_end_timestamp = $1; my $cal_valid=0; foreach $cal_id (@calendar_ids) { if ($temp_cal_id == $cal_id) {$cal_valid=1;} } if ($cal_valid == 0 && $start ne "all") {next;} # event on some other calendar that we don't care about if ($temp_end_timestamp < $start && $start ne "all") {next;} # in the past if ($temp_start_timestamp > $end && $start ne "all") {next;} # in the future $event_loaded_count++; $line =~ s/<\/?event>//g; # remove and #my ($evt_id) = &xml_quick_extract($line, "id"); my ($cal_id) = &xml_quick_extract($line, "cal_id"); $cal_id = &decode($cal_id); my ($evt_start) = &xml_quick_extract($line, "start"); #$evt_start = &decode($evt_start); my ($evt_end) = &xml_quick_extract($line, "end"); my ($evt_title) = &xml_quick_extract($line, "title"); $evt_title = &decode($evt_title); my ($evt_details) = &xml_quick_extract($line, "details"); $evt_details = &decode($evt_details); my ($evt_icon) = &xml_quick_extract($line, "icon"); $evt_icon = &decode($evt_icon); my ($evt_bgcolor) = &xml_quick_extract($line, "bgcolor"); $evt_bgcolor = &decode($evt_bgcolor); my ($evt_unit_number) = &xml_quick_extract($line, "unit_number"); $evt_unit_number = &decode($evt_unit_number); my $update_timestamp = 0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); my $evt_days = int(($evt_end - $evt_start)/86400)+1; $events{$evt_id} = {id => $evt_id, cal_id => $cal_id, start => $evt_start, end => $evt_end, days => $evt_days, title => $evt_title, details => $evt_details, icon => $evt_icon, bgcolor => $evt_bgcolor, unit_number => $evt_unit_number, update_timestamp => $update_timestamp}; if ($evt_id > $max_event_id) {$max_event_id = $evt_id;} if ($update_timestamp > $max_update_timestamp) { $max_update_timestamp = $update_timestamp; $latest_event_id = $evt_id; } } #$debug_info .= "$event_loaded_count events total.\n"; #$debug_info .= "loaded event $evt_id\n"; %latest_event = %{$events{$latest_event_id}}; } elsif ($data_storage_mode == 1 ) # SQL database { my $query_string; if ($start eq "all") { $query_string="select * from $events_table;"; } else { $query_string="select * from $events_table where (start > $start and end < $end )"; if ($calendar_ids[0] ne "" && $calendar_ids[0] !~ /\D/) { $query_string .= " and ( cal_id=$calendar_ids[0]"; for ($l1=1;$l1prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error loading events!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } while(@row = $sth->fetchrow_array) { my $evt_id = $row[0]; my $temp_cal_id = $row[1]; #my $temp_start_timestamp = $row[2]; #$temp_line =~ /(\d+)/; #my $temp_end_timestamp = $row[3]; my $cal_valid=0; foreach $cal_id (@calendar_ids) { if ($temp_cal_id == $cal_id) {$cal_valid=1;} } my $line = $row[4]; $line =~ s/<\/?event>//g; # remove and #my ($evt_id) = &xml_quick_extract($line, "id"); my ($cal_id) = &xml_quick_extract($line, "cal_id"); $cal_id = &decode($cal_id); my ($evt_start) = &xml_quick_extract($line, "start"); #$evt_start = &decode($evt_start); my ($evt_end) = &xml_quick_extract($line, "end"); my ($evt_title) = &xml_quick_extract($line, "title"); $evt_title = &decode($evt_title); my ($evt_details) = &xml_quick_extract($line, "details"); $evt_details = &decode($evt_details); my ($evt_icon) = &xml_quick_extract($line, "icon"); $evt_icon = &decode($evt_icon); my ($evt_bgcolor) = &xml_quick_extract($line, "bgcolor"); $evt_bgcolor = &decode($evt_bgcolor); my ($evt_unit_number) = &xml_quick_extract($line, "unit_number"); $evt_unit_number = &decode($evt_unit_number); my $update_timestamp = 0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); my $evt_days = int(($evt_end - $evt_start)/86400)+1; $events{$evt_id} = {id => $evt_id, cal_id => $cal_id, start => $evt_start, end => $evt_end, days => $evt_days, title => $evt_title, details => $evt_details, icon => $evt_icon, bgcolor => $evt_bgcolor, unit_number => $evt_unit_number, update_timestamp => $update_timestamp}; } # get max event id my $query_string="select max(id) from $events_table;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "$dbh->errstr\n"; $debug_info .= "query string:\n$query_string\n"; } $max_event_id = $sth->fetchrow_array; # get latest event my $query_string="select * from $events_table order by update_timestamp desc limit 0, 1;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "$dbh->errstr\n"; $debug_info .= "query string:\n$query_string\n"; } while(@row = $sth->fetchrow_array) { my $evt_id = $row[0]; my $temp_cal_id = $row[1]; my $line = $row[4]; $line =~ s/<\/?event>//g; # remove and my ($cal_id) = &xml_quick_extract($line, "cal_id"); $cal_id = &decode($cal_id); my ($evt_start) = &xml_quick_extract($line, "start"); my ($evt_end) = &xml_quick_extract($line, "end"); my ($evt_title) = &xml_quick_extract($line, "title"); $evt_title = &decode($evt_title); my ($evt_details) = &xml_quick_extract($line, "details"); $evt_details = &decode($evt_details); my ($evt_icon) = &xml_quick_extract($line, "icon"); $evt_icon = &decode($evt_icon); my ($evt_bgcolor) = &xml_quick_extract($line, "bgcolor"); $evt_bgcolor = &decode($evt_bgcolor); my ($evt_unit_number) = &xml_quick_extract($line, "unit_number"); $evt_unit_number = &decode($evt_unit_number); my $update_timestamp = 0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); my $evt_days = int(($evt_end - $evt_start)/86400)+1; $latest_event_id = $evt_id; %latest_event = (id => $evt_id, cal_id => $cal_id, start => $evt_start, end => $evt_end, days => $evt_days, title => $evt_title, details => $evt_details, icon => $evt_icon, bgcolor => $evt_bgcolor, unit_number => $evt_unit_number, update_timestamp => $update_timestamp); } } } sub load_event() { # load events for a given number of calendars, within a given time range. my ($event_id) = @_; if ($data_storage_mode == 0 ) # flat text files { open (FH, "$events_file") || {$debug_info.= "unable to open file $events_file\n"}; flock FH,2; my @event_lines=; close FH; my $max_update_timestamp = 0; my $latest_event_id = 0; my $event_loaded_count = 0; foreach $line (@event_lines) { my $temp_line = substr($line,0,120); # grab first 180 characters $temp_line =~ s///; # remove $temp_line =~ /(\d+)/; my $evt_id = $1; if ($evt_id != $event_id) {next;} # event on some other calendar that we don't care about $line =~ s/<\/?event>//g; # remove and #my ($evt_id) = &xml_quick_extract($line, "id"); my ($cal_id) = &xml_quick_extract($line, "cal_id"); $cal_id = &decode($cal_id); my ($evt_start) = &xml_quick_extract($line, "start"); #$evt_start = &decode($evt_start); my ($evt_end) = &xml_quick_extract($line, "end"); my ($evt_title) = &xml_quick_extract($line, "title"); $evt_title = &decode($evt_title); my ($evt_details) = &xml_quick_extract($line, "details"); $evt_details = &decode($evt_details); my ($evt_icon) = &xml_quick_extract($line, "icon"); $evt_icon = &decode($evt_icon); my ($evt_bgcolor) = &xml_quick_extract($line, "bgcolor"); $evt_bgcolor = &decode($evt_bgcolor); my ($evt_unit_number) = &xml_quick_extract($line, "unit_number"); $evt_unit_number = &decode($evt_unit_number); my $update_timestamp = 0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); my $evt_days = int(($evt_end - $evt_start)/86400)+1; $events{$evt_id} = {id => $evt_id, cal_id => $cal_id, start => $evt_start, end => $evt_end, days => $evt_days, title => $evt_title, details => $evt_details, icon => $evt_icon, bgcolor => $evt_bgcolor, unit_number => $evt_unit_number, update_timestamp => $update_timestamp}; if ($evt_id > $max_event_id) {$max_event_id = $evt_id;} if ($update_timestamp > $max_update_timestamp) { $max_update_timestamp = $update_timestamp; $latest_event_id = $evt_id; } } } elsif ($data_storage_mode == 1 ) # SQL database { my $query_string; $query_string="select * from $events_table where (id = $event_id);"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error loading events!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } while(@row = $sth->fetchrow_array) { my $evt_id = $row[0]; my $temp_cal_id = $row[1]; my $line = $row[4]; $line =~ s/<\/?event>//g; # remove and my ($cal_id) = &xml_quick_extract($line, "cal_id"); $cal_id = &decode($cal_id); my ($evt_start) = &xml_quick_extract($line, "start"); my ($evt_end) = &xml_quick_extract($line, "end"); my ($evt_title) = &xml_quick_extract($line, "title"); $evt_title = &decode($evt_title); my ($evt_details) = &xml_quick_extract($line, "details"); $evt_details = &decode($evt_details); my ($evt_icon) = &xml_quick_extract($line, "icon"); $evt_icon = &decode($evt_icon); my ($evt_bgcolor) = &xml_quick_extract($line, "bgcolor"); $evt_bgcolor = &decode($evt_bgcolor); my ($evt_unit_number) = &xml_quick_extract($line, "unit_number"); $evt_unit_number = &decode($evt_unit_number); my $update_timestamp = 0; ($update_timestamp) = &xml_quick_extract($line, "update_timestamp"); $update_timestamp = 0 if ($update_timestamp eq ""); my $evt_days = int(($evt_end - $evt_start)/86400)+1; $events{$evt_id} = {id => $evt_id, cal_id => $cal_id, start => $evt_start, end => $evt_end, days => $evt_days, title => $evt_title, details => $evt_details, icon => $evt_icon, bgcolor => $evt_bgcolor, unit_number => $evt_unit_number, update_timestamp => $update_timestamp}; } } } # add an event to the data file sub add_event() { my ($event_id) = @_; # temporary copy of the event in question my %temp_event = %{$events{$event_id}}; if ($data_storage_mode == 0 ) # flat text files { my $out_text=""; my $event_xml .= &event2xml($events{$event_id})."\n"; $event_xml =~ s/()\d*(<\/update_timestamp>)/$1$rightnow$2/; open (FH, ">>$events_file") || {$debug_info .= "unable to open file $events_file for writing!\n"}; flock FH,2; print FH $event_xml; close FH; } elsif ($data_storage_mode == 1 ) # DBI { my $event_xml = &event2xml(\%temp_event); my $query_string="insert into $events_table (id, cal_id, start, end, xml_data, update_timestamp) values ($temp_event{id}, $temp_event{cal_id}, $temp_event{start}, $temp_event{end}, '$event_xml', $temp_event{update_timestamp});"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $debug_info .= "Error adding event!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } $sth->finish(); } } # add multiple events to the data file sub add_events() { my ($event_ids_ref) = @_; my @event_ids = @{$event_ids_ref}; if ($data_storage_mode == 0 ) # flat text files { my $out_text=""; foreach $id (sort {$a <=> $b} @event_ids) { $out_text .= &event2xml($events{$id})."\n"; } open (FH, ">>$events_file") || {$debug_info .= "unable to open file $events_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { foreach $id (@event_ids) { my %temp_event = %{$events{$id}}; my $event_xml = &event2xml(\%temp_event); my $query_string="insert into $events_table (id, cal_id, start, end, xml_data, update_timestamp) values ($temp_event{id}, $temp_event{cal_id}, $temp_event{start}, $temp_event{end}, '$event_xml', $temp_event{update_timestamp});"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $debug_info .= "Error adding event!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } $sth->finish(); } } } # update an event (already present in the data file) sub update_event() { my ($event_id) = @_; # temporary copy of the event in question my %temp_event = %{$events{$event_id}}; if ($data_storage_mode == 0 ) # flat text files { my $out_text=""; foreach $id (sort {$a <=> $b} keys %events) { my $event_xml = &event2xml($events{$id})."\n"; $out_text .= $event_xml; #if ($id eq $event_id) # {$event_xml =~ s/()\d*(<\/update_timestamp>)/$1$rightnow$2/;} } open (FH, ">$events_file") || {$debug_info .= "unable to open file $events_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { my $event_xml = &event2xml(\%temp_event); my $query_string="update $events_table set cal_id=$temp_event{cal_id}, start=$temp_event{start}, end=$temp_event{end}, xml_data='$event_xml', update_timestamp=$temp_event{update_timestamp} where id=$temp_event{id};"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $debug_info .= "Error updating event!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } $sth->finish(); } } # delete an event sub delete_event() { my ($event_id) = @_; if ($data_storage_mode == 0 ) # flat text files { delete $events{$event_id}; my $out_text=""; foreach $id (sort {$a <=> $b} keys%events) {$out_text .= &event2xml($events{$id})."\n";} open (FH, ">$events_file") || {$debug_info .= "unable to open file $events_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { my $query_string="delete from $events_table where id=$event_id;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $debug_info .= "Error delteing event!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } $sth->finish(); } } # delete multiple events sub delete_events() { my ($event_ids_ref) = @_; my @event_ids = @{$event_ids_ref}; if ($data_storage_mode == 0 ) # flat text files { foreach $event_id (@event_ids) {delete $events{$event_id};} delete $events{$event_id}; my $out_text=""; foreach $id (sort {$a <=> $b} keys%events) {$out_text .= &event2xml($events{$id})."\n";} open (FH, ">$events_file") || {$debug_info .= "unable to open file $events_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { foreach $event_id (@event_ids) { my $query_string="delete from $events_table where id=$event_id;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $debug_info .= "Error deleting event!\n".$dbh->errstr."\n"; $debug_info .= "query string:\n$query_string\n"; } $sth->finish(); } } } sub add_new_calendar() { my ($cal_id) = @_; #$debug_info .= "adding new calendar $cal_id\n"; if ($data_storage_mode == 0 ) # flat text files { # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $id (sort {$a <=> $b} keys %new_calendars) { #$debug_info .= "calendar2xml $id\n"; my $cal_xml = &calendar2xml($new_calendars{$id})."\n"; #if ($id eq $cal_id) # {$cal_xml =~ s/()\d*(<\/update_timestamp>)/$1$rightnow$2/;} $out_text .= $cal_xml; } open (FH, ">$new_calendars_file") || {$debug_info.= "unable to open file $new_calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { my $cal_xml = &calendar2xml($new_calendars{$cal_id})."\n"; # add the primary calendar to the table my $query_string="insert into $new_calendars_table (id, xml_data, update_timestamp) values ($cal_id, '$cal_xml', $new_calendars{$cal_id}{update_timestamp});"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "Error adding new calendar!\n".$dbh->errstr."\n"; $error_info .= "$query_string\n"; } } } sub add_new_calendars() # add multiple calendars (this is used for data conversion) { my ($add_new_cal_ids_ref) = @_; my @add_new_cal_ids = @{$add_new_cal_ids_ref}; if ($data_storage_mode == 0 ) # flat text files { } elsif ($data_storage_mode == 1 ) # DBI { foreach $new_cal_id (@add_new_cal_ids) { my $new_cal_xml = &calendar2xml($new_calendars{$new_cal_id}); my $query_string="insert into $calendars_table (id, xml_data, update_timestamp) values ($new_cal_id, '$new_cal_xml', $new_calendars{$new_cal_id}{update_timestamp});"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error adding new calendar!\n".$dbh->errstr."\n"; $debug_info .= "$query_string\n"; } } } } sub update_new_calendars() # this is called after a record is trandferred from new_calendars to calendars { my ($temp1, $temp2) = @_; my @pending_calendars_to_delete = @{$temp1}; my @calendars_to_add = @{$temp2}; if ($data_storage_mode == 0 ) # flat text files { # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $calendar_id (sort {$a <=> $b} keys %new_calendars) { $out_text .= &calendar2xml($new_calendars{$calendar_id})."\n"; } open (FH, ">$new_calendars_file") || {$html_output.= "unable to open file $new_calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $calendar_id (sort {$a <=> $b} keys %calendars) { $out_text .= &calendar2xml($calendars{$calendar_id})."\n"; } open (FH, ">$calendars_file") || {$html_output.= "unable to open file $calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { foreach $cal_id (@calendars_to_add) { my $cal_xml = &calendar2xml($calendars{$cal_id}); my $query_string="insert into $calendars_table (id, xml_data, update_timestamp) values ($cal_id, '$cal_xml', $calendars{$cal_id}{update_timestamp});"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error approving new calendar!\n".$dbh->errstr."\n"; $debug_info .= "$query_string\n"; } } foreach $cal_id (@pending_calendars_to_delete) { my $query_string="delete from $new_calendars_table where id=$cal_id;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error deleting pending calendar after approval!\n".$dbh->errstr."\n"; $debug_info .= "$query_string\n"; } } } } sub add_calendars() # add multiple calendars (this is used for data conversion) { my ($add_cal_ids_ref) = @_; my @add_cal_ids = @{$add_cal_ids_ref}; if ($data_storage_mode == 0 ) # flat text files { my $out_text=""; # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $calendar_id (sort {$a <=> $b} keys %calendars) { my $cal_xml = &calendar2xml($calendars{$calendar_id})."\n"; $out_text .= $cal_xml; } open (FH, ">$calendars_file") || {$debug_info.= "unable to open file $calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { foreach $cal_id (@add_cal_ids) { my $cal_xml = &calendar2xml($calendars{$cal_id}); my $query_string="insert into $calendars_table (id, xml_data, update_timestamp) values ($cal_id, '$cal_xml', $calendars{$cal_id}{update_timestamp});"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error adding calendar!\n".$dbh->errstr."\n"; $debug_info .= "$query_string\n"; } } } } sub update_calendar() { my ($cal_id) = @_; if ($data_storage_mode == 0 ) # flat text files { my $out_text=""; # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $calendar_id (sort {$a <=> $b} keys %calendars) { my $cal_xml = &calendar2xml($calendars{$calendar_id})."\n"; $out_text .= $cal_xml; } open (FH, ">$calendars_file") || {$debug_info.= "unable to open file $calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { my $cal_xml = &calendar2xml($calendars{$cal_id}); # add the primary calendar to the table my $query_string="update $calendars_table set xml_data='$cal_xml', update_timestamp=$calendars{$cal_id}{update_timestamp} where id=$cal_id;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $fatal_error = 1; $error_info .= "Error updating calendar!\n".$dbh->errstr."\n"; $error_info .= "$query_string\n"; } } } sub update_calendars() # update multiple calendars { my ($update_cal_ids_ref) = @_; my @update_cal_ids = @{$update_cal_ids_ref}; if ($data_storage_mode == 0 ) # flat text files { my $out_text=""; # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $calendar_id (sort {$a <=> $b} keys %calendars) { my $cal_xml = &calendar2xml($calendars{$calendar_id})."\n"; #foreach $update_cal_id (@update_cal_ids) #{ # if ($update_cal_id eq $calendar_id) # {$cal_xml =~ s/()\d*(<\/update_timestamp>)/$1$rightnow$2/;} #} $out_text .= $cal_xml; } open (FH, ">$calendars_file") || {$debug_info.= "unable to open file $calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { foreach $cal_id (@update_cal_ids) { my $cal_xml = &calendar2xml($calendars{$cal_id}); my $query_string="update $calendars_table set xml_data='$cal_xml', update_timestamp=$calendars{$cal_id}{update_timestamp} where id=$cal_id;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error updating calendar!\n".$dbh->errstr."\n"; $debug_info .= "$query_string\n"; } } } } sub delete_calendar() { my ($cal_id) = @_; delete $calendars{$cal_id}; if ($data_storage_mode == 0 ) # flat text files { my $out_text =""; # write out the entire file! Grossly inefficient, but that's how it goes if you don't use a DB. foreach $calendar_id (sort {$a <=> $b} keys %calendars) { my $cal_xml = &calendar2xml($calendars{$calendar_id})."\n"; $out_text .= $cal_xml; } open (FH, ">$calendars_file") || {$debug_info.= "unable to open file $calendars_file for writing!\n"}; flock FH,2; print FH $out_text; close FH; } elsif ($data_storage_mode == 1 ) # DBI { my $query_string="delete from $calendars_table where id=$cal_id;"; my $sth = $dbh->prepare($query_string) or ($error_info .= "Can't prepare $query_string:\n"); my $rv = $sth->execute(); if ($dbh->errstr ne "") { $debug_info .= "Error deleting calendar!\n".$dbh->errstr."\n"; $debug_info .= "$query_string\n"; } } } sub calendar2xml() { my ($calendar_ref) = @_; my %calendar = %{$calendar_ref}; #$error_info .= "Calendar title: $calendar{title}\n"; my $xml_data = ""; $xml_data .= &xml_store($calendar{id}, "id"); $xml_data .= &xml_store($calendar{title}, "title"); $xml_data .= &xml_store($calendar{details}, "details"); $xml_data .= &xml_store($calendar{link}, "link"); $xml_data .= &xml_store($calendar{password}, "admin_password"); # add local background calendars foreach $local_background_calendar (sort {$a <=> $b} keys %{$calendar{local_background_calendars}}) {$xml_data .= "plans_local$local_background_calendar";} # add selectable calendars foreach $selectable_calendar (sort {$a <=> $b} keys %{$calendar{selectable_calendars}}) {$xml_data .= "$selectable_calendar";} # add other fields $xml_data .= &xml_store($calendar{list_background_calendars_together}, "list_background_calendars_together"); $xml_data .= &xml_store($calendar{background_events_display_style}, "background_events_display_style"); $xml_data .= &xml_store($calendar{background_events_fade_factor}, "background_events_fade_factor"); $xml_data .= &xml_store($calendar{background_events_color}, "background_events_color"); $xml_data .= &xml_store($calendar{default_number_of_months}, "default_number_of_months"); $xml_data .= &xml_store($calendar{max_number_of_months}, "max_number_of_months"); $xml_data .= &xml_store($calendar{gmtime_diff}, "gmtime_diff"); $xml_data .= &xml_store($calendar{date_format}, "date_format"); $xml_data .= &xml_store($calendar{week_start_day}, "week_start_day"); $xml_data .= &xml_store($calendar{info_window_size}, "info_window_size"); $xml_data .= &xml_store($calendar{custom_template}, "custom_template"); $xml_data .= &xml_store($calendar{custom_stylesheet}, "custom_stylesheet"); $xml_data .= &xml_store($calendar{update_timestamp}, "update_timestamp"); $xml_data .= ""; return $xml_data; } sub event2xml() { my ($event_ref) = @_; my %event = %{$event_ref}; my $xml_data = ""; $xml_data .= &xml_store($event{id}, "id"); $xml_data .= &xml_store($event{cal_id}, "cal_id"); $xml_data .= &xml_store($event{start}, "start"); $xml_data .= &xml_store($event{end}, "end"); $xml_data .= &xml_store($event{title}, "title"); $xml_data .= &xml_store($event{details}, "details"); $xml_data .= &xml_store($event{icon}, "icon"); $xml_data .= &xml_store($event{bgcolor}, "bgcolor"); $xml_data .= &xml_store($event{unit_number}, "unit_number"); $xml_data .= &xml_store($event{update_timestamp}, "update_timestamp"); $xml_data .= ""; return $xml_data; } sub find_end_of_month { my ($month, $year) = @_; my $next_month = $month+1; if ($next_month > 11) { $next_month=0; $year++; } my $month_end_timestamp = timegm(0,0,0,1,$next_month,$year); return $month_end_timestamp; } sub xml_store { my ($data_string, $tag_name) = @_; my $result_string = ""; $data_string = &encode($data_string); my $result_string = "<$tag_name>$data_string"; return $result_string; } sub xml_quick_extract # it doesn't get any dumber than this. ignores attributes, element order, fooled by duplicate tag names at different depths. { my ($data, $tag_name) = @_; my @results_array = (); while ($data =~ /<$tag_name>(.+?)<\/$tag_name>/g) { push @results_array, $1; } return @results_array; } sub xml_extract # Slow, but can handle attributes, element order, same tag names at different depths. Can't handle encodings, DTDs. { my ($data, $tag_name, $debug) = @_; my @results_array = (); my $results = ""; my $final_results = ""; my $depth_count=0; my $start_index=0; my $end_index=0; my $match_index=0; my $attributes=(); my $position=0; # position is the position of the element we're looking for, with respect to all other elements # under the parent element while ($data =~ /(<.*?>|<\/.*?>)/g) { my $match=$1; my $temp_index = $+[1]; if ($match =~ /<$tag_name\b.*?>/ && $depth_count==0) # the opening tag we're looking for { $start_index = $temp_index; $depth_count++; if ($debug) {$debug_info .= "active opening tag, $match \ndepth count $depth_count\n";} if ($debug) {$debug_info .= "start index $start_index\n";} my $attribute_text = $match; $attribute_text =~ s/\s*=\s*/=/g; # compress whitespace on either side of = sign $attribute_text =~ s/=([^"])(.+?\b)/="$1$2"/g; # properly format attributes with quote marks #if ($debug) {$debug_info .= "rejiggered attribute text: $attribute_text\n";} # extract attributes while ($attribute_text =~ /\w+?=".+?[^\\]"/g) { my $a_match = $&; my ($name, $value)= split('=',$a_match); $value =~ s/\\"/"/g; # remove first and last characters (the quotes) from value $value = substr $value, 1,-1; if ($debug) {$debug_info .= "attribute: $a_match\n";} if ($debug) {$debug_info .= " name: $name\n";} if ($debug) {$debug_info .= " value: $value\n";} $attributes->{$name} = $value; } #%attributes=(); #$debug_info .= "end position, $+[0]\n\n"; } elsif ($match =~ /<[^\/].*?>/) # some other opening tag { $depth_count++; if ($debug) {$debug_info .= "other opening tag, $match \ndepth count $depth_count\n";} } elsif ($match eq "<\/$tag_name>" && $depth_count == 1) # the closing tag we're looking for { $depth_count--; if ($debug) {$debug_info .= "active closing tag, $match \ndepth count $depth_count\n";} if ($depth_count==0) # done! return results { $end_index = $-[0]; $results = substr $data, $start_index,($end_index-$start_index); my $results_hash=(); $results_hash -> {data} = $results; $results_hash -> {attributes} = $attributes; $results_hash -> {position} = $position; push @results_array, $results_hash; if ($debug) {$debug_info .= " pushing results: \"$results\" onto array\n";} if ($debug) {$debug_info .= " attributes: \"$attributes\" \n";} if ($debug) {$debug_info .= " position: \"$position\" \n";} if ($debug) {$debug_info .= " start: $start_index end $end_index\n\n";} #if ($debug) {$debug_info .= " $results\n\n";} $start_index=0; $end_index=0; $attributes=(); } #$debug_info .= "closing tag, $1 \ndepth count $depth_count\n"; #$debug_info .= "start position, $-[0]\n\n"; $position++; } else # other closing tag { $depth_count--; if ($depth_count==0) {$position++;} if ($debug) {$debug_info .= "other closing tag, $match \ndepth count $depth_count\n";} } $match_index++; } return @results_array; } #******************** end xml_extract ********************** sub xml_tags { my ($data, $debug) = @_; my @results_array = (); my %tags_hash; my $depth_count=0; while ($data =~ /(<.*?>|<\/.*?>)/g) { my $match=$1; if ($match =~ /<[^\/].*?>/) # any opening tag { if ($depth_count == 0) # level 0 opening tag { $tag_name = $match; $tag_name =~ s/).+/$1/; $depth_count--; if ($debug) {$debug_info .= "level 1 closing tag, $tag_name \n";} $tags_hash{$tag_name}=1; if ($debug) {$debug_info .= " pushing tag name $tag_name onto array\n\n";} } else # other closing tag { $depth_count--; if ($debug) {$debug_info .= "other closing tag, $match \ndepth count $depth_count\n";} } } return keys %tags_hash; } #******************** end xml_tags ********************** sub xml2hash { my ($xml_data, $debug) = @_; my $item; my @item_tags = &xml_tags($xml_data); if (scalar @item_tags == 0) { if ($debug) {$debug_info .= " plain text item data: ($xml_data) \n";} return $xml_data; } else { if ($debug) {$debug_info .= " xml data: ($xml_data) \n";} my %results_hash; foreach $tag (@item_tags) { my @tag_data = &xml_extract($xml_data,"$tag"); if (scalar @tag_data == 1) { if ($debug) {$debug_info .= " extracting xml for tag $tag (single data)\n";} $results_hash{$tag} = &xml2hash($tag_data[0]->{data},$debug); } else { if ($debug) {$debug_info .= " extracting xml for tag $tag (array data)\n";} my @tag_array; foreach $thing (@tag_data) { push @tag_array, &xml2hash($thing->{data},$debug); } $results_hash{$tag}=\@tag_array; } } if ($debug) {$debug_info .= "\n";} return \%results_hash; } } #******************** end xml2hash ********************** sub get_remote_file { my ($url) = @_; $url =~ s/http:\/\///; my $hostname = $url; $hostname =~ s/\/.+//g; my $document = $url; $document =~ s/.+?\//\//; #$debug_info .= "url: $url
"; #$debug_info .= "hostname: $hostname
"; #$debug_info .= "document: $document
"; if ($hostname eq "" | $document eq "") {return;} $remote = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $hostname, PeerPort => "http(80)" ); unless ($remote) { $debug_info .= "cannot connect to http daemon on $hostname
"; return; } $remote->autoflush(1); print $remote "GET $document HTTP/1.0\n"; print $remote "User-Agent: Mozilla 4.0 (compatible; I; Linux-2.0.35i586)\n"; #without this line, virtual hosts won't work (multiple domain names on a single IP) print $remote "Host: $hostname\n"; print $remote "\n\n"; @textbuffer=<$remote>; my $textstring = join "", @textbuffer; $textstring =~ s/\r//gs; #some servers sneak these in. $textstring =~ s/.+?\n\n//si; return $textstring; } sub time_overlap { my ($start1, $end1, $start2, $end2) = @_; my $temp1 = $end2 - $start1; my $temp2 = $end1 - $start2; my $range_total = $end2 - $start2; #$debug_info .= "temp1:$temp1 temp2:$temp2 range_total:$range_total\n"; # if the event falls in or overlaps this week (there are 3 cases), the third being an event # that *completely* overlaps the week. if ( ($temp1 <= $range_total && $temp1 > 0) || ($temp2 <= $range_total && $temp2 > 0) || ($temp1 > 0 && $temp2 > 0)) {return 1;} else {return 0;} } sub make_email_link { my ($string) = @_; my $new_string = ""; #remove all newlines $string =~ s/\n//g; #insert newlines after > characters $string =~ s/]+?\@[^ <>]+)/$1<\/a>/g; #ignore substitution if the email address was already a link. if ($1 =~ /(:|")/) {$new_string .= $line;} else { $new_line =~ s/\n//g; $new_string .= $new_line; } } return $new_string; } sub formatted_time { my ($input_time, $format_string) = @_; my @input_time_array = gmtime ($input_time+0); my $ampm=""; if ($input_time_array[5]<1900) {$input_time_array[5]+=1900;} $month_name=$months[$input_time_array[4]]; $input_time_array[4]++; if ($input_time_array[1]<10) {$input_time_array[1]="0".$input_time_array[1];} if ($input_time_array[2]>12) #convert from 24-hour to am/pm { $input_time_array[2]=$input_time_array[2] - 12; $ampm="pm"; } else { $ampm="am"; } $format_string =~ s/ampm/$ampm[2]/g; $format_string =~ s/hh/$input_time_array[2]/g; $format_string =~ s/mm/$input_time_array[1]/g; $format_string =~ s/ss/$input_time_array[0]/g; $format_string =~ s/mo/$input_time_array[4]/g; $format_string =~ s/mn/$month_name/g; $format_string =~ s/md/$input_time_array[3]/g; $format_string =~ s/yy/$input_time_array[5]/g; return $format_string; } sub nice_date_range_format { my ($timestamp1, $timestamp2, $separator_string) = @_; my $result_string = ""; #make sure the timestamps are in the correct order if ($timestamp1> $timestamp2) { $temp=$timestamp2; $timestamp2=$timestamp1; $timestamp1=$temp; } my @timestamp1_array = gmtime $timestamp1; my @timestamp2_array = gmtime $timestamp2; #format the year for humans $timestamp1_array[5] +=1900; $timestamp2_array[5] +=1900; if ($timestamp1_array[4] == $timestamp2_array[4] && $timestamp1_array[5] == $timestamp2_array[5]) { #same year, same month $result_string = "$months[$timestamp1_array[4]] $timestamp1_array[3]$separator_string$timestamp2_array[3], $timestamp1_array[5]"; } elsif ($timestamp1_array[5] != $timestamp2_array[5]) { #different year $result_string = "$months[$timestamp1_array[4]] $timestamp1_array[3], $timestamp1_array[5]$separator_string$months[$timestamp2_array[4]] $timestamp2_array[3], $timestamp2_array[5]"; } else { #same year, different months $result_string = "$months[$timestamp1_array[4]] $timestamp1_array[3],$separator_string$months[$timestamp2_array[4]] $timestamp2_array[3], $timestamp2_array[5]"; } return $result_string; } sub encode { my ($input_string) = @_; return if ($input_string eq ""); my $output_string=$input_string; $output_string =~ s/(\W)/"\%".sprintf("%02x", (ord $1))/ge; $output_string =~ s/\%20/+/g; return $output_string; } sub decode { my ($input_string) = @_; return if ($input_string eq ""); my $output_string = $input_string; $output_string =~ s/\+/ /g; $output_string =~ s/%([0-9A-Fa-f]{2})/pack("c",hex($1))/ge; return $output_string; } sub generate_event_details { my ($event_ref) = @_; my %event = %{$event_ref}; my $return_text = $event_details_template; my @event_start_timestamp_array = gmtime $event{start}; my $event_cal_name = "$calendars{$event{cal_id}}{title}"; if ($calendars{$event{cal_id}}{link} =~ /\S/) { $event_cal_name = "$calendars{$event{cal_id}}{title}"; } $return_text =~ s/###event calendar name###/$event_cal_name/g; my $date_string = ""; if ($event{days} == 1) { #single-day event $date_string="$day_names[$event_start_timestamp_array[6]], $months[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]"; } elsif ($event{days} != 0) #multi-day event { my @event_end_timestamp_array = gmtime $event{end}; $date_string= < $day_names[$event_start_timestamp_array[6]], $months[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $day_names[$event_end_timestamp_array[6]], $months[$event_end_timestamp_array[4]] $event_end_timestamp_array[3] p1 } $return_text =~ s/###event date###/$date_string/g; $return_text =~ s/###event title###/$event{title}/g; $return_text =~ s/###event id###/$event{id}/g; $return_text =~ s/###event calendar id###/$event{cal_id}/g; $return_text =~ s/###event background color###/$event{bgcolor}/g; my $event_details = $event{details}; #replace \n characters with
tags $event_details =~ s/\n/\n
\n/g; # check the event details, and see if there are any non-htmlified # links. If so, turn them into links. $event_details =~ s/[^"](htt.:\/\/.+?),*\.?(\s|\n|<|$)/ $1<\/a>$2/g; # convert email addresses to links. $event_details = &make_email_link($event_details); # make sure all links open up in a new window $event_details =~ s/
"; } $return_text =~ s/###event icon###/$event_icon_text/g; my $unit_number_text = $event{unit_number}; $unit_number_text =~ s/(\d)//g; $return_text =~ s/###unit number icon###/$unit_number_text/g; my $edit_event_link = "
Edit this event"; $return_text =~ s/###edit event link###/$edit_event_link/g; my $edit_event_link = "Delete this event"; $return_text =~ s/###delete event link###/$edit_event_link/g; my $temp = &export_event_link(\%event); $return_text =~ s/###export event link###/$temp/g; my $cal_detail_text .= < $lang{this_event_to}
p1 } sub fatal_error() { $error_info =~ s/\n/
/g; $html_output .=< Plans alert! Plans alert:
$error_info p1 if ($debug_info ne "") { $debug_info =~ s/\n/
/g; $html_output .=< Debug info:
$debug_info p1 } $html_output .=< p1 print $html_output; exit(0); } # default calendar data structure #%default_cal; %default_cal = (id => "", title => "", details => $new_calendar_default_details, link => "", local_background_calendars => {}, selectable_calendars => {}, list_background_calendars_together => "", background_events_display_style => "normal", background_events_fade_factor => "", background_events_color => "#ffffff", default_number_of_months => 1, max_number_of_months => 24, gmtime_diff => 0, date_format => "mm/dd/yy", week_start_day => 0, info_window_size => "400x400", custom_template => "", custom_stylesheet => "", password => "", update_timestamp => 0); # If an included file contains only subroutines, perl will complain # that it "did not return a true value". The "return 1;" at the end fixes this. return 1;