#!/usr/bin/perl
require v5.6.1;
# 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
# The "use Cwd" method would be nice, but it doesn't work with
# some versions of IIS/ActivePerl
#use Cwd;
#$path = cwd;
if ($path ne "") {
chdir $path;
push @INC,$path;
}
# finished discovering name
#use Data::Dumper;
# some global variables (more further down)
local $plans_version = "8.2.1"; # version
local $debug_info;
local %options;
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 $script_url = "";
local $messages = ""; # formatted in plain text with newlines. Converted to html at display time.
local $template_html;
local $local_template_file = 0; # tells whether the template was loaded via a filesystem open or through a http request.
local $event_details_template;
local $list_item_template;
local $calendar_item_template;
local $upcoming_item_template;
local %calendars;
local %current_calendar;
local %latest_calendar;
local %new_calendars;
local $normalized_timezone = 0;
local $normalized_timezone_pending_events = 0;
# used when adding new entries
local $max_cal_id = 0;
local $max_event_id = 0;
local $max_series_id = 0;
local $max_user_id = 0;
local $max_action_id = 0;
# used to protect against refreshes
local $latest_cal_id = 0;
local $latest_event_id = 0;
local $latest_new_cal_id = 0;
local $latest_new_event_id = 0;
local $session;
local $json = new JSON::PP;
local %users;
my $profile;
local $logged_in = 0;
local $logged_in_as_root = 0;
local $logged_in_as_current_cal_user = 0;
local $logged_in_as_current_cal_admin = 0;
local $lg_name = "";
local $lg_password = "";
local %events;
local %new_events;
local @pending_events_to_display;
local %text;
local %cookie_parms;
local $cookie_text = "";
local $cookie_header_text = "";
local $max_remote_event_id = 0;
local $options{default_template_path} = "";
local $theme_url = "";
local $options{choose_themes} = "";
local $graphics_url = "";
local $ical_export_url = "";
local $icons_url = "";
local $input_cal_id_valid = 0;
local $options{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)
local @disabled_tabs;
# check for required modules.
require "includes.pl";
$module_found=0;
foreach $temp_path (@INC) {
if (-e "$temp_path/JSON") {
$module_found=1;}
}
if ($module_found == 0) {
$fatal_error=1;
$error_info .= "unable to locate required module JSON!\n";
} else {
require "JSON/PP58.pm";
use JSON::PP;
}
if ($fatal_error == 1) { # print error and bail out
&fatal_error();
}
# anonymous events only work when sessions are turned on
$options{'anonymous_events'} = $options{'anonymous_events'} && $options{'sessions'};
if (defined $options{language_files}) {
my @language_files = split(',', $options{language_files});
# create a javascript file with language strings
open (FH, "$options{default_theme_path}/$options{js_language_file}") || {$debug_info.= "unable to open file $options{default_theme_path}/$options{js_language_file}\n"};
flock FH,2;
my $first_lang_line=;
close FH;
if ($options{generate_js_lang} eq "1" || $first_lang_line !~ /$plans_version/) {
my $lang_string = "";
$lang_string .= "//$plans_version\n";
$lang_string .= "var plans_lang = {};\n";
# generate %lang keys
foreach $lang_key (keys %lang) {
if (ref $lang{$lang_key} eq "ARRAY") {
$lang_string .= "plans_lang['$lang_key']=[";
my $first = 1;
foreach $key (@{$lang{$lang_key}}) {
if (!$first) {$lang_string .= ',';}
if ($first) {$first = 0;}
my $lang_val = &js_string($key);
$lang_string .= "'$lang_val'";
}
$lang_string .= "];\n";
} else {
my $lang_val = &js_string($lang{$lang_key});
$lang_string .= "plans_lang['$lang_key']='$lang_val';\n"
}
}
open (FH, ">$options{default_theme_path}/$options{js_language_file}") || {$debug_info .= "unable to open file $options{default_theme_path}/$options{js_language_file} for writing!\n"};
flock FH,2;
print FH $lang_string;
close FH;
}
} else {
$fatal_error=1;
$error_info .= "No language files defined in plans.config!\n";
}
if ($fatal_error == 1) { # print error and bail out
&fatal_error();
}
# init cgi stuff
$q = new CGI;
if ($options{calendar_url} ne "") {
$script_url = $options{calendar_url};
} else {
$script_url = $q->url(-path_info>=1);
}
$script_url =~ /(.*)\//; # remove trailing / and all text after
$script_url = $1; # remove trailing / and all text after
%cookie_parms = %{ &extract_cookie_parms() };
my $cookie_path = $q->url( -absolute => 1 );
$cookie_path =~ s/$name$//;
$cookie_path =~ s/admin\/?$//; # This is better than using just '/'
# check if data files or tables are present
&check_data();
# fatal error? Print error and bail out
if ($fatal_error == 1) {
&fatal_error();}
if ($theme_url eq "") { # not defined in config file
$theme_url = "$script_url/theme";
}
if ($options{choose_themes}) {
$chosen_url = $q->param('theme_url');
$chosen_url = $cookie_parms{'theme_url'} if ($chosen_url eq "");
$theme_url = $chosen_url if ($chosen_url ne "");
}
$graphics_url ="$theme_url/graphics"; # where misc. graphics are
$ical_export_url ="$theme_url/ical"; # where icalendar .ics files are placed
$ical_export_url =~ s/http:\/\//$options{ical_prefix}/; # replace with custom prefix
$icons_url = "$theme_url/icons"; # where icons are
$css_path = "$theme_url/plans.css"; # css file
# globals from http parameters
my $active_tab = $q->param('active_tab') + 0; # +0 ensures numericity
$active_tab = 0 if ($active_tab > scalar @{$lang{tab_text}} - 1);
my $api_command = $q->param('api_command');
my $add_edit_cal_action = $q->param('add_edit_cal_action');
$add_edit_cal_action = "" if (!&contains(["add", "edit", "view_pending"],$add_edit_cal_action)); # validate
my $add_edit_event = $q->param('add_edit_event');
$add_edit_event = "" if (!&contains(["add", "edit"],$add_edit_event)); # validate
local $current_event_id = $q->param('evt_id');
$current_event_id = "" if ($current_event_id !~ /^R?\d+$/); # validate
local $pending_event_id = $q->param('pending_event_id');
$pending_event_id = "" if ($pending_event_id !~ /^R?\d+$/); # validate
local $cal_start_month = $q->param('cal_start_month') + 0; # +0 ensures numericity
local $cal_start_year = $q->param('cal_start_year') + 0; # +0 ensures numericity
local $cal_num_months = $q->param('cal_num_months') + 0; # +0 ensures numericity
# if view parameters not supplied in http request, check cookie
$cal_start_month = $cookie_parms{'cal_start_month'} if ($q->param('cal_start_month') eq "");
$cal_start_year = $cookie_parms{'cal_start_year'} + 0 if ($cal_start_year == 0);
$cal_num_months = $cookie_parms{'cal_num_months'} + 0 if ($cal_num_months == 0);
my $special_action = $q->param('special_action'); # needs no validation - never used in output
local $display_type = $q->param('display_type') + 0; # +0 ensures numericity
$display_type = $cookie_parms{'display_type'} if ($q->param('display_type') eq "");
$messages = $q->param('messages') if ($q->param('messages') ne "");
# 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 $prev_month_link = "";
my $next_month_link = "";
# load calendar data
&load_calendars();
&load_users();
&load_actions();
local $current_cal_id = 0;
if ($q->param('cal_id') eq "") {
$current_cal_id = $cookie_parms{'current_cal_id'} if ($current_cal_id == 0);
} else {
$current_cal_id = $q->param('cal_id');
}
$current_cal_id += 0; # +0 ensures numericity
foreach $cal_id (keys %calendars) {
if ($cal_id eq $current_cal_id) {
$input_cal_id_valid = 1;
}
}
if ($current_cal_id eq "") {
$input_cal_id_valid = 0;
}
if ($current_cal_id =~ /\D/) {
$input_cal_id_valid = 0;
}
$current_cal_id = 0 if ($current_event_id eq "" && !$input_cal_id_valid);
# 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 yyyy");
@weekday_sequence = @day_names;
# session stuff
if ($options{sessions} eq "1") {
$lg_name = $current_cal_id;
$lg_password = $q->param('cal_password');
&delete_old_sessions(1); # in days
my $current_session_id = $q->cookie("plans_sid") || undef;
$session = new CGI::Session(undef, $current_session_id, {Directory=>$options{sessions_directory}});
$session->expire("+1d");
#$debug_info .= "current_session_id: $current_session_id\n";
# log out?
if ($q->param('logout') eq "1") {
$session->delete();
$logged_in = 0;
$cookie_text .= "Set-Cookie; plans_sid=deleted; path=$cookie_path;\n";
} else {
# try to match session with user id. (If this fails, it's not really a session.)
my $results = &init_session($q, $session);
$profile = $session->param("~profile");
if (defined $profile->{calendar_permissions}) {
$logged_in = 1;
$cookie_text .= "Set-Cookie: plans_sid=".$session->id."; path=$cookie_path;\n";
}
}
}
# $debug_info .= "cal password: " . $q->param('cal_password') . "\n";
# $debug_info .= "encrypted cal password: " . crypt($q->param('cal_password'), $options{salt}) . "\n";
# $debug_info .= "root cal password: " . $calendars{0}{password} . "\n";
if ($options{sessions} eq "1") {
$logged_in_as_root = ($profile->{calendar_permissions}->{0}->{admin} eq "1") ? 1:0;
$logged_in_as_current_cal_user = ($profile->{calendar_permissions}->{$current_cal_id}->{user} ne "") ? 1:0;
$logged_in_as_current_cal_admin = ($profile->{calendar_permissions}->{$current_cal_id}->{admin} ne "") ? 1:0;
} elsif ($q->param('cal_password') ne "") {
$logged_in_as_root = ($calendars{0}{password} eq crypt($q->param('cal_password'), $options{salt})) ? 1:0;
$logged_in_as_current_cal_admin = ($current_calendar{password} eq crypt($q->param('cal_password'), $options{salt})) ? 1:0;
foreach $user_id (keys %users) {
my %user = %{$users{$user_id}};
my %user_calendars = %{$user{calendars}};
foreach $user_cal_id (keys %user_calendars) {
if ($user_cal_id eq $current_cal_id && $user{calendars}{$user_cal_id}{edit_events} eq "1" &&
$user{password} eq crypt($q->param('cal_password'), $options{salt})) {
$logged_in_as_current_cal_user = 1;
last;
}
last if ($logged_in_as_current_cal_user == 1);
}
last if ($logged_in_as_current_cal_user == 1);
}
}
$logged_in_as_current_cal_user = 0 if (!$options{users}) ;
#$debug_info .= "init_session results: $results\n";
#$debug_info .= "logged-in: ".$session->param("~logged-in")."\n";
#$debug_info .= "session id: ".$session->id."\n";
#$debug_info .= "profile user_id: ".$profile->{calendar_permissions}->{$current_cal_id}."\n";
#$debug_info .= "options{sessions}: $options{sessions}\n";
#$debug_info .= "logged_in_as_root: $logged_in_as_root\n";
#$debug_info .= "logged_in_as_current_cal_user: $logged_in_as_current_cal_user\n";
#$debug_info .= "logged_in_as_current_cal_admin: $logged_in_as_current_cal_admin\n";
#$debug_info .= "current_calendar{password}: $current_calendar{password}\n";
#$debug_info .= ($profile->{calendar_permissions}->{$current_cal_id}->{admin})."\n";
# 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') eq "1") {
$current_cal_id = $q->param('custom_calendar_calendar') + 0;
@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;
# 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) {
next if ($temp_line !~ /\w/); # skip any blank lines
$temp_line =~ s/^\s+//;
my ($hex_color, $hex_color_title) = split (/,*\s+/, $temp_line, 2);
$hex_color_title = " " if ($hex_color_title eq "");
push @event_bgcolors, {color => $hex_color, title => $hex_color_title};
}
#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 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;
}
$cal_num_months = $current_calendar{default_number_of_months} if ($cal_num_months < 1);
$cal_num_months = $current_calendar{default_number_of_months} if ($cal_num_months > $current_calendar{max_number_of_months});
$cal_num_months = 1 if ($cal_num_months > $current_calendar{max_number_of_months});
$cal_num_months = 1 if ($cal_num_months == 0);
#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;
}
my $initial_load_events = 1;
$initial_load_events = 0 if ($q->param('get_upcoming_events') eq "1");
&load_events($cal_start_timestamp, $cal_end_timestamp, \@temp_calendars) if ($initial_load_events == 1);
if ($current_event_id ne "") {
&load_event($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;
$xml_results =~ s/>/>/g;
#$debug_info .= "Error fetching remote calendar: $xml_results\n";
} else {
my %remote_calendar = %{&xml2hash($xml_results)};
my $remote_cal_title = $remote_calendar{'xml'}{calendar}{title};
my $remote_cal_gmtime_diff = $remote_calendar{'xml'}{calendar}{gmtime_diff};
#$debug_info .= "remote_cal_gmtime_diff: $remote_cal_gmtime_diff\n";
#my $temp = $xml_results;
#$temp=~ s/>/>/g;
#$temp=~ s/</g;
#$debug_info .= "xml results: $temp\n";
&load_remote_events($xml_results, $remote_calendar_id, $remote_cal_gmtime_diff);
}
}
}
# this should be done after all $current_cal_id is calculated and events are loaded.
&normalize_timezone();
&normalize_timezone_pending_events();
# calculate previous X months range.
my $previous_cal_start_month = $cal_start_month - $cal_num_months;
my $previous_cal_start_year = $cal_start_year;
if ($previous_cal_start_month < 0) {
$previous_cal_start_year = $cal_start_year - 1 - int(abs($cal_num_months - $cal_start_month) / 12);
$previous_cal_start_month = 12 - abs($previous_cal_start_month) % 12;
}
# for the case when num_months = 12 and start_month=0
if ($previous_cal_start_month == 12) {
$previous_cal_start_month=0;
$previous_cal_start_year++;
}
# singular or plural?
if ($cal_num_months > 1) {
$prev_string = $lang{previous_months};
$prev_string =~ s/###num###/$cal_num_months/;
} else {
$prev_string = $lang{previous_month};
}
# calculate next X months range.
my $next_cal_start_month = $cal_start_month + $cal_num_months;
my $next_cal_start_year = $cal_start_year;
if ($next_cal_start_month > 11) {
$next_cal_start_year = $cal_start_year + int(abs($cal_num_months + $cal_start_month) / 12);
$next_cal_start_month = abs($cal_start_month + $cal_num_months) % 12;
}
# singular or plural?
if ($cal_num_months > 1) {
$next_string = $lang{next_months};
$next_string =~ s/###num###/$cal_num_months/;
} else {
$next_string = $lang{next_month};
}
if ($q->param('diagnostic_mode') eq "1") {
my $diagnostic_results = &diagnostic_info;
$html_output = <Diagnostic mode
Plans Diagnostic information
$diagnostic_results
Debug info:
$debug_info
p1
print $html_output;
exit(0);
}
# dispatch all actions
if ($api_command eq "delete_event" || $api_command eq "add_update_event" ) {
&api_add_delete_events();
exit(0);
}
if ($api_command eq "delete_calendar" || $api_command eq "add_update_calendar" ) {
&api_add_delete_calendar();
exit(0);
}
if ($api_command eq "approve_delete_pending_calendars" ) {
&api_approve_delete_pending_calendars();
exit(0);
}
if ($api_command eq 'add_edit_user') {
&add_edit_user();
exit(0);
}
if ($api_command eq 'detect_remote_calendars' ) {
&detect_remote_calendars();
exit(0);
}
if ($api_command eq 'add_ical') {
&add_new_ical();
exit(0);
}
if ($api_command eq 'js_login') {
&js_login();
exit(0);
}
if ($api_command eq 'preview_date') {
&load_templates();
&preview_date();
exit(0);
}
if ($api_command eq 'set_email_reminder') {
&load_templates();
&set_email_reminder();
exit(0);
}
if ($api_command eq 'manage_pending_events') {
&manage_pending_events();
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 "csv_file_palm") {
&csv_file_palm($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);
} elsif ($q->param('export_type') eq "icalendar") {
my $html_output =<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('get_upcoming_events') eq "1") {
&get_upcoming_events();
exit(0);
} elsif ($q->param('view_event') eq "1") {
&load_templates();
&view_event();
exit(0);
} elsif ($q->param('view_pending_event') eq "1") {
&load_templates();
my %pending_event = %{$new_events{$pending_event_id}};
&view_pending_event(\%pending_event);
exit(0);
}
&load_templates();
# 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/;
}
}
if($options{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###//;
}
my %new_cookie_parms = ( "cal_start_month" => $cal_start_month,
"cal_start_year" => $cal_start_year,
"cal_num_months" => $cal_num_months,
"current_cal_id" => $current_cal_id,
"display_type" => $display_type
);
my $view_cookie = &encode( encode_json( \%new_cookie_parms ) );
$cookie_text .= "Set-Cookie: plans_view=$view_cookie; path=$cookie_path; expires=Thu, 31-Dec-2099 00:00:00 GMT\n";
$cookie_header_text = $cookie_text;
$html_output .=< $b} keys %calendars) {
$json_calendars .= "jQuery.planscalendar.calendars.push(" . calendar2json( $calendars{$calendar_id} ) . ");\n";
}
$json_pending_calendars = &calendars2json( \%new_calendars, 1 );
@temp = &assemble_icon_menus( $event_icons_menu );
$json_icons = encode_json( \@temp );
$json_event_background_colors = encode_json( \@event_bgcolors);
$insert_text =<
p1
chomp $insert_text;
$html_output =~ s/###javascript stuff###/$insert_text/;
# insert library javascript before all other javascript.
$temp = &get_js_includes( $theme_url );
$html_output =~ s/(
p1
# finished displaying tab menus, now display the appropriate stuff for the selected tab
if ($active_tab eq "0") { # tab 1 = main calendar view
$prev_month_link .=<$prev_string
p1
$next_month_link .=<$next_string
p1
$cal_controls_text = &generate_calendar_controls();
if ($q->param('custom_calendar') == 1) {
$html_output =~ s/###calendar controls###//g;
} else {
$html_output =~ s/###calendar controls###/$cal_controls_text/g;
}
if ( !$logged_in && $options{force_login} ) {
$insert_text .= &forced_login();
} else {
$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.
$page_javascript .= &calendar_view_javascript($events_start_timestamp, $events_end_timestamp);
#replace javascript placeholders with actual html/javascript code
$html_output =~ s/###previous month link###/$prev_month_link/g;
$html_output =~ s/###next month link###/$next_month_link/g;
}
#done with main active tab stuff (the stuff that's different depending
#on which tab is active. The following stuff is the same regardless
#of which tab is active.
$html_output =~ s/###calendar area###/$insert_text/g;
$html_output =~ s/###version###/$plans_version/g;
my $add_event_to_current_cal_text =<$lang{add_event_to_this_calendar}
p1
chomp $add_event_to_current_cal_text;
my $current_calendar_options_text =<$lang{edit_calendar_options}
p1
chomp $current_calendar_options_text;
my $current_calendar_subscribe_text =<$lang{subscribe_to_this_calendar}
p1
chomp $current_calendar_subscribe_text;
$current_calendar_subscribe_text = '' if ( $options{'ical_export'} ne "1" );
if ($active_tab eq "0") {
$html_output =~ s/###add event to current calendar link###/$add_event_to_current_cal_text/;
$html_output =~ s/###edit calendar options link###/$current_calendar_options_text/;
if ( !$logged_in && $options{force_login} ) {
$html_output =~ s/###subscribe calendar link###//g;
$html_output =~ s/###export calendar link###//;
$html_output =~ s/###custom calendar link###//;
} else {
$html_output =~ s/###subscribe calendar link###/$current_calendar_subscribe_text/g;
my $temp = &export_calendar_link();
$html_output =~ s/###export calendar link###/$temp/;
my $custom_calendar_link =<$lang{make_custom_calendar}
p1
chomp $custom_calendar_link;
$html_output =~ s/###custom calendar link###/$custom_calendar_link/;
#$debug_info .= "custom calendar link: $custom_calendar_link\n";
}
} else {
$html_output =~ s/###subscribe calendar link###//g;
$html_output =~ s/###add event to current calendar link###//;
$html_output =~ s/###edit calendar options link###//;
$html_output =~ s/###custom calendar link###//;
$html_output =~ s/###export calendar link###//;
}
# pending event stuff
$html_output =~ s/###messages###//;
my $pending_events_area = &generate_pending_events_area();
if ($pending_events_area ne "") {
$pending_events_area = <
$pending_events_area
p1
}
$html_output =~ s/###logged-in stuff###/$pending_events_area/;
$common_javascript .= &common_javascript();
$common_javascript .= &generate_pending_events_javascript() if (&pending_events_visible());
#replace javascript placeholders with actual html/javascript code
$html_output =~ s/###page-specific javascript###/\n$page_javascript/;
$html_output =~ s/###common javascript###/\n$common_javascript/;
$debug_info = "$error_info$debug_info";
if ($debug_info =~ /\S/) {
$debug_info =~ s/\n/ \n/g;
$debug_info = <Error, Warnings, & Debug Messages:
$debug_info
<\/div>
p1
}
$html_output =~ s/###debug stuff###/$debug_info/g;
$html_output =~ s/###cookie_text###/$cookie_header_text/;
print $html_output;
} #********************end default view code*****************************
sub add_edit_calendars {
my %results;
$results{'messages'} = [];
$results{'success'} = 0;
my $cal_id = $current_cal_id; # need to validate cal id for add/edit
my $cal_valid = 1;
if ($q->param('add_edit_cal_action') eq "delete") {
#delete calendar
&load_events("all");
&normalize_timezone();
my $del_valid=1;
#check password.
if ($options{disable_passwords} ne "1" && !$logged_in_as_root && !$logged_in_as_current_cal_admin) {
$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;
my @updated_event_ids;
foreach $event_id (keys %events) {
# if the event is only on one calendar, delete it
if (scalar@{$events{$event_id}{cal_ids}} == 1) {
if ($events{$event_id}{cal_ids}[0] eq $cal_id) {
push @deleted_event_ids, $event_id;
} else {next;}
} else { # otherwise, just remove that calendar from its cal_ids
my $index=0;
foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
if ($temp_cal_id eq $cal_id) {
break;
}
$index++;
}
splice @{$events{$event_id}{cal_ids}}, $index, 1; {
push @updated_event_ids, $event_id;}
}
}
&delete_events(\@deleted_event_ids);
&update_events(\@updated_event_ids);
# next, delete the calendar in question
&delete_calendar($cal_id); # redundant in flat-file mode, needed for sql mode
# finally, delete any references in other calendars (background calendars)
my @cals_to_update;
foreach $calendar_id (sort {$a <=> $b} keys %calendars) {
#$debug_info .= "calendar $calendar_id\n";
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;
}
$results{success} = $del_valid;
# properly format errors, warnings
} else { #the user added/updated a calendar
#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 $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 $new_calendars_automatically_selectable = "y" if ($q->param('new_calendars_automatically_selectable') =~ "y");
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_calendars_xml = $q->param('new_remote_calendars_xml');
my $calendar_events_color = $q->param('calendar_events_color');
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 $event_change_email = $q->param('event_change_email');
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}}, '[error]' . $lang{update_cal_error5};
}
#strip all html from label field
if ($cal_title =~ m/<(.*)>/) {
push @{$results{messages}}, '[warning]' .$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 =~ /y{2}/ && $date_format !~ /y{4}/ ) {
$date_format =~ s/yy/yyyy/g;
}
if ($date_format !~ /^(mm|dd|yyyy)\W(mm|dd|yyyy)\W(mm|dd|yyyy)$/ ) {
$cal_valid=0;
push @{$results{messages}}, '[error]' .$lang{update_cal_error6_5};
}
if ($add_edit_cal_action eq "edit") {
if ($options{disable_passwords} ne "1") {
#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}}, '[error]' .$lang{update_cal_error7};
} else { #check password
if ($options{disable_passwords} ne "1" && !$logged_in_as_root && !$logged_in_as_current_cal_admin) {
$cal_valid=0;
push @{$results{messages}}, '[error]' ."$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}}, '[error]' .$lang{update_cal_error8};
} else {
$calendars{$cal_id}{password} = crypt($new_cal_password, $options{salt});
}
}
}
# check for gmtime_diff field
if ($options{force_single_timezone} eq "1" && $cal_id ne "0") {
$gmtime_diff = $calendars{0}{gmtime_diff}
}
# encrypt remote calendar password
$remote_calendar_requests_password = crypt($remote_calendar_requests_password, $options{salt});
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}{calendar_events_color} = $calendar_events_color;
$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}{event_change_email} = $event_change_email;
$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_calendars_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_calendars_xml eq "") {
my %new_remote_calendars = %{&xml2hash($new_remote_calendars_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
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";
$found=1 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});
}
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};
$calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{title} = $new_remote_calendar{title};
$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};
$calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{title} = $new_remote_calendar{title};
} 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;
}
}
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 { # add new calendar
# check password, if necessary
if ($options{anonymous_calendar_requests} eq "1") {
# TODO - come up with a better auth token
#my $t1 = $q->param('as');
#my $t2 = $rightnow;
#if (abs($t1 - $t2) > 3600) {
# $cal_valid=0;
#}
} else {
if ($options{disable_passwords} ne "1" && !$logged_in_as_root && !$logged_in_as_current_cal_admin) {
$cal_valid=0;
push @{$results{messages}}, '[error]' ."$lang{update_cal_error0}";
}
}
#check new password
if ($options{disable_passwords} ne "1") {
if ($new_cal_password ne $repeat_new_cal_password) {
$cal_valid=0;
push @{$results{messages}}, '[error]' . $lang{update_cal_error9};
} elsif ($new_cal_password eq "" || $repeat_new_cal_password eq "" ) {
$cal_valid=0;
push @{$results{messages}}, '[error]' . $lang{update_cal_error10};
} else {
$input_password = crypt($new_cal_password, $options{salt});
}
}
my $new_cal_id;
if ($cal_valid == 1) {
$new_cal_id = $max_action_id + int(rand(100)); # just in case several people decide to add something new at the same time.
$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}{calendar_events_color} = $calendar_events_color;
$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}{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) {
my %latest_new_calendar = $new_calendars{$latest_new_cal_id};
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_action($new_cal_id, "new_calendar");
$results{'calendar'} = $new_calendars{$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 ($options{new_calendar_request_notify} ne "") {
my $body = <$lang{add_cal_success3}
p1
&send_email($options{new_calendar_request_notify}, $options{reply_address}, $options{reply_address}, $lang{add_cal_email_notify2}, $body);
}
my $temp = $lang{add_cal_success1}; # add successful
$temp = $lang{add_cal_success4} if ($add_edit_cal_action eq "edit"); # update successful
push @{$results{messages}}, $temp;
push @{$results{messages}}, $lang{add_cal_success2};
$results{'calendars_waiting_for_approval'} = \%new_calendars;
} else {
push @{$results{messages}}, $lang{add_cal_fail1};
}
}
$results{'success'} = $cal_valid;
}
return \%results;
} #********************end add_edit_calendars code*****************************
sub approve_delete_pending_calendars {
my %results;
$results{'messages'} = [];
$results{'success'} = 1;
my @pending_calendars_to_delete;
my @calendars_to_add;
my @calendars_to_update;
#check password
$input_password = crypt($q->param('main_password'), $options{salt});
if ($options{disable_passwords} ne "1") {
if ($input_password ne $master_password) {
$results{'success'} = 0;
push @{$results{messages}}, $lang{view_pending_calendars7};
return \%results;
}
}
#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("pending_calendar_".$new_cal_id."_approve_delete") eq "approve") {
$max_cal_id+=1; #calculate new id # for the new calendar
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.
$calendars{$max_cal_id}{selectable_calendars}{$max_cal_id} = 1 if (scalar keys %{$calendars{$max_cal_id}{selectable_calendars}} > 0);
$approve_or_delete_result = $new_calendars{$new_cal_id}{'title'} . ' : ' .$lang{view_pending_calendars8};
delete $new_calendars{$new_cal_id};
push @pending_calendars_to_delete, $new_cal_id;
push @calendars_to_add, $max_cal_id;
} elsif ($q->param("pending_calendar_".$new_cal_id."_approve_delete") eq "delete") {
$approve_or_delete_result = $new_calendars{$new_cal_id}{'title'} . ' : ' . $lang{view_pending_calendars9};
delete $new_calendars{$new_cal_id};
push @pending_calendars_to_delete, $new_cal_id;
} else {
$approve_or_delete_result = $new_calendars{$new_cal_id}{'title'} . ' : ' . $lang{view_pending_calendars10};
}
push @{$results{messages}}, $approve_or_delete_result;
}
&delete_pending_actions(\@pending_calendars_to_delete);
&add_calendars(\@calendars_to_add);
&update_calendars(\@calendars_to_update);
return \%results;
}
sub do_calendar_list_view() {
my $return_text = "";
if ($cal_num_months> 1) {
$cal_title_string .=<
$prev_month_link
$cal_title_string
$next_month_link
p1
if ($display_type == 1) { #list view
$return_text .= &render_list($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
} else { #calendar view
$return_text .= &render_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 %results;
my $recurring_event = $q->param('recurring_event');
my $all_in_series = $q->param('all_in_series');
# load (reload) all events (we have to write events beyond the default time window)
if ( $options{data_storage_mode} == 0 ) {
unless ($loaded_all_events eq "1") {
&load_events("all");
&normalize_timezone();
}
}
my $login_valid = 0;
if ($options{disable_passwords} eq "1") {
$login_valid = 1
} elsif ($current_cal_id ne "") {
#$debug_info .= "current_cal_id: $current_cal_id\n";
if ($options{multi_calendar_event_mode} == 0 || $options{multi_calendar_event_mode} == 1) { # only the event's calendar's user or the root user are allowed
$login_valid = 1 if ($logged_in_as_root || $logged_in_as_current_cal_admin || $logged_in_as_current_cal_user); # current calendar user
} elsif ($options{multi_calendar_event_mode} == 2) { # any of the event's calendars' users or the root user are allowed
if ($logged_in_as_root || $logged_in_as_current_cal_admin || $logged_in_as_current_cal_user) { # current calendar user
$login_valid = 1;
} else {
my $cal_password_valid = 0;
foreach $cal_id (@evt_other_cal_ids) {
my $temp = $cal_id;
$cal_password_valid = 1 if ($profile->{calendar_permissions}->{$cal_id}->{admin} eq "1"); # shared calendar admin
$cal_password_valid = 1 if ($profile->{calendar_permissions}->{$cal_id}->{user} ne ""); # shared calendar user
}
$login_valid = 1 if ($cal_password_valid == 1);
}
}
}
if ($q->param('del_event_button') ne "" || $api_command eq "delete_event") {
$del_valid = 1; #delete event.
if ($login_valid == 0) {
$del_valid = 0;
push @{$results{messages}}, "[error]$lang{update_event_err1} '$current_calendar{title}'";
}
if ( ! &event_exists( $current_event_id ) ) {
$del_valid=0;
push @{$results{messages}}, "[error]$lang{update_event_err2}";
}
if ($del_valid == 1) { #actually delete the event(s).
if ($all_in_series ne "1") {
my $subj = $lang{notify_subj};
$subj =~ s/\$1/$script_url\/$name/;
my $body = $lang{event_delete_notify};
$body =~ s/\$1/$events{$current_event_id}{title}/;
$body =~ s/\$2/$calendars{$current_cal_id}{title}/;
foreach $email (@{$current_calendar{delete_emails}}) {
#$debug_info .= "email notification sent to $email\n";
&send_email($email, $options{reply_address}, $options{reply_address}, $subj, $body) if ($options{email_mode} > 0);
}
&delete_event($current_event_id);
push @{$results{messages}}, "[status]$lang{update_event_delete_successful}";
} else {
# get the ids of the events in the series.
my @events_in_series = &get_events_in_series($q->param('series_id'));
&normalize_timezone();
&delete_events(\@events_in_series);
push @{$results{messages}}, "[status]$lang{update_event_delete_successful_recurring}";
}
$results{success} = 1;
} else {
$results{success} = 0;
}
} else { # not a delete
if (!$login_valid) {
if ($options{anonymous_events} && $add_edit_event eq "add" ) {
my $temp = $lang{update_event_err16};
$temp =~ s/###calendar###/$current_calendar{title}<\/b>/g;
push @{$results{messages}}, ("[error]".$temp);
} else {
push @{$results{messages}}, "[error]".($lang{update_event_err1}."'".$current_calendar{title}."'");
}
}
#check all input fields for validity
my $event_valid = 1;
my $event_id = $q->param('evt_id'); # only if editing.
#my $event_cal_id = $current_cal_id;
my @evt_other_cal_ids;
@evt_other_cal_ids = $q->param('evt_other_cal_ids') if ($options{multi_calendar_event_mode} > 0);
my $event_cal_password = $q->param('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_block_merge = $q->param('evt_block_merge');
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 $all_day_event = $q->param('evt_all_day_event');
my $no_end_time = "";
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');
my $event_days = $q->param('evt_days');
my %recurrence_parms;
$recurrence_parms{'recurrence_type'} = $q->param('recurrence_type');
$recurrence_parms{'weekday_of_month_type'} = $q->param('weekday_of_month_type');
$recurrence_parms{'every_x_days'} = $q->param('every_x_days');
$recurrence_parms{'every_x_weeks'} = $q->param('every_x_weeks');
$recurrence_parms{'year_fit_type'} = $q->param('year_fit_type');
$recurrence_parms{'recur_end_date'} = $q->param('recur_end_date');
my @custom_months = $q->param('custom_months');
$recurrence_parms{'custom_months'} = \@custom_months;
$recurrence_parms{'recur_end_timestamp'} = 0;
my %input_parms; # parms that are input by the user, but not stored as final event data
$input_parms{'update_all_in_series'} = $q->param('all_in_series');
$input_parms{'event_days'} = $event_days;
$input_parms{'event_start_time'} = $event_start_time;
$input_parms{'event_end_time'} = $event_end_time;
$input_parms{'all_day'} = $all_day_event;
# Check data for legitimacy.
# some of these checks might be a bit redundant.
if ($current_cal_id eq "") {
$event_valid = 0;
push @{$results{messages}}, "[error]".$lang{update_event_err3};
}
if ($event_title eq "") {
$event_valid = 0;
push @{$results{messages}}, "[error]".$lang{update_event_err4};
}
if ($event_icon eq "") {
$event_valid = 0;
push @{$results{messages}}, "[error]".$lang{update_event_err5};
}
$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;
$temp =~ s/>/>/g;
push @{$results{messages}}, "[warning]".$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{$current_cal_id}) {
$event_valid = 0;
push @{$results{messages}}, "[error]".$lang{update_event_err8};
}
$event_valid = 0 if ($login_valid == 0 && !$options{anonymous_events});
# check dates
if ($event_valid == 1) {
my $verify_date_results = &verify_date($event_start_date);
if ($verify_date_results ne "") {
$event_valid = 0;
my @sub_results = split("\n", $verify_date_results);
foreach $sub_result (@sub_results) {
push @{$results{messages}}, "[error]$lang{update_event_err9} $sub_result";
}
if ($event_days eq "") {
push @{$results{messages}}, "[error]$lang{update_event_err9}$lang{date_verify_err2}";
}
if ($event_days =~ m/\D/ || $event_days <= 0) {
my $temp = $lang{date_verify_err3};
$temp =~ s/\$1/$event_days/;
push @{$results{messages}}, "[error]$lang{update_event_err9}$temp";
}
}
}
# check recurring "repeat until" date
if ($event_valid == 1) {
if ($recurring_event ne "" && $add_edit_event eq "add") {
my $verify_date_results = &verify_date($recurrence_parms{'recur_end_date'}, \%recurrence_parms);
if ($verify_date_results ne "") {
$event_valid = 0;
my @sub_results = split("\n", $verify_date_results);
foreach $sub_result (@sub_results) {
push @{$results{messages}}, "[error]$lang{update_event_err10} $sub_result";
}
}
}
}
# check time
if ($event_valid == 1 && $all_day_event ne "1") {
my $verify_time_results = &verify_time($event_start_time);
if ($verify_time_results ne "") {
$event_valid = 0;
my @sub_results = split("\n", $verify_time_results);
foreach $sub_result (@sub_results) {
push @{$results{messages}}, "[error]$lang{update_event_err14} $sub_result";
}
}
if ($event_end_time ne "") {
my $verify_time_results = &verify_time($event_end_time);
if ($verify_time_results ne "") {
$event_valid = 0;
my @sub_results = split("\n", $verify_time_results);
foreach $sub_result (@sub_results) {
push @{$results{messages}}, "[error]$lang{update_event_err15} $sub_result";
}
}
}
}
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
($event_start_timestamp, $event_end_timestamp) = ×tamp_from_datetime($start_mday,$start_mon,$start_year,$event_days,$event_start_time,$event_end_time,$all_day_event);
$event_end_timestamp +=1 if ($event_start_timestamp == $event_end_timestamp); # give all events a duration of at least 1 second
$event_duration = $event_end_timestamp - $event_start_timestamp;
$no_end_time = 1 if ($event_duration == 1);
$recurrence_parms{'duration'} = $event_duration if ($recurring_event ne "");
if ($recurring_event ne "" && $add_edit_event eq "add") {
my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recurrence_parms{'recur_end_date'}, $current_calendar{date_format});
$recur_end_mon--;
$recurrence_parms{'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}}, "[warning]$lang{update_event_err11}";
}
}
# check for refreshes!
if ($recurring_event eq "") {
my %latest_event = $events{$latest_event_id};
if ($latest_event{cal_ids}[0] eq $current_cal_id &&
$latest_event{start} eq $event_start_timestamp &&
$latest_event{end} eq $event_end_timestamp &&
$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}}, "[error]$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}}, "[error]$lang{update_event_err13}";
}
}
# properly format errors & warnings
$message_results="";
if ($event_valid == 1) {
$results{success} = 1;
#$debug_info .= "(add_update_event) event_id: $event_id\n";
unshift @evt_other_cal_ids, $current_cal_id;
my %new_event = (recurring => $recurring_event,
cal_ids => \@evt_other_cal_ids,
start => $event_start_timestamp,
end => $event_end_timestamp,
all_day_event => $all_day_event,
days => &calculate_event_days($event_start_timestamp, $event_end_timestamp),
title => $event_title,
details => $event_details,
icon => $event_icon,
bgcolor => $event_bgcolor,
block_merge => $event_block_merge,
unit_number => $event_unit_number,
update_timestamp => $rightnow,
existing_id => $event_id,
recurrence_parms => \%recurrence_parms);
if ($login_valid) {
my %commit_results = %{&commit_event(\%new_event, \%input_parms)};
my @commit_messages = @{$commit_results{messages}};
my @new_event_ids = @{$commit_results{new_event_ids}};
$results{messages} = \(@{$results{messages}}, @commit_messages); # array concatenate
$results{new_event_ids} = \@new_event_ids;
} elsif ( $options{anonymous_events} && $add_edit_event eq "add" ) { # anonymous event add -> update queue
my $new_event_id = $max_action_id + int(rand(100)); # just in case several people decide to add something new at the same time.
$new_event{id} = $new_event_id;
# add event to %events data structure
$new_events{$new_event_id} = \%new_event;
# notify email(s)
if ($options{email_mode} > 0) {
my $subj = $lang{notify_subj};
$subj =~ s/\$1/$script_url\/$name/;
my $body = $lang{event_pending_notify};
$body =~ s/\$1/$events{$current_event_id}{title}/;
$body =~ s/\$2/$calendars{$current_cal_id}{title}/;
$body =~ s/\$3/$script_url\/$name?view_pending_event=1&pending_event_id=$new_event_id/;
foreach $add_email (@{$current_calendar{add_emails}}) {
push @{$results{messages}}, "[status]email notification sent to $add_email";
&send_email($add_email, $options{reply_address}, $options{reply_address}, $subj, $body);
}
}
&add_action($new_event_id, "new_event");
$event_box_text .= &generate_event_details(\%new_event, $event_details_template);
$results{text} .= <$lang{update_event_add_pending_successful}
$event_box_text
p1
} else {
$results{'success'} = 0;
}
}
}
return \%results;
} #******************** end add_edit_event *****************************
sub commit_event() { # commit an add or update of an event
my ($new_event_ref, $input_parms_ref) = @_;
my %results;
$results{'messages'} = [];
$results{'new_event_ids'} = [];
my $new_event_id;
my %new_event = %{$new_event_ref};
my %input_parms = %{$input_parms_ref};
#unless ($loaded_all_events eq "1") {
# &load_events("all");
# &normalize_timezone();
#}
if ($add_edit_event eq "add") { # add a new event
if ($new_event{'recurring'} eq "") {
my $event_box_text = "";
$new_event_id = ++$max_event_id;
$events{$new_event_id} = deep_copy(\%new_event);
$events{$new_event_id}{id} = $new_event_id;
&add_event($new_event_id);
$event_box_text .= &generate_event_details($events{$new_event_id}, $event_details_template);
push @{$results{new_event_ids}}, $new_event_id;
#temporarily offset event times by calendar gmtime diff
push @{$results{messages}}, $lang{update_event_add_successful};
} else { # recurring events loop
my %recurrence_parms = %{$new_event{'recurrence_parms'}};
my $new_series_id = ++$max_series_id;
my $date_text = "";
my @recurring_events_timestamps = @{&calculate_recurring_events($new_event{'start'}, \%recurrence_parms)};
my @recurring_event_ids = ();
foreach $recurring_event_start_timestamp (@recurring_events_timestamps) {
my $new_event_id = ++$max_event_id;
my $recurring_event_end_timestamp = $recurring_event_start_timestamp + $recurrence_parms{'duration'};
$events{$new_event_id} = deep_copy(\%new_event);
$events{$new_event_id}{id} = $new_event_id;
$events{$new_event_id}{series_id} = $new_series_id;
$events{$new_event_id}{start} = $recurring_event_start_timestamp;
$events{$new_event_id}{end} = $recurring_event_end_timestamp;
$events{$new_event_id}{recurrence_parms} = [];
push @recurring_event_ids, $new_event_id;
push @{$results{new_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_details_template);
my $temp = <$lang{update_event_add_successful_recurring}
$date_text
$event_box_text
p1
push @{$results{messages}}, $temp;
}
if ($options{email_mode} > 0) {
my $subj = $lang{notify_subj};
$subj =~ s/\$1/$script_url\/$name/;
my $body = $lang{event_add_notify};
$body =~ s/\$1/$new_event{title}/;
$body =~ s/\$2/$calendars{$current_cal_id}{title}/;
$body =~ s/\$3/$script_url\/$name?view_event=1&evt_id=$max_event_id/;
foreach $add_email (@{$current_calendar{add_emails}}) {
push @{$results{messages}}, "[status]email notification sent to $add_email";
&send_email($add_email, $options{reply_address}, $options{reply_address}, $subj, $body);
}
}
} elsif ($add_edit_event eq "edit") { #if we need to replace an existing record
my $event_id = $new_event{'existing_id'};
&load_event( $event_id );
&normalize_timezone( );
my $old_series_id = $events{$event_id}{'series_id'};
if ($new_event{'recurring'} eq "" || $input_parms{'update_all_in_series'} ne "1") {
$events{$event_id} = deep_copy(\%new_event);
$events{$event_id}{id} = $event_id;
$events{$event_id}{'series_id'} = $old_series_id;
&update_event($event_id);
push @{$results{new_event_ids}}, $event_id;
$event_box_text .= &generate_event_details($events{$event_id}, $event_details_template);
push @{$results{messages}}, $lang{update_event_update_successful};
} else { # update recurring events
# get the ids of the events in the series.
my @events_in_series = &get_events_in_series($old_series_id);
&normalize_timezone( );
foreach $event_id (@events_in_series) {
my %event = %{$events{$event_id}};
my @temp = gmtime($event{end});
($recurring_event_start_timestamp, $recurring_event_end_timestamp) = ×tamp_from_datetime($temp[3],$temp[4],$temp[5]+1900,$input_parms{'event_days'},$input_parms{'event_start_time'},$input_parms{'event_end_time'},$input_parms{'all_day'});
$events{$event_id} = deep_copy(\%new_event);
$events{$event_id}{id} = $event_id;
$events{$event_id}{series_id} = $old_series_id;
$events{$event_id}{start} = $recurring_event_start_timestamp;
$events{$event_id}{end} = $recurring_event_end_timestamp;
$events{$event_id}{recurrence_parms} = [];
push @{$results{new_event_ids}}, $event_id;
}
&update_events(\@events_in_series);
push @{$results{messages}}, $lang{update_event_update_successful_recurring};
}
if ($options{email_mode} > 0) {
my $subj = $lang{notify_subj};
$subj =~ s/\$1/$script_url\/$name/;
my $body = "";
$body = $lang{event_update_notify};
$body =~ s/\$1/$new_event{title}/;
$body =~ s/\$2/$calendars{$current_cal_id}{title}/;
$body =~ s/\$3/$script_url\/$name?view_event=1&evt_id=$event_id/;
foreach $email (@{$current_calendar{update_emails}}) {
$debug_info .= "email notification sent to $email\n";
&send_email($email, $options{reply_address}, $options{reply_address}, $subj, $body);
}
}
}
return \%results;
}
sub common_javascript {
my $logged_in_boolean = ($logged_in) ? "true":"false";
my $date_format = lc $current_calendar{date_format};
$return_string .=<
$lang{custom_calendar_title}
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};
$cal_start_day_offset += 7 if ($cal_start_day_offset < 0);
my $cal_start_date = $cal_month_start_date - (86400 * $cal_start_day_offset);
# in continuous_multimonth mode, skip first week if we already drew it in the previous iteration
$cal_start_date = $cal_start_date + 604800 if (!$show_month_breaks && $cal_month_idx > 0 && $cal_start_day_offset != 0);
# start with other_month if the first month does not start on the first day of the week (i.e there is an offset)
@use_other_month = (1, 0) if (!$show_month_breaks && $cal_month_idx == 0 && $cal_start_day_offset != 0 && $current_month % 2);
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) {
$debug = 1 if ($debug == 1 && (&contains(\@debug_events, $event_id) || $debug_events[0] eq "all"));
my %event = %{$events{$event_id}};
if (&time_overlap($event{start}, $event{end}, $week_start_timestamp, $week_end_timestamp)) {
my @event_date_array = gmtime $event{start};
my @event_end_date_array = gmtime $event{end};
my $event_start_weekday = $event_date_array[6] - $current_calendar{week_start_day};
my $event_end_weekday = $event_end_date_array[6] - $current_calendar{week_start_day};
$event_start_weekday +=7 if ($event_start_weekday < 0);
$event_end_weekday +=7 if ($event_end_weekday < 0);
#$event_start_weekday = 0 if ($event_start_weekday < 0);
#$event_end_weekday = 0 if ($event_end_weekday < 0);
#$event_start_weekday = 6 if ($event_start_weekday > 6);
#$event_end_weekday = 6 if ($event_end_weekday > 6);
my $days_before_week_start = 0;
my $days_after_week_end = 0;
$debug_info .= "week $l1 event $event_id event_date_array[6]: $event_date_array[6]\n" if ($debug);
$debug_info .= "week $l1 event $event_id event_end_date_array[6]: $event_end_date_array[6]\n" if ($debug);
$debug_info .= "week $l1 event $event_id current_calendar{week_start_day}: $current_calendar{week_start_day}\n" if ($debug);
$debug_info .= "week $l1 event $event_id event_start_weekday: $event_start_weekday event_end_weekday: $event_end_weekday\n" if ($debug);
# 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):
if ($event{start} < $week_start_timestamp && $event{end} > $week_end_timestamp) { # the event both starts and ends outside this week
$debug_info .= "case 0\n" if ($debug);
$week_events{$l1}{$event{id}}{start_weekday} = 0;
$week_events{$l1}{$event{id}}{length} = 7;
} elsif ($event{start} < $week_start_timestamp) { # the event starts before this week and ends within it
$debug_info .= "case 1\n" if ($debug);
#$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;
$week_events{$l1}{$event{id}}{length} = $event_end_weekday+1;
$debug_info .= "week $l1 event $event_id week_start_timestamp: $week_start_timestamp start: $event{start} start_wkday: $week_events{$l1}{$event{id}}{start_weekday} length: $week_events{$l1}{$event{id}}{length}\n" if ($debug);
} elsif ($event{end} > $week_end_timestamp) { # the event starts within this week and ends after it
$debug_info .= "case 2\n" if ($debug);
$week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
$week_events{$l1}{$event{id}}{length} = 7-$event_start_weekday;
if ($debug == 1) {
foreach $debug_event_id (@debug_events) {
next if ($debug_event_id ne $event{id});
$debug_info .= "event $debug_event_id days: $events{$debug_event_id}{days} event_start_weekday: $event_start_weekday event_end_weekday: $event_end_weekday length: $week_events{$l1}{$debug_event_id}{length}\n";
}
}
} else { #the event begins and ends within the week
$debug_info .= "case 3\n" if ($debug);
$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;
}
$week_events{$l1}{$event{id}}{length} = 7 if ($week_events{$l1}{$event{id}}{length} > 7);
$debug_info .= "week $l1 event $event_id event_start_weekday: $week_events{$l1}{$event{id}}{start_weekday} length: $week_events{$l1}{$event{id}}{length}\n\n" if ($debug);
}
}
$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;
}
if ($debug == 1) {
foreach $debug_event_id (@debug_events) {
$debug_info .= "event $debug_event_id length: $week_events{$l1}{$debug_event_id}{length} start: $events{$debug_event_id}{start}\n";
}
}
#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
my $max_week_needed_slots = 0;
my %max_day_needed_slots;
# hey man, that's a sharp-lookin' sort you got there
foreach $week_event_id (sort {
return $week_events{$l1}{$b}{length} <=> $week_events{$l1}{$a}{length}
if ($week_events{$l1}{$b}{length} != $week_events{$l1}{$a}{length});
return $events{$a}{title} cmp $events{$b}{title}
if ($events{$b}{all_day_event} ne "" && $events{$a}{all_day_event} ne "");
return $events{$b}{all_day_event} cmp $events{$a}{all_day_event}
if ($events{$b}{all_day_event} ne "" || $events{$a}{all_day_event} ne "");
return $events{$a}{start} <=> $events{$b}{start};
}
keys %{$week_events{$l1}})
{
#$debug = 0;
#$debug = 1 if (&contains(\@debug_events, $week_event_id));
#$debug_info .= "week $l1 week_event $week_event_id length: $week_events{$l1}{$week_event_id}{length} start: $events{$week_event_id}{start}\n" if ($debug);
$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;
}
#$debug_info .= "event $week_event_id start_wkday $week_events{$l1}{$week_event_id}{start_weekday} slot $slot_index length $week_events{$l1}{$week_event_id}{length}\n" if ($debug);
#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;
}
}
}
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 ($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";
}
}
}
#if ($l1 == 3) {
#$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 ($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";
}
}
%max_day_needed_slots = (0=>$week_max_slots{$l1},1=>$week_max_slots{$l1},2=>$week_max_slots{$l1},3=>$week_max_slots{$l1},4=>$week_max_slots{$l1},5=>$week_max_slots{$l1},6=>$week_max_slots{$l1});
#$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 "3" && $debug) {
$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}};
$max_day_needed_slots{$l2}--;
#$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 "3" && $debug) {
$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}++;
$max_day_needed_slots{$l2}--;
#$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" if ($debug);
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
next if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0);
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" if ($debug);
$week_slots{$l1}{$l2}{$l4}{width}=0;
$week_slots{$l1}{$l2}{$l4}{depth}=0;
$week_slots{$l1}{$l2}{$l3}{depth}++;
$max_day_needed_slots{$l2}--;
} 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";
# yet another pass. trim vertical depth and re-calculate max_slots
# calculate trim
my $trim = 0;
#$debug_info .= "\n week $l1 max slots: $week_max_slots{$l1}\n";
#$debug_info .= "\nweek $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" if ($debug);
$max_week_needed_slots = max(values %max_day_needed_slots);
#$debug_info .= "week $l1 max_week_needed_slots: $max_week_needed_slots\n";
#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
if ($cal_month_idx == 0 || $show_month_breaks) {
my @lowercase_day_names;
foreach $day_name (@day_names) {
push @lowercase_day_names, lc $day_name;
}
$return_text .=<
$weekday_sequence[0]
$weekday_sequence[1]
$weekday_sequence[2]
$weekday_sequence[3]
$weekday_sequence[4]
$weekday_sequence[5]
$weekday_sequence[6]
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;
$last_week = 1 if ($current_month != $timestamp_next_week_array[4]);
my $week_date_index = $cal_date;
# draw the table!
for ($l3=0;$l3<$week_max_slots{$l1}+1;$l3++) {
$return_text .="
";
$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]);
# display date numbers differently, depending on whether they are in the current month or not
my $cal_month_name = "";
if ($show_month_breaks || $cal_num_months == 1) {
$td_class .= " other_month" if ($cal_date_array[4] != $current_month);
} else {
$td_class .= " other_month_multi" if ($use_other_month[$cal_date_array[4] % 2]);
$cal_month_name = $months[$cal_date_array[4]] if ($cal_date_array[3] == 1);
}
#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.
$return_text .=<
$cal_date_array[3] $cal_month_name
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
} 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
foreach $event_id (@{$week_slots{$l1}{$l2}{$l3}{ids}}) {
my $multi_day_event = ($week_slots{$l1}{$l2}{$l3}{width} > 1) ? 1:0;
my $background_event = (&contains($events{$event_id}{cal_ids}, $current_calendar{id})) ? 0:1;
$return_text .= &display_calendar_event($event_id, $multi_day_event, $background_event)
}
$return_text .=<
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
}
}
$week_date_index += 86400;
} # next day (first row)
#right border
$return_text .=<
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;";
}
$tr_class .= " last_week" if ( $last_week == 1 );
$return_text .=<
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";
$td_class .= " today" if ($cal_date_array[4] == $rightnow_month &&
$cal_date_array[3] == $rightnow_mday &&
$cal_date_array[5]+1900 == $rightnow_year);
if ($show_month_breaks || $cal_num_months == 1) {
$td_class .= " other_month" if ($cal_date_array[4] != $current_month);
} else {
$td_class .= " other_month_multi" if ($use_other_month[$cal_date_array[4] % 2]);
}
$return_text .=<
p1
$week_date_index+=86400;
}
$return_text .=<
p1
$cal_date+=604800;
@cal_date_array = gmtime $cal_date;
}
#close table tag for each month or only for last month on continuous_multimonth mode
if ($show_month_breaks || $last_cal_month) {
$return_text .=<
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++;
$cal_month_idx++;
if ($current_month == 12) {
$current_month=0;
$current_year++;
}
}
return $return_text;
} #********************end render_calendar subroutine**********************
sub background_event_colorize {
my ($event_id, $calendar_id) = @_;
my %event = %{$events{$event_id}};
my %calendar = %{$calendars{$calendar_id}};
my $event_bgcolor = $event{bgcolor};
if ($calendars{$event{cal_ids}[0]}{calendar_events_color} ne "") {
$event_bgcolor = $calendars{$event{cal_ids}[0]}{calendar_events_color};
}
if ($calendar{background_events_display_style} eq "single_color") {
$event_bgcolor = $calendar{background_events_color};
}
return $event_bgcolor;
}
sub display_calendar_event {
my ($event_id, $multi_day, $background_event) = @_;
my %event = %{$events{$event_id}};
my $results = "";
my $event_bgcolor = $event{bgcolor};
# force white color if the background is dark
my $textcolor_style = "";
my $r = hex substr $event_bgcolor,1,2;
my $g = hex substr $event_bgcolor,3,2;
my $b = hex substr $event_bgcolor,5,2;
my $bright = ($r*299+$g*587+$b*114)/1000;
$textcolor_style = "color:#fff" if ($bright < 128);
#$textcolor_style = "color:#000" if ($event_bgcolor == "");
$event_bgcolor = $current_calendar{calendar_events_color} if ($current_calendar{calendar_events_color} ne "");
my $event_box_class = "event_box";
# handle link
my $event_link = "javascript:display_event('$event_id');";
$event_link = "$event{details}" if ($event{details_url} eq "1");
if ($background_event) {
$event_box_class .= " background";
$event_bgcolor = &background_event_colorize($event_id, $current_calendar{id});
}
my $series_text = ($event{series_id} eq "") ? "" : " series_id=\"$event{series_id}\"";
# handle icon
my $icon_text = "";
my $unit_icon_text = "";
if ($event{unit_number} ne "") {
$unit_icon_text = $event{unit_number}." ";
$unit_icon_text =~ s/(\d)//g;
}
my $link_style = "";
if ($event{icon} ne "blank" && $event{icon} ne "") {
$icon_text = <
p1
chomp $icon_text;
$link_style = "padding-left:29px";
}
my $fade_style = "";
if ($calendar{background_events_display_style} eq "single_color") {
$fade_style = "opacity:". 1- ( $calendar{background_events_fade_factor} / 100 );
}
if ($multi_day == 0) {
my $event_time = "";
if ($event{all_day_event} ne "1") {
$event_time = &nice_time_range_format($event{start}, $event{end});
$event_time = " $event_time ";
}
my $temp_item_text = $calendar_item_template;
$temp_item_text =~ s/###icon###/$icon_text$unit_icon_text/g;
$temp_item_text =~ s/###title###/$event{title}/g;
$temp_item_text =~ s/###id###/$event{id}/g;
$temp_item_text =~ s/###time###/$event_time/g;
my $calendar_title = $calendars{$event{cal_ids}[0]}{title};
$temp_item_text =~ s/###calendar title###/$calendar_title/g;
$results .=<
$temp_item_text
p1
} else { # multi-day-event
# handle the case where an event is < 24 hours and crosses midnight.
my $nudge_edge="";
my $event_time = "";
if ($event{all_day_event} ne "1") {
if ($event{end} - $event{start} < 86400) {
my $offset = 25;
my $width = 50;
$nudge_edge = "width:$width%;position:relative;left:$offset%;";
}
$event_time = &nice_time_range_format($event{start}, $event{end});
$event_time = " $event_time ";
}
if ($event{icon} ne "blank" && $event{icon} ne "") {
$icon_text = <
p1
chomp $icon_text;
}
my $temp_item_text = $calendar_item_template;
$temp_item_text =~ s/###icon###/$icon_text$unit_icon_text/g;
$temp_item_text =~ s/###title###/$event{title}/g;
$temp_item_text =~ s/###time###/$event_time/g;
my $calendar_title = $calendars{$event{cal_ids}[0]}{title};
$temp_item_text =~ s/###calendar title###/$calendar_title/g;
$results .=<
$temp_item_text
p1
}
}
sub display_list_event {
my ($event_id, $background_event, $sameday) = @_;
my %event = %{$events{$event_id}};
my $results="";
@event_start_timestamp_array = gmtime $event{start};
my $date_string;
my $weekday_string;
if ($event{days} == 1) {
#single-day event
$date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
$weekday_string = $day_names_abv[$event_start_timestamp_array[6]]
} 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]";
}
$weekday_string = "$day_names_abv[$event_start_timestamp_array[6]]-$day_names_abv[$event_end_timestamp_array[6]]";
}
# weekday abbreviations
my $weekday_abv_string = $weekday_string;
for ($l1=0;$l1/g;
}
if ($event{icon} eq "blank" || $event{icon} eq "") {
$icon_text .= "$unit_icon_text";
} else {
$icon_text .= "$unit_icon_text";
}
my $event_bgcolor = $event{bgcolor};
if ($calendars{$event{cal_ids}[0]}{calendar_events_color} ne "") {
$event_bgcolor = $calendars{$event{cal_ids}[0]}{calendar_events_color};}
if ($background_event eq "1") {
$event_bgcolor = &background_event_colorize($event_id, $current_calendar{id});
}
# event time
my $event_time = "";
if ($event{all_day_event} ne "1") {
$event_time = &nice_time_range_format($event{start}, $event{end});
$event_time = "$event_time";
}
my $event_link = "javascript:display_event('$event{id}');";
if ($event{details_url} eq "1") {
$event_link = "$event{details}";}
my $margin_top="7px";
$margin_top = "0" if ($sameday);
my $temp_item_text = $list_item_template;
$temp_item_text =~ s/###variable_margin###/$margin_top/g;
$temp_item_text =~ s/###id###/$event_id/g;
$temp_item_text =~ s/###bgcolor###/$event_bgcolor/g;
$temp_item_text =~ s/###link###/$event_link/g;
$temp_item_text =~ s/###details###/$event{details}/g;
$temp_item_text =~ s/###icon###/$icon_text/g;
$temp_item_text =~ s/###title###/$event{title}/g;
$temp_item_text =~ s/###date###/$date_string/g;
$temp_item_text =~ s/###weekday###/$weekday_string/g;
$temp_item_text =~ s/###weekday_abv###/$weekday_abv_string/g;
$temp_item_text =~ s/###time###/$event_time/g;
$results .= $temp_item_text;
$no_results .=< $date_string $icon_text $event_time $event{title}
p1
return $results;
}
sub render_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
my @selected_cal_events;
#and a funky data structure for the background calendars
# each element of this hash will be an array.
my $shared_cal_events={}; #empty hash
foreach $event_id (keys %events) {
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
my $event_in_current_calendar = 0;
foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
if ($temp_cal_id eq $current_cal_id) {
push @selected_cal_events, $event_id;}
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
if ($temp_cal_id eq $background_cal_id) {
if ($current_calendar{list_background_calendars_together} eq "yes") {
push @selected_cal_events, $event_id;
} else {
push @{$shared_cal_events{$background_cal_id}}, $event_id if (!&contains(\@selected_cal_events, $event_id));
}
}
}
}
}
}
# initialize loop variables
$current_month = $start_month;
$current_year = $start_year;
$return_text .=<
p1
if ($cal_num_months> 1) {
$return_text .=<
$months[$current_month] $current_year
p1
}
if ($current_calendar{list_background_calendars_together} eq "yes") {
$return_text .=<
$calendars{$current_cal_id}{title}
p1
#display events for selected calendar
my $previous_event_id;
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 $background_event = "";
$background_event = "1" if ($event{cal_ids}[0] ne $current_cal_id);
my @temp1 = gmtime($event{start});
my @temp2 = gmtime($events{$previous_event_id}{start});
my $sameday = "";
$sameday = "1" if ($temp1[3] == $temp2[3]);
$return_text .= &display_list_event($event_id, $background_event, $sameday);
$previous_event_id = $event_id;
}
}
$return_text .=<
p1
} else {
$return_text .=<
$calendars{$current_cal_id}{title}
p1
#display events for selected calendar
my $previous_event_id;
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 @temp1 = gmtime($event{start});
my @temp2 = gmtime($events{$previous_event_id}{start});
my $sameday = "";
$sameday = "1" if ($temp1[3] == $temp2[3]);
$return_text .= &display_list_event($event_id,0,$sameday);
$previous_event_id = $event_id;
}
}
$return_text .=<
p1
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
$return_text .=<
$calendars{$background_cal_id}{title}
p1
#list events for that calendar
my $previous_event_id;
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)) {
my @temp1 = gmtime($event{start});
my @temp2 = gmtime($events{$previous_event_id}{start});
my $sameday = "";
$sameday = "1" if ($temp1[3] == $temp2[3]);
$return_text .= &display_list_event($event_id,1,$sameday);
$previous_event_id = $event_id;
}
}
$return_text .=<
p1
}
}
$return_text .=<
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 .=<
";
}
return $results;
}
sub csv_file_palm {
($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 list view dates
my @selected_cal_events;
#and a funky data structure for the background calendars
# each element of this hash will be an array.
my $shared_cal_events={}; #empty hash
foreach $event_id (keys %events) {
if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
my $event_in_current_calendar = 0;
foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
if ($temp_cal_id eq $current_cal_id) {
push @selected_cal_events, $event_id;}
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
if ($temp_cal_id eq $background_cal_id) {
push @{$shared_cal_events{$background_cal_id}}, $event_id;}
}
}
}
}
$html_output =< $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}";
@event_start_timestamp_array = gmtime $event{start};
my $csv_start_date = ($event_start_timestamp_array[5]+1900)." ".($event_start_timestamp_array[4]+1)." ".($event_start_timestamp_array[3]);
my $csv_start_time = "$event_start_timestamp_array[2]:$event_start_timestamp_array[1]";
@event_end_timestamp_array = gmtime $event{end};
my $csv_end_date = ($event_end_timestamp_array[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
my $csv_end_time = "$event_end_timestamp_array[2]:$event_end_timestamp_array[1]";
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[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
}
$html_output .=< $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}";
@event_start_timestamp_array = gmtime $event{start};
my $csv_start_date = ($event_start_timestamp_array[5]+1900)." ".($event_start_timestamp_array[4]+1)." ".($event_start_timestamp_array[3]);
my $csv_start_time = "$event_start_timestamp_array[2]:$event_start_timestamp_array[1]";
@event_end_timestamp_array = gmtime $event{end};
my $csv_end_date = ($event_end_timestamp_array[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
my $csv_end_time = "$event_end_timestamp_array[2]:$event_end_timestamp_array[1]";
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[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
}
$html_output .=< $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 .=< $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 .=< $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)) {
$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)) {
$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 .=< $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] ".($event_start_timestamp_array[5]+1900);
if ($event{all_day_event} ne "1") {
$event_time = &nice_time_range_format($event{start}, $event{end});
$event_time = " ($event_time)";
}
} else { #multi-day event
$date_string = &nice_date_range_format($event{start}, $event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
}
my $event_details = $event{details};
$event_details =~ s/\n[ \t\r\f]+/\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";
}
$html_output .= "\n";
}
}
foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
$html_output .=< $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] ".($event_start_timestamp_array[5]+1900);
if ($event{all_day_event} ne "1") {
$event_time = &nice_time_range_format($event{start}, $event{end});
$event_time = " ($event_time)";
}
} else { #multi-day event
$date_string = &nice_date_range_format($event{start}, $event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
}
my $event_details = $event{details};
$event_details =~ s/\n[ \t\r\f]+/\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";
}
$html_output .= "\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;
} #********************end ascii_text_cal subroutine**********************
sub ascii_text_event {
my %current_event = %{$events{$current_event_id}};
$html_output =< 23 || $hours < 0){
$lang{time_verify_err1} =~ s/\{0\}/$hours/;
$results .= $lang{time_verify_err1};
}
if ($minutes > 59 || $minutes < 0){
$lang{time_verify_err2} =~ s/\{0\}/$minutes/;
$results .= $lang{time_verify_err2};
}
}
} else {
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 preview_date {
my $results = {};
$results{'success'} = 1;
$results{'messages'} = [];
my @valid_dates;
my %recurrence_parms;
$recurrence_parms{'recurrence_type'} = $q->param('recurrence_type');
$recurrence_parms{'weekday_of_month_type'} = $q->param('weekday_of_month_type');
$recurrence_parms{'every_x_days'} = $q->param('every_x_days');
$recurrence_parms{'every_x_weeks'} = $q->param('every_x_weeks');
$recurrence_parms{'year_fit_type'} = $q->param('year_fit_type');
$recurrence_parms{'recur_end_date'} = $q->param('recur_end_date');
$recurrence_parms{'recur_end_timestamp'} = 0;
my @custom_months = $q->param('custom_months');
$recurrence_parms{'custom_months'} = \@custom_months;
my $recurring_event = $q->param('recurring_event');
my $event_start_date = $q->param('evt_start_date');
my $recur_end_date = $q->param('recur_end_date');
my $event_days = $q->param('evt_days');
my $event_start_time = $q->param('evt_start_time');
my $event_end_time = $q->param('evt_end_time');
my $all_day_event = $q->param('all_day_event');
my $date_valid = &verify_date($event_start_date);
if ( $date_valid ne "" ) {
$results{'success'} = 0;
push @{$results{messages}}, $date_valid;
}
if ($event_days eq "") {
$results{'success'} = 0;
push @{$results{messages}}, $lang{date_verify_err2};
}
if ($event_days =~ m/\D/ || $event_days <= 0) {
$results{'success'} = 0;
my $temp = $lang{date_verify_err3};
$temp =~ s/\$1/$event_days/;
push @{$results{messages}}, $temp;
}
if ($recurring_event) {
my $temp .= &verify_date($recurrence_parms{'recur_end_date'}, \%recurrence_parms);
if ($temp ne "") {
$results{'success'} = 0;
push @{$results{messages}}, $lang{date_preview_for_recurring_end_date}. " " . $temp;
}
}
if ($results{'success'} == 1) {
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($recurrence_parms{'recur_end_date'}, $current_calendar{date_format});
$start_mon--;
$recur_end_mon--;
my ($event_start_timestamp, $event_end_timestamp) = ×tamp_from_datetime($start_mday,$start_mon,$start_year,$event_days,$event_start_time,$event_end_time,$all_day_event);
@timestamp_array = gmtime $event_start_timestamp;
my $real_year = $timestamp_array[5]+1900;
if ($recurring_event == 1) {
#calculate end timestamp
$recurrence_parms{'recur_end_timestamp'} = timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year);
my @recurring_events_array = @{&calculate_recurring_events($event_start_timestamp, \%recurrence_parms)};
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, "-");
push @valid_dates, $date_range;
}
} 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, "-");
push @valid_dates, $date_range;
}
}
$results{success} = ($results{success} eq "1") ? JSON::PP::true() : JSON::PP::false();
$results{debug_info} = $debug_info;
$results{valid_dates} = \@valid_dates;;
$json_results = encode_json \%results;
print <\n/g;
my $html_output .=<
p1
$html_output .= &get_js_includes( $theme_url );
$html_output .= <$current_event{title}
$event_info
$debug_info
p1
print $html_output;
} # view_event
sub view_pending_event {
my ($pending_event_ref) = @_;
my %pending_event = %{$pending_event_ref};
$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/###email reminder link###/$lang{event_email_reminder_disable}/g;
my $event_info = &generate_event_details(\%pending_event, $event_details_template);
$debug_info =~ s/\n/ \n/g;
my $html_output .=<
p1
$html_output .= &get_js_includes( $theme_url );
$html_output .= <$current_event{title}
$event_info
$debug_info
p1
print $html_output;
} # view_pending_event
sub set_email_reminder {
my $results = {};
$results{'success'} = 1;
$results{'messages'} = [];
my %current_event = %{$events{$current_event_id}};
my $reminder_results = "";
my $to_address = $q->param('email_address');
my $extra_text = $q->param('extra_text');
$to_address =~ s/\s//g;
$to_address =~ s/;/,/g;
chomp $to_address;
my $reminder_seconds = $q->param('reminder_seconds');
my $reminder_time = $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;
push @{$results{messages}}, $reminder_results;
$results{'success'} = 0;
} else {
my @event_reminder_ids = ($current_event{id});
my @future_event_reminder_ids;
if ($q->param('all_in_series') ne "") {
@event_reminder_ids = &get_events_in_series($current_event{series_id});
&normalize_timezone();
}
foreach $event_reminder_id (@event_reminder_ids) {
if ($events{$event_reminder_id}{start} > $rightnow) {
push @future_event_reminder_ids, $event_reminder_id;
}
}
foreach $event_reminder_id (@future_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($extra_text, "extra_text").
&xml_store("$script_url/$name", "script_url").
&xml_store($rightnow, "timestamp");
$reminder_xml = "$reminder_xml\n";
# write email reminder to file
open (FH, ">>$options{email_reminders_datafile}") || ($debug_info .=" Unable to open email reminders data file $options{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}, " - ");
my $event_time = "";
if ($current_event{all_day_event} ne "1") {
$event_time = &nice_time_range_format($current_event{start}, $current_event{end});
}
$reminder_text =~ s/###time###/$event_time/g;
$reminder_text =~ s/###title###/$current_event{title}/g;
$reminder_text =~ s/###date###/$date_string/g;
$reminder_text =~ s/###extra text###/$extra_text/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}
}
push @{$results{messages}}, $lang{email_reminder_results1};
push @{$results{messages}}, $test_reminder_results;;
}
$results{success} = ($results{success} eq "1") ? JSON::PP::true() : JSON::PP::false();
$results{debug_info} = $debug_info;
$json_results = encode_json \%results;
print <param('remote_calendar_url');
$remote_calendar_url =~ s/\?.+//;
$remote_calendar_url .= "/" if ($remote_calendar_url !~ /\.cgi$/);
$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);
my %remote_calendars = %{&xml2hash($xml_results)};
my @public_calendars;
if (ref $remote_calendars{'xml'}{public_calendar} eq "ARRAY") {
@public_calendars = @{$remote_calendars{'xml'}{public_calendar}};
} else {
push @public_calendars, $remote_calendars{'xml'}{public_calendar};
}
$results{public_calendars} = \@public_calendars;
$results{url} = $remote_calendar_base_url;
$results{remote_calendar_version} = $remote_calendars{'xml'}{plans_version};
$results{success} = ($results{success} eq "1") ? JSON::PP::true() : JSON::PP::false();
$results{debug_info} = $debug_info;
$json_results = encode_json \%results;
print <param('cal_id');
$results .=<$plans_version
p1
# 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_id (keys %events) {
my $event_in_current_calendar = 0;
foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
if ($temp_cal_id eq $current_cal_id) {
$event_in_current_calendar = 1;
last;
}
}
next if ($event_in_current_calendar == 0);
my $xml_data = &event2xml($events{$event_id});
$results .=<Script Name:$name
p1
if ($options{email_mode} && !$writable{email_reminders_datafile}) {
$results .=<Warning: The email reminders data file: $options{email_reminders_datafile} is not writable. This will
cause some email functions to be disabled or not work correctly.
p1
}
if ($options{data_storage_mode} == 0 && !$writable{calendars_file}) {
$results .=<Warning: The calendars data file: $options{calendars_file} is not writable. The add/edit calendars tab won't appear
unless this file is writable.
p1
}
if ($options{data_storage_mode} == 0 && !$writable{pending_actions_file}) {
$results .=<Warning: The pending actions data file: $options{pending_actions_file} is not writable. The add/edit calendars tab won't appear
unless this file is writable.
p1
}
if ($options{data_storage_mode} == 0 && !$writable{events_file}) {
$results .=<Warning: The events data file: $options{events_file} is not writable. The add/edit events tab won't appear
unless this file is writable.
p1
}
my $cwd = `pwd`;
$results .=<Plans version: $plans_version script name: $name script file path:$cwd script url path: $script_url