#!/usr/bin/perl # before anything else, the script needs to find out its own name # # some servers (notably IIS on windows) don't set the cwd to the script's # directory before executing it. So we get that information # from $0 (the full name & path of the script). BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_} $name = $0; $name =~ s/.+\/?.+\///; # for unix $name =~ s/.+\\.+\\//; # for windows $path = $0; $path =~ s/(.+\/).+/$1/g; # for unix $path =~ s/(.+\\).+/$1/g; # for windows if ($path ne "") { chdir $path; push @INC,$path; } # finished discovering name # some global variables (more further down) local $plans_version = "6.0.1"; # version local $debug_info; local $perl_version = (sprintf ("%vd",$^V)); local $data_storage_mode; local $fatal_error = 0; # fatal errors cause plans to abort and print an error message to the browser local $error_info = ""; local $html_output; local $event_details_template; local %calendars; local %current_calendar; local %latest_calendar; local %latest_new_calendar; local $max_cal_id = 0; local $max_new_cal_id = 0; local $max_series_id = 0; local %events; local %current_event; local %latest_event; local $max_event_id = 0; local %text; local $max_remote_event_id = 0; local $default_template_path = ""; local $theme_url = ""; local $choose_themes = ""; local $graphics_url = ""; local $icons_url = ""; local $input_cal_id_valid = 0; local $right_click_menus_enabled = 0; local %cal_options; local $rightnow; local @months; local @months_abv; local @day_names; local $loaded_all_events; # flag used to avoid calling load_events("all") twice # not needed for calendars (we always load all calendars) # check for required modules. my $module_found=0; foreach $temp_path (@INC) { if (-e "$temp_path/plans_config.pl") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "Unable to locate plans_config.pl! It should be in the same directory as plans.cgi!\n"; } else {require "plans_config.pl";} $module_found=0; foreach $temp_path (@INC) { if (-e "$temp_path/CGI") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "unable to locate required module CGI!\n"; } else {use CGI;} $module_found=0; foreach $temp_path (@INC) { if (-e "$temp_path/CGI/Carp.pm") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "unable to locate required module CGI::Carp!\n"; } else {use CGI::Carp qw/fatalsToBrowser/;} $module_found=0; foreach $temp_path (@INC) { if (-e "$temp_path/Time") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "unable to locate required module Time.pm!\n"; } else {use Time::Local;} $module_found=0; foreach $temp_path (@INC) { if (-e "$temp_path/IO.pm") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "unable to locate required module IO.pm!\n"; } else {use IO::Socket;} if ($fatal_error == 1) # print error and bail out { &fatal_error(); } $module_found=0; foreach $temp_path (@INC) { if (-r "$temp_path/plans_lib.pl") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "Unable to locate plans_lib.pl! It should be in the same directory as plans.cgi!\n"; } else {require "plans_lib.pl";} # get the language file, if one is defined if (defined $language_file) { $module_found=0; foreach $temp_path (@INC) { if (-r "$temp_path/$language_file") {$module_found=1;} } if ($module_found == 0) { $fatal_error=1; $error_info .= "Unable to locate language file $language_file! It should be in the same directory as plans.cgi!\n"; } else {require $language_file;} } else { $fatal_error=1; $error_info .= "No language file defined in plans.config!\n"; } # check for perl version my $temp = substr($perl_version,0,3); if ($temp < 5.6) { $fatal_error=1; $error_info .= "Your version of perl ($perl_version) is too old! Plans requires perl version 5.6 or better.\n"; } if ($fatal_error == 1) # print error and bail out { &fatal_error(); } # init cgi stuff $q = new CGI; $script_url = $q->url(-path_info>=1); $script_url =~ /(.*)\//; # remove trailing / and all text after $script_url = $1; # remove trailing / and all text after # check if data files or tables are present &check_data(); # fatal error? Print error and bail out if ($fatal_error == 1) {&fatal_error();} if ($choose_themes) { $theme_url=$q->param('theme_url'); $theme_url=$theme_url; } if ($theme_url eq "") {$theme_url = "$script_url/theme";} $graphics_url ="$theme_url/graphics"; # where misc. graphics are $icons_url = "$theme_url/icons"; # where icons are $css_path = "$theme_url/plans.css"; # css file # globals for http parameters my $active_tab = $q->param('active_tab'); my $add_edit_cal_action = $q->param('add_edit_cal_action'); local $current_cal_id = $q->param('cal_id'); $current_cal_id = 0 if ($current_cal_id eq "" || $current_cal_id =~ /\D/); my $add_edit_event = $q->param('add_edit_event'); local $current_event_id = $q->param('evt_id'); local $cal_num_months = $q->param('cal_num_months'); local $cal_start_month = $q->param('cal_start_month'); local $cal_start_year = $q->param('cal_start_year'); my $special_action = $q->param('special_action'); local $cal_or_list = $q->param('cal_or_list'); # other globals my $event_start_date; my $event_start_timestamp; my $event_days; my $start_mday; my $start_mon; my $start_year; my @timestamp_array; my $recur_end_timestamp; # load calendar data &load_calendars(); foreach $cal_id (keys %calendars) { if ($cal_id eq $current_cal_id && $cal_id ne "") {$input_cal_id_valid = 1;} } if (!$input_cal_id_valid) { $current_cal_id=0; #$q->param(-name=>'cal_id',-values=>[0]); } # make all calendars selectable by default foreach $cal_id (keys %calendars) {$default_cal{selectable_calendars}{$cal_id} = 1;} %current_calendar = %{$calendars{$current_cal_id}}; # time-related globals $rightnow = time() + 3600 * $current_calendar{gmtime_diff}; @rightnow_array = gmtime $rightnow; $rightnow_year = $rightnow_array[5]+1900; $rightnow_month = $rightnow_array[4]; $rightnow_mday = $rightnow_array[3]; $next_year = $rightnow_year+1; $rightnow_description = formatted_time($rightnow, "hh:mm:ss mn md yy"); @weekday_sequence = @day_names; # custom stylesheet? if ($current_calendar{custom_stylesheet} ne "") { $css_path = "http://$current_calendar{custom_stylesheet}"; } # if this is a custom calendar request, shoehorn the request parameters in if ($q->param('custom_calendar') == 1) { $current_cal_id = $q->param('custom_calendar_calendar'); @custom_calendar_backgound_calendars = $q->param('custom_calendar_background_calendars'); foreach $local_background_calendar (keys %{$calendars{$current_cal_id}{local_background_calendars}}) {delete $calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar};} foreach $local_background_calendar (@custom_calendar_backgound_calendars) {$calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar} = 1;} %current_calendar = %{$calendars{$current_cal_id}}; } # make sure we can select the current calendar #$current_calendar{selectable_calendars}{$current_cal_id} = 1; # set info window height & width my ($info_window_width, $info_window_height) = split("x", $current_calendar{info_window_size}); # rotate weekday_sequence by the offset defined in the week start day. for ($l1=0;$l1 < $current_calendar{week_start_day};$l1++) {push @weekday_sequence, (shift @weekday_sequence);} # load background_colors my @temp_lines = split ("\n", $event_background_colors); foreach $temp_line (@temp_lines) { if ($temp_line !~ /\w/) # skip any blank lines {next;} $temp_line =~ s/^\s+//; my ($hex_color, $hex_color_title) = split (/,*\s+/, $temp_line, 2); if ($hex_color_title eq "") {$hex_color_title = " ";} push @event_bgcolors, {color => $hex_color, title => $hex_color_title}; } my $template_html; #load template my $custom_template_file_found=1; my $local_template_file = 0; # tells whether the template was loaded via a filesystem open or through a http request. if ($current_calendar{custom_template} ne "") # custom template { $template_html = &get_remote_file("$current_calendar{custom_template}"); if ($template_html !~ /###/) { $custom_template_file_found=0; $lang{custom_template_fail} =~ s/###template###/$current_calendar{custom_template}/; $debug_info .= "$lang{custom_template_fail}\n"; } } if ($current_calendar{custom_template} eq "" || $custom_template_file_found ==0) { if (!(-e "$default_template_path")) { $fatal_error=1; $lang{default_template_fail} =~ s/###template###/$default_template_path/; $debug_info .= "$lang{default_template_fail}\n"; &fatal_error(); } else { open (FH, "$default_template_path") || ($debug_info .="
Unable to open default template file $default_template_path for reading
"); flock FH,2; @template_lines=; close FH; $template_html = join "", @template_lines; $local_template_file = 1; } } # separate the main calendar template and the event details template $event_details_template = $template_html; $template_html =~ s/<\/html>.+/<\/html>/s; $template_html =~ s/.+<\/event_details>//s; # needed in case the event details aren't at the bottom of the html. It happens. if ($event_details_template =~ // && $event_details_template =~ /<\/event_details>/) { $event_details_template =~ s/.*//s; $event_details_template =~ s/<\/event_details>.+//s; } else { $debug_info .= "Warning! No event details template found. (The template file doesn't contain <event_details>...</event_details>\n"; $event_details_template = ""; } # ssi-style includes in the template if ($local_template_file) { my $new_html = $template_html; $template_html =~ s/###include\s+(.+)###/&load_file($1)/ge; #while ($new_html =~ s/###include\s+(.+)###//g) if(0) { my $include_file=$1; if (-e $include_file) { open (FH, "$include_file") || ($debug_info .="
unable to open include file $include_file for reading
"); flock FH,2; my @include_lines=; close FH; $include_html = join "", @include_lines; } $template_html =~ s/###include\s+(.+)###/$include_html/; } } sub load_file() { my ($file)=@_; if (-e $file) { open (FH, "$file") || (return "unable to open include file $file for reading"); flock FH,2; my @lines=; close FH; $text = join "", @lines; return $text; } else { return "file $file does not exist"; } } if($choose_themes) { my $theme_file="choose_theme.html"; my $theme_html=""; if (-e $theme_file) { open (FH, "$theme_file") || ($debug_info .="
unable to open theme file $theme_file for reading
"); flock FH,2; my @theme_lines=; close FH; $theme_html = join "", @theme_lines; } $template_html =~ s/###choose theme###/$theme_html/; } else { $template_html =~ s/###choose theme###//; } #evaluate browser type and version $_ = $ENV{HTTP_USER_AGENT}; if (/Mozilla/) { if (/Opera.([0-9\.]+)/) { $browser_type = 'Opera'; $browser_version=$1;} elsif (/MSIE.([0-9.]+)/) { $browser_type = 'IE'; $browser_version = $1;} elsif (/Mozilla\/([0-9\.]+)/) {$browser_type = 'Mozilla'; $browser_version=$1; if (($browser_version<5) || (/Netscape/)) {$browser_type = "Netscape";} } if (/\)[^0-9.]+[0-9]*[\/\ ]([0-9.]+)/) {$browser_version=$1;} } elsif (/(\w+)\/([0-9\.]+)/) {$browser_type = $1; $browser_version = $2} #evaluate, transform, tweak, adjust, modify input values #$debug_info .= "browser type: $browser_type
"; #if the input is greater than the number of tabs, things look goofy if ($q->param('active_tab') >= scalar @tab_text || $q->param('active_tab') eq "") { $active_tab = 0; } #if no month is selected, use the current month if ($cal_start_month eq "") { $cal_start_month = $rightnow_month; #$cal_start_month = 2; } #if the input year is out of range use the current year if (($cal_start_year+0) < 1902 || ($cal_start_year+0)> 2037) { $cal_start_year = $rightnow_year; } if ($cal_num_months eq "" || $cal_num_months > $current_calendar{max_number_of_months}) { $cal_num_months = "$current_calendar{default_number_of_months}"; } if ($cal_num_months eq "" || $cal_num_months > $current_calendar{max_number_of_months}) { $cal_num_months = 1; } #calculate calendar end month and year $cal_end_month = $cal_start_month; $cal_end_year = $cal_start_year; for ($l1=1;$l1<$cal_num_months;$l1++) { $cal_end_month++; if ($cal_end_month == 12) { $cal_end_month=0; $cal_end_year++; } } #check to make sure num_months+cal_start_date doesn't go out of bounds if ($cal_end_year < 1902 || $cal_end_year> 2037) { $cal_end_year = $cal_start_year; $cal_end_month = $cal_start_month; $cal_num_months = 1; } # time window for loading events my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year) - 2592000; my $cal_end_timestamp = timegm(0,0,0,1,$cal_end_month,$cal_end_year) + 5184000; if ($q->param('cal_start_timestamp') ne "" && $q->param('cal_start_timestamp') !~ /\D/) {$cal_start_timestamp = $q->param('cal_start_timestamp');} if ($q->param('cal_end_timestamp') ne "" && $q->param('cal_end_timestamp') !~ /\D/) {$cal_end_timestamp = $q->param('cal_end_timestamp');} #$debug_info .="start: $cal_start_timestamp\nend: $cal_end_timestamp\nrightnow: $rightnow\n"; # load event data, for main calendar and its background calendars my @temp_calendars = ($current_cal_id); foreach $local_background_calendar (keys %{$current_calendar{local_background_calendars}}) {push @temp_calendars, $local_background_calendar;} &load_events($cal_start_timestamp, $cal_end_timestamp, \@temp_calendars); if ($current_event_id ne "") { &load_event($current_event_id); %current_event = %{$events{$current_event_id}}; } # load events from remote background calendars if (scalar keys %{$current_calendar{remote_background_calendars}} > 0) { $remote_calendars_status=""; my $temp = scalar keys %{$current_calendar{remote_background_calendars}}; foreach $remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) { # pull in remote calendar name my $remote_calendar_url = $current_calendar{remote_background_calendars}{$remote_calendar_id}{url}; $remote_calendar_complete_url = $remote_calendar_url; #$debug_info .= "remote calendar: $remote_calendar_complete_url\n"; $remote_calendar_complete_url .= "?remote_calendar_request=1&cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}&cal_start_year=$cal_start_year&cal_start_month=$cal_start_month&num_months=$cal_num_months"; #$debug_info .= "remote calendar url: $remote_calendar_complete_url\n"; my $xml_results = &get_remote_file($remote_calendar_complete_url); if ($xml_results =~ //) { $xml_results =~ s//>/g; $debug_info .= "Error fetching remote calendar: $xml_results\n"; } else { my %remote_calendars = %{&xml2hash($xml_results)}; my $remote_cal_title=$remote_calendars{'xml'}{calendar}{title}; my $temp=$xml_results; $temp=~ s/>/>/g; $temp=~ s/ 1) { $prev_string = $lang{previous_months}; $prev_string =~ s/###num###/$cal_num_months/; } else { $prev_string = $lang{previous_month}; } $next_cal_start_month=$cal_start_month+$cal_num_months; $next_cal_start_year=$cal_start_year; if ($next_cal_start_month > 11) { $next_cal_start_month -= 12; $next_cal_start_year++; } if ($cal_num_months > 1) { $next_string = $lang{next_months}; $next_string =~ s/###num###/$cal_num_months/; } else { $next_string = $lang{next_month}; } $consistent_parameter_string=""; &make_consistent ("cal_id"); &make_consistent ("cal_start_month"); &make_consistent ("cal_start_year"); &make_consistent ("cal_num_months"); &make_consistent ("cal_or_list"); &make_consistent ("theme_url"); if ($q->param('diagnostic_mode') eq "1") { &diagnostic_mode(); exit(0); } if ($q->param('detect_remote_calendars') eq "1") { &detect_remote_calendars(); exit(0); } if ($q->param('remote_calendar_request') eq "1") { &remote_calendar_request(); exit(0); } if ($q->param('export_calendar') eq "1") { if ($q->param('export_type') eq "ascii_text") { &ascii_text_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year); exit(0); } elsif ($q->param('export_type') eq "csv_file") { &csv_file($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year); exit(0); } elsif ($q->param('export_type') eq "vcalendar") { &vcalendar_export_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year); exit(0); } } if ($q->param('export_event') eq "1") { if ($q->param('export_type') eq "ascii_text") { &ascii_text_event(); exit(0); } elsif ($q->param('export_type') eq "icalendar") { &icalendar_export_event(); exit(0); } elsif ($q->param('export_type') eq "vcalendar") { &vcalendar_export_event(); exit(0); } } elsif ($q->param('view_event') eq "1") { &view_event(); exit(0); } elsif ($q->param('email_reminder') eq "1") { &email_reminder_prompt(); exit(0); } elsif ($q->param('email_reminder_confirm') eq "1") { &email_reminder_confirm(); exit(0); } elsif ($special_action eq "preview_event") { &preview_event(); exit(0); } elsif ($special_action eq "preview_date") { &preview_date(); exit(0); } $html_output .=< p1 chomp $insert_text; $html_output =~ s/###javascript stuff###/$insert_text/; #default page &display_default(); exit(0); sub display_default { chomp $insert_text; $html_output =~ s/###css file###/$css_path/g; # tab menu stuff $menu_tabs[0] = {status => "inactive", html => "$tab_text[0]"}; $menu_tabs[1] = {status => "inactive", html => "$tab_text[1]"}; $menu_tabs[2] = {status => "inactive", html => "$tab_text[2]"}; $menu_tabs[$active_tab]{status} ="active"; $menu_tabs[2]{html} = "$tab_text[2]"; $insert_text =<
p1 # this kludge sucks! if ($browser_type eq "IE") {$tab_vert_offset=4;} else {$tab_vert_offset=0;} #lay out the actual menu tabs for ($l1=0;$l1       $$menu_tab{html}       p1 $noinsert_text .=<$$menu_tab{html}       p1 } $insert_text .=< p1 chomp $insert_text; if ($q->param('custom_calendar') == 1) { $html_output =~ s/###tab menu stuff###//; } else { $html_output =~ s/###tab menu stuff###/$insert_text/; } $insert_text =""; #invisible html for context menu $insert_text .=<
p1 #main box stuff $insert_text .=<
$lang{controls_start_month}:
$lang{controls_num_months}
p1 $cal_controls_text .=< $lang{controls_calendar_label}
p1 my $num_selectable_calendars = scalar keys %{$current_calendar{selectable_calendars}}; if (scalar keys %{$current_calendar{selectable_calendars}} > 0) { $cal_controls_text .=< p1 #list each calendar for the user to select foreach $selectable_calendar_id (sort {$a <=> $b} keys %{$current_calendar{selectable_calendars}}) { my $selected =""; $selected =" selected" if ($selectable_calendar_id eq $current_calendar{id}); $selectable_calendar_id=~ s/\D//g; #$debug_info .= "calendar id: -$selectable_calendar_id-\n "; $cal_controls_text .=<$calendars{$selectable_calendar_id}{title} p1 } $cal_controls_text .=< p1 } else { $cal_controls_text .=<$current_calendar{title} p1 } $cal_controls_text .=< p1 if ($cal_or_list eq "list") {$list_selected = "selected";} else {$cal_selected = "selected";} $cal_controls_text .=< $lang{controls_display_label}
p1 $cal_controls_text .=< p1 if ($q->param('custom_calendar') == 1) { $html_output =~ s/###calendar controls###//g; } else { $html_output =~ s/###calendar controls###/$cal_controls_text/g; } $insert_text .= &do_calendar_list_view(); #select event range $cal_month_start_date = timegm(0,0,0,1,$cal_start_month,$cal_start_year); @cal_month_start_date_array = gmtime $cal_month_start_date; $events_start_timestamp = $cal_month_start_date - 604800; # +7 day margin $events_end_timestamp = &find_end_of_month($cal_end_month, $cal_end_year) + 604800; # +7 day margin #now that we have selected the appropriate events, we can #generate the corresponding javascript and calendar view #and insert/add it to the html output. $common_javascript = &common_javascript(); $page_javascript = &calendar_view_javascript($events_start_timestamp, $events_end_timestamp); #display browser-appropriate javascript if ($browser_type eq "IE") {$browser_javascript = &IE_javascript();} else {$browser_javascript = &NS6_javascript();} #replace javascript placeholders with actual html/javascript code $html_output =~ s/###common javascript###/$common_javascript/; $html_output =~ s/###page-specific javascript###/$page_javascript/; $html_output =~ s/###browser-specific javascript###/$browser_javascript/; my $temp1 .=<$prev_string p1 my $temp2 .=<$next_string p1 $html_output =~ s/###previous month link###/$temp1/g; $html_output =~ s/###next month link###/$temp2/g; } elsif ($active_tab eq "1") #the second tab is the add/edit events view { $html_output =~ s/###calendar controls###//; $insert_text .=< p1 $insert_text .= &add_edit_events(); $insert_text .=< p1 #generate javascript for add/edit events page $common_javascript = &common_javascript(); $page_javascript = &add_edit_events_javascript(); #display browser-appropriate javascript if ($browser_type eq "IE") {$browser_javascript = &IE_javascript();} else {$browser_javascript = &NS6_javascript();} #replace javascript placeholders with actual html/javascript code $html_output =~ s/###common javascript###/$common_javascript/; $html_output =~ s/###page-specific javascript###/$page_javascript/; $html_output =~ s/###browser-specific javascript###/$browser_javascript/; # sneak in the color select javascript before all other javascript. my $temp =< p1 $html_output =~ s/(
$lang{tab2_select_a_calendar}

$add_edit_string

$lang{fields_text1} $lang{fields_text2} $lang{fields_text3}

$lang{help_on_this}  

 

p1 if ($add_edit_cal_action eq "edit") { $return_text .=<

$lang{help_on_this}
$lang{new_password}
$lang{repeat_new_password}
 
 
$lang{preview_warning}

$lang{del_cal_button3}


p1 } elsif ($add_edit_cal_action eq "add") { $return_text .=<
$lang{choose_password}   $lang{help_on_this}
$lang{repeat_password}
 
 
$lang{preview_warning}

p1 } $return_text .=< p1 } else #a user added/edited/deleted an calendar--do checks and perform resulting action { my @results_messages; my $cal_id = $current_cal_id; # need to validate cal id for add/edit my $cal_valid = 1; if ($q->param('del_cal_button') ne "") { #delete calendar &load_events("all"); my $del_valid=1; #check password. $input_password = crypt($q->param('cal_password'), substr($q->param('cal_password'), 0, 2)); if ($input_password ne $current_calendar{password} && $input_password ne $master_password) { $del_valid=0; push @results_messages, "$lang{update_cal_error1}$current_calendar{title}"; } # prevent delete of primary calendar if ($cal_id eq "0") { $del_valid=0; push @results_messages, $lang{update_cal_error2}; } if ($del_valid == 1) { #actually delete the calendar. # first, delete all its events my @deleted_event_ids; foreach $event_id (keys %events) { if ($events{$event_id}{cal_id} eq $cal_id) {push @deleted_event_ids, $event_id;} } &delete_events(\@deleted_event_ids); # next, delete the calendar in question &delete_calendar($cal_id); # finally, delete any references in other calendars (background calendars) my @cals_to_update; foreach $calendar_id (sort {$a <=> $b} keys %calendars) { if ($calendars{$calendar_id}{local_background_calendars}{$cal_id} eq "1") { delete $calendars{$calendar_id}{local_background_calendars}{$cal_id}; push @cals_to_update, $calendar_id; } if ($calendars{$calendar_id}{selectable_calendars}{$cal_id} eq "1") { delete $calendars{$calendar_id}{selectable_calendars}{$cal_id}; push @cals_to_update, $calendar_id; } } &update_calendars(\@cals_to_update); my $temp = $lang{update_cal_error3}; $temp =~ s/###title###/$current_calendar{title}/; push @results_messages, $temp; } # properly format errors, warnings my @messages = split ("\n",$cal_del_results); $cal_del_results=""; foreach $message (@messages) { $message =~ s/(.*$lang{Warning})/$1<\/span>/i; $message =~ s/(.*$lang{Error})/$1<\/span>/i; $cal_del_results .= "$message
\n"; } #$event_action_results = join "\n", @messages; $cal_del_results = "
    $cal_del_results
"; } else #the user added/updated an calendar { &load_new_calendars(); #check all input fields for validity my $cal_title = $q->param('cal_title'); my $cal_link = $q->param('cal_link'); my $cal_details = $q->param('cal_details'); my @local_background_calendars = $q->param('background_calendars'); my @selectable_calendars = $q->param('selectable_calendars'); my $new_calendars_automatically_selectable = $q->param('new_calendars_automatically_selectable'); my $list_background_calendars_together = $q->param('list_background_calendars_together'); my $background_events_display_style = $q->param('background_events_display_style'); my $background_events_fade_factor = $q->param('background_events_fade_factor'); my $background_events_color = $q->param('background_events_color'); my $allow_remote_calendar_requests = $q->param('allow_remote_calendar_requests'); my $remote_calendar_requests_require_password = $q->param('remote_calendar_requests_require_password'); my $remote_calendar_requests_password = $q->param('remote_calendar_requests_password'); my $new_remote_calandars_xml = $q->param('new_remote_calandars_xml'); my $default_number_of_months = $q->param('default_number_of_months'); my $max_number_of_months = $q->param('max_months'); my $gmtime_diff = $q->param('gmtime_diff'); my $date_format = $q->param('date_format'); $date_format = lc $date_format; my $week_start_day = $q->param('week_start_day'); my $preload_event_details = $q->param('preload_event_details'); my $info_window_size = $q->param('popup_window_size'); if ($info_window_size !~ /^\d{1,}x\d{1,}$/) { $cal_valid=0; my $temp=$lang{update_cal_error4}; $temp =~ s/###size###/$info_window_size/; push @results_messages, $temp; } $new_calendars_automatically_selectable = "no" if ($new_calendars_automatically_selectable ne "yes"); $preload_event_details = "no" if ($preload_event_details ne "yes"); my $custom_template = $q->param('custom_template'); $custom_template =~ s/http:\/\///g; my $custom_stylesheet = $q->param('custom_stylesheet'); $custom_stylesheet =~ s/http:\/\///g; my $cal_password = $q->param('cal_password'); my $new_cal_password = $q->param('new_cal_password'); my $repeat_new_cal_password = $q->param('repeat_new_cal_password'); $cal_title =~ s/\r//g; # some browsers sneak these in $cal_link =~ s/\r//g; # some browsers sneak these in $cal_details =~ s/\r//g; # some browsers sneak these in #check for required fields if ($cal_title eq "") { $cal_valid=0; push @results_messages, $lang{update_cal_error5}; } #strip all html from label field if ($cal_title =~ m/<(.*)>/) { push @results_messages, $lang{update_cal_error6}; $cal_title =~ s/<(.*)>//g; } $cal_link =~ s/http:\/\///g; #strip http:// from link field #check for date format if ($date_format !~ /^(mm|dd|yy)\/(mm|dd|yy)\/(mm|dd|yy)$/ ) { $cal_valid=0; push @results_messages, $lang{update_cal_error6_5}; } if ($add_edit_cal_action eq "edit") { #this action is an edit of an existing calendar, so we need to make a replacement. if (!(defined $calendars{$cal_id})) { $cal_valid=0; push @results_messages, $lang{update_cal_error7}; } else { #check password $input_password = crypt($cal_password, substr($cal_password, 0, 2)); if ($input_password ne $calendars{$cal_id}{password} && $input_password ne $master_password) { $cal_valid=0; push @results_messages, "$lang{update_cal_error1} $calendars{$cal_id}{title}"; } } #check for new password if ($new_cal_password ne "" || $repeat_new_cal_password ne "") { if ($new_cal_password ne $repeat_new_cal_password) { $cal_valid=0; push @results_messages, $lang{update_cal_error8}; } else { $calendars{$cal_id}{password} = crypt($new_cal_password, substr($new_cal_password, 0, 2)); } } # encrypt remote calendar password $remote_calendar_requests_password = crypt($remote_calendar_requests_password, substr($remote_calendar_requests_password, 0, 2)); if ($cal_valid == 1) { # update calendar record my $xml_data = ""; $calendars{$cal_id}{title} = $cal_title; $calendars{$cal_id}{details} = $cal_details; $calendars{$cal_id}{link} = $cal_link; $calendars{$cal_id}{new_calendars_automatically_selectable} = $new_calendars_automatically_selectable; $calendars{$cal_id}{list_background_calendars_together} = $list_background_calendars_together; $calendars{$cal_id}{background_events_display_style} = $background_events_display_style; $calendars{$cal_id}{background_events_fade_factor} = $background_events_fade_factor; $calendars{$cal_id}{background_events_color} = $background_events_color; $calendars{$cal_id}{default_number_of_months} = $default_number_of_months; $calendars{$cal_id}{max_number_of_months} = $max_number_of_months; $calendars{$cal_id}{gmtime_diff} = $gmtime_diff; $calendars{$cal_id}{date_format} = $date_format; $calendars{$cal_id}{week_start_day} = $week_start_day; $calendars{$cal_id}{preload_event_details} = $preload_event_details; $calendars{$cal_id}{info_window_size} = $info_window_size; $calendars{$cal_id}{custom_template} = $custom_template; $calendars{$cal_id}{custom_stylesheet} = $custom_stylesheet; $calendars{$cal_id}{allow_remote_calendar_requests} = $allow_remote_calendar_requests; $calendars{$cal_id}{remote_calendar_requests_require_password} = $remote_calendar_requests_require_password; $calendars{$cal_id}{remote_calendar_requests_password} = $remote_calendar_requests_password; # update local background calendars foreach $local_background_calendar (keys %{$calendars{$cal_id}{local_background_calendars}}) {delete $calendars{$cal_id}{local_background_calendars}{$local_background_calendar};} foreach $local_background_calendar (@local_background_calendars) {$calendars{$cal_id}{local_background_calendars}{$local_background_calendar} = 1;} #$debug_info .= "new remote calendars xml: $new_remote_calandars_xml\n"; #delete existing remote background calendars foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) { if ($q->param("delete_remote_calendar_$current_remote_calendar_id") ne "") { my $temp = $lang{get_remote_calendar5}; $temp =~ s/###remote url###/$current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url}/g; $temp =~ s/###remote id###/$current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id}/g; push @results_messages, $temp; delete $calendars{$current_cal_id}{remote_background_calendars}{$current_remote_calendar_id}; } } # update remote background calendars unless ($new_remote_calandars_xml eq "") { my %new_remote_calendars = %{&xml2hash($new_remote_calandars_xml)}; #$debug_info .= "$new_remote_calendars{remote_calendars}{remote_calendar}\n"; my $new_remote_cal_id = &max(keys %{$calendars{$cal_id}{remote_background_calendars}}) + 1; $debug_info .= (scalar keys %{$calendars{$cal_id}{remote_background_calendars}})." remote calendars already\n"; $debug_info .= "new_remote_cal_id: $new_remote_cal_id\n"; if ($new_remote_calendars{remote_calendars}{remote_calendar} =~ /array/i) # multiple remote background calendars { #$debug_info .= "multiple new remote calendars\n"; foreach $temp (@{$new_remote_calendars{remote_calendars}{remote_calendar}}) { my %new_remote_calendar = %{$temp}; $found=0; foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) { #$debug_info .= "comparing $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} with $new_remote_calendar{url}\n"; if ($current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} eq $new_remote_calendar{url} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{type} eq $new_remote_calendar{type} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{version} eq $new_remote_calendar{version} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{password} eq $new_remote_calendar{password} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id} eq $new_remote_calendar{remote_id}) {$found=1;} } if ($found==0) { $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{url} = $new_remote_calendar{url}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{type} = $new_remote_calendar{type}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{version} = $new_remote_calendar{version}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{password} = $new_remote_calendar{password}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{remote_id} = $new_remote_calendar{remote_id}; $new_remote_cal_id++; } else { my $temp = $lang{get_remote_calendar4}; $temp =~ s/###remote url###/$new_remote_calendar{url}/g; $temp =~ s/###remote id###/$new_remote_calendar{remote_id}/g; push @results_messages, $temp; } #$debug_info .= "remote calendar: $new_remote_calendar{url}\n"; #$debug_info .= "type: $new_remote_calendar{type}\n"; } } else # single remote background calendar { # check against existing remote background calendars. my %new_remote_calendar = %{$new_remote_calendars{remote_calendars}{remote_calendar}}; $found=0; foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) { #$debug_info .= "comparing $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} with $new_remote_calendar{url}\n"; if ($current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} eq $new_remote_calendar{url} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{type} eq $new_remote_calendar{type} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{version} eq $new_remote_calendar{version} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{password} eq $new_remote_calendar{password} && $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id} eq $new_remote_calendar{remote_id}) {$found=1;} } if ($found==0) { $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{url} = $new_remote_calendar{url}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{type} = $new_remote_calendar{type}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{version} = $new_remote_calendar{version}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{password} = $new_remote_calendar{password}; $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{remote_id} = $new_remote_calendar{remote_id}; } else { my $temp = $lang{get_remote_calendar4}; $temp =~ s/###remote url###/$new_remote_calendar{url}/g; $temp =~ s/###remote id###/$new_remote_calendar{remote_id}/g; push @results_messages, $temp; } } } #$calendars{$cal_id}{remote_background_calendars} = $remote_calendar_requests_password; # update selectable calendars foreach $selectable_calendar (keys %{$calendars{$cal_id}{selectable_calendars}}) {delete $calendars{$cal_id}{selectable_calendars}{$selectable_calendar};} foreach $selectable_calendar (@selectable_calendars) {$calendars{$cal_id}{selectable_calendars}{$selectable_calendar} = 1;} # make sure the calendar can select itself. if (scalar keys %{$calendars{$cal_id}{selectable_calendars}} > 0) {$calendars{$cal_id}{selectable_calendars}{$cal_id} = 1;} } if ($cal_valid == 1) { #all checks successful, add/update calendar! &update_calendar($cal_id); push @results_messages, "$calendars{$current_cal_id}{title} $lang{update_cal_success}"; } else {$cal_add_results .= $lang{update_cal_failure};} } else #if we need to create a completely new record { #check new password if ($new_cal_password ne $repeat_new_cal_password) { $cal_valid=0; push @results_messages, $lang{update_cal_error9}; } elsif ($new_cal_password eq "" || $repeat_new_cal_password eq "" ) { $cal_valid=0; push @results_messages, $lang{update_cal_error10}; } else { $input_password = crypt($new_cal_password, substr($new_cal_password, 0, 2)); } my $new_cal_id; if ($cal_valid == 1) { $new_cal_id = $max_new_cal_id + 1; $new_calendars{$new_cal_id}{id} = $new_cal_id; $new_calendars{$new_cal_id}{title} = $cal_title; $new_calendars{$new_cal_id}{details} = $cal_details; $new_calendars{$new_cal_id}{link} = $cal_link; $new_calendars{$new_cal_id}{list_background_calendars_together} = $list_background_calendars_together; $new_calendars{$new_cal_id}{background_events_fade_factor} = $background_events_fade_factor; $new_calendars{$new_cal_id}{background_events_color} = $background_events_color; $new_calendars{$new_cal_id}{default_number_of_months} = $default_number_of_months; $new_calendars{$new_cal_id}{max_number_of_months} = $max_number_of_months; $new_calendars{$new_cal_id}{gmtime_diff} = $gmtime_diff; $new_calendars{$new_cal_id}{date_format} = $date_format; $new_calendars{$new_cal_id}{week_start_day} = $week_start_day; $new_calendars{$new_cal_id}{info_window_size} = $info_window_size; $new_calendars{$new_cal_id}{custom_template} = $custom_template; $new_calendars{$new_cal_id}{custom_stylesheet} = $custom_stylesheet; $new_calendars{$new_cal_id}{password} = $input_password; $new_calendars{$new_cal_id}{update_timestamp} = $rightnow; $new_calendars{$new_cal_id}{allow_remote_calendar_requests} = $allow_remote_calendar_requests; $new_calendars{$new_cal_id}{remote_calendar_requests_require_password} = $remote_calendar_requests_require_password; $new_calendars{$new_cal_id}{remote_calendar_requests_password} = $remote_calendar_requests_password; # local background calendars foreach $local_background_calendar (@local_background_calendars) {$new_calendars{$new_cal_id}{local_background_calendars}{$local_background_calendar} = 1;} # selectable calendars foreach $selectable_calendar (@selectable_calendars) {$new_calendars{$new_cal_id}{selectable_calendars}{$selectable_calendar} = 1;} } # check for refreshes! if ($cal_valid == 1) { if ($new_calendars{$new_cal_id}{title} eq $latest_new_calendar{title} && $new_calendars{$new_cal_id}{details} eq $latest_new_calendar{details} && $new_calendars{$new_cal_id}{link} eq $latest_new_calendar{link}) { $cal_valid = 0; push @results_messages, $lang{update_cal_dup}; } } if ($cal_valid == 1) #all checks successful, add calendar! { &add_new_calendar($new_cal_id); my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id}); $new_cal_details =~ s///; $new_cal_details =~ s/Link directly.+<\/a>//s; if ($new_calendar_request_notify ne "") { my $body = <$lang{add_cal_success3} p1 &send_email($new_calendar_request_notify, $reply_address, $reply_address, $lang{add_cal_email_notify2}, $body); } my $temp = $lang{add_cal_success1}; # add successful if ($add_edit_cal_action eq "edit") {$temp = $lang{add_cal_success4}}; # update successful $cal_add_results .= <

$temp

$new_cal_details

$lang{add_cal_success2}

p1 close FH; } else { push @results_messages, $lang{add_cal_fail1}; } } close FH; } # properly format errors & warnings my $message_results=""; foreach $results_message (@results_messages) { $results_message =~ s/(.*$lang{Warning})/$1<\/span>/i; $results_message =~ s/(.*$lang{Error})/$1<\/span>/i; $message_results .= "
  • $results_message
  • \n"; } $cal_add_results = "
      $message_results
    $cal_add_results"; } $return_text .=< $cal_add_results $cal_del_results p1 return $return_text; } #********************end add_edit_calendars code***************************** sub view_pending_calendars { my $return_text = ""; if ($q->param('approve_cal_button') eq "") #view pending calendars main screen { $cal_details =""; $shared_cal_select_size = scalar keys %calendars; $return_text.=< $lang{view_pending_calendars1}

    p1 if (scalar keys %new_calendars == 0) { $return_text.=< $lang{view_pending_calendars2}

    p1 } else { $return_text.=< p1 foreach $new_cal_id (keys %new_calendars) { my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id}); $new_cal_details =~ s///; $new_cal_details =~ s/Link directly.+<\/a>//s; #Link directly to this calendar:
    #$script_url/$name?cal_id=$calendar{id} $return_text.=< $new_cal_details

    $lang{view_pending_calendars3}

    $lang{view_pending_calendars4}

    p1 } $return_text.=<
    p1 } } else #view pending calendars approve/delete results screen { my @pending_calendars_to_delete; my @calendars_to_add; my @calendars_to_update; $cal_details =""; $shared_cal_select_size = scalar keys %calendars; $return_text.=< $lang{view_pending_calendars6}

    p1 #check password $input_password = crypt($q->param('main_password'), substr($q->param('main_password'), 0, 2)); { if ($input_password ne $master_password) { $return_text .=<
  • $lang{view_pending_calendars7}
  • p1 return $return_text; } } #go through each new calendar in the new calendars file--take appropriate action foreach $new_cal_id (keys %new_calendars) { my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id}); if ($q->param("new_cal_$new_cal_id") eq "approve") { #calculate new id # for the new calendar $max_cal_id+=1; foreach $cal_id (keys %calendars) { if ($calendars{$cal_id}{new_calendars_automatically_selectable} =~ /y/) { $calendars{$cal_id}{selectable_calendars}{$max_cal_id} = 1; push @calendars_to_update, $cal_id; } } $calendars{$max_cal_id} = $new_calendars{$new_cal_id}; $calendars{$max_cal_id}{id} = $max_cal_id; # make sure the calendar can select itself. if (scalar keys %{$calendars{$max_cal_id}{selectable_calendars}} > 0) {$calendars{$max_cal_id}{selectable_calendars}{$max_cal_id} = 1;} delete $new_calendars{$new_cal_id}; push @pending_calendars_to_delete, $new_cal_id; push @calendars_to_add, $max_cal_id; $approve_or_delete_result = $lang{view_pending_calendars8}; } elsif ($q->param("new_cal_$new_cal_id") eq "delete") { delete $new_calendars{$new_cal_id}; push @pending_calendars_to_delete, $new_cal_id; $approve_or_delete_result = $lang{view_pending_calendars9}; } else { $approve_or_delete_result = $lang{view_pending_calendars10}; } $new_cal_details =~ s///; $new_cal_details =~ s/Link directly.+<\/a>//s; $return_text .= <
    $new_cal_details

    $approve_or_delete_result
    p1 } &delete_pending_calendars(\@pending_calendars_to_delete); &add_calendars(\@calendars_to_add); &update_calendars(\@calendars_to_update); } $return_text.=< p1 return $return_text; } #********************end view_pending_calendars code***************************** sub do_calendar_list_view() { my $return_text = ""; my $temp1=""; my $temp2=""; if ($q->param('custom_calendar') != 1) { $temp1 .=<$prev_string p1 $temp2 .=<$next_string p1 } if ($cal_num_months> 1) { $cal_title_string .=< $temp1 $cal_title_string $temp2
    p1 if ($cal_or_list eq "list") #list view { $return_text .= &generate_list($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year); } else #calendar view { $return_text .= &generate_calendar($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year); } $return_text .=< p1 return $return_text; } ###############end do_calendar_list_view ################### sub add_edit_events() { my $temp=""; $html_output =~ s//\n$temp\n/; my $return_text = ""; $add_edit_event = "add" if ($add_edit_event eq ""); if ($q->param('add_event_button') eq "" && $q->param('del_event_button') eq "") #add event main screen { $add_edit_string = $lang{add_or_edit1}; $event_details =""; $event_start_date = $current_calendar{date_format}; if ($q->param('add_date_timestamp') eq "" || $q->param('add_date_timestamp') =~ /\D/) # no date supplied--generic add event { # no date supplied--generic add event if ($cal_start_year ne "") { $event_start_date =~ s/yy/$cal_start_year/; } else { $event_start_date =~ s/yy/$rightnow_year/; } } else # add event on a particular date -- calculate date { my @event_start_date_array = gmtime $q->param('add_date_timestamp'); my $mm = $event_start_date_array[4]+1; my $md = $event_start_date_array[3]; my $yy = $event_start_date_array[5]+1900; $event_start_date =~ s/mm/$mm/; $event_start_date =~ s/dd/$md/; $event_start_date =~ s/yy/$yy/; } $recur_end_date = $current_calendar{date_format}; $recur_end_date =~ s/mm/12/; $recur_end_date =~ s/dd/31/; $recur_end_date =~ s/yy/$rightnow_year/; $event_days = "1"; $event_icon = "blank"; my %current_event; my $unit_number_text=""; if ($add_edit_event eq "add") { $event_unit_number = ""; } elsif ($add_edit_event eq "edit") { $add_edit_string = $lang{add_or_edit2}; #select the appropriate event to edit %current_event = %{$events{$q->param('evt_id')}}; $current_cal_id=$current_event{cal_id}; %current_calendar = %{$calendars{$current_event{cal_id}}}; $cal_title=$calendars{$current_event{cal_id}}{title}; $event_name=$current_event{title}; $event_details=$current_event{details}; $event_start_date = $current_calendar{date_format}; my @temp_date = gmtime($current_event{start}); $temp_date[5] += 1900; $temp_date[4] += 1; $event_start_date =~ s/mm/$temp_date[4]/; $event_start_date =~ s/dd/$temp_date[3]/; $event_start_date =~ s/yy/$temp_date[5]/; $event_days=$current_event{days}; $event_icon = $current_event{icon}; $event_bgcolor = $current_event{bgcolor}; $event_unit_number = $current_event{unit_number}; $unit_number_text = $event_unit_number; $unit_number_text =~ s/(\d)//g; } $return_text .=<

    $add_edit_string

    $lang{fields_text1} $lang{fields_text2} $lang{fields_text3}
    p1 if ($add_edit_event eq "edit" || scalar keys %{$current_calendar{selectable_calendars}} == 0) # force event calendar { $return_text .=<
    $lang{event_calendar}
    $current_calendar{title}
    p1 } else # user can select event calendar { $return_text .=< $lang{event_calendar}
    $lang{help_on_this}

    $lang{help_on_this}  
    p1 $return_text .=<
    event icon
    p1 if ($unit_number_icons == 1) { $return_text .=< $unit_number_text
    p1 } $return_text .=<
    p1 $return_text .=<
    p1 } $return_text .=<
    $lang{recurring_event_edit1}
    $lang{recurring_event_change_all2}
    p1 } else { $return_text .=< p1 } else { $return_text .=< $lang{help_on_this}  
    $lang{recurrence_type}
    $lang{help_on_this}
    $lang{same_day_of_month}
    $lang{same_weekday} $lang{of_the_month}
    p1 my $temp =< p1 $lang{every_x_days} =~ s/###x###/$temp/; $return_text .=< $lang{every_x_days}
    p1 my $temp =< p1 $lang{every_x_weeks} =~ s/###x###/$temp/; $return_text .=< $lang{every_x_weeks}
    $lang{fit_into_year}
    $lang{help_on_this}
    $lang{every_momth}
    $lang{certain_months1}
    $lang{certain_months2}

    p1 } $return_text .=<
    $lang{preview_event1}

    $lang{preview_event2}

    $lang{preview_dates1}

    $lang{preview_dates2}

    p1 $return_text .=<
    p1 if ($q->param('add_edit_event') eq "edit") { $return_text .=<  
    $lang{add_event2_update}
    $lang{delete_event2}
    p1 } else { $return_text .=<  

    $lang{add_event2}


    p1 } $return_text .=< p1 } else #a user added/edited/deleted an event--do checks and perform resulting action { my @results_messages; my $recurring_event = $q->param('recurring_event'); my $all_in_series = $q->param('all_in_series'); #$debug_info .= "recurring_event_change_all: $all_in_series\n"; if ($q->param('evt_cal_id') ne "") { %current_calendar =%{$calendars{$q->param('evt_cal_id')}}; } # load (reload) all events (we have to write events beyond the default time window) if ($data_storage_mode == 0) { &load_events("all") unless ($loaded_all_events eq "1"); } if ($q->param('del_event_button') ne "") { #delete event. $del_valid=1; #check password. $input_password = crypt($q->param('evt_cal_password'), substr($q->param('evt_cal_password'), 0, 2)); if ($input_password ne $calendars{$current_event{cal_id}}{password} && $input_password ne $master_password) { $del_valid=0; push @results_messages, ($lang{update_event_err1}.$calendars{$current_event{cal_id}}{title}); } if (! defined $events{$current_event_id}) { $del_valid=0; push @results_messages, $lang{update_event_err2}; } if ($del_valid == 1) { #actually delete the event(s). if ($all_in_series ne "1") { &delete_event($current_event_id); $event_action_results .= <$lang{update_event_delete_successful}

    p1 } else { # get the ids of the events in the series. my @events_in_series = &get_events_in_series($q->param('series_id')); &delete_events(\@events_in_series); $event_action_results .= <$lang{update_event_delete_successful_recurring}

    p1 } } else { foreach $results_message (@results_messages) { $results_message =~ s/(.*$lang{Warning})/$1<\/span>/i; $results_message =~ s/(.*$lang{Error})/$1<\/span>/i; $message_results .= "
  • $results_message
  • \n"; } $event_action_results = "
      $message_results
    $event_action_results"; } } else { #check all input fields for validity my $event_valid = 1; my $event_id = $q->param('evt_id'); # only if editing. my $event_cal_id = $q->param('evt_cal_id'); my $event_cal_password = $q->param('evt_cal_password'); my $event_title = $q->param('evt_title'); my $event_icon = $q->param('evt_icon'); my $event_details = $q->param('evt_details'); my $event_unit_number = $q->param('unit_number'); my $event_bgcolor = $q->param('evt_bgcolor'); my $event_series_id = $q->param('series_id'); my $event_duration = 0; my $event_start_timestamp = 0; my $event_end_timestamp = 0; $recur_end_date = $q->param('recur_end_date'); my $recur_end_timestamp = 0; my $all_day_event = $q->param('all_day_event'); my $event_start_time = $q->param('evt_start_time'); my $event_end_time = $q->param('evt_end_time'); $event_start_date = $q->param('evt_start_date'); $event_days = $q->param('evt_days'); # Check data for legitimacy. # some of these checks might be a bit redundant. if ($event_cal_id eq "") { $event_valid=0; push @results_messages, $lang{update_event_err3}; } if ($event_title eq "") { $event_valid=0; push @results_messages, $lang{update_event_err4}; } if ($event_icon eq "") { $event_valid=0; push @results_messages, $lang{update_event_err5}; } if ($event_cal_password eq "") { $event_valid=0; push @results_messages, $lang{update_event_err6}; } $event_title =~ s/\r//g; # some browsers sneak these in $event_details =~ s/\r//g; # some browsers sneak these in #strip html if ($event_title =~ m/<(.*)>/) { my $temp = $event_title; $temp =~ s//>/g; push @results_messages, $lang{update_event_err7}; $event_title =~ s/<(.*)>//g; } # strip out all non-numeric information from unit number my $unit_number = $event_unit_number; $unit_number =~ s/\D//g; #check event calendar name against existing calendars if (!defined == $calendars{$event_cal_id}) { $event_valid=0; push @results_messages, $lang{update_event_err8}; } else { #check password $input_password = crypt($event_cal_password, substr($event_cal_password, 0, 2)); my $temp=$q->param("evt_cal_id"); if ($temp eq "" || $input_password ne $calendars{$temp}{password} && $input_password ne $master_password) { $event_valid=0; push @results_messages, ($lang{update_event_err1}."".$current_calendar{title}.""); } } # check dates if ($event_valid == 1) { my $results = &verify_date($event_start_date); if ($results ne "") { $event_valid=0; $results =~ s/(.+?)\n/
  • $1<\/li>\n/g; push @results_messages, "$lang{update_event_err9}
      $results
    " } if ($event_days eq "") { push @results_messages, "$lang{update_event_err9}
      $lang{date_verify_err2}
    " } if ($days =~ m/\D/ || $event_days <= 0) { push @results_messages, "$lang{update_event_err9}
      $lang{date_verify_err3}
    " } } # check recurring "repeat until" date if ($event_valid == 1) { @custom_months = $q->param('custom_months'); if ($recurring_event ne "" && $add_edit_event eq "add") { $results = &verify_date($recur_end_date); if ($results ne "") { $event_valid=0; $results =~ s/(.+?)\n/
  • $1<\/li>\n/g; push @results_messages, "$lang{update_event_err10}
      $results
    " } } } # check time if ($event_valid == 1 && $all_day_event ne "1") { my $results = &verify_time($event_start_time); if ($results ne "") { $event_valid=0; $results =~ s/(.+?)\n/
  • $1<\/li>\n/g; push @results_messages, "$lang{update_event_err14}
      $results
    " } my $results = &verify_time($event_end_time); if ($results ne "") { $event_valid=0; $results =~ s/(.+?)\n/
  • $1<\/li>\n/g; push @results_messages, "$lang{update_event_err15}
      $results
    " } } if ($event_valid == 1) { my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_calendar{date_format}); $start_mon--; # convert month to 0-11 format if ($all_day_event eq "1") { $event_start_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year); $event_end_timestamp = $event_start_timestamp + ($event_days * 86400) - 1; } else { $event_start_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year) + &time2seconds($event_start_time); $event_end_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year) + &time2seconds($event_end_time); $event_days = 1; } $event_duration = $event_end_timestamp - $event_start_timestamp; #if ($event_start_timestamp == $event_end_timestamp) # {$event_end_timestamp +=1;} # give all events a duration of at least 1 second if ($recurring_event ne "" && $add_edit_event eq "add") { my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recur_end_date, $current_calendar{date_format}); $recur_end_mon--; $recur_end_timestamp=timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year); } # display warning if start timestamp is before present date if ($event_start_timestamp < $rightnow-86400) { push @results_messages, $lang{update_event_err11}; } } # check for refreshes! if ($recurring_event eq "") { #$debug_info .= "comparing $latest_event{start} (event $latest_event_id) and $event_start_timestamp\n"; if ($latest_event{cal_id} eq $event_cal_id && $latest_event{start} eq $event_start_timestamp && $latest_event{end} eq $event_end_timestamp && $latest_event{days} eq $event_days && $latest_event{title} eq $event_title && $latest_event{details} eq $event_details && $latest_event{icon} eq $event_icon && $latest_event{bgcolor} eq $event_bgcolor && $latest_event{unit_number} eq $event_unit_number) { $event_valid=0; push @results_messages, $lang{update_event_err12}; } } else # recurring event refresh protection is a little trickier. { # it's currently not implemented } if ($add_edit_event eq "edit") { #check to make sure the event id matches some event in the data structure. #it always should, but we check anyway. if (!defined $events{$event_id}) { $event_valid=0; push @results_messages, $lang{update_event_err13}; } } # properly format errors & warnings $message_results=""; foreach $results_message (@results_messages) { $results_message =~ s/(.*$lang{Warning})/$1<\/span>/i; $results_message =~ s/(.*$lang{Error})/$1<\/span>/i; $message_results .= "
  • $results_message
  • \n"; } $event_action_results = "
      $message_results
    $event_action_results"; @results_message=(); if ($event_valid == 1) { #all checks successful, add/update event! $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}/g; $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}/g; $event_details_template =~ s/###delete event link###/$lang{event_details_delete_disable}/g; $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g; if ($add_edit_event eq "add") # add a new event { if ($recurring_event eq "") { my $new_event_id = $max_event_id + 1; # add event to %events data structure $events{$new_event_id} = {id => $new_event_id, cal_id => $event_cal_id, start => $event_start_timestamp, end => $event_end_timestamp, days => $event_days, title => $event_title, details => $event_details, icon => $event_icon, bgcolor => $event_bgcolor, unit_number => $event_unit_number, update_timestamp => $rightnow}; &add_event($new_event_id); $event_box_text .= &generate_event_details($events{$new_event_id}); $event_action_results .= <$lang{update_event_add_successful}

    $event_box_text p1 } else # recurring events loop { &load_events("all") unless $loaded_all_events; $new_series_id = $max_series_id + 1; my $date_text=""; my @recurring_events_timestamps = @{&calculate_recurring_events($event_start_timestamp,$recur_end_timestamp)}; my @recurring_event_ids = (); foreach $recurring_event_start_timestamp (@recurring_events_timestamps) { $max_event_id += 1; my $new_event_id = $max_event_id; my $recurring_event_end_timestamp = $recurring_event_start_timestamp + $event_duration; #if ($recurring_event_end_timestamp == $recurring_event_start_timestamp) # {$recurring_event_end_timestamp +=1;} # give all events a duration of at least 1 second $events{$new_event_id} = {id => $new_event_id, cal_id => $event_cal_id, start => $recurring_event_start_timestamp, end => $recurring_event_end_timestamp, days => $event_days, series_id => $new_series_id, title => $event_title, details => $event_details, icon => $event_icon, bgcolor => $event_bgcolor, unit_number => $event_unit_number, update_timestamp => $rightnow}; push @recurring_event_ids, $new_event_id; my $date_range = &nice_date_range_format($recurring_event_start_timestamp, $recurring_event_end_timestamp, "-"); $date_text .= <$date_range p1 } &add_events(\@recurring_event_ids); $event_box_text .= &generate_event_details($events{$max_event_id}); $event_action_results .= <$lang{update_event_add_successful_recurring}

      $date_text
    $event_box_text p1 } } elsif ($add_edit_event eq "edit") #if we need to replace an existing record { &load_events("all") unless $loaded_all_events; if ($recurring_event eq "" || $all_in_series ne "1") { $events{$event_id} = {id => $event_id, cal_id => $event_cal_id, start => $event_start_timestamp, end => $event_end_timestamp, days => $event_days, series_id => $event_series_id, title => $event_title, details => $event_details, icon => $event_icon, bgcolor => $event_bgcolor, unit_number => $event_unit_number, update_timestamp => $rightnow}; &update_event($event_id); $event_box_text .= &generate_event_details($events{$event_id}); $event_action_results .= <$lang{update_event_update_successful}

    p1 } else # update recurring events { #$debug_info .= "updating recurring event series\n"; # get the ids of the events in the series. my @events_in_series; foreach $event_id (keys %events) { my %event = %{$events{$event_id}}; #$debug_info .= "checking event $event_id series id $event{series_id} against ".$q->param('series_id')."\n"; if ($event{series_id} eq $q->param('series_id')) { #$debug_info .= "event in series: $event_id\n"; push @events_in_series, $event_id; my $recurring_event_end_timestamp = $event{start} + $event_duration; $events{$event_id} = {id => $event_id, cal_id => $event_cal_id, start => $event{start}, end => $recurring_event_end_timestamp, days => $event{days}, series_id => $event{series_id}, title => $event_title, details => $event_details, icon => $event_icon, bgcolor => $event_bgcolor, unit_number => $event_unit_number, update_timestamp => $rightnow}; } } &update_events(\@events_in_series); $event_action_results .= <$lang{update_event_update_successful_recurring}

    p1 } } } } } $return_text .=< $event_action_results p1 return $return_text; } #******************** end add_edit_events ***************************** sub IE_javascript { my $return_string=""; $return_string .=<
    $lang{context_menu_edit_event}
    $lang{context_menu_delete_event}
    p1 $event_contextmenu_text = '' unless $writable{events_file}; $event_contextmenu_text =~ s/\//\\\//g; $event_contextmenu_text =~ s/\n/\\n/g; $event_contextmenu_text =~ s/"/\\"/g; $return_string .= <
    $lang{add_event_on_this_day}
    p1 $day_contextmenu_text = '' unless $writable{events_file}; $day_contextmenu_text =~ s/\//\\\//g; $day_contextmenu_text =~ s/\n/\\n/g; $day_contextmenu_text =~ s/"/\\"/g; $return_string .= < $lang{delete_event}

    $lang{password}: p1 $delete_event_text =~ s/\//\\\//g; $delete_event_text =~ s/\n/\\n/g; $delete_event_text =~ s/"/\\"/g; $delete_series_text .=<$lang{recurring_event_delete_all2} p1 $delete_series_text =~ s/\//\\\//g; $delete_series_text =~ s/\n/\\n/g; $delete_series_text =~ s/"/\\"/g; $return_string .= <'); doc.write('$lang{delete_event}<\\/title>'); doc.write('<base target=\\"'+main_window_name+'\\">'); doc.write('<link rel=\\"stylesheet" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('<body onload=\\"document.delete_event_form.evt_cal_password.focus();\\">'); doc.write("$delete_event_text"); if (active_series_id) { doc.write("$delete_series_text"); doc.write('<input type=\\"hidden\\" name=\\"series_id\\" value=\\"'+active_series_id+'\\">'); } doc.write('<input type=\\"hidden\\" name=\\"evt_id\\" value=\\"'+active_event_id+'\\">'); doc.write('<br/><input type=\\"submit\\" value= \\"Delete\\">'); doc.write('<\\/form><\\/div>'); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function docjslib_getRealLeft(imgElem) { xPos = imgElem.offsetLeft; tempEl = imgElem.offsetParent; //alert("element " + imgElem.id + "\\nparent "+ tempEl.id); //alert("element " + imgElem + "\\nparent "+ tempEl); while (tempEl != null) { xPos += tempEl.offsetLeft; tempEl = tempEl.offsetParent; } return xPos; } function docjslib_getRealTop(imgElem) { yPos = imgElem.offsetTop; tempEl = imgElem.offsetParent; while (tempEl != null) { yPos += tempEl.offsetTop; tempEl = tempEl.offsetParent; } return yPos; } function removename(el, name) { var i, curList, newList; // Remove the given class name from the className property of the element. newList = new Array(); curList = el.className.split(" "); for (i = 0; i < curList.length; i++) if (curList[i] != name) newList.push(curList[i]); el.className = newList.join(" "); } p1 return $return_string; } #********************end common_javascript ********************** sub calendar_view_javascript { my ($events_start_timestamp, $events_end_timestamp) = @_; my $return_string=""; # generate pre-formatted html for each day-zoom view for each day on the # current calendar. This routine is a good example of one of the choices # made in the design of this site--gaining client-side processor cycles # at the expense of bandwidth. It would be possible to send the event details # in a javascript array or hash, and have the client's browser dynamically # genearate the appropriate html. But it should be much faster to perform # this operation on the server and simply ship html to the client. The idea is # to make the javascript processing as simple as possible, becuase javascript # is sloooow. And even with all that extra html text, each page should still be # less than 100k (not counting images) #generate pre-formatted html for each event view if ($current_calendar{preload_event_details} =~ /y/) { $return_string .= &generate_event_details_javascript($events_start_timestamp, $events_end_timestamp); } $return_string .=<<p1; var current_cell_id = -1; //line globals var num_lines=3; var source_x1=0; var source_y1=0; var target_obj=null; var line_color="\#000000"; var result=""; function do_on_load() { } function blink(el, times, onoff) { if (times==0) { if (onoff == 0 && document.getElementById(el).className.match(/blink/)) removename (document.getElementById(el),"blink"); if (onoff == 1 && !document.getElementById(el).className.match(/blink/)) document.getElementById(el).className += " blink"; return; } if (document.getElementById(el).className.match(/blink/)) removename (document.getElementById(el),"blink"); else document.getElementById(el).className += " blink"; setTimeout("blink('"+el+"',"+(times-1)+", "+onoff+")", 100); } function custom_calendar() { var info_window_x = window_x()-400; var info_window_y = window_y(); p1 $custom_form_text .=<<p1; <div class="cal_title"> $lang{custom_calendar_title} </div> <form action="$script_url/$name" method="POST"> <input type="hidden" name="custom_calendar" value="1"> <input type="hidden" name="theme_url" value="$theme_url"> <label for="custom_calendar_calendar" class="required_field"> $lang{custom_calendar_choose_calendar} </label> <br/> <select id="custom_calendar_calendar" name="custom_calendar_calendar"> p1 foreach $cal_id (sort {$a <=> $b} keys %calendars) { $custom_form_text .=<<p1; <option value = "$cal_id">$calendars{$cal_id}{title} p1 } $custom_form_text .=<<p1; </select> <br/><br/> <label for="custom_calendar_background_calendars" class="optional_field"> $lang{custom_calendar_choose_bg_calendar} </label> <br/> <select id="custom_calendar_background_calendars" name="custom_calendar_background_calendars" multiple size=6> p1 foreach $cal_id (sort {$a <=> $b} keys %calendars) { $custom_form_text .=<<p1; <option value = "$cal_id">$calendars{$cal_id}{title} p1 } $custom_form_text .=<<p1; </select> <br/><br/> p1 if ($cal_or_list eq "list") {$list_selected = "selected";} else {$cal_selected = "selected";} $custom_form_text .=<<p1; <label for="cal_or_list" class="required_field"> $lang{custom_calendar_cal_or_list} </label> <select id="cal_or_list" name="cal_or_list"> <option value="calendar" $cal_selected>$lang{controls_calendar} <option value="list" $list_selected>$lang{controls_list} </select> <br/><br/> <label for="cal_start_month" class="required_field"> $lang{custom_calendar_time_range} </label> <table class="layout"> <tr><td nowrap align=right> $lang{controls_start_month} </td><td nowrap> <select id="cal_start_month" name="cal_start_month"> p1 #list each month in the year $month_index=0; foreach $possible_month (@months) { if ($cal_start_month eq $month_index) { $custom_form_text .=<<p1; <option value="$month_index" selected>$possible_month p1 } else { $custom_form_text .=<<p1; <option value="$month_index">$possible_month p1 } $month_index++; } $custom_form_text .=<<p1; </select> <input name="cal_start_year" value = "$cal_start_year" size=4> </td></tr> <tr><td nowrap align=left colspan=2> $lang{controls_num_months} <input name="cal_num_months" value = "$cal_num_months" size=3> </td></tr> </table> <br/><br/> <input type=submit value = "$lang{custom_calendar_make_calendar}"> p1 $custom_form_text =~ s/\//\\\//g; $custom_form_text =~ s/\n/\\n/g; $custom_form_text =~ s/"/\\"/g; $return_string .=<<p1; info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=400,height=500"); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{custom_calendar_title}<\\/title>'); doc.write('<base target=\\"'+main_window_name+'\\">'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('<body>'); doc.write("$custom_form_text"); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function display_event(evt_id) { p1 # Here's another rare occurrence where Mozilla and IE 6+ are incompatible. # normally, this would be taken care of in the NS_javascript and IE_javascript # subroutines, but this is a special case. The javascript here is being stored # inside another javascript string, to be written to the details window if # an event is called. It's not being stored in perl at all, really. It just # looks that way. my $javascript_info = ""; if ($browser_type eq "IE") { $javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = document.body.clientWidth; opener.info_window_height = document.body.clientHeight; } //--> </script> p1 } else { $javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = this.outerWidth; opener.info_window_height = this.outerHeight; } //--> </script> p1 } $javascript_info =~ s/\//\\\//g; $javascript_info =~ s/\n/\\n/g; $javascript_info =~ s/"/\\"/g; $return_string .=<<p1; var info_window_x = window_x()-$info_window_width; var info_window_y = window_y(); if (evt_id.match(/^r/)) { var URL_string = remote_event_details[evt_id].url; info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); } else { p1 if ($current_calendar{preload_event_details} =~ /y/) { $return_string .=<<p1; var detail_string = event_details[evt_id].text; info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<head>'); doc.write('<title>$lang{event_details}<\\/title>'); doc.write('<base target=\\"'+main_window_name+'\\">'); doc.write('<\\/head>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('$javascript_info'); doc.write('<body class=\\"event_details_body\\" onResize=\\"javascript:do_onresize()\\">'); doc.write(detail_string); doc.write('<\\/body><\\/html>'); doc.close(); p1 } else { $return_string .=<<p1; var URL_string="$script_url/$name?view_event=1&evt_id="+evt_id; info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); p1 } $return_string .=<<p1; } info_window.focus(); } p1 return $return_string; } #***********************end calendar_view_javascript************************" sub add_edit_events_javascript { $return_string=""; my $javascript_info = ""; if ($browser_type eq "IE") { $javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = document.body.clientWidth; opener.info_window_height = document.body.clientHeight; } //--> </script> p1 } else { $javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = this.outerWidth; opener.info_window_height = this.outerHeight; } //--> </script> p1 } $javascript_info =~ s/\n/\\n/g; $javascript_info =~ s/"/\\"/g; $javascript_info =~ s/\//\\\//g; $return_string.=<<p1; var help_text=""; var info_window_x = window_x()-$info_window_width; var info_window_y = window_y(); // color select stuff var cs0 = new color_select(); cs0.setrgb("$current_event{bgcolor}"); // hook up the color select to the appropriate browser events. cs_hookup(); function cs_init() { cs0.sv_image="$graphics_url/sv_blend.png"; // initial values for position var temp = document.getElementById("color_select_icon0"); cs0.x = docjslib_getRealLeft(temp); cs0.y = docjslib_getRealTop(temp) + 22; // attach the page elements to the appropriate color select handles. cs0.color_select_box = document.getElementById("color_select_box0"); cs0.h_select_box = document.getElementById("h_select_box0"); cs0.sv_select_box = document.getElementById("sv_select_box0"); cs0.sv_select_box_bg = document.getElementById("sv_select_box_bg0"); cs0.color_box = document.getElementById("color_box0"); cs0.color_value_box = document.getElementById("color_value_box0"); cs0.hue_cursor = document.getElementById("hue_cursor0"); cs0.sv_crosshair_horiz_cursor = document.getElementById("sv_crosshair_horiz_cursor0"); cs0.sv_crosshair_vert_cursor = document.getElementById("sv_crosshair_vert_cursor0"); cs0.update_function = "color_menu0_update"; // NOTE-there are no () cs0.update_color_box(); //cs0.sethsv(); //alert ("cs init done!"); } function color_menu0_update(new_color) { document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.options.length-1].value = new_color; document.add_event_form.evt_bgcolor.style.background = new_color; document.getElementById("custom_evt_color").style.background = new_color; } function do_on_load() { if (!document.add_event_form.evt_bgcolor) return; for (i=0; i<document.add_event_form.evt_bgcolor.options.length; i++) document.add_event_form.evt_bgcolor[i].style.background = document.add_event_form.evt_bgcolor[i].value; update_bg_color_select_box(); } function show_help() { info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{help_box_title}<\\/title>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('$javascript_info'); doc.write('<body onResize=\\"javascript:do_onresize()\\">'); doc.write(help_text); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function update_bg_color_select_box() { // did the user just select custom? if (document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].text == "custom") { document.getElementById("color_select_icon0").style.visibility = "visible"; } else { document.getElementById("color_select_icon0").style.visibility = "hidden"; } // take focus off the select (in IE, making a selection highlights it in blue, so you cannot see the actual color you picked. Removing focus makes this go away) document.add_event_form.dummy.style.display='inline'; document.add_event_form.dummy.focus(); document.add_event_form.dummy.style.display='none'; if (!document.add_event_form.evt_bgcolor) return; document.add_event_form.evt_bgcolor.style.background = document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].value //document.add_event_form.evt_title.focus(); } function update_preview_icon() { var icon_preview_area = document.getElementById("icon_preview") icon_name = document.add_event_form.evt_icon.options[document.add_event_form.evt_icon.selectedIndex].value icon_preview_area.innerHTML = "<img src=\\"$icons_url/" + icon_name + "_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>" if (!document.add_event_form.unit_number) return; var unit_number_preview_area = document.getElementById("unit_number_preview") // remove non-numeric text from the string var unit_number = document.add_event_form.unit_number.value; unit_number = unit_number.replace(/[^0-9]/g, ""); // this next part might be really clever or really stupid (using a regex for something like this). // regardless, it's only one line, and that's nice. var unit_number_graphic_string = unit_number.replace(/([0-9])/g, "<img src=\\"$graphics_url/unit_number_patch_\$1_20x13.gif\\" border=\\"0\\" vspace=0 hspace=0>"); unit_number_preview_area.innerHTML = unit_number_graphic_string; document.add_event_form.unit_number.value = unit_number; // it would be nice if we could do things with the DOM model, as opposed to innerHTML, but // that would be crazy cumbersome. The following is a non-working stab at it. Maybe useful someday. //preview_area.nodeValue = "unit num"; //preview_area.appendChild(document.createTextNode("unit <img name=\\"event_icon\\" src=\\"$icons_url/eagle_medal_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>")); } function all_day_event_toggle(value) { var el0 = document.getElementById("all_day_event_toggle0"); el0.style.display=""; if (value) el0.style.display="none"; } function tab_show(tab_num) { if (tab_num == null) return; var elList, i; i=0; // update all tabs. while (document.getElementById("tab"+i) && i<100) { if (i == tab_num) { // If the tab is the new active tab, activate it. document.getElementById("tab"+i).className += " active"; document.getElementById("tab_area"+i).style.display="" document.getElementById("tab"+i).blur(); } else { // Otherwise, make sure the tab is deactivated. removename (document.getElementById("tab"+i),"active"); document.getElementById("tab_area"+i).style.display="none" } i++; } } function preview_event() { info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,width=300,height=200"); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{event_preview_title}<\\/title>'); doc.write('<body bgcolor=\\"#ffffff\\" style=\\"font-family:arial,helvetica\\">'); doc.write('<font size=5><font color=\\"0049df\\">$lang{generating_preview}<\\/font>'); doc.write('<\\/body><\\/html>'); doc.close(); document.add_event_form.special_action.value = "preview_event"; document.add_event_form.target = "info_window"; document.add_event_form.submit(); document.add_event_form.special_action.value = ""; document.add_event_form.target = ""; info_window.focus(); } function recur_toggle() { if (document.add_event_form.recurring_event.checked) { document.add_event_form.recurrence_type[0].disabled=false; document.add_event_form.recurrence_type[1].disabled=false; document.add_event_form.recurrence_type[2].disabled=false; document.add_event_form.recurrence_type[3].disabled=false; document.add_event_form.weekday_of_month_type.disabled=false; document.add_event_form.custom_months.disabled=false; document.add_event_form.year_fit_type[0].disabled=false; document.add_event_form.year_fit_type[1].disabled=false; document.add_event_form.custom_months.disabled=false; if (!document.add_event_form.recurrence_type[1].checked) document.add_event_form.weekday_of_month_type.disabled=true; if (document.add_event_form.year_fit_type[0].checked) document.add_event_form.custom_months.disabled=true; document.add_event_form.recur_end_date.disabled=false; } else { document.add_event_form.recurrence_type[0].disabled=true; document.add_event_form.recurrence_type[1].disabled=true; document.add_event_form.recurrence_type[2].disabled=true; document.add_event_form.recurrence_type[3].disabled=true; setTimeout("document.add_event_form.every_x_days.disabled=true",100); setTimeout("document.add_event_form.every_x_weeks.disabled=true",100); setTimeout("document.add_event_form.weekday_of_month_type.disabled=true",100); setTimeout("document.add_event_form.custom_months.disabled=true",100); document.add_event_form.year_fit_type[0].disabled=true; document.add_event_form.year_fit_type[1].disabled=true; document.add_event_form.custom_months.disabled=true; document.add_event_form.recur_end_date.disabled=true; } recurrence_type_update(); //alert(document.add_event_form.recurring_event.checked); } function recurrence_type_update(last) { document.add_event_form.weekday_of_month_type.disabled=true; document.add_event_form.every_x_days.disabled=true; document.add_event_form.every_x_weeks.disabled=true; if (document.add_event_form.recurrence_type[1].checked && !document.add_event_form.recurrence_type[1].disabled) { document.add_event_form.weekday_of_month_type.disabled=false; } if (document.add_event_form.recurrence_type[2].checked && !document.add_event_form.recurrence_type[2].disabled) { document.add_event_form.every_x_days.disabled=false; } if (document.add_event_form.recurrence_type[3].checked && !document.add_event_form.recurrence_type[3].disabled) { document.add_event_form.every_x_weeks.disabled=false; } if (!last) setTimeout("recurrence_type_update(true)",100); } function recur_edit_toggle() { if (document.add_event_form.all_in_series.checked) { document.add_event_form.add_event_button.value="$lang{recurring_event_update_all1}"; document.add_event_form.del_event_button.value="$lang{recurring_event_delete_all1}"; } else { document.add_event_form.add_event_button.value="$lang{update_event}"; document.add_event_form.del_event_button.value="$lang{delete_event1}"; } } function preview_dates() { var i = 0; var j = 0; var info_window_x = window_x()-$info_window_width; var info_window_y = window_y(); var evt_start_date = document.add_event_form.evt_start_date.value; var evt_days = document.add_event_form.evt_days.value; var recurring_event = ""; var every_x_days; var every_x_weeks; var recur_end_date; var recurrence_type = ""; var year_fit_type = ""; var weekday_of_month_type = ""; if (document.add_event_form.recur_end_date) { every_x_days = document.add_event_form.every_x_days.value; every_x_weeks = document.add_event_form.every_x_weeks.value; recur_end_date = document.add_event_form.recur_end_date.value; if (document.add_event_form.recurring_event.checked) recurring_event = document.add_event_form.recurring_event.value; for (i=0; i<document.add_event_form.recurrence_type.length; i++) if (document.add_event_form.recurrence_type[i].checked) recurrence_type = document.add_event_form.recurrence_type[i].value; for (i=0; i<document.add_event_form.year_fit_type.length; i++) if (document.add_event_form.year_fit_type[i].checked) year_fit_type = document.add_event_form.year_fit_type[i].value; if (document.add_event_form.weekday_of_month_type.selectedIndex > -1) weekday_of_month_type = document.add_event_form.weekday_of_month_type.options[document.add_event_form.weekday_of_month_type.selectedIndex].value var selects = new Array(); var custom_months = ""; if (document.add_event_form.custom_months.selectedIndex > -1) for (j=0, i=document.add_event_form.custom_months.selectedIndex; i<document.add_event_form.custom_months.options.length;i++) if (document.add_event_form.custom_months.options[i].selected) selects[j++] = document.add_event_form.custom_months.options[i].value; for (j=0;j<selects.length; j++) custom_months += selects[j] + ' '; } var URL_string="$script_url/$name?special_action=preview_date&evt_start_date="+evt_start_date+ "&evt_cal_id="+document.add_event_form.evt_cal_id.value+ "&recur_end_date="+recur_end_date+ "&recurring_event="+recurring_event+ "&recurrence_type="+recurrence_type+ "&year_fit_type="+year_fit_type+ "&every_x_days="+every_x_days+ "&every_x_weeks="+every_x_weeks+ "&weekday_of_month_type="+weekday_of_month_type+ "&custom_months="+custom_months+ "&evt_days="+evt_days; info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height"); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<head>'); doc.write('<title>$lang{event_preview_computing}<\\/title>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('<\\/head>'); doc.write('<body style=\\"font-family:arial;\\">'); doc.write('$lang{event_preview_computing}'); doc.write('<\\/body><\\/html>'); doc.close(); info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height"); info_window.focus(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_evt_calendar1} </div> <div class="help_box"> $lang{help_evt_calendar2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; function display_help(topic) { if (topic == "evt_cal_id") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_evt_title1} </div> <div class="help_box"> $lang{help_evt_title2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "evt_title") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_evt_details1} </div> <div class="help_box"> $lang{help_evt_details2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "evt_details") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_recurring_event1} </div> <div class="help_box"> $lang{help_recurring_event2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "recurring_event") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_recurrence_type1} </div> <div class="help_box"> $lang{help_recurrence_type2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "recurrence_type") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_fit_into_year1} </div> <div class="help_box"> $lang{help_fit_into_year2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "fit_into_year") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_evt_cal_password1} </div> <div class="help_box"> $lang{help_evt_cal_password2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "evt_cal_password") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_recurring_event_change_all1} </div> <div class="help_box"> $lang{help_recurring_event_change_all2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "recurring_event_change_all") { help_text="$help_text"; show_help(); } } p1 return $return_string } #********************end add_edit_events_javascript********************** sub add_edit_calendars_javascript { my $return_string = ""; $return_string.=<<p1; function set_merge_xml(merge_xml) { var results = merge_xml.match(/\\/remote_calendar>/g); //var num_merged_calendars = results.length; if (results) if (results.length > 1) document.getElementById("remote_background_calendars_status").innerHTML = results.length + " $lang{get_remote_calendar2_plural} $current_calendar{title}<br/>"; else document.getElementById("remote_background_calendars_status").innerHTML = results.length + " $lang{get_remote_calendar2_singular} $current_calendar{title}<br/>"; else document.getElementById("remote_background_calendars_status").innerHTML = "$lang{get_remote_calendar3}"; //for(var i =0; i < results.length; i++) // document.getElementById("remote_background_calendars_status").innerHTML +="calendar "+i+"<br/>"; document.update_cal_form.new_remote_calandars_xml.value = merge_xml; //alert (num_merged_calendars +" new calendars to merge!") //alert(merge_xml); } p1 my $popup_javascript_info = ""; if ($browser_type eq "IE") { $popup_javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = document.body.clientWidth; opener.info_window_height = document.body.clientHeight; } //--> </script> p1 } else { $popup_javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = this.outerWidth; opener.info_window_height = this.outerHeight; } //--> </script> p1 } $popup_javascript_info =~ s/\n/\\n/g; $popup_javascript_info =~ s/"/\\"/g; $popup_javascript_info =~ s/\//\\\//g; $return_string.=<<p1; function do_on_load() { update_remote_calendar_requests(); } p1 my $get_remote_calendars_html =<<p1; <br/> <form name="detect_remote_calendars" action="$script_url/$name" method="POST"> <input type="hidden" name="detect_remote_calendars" value="1"/> $lang{get_remote_calendars_url}<br/> <input name="remote_calendar_url" value="http://" style="width:90%;"> <br/> <input type="submit" value="Go!" style="width:5em;"> </form> p1 $get_remote_calendars_html =~ s/\n/\\n/g; $get_remote_calendars_html =~ s/"/\\"/g; $get_remote_calendars_html =~ s/\//\\\//g; $return_string.=<<p1; function get_remote_calendars() { info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{get_remote_calendars}<\\/title>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('$popup_javascript_info'); doc.write('<body onResize=\\"javascript:do_onresize()\\">'); doc.write("<div class=\\"info_box\\" style=\\"padding:5px;\\"><br\\/>"); doc.write('$get_remote_calendars_html'); doc.write("<\\/div>"); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function update_remote_calendar_requests() { if (!document.update_cal_form || !document.update_cal_form.allow_remote_calendar_requests) return; if (document.update_cal_form.allow_remote_calendar_requests.checked) { document.update_cal_form.remote_calendar_requests_require_password.disabled = false; if (document.update_cal_form.remote_calendar_requests_require_password.checked) document.update_cal_form.remote_calendar_requests_password.disabled = false; } } // color select stuff var cs0 = new color_select(); cs0.setrgb("$current_calendar{background_events_color}"); // hook up the color select to the appropriate browser events. cs_hookup(); function cs_init() { cs0.sv_image="$graphics_url/sv_blend.png"; // initial values for position var temp = document.getElementById("color_select_icon0"); cs0.x = docjslib_getRealLeft(temp); cs0.y = docjslib_getRealTop(temp) + 22; // attach the page elements to the appropriate color select handles. cs0.color_select_box = document.getElementById("color_select_box0"); cs0.h_select_box = document.getElementById("h_select_box0"); cs0.sv_select_box = document.getElementById("sv_select_box0"); cs0.sv_select_box_bg = document.getElementById("sv_select_box_bg0"); cs0.color_box = document.getElementById("color_box0"); cs0.color_value_box = document.getElementById("color_value_box0"); cs0.hue_cursor = document.getElementById("hue_cursor0"); cs0.sv_crosshair_horiz_cursor = document.getElementById("sv_crosshair_horiz_cursor0"); cs0.sv_crosshair_vert_cursor = document.getElementById("sv_crosshair_vert_cursor0"); cs0.update_function = "color_menu0_update"; // NOTE-there are no () cs0.update_color_box(); } function color_menu0_update(new_color) { document.update_cal_form.background_events_color.value = new_color; document.getElementById("bg_preview_e1").style.background = new_color; document.getElementById("bg_preview_e2").style.background = new_color; } function fade_preview() { document.getElementById("bg_preview_e1").style.background = fade("#ffffcc", (1+parseInt(document.update_cal_form.background_events_fade_factor.value))); document.getElementById("bg_preview_e2").style.background = fade("#ccffff", (1+parseInt(document.update_cal_form.background_events_fade_factor.value))); } function fade(color, fade_factor) { if (!color.match(/#([0-9]|[A-F]){6}/i)) // valid hex #color? return false; var rgb = hex2rgb(color.substring(1,7)); var hsv = rgb2hsv(rgb); hsv[1] = hsv[1] / fade_factor; var new_rgb = hsv2rgb(hsv); return "rgb("+new_rgb[0]+","+new_rgb[1]+","+new_rgb[2]+")"; } // end color_select stuff p1 $return_string.=<<p1; var help_text=""; var info_window_x = window_x()-$info_window_width; var info_window_y = window_y() + 200; function show_help() { info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{help_box_title}<\\/title>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('$popup_javascript_info'); doc.write('<body onResize=\\"javascript:do_onresize()\\">'); doc.write(help_text); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function preview_cal() { var cal_title = document.update_cal_form.cal_title.value var cal_link = document.update_cal_form.cal_link.value var cal_details = document.update_cal_form.cal_details.value; if (cal_title == "") { evt_label = "<span style=\\"color:#ff0000\\">$lang{preview_calendar_temp_title}<\\/span>"; add_disable = true; } // if (document.getElementById("preview_warning")) { document.getElementById("preview_warning").innerHTML=""; } info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{preview_calendar_title}<\\/title>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('$popup_javascript_info'); doc.write('<body onResize=\\"javascript:do_onresize()\\">'); doc.write("<div class=\\"info_box\\" style=\\"padding:5px;\\"><br/><div style=\\"white-space:nowrap;\\"><span class=\\"cal_title\\">"); doc.write("<a target=\\"_blank\\" href=\\""+cal_link+"\\">"+cal_title+"<\\/a><\\/span><\\/div><br/><div>"+cal_details+"<\\/div><\\/div>"); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function tab_show(tab_num) { if (tab_num == null) return; var elList, i; i=0; // update all tabs. while (document.getElementById("tab"+i) && i<100) { if (i == tab_num) { // If the tab is the new active tab, activate it. document.getElementById("tab"+i).className += " active"; document.getElementById("tab_area"+i).style.display="" document.getElementById("tab"+i).blur(); } else { // Otherwise, make sure the tab is deactivated. removename (document.getElementById("tab"+i),"active"); document.getElementById("tab_area"+i).style.display="none" } i++; } } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_title1} </div> <div class="help_box"> $lang{help_cal_title2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; function display_help(topic) { if (topic == "cal_title") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_link1} </div> <div class="help_box"> $lang{help_cal_link2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "cal_link") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_details1} </div> <div class="help_box"> $lang{help_cal_details2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "cal_details") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_new_cal_password1} </div> <div class="help_box"> $lang{help_new_cal_password2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "new_cal_password") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_current_cal_password1} </div> <div class="help_box"> $lang{help_current_cal_password2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "current_cal_password") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_change_cal_password1} </div> <div class="help_box"> $lang{help_change_cal_password2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "change_cal_password") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_selectable_calendars1} </div> <div class="help_box"> $lang{help_cal_selectable_calendars2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "selectable_calendars") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_background_calendars1} </div> <div class="help_box"> $lang{help_cal_background_calendars2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "cal_background_calendars") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_remote_background_calendars1} </div> <div class="help_box"> $lang{help_remote_background_calendars2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "help_remote_background_calendars") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_background_events_display_style1} </div> <div class="help_box"> $lang{help_cal_background_events_display_style2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "background_events_display_style") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_list_background_calendars_together1} </div> <div class="help_box"> $lang{help_cal_list_background_calendars_together2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "list_background_calendars_together") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_number_of_months1} </div> <div class="help_box"> $lang{help_cal_number_of_months2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "number_of_months") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_max_months1} </div> <div class="help_box"> $lang{help_cal_max_months2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "max_months") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_gmtime_diff1} </div> <div class="help_box"> $lang{help_cal_gmtime_diff2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "gmtime_diff") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_date_format1} </div> <div class="help_box"> $lang{help_cal_date_format2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "date_format") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_week_start_day1} </div> <div class="help_box"> $lang{help_cal_week_start_day2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "week_start_day") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_new_calendars_automatically_selectable1} </div> <div class="help_box"> $lang{help_cal_new_calendars_automatically_selectable2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "new_calendars_automatically_selectable") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_allow_remote_calendar_requests1} </div> <div class="help_box"> $lang{help_cal_allow_remote_calendar_requests2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "allow_remote_calendar_requests") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_remote_calendar_requests_password1} </div> <div class="help_box"> $lang{help_remote_calendar_requests_password2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "remote_calendar_requests_password") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_preload_event_details1} </div> <div class="help_box"> $lang{help_cal_preload_event_details2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "preload_event_details") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_popup_window_size1} </div> <div class="help_box"> $lang{help_cal_popup_window_size2} </div> p1 $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "popup_window_size") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_custom_stylesheet1} </div> <div class="help_box"> $lang{help_cal_custom_stylesheet2} </div> p1 $help_text =~ s/###css file###/$css_path/g; $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "custom_stylesheet") { help_text="$help_text"; show_help(); } p1 $help_text=<<p1; <div class="help_title"> $lang{help_cal_custom_template1} </div> <div class="help_box"> $lang{help_cal_custom_template2} </div> p1 $help_text =~ s/###template file###/$theme_url\/plans.template/g; $help_text =~ s/\n/\\n/g; $help_text =~ s/"/\\"/g; $help_text =~ s/'/\\'/g; $help_text =~ s/\//\\\//g; $return_string .=<<p1; if (topic == "custom_template") { help_text="$help_text"; show_help(); } p1 $return_string .=<<p1; } p1 return $return_string } #********************end add_edit_calendars_javascript********************** sub generate_calendar { my $return_text = ""; my $week_events = {}; my $week_slots = {}; my ($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year, $selected_events) = @_; #initialize loop variables my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year); my $cal_end_timestamp = find_end_of_month($cal_end_month, $cal_end_year); my $current_month = $cal_start_month; my $current_year = $cal_start_year; while ($current_year < $cal_end_year || ($current_year == $cal_end_year && $current_month <= $cal_end_month)) { foreach $key (keys %week_events) {delete $week_events{$key};} foreach $key (keys %week_slots) {delete $week_slots{$key};} #for calendars with multiple months, display the name of each month above the calendar if ($cal_num_months > 1) { $return_text .=<<p1; <p class="cal_month_title" style="padding:5px;"> $months[$current_month] $current_year </p> p1 } #calculate where to start the calendar (first sunday) #first, calculate what day of the week this month begins on #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); my $cal_month_start_date = timegm(0,0,0,1, $current_month, $current_year); my @cal_month_start_date_array = gmtime $cal_month_start_date; my $cal_start_day_offset = $cal_month_start_date_array[6] - $current_calendar{week_start_day}; if ($cal_start_day_offset < 0) { $cal_start_day_offset += 7; } my $cal_start_date = $cal_month_start_date - (86400 * $cal_start_day_offset); my @cal_start_date_array = gmtime $cal_start_date; my $cal_end_date = $cal_start_date + 86400*37; my $next_month = $current_month+1; if ($next_month == 12) { $next_month=0;} #cal_date keeps track of the date (in timestamp format) #as the calendar loop iterates through each day on the calendar page my $cal_date = $cal_start_date; my @cal_date_array = gmtime $cal_date; my %max_day_events; my %week_max_slots; #make a first pass through the month, assemble event week events structure: #week_events{week_index}{id} ={} #this hash has 4 keys--start_weekday, start_day, length and slot_order (slot_order will be calculated in the second pass) for ($l1=0;$cal_date_array[4] != $next_month;$l1++) #each calendar has 5 or 6 weeks { $week_start_timestamp = $cal_date; $week_end_timestamp = $week_start_timestamp + 604800; $max_day_events{$l1} = 0; @cal_date_array = gmtime $cal_date; foreach $event_id (keys %events) { my %event = %{$events{$event_id}}; #$debug_info .= "checking event $event_id ($event{start}, $event{end})\n"; #$debug_info .= "checking event $event_id ($event{start} - $event{end}) against week $l1 ($week_start_timestamp - $week_end_timestamp)\n"; if (time_overlap($event{start}, $event{end}, $week_start_timestamp, $week_end_timestamp)) { #$debug_info .= "event $event_id\n"; #$debug_info .= "event $event_id ($event{days} days) in week $l1\n"; #$debug_info .= "check passed!\n"; @event_date_array = gmtime $event{start}; $event_start_weekday = $event_date_array[6] - $current_calendar{week_start_day}; my $days_before_week_start = 0; my $days_after_week_end = 0; # the event might fall completely within the week boundary, or it # might overlap event begins or ends outside the week boundaries # (there are four possible cases): #the event both starts and ends outside this week if ($event{start} < $week_start_timestamp && $event{end} > $week_end_timestamp) { $week_events{$l1}{$event{id}}{start_weekday} = 0; $week_events{$l1}{$event{id}}{length} = 7; } #the event starts before this week and ends within it elsif ($event{start} < $week_start_timestamp) { $days_before_week_start = int(($week_start_timestamp - $event{start})/86400); $week_events{$l1}{$event{id}}{start_weekday} = 0; $week_events{$l1}{$event{id}}{length} = $event{days} - $days_before_week_start; } #the event starts within this week and ends after it elsif ($event{end} > $week_end_timestamp) { $days_after_week_end = int(($event{end} - $week_end_timestamp)/86400); $week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday; $week_events{$l1}{$event{id}}{length} = $event{days} - $days_after_week_end - 1; # <-- the -1 is necessary } #the event begins and ends within the week else { $week_events{$l1}{$event{id}}{length} = $event{days}; $week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday; } if ($week_events{$l1}{$event{id}}{start_weekday} < 0) { $week_events{$l1}{$event{id}}{start_weekday} += 7; } elsif ($week_events{$l1}{$event{id}}{start_weekday} > 6) { $week_events{$l1}{$event{id}}{start_weekday} -= 7; } } } $temp_debug_info = ""; $cal_date += 604800; # each day has at least two slots (the date, and a blank box beneath it) for ($l2=0;$l2<7;$l2++) { $week_slots{$l1}{$l2}{0}{width}=1; $week_slots{$l1}{$l2}{0}{depth}=1; $week_slots{$l1}{$l2}{1}{width}=1; $week_slots{$l1}{$l2}{1}{depth}=1; } #order the week_events #fill in the %slots data structure: # $week_slots{week_index}{day_index}{slot_index} # $width = colspan # $depth = rowspan # $spacer = 1 if spacer slot. # @ids = event ids # hey man, that's a sharp-lookin' sort you got there. foreach $week_event_id (sort { if ($week_events{$l1}{$b}{length} == $week_events{$l1}{$a}{length}) { if ($events{$b}{all_day_event} eq "1") {return 1;} else {return $events{$a}{start} <=> $events{$b}{start};} } else {return $week_events{$l1}{$b}{length} <=> $week_events{$l1}{$a}{length};} } keys %{$week_events{$l1}}) { #$debug_info .= "length: $week_events{$l1}{$week_event_id}{length} start: $events{$week_event_id}{start}\n"; $empty_slot = 0; #starting at 1 leaves a row of empty slots (row 0), where the calendar dates will go. for ($l4=1; $empty_slot != 1; $l4++) { $empty_slot = 1; #check each day of the week_event, to make sure the slot is empty for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++) { $day_index=$l2+$week_events{$l1}{$week_event_id}{start_weekday}; if (scalar @{$week_slots{$l1}{$day_index}{$l4}{ids}} > 0) { $empty_slot = 0; } } $slot_index=$l4; } $temp_debug_info .= "<br/>event: $week_event start weekday $week_events{$l1}{$week_event_id}{start_weekday} slot: $slot_index<br/>"; #fill up $week_slots with the new event (extend horizontally) for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++) { #$slots_in_row{$l1}{$slot_index}++; $day_index = $l2+$week_events{$l1}{$week_event_id}{start_weekday}; push @{$week_slots{$l1}{$day_index}{$slot_index}{ids}}, $week_event_id; if ($l2==0) # first slot gets the width {$week_slots{$l1}{$day_index}{$slot_index}{width} = $week_events{$l1}{$week_event_id}{length};} else # other slots get 0 for length (they get absorbed later) {$week_slots{$l1}{$day_index}{$slot_index}{width} = 0;} $week_slots{$l1}{$day_index}{$slot_index}{depth} = 1; } #keep track of the maximum number of slots each week has if ($slot_index > $week_max_slots{$l1}) { $week_max_slots{$l1} = $slot_index; $max_day_events{$l1} = $slot_index; } } # give all blank slots width and depth of 1 for ($l2=0;$l2<7;$l2++) { for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++) # for each slot { if ($week_slots{$l1}{$l2}{$l3}{depth} eq "" || $week_slots{$l1}{$l2}{$l3}{width} eq "") { $week_slots{$l1}{$l2}{$l3}{width}=1; $week_slots{$l1}{$l2}{$l3}{depth}=1; } } } #$debug_info .= "week $l1 day 0, slot 2: ".$week_slots{$l1}{0}{2}{ids}[0]."\n"; my $total_spacers=0; # insert spacer slots below multi-day events. for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++) # for each slot { my $inserted_spacers=0; for ($l2=0;$l2<7;$l2++) { #if ($l3 != 3) {next}; if ($week_slots{$l1}{$l2}{$l3}{width} > 1) #multi-day event, add spacers beneath { # create spacer row if ($inserted_spacers == 0) { # move everything else down and increment the number of rows $week_max_slots{$l1}++; for ($l4=0;$l4<7;$l4++) # insert blank slots { for ($l5=$week_max_slots{$l1};$l5>$l3+1;$l5--) # count backwards { $week_slots{$l1}{$l4}{$l5} = &deep_copy($week_slots{$l1}{$l4}{$l5-1}); } $week_slots{$l1}{$l4}{$l3+1}{width}=1; $week_slots{$l1}{$l4}{$l3+1}{depth}=1; $week_slots{$l1}{$l4}{$l3+1}{spacer}=0; $week_slots{$l1}{$l4}{$l3+1}{ids}=(); } $inserted_spacers=1 } # insert spacers into previously created row. for ($l4=$l2;$l4<$l2+$week_slots{$l1}{$l2}{$l3}{width};$l4++) { $week_slots{$l1}{$l4}{$l3+1}{spacer}=1; #$debug_info .= "inserted spacer into row: ".($l3+1).", column $l4, event ".($week_slots{$l1}{$l4}{$l3}{ids}[0])."\n"; $total_spacers++; } #$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n"; } } } #$debug_info .= "$total_spacers spacers inserted for week $l1.\n"; #$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n"; #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n"; # calculate slots in each row: #for ($l2=0;$l2<7;needed for pre-5.8.3 way of calculating trim. { for ($l3=1;$l3<$week_max_slots{$l1};$l3++) # for each slot { if ((scalar @{$week_slots{$l1}{$l2}{$l3}{ids}}) > 0 ) { $slots_in_row{$l1}{$l3} += $week_slots{$l1}{$l2}{$l3}{width}; #$debug_info .= "event in row $l1. Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n"; } if ($week_slots{$l1}{$l2}{$l3}{spacer} == 1) { $slots_in_row{$l1}{$l3}++; #$debug_info .= "spacer in row $l1. Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n"; } } } #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n"; #$slots_in_row{$l1}{$slot_index}++; # extend event slots vertically. for ($l2=0;$l2<7;$l2++) # for each day of the week { for ($l3=1;$l3<$week_max_slots{$l1};$l3++) # for each slot { if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0 && $week_slots{$l1}{$l2}{$l3}{width} > 0) # if this slot begins an event { my $start_slot = $l3+1; for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++) { #$debug_info .= "checking slot $l4 below event slot ($l2, $l3)\n"; #if ($week_slots{$l1}{$l2}{$l4}{width} == 0) # {next;} if (scalar @{$week_slots{$l1}{$l2}{$l4}{ids}} > 0 && $week_slots{$l1}{$l2}{$l4}{width} eq $week_slots{$l1}{$l2}{$l3}{width}) # another event below this one, with the same width. { #if ($l1 eq "4" && $l2 eq "4" && $l3 eq "2") # {$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";} #$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n"; #$debug_info .= "same-width event slot below week $l1, slot ($l2, $l3)\n"; $week_slots{$l1}{$l2}{$l4}{width}=0; $week_slots{$l1}{$l2}{$l4}{depth}=0; $week_slots{$l1}{$l2}{$l3}{depth}++; push @{$week_slots{$l1}{$l2}{$l3}{ids}}, @{$week_slots{$l1}{$l2}{$l4}{ids}}; #$slots_in_row{$l1}{$l4}--; } elsif ($week_slots{$l1}{$l2}{$l3}{width} == 1 && (scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}) == 0 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0) # blank slot below 1-slot wide event slot { #if ($l1 eq "4" && $l2 eq "4" && $l3 eq "2") # {$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";} #$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n"; #$debug_info .= "week $l1 slot ($l2, $l4) # ids:".scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}."\n"; #$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n"; $week_slots{$l1}{$l2}{$l4}{width}=0; $week_slots{$l1}{$l2}{$l4}{depth}=0; $week_slots{$l1}{$l2}{$l3}{depth}++; #$debug_info .= "week $l1, slot ($l2, $l3) depth: $week_slots{$l1}{$l2}{$l3}{depth} \n"; } else { #$debug_info .= "week $l1 slot ($l2, $l4) occupied. Finished attempting to extend slot $l3\n"; last; } } } } } #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n"; # extend blank slots vertically into other blank slots. for ($l2=0;$l2<7;$l2++) # for each day of the week { for ($l3=1;$l3<$week_max_slots{$l1};$l3++) # for each slot { if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0) {next;} if ($week_slots{$l1}{$l2}{$l3}{width} > 0 && $week_slots{$l1}{$l2}{$l3}{spacer} == 0) # if it's blank (but not a spacer) { my $start_slot = $l3+1; for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++) { if ($week_slots{$l1}{$l2}{$l4}{width} == 1 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0) { #$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n"; $week_slots{$l1}{$l2}{$l4}{width}=0; $week_slots{$l1}{$l2}{$l4}{depth}=0; $week_slots{$l1}{$l2}{$l3}{depth}++; } else {last;} } } } } #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n"; #$debug_info .= "week $l1 slot (4, 1) depth: $week_slots{$l1}{4}{1}{depth}\n"; #$debug_info .= "week $l1 slot (0, 1) width: $week_slots{$l1}{0}{1}{width}\n"; # yet another pass. trim vertical depth and re-calculate max_slots # calculate trim my $trim = 0; #$debug_info .= " week $l1 max slots: $week_max_slots{$l1}\n"; my $max_week_needed_slots=0; my %max_day_needed_slots; for ($l2=0;$l2<7;$l2++) # for each day of the week { my $found_single_day_event=0; for ($l3=1;$l3<=$week_max_slots{$l1};$l3++) { if ($week_slots{$l1}{$l2}{$l3}{width} > 1) # if multi-day, or a spacer { #$debug_info .= "week $l1, found multi-day event (day $l2, width $week_slots{$l1}{$l2}{$l3}{width})\n"; for ($l4=0;$l4<$week_slots{$l1}{$l2}{$l3}{width};$l4++) { #$debug_info .= "week $l1, adding needed slot to day ".($l2+$l4)."\n"; $max_day_needed_slots{$l2+$l4}++; } } elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0) { $max_day_needed_slots{$l2}++; #$debug_info .= "week $l1, found spacer (day $l2)\n"; } elsif (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0) # single-day event { $found_single_day_event=1; #$debug_info .= "week $l1, found single day event (day $l2)\n"; } } $max_day_needed_slots{$l2} += $found_single_day_event; } #$debug_info .= "week $l1, max_day_needed_slots: $max_day_needed_slots{0} $max_day_needed_slots{1} $max_day_needed_slots{2} $max_day_needed_slots{3} $max_day_needed_slots{4} $max_day_needed_slots{5} $max_day_needed_slots{6} $max_day_needed_slots{7}\n"; $max_week_needed_slots = max(values %max_day_needed_slots); #if ($max_day_needed_slots >$max_week_needed_slots) # {$max_week_needed_slots = $max_day_needed_slots;} #$debug_info .= "max needed slots for week $l1, $max_week_needed_slots\n"; my $trim = $week_max_slots{$l1} - $max_week_needed_slots; # apply trim #$debug_info .= "trim for week $l1, $trim\n"; for ($l2=0;$l2<7;$l2++) # for each day of the week { for ($l3=$week_max_slots{$l1};$l3>0;$l3--) # for each slot, counting backwards (upwards) { if ($week_slots{$l1}{$l2}{$l3}{depth} > 0) # blank or non-blank, with depth > 0 { #$debug_info .= "trimming week $l1, slot ($l2, $l3) by $trim\n"; $week_slots{$l1}{$l2}{$l3}{depth} = $week_slots{$l1}{$l2}{$l3}{depth} - $trim; last; } } } $week_max_slots{$l1} = $week_max_slots{$l1} - $trim; } # repeat for next week # print day names $return_text .=<<p1; <table class="calendar"> <tr> <td class="day_names">$weekday_sequence[0]</td> <td class="day_names">$weekday_sequence[1]</td> <td class="day_names">$weekday_sequence[2]</td> <td class="day_names">$weekday_sequence[3]</td> <td class="day_names">$weekday_sequence[4]</td> <td class="day_names">$weekday_sequence[5]</td> <td class="day_names">$weekday_sequence[6]</td> </tr> p1 #cal_date keeps track of the date (in timestamp format) #as the calendar loop iterates through each day on the calendar page $cal_date = $cal_start_date; @cal_date_array = gmtime $cal_date; #locked and loaded, data structures assembled--now it's time to kick it, calendar-style. for ($l1=0;$cal_date_array[4] != $next_month; $l1++) #each calendar has 5 or 6 weeks { my $last_week=0; my $timestamp_next_week = $cal_date+604800; my @timestamp_next_week_array = gmtime $timestamp_next_week; if ($timestamp_next_week_array[4] == $next_month) { $last_week = 1; } my $week_date_index = $cal_date; # draw the table! for ($l3=0;$l3<$week_max_slots{$l1}+1;$l3++) { $return_text .="<tr>"; $week_date_index = $cal_date; for ($l2=0;$l2<7;$l2++) # 7 days / week { @cal_date_array = gmtime $week_date_index; my $td_class = "day ".lc($day_names[$l2]); if ($cal_date_array[4] == $rightnow_month && $cal_date_array[3] == $rightnow_mday && $cal_date_array[5]+1900 == $rightnow_year) {$td_class .= " today";} #display date numbers differently, depending on whether they are #in the current month or not if ($cal_date_array[4] != $current_month) {$td_class .= " other_month";} #if ($l2 == $week_events{$l1}{$week_slots{$l1}{$l2}{$l3}{id}}{start_weekday} && $week_events{$l1}{$week_slots{$l1}{$l2}{$l3}{id}}{start_weekday} ne "") if ($l3 == 0) #if it's the top blank slot, put the date in there. { $td_style="border-bottom-width:0px;"; #display the cell differently if it is today. if ($cal_date_array[4] == $rightnow_month && $cal_date_array[3] == $rightnow_mday && $cal_date_array[5]+1900 == $rightnow_year) { # offset the date number a few pixels # (so it will be in the center of the red circle) # offset a bit more for a double-digit day number. # small touches are the difference between good and great :) my $date_div_style = ""; if ($rightnow_mday > 10) {$date_div_style = "text-indent: 11px;";} $return_text .=<<p1; <td class="$td_class" style="$td_style" oncontextmenu="return show_day_contextmenu(event, $week_date_index);"> <div class="date today" style="$date_div_style"><a id="today"></a>$cal_date_array[3]</div> </td> p1 } else { $return_text .=<<p1; <td class="$td_class" style="$td_style" oncontextmenu="return show_day_contextmenu(event, $week_date_index);"> <div class="date">$cal_date_array[3]</div> </td> p1 } } elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0) # spacer slot { my $spacer_class = "spacer"; if ($l3 == $week_max_slots{$l1}-1) { $spacer_class .= " bottom"; } $return_text .=<<p1; <td class="$td_class $spacer_class" style="$td_style" colspan=1 rowspan=1 oncontextmenu="return show_day_contextmenu(event, $week_date_index);"> </td> p1 } elsif ($week_slots{$l1}{$l2}{$l3}{width} != 0) # slot containing events { $num_cols = $week_slots{$l1}{$l2}{$l3}{width}; $num_rows = $week_slots{$l1}{$l2}{$l3}{depth}; if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0) { $td_style="border-top-width:0px;border-bottom-width:0px;"; #($l2,$l3) $num_cols\lx$num_rows $return_text .=<<p1; <td class="$td_class" style="$td_style" colspan=$num_cols rowspan=$num_rows oncontextmenu="return show_day_contextmenu(event, $week_date_index);"> p1 foreach $event_id (@{$week_slots{$l1}{$l2}{$l3}{ids}}) { my $event_bgcolor = $events{$event_id}{bgcolor}; my $event_box_class = "event_box"; if ($events{$event_id}{cal_id} != $current_calendar{id}) { $event_box_class .= " background"; if ($current_calendar{background_events_display_style} eq "single_color") {$event_bgcolor = $current_calendar{background_events_color};} elsif ($current_calendar{background_events_display_style} eq "faded") { # create "faded" look for background event my $faded_color = $events{$event_id}{bgcolor}; #convert rgb values from hex (00-FF) to decimal integer (0-255) my $r = hex substr $faded_color,1,2; my $g = hex substr $faded_color,3,2; my $b = hex substr $faded_color,5,2; #convert integer rgb values to hsv my @hsv_array = &rgb2hsv($r,$g,$b); #convert s and v from percentages to decimal $hsv_array[1] = $hsv_array[1]/100; $hsv_array[2] = $hsv_array[2]/100; #"fade" the color (decrease saturation) $hsv_array[1] = $hsv_array[1]/$current_calendar{background_events_fade_factor}; my @new_rgb_array = &hsv2rgb($hsv_array[0],$hsv_array[1],$hsv_array[2]); #convert back to hex $r = (sprintf ("%1.1X",$new_rgb_array[0])); $g = (sprintf ("%1.1X",$new_rgb_array[1])); $b = (sprintf ("%1.1X",$new_rgb_array[2])); #$debug_info .= "<table><tr><td>initial:$intial_values<br/>$hsv_values<br/>new:$new_rgb_values</td><td bgcolor=$events{$week_slots{$l1}{$l2}{$l3}{id}}{bgcolor}>color</td> <td bgcolor=$faded_color>faded color</td></tr></table><br/>\n"; $event_bgcolor = "#$r$g$b"; } } # handle icon my $icon_text = ""; my $unit_icon_text = ""; if ($events{$event_id}{unit_number} ne "") { $unit_icon_text = $events{$event_id}{unit_number}; $unit_icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" border="0" alt=\"\" vspace=0 hspace=0 style="vertical-align:middle;">/g; } if ($events{$event_id}{icon} ne "blank") { $icon_text = <<p1; <img align="bottom" src = "$icons_url/$events{$event_id}{icon}_16x16.gif" alt="" hspace=2 vspace=0> p1 } $icon_text = "$unit_icon_text$icon_text"; # context menu stuff my $event_context_menu_text=" oncontextmenu=\"return show_event_contextmenu(event, $event_id, '$event_bgcolor', '$events{$event_id}{series_id}');\""; if ($event_id =~ /\D/) {$event_context_menu_text=""} if ($week_slots{$l1}{$l2}{$l3}{width} == 1) { my $event_time = ""; if ($events{$event_id}{all_day_event} ne "1") { $event_time = &formatted_time($events{$event_id}{start},"hh:mm ampm")." - ".&formatted_time($events{$event_id}{end},"hh:mm ampm"); # if both times are am or pm, remove the first one (it's redundant!) $event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/; $event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/; $event_time = "<span class=\"event_time\">$event_time</span>"; } $return_text .=<<p1; <a href="javascript:display_event('$event_id');" class="$event_box_class" style="display:block;padding-left:29px;text-align:left;background-color:$event_bgcolor;cursor:pointer;cursor:hand;" $event_context_menu_text> <img src="$icons_url/$events{$event_id}{icon}_16x16.gif" style="margin-left:-22px;margin-right:5px;margin-bottom:-5px;" alt="">$unit_icon_text<span style="margin-left:5px;">$event_time $events{$event_id}{title}</span></a> p1 p1 } else { # handle the case where an event stretches across two days not because it's >24 hours # but because it crosses midnight. my $temp=""; my $event_time = ""; if ($events{$event_id}{all_day_event} ne "1") { #my $offset = int(100*($events{$event_id}{start} - $week_date_index)/(86400*$week_slots{$l1}{$l2}{$l3}{width})); #my $width = int(100*($events{$event_id}{end} - $events{$event_id}{start})/(86400*$week_slots{$l1}{$l2}{$l3}{width})); my $offset = 25; my $width = 50; $temp = "width:$width%;position:relative;left:$offset%;"; $event_time = &formatted_time($events{$event_id}{start},"hh:mm ampm")." - ".&formatted_time($events{$event_id}{end},"hh:mm ampm"); # if both times are am or pm, remove the first one (it's redundant!) $event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/; $event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/; $event_time = "<span class=\"event_time\">$event_time</span>"; } $return_text .=<<p1; <a href="javascript:display_event('$event_id');" class="$event_box_class" style="display:block;text-align:center;background-color:$event_bgcolor;cursor:pointer;cursor:hand;$temp" $event_context_menu_text> <img src="$icons_url/$events{$event_id}{icon}_16x16.gif" style="vertical-align:middle;margin-right:5px;" alt="">$unit_icon_text<span style="margin-left:5px;">$event_time $events{$event_id}{title}</span></a> p1 p1 } } # next event id $return_text .=<<p1; </td> p1 } elsif ($week_slots{$l1}{$l2}{$l3}{ids} eq "" && $week_slots{$l1}{$l2}{$l3}{width} > 0) # blank slot { $td_style="border-top-width:0px;border-bottom-width:0px;"; #($l2,$l3) blank $num_cols\lx$num_rows $return_text .=<<p1; <td class="$td_class" style="$td_style" colspan=$num_cols rowspan=$num_rows oncontextmenu="return show_day_contextmenu(event, $week_date_index);"> </td> p1 } } $week_date_index += 86400; } # next day #right border $return_text .=<<p1; </tr> p1 } # event slot index # this little trick is the cat's pajamas. It's another row of # table cells that cause each calendar day to come down a little # bit below the lowest event. It makes the calendar # look sharp. # Also, if the week has a small number of # events, we expand the height of the bottom cell. # This makes all the calendar cells look square, # which is the bee's knees. my $bottom_height_style = ""; if ($max_day_events{$l1} < 2) { my $height = (4-$max_day_events{$l1}) . "em"; # this algorithm was developed by guess & check #my $height = "100px"; # this algorithm was developed by guess & check $bottom_height_style = "line-height:$height;"; } $return_text .=<<p1; <tr style="$bottom_height_style"> p1 $week_date_index = $cal_date; for ($l2=0;$l2<7;$l2++) #each week has 7 days(!) { my $td_class = ""; @cal_date_array = gmtime $week_date_index; $td_class .= "day ".lc($day_names[$l2])." cell_bottom"; if ($cal_date_array[4] != $current_month) { $td_class .= " other_month"; } if ($cal_date_array[4] == $rightnow_month && $cal_date_array[3] == $rightnow_mday && $cal_date_array[5]+1900 == $rightnow_year) {$td_class .= " today";} $return_text .=<<p1; <td class="$td_class" style="line-height:5px;border-top-width:0px;$bottom_height_style" oncontextmenu="return show_day_contextmenu(event, $week_date_index);"> </td> p1 $week_date_index+=86400; } $return_text .=<<p1; </tr> p1 $cal_date+=604800; } $return_text .=<<p1; </table> <br style="page-break-after:always;"> p1 #increment to the next month--the method used #here is the most painless way of making #this work the right way in all cases. $current_month++; if ($current_month == 12) { $current_month=0; $current_year++; } } return $return_text; } #********************end generate_calendar subroutine********************** sub generate_list { my $return_text = ""; ($start_month, $start_year, $end_month, $end_year) = @_; #calculate where to start and end the list #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year); my $list_end_timestamp = &find_end_of_month($end_month, $end_year); #loop through all the events. Create an array of events which fall #within the current list view dates. foreach $event_id (keys %events) { if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) { if ($events{$event_id}{cal_id} eq $current_cal_id) {push @selected_cal_events, $event_id;} else {push @list_events, $event_id;} } } # take the results of the previous sort and create a # funky data structure (broken down according to the calendars currently # selected) # create hash to hold that data structure # each element of this hash will be an array. $shared_cal_events={}; #empty hash #fill up that hash foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) { foreach $event_id (@list_events) { if ($events{$event_id}{cal_id} eq $background_cal_id) {push @{$shared_cal_events{$background_cal_id}}, $event_id;} } } # initialize loop variables $current_month = $start_month; $current_year = $start_year; $return_text .=<<p1; p1 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) { my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year); my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year); $return_text .=<<p1; <div class="list_month_box"> p1 if ($cal_num_months> 1) { $return_text .=<<p1; $months[$current_month] $current_year p1 } $return_text .=<<p1; <ul class="list_cal_box" style="list-style-type:none;float:left;text-align:left;"> <li style="text-align:center;font-weight:bold;">$calendars{$current_cal_id}{title}</li> p1 #display events for selected calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) { %event = %{$events{$event_id}}; if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) { @event_start_timestamp_array = gmtime $event{start}; if ($event{days} == 1) { #single-day event $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]"; } else #multi-day event { @event_end_timestamp_array = gmtime $event{end}; if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4]) { $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]"; } else { $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $months_abv[$event_end_timestamp_array[4]] $event_end_timestamp_array[3]"; } } my $icon_text=""; my $unit_icon_text=""; if ($event{unit_number} ne "") { $icon_text = $event{unit_number}; $icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" style=\"vertical-align:middle;\" alt=\"\">/g; } if ($event{icon} eq "blank") { $icon_text .= "$unit_icon_text"; } else { $icon_text .= "$unit_icon_text<img src = \"$icons_url/$event{icon}_16x16.gif\" style=\"vertical-align:middle;\" alt=\"\">"; } my $event_context_menu_text=" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$events{$event_id}{series_id}');\""; if ($event_id =~ /\D/) {$event_context_menu_text=""} # event time my $event_time = ""; if ($events{$event_id}{all_day_event} ne "1") { $event_time = &formatted_time($events{$event_id}{start},"hh:mm ampm")." - ".&formatted_time($events{$event_id}{end},"hh:mm ampm"); # if both times are am or pm, remove the first one (it's redundant!) $event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/; $event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/; $event_time = "<span class=\"event_time\">$event_time</span>"; } $return_text .=<<p1; <li style="margin-top:10px;margin-bottom:4px;"$event_context_menu_text> <span class="small_note" style="border:0;vertical-align:middle;width:7em;white-space:nowrap;text-align:right;cursor:pointer;cursor:hand;" onclick="display_event('$event_id')"> $date_string </span> <a class="event_box" style="text-align:left;white-space:nowrap;margin-bottom:2px;background-color:$event{bgcolor};" href="javascript:display_event('$event{id}')"> $icon_text $event_time $event{title}</a> </li> p1 } } if ($current_calendar{list_background_calendars_together} ne "yes") { $return_text .=<<p1; </ul> p1 } foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) { if ($current_calendar{list_background_calendars_together} eq "no") { $return_text .=<<p1; <ul class="list_cal_box background" style="list-style-type:none;float:left;text-align:left;"> <li style="text-align:center;font-weight:bold;">$calendars{$background_cal_id}{title}</li> p1 } #list events for that calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) { %event = %{$events{$event_id}}; if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) { @event_start_timestamp_array = gmtime $event{start}; #if the event headline is longer than 30 characters, #split it into another line after the second word. if ($event{days} == 1) { #single-day event $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]"; } else #multi-day event { @event_end_timestamp_array = gmtime $event{end}; if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4]) { $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]"; } else { $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] - $months_abv[$event_end_timestamp_array[4]] $event_end_timestamp_array[3]"; } } my $icon_text=""; if ($event{unit_number} ne "") { $icon_text = $event{unit_number}; $icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" style=\"vertical-align:middle;\" alt=\"\" vspace=0>/g; } if ($event{icon} eq "blank") { $icon_text .= "$unit_icon_text"; } else { $icon_text .= "$unit_icon_text<img src = \"$icons_url/$event{icon}_16x16.gif\" style=\"vertical-align:middle;\" alt=\"\" vspace=0>"; } my $date_style="line-height:120%;"; if ($icon_text eq "") {$date_style="";} my $event_context_menu_text=" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$events{$event_id}{series_id}');\""; if ($event_id =~ /\D/) {$event_context_menu_text=""} $return_text .=<<p1; <li style="margin-top:10px;margin-bottom:4px;white-space:nowrap;" onclick="display_event('$event_id')" $event_context_menu_text> <span class="small_note" style="border:0;vertical-align:middle;width:7em;white-space:nowrap;text-align:right;cursor:pointer;cursor:hand;"> $date_string </span> <a class="event_box" style="text-align:left;white-space:nowrap;margin-bottom:2px;background-color:$event{bgcolor};" href="javascript:display_event('$event{id}')"> $icon_text $event{title}</a> </li> p1 } } if ($current_calendar{list_background_calendars_together} ne "yes") { $return_text .=<<p1; </ul> <br style="clear:both;"/> <!--needed because IE sucks--> p1 } } if ($current_calendar{list_background_calendars_together} eq "yes") { $return_text .=<<p1; </ul> p1 } $return_text .=<<p1; <br style="clear:both;"/> <!-- because IE sucks--> <br style="clear:both;"/> <!-- because IE sucks--> </div> <br style="clear:both;"/> <!-- because IE sucks--> <br style="clear:both;"/> <!-- because IE sucks--> p1 #increment to the next month--the method used #here is the most painless way of making #this work the right way in all cases. $current_month +=1; if ($current_month == 12) { $current_month=0; $current_year++; } } $return_text .=<<p1; p1 return $return_text; } #********************end generate_list subroutine********************** sub generate_event_details_javascript { my ($events_start_timestamp, $events_end_timestamp) = @_; my $return_string=""; my $num_events = 0; my $num_remote_events = 0; my $event_defs=""; my $remote_event_defs=""; $index=0; #loop through the events, check to see if they fall #within the current calendar month foreach $event_id (keys %events) { my %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$events_start_timestamp,$events_end_timestamp)) { if ($event_id =~ /^r/) { $num_remote_events++; $remote_event_defs .= <<p1; remote_event_details["$event_id"] = new Object; remote_event_details["$event_id"].url = "$event{remote_calendar}{url}?view_event=1&evt_id=$event{remote_event_id}"; p1 } else { $num_events++; my $event_details = &generate_event_details(\%event); $event_detail_text =<<p1; $event_details p1 #prepare event detail text to be stored in a javascript array $event_detail_text =~ s/\n/\\n/g; $event_detail_text =~ s/"/\\"/g; $event_detail_text =~ s/\//\\\//g; $event_defs .= <<p1; event_details[$event_id] = new Object; event_details[$event_id].id = "$event_id"; event_details[$event_id].text = "$event_detail_text"; p1 $index++; } } } $return_string .=<<p1; var remote_event_details = new Array($num_remote_events); $remote_event_defs var event_details = new Array($num_events); $event_defs p1 return $return_string; } #********************end generate_event_details_javascript subroutine********************** sub cal_info_view_javascript { my $return_string =""; $return_string .= &generate_cal_details_javascript(); my $javascript_info = ""; if ($browser_type eq "IE") { $javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = document.body.clientWidth; opener.info_window_height = document.body.clientHeight; } //--> </script> p1 } else { $javascript_info .=<<p1; <script type="text/javascript" ><!-- function do_onresize() { opener.info_window_width = this.outerWidth; opener.info_window_height = this.outerHeight; } //--> </script> p1 } $javascript_info =~ s/\n/\\n/g; $javascript_info =~ s/"/\\"/g; $javascript_info =~ s/\//\\\//g; $return_string .=<<p1; function display_cal_info(cal_id) { if (cal_id == "") { return; } info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height); doc = info_window.document; doc.open('text/html'); doc.write('<html>'); doc.write('<title>$lang{calendar_details}<\\/title>'); doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>'); doc.write('<base target=\\"'+main_window_name+'\\">'); doc.write('$javascript_info'); doc.write('<body onResize=\\"javascript:do_onresize()\\">'); doc.write(cal_details[cal_id].text); doc.write('<\\/body><\\/html>'); doc.close(); info_window.focus(); } function do_on_load() { } p1 return $return_string; } #********************end cal_view_inf0_javascript subroutine********************** sub generate_cal_details() { my ($calendar_ref) = @_; my %calendar = %{$calendar_ref}; my $return_text = <<p1; <div class="cal_title"> $calendar{title} </div> <div> $calendar{details} </div> p1 $writable{calendar_file} and $return_text .= <<p1; <div style="white-space:nowrap;"> <span class="small_note"> <a href="$script_url/$name?active_tab=2&add_edit_cal_action=edit&cal_id=$calendar{id}">$lang{calendar_add_edit}</a> </span> </div> p1 $return_text .= <<p1; <div style="white-space:nowrap;margin-top:2em;"> <span class="small_note"> $lang{calendar_direct_link}<br/> <a href="$script_url/$name?cal_id=$calendar{id}">$script_url/$name?cal_id=$calendar{id}</a> </span> </div> p1 return $return_text; } sub generate_cal_details_javascript() { my $return_string =""; my $cal_detail_text = ""; foreach $cal_id (sort {$a <=> $b} keys %calendars) { $cal_detail_text = &generate_cal_details($calendars{$cal_id}); $cal_detail_text =~ s/\n/\\n/g; #$cal_detail_text =~ s/\n/adsf/g; $cal_detail_text =~ s/"/\\"/g; $cal_detail_text =~ s/\//\\\//g; $cal_defs .=<<p1; cal_details[$cal_id] = new Object; cal_details[$cal_id].text = "$cal_detail_text"; p1 } $num_calendars = scalar keys %calendars; $return_string .=<<p1; var cal_details = new Array($num_calendars); // array to hold calendar details $cal_defs p1 return $return_string; } #********************end generate_cal_details_javascript subroutine********************** sub csv_file { ($start_month, $start_year, $end_month, $end_year) = @_; #calculate where to start and end the list #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year); my $list_end_timestamp = &find_end_of_month($end_month, $end_year); #@cal_month_start_date_array = gmtime $cal_month_start_date; #loop through all the events. Create an array of events which fall #within the current calendar view dates. foreach $event_id (keys %events) { my %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$list_start_timestamp,$list_end_timestamp)) { if ($event{cal_id} eq $current_cal_id) {push @selected_cal_events, $event_id;} else {push @list_events, $event_id;} } } #take the results of the previous sort and arrange them into a #funky data structure (broken down according to the calendars currently #selected) #create hash to hold that data structure #each element of this hash will be an array. $shared_cal_events={}; #empty hash #fill up that hash foreach $background_cal_id (keys %{$calendars{$current_cal_id}{local_background_calendars}}) { foreach $event_id (@list_events) { if ($events{$event_id}{cal_id} eq $background_cal_id) {push @{$shared_cal_events{$background_cal_id}}, $event_id;} } } $html_output =<<p1; Cache-control: no-cache,no-store,private Content-disposition: filename="events.csv" Content-Type: text/plain; charset=$lang{charset}\n\n p1 #initialize loop variables #$current_timestamp = $list_start_timestamp; $current_month = $start_month; $current_year = $start_year; $html_output .=<<p1; "Subject","Start Date","Start Time","End Date","End Time","All day event","Reminder on/off","Reminder Date","Reminder Time","Meeting Organizer","Required Attendees","Optional Attendees","Meeting Resources","Billing Information","Categories","Description","Location","Mileage","Priority","Private","Sensitivity","Show time as" p1 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) { my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year); my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year); #display events for selected calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) { my %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) { my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})"; @event_start_timestamp_array = gmtime $event{start}; my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900); my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]); @event_end_timestamp_array = gmtime $event{end}; my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900); my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]); my $csv_description = $event{details}; $csv_description =~ s/"/""/g; $csv_description =~ s/\n/\\n/g; if ($event{days} != 1) { @event_end_timestamp_array = gmtime $event{end}; $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900); } $html_output .=<<p1; "$csv_subject","$csv_start_date","$csv_start_time",$csv_end_date,"$csv_end_time","True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1" p1 } } foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) { #list events for that calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) { my %event = %{$events{$event_id}}; if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) { my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})"; @event_start_timestamp_array = gmtime $event{start}; my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900); my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]); @event_end_timestamp_array = gmtime $event{end}; my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900); my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]); my $csv_description = $event{details}; $csv_description =~ s/"/""/g; $csv_description =~ s/\n/\\n/g; $csv_description =~ s/"/""/g; $csv_description =~ s/\n/\\n/g; if ($event{days} != 1) { @event_end_timestamp_array = gmtime $event{end}; $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900); } $html_output .=<<p1; "$csv_subject","$csv_start_date","$csv_start_time",$csv_end_date,"$csv_end_time","True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1" p1 } } } #increment to the next month--the method used #here is the most painless way of making #this work the right way in all cases. $current_month +=1; if ($current_month == 12) { $current_month=0; $current_year++; } } $html_output .= $debug_info; print $html_output; } sub vcalendar_export_cal { ($start_month, $start_year, $end_month, $end_year) = @_; #calculate where to start and end the list #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year); my $list_end_timestamp = &find_end_of_month($end_month, $end_year); #@cal_month_start_date_array = gmtime $cal_month_start_date; #loop through all the events. Create an array of events which fall #within the current calendar view dates. foreach $event_id (keys %events) { my %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$list_start_timestamp,$list_end_timestamp)) { if ($event{cal_id} eq $current_cal_id) {push @selected_cal_events, $event_id;} else {push @list_events, $event_id;} } } #take the results of the previous sort and arrange them into a #funky data structure (broken down according to the calendars currently #selected) #create hash to hold that data structure #each element of this hash will be an array. $shared_cal_events={}; #empty hash #fill up that hash foreach $background_cal_id (keys %{$calendars{$current_cal_id}{local_background_calendars}}) { foreach $event_id (@list_events) { if ($events{$event_id}{cal_id} eq $background_cal_id) {push @{$shared_cal_events{$background_cal_id}}, $event_id;} } } my $csv_string = <<p1; p1 $html_output =<<p1; Cache-control: no-cache,no-store,private Content-Type: text/csv; charset=$lang{charset} Content-disposition: filename="events.csv" p1 #initialize loop variables #$current_timestamp = $list_start_timestamp; $current_month = $start_month; $current_year = $start_year; $html_output .=<<p1; CSV datebook: Category, Private, Description, Note, Event, Begin, End, Alarm, Advance, Advance Units, Repeat Type, Repeat Forever, Repeat End, Repeat Frequency, Repeat Day, Repeat Days, Week Start, Number of Exceptions, Exceptions p1 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) { my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year); my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year); #display events for selected calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) { my %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) { my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})"; @event_start_timestamp_array = gmtime $event{start}; my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900); my $csv_end_date = $csv_start_date; my $csv_description = $event{details}; $csv_description =~ s/"/""/g; $csv_description =~ s/\n/\\n/g; if ($event{days} != 1) { @event_end_timestamp_array = gmtime $event{end}; $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900); } $html_output .= &event2vcal(\%event)."\n"; } } foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) { #list events for that calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) { my %event = %{$events{$event_id}}; if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) { my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})"; @event_start_timestamp_array = gmtime $event{start}; my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900); my $csv_end_date = $csv_start_date; my $csv_description = $event{details}; $csv_description =~ s/"/""/g; $csv_description =~ s/\n/\\n/g; if ($event{days} != 1) { @event_end_timestamp_array = gmtime $event{end}; $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900); } $html_output .= &event2vcal(\%event)."\n"; } } } #increment to the next month--the method used #here is the most painless way of making #this work the right way in all cases. $current_month +=1; if ($current_month == 12) { $current_month=0; $current_year++; } } $html_output .= $debug_info; print $html_output; } sub ascii_text_cal { ($start_month, $start_year, $end_month, $end_year) = @_; #calculate where to start and end the list #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year); my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year); my $list_end_timestamp = &find_end_of_month($end_month, $end_year); #@cal_month_start_date_array = gmtime $cal_month_start_date; #loop through all the events. Create an array of events which fall #within the current calendar view dates. foreach $event_id (keys %events) { if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) { if ($events{$event_id}{cal_id} eq $current_cal_id) {push @selected_cal_events, $event_id;} else {push @list_events, $event_id;} } } #take the results of the previous sort and arrange them into a #funky data structure (broken down according to the calendars currently #selected) #create hash to hold that data structure #each element of this hash will be an array. $shared_cal_events={}; #empty hash #fill up that hash foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) { foreach $event_id (@list_events) { if ($events{$event_id}{cal_id} eq $background_cal_id) {push @{$shared_cal_events{$background_cal_id}}, $event_id;} } } $html_output =<<p1; Cache-control: no-cache,no-store,private Content-Type: text/plain; charset=$lang{charset}\n\n p1 #initialize loop variables #$current_timestamp = $list_start_timestamp; $current_month = $start_month; $current_year = $start_year; while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) { my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year); my $current_month_end_timestamp = &find_end_of_month($current_month,$current_year); $html_output .=<<p1; ******************************************* $months[$current_month] $current_year ******************************************* * $current_calendar{title} p1 #display events for selected calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) { %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) { @event_start_timestamp_array = gmtime $event{start}; my $event_time = ""; if ($event{days} == 1) { #single-day event $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]"; if ($event{all_day_event} ne "1") { $event_time = &formatted_time($event{start},"hh:mm ampm")." - ".&formatted_time($event{end},"hh:mm ampm"); # if both times are am or pm, remove the first one (it's redundant!) $event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/; $event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/; $event_time = " ($event_time)"; } } else #multi-day event { $date_string = &nice_date_range_format($event{start}, $event{end}, "-"); } my $event_details = $event{details}; $event_details =~ s/\n\s+/\n/g; $event_details =~ s/\n{2,}/\n/g; chomp $event_details; #indent each line of the details $event_details =~ s/\n/\n /g; $html_output .=" $date_string$event_time: $event{title}\n"; if ($event_details ne "") { $html_output .= " $event_details\n\n"; } } } foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) { $html_output .=<<p1; * $calendars{$background_cal_id}{title} p1 #list events for that calendar foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) { my %event = %{$events{$event_id}}; if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) { @event_start_timestamp_array = gmtime $event{start}; my $event_time = ""; if ($event{days} == 1) { #single-day event $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]"; if ($event{all_day_event} ne "1") { $event_time = &formatted_time($event{start},"hh:mm ampm")." - ".&formatted_time($event{end},"hh:mm ampm"); # if both times are am or pm, remove the first one (it's redundant!) $event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/; $event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/; $event_time = " ($event_time)"; } } else #multi-day event { $date_string = &nice_date_range_format($event{start}, $event{end}, "-"); } my $event_details = $event{details}; $event_details =~ s/\n\s+/\n/g; $event_details =~ s/\n{2,}/\n/g; chomp $event_details; #indent each line of the details $event_details =~ s/\n/\n /g; $html_output .=" $date_string$event_time: $event{title}\n"; if ($event_details ne "") { $html_output .= " $event_details\n\n"; } $html_output .=<<p1; $date_string: $event{title} p1 } } } #increment to the next month--the method used #here is the most painless way of making #this work the right way in all cases. $current_month +=1; if ($current_month == 12) { $current_month=0; $current_year++; } } $html_output .= $debug_info; print $html_output; } #********************end ascii_text_cal subroutine********************** sub ascii_text_event { $html_output =<<p1; Cache-control: no-cache,no-store,private Content-Type: text/plain; charset=$lang{charset}\n\n p1 my @event_start_timestamp_array = gmtime $current_event{start}; my $date_string=""; my $event_time = ""; if ($current_event{days} == 1) { #single-day event $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]"; if ($current_event{all_day_event} ne "1") { $event_time = &formatted_time($current_event{start},"hh:mm ampm")." - ".&formatted_time($current_event{end},"hh:mm ampm"); # if both times are am or pm, remove the first one (it's redundant!) $event_time =~ s/(.*) $lang{am}(.*$lang{am}.*)/$1$2/; $event_time =~ s/(.*) $lang{pm}(.*$lang{pm}.*)/$1$2/; $event_time = "($event_time)"; } } else #multi-day event { $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, "-"); } my $event_details = $current_event{details}; $event_details =~ s/\n\s+/\n/g; $event_details =~ s/\n{2,}/\n/g; chomp $event_details; #indent each line of the details $event_details =~ s/\n/\n /g; $html_output .=" $date_string$event_time: $current_event{title}\n"; if ($event_details ne "") { $html_output .= " $event_details\n\n"; } $html_output .= $debug_info; print $html_output; } #********************end ascii_text_event subroutine********************** sub icalendar_export_event # only for 1 event { # when exporting to outlook, plans uses the vcalendar standard. # (http://www.imc.org/rfc2445) # This standard is horribly supported by MS outlook (outlook 2000, at the # time of this writing. Outlook refuses to correctly interpret the # date-time strings in the following ways: # 1. If the date-time parameter does not specify a time (only a date), do you # think outlook sets its "all-day event" flag? Nope. It just assumes the # event occurs at 000000 hours (12 midnight). # 2. if no time zone is specified, the date-time string is supposed to be # interpreted as if it applied to the *current* timezone the user's computer # is in (according to the standard). Do you think outlook does this? Nope. # If no timezone is specified, outlook assumes the time zone is GMT. As if this # weren't enough, outlook "helpfully" adjusts the time to the user's time zone. # Depending on how far a user is from GMT, this may cause the day to change. # Since there's no way to predict what time zone a user is in, it is impossible # to compensate on the server side for outlook's stupidity. The workaround is # to generate event times for each event (even though this is misleading because # the events are all-day events), and force all the event times to 12 noon. # This puts them as far from the previous and next days as possible, giving the # least chance for outlook to screw up the day when it does its adjustment. my $ical_string = &event2ical(\%current_event); $ical_string_length = length $ical_string; #Content-type: text/plain #Last-modified: Wed, 30 Jan 2002 22:43:12 GMT $html_output =<<p1; Content-type: text/x-vcalendar Content-length: $ical_string_length Content-disposition: filename="event.ics" Accept-ranges: bytes $ical_string p1 print $html_output; } #********************end vcalendar_export subroutine********************** sub vcalendar_export_event # only for 1 event { my $csv_string = <<p1; CSV datebook: Category, Private, Description, Note, Event, Begin, End, Alarm, Advance, Advance Units, Repeat Type, Repeat Forever, Repeat End, Repeat Frequency, Repeat Day, Repeat Days, Week Start, Number of Exceptions, Exceptions p1 $csv_string .= &event2vcal(\%current_event); $csv_string_length = length $csv_string; #my $last_modified = &formatted_time($rightnow, "md mn yy hh:mm:ss GMT"); #Last-modified: $last_modified #Content-type: text/plain $html_output =<<p1; Content-type: text/vcs Content-length: $csv_string_length Content-disposition: filename="event.vcs" Accept-ranges: bytes $csv_string p1 print $html_output; } #********************end vcalendar_export_event subroutine********************** sub calculate_recurring_events { my ($start_timestamp, $recur_end_timestamp) = @_; my @recurring_events_array = (); my @timestamp_array = gmtime $start_timestamp; #$debug_info .= "start timestamp: $start_timestamp\n"; #foreach $custom_month (@custom_months) # {$debug_info .= "custom month: $custom_month\n";} #my $start_timestamp = $start_timestamp+50; #calculate the weekday_in_month_count for the start timestamp # (is it the first tuesday? second saturday? This is required for # things to work right. $real_year = 1900 + $timestamp_array[5]; $temp_start_timestamp = timegm(0,0,0,1,$timestamp_array[4],$real_year); @temp_start_timestamp_array = gmtime($temp_start_timestamp); # $debug_info .= <<p1; #start timestamp: $start_timestamp<br/> #end timestamp: $recur_end_timestamp<br/> #the start timestamp ($months[$timestamp_array[4]] $timestamp_array[3], $real_year) <br/> #the temp start timestamp ($months[$temp_start_timestamp_array[4]] $temp_start_timestamp_array[3], $temp_start_timestamp_array[5]) <br/> #p1 my $weekday_in_month_count = 0; #figure out what weekday of the month the start timestamp is for (;$temp_start_timestamp < $start_timestamp;$temp_start_timestamp+=86400) { @temp_start_timestamp_array = gmtime($temp_start_timestamp); if ($temp_start_timestamp_array[6] == $timestamp_array[6]) { $weekday_in_month_count++; } } #this must be done, or the week-of-month recurring dates will be hosed #@temp_array = gmtime $start_timestamp; #my $current_month = $temp_array[4]; my $last_week=0; # The recurring event algorithm loops through each day in the timeframe # and tests its validity against the recurrence parameters. # These tests take the form of "assumed valid unless proven otherwise" # Doing it this way lets the various recurrence type tests operate # independently of each other, while looping only once through the timeframe for ($recur_timestamp = $start_timestamp; $recur_timestamp <= $recur_end_timestamp; $recur_timestamp += 86400) { $last_week=0; my @recur_timestamp_array = gmtime $recur_timestamp; my $current_month = $recur_timestamp_array[4]; #look a week ahead, to see if the current weekday is the last one in the month my $recur_timestamp_next_week = $recur_timestamp+604800; my @recur_timestamp_next_week_array = gmtime $recur_timestamp_next_week; if ($current_month != $recur_timestamp_next_week_array[4]) {$last_week = 1;} $real_year = 1900 + $recur_timestamp_array[5]; $recur_timestamp_valid=1; if ($q->param('recurrence_type') eq "same_day_of_month") { if ($recur_timestamp_array[3] != $timestamp_array[3]) {$recur_timestamp_valid=0;} } elsif ($q->param('recurrence_type') eq "same_day_of_week") { if ($recur_timestamp_array[6] != $timestamp_array[6]) { $recur_timestamp_valid=0; } elsif ($q->param('weekday_of_month_type') eq "only_first_week") { if ($weekday_in_month_count != 0) {$recur_timestamp_valid=0;} } elsif ($q->param('weekday_of_month_type') eq "only_second_week") { if ($weekday_in_month_count != 1) {$recur_timestamp_valid=0;} } elsif ($q->param('weekday_of_month_type') eq "only_third_week") { if ($weekday_in_month_count != 2) {$recur_timestamp_valid=0;} } elsif ($q->param('weekday_of_month_type') eq "only_fourth_week") { if ($weekday_in_month_count != 3) {$recur_timestamp_valid=0;} } elsif ($q->param('weekday_of_month_type') eq "only_fifth_week") { if ($weekday_in_month_count != 4) {$recur_timestamp_valid=0;} } elsif ($q->param('weekday_of_month_type') eq "only_last_week") { if ($last_week != 1) {$recur_timestamp_valid=0;} else { $debug_info .= "timestamp: $recur_timestamp<br/>\n"; $debug_info .= "current month: $current_month<br/>\n"; $debug_info .= "lookahead timestamp: $recur_timestamp_next_week<br/>\n"; $debug_info .= "lookahead month: $recur_timestamp_next_week_array[4]<br/>\n"; $debug_info .= "<br/>\n"; } } } elsif ($q->param('recurrence_type') eq "every_x_days") { #$debug_info .= $q->param('every_x_days'); #$debug_info .= "\n"; if (($recur_timestamp - $start_timestamp) % (86400 * $q->param('every_x_days')) !=0) {$recur_timestamp_valid=0;} } elsif ($q->param('recurrence_type') eq "every_x_weeks") { #$debug_info .= ($q->param('every_x_weeks')."\n"); if (($recur_timestamp - $start_timestamp) % (86400 * 7 * $q->param('every_x_weeks')) !=0) {$recur_timestamp_valid=0;} } if ($q->param('year_fit_type') eq "every_month") { } elsif ($q->param('year_fit_type') eq "custom_months") { my $month_valid=0; foreach $custom_month (@custom_months) { if ($custom_month == $recur_timestamp_array[4]) {$month_valid=1;} } if ($month_valid == 0) {$recur_timestamp_valid=0;} } if ($recur_timestamp_valid == 1) { push @recurring_events_array, $recur_timestamp; my $real_year = $recur_timestamp_array[5]+1900; } #count how many of the event's weekdays we have come across in #each month. This is for validating events that occur on the #second tuesday, fifth monday, etc. if ($recur_timestamp_array[6] == $timestamp_array[6]) { $weekday_in_month_count++; } #reset week_in_month count if this is the last week in the month if ($last_week == 1 && $recur_timestamp_array[6] == $timestamp_array[6]) {$weekday_in_month_count=0;} } if (scalar @recurring_events_array == 0) { $debug_info .= "Error! No valid recurring event dates found!\n"; } return \@recurring_events_array; } sub verify_date() { # $date is of the format similar to mm/dd/yy (or a permutation like dd/mm/yy) my ($date) = @_; my $results=""; if ($date !~ /^(\w{1,2}\/\w{1,2}\/\w{2,4}|\w{1,2}\/\w{2,4}\/\w{1,2}|\w{2,4}\/\w{1,2}\/\w{1,2})$/) { $lang{date_verify_err0} =~ s/###date###/$date/; $lang{date_verify_err0} =~ s/###format###/$current_calendar{date_format}/; $results .= $lang{date_verify_err0}."\n"; } if ($q->param('recurrence_type') eq "every_x_days") { if ($q->param('every_x_days') == 0) {$results .= $lang{date_verify_err7}."\n"}; } elsif ($q->param('recurrence_type') eq "every_x_weeks") { if ($q->param('every_x_weeks') == 0) {$results .= $lang{date_verify_err8}."\n"}; } if ($date eq "") { $results .= $lang{date_verify_err1}."\n"; } my ($mon, $day, $year) = &format2mdy($date, $current_calendar{date_format}); if ($mon < 1 || $mon > 12) { $lang{date_verify_err4} =~ s/###month###/$mon/; $results .= $lang{date_verify_err4}."\n"; } $mon --; # convert month to 0-11 format if ($day < 1 || $day > 31) { $lang{date_verify_err5} =~ s/###day###/$day/; $results .= $lang{date_verify_err5}."\n"; } if ($year < 100) {$year+=2000;} if ($year < 1902 || $year > 2037) { $lang{date_verify_err6} =~ s/###year###/$year/; $results .= $lang{date_verify_err6}."\n"; } return $results; } sub verify_time { my ($time) = @_; my $results=""; if ($time !~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/) { $lang{time_verify_err0} =~ s/\{0\}/$time/; $results .= $lang{time_verify_err0}; } else { my $hours = $1; my $minutes = $2; my $ampm = $3; if ($hours > 12 || $hours < 0) { $lang{time_verify_err1} =~ s/\{0\}/$hours/; $results .= $lang{time_verify_err1}; } if ($minutes > 60 || $minutes < 0) { $lang{time_verify_err2} =~ s/\{0\}/$minutes/; $results .= $lang{time_verify_err2}; } } return $results; } sub time2seconds { my ($time) = @_; $time =~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/; my $hours = $1; my $minutes = $2; my $ampm = $3; my $seconds = 3600*$hours + 60*$minutes; if ($ampm eq $lang{pm} && $hours < 12) { $seconds += 3600*12; } if ($ampm eq $lang{am} && $hours == 12) { $seconds -= 3600*12; } return $seconds; } sub preview_date { my $html_output .=<<p1; Cache-control: no-cache,no-store,private Content-Type: text/html; charset=$lang{charset}\n <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="pragma" content="no-cache"> <link rel="stylesheet" href="$css_path" type="text/css" media=screen> <title>$lang{date_preview_title}
    $lang{date_preview_title} p1 $recurring_event = $q->param('recurring_event'); $event_start_date = $q->param('evt_start_date'); $recur_end_date = $q->param('recur_end_date'); $event_days = $q->param('evt_days'); $event_cal_id = $q->param('evt_cal_id'); %current_calendar = %{$calendars{$event_cal_id}}; my $custom_months_string = $q->param('custom_months'); local @custom_months = split (/\s/, $custom_months_string); #// my $date_valid = &verify_date($event_start_date); if ($event_days eq "") { $date_valid=$lang{date_verify_err2}; } if ($days =~ m/\D/ || $event_days <= 0) { $date_valid=$lang{date_verify_err3}; } if ($recurring_event) { my $temp .= &verify_date($recur_end_date); if ($temp ne "") { $date_valid .= "\n$lang{date_verify_for_recurring_end_date}\n

    $temp

    "; } } if ($date_valid eq "") { my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_calendar{date_format}); my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recur_end_date, $current_calendar{date_format}); $start_mon--; $recur_end_mon--; #calculate start timestamp $event_start_timestamp=timegm(0,0,0,$start_mday,$start_mon,$start_year); @timestamp_array = gmtime $event_start_timestamp; my $real_year = $timestamp_array[5]+1900; if ($recurring_event == 1) { #calculate end timestamp $recur_end_timestamp=timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year); $html_output .= <$lang{date_preview_recurring_event_falls_on}

    p1 my @recurring_events_array = @{&calculate_recurring_events($event_start_timestamp, $recur_end_timestamp)}; foreach $recurring_event_timestamp (@recurring_events_array) { $timestamp1 = $recurring_event_timestamp; $timestamp2 = $recurring_event_timestamp + 86400 * ($event_days-1); if ($timestamp1 == $timestamp2) {$timestamp2++;} $date_range = &nice_date_range_format($timestamp1, $timestamp2, "-"); $html_output .= <$date_range

    p1 } } else { my $date = ""; $timestamp1 = $event_start_timestamp; $timestamp2 = $event_start_timestamp + 86400 * ($event_days-1); if ($timestamp1 == $timestamp2) {$timestamp2++;} $date_range = &nice_date_range_format($timestamp1, $timestamp2, "-"); $html_output .= <$lang{date_preview_this_event_falls_on}

    $date_range

    p1 } } else { $date_valid =~ s/\n//g; $html_output .= "

    $date_valid

    "; } $html_output .=< p1 #$html_output .="$debug_info"; $html_output .=< p1 print $html_output; } # end preview date subroutine sub preview_event { $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}<\/i>/g; $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}<\/i>/g; $event_details_template =~ s/###delete event link###/$lang{event_details_delete_disable}<\/i>/g; $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g; my $event_info = &generate_event_details({title => $q->param('evt_title'), details => $q->param('evt_details'), cal_id => $q->param('evt_cal_id'), icon => $q->param('evt_icon'), bgcolor => $q->param('evt_bgcolor'), start => $q->param('evt_start_time'), end => $q->param('evt_start_time'), unit_number => $q->param('unit_number')}); my $html_output .=< $lang{event_preview_title} $lang{event_preview_title} $event_info p1 print $html_output; } # preview_event sub view_event { my $event_info = &generate_event_details(\%current_event); my $html_output .=< $current_event{title} $event_info p1 print $html_output; } # view_event sub email_reminder_prompt { $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, " - "); my $html_output .=< $current_event{title}$lang{email_reminder_title}

    $current_event{title}

    $lang{email_reminder_text1}
    $date_string

    $lang{email_reminder_text2}


    $lang{email_reminder_text3}

    $lang{email_reminder_text4}

    p1 if ($current_event{series_id} ne "") { $html_output .=< $lang{email_reminder_text6}

    p1 } $html_output .=<
    p1 print $html_output; } # email_reminder_prompt sub email_reminder_confirm { my $reminder_results = ""; my $to_address = $q->param('email_address'); $to_address =~ s/\s//g; $to_address =~ s/;/,/g; chomp $to_address; my ($reminder_seconds, $reminder_time) = split(/, ?/,$q->param('reminder_time')); $reminder_time = lc $reminder_time; my $email_valid = &validate_emails($to_address); if ($email_valid ne "") { $reminder_results = $lang{email_reminder_invalid_address}; $reminder_results =~ s/###address###/$email_valid/g; } else { my @event_reminder_ids=($current_event{id}); if ($q->param('all_in_series') ne "") { @event_reminder_ids = &get_events_in_series($current_event{series_id}); } foreach $event_reminder_id (@event_reminder_ids) { # assemble email reminder xml my $reminder_xml = ""; $reminder_xml .= &xml_store($event_reminder_id, "evt_id"). &xml_store($reminder_seconds, "before"). &xml_store($to_address, "email_address"). &xml_store($script_url, "script_url"). &xml_store($rightnow, "timestamp"); $reminder_xml = "$reminder_xml\n"; # write email reminder to file open (FH, ">>$email_reminders_datafile") || ($debug_info .="
    Unable to open email reminders data file $email_reminders_datafile for writing
    "); print FH $reminder_xml; close FH; } my $test_reminder_results = ""; if ($q->param('send_test_now') == 1) { my $reminder_text = $lang{email_reminder_test_text}; $reminder_text =~ s/###reminder_time###/$reminder_time/g; my $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, " - "); $reminder_text =~ s/###title###/$current_event{title}/g; $reminder_text =~ s/###date###/$date_string/g; $reminder_text =~ s/###details###/$current_event{details}/g; $reminder_text =~ s/###link###/$script_url\/$name?view_event=1&evt_id=$current_event{id}/g; $test_reminder_results = &send_email_reminder(\%current_event, $to_address, $reminder_text); if ($test_reminder_results eq "1") { $test_reminder_results = $lang{email_reminder_test_success}; $test_reminder_results =~ s/###address###/$to_address/g; } else { $test_reminder_results = $lang{email_reminder_test_fail}; $test_reminder_results =~ s/###results###/$test_reminder_results/g; } } $lang{email_reminder_results1} =~ s/###address###/$to_address/g; $lang{email_reminder_results1} =~ s/###reminder time###/$reminder_time/g; if ($q->param('send_test_now') == 1) {$lang{email_reminder_results1} .= $lang{email_reminder_results3}} else {$lang{email_reminder_results1} .= $lang{email_reminder_results2}} $reminder_results = <
    $test_reminder_results p1 } my $html_output .=< $current_event{title}$lang{email_reminder_title}

    $reminder_results

    $debug_info p1 print $html_output; } # email_reminder_confirm sub detect_remote_calendars() { my $remote_calendar_url = $q->param('remote_calendar_url'); $remote_calendar_url =~ s/\?.+//; #$debug_info .= "url: $remote_calendar_url\n"; $remote_calendar_base_url = $remote_calendar_url; $remote_calendar_url .= "?remote_calendar_request=1&get_public_calendars=1"; my $xml_results = &get_remote_file($remote_calendar_url); #$results =~ s/>/>/g; #$results =~ s/ $lang{detect_remote_calendars1} $remote_calendar_base_url:

    p1 my $index = 0; foreach $temp (@public_calendars) { my %public_calendar = %{$temp}; my $list_class="list_odd"; my $merge_xml = < plans$remote_calendars{'xml'}{'plans_version'} $remote_calendar_base_url $public_calendar{id} ###password### p1 #$merge_xml =~ s/\//\\\//g; $merge_xml =~ s/\n//g; $merge_xml =~ s/"/\\"/g; if ($index%2 == 0) {$list_class="list_even"} $remote_calendar_info .= < p1 #$remote_calendar_info .= "public calendar: ".$remote_calendars{'xml'}{public_calendar}."
    "; $remote_calendar_info .= <$public_calendar{title}
    p1 $remote_calendar_info .= <$lang{detect_remote_calendars2} p1 if ($public_calendar{requires_password} ne "") { $remote_calendar_info .= <($lang{detect_remote_calendars3}): p1 } $remote_calendar_info .= < p1 $remote_calendar_info .= < p1 $index++; } $remote_calendar_info .= <
    p1 if ($index > 0) { $remote_calendar_info .= <$lang{detect_remote_calendars4}



    p1 } else { $remote_calendar_info .= <$lang{detect_remote_calendars5}



    p1 } #
    #
    #my $temp_xml_results = $xml_results; #$temp_xml_results =~ s/>/>/g; #$temp_xml_results =~ s/ p1 my $html_output .=<\n/g; $html_output .=< $lang{get_remote_calendars} $popup_javascript_info

    p1 # $html_output .=<
    $debug_info
    p1 print $html_output; } sub remote_calendar_request() { my $html_output .=<param('cal_id'); $results .=<$plans_version p1 #$debug_info .= "remote calendar request!"; # if the client requests a list of all calendars that are publically share-able. if ($q->param('get_public_calendars') eq "1") { foreach $cal_id (keys %calendars) { if ($calendars{$cal_id}{allow_remote_calendar_requests}) { my $temp=$calendars{$cal_id}{remote_calendar_requests_require_password}; $results .=<$cal_id$calendars{$cal_id}{title}$temp p1 } } } else # return xml data for the events. { my @current_cal_ids = (); my @temp = split (",",$current_cal_ids_string); my $cal_id_valid=1; foreach $cal_id (@temp) { if ($cal_id !~ /\D/) { push @current_cal_ids, $cal_id; } else { $cal_id_valid=0; $results .= "Invalid calendar ID: $cal_id"; last; } } if ($cal_id_valid) { foreach $current_cal_id (@current_cal_ids) { $results .=<$current_cal_id$calendars{$current_cal_id}{title}$calendars{$current_cal_id}{gmtime_diff} p1 } foreach $current_cal_id (@current_cal_ids) { foreach $event (keys %events) { if ($events{$event}{cal_id} ne $current_cal_id) {next;} my $xml_data = &event2xml($events{$event}); $results .=<"; @awords=split(' ', $A); @bwords=split(' ', $B); $score=0; foreach $aword (@awords) { if ((index $B,$aword) != -1) { # print "$temp"; # print "pruned to \"$A\" and \"$B\"
    "; # print "wmatch matched $aword and $bword

    "; $score++; } } return $score; } sub rgb2hsv { # r,g,b values are from 0 to 255 # h = [0..360], s = [0..100], v = [0..100] # if s == 0, then h = -1 (undefined) my ($r,$g,$b) = @_; $r /= 255; $g /= 255; $b /= 255; my ($h, $s, $v); my ($min, $max, $delta); $min = &min ( $r, $g, $b ); $max = &max ( $r, $g, $b ); # value is just the brightest rgb value $v = $max; # account for shades of gray: $delta = $max - $min; if ($delta == 0 ) { $s = 0; # no hue, so it can't be saturated! $h = -1; # hue is really undefined, but... return ($h, $s, $v*100); } # saturation is intensity/blandness of color: $s = $delta / $max; # max > 0 or delta would be 0 # hue depends on the relative strengths of the colors: if( $r == $max ) { $h = ( $g - $b ) / $delta; # between yellow & magenta } elsif( $g == $max ) { $h = 2 + (( $b - $r ) / $delta); # between cyan & yellow } else { $h = 4 + (( $r - $g ) / $delta); # between magenta & cyan } # it's also calculated as degrees on a color wheel $h *= 60; # degrees $h += 360 if ($h < 0); # s and v are percentages $s *= 100; $v *= 100; return (int( $h ), int($s), int($v)); } sub hsv2rgb { my ($hue, $sat, $val) = @_; my @hsv_map = ( 'vkm', 'nvm', 'mvk', 'mnv', 'kmv', 'vmn' ); # HSV conversions from pages 401-403 "Procedural Elements for Computer # Graphics", 1985, ISBN 0-07-053534-5. my @result; if ($sat <= 0) { return ( 255 * $val, 255 * $val, 255 * $val ); } else { $val >= 0 or $val = 0; $val <= 1 or $val = 1; $sat <= 1 or $sat = 1; $hue >= 360 and $hue %= 360; $hue < 0 and $hue += 360; $hue /= 60.0; my $i = int($hue); my $f = $hue - $i; $val *= 255; my $m = $val * (1.0 - $sat); my $n = $val * (1.0 - $sat * $f); my $k = $val * (1.0 - $sat * (1 - $f)); my $v = $val; my %fields = ( 'm'=>$m, 'n'=>$n, 'v'=>$v, 'k'=>$k, ); return @fields{split //, $hsv_map[$i]}; } } sub make_consistent { my ($string) = @_; my $input = $q->param($string); if ($input ne "") {$consistent_parameter_string .= "&$string=$input";} } sub remove_consistent { my ($string) = @_; my $return_string = $consistent_parameter_string; $return_string =~ s/&$string=.+?&/&/; return $return_string; } sub diagnostic_mode() { $html_output .=< Diagnostic mode

    Plans Diagnostic information



    Script Name:$name
    Data Storage Mode: $data_storage_mode

    p1 if ($email_mode && !$writable{email_reminders_datafile}) { $html_output .=<Warning: The email reminders data file: $email_reminders_datafile is not writable. This will cause some email functions to be disabled or not work correctly.
    p1 } if ($data_storage_mode == 0 && !$writable{calendars_file}) { $html_output .=<Warning: The calendars data file: $calendars_file is not writable. The add/edit calendars tab won't appear unless this file is writable.
    p1 } if ($data_storage_mode == 0 && !$writable{new_calendars_file}) { $html_output .=<Warning: The new calendars data file: $new_calendars_file is not writable. The add/edit calendars tab won't appear unless this file is writable.
    p1 } if ($data_storage_mode == 0 && !$writable{events_file}) { $html_output .=<Warning: The events data file: $events_file is not writable. The add/edit events tab won't appear unless this file is writable.
    p1 } $html_output .=<Plans version: $version
    Perl version: $perl_version
    script name: $name
    script url path: $script_url

    Theme url: $theme_url
    graphics url: $graphics_url
    icons url: $icons_url

    Default template path: $default_template_path
    Email mode: $email_mode

    events file: $events_file
    calendars file: $calendars_file


    Debug info:
    $debug_info
    p1 print $html_output; } # end diagnostic subroutine sub assemble_icon_menus() { # this function extracts a data structure for the icon menus from the xml definition my ($data)= @_; # first, get the menuitems my @new_menuitems=(); my @menuitems = &xml_extract($data, "menuitem", 0); if (scalar @menuitems == 0) { $debug_info .= "Warning. There's a menu with no menuitems. This may be caused by an older version of Perl ( < 5.6).\n"; $debug_info .= "$data"; } else { foreach my $menuitem (@menuitems) { #$debug_info .= "menuitem: $menuitem->{data} ($menuitem->{position})
    "; my $icon_name = $menuitem->{attributes}{"value"}; my $icon_description = $menuitem->{data}; $icon_description = &encode($icon_description); $new_menuitems[$menuitem->{position}] = [$icon_name,$icon_description]; #$new_menuitems[$menuitem->{position}] = "name,description"; } } # then get the submenus my @submenus = &xml_extract($data, "menu", 0); foreach $submenu (@submenus) { my $temp = $submenu->{data}; my $temp2 = $submenu->{attributes}{name}; my @submenuitems = assemble_icon_menus($temp); #$debug_info .= "submenu: $temp2 ($submenu->{position})
    "; $new_menuitems[$submenu->{position}] = [$temp2, \@submenuitems]; } return @new_menuitems; } #******************** end assemble_icon_menus ********************** sub generate_flat_icon_menus { my ($icons_list, $selected_icon) = @_; my $return_text=""; #$debug_info .= "selected icon: $selected_icon
    "; my $indent = " "; for ($l1=0;$l1<$index_number;$l1++) { $indent .= " "; } foreach $icon_ref (@{$icons_list}) { my $identifier = @{$icon_ref}[1]; if ($identifier =~ /ARRAY/) # if it's a submenu { $icon_menu_index_number++; my $submenu_name = @{$icon_ref}[0]; #$debug_info .= "submenu $submenu_name
    "; $return_text .= < p1 $return_text .= &generate_flat_icon_menus(@{$icon_ref}[1], $selected_icon); $return_text .= < p1 } else # if it's a menu item { my $icon_filename = @{$icon_ref}[0]; my $icon_name = @{$icon_ref}[1]; $icon_name = &decode($icon_name); #$debug_info .= "icon name: $icon_name
    "; #$debug_info .= "icon filename: $icon_filename
    "; #$debug_info .= "
    "; if ($icon_filename eq $selected_icon) { $return_text .= <$icon_name p1 } else { $return_text .= <$icon_name p1 } } } return $return_text; } #******************** end generate_flat_icon_menus ********************** sub export_calendar_link() { my $results = ""; $results .=<$lang{export} $lang{these_events_to} p1 } sub format2mdy() { # takes a format string (which can be "dd/mm/yy", "yy,mm,dd", etc.) # and a date in that format, and returns the month, day, and year. my ($date, $format) = @_; my @temp_date = split ('/', $date); my @temp_format = split ('/', $format); my %temp_format_map; for (my $l1=0;$l1<3;$l1++) { $temp_format_map{$temp_format[$l1]} = $temp_date[$l1]; } my $mon = $temp_format_map{"mm"}; my $day = $temp_format_map{"dd"}; my $year = $temp_format_map{"yy"}; return ($mon, $day, $year); }