Fixing http%3A bug for after adding a new iCal Calendar
[plans.git] / plans.cgi
blobd1f66768e07915c10d0d84b91bbecd49d49fb1ea
1 #!/usr/bin/perl
3 # before anything else, the script needs to find out its own name
5 # some servers (notably IIS on windows) don't set the cwd to the script's
6 # directory before executing it. So we get that information
7 # from $0 (the full name & path of the script).
8 BEGIN{($_=$0)=~s![\\/][^\\/]+$!!;push@INC,$_}
10 $name = $0;
11 $name =~ s/.+\/?.+\///; # for unix
12 $name =~ s/.+\\.+\\//; # for windows
13 $path = $0;
14 $path =~ s/(.+\/).+/$1/g; # for unix
15 $path =~ s/(.+\\).+/$1/g; # for windows
17 # The "use Cwd" method would be nice, but it doesn't work with
18 # some versions of IIS/ActivePerl
19 #use Cwd;
20 #$path = cwd;
22 if ($path ne "") {
23 chdir $path;
24 push @INC,$path;
26 # finished discovering name
28 #use Data::Dumper;
30 # some global variables (more further down)
31 local $plans_version = "7.9.7"; # version
32 local $debug_info;
33 local %options;
34 local $perl_version = (sprintf ("%vd",$^V));
35 #local $options{data_storage_mode};
36 local $fatal_error = 0; # fatal errors cause plans to abort and print an error message to the browser
37 local $error_info = "";
38 local $html_output;
39 local $script_url = "";
40 local $messages = ""; # formatted in plain text with newlines. Converted to html at display time.
42 local $template_html;
43 local $local_template_file = 0; # tells whether the template was loaded via a filesystem open or through a http request.
44 local $event_details_template;
45 local $list_item_template;
46 local $calendar_item_template;
47 local $upcoming_item_template;
49 local %calendars;
50 local %current_calendar;
51 local %latest_calendar;
52 local %new_calendars;
53 local $normalized_timezone = 0;
54 local $normalized_timezone_pending_events = 0;
56 # used when adding new entries
57 local $max_cal_id = 0;
58 local $max_event_id = 0;
59 local $max_series_id = 0;
60 local $max_user_id = 0;
61 local $max_action_id = 0;
63 # used to protect against refreshes
64 local $latest_cal_id = 0;
65 local $latest_event_id = 0;
66 local $latest_new_cal_id = 0;
67 local $latest_new_event_id = 0;
69 local $session;
70 local %users;
71 my $profile;
72 local $logged_in = 0;
73 local $logged_in_as_root = 0;
74 local $logged_in_as_current_cal_user = 0;
75 local $logged_in_as_current_cal_admin = 0;
77 local $lg_name = "";
78 local $lg_password = "";
80 local %events;
81 local %new_events;
82 local @pending_events_to_display;
84 local %text;
85 local %cookie_parms;
86 local $cookie_text = "";
87 local $cookie_header_text = "";
88 local $max_remote_event_id = 0;
90 local $options{default_template_path} = "";
91 local $theme_url = "";
92 local $options{choose_themes} = "";
93 local $graphics_url = "";
94 local $ical_export_url = "";
95 local $icons_url = "";
96 local $input_cal_id_valid = 0;
97 local $options{right_click_menus_enabled} = 0;
98 local %cal_options;
100 local $rightnow;
101 local @months;
102 local @months_abv;
103 local @day_names;
104 local $loaded_all_events; # flag used to avoid calling load_events("all") twice
105 # not needed for calendars (we always load all calendars)
107 local @disabled_tabs;
109 # check for required modules.
111 my $module_found=0;
112 foreach $temp_path (@INC) {
113 if (-e "$temp_path/plans_config.pl") {
114 $module_found=1;}
116 if ($module_found == 0) {
117 $fatal_error=1;
118 $error_info .= "Unable to locate <b>plans_config.pl</b>! It should be in the same directory as plans.cgi!\n";
119 } else {require "plans_config.pl";}
123 $module_found=0;
124 foreach $temp_path (@INC) {
125 if (-e "$temp_path/CGI") {
126 $module_found=1;}
129 if ($module_found == 0) {
130 $fatal_error=1;
131 $error_info .= "unable to locate required module <b>CGI</b>!\n";
132 } else {
133 use CGI;}
135 $module_found=0;
136 foreach $temp_path (@INC) {
137 if (-e "$temp_path/CGI/Session") {
138 $module_found=1;}
141 if ($options{sessions} eq "1") {
142 if ($module_found == 0) {
144 $fatal_error = 1;
145 $error_info .= "unable to locate required module <b>CGI::Session</b>!\n";
146 } else {
147 require CGI::Session;}
150 $module_found=0;
151 foreach $temp_path (@INC) {
152 if (-e "$temp_path/CGI/Carp.pm") {
153 $module_found=1;}
156 if ($module_found == 0) {
157 $fatal_error=1;
158 $error_info .= "unable to locate required module <b>CGI::Carp</b>!\n";
159 } else {
160 use CGI::Carp qw/fatalsToBrowser/;}
162 $module_found=0;
163 foreach $temp_path (@INC) {
164 if (-e "$temp_path/Time") {
165 $module_found=1;}
168 if ($module_found == 0) {
169 $fatal_error=1;
170 $error_info .= "unable to locate required module <b>Time.pm</b>!\n";
171 } else {
172 use Time::Local;}
174 $module_found=0;
175 foreach $temp_path (@INC) {
176 if (-e "$temp_path/IO.pm") {
177 $module_found=1;}
179 if ($module_found == 0) {
180 $fatal_error=1;
181 $error_info .= "unable to locate required module <b>IO.pm</b>!\n";
182 } else {
183 use IO::Socket;}
185 if ($fatal_error == 1) { # print error and bail out
186 &fatal_error();
190 $module_found=0;
191 foreach $temp_path (@INC) {
192 if (-r "$temp_path/plans_lib.pl") {
193 $module_found=1;}
195 if ($module_found == 0) {
196 $fatal_error=1;
197 $error_info .= "Unable to locate <b>plans_lib.pl</b>! It should be in the same directory as plans.cgi!\n";
198 } else {require "plans_lib.pl";}
200 # multi-language stuff
201 if (defined $options{language_files}) {
202 my @language_files = split(',', $options{language_files});
204 # pull in language files
205 foreach $language_file (@language_files) {
207 $module_found=0;
208 foreach $temp_path (@INC) {
209 if (-r "$temp_path/$language_file") {
210 $module_found=1;}
212 if ($module_found == 0) {
213 $fatal_error=1;
214 $error_info .= "Unable to locate language file <b>$language_file</b>! It should be in the same directory as plans.cgi!\n";
215 } else {require $language_file;}
218 # create a javascript file with language strings
219 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"};
220 flock FH,2;
221 my $first_lang_line=<FH>;
222 close FH;
224 if ($options{generate_js_lang} eq "1" || $first_lang_line !~ /$plans_version/) {
225 my $lang_string = "";
226 $lang_string .= "//$plans_version\n";
227 $lang_string .= "var plans_lang = new Array();\n";
229 # generate %lang keys
230 foreach $lang_key (keys %lang) {
231 if (ref $lang{$lang_key} eq "ARRAY") {
232 $lang_string .= "plans_lang['$lang_key']=new Array(";
233 my $first = 1;
234 foreach $key (@{$lang{$lang_key}}) {
235 if (!$first) {$lang_string .= ',';}
236 if ($first) {$first = 0;}
238 my $lang_val = &js_string($key);
239 $lang_string .= "'$lang_val'";
241 $lang_string .= ");\n";
243 } else {
244 my $lang_val = &js_string($lang{$lang_key});
246 $lang_string .= "plans_lang['$lang_key']='$lang_val';\n"
250 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"};
251 flock FH,2;
252 print FH $lang_string;
253 close FH;
255 } else {
256 $fatal_error=1;
257 $error_info .= "No language files defined in plans.config!\n";
260 # check for perl version
261 my $temp = substr($perl_version,0,3);
262 if ($temp < 5.6) {
263 $fatal_error=1;
264 $error_info .= "Your version of perl ($perl_version) is too old! Plans requires perl version 5.6 or better.\n";
267 if ($fatal_error == 1) { # print error and bail out
268 &fatal_error();
272 # init cgi stuff
273 $q = new CGI;
274 if ($options{calendar_url} ne "") {
275 $script_url = $options{calendar_url};
276 } else {
277 $script_url = $q->url(-path_info>=1);
279 $script_url =~ /(.*)\//; # remove trailing / and all text after
280 $script_url = $1; # remove trailing / and all text after
282 %cookie_parms = %{&extract_cookie_parms()};
283 my $cookie_path = $q->url( -absolute => 1 );
284 $cookie_path =~ s/$name$//;
285 $cookie_path =~ s/admin\/?$//; # This is better than using just '/'
287 # check if data files or tables are present
288 &check_data();
290 # fatal error? Print error and bail out
291 if ($fatal_error == 1) {
292 &fatal_error();}
295 if ($theme_url eq "") { # not defined in config file
296 $theme_url = "$script_url/theme";
299 if ($options{choose_themes}) {
300 $chosen_url = $q->param('theme_url');
301 $chosen_url = $cookie_parms{'theme_url'} if ($chosen_url eq "");
302 $theme_url = $chosen_url if ($chosen_url ne "");
305 $graphics_url ="$theme_url/graphics"; # where misc. graphics are
306 $ical_export_url ="$theme_url/ical"; # where icalendar .ics files are placed
307 $icons_url = "$theme_url/icons"; # where icons are
308 $css_path = "$theme_url/plans.css"; # css file
311 # globals from http parameters
312 my $active_tab = $q->param('active_tab') + 0; # +0 ensures numericity
313 $active_tab = 0 if ($active_tab > scalar @{$lang{tab_text}} - 1);
315 my $api_output_format = $q->param('output_format');
316 my $api_command = $q->param('api_command');
318 my $add_edit_cal_action = $q->param('add_edit_cal_action');
319 $add_edit_cal_action = "" if (!&contains(["add", "edit", "view_pending"],$add_edit_cal_action)); # validate
321 my $add_edit_event = $q->param('add_edit_event');
322 $add_edit_event = "" if (!&contains(["add", "edit"],$add_edit_event)); # validate
324 local $current_event_id = $q->param('evt_id');
325 $current_event_id = "" if ($current_event_id !~ /^R?\d+$/); # validate
327 local $current_event_ids = $q->param('evt_ids');
328 $current_event_ids = "" if ($current_event_ids !~ /^R?[\d,\,]+$/); # validate
330 local $pending_event_id = $q->param('pending_event_id');
331 $pending_event_id = "" if ($pending_event_id !~ /^R?\d+$/); # validate
333 local $cal_start_month = $q->param('cal_start_month') + 0; # +0 ensures numericity
334 local $cal_start_year = $q->param('cal_start_year') + 0; # +0 ensures numericity
335 local $cal_num_months = $q->param('cal_num_months') + 0; # +0 ensures numericity
337 # if view parameters not supplied in http request, check cookie
338 $cal_start_month = $cookie_parms{'cal_start_month'} if ($q->param('cal_start_month') eq "");
339 $cal_start_year = $cookie_parms{'cal_start_year'} if ($cal_start_year == 0);
340 $cal_num_months = $cookie_parms{'cal_num_months'} if ($cal_num_months == 0);
342 my $special_action = $q->param('special_action'); # needs no validation - never used in output
344 local $display_type = $q->param('display_type') + 0; # +0 ensures numericity
345 $display_type = $cookie_parms{'display_type'} if ($q->param('display_type') eq "");
348 $messages = $q->param('messages') if ($q->param('messages') ne "");
351 # other globals
352 my $event_start_date;
353 my $event_start_timestamp;
354 my $event_days;
355 my $start_mday;
356 my $start_mon;
357 my $start_year;
358 my @timestamp_array;
360 my $prev_month_link = "";
361 my $next_month_link = "";
363 # load calendar data
364 &load_calendars();
365 &load_users();
366 &load_actions();
368 local $current_cal_id = 0;
370 if ($q->param('cal_id') eq "") {
371 $current_cal_id = $cookie_parms{'cal_id'} if ($current_cal_id == 0);
372 } else {
373 $current_cal_id = $q->param('cal_id');
375 $current_cal_id += 0; # +0 ensures numericity
377 # if calendar id not supplied, but evt_id is supplied (like when viewing an event) use that event's calendar as the current calendar
378 #if ($current_event_id ne "")
380 # &load_event($current_event_id);
382 # my %temp_current_event = %{$events{$current_event_id}};
383 # if ($current_cal_id eq "")
385 # $current_cal_id = $temp_current_event{cal_ids}[0];
389 foreach $cal_id (keys %calendars) {
390 if ($cal_id eq $current_cal_id) {
391 $input_cal_id_valid = 1;}
394 if ($current_cal_id eq "") {
395 $input_cal_id_valid = 0;}
397 if ($current_cal_id =~ /\D/) {
398 $input_cal_id_valid = 0;}
400 $current_cal_id = 0 if ($current_event_id eq "" && !$input_cal_id_valid);
402 # make all calendars selectable by default
403 foreach $cal_id (keys %calendars) {
404 $default_cal{selectable_calendars}{$cal_id} = 1;}
406 %current_calendar = %{$calendars{$current_cal_id}};
408 # time-related globals
409 $rightnow = time() + 3600 * $current_calendar{gmtime_diff};
410 @rightnow_array = gmtime $rightnow;
411 $rightnow_year = $rightnow_array[5]+1900;
412 $rightnow_month = $rightnow_array[4];
413 $rightnow_mday = $rightnow_array[3];
414 $next_year = $rightnow_year+1;
415 $rightnow_description = formatted_time($rightnow, "hh:mm:ss mn md yy");
417 @weekday_sequence = @day_names;
419 # session stuff
421 if ($options{sessions} eq "1") {
422 #$lg_name = $q->param('lg_name');
423 $lg_name = $current_cal_id;
424 $lg_password = $q->param('cal_password');
426 &delete_old_sessions(1); # in days
428 #$debug_info .= "plans_sid (cookie): ".$q->cookie("plans_sid")."\n";
430 my $current_session_id = $q->cookie("plans_sid") || undef;
433 $session = new CGI::Session(undef, $current_session_id, {Directory=>$options{sessions_directory}});
434 $session->expire("+1d");
436 #$debug_info .= "current_session_id: $current_session_id\n";
438 # log out?
439 if ($q->param('logout') eq "1") {
440 $session->delete();
441 $cookie_text .= "Set-Cookie; plans_sid=deleted; path=$cookie_path;\n";
444 # try to match session with user id. (If this fails, it's not really a session.)
445 my $results = &init_session($q, $session);
446 $profile = $session->param("~profile");
448 if (defined $profile->{calendar_permissions}) {
449 $logged_in = 1;
450 $cookie_text .= "Set-Cookie: plans_sid=".$session->id."; path=$cookie_path;\n";
454 if ($options{sessions} eq "1") {
455 $logged_in_as_root = ($profile->{calendar_permissions}->{0}->{admin} eq "1") ? 1:0;
456 $logged_in_as_current_cal_user = ($profile->{calendar_permissions}->{$current_cal_id}->{user} ne "") ? 1:0;
457 $logged_in_as_current_cal_admin = ($profile->{calendar_permissions}->{$current_cal_id}->{admin} ne "") ? 1:0;
458 } elsif ($q->param('cal_password') ne "") {
459 $logged_in_as_root = ($calendars{0}{password} eq crypt($q->param('cal_password'), $options{salt})) ? 1:0;
460 $logged_in_as_current_cal_admin = ($current_calendar{password} eq crypt($q->param('cal_password'), $options{salt})) ? 1:0;
462 foreach $user_id (keys %users) {
463 my %user = %{$users{$user_id}};
464 my %user_calendars = %{$user{calendars}};
465 foreach $user_cal_id (keys %user_calendars) {
466 if ($user_cal_id eq $current_cal_id && $user{calendars}{$user_cal_id}{edit_events} eq "1" &&
467 $user{password} eq crypt($q->param('cal_password'), $options{salt})) {
468 $logged_in_as_current_cal_user = 1;
469 last;
471 last if ($logged_in_as_current_cal_user == 1);
473 last if ($logged_in_as_current_cal_user == 1);
477 $logged_in_as_current_cal_user = 0 if (!$options{users}) ;
479 #$debug_info .= "init_session results: $results\n";
480 #$debug_info .= "logged-in: ".$session->param("~logged-in")."\n";
481 #$debug_info .= "session id: ".$session->id."\n";
482 #$debug_info .= "profile user_id: ".$profile->{calendar_permissions}->{$current_cal_id}."\n";
484 #$debug_info .= "options{sessions}: $options{sessions}\n";
485 #$debug_info .= "logged_in_as_root: $logged_in_as_root\n";
486 #$debug_info .= "logged_in_as_current_cal_user: $logged_in_as_current_cal_user\n";
487 #$debug_info .= "logged_in_as_current_cal_admin: $logged_in_as_current_cal_admin\n";
488 #$debug_info .= "current_calendar{password}: $current_calendar{password}\n";
489 #$debug_info .= ($profile->{calendar_permissions}->{$current_cal_id}->{admin})."\n";
492 # custom stylesheet?
493 if ($current_calendar{custom_stylesheet} ne "") {
494 $css_path = "http://$current_calendar{custom_stylesheet}";
497 # if this is a custom calendar request, shoehorn the request parameters in
498 if ($q->param('custom_calendar') eq "1") {
499 $current_cal_id = $q->param('custom_calendar_calendar') + 0;
500 @custom_calendar_backgound_calendars = $q->param('custom_calendar_background_calendars');
502 foreach $local_background_calendar (keys %{$calendars{$current_cal_id}{local_background_calendars}}) {
503 delete $calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar};}
505 foreach $local_background_calendar (@custom_calendar_backgound_calendars) {
506 $calendars{$current_cal_id}{local_background_calendars}{$local_background_calendar} = 1;}
508 %current_calendar = %{$calendars{$current_cal_id}};
514 # make sure we can select the current calendar
515 #$current_calendar{selectable_calendars}{$current_cal_id} = 1;
518 # set info window height & width
519 $current_calendar{info_window_size} ="400x400" if ($current_calendar{info_window_size} eq ""); # default
520 my ($info_window_width, $info_window_height) = split("x", $current_calendar{info_window_size});
523 # rotate weekday_sequence by the offset defined in the week start day.
524 for ($l1=0;$l1 < $current_calendar{week_start_day};$l1++) {
525 push @weekday_sequence, (shift @weekday_sequence);}
529 # load background_colors
530 my @temp_lines = split ("\n", $event_background_colors);
532 foreach $temp_line (@temp_lines) {
533 next if ($temp_line !~ /\w/); # skip any blank lines
535 $temp_line =~ s/^\s+//;
536 my ($hex_color, $hex_color_title) = split (/,*\s+/, $temp_line, 2);
537 $hex_color_title = "&nbsp;" if ($hex_color_title eq "");
539 push @event_bgcolors, {color => $hex_color, title => $hex_color_title};
543 #evaluate browser type and version
544 $_ = $ENV{HTTP_USER_AGENT};
546 if (/Mozilla/) {
547 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;
548 if (($browser_version<5) || (/Netscape/)) {$browser_type = "Netscape";} }
549 if (/\)[^0-9.]+[0-9]*[\/\ ]([0-9.]+)/) {$browser_version=$1;}
550 } elsif (/(\w+)\/([0-9\.]+)/) {$browser_type = $1; $browser_version = $2}
552 #evaluate, transform, tweak, adjust, modify input values
553 #$debug_info .= "browser type: $browser_type<br/>";
557 #if no month is selected, use the current month
558 if ($cal_start_month eq "" && $q->param('cal_start_month') eq "") {
559 $cal_start_month = $rightnow_month;
560 #$cal_start_month = 2;
563 #if the input year is out of range use the current year
564 if (($cal_start_year+0) < 1902 || ($cal_start_year+0)> 2037) {
565 $cal_start_year = $rightnow_year;
568 $cal_num_months = $current_calendar{default_number_of_months} if ($cal_num_months < 1);
569 $cal_num_months = $current_calendar{default_number_of_months} if ($cal_num_months > $current_calendar{max_number_of_months});
570 $cal_num_months = 1 if ($cal_num_months > $current_calendar{max_number_of_months});
571 $cal_num_months = 1 if ($cal_num_months == 0);
574 #calculate calendar end month and year
575 $cal_end_month = $cal_start_month;
576 $cal_end_year = $cal_start_year;
577 for ($l1=1;$l1<$cal_num_months;$l1++) {
578 $cal_end_month++;
579 if ($cal_end_month == 12) {
580 $cal_end_month=0;
581 $cal_end_year++;
585 #check to make sure num_months+cal_start_date doesn't go out of bounds
586 if ($cal_end_year < 1902 || $cal_end_year> 2037) {
587 $cal_end_year = $cal_start_year;
588 $cal_end_month = $cal_start_month;
589 $cal_num_months = 1;
592 # time window for loading events
594 my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year) - 2592000;
595 my $cal_end_timestamp = timegm(0,0,0,1,$cal_end_month,$cal_end_year) + 5184000;
596 if ($q->param('cal_start_timestamp') ne "" && $q->param('cal_start_timestamp') !~ /\D/) {
597 $cal_start_timestamp = $q->param('cal_start_timestamp');}
598 if ($q->param('cal_end_timestamp') ne "" && $q->param('cal_end_timestamp') !~ /\D/) {
599 $cal_end_timestamp = $q->param('cal_end_timestamp');}
602 #$debug_info .="start: $cal_start_timestamp\nend: $cal_end_timestamp\nrightnow: $rightnow\n";
604 # load event data, for main calendar and its background calendars
605 my @temp_calendars = ($current_cal_id);
606 foreach $local_background_calendar (keys %{$current_calendar{local_background_calendars}}) {
607 push @temp_calendars, $local_background_calendar;
610 my $initial_load_events = 1;
611 $initial_load_events = 0 if ($q->param('get_upcoming_events') eq "1");
613 &load_events($cal_start_timestamp, $cal_end_timestamp, \@temp_calendars) if ($initial_load_events == 1);
617 if ($current_event_id ne "") {
618 &load_event($current_event_id);
622 # load events from remote background calendars
624 if (scalar keys %{$current_calendar{remote_background_calendars}} > 0) {
625 $remote_calendars_status="";
626 my $temp = scalar keys %{$current_calendar{remote_background_calendars}};
627 foreach $remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) {
628 # pull in remote calendar name
629 my $remote_calendar_url = $current_calendar{remote_background_calendars}{$remote_calendar_id}{url};
630 $remote_calendar_complete_url = $remote_calendar_url;
631 #$debug_info .= "remote calendar: $remote_calendar_complete_url\n";
633 $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";
634 #$debug_info .= "remote calendar url: $remote_calendar_complete_url\n";
636 my $xml_results = &get_remote_file($remote_calendar_complete_url);
638 if ($xml_results =~ /<error>/) {
639 $xml_results =~ s/</&lt;/g;
640 $xml_results =~ s/>/&gt;/g;
642 #$debug_info .= "Error fetching remote calendar: $xml_results\n";
643 } else {
644 my %remote_calendar = %{&xml2hash($xml_results)};
646 my $remote_cal_title = $remote_calendar{'xml'}{calendar}{title};
647 my $remote_cal_gmtime_diff = $remote_calendar{'xml'}{calendar}{gmtime_diff};
649 #$debug_info .= "remote_cal_gmtime_diff: $remote_cal_gmtime_diff\n";
650 #my $temp = $xml_results;
651 #$temp=~ s/>/&gt;/g;
652 #$temp=~ s/</&lt;/g;
653 #$debug_info .= "xml results: $temp\n";
655 &load_remote_events($xml_results, $remote_calendar_id, $remote_cal_gmtime_diff);
660 # this should be done after all $current_cal_id is calculated and events are loaded.
661 &normalize_timezone();
662 &normalize_timezone_pending_events();
667 # calculate previous X months range.
668 my $previous_cal_start_month = $cal_start_month - $cal_num_months;
669 my $previous_cal_start_year = $cal_start_year;
670 if ($previous_cal_start_month < 0) {
671 $previous_cal_start_year = $cal_start_year - 1 - int(abs($cal_num_months - $cal_start_month) / 12);
672 $previous_cal_start_month = 12 - abs($previous_cal_start_month) % 12;
675 # for the case when num_months = 12 and start_month=0
676 if ($previous_cal_start_month == 12) {
677 $previous_cal_start_month=0;
678 $previous_cal_start_year++;
682 # singular or plural?
683 if ($cal_num_months > 1) {
684 $prev_string = $lang{previous_months};
685 $prev_string =~ s/###num###/$cal_num_months/;
686 } else {
687 $prev_string = $lang{previous_month};
691 # calculate next X months range.
692 my $next_cal_start_month = $cal_start_month + $cal_num_months;
693 my $next_cal_start_year = $cal_start_year;
694 if ($next_cal_start_month > 11) {
695 $next_cal_start_year = $cal_start_year + int(abs($cal_num_months + $cal_start_month) / 12);
696 $next_cal_start_month = abs($cal_start_month + $cal_num_months) % 12;
700 # singular or plural?
701 if ($cal_num_months > 1) {
702 $next_string = $lang{next_months};
703 $next_string =~ s/###num###/$cal_num_months/;
704 } else {
705 $next_string = $lang{next_month};
711 if ($q->param('diagnostic_mode') eq "1") {
712 my $diagnostic_results = &diagnostic_info;
715 $html_output = <<p1;
716 Cache-control: no-cache,no-store,private
717 Content-Type: text/html; charset=$lang{charset}\n
718 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
720 <html>
721 <head>
722 <title>Diagnostic mode</title>
723 </head>
724 <body style="font-family: arial;">
727 <h2>Plans Diagnostic information</h2>
729 $diagnostic_results
731 </p><p>
732 <b>Debug info:</b><br/>
733 <div style="color=:#0000ff;">
734 $debug_info
735 </div>
736 </body>
737 </html>
741 print $html_output;
743 exit(0);
746 if ($q->param('detect_remote_calendars') eq "1") {
747 &detect_remote_calendars();
748 exit(0);
751 if ($q->param('remote_calendar_request') eq "1") {
752 &remote_calendar_request();
753 exit(0);
756 if ($q->param('add_edit_user') eq "1") {
757 &add_edit_user();
758 exit(0);
760 if ($q->param('add_new_ical') eq "1") {
761 &add_new_ical();
762 exit(0);
765 if ($q->param('js_login') eq "1") {
766 &js_login();
767 exit(0);
770 if ($q->param('manage_pending_events') eq "1") {
771 &manage_pending_events();
772 exit(0);
775 if ($q->param('export_calendar') eq "1") {
776 if ($q->param('export_type') eq "ascii_text") {
777 &ascii_text_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
778 exit(0);
779 } elsif ($q->param('export_type') eq "csv_file") {
780 &csv_file($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
781 exit(0);
782 } elsif ($q->param('export_type') eq "csv_file_palm") {
783 &csv_file_palm($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
784 exit(0);
785 } elsif ($q->param('export_type') eq "vcalendar") {
786 &vcalendar_export_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
787 exit(0);
788 } elsif ($q->param('export_type') eq "icalendar") {
790 my $html_output =<<p1;
791 Cache-control: no-cache,no-store,private
792 Content-disposition: filename="events.ics"
793 Content-Type: text/calendar; charset=$lang{charset}
797 $html_output .= &icalendar_export_cal($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
798 print $html_output;
799 exit(0);
803 if ($q->param('export_event') eq "1") {
804 if ($q->param('export_type') eq "ascii_text") {
805 &ascii_text_event();
806 exit(0);
807 } elsif ($q->param('export_type') eq "icalendar") {
808 &icalendar_export_event();
809 exit(0);
810 } elsif ($q->param('export_type') eq "vcalendar") {
811 &vcalendar_export_event();
812 exit(0);
814 } elsif ($q->param('get_upcoming_events') eq "1") {
815 &get_upcoming_events();
816 exit(0);
817 } elsif ($api_command ne "") {
818 if ($api_command eq "delete_event") {
819 &api_add_delete_events();
820 exit(0);
822 } elsif ($q->param('view_event') eq "1") {
823 &load_templates();
824 &view_event();
825 exit(0);
826 } elsif ($q->param('view_events') eq "1") {
827 &load_templates();
828 &view_events();
829 exit(0);
830 } elsif ($q->param('view_pending_event') eq "1") {
831 &load_templates();
832 my %pending_event = %{$new_events{$pending_event_id}};
833 &view_pending_event(\%pending_event);
834 exit(0);
835 } elsif ($q->param('email_reminder') eq "1") {
836 &load_templates();
837 &email_reminder_prompt();
838 exit(0);
839 } elsif ($q->param('email_reminder_confirm') eq "1") {
840 &load_templates();
841 &email_reminder_confirm();
842 exit(0);
843 } elsif ($special_action eq "preview_event") {
844 &load_templates();
845 &preview_event();
846 exit(0);
847 } elsif ($special_action eq "preview_date") {
848 &load_templates();
849 &preview_date();
850 exit(0);
851 } elsif ($q->param('validate_event') eq "1") {
852 &validate_event();
853 exit(0);
857 #load templates
858 &load_templates();
862 # ssi-style includes in the template
863 if ($local_template_file) {
864 my $new_html = $template_html;
866 $template_html =~ s/###include\s+(.+)###/&load_file($1)/ge;
868 #while ($new_html =~ s/###include\s+(.+)###//g)
869 if(0) {
870 my $include_file=$1;
871 if (-e $include_file) {
872 open (FH, "$include_file") || ($debug_info .="<br/>unable to open include file $include_file for reading<br/>");
873 flock FH,2;
874 my @include_lines=<FH>;
875 close FH;
876 $include_html = join "", @include_lines;
878 $template_html =~ s/###include\s+(.+)###/$include_html/;
885 if($options{choose_themes}) {
886 my $theme_file="choose_theme.html";
887 my $theme_html="";
888 if (-e $theme_file) {
889 open (FH, "$theme_file") || ($debug_info .="<br/>unable to open theme file $theme_file for reading<br/>");
890 flock FH,2;
891 my @theme_lines=<FH>;
892 close FH;
893 $theme_html = join "", @theme_lines;
895 $template_html =~ s/###choose theme###/$theme_html/;
896 } else {
897 $template_html =~ s/###choose theme###//;
903 my $view_cookie = &xml_store($cal_start_month, "cal_start_month");
904 $view_cookie .= &xml_store($cal_start_year, "cal_start_year");
905 $view_cookie .= &xml_store($cal_num_months, "cal_num_months");
906 $view_cookie .= &xml_store($current_cal_id, "cal_id");
907 $view_cookie .= &xml_store($display_type, "display_type");
909 $cookie_text .= "Set-Cookie: plans_view=$view_cookie; path=$cookie_path;\n";
910 $cookie_header_text = $cookie_text;
912 #$debug_info .= "cookie: $cookie_header_text\n";
914 $html_output .=<<p1;
915 Cache-control: no-cache,no-store,private
916 Content-Type: text/html; charset=$lang{charset}
917 ###cookie_text###
919 $template_html
923 $html_output =~ s/###current calendar title###/$current_calendar{title}/g;
924 $html_output =~ s/###current calendar details###/$current_calendar{details}/g;
925 $html_output =~ s/###calendar\{(\d+)\}\{(.+?)\}###/$calendars{$1}{$2} if ($2 ne 'admin_password')/ge;
926 $html_output =~ s/###event\{(\d+)\}\{(.+?)\}###/$events{$1}{$2}/ge;
928 $insert_text =<<p1;
929 <script type="text/javascript" src="$theme_url/plans.js"></script>
930 <script type="text/javascript" src="$theme_url/plans_lang.js"></script>
931 <script type="text/javascript" ><!--
933 //###common javascript###
934 //###page-specific javascript###
935 //-->
936 </script>
938 chomp $insert_text;
939 $html_output =~ s/###javascript stuff###/$insert_text/;
941 # sneak in the color select javascript before all other javascript.
942 my $temp =<<p1;
943 <script type="text/javascript" src="$theme_url/lpd.js"></script>
944 <script type="text/javascript" src="$theme_url/color_select.js"></script>
946 $html_output =~ s/(<script)/$temp$1/;
949 #default page
950 &display_default();
952 exit(0);
957 sub display_default {
958 my $common_javascript = "";
959 my $page_javascript = "";
960 my $browser_javascript = "";
962 chomp $insert_text;
963 $html_output =~ s/###css file###/$css_path/g;
965 # tab menu stuff
966 $menu_tabs[0] = {status => "inactive",
967 html => "<a href=\"$script_url/$name?active_tab=0\">$lang{tab_text}[0]</a>"};
968 $menu_tabs[1] = {status => "inactive",
969 html => "<a href=\"$script_url/$name?active_tab=1\">$lang{tab_text}[1]</a>"};
970 $menu_tabs[2] = {status => "inactive",
971 html => "<a href=\"$script_url/$name?active_tab=2\">$lang{tab_text}[2]</a>"};
973 $menu_tabs[$active_tab]{status} ="active";
975 $menu_tabs[2]{html} = "<a href=\"$script_url/$name?active_tab=2\">$lang{tab_text}[2]</a>";
977 $insert_text =<<p1;
978 <br/>
979 <div style="padding:0px;margin:0px;margin-left:20px;white-space:nowrap;">
982 # this kludge sucks!
983 if ($browser_type eq "IE") {
984 $tab_vert_offset=4;} else {
985 $tab_vert_offset=0;}
987 #lay out the actual menu tabs
988 for ($l1=0;$l1<scalar @{$lang{tab_text}};$l1++) {
989 if (&contains (\@disabled_tabs, $l1)) {
990 next;}
991 $menu_tab = $menu_tabs[$l1];
992 my $style="";
994 #$tab_vert_offset=0;
996 if ($$menu_tab{status} eq "active") {
997 $style="top:".($tab_vert_offset-3)."px;padding-top:5px;padding-bottom:5px;margin-top:0;height:2em;";
998 } else {
999 $style="top:".($tab_vert_offset-3)."px;padding-top:3px;padding-bottom:4px;margin-top:1px;height:2em;";
1001 $insert_text .=<<p1;
1002 <span class="$$menu_tab{status}_tab" style="position:relative;border-bottom-width:0px;padding-top:5px;margin-bottom:0;margin-left:5px;margin-right:2px;white-space:nowrap;text-align:center;$style"> &nbsp; &nbsp; &nbsp; $$menu_tab{html} &nbsp; &nbsp; &nbsp; </span>
1005 $noinsert_text .=<<p1;
1006 <span class="$$menu_tab{status}_tab" style="position:relative;$style">$$menu_tab{html} &nbsp; &nbsp; &nbsp; </span>
1010 $insert_text .=<<p1;
1011 </div>
1013 chomp $insert_text;
1016 if ($q->param('custom_calendar') == 1) {
1017 $html_output =~ s/###tab menu stuff###//g;
1018 } else {
1019 $html_output =~ s/###tab menu stuff###/$insert_text/g;
1023 $insert_text ="";
1025 #invisible html for context menu
1026 $insert_text .=<<p1;
1027 <div id="contextmenu" class="contextmenu" style="visibility:hidden;">
1028 </div>
1031 #main box stuff
1032 $insert_text .=<<p1;
1035 # finished displaying tab menus, now display the appropriate stuff for the selected tab
1037 if ($active_tab eq "0") { # tab 1 = main calendar view
1040 $prev_month_link .=<<p1;
1041 <a class="prev_next" href="$script_url/$name?cal_id=$current_cal_id&cal_start_month=$previous_cal_start_month&amp;cal_start_year=$previous_cal_start_year">$prev_string</a>
1043 $next_month_link .=<<p1;
1044 <a class="prev_next" href="$script_url/$name?cal_id=$current_cal_id&cal_start_month=$next_cal_start_month&amp;cal_start_year=$next_cal_start_year">$next_string</a>
1048 my $cal_controls_text =<<p1;
1049 <div class="calendar_controls">
1050 <form name="tab0_form" action="$script_url/$name" method="get">
1052 <div style="float:right;margin:5px;padding:2px;vertical-align:middle;">
1053 <input id="controls_submit_button" type="submit" value="$lang{controls_change}"/>
1054 </div>
1056 <div style="margin:5px;padding:2px;text-align:right;float:right;">
1057 $lang{controls_start_month}:
1058 <select name="cal_start_month" onChange="blink('controls_submit_button', 3, 0);">
1060 #list each month in the year
1061 $month_index=0;
1062 foreach $possible_month (@months) {
1063 if ($cal_start_month eq $month_index) {
1064 $cal_controls_text .=<<p1;
1065 <option value="$month_index" selected>$possible_month
1067 } else {
1068 $cal_controls_text .=<<p1;
1069 <option value="$month_index">$possible_month
1072 $month_index++;
1074 $cal_controls_text .=<<p1;
1075 </select>
1076 <input name="cal_start_year" value = "$cal_start_year" size=4 onChange="blink('controls_submit_button', 3, 0);"/><br/>
1077 $lang{controls_num_months}
1078 <input name="cal_num_months" value = "$cal_num_months" size=3 onChange="blink('controls_submit_button', 3, 0);"/>
1079 </div>
1081 $cal_controls_text .=<<p1;
1082 <div class="calendar_select" style="margin:5px;padding:2px;float:left;text-align:left;">
1083 $lang{controls_calendar_label}<br/>
1086 my $num_selectable_calendars = scalar keys %{$current_calendar{selectable_calendars}};
1088 my @selectable_calendars;
1089 if ($options{all_calendars_selectable}) {
1090 @selectable_calendars = keys %calendars;
1091 } else {
1092 @selectable_calendars = keys %{$current_calendar{selectable_calendars}};
1093 unshift @selectable_calendars, $current_cal_id if (!&contains(\@selectable_calendars, $current_cal_id));
1097 if (scalar @selectable_calendars > 1) {
1098 $cal_controls_text .=<<p1;
1099 <select id="cal_id" name="cal_id" onChange="blink('controls_submit_button', 3, 0);">
1103 #list each calendar for the user to select
1104 my %explicit_calendar_order;
1105 if ($options{calendar_select_order} ne "alpha" && $options{calendar_select_order} ne "") {
1106 my @cal_order_ids = split(',',$options{calendar_select_order});
1107 my $cal_order_index = 0;
1109 foreach $selectable_calendar_id (@selectable_calendars) {
1110 $explicit_calendar_order{"$selectable_calendar_id"} = 9999999;
1114 foreach $cal_order_id (@cal_order_ids) {
1115 next if ($cal_order_id eq "");
1117 $explicit_calendar_order{"$cal_order_id"} = $cal_order_index;
1118 $cal_order_index++;
1122 foreach $selectable_calendar_id (sort {
1123 if ($options{calendar_select_order} eq "alpha") {
1124 return lc $calendars{$a}{title} cmp lc $calendars{$b}{title};
1125 } elsif ($options{calendar_select_order} ne "") {
1126 return $explicit_calendar_order{"$a"} <=> $explicit_calendar_order{"$b"} || lc $calendars{$a}{title} cmp lc $calendars{$b}{title};} else {
1127 return $a <=> $b;}
1129 } @selectable_calendars) {
1130 my $selected ="";
1131 $selected =" selected" if ($selectable_calendar_id eq $current_calendar{id});
1132 $selectable_calendar_id=~ s/\D//g;
1134 $cal_controls_text .=<<p1;
1135 <option value = "$selectable_calendar_id"$selected>$calendars{$selectable_calendar_id}{title}
1139 $cal_controls_text .=<<p1;
1140 </select>
1142 } else {
1143 $cal_controls_text .=<<p1;
1144 <span style="font-weight:bold;">$current_calendar{title}</span>
1145 <input type="hidden" name="cal_id" value="$current_calendar{id}"/>
1148 $cal_controls_text .=<<p1;
1149 </div>
1153 $cal_controls_text .=<<p1;
1154 <div style="margin:5px;padding:2px;float:left;text-align:left;">
1155 $lang{controls_display_label}<br/>
1156 <select name="display_type" onChange="blink('controls_submit_button', 3, 0);">
1158 #foreach $possible_display_type (@{$options{display_types}})
1159 for (my $l1=0;$l1<scalar @{$options{display_types}};$l1++) {
1160 if ($options{display_types}[$l1] ne "1") {
1161 next};
1162 my $selected="";
1164 if ($l1 eq $display_type) {
1165 $selected = "selected";}
1167 $cal_controls_text .=<<p1;
1168 <option value="$l1" $selected>$lang{controls_display_type}[$l1]
1171 $cal_controls_text .=<<p1;
1172 </select>
1173 </div>
1178 $cal_controls_text .=<<p1;
1179 <br style="clear:both;"/>
1180 </form>
1181 </div>
1183 if ($q->param('custom_calendar') == 1) {
1184 $html_output =~ s/###calendar controls###//g;
1185 } else {
1186 $html_output =~ s/###calendar controls###/$cal_controls_text/g;
1189 if ( !$logged_in && $options{force_login} ) {
1190 $insert_text .= &forced_login();
1191 } else {
1192 $insert_text .= &do_calendar_list_view();
1195 #select event range
1197 $cal_month_start_date = timegm(0,0,0,1,$cal_start_month,$cal_start_year);
1198 @cal_month_start_date_array = gmtime $cal_month_start_date;
1200 $events_start_timestamp = $cal_month_start_date - 604800; # +7 day margin
1201 $events_end_timestamp = &find_end_of_month($cal_end_month, $cal_end_year) + 604800; # +7 day margin
1203 #now that we have selected the appropriate events, we can
1204 #generate the corresponding javascript and calendar view
1205 #and insert/add it to the html output.
1206 $page_javascript .= &calendar_view_javascript($events_start_timestamp, $events_end_timestamp);
1208 #replace javascript placeholders with actual html/javascript code
1210 $html_output =~ s/###previous month link###/$prev_month_link/g;
1211 $html_output =~ s/###next month link###/$next_month_link/g;
1213 } elsif ($active_tab eq "1") { #the second tab is the add/edit events view
1214 $html_output =~ s/###calendar controls###//;
1216 if ( !$logged_in && $options{force_login} ) {
1217 $insert_text .= &forced_login();
1218 } else {
1219 my $edit_event_id = "";
1220 $edit_event_id = $current_event_id if ($add_edit_event eq "edit");
1222 if ($q->param('add_event_button') eq "" && $q->param('del_event_button') eq "") { #add event main screen
1224 $add_edit_event = "add" if ($add_edit_event eq "");
1226 $insert_text .=<<p1;
1227 <form id="add_event_form" name="add_event_form" action="$script_url/$name" method="POST" onsubmit="return validate_event();">
1228 <input type="hidden" name="active_tab" value="1"/>
1229 <input type="hidden" name="special_action" value=""/>
1230 <input type="hidden" name="add_edit_event" value="$add_edit_event"/>
1231 <input type="hidden" name="evt_id" value="$edit_event_id"/>
1233 $insert_text .= &add_edit_events_interface();
1234 $insert_text .=<<p1;
1235 </form>
1237 } else {
1238 my %results = %{&add_edit_events()};
1239 my $results_html = "";
1241 foreach $results_message (@{$results{messages}}) {
1242 $results_message =~ s/\[warning\](.*)/<span class="warning">$1<\/span>/i;
1243 $results_message =~ s/\[error\](.*)/<span class="error">$1<\/span>/i;
1244 $results_message =~ s/\[status\](.*)/<span class="status">$1<\/span>/i;
1245 $results_html .= "<li>$results_message</li>\n";
1248 $insert_text .= "<div style=\"text-align:left;\"><ul style=\"font-size:small;\">$results_html</ul>$results{text}</div>";
1252 #generate javascript for add/edit events page
1253 $page_javascript .= &add_edit_events_javascript();
1255 } elsif ($active_tab eq "2") { #the third tab is for calendar information
1257 $html_output =~ s/###calendar controls###//;
1259 if ( !$logged_in && $options{force_login} ) {
1260 $insert_text .= &forced_login();
1261 } else {
1262 if ($add_edit_cal_action eq "") { # calendar management view
1263 $num_new_calendars = scalar keys %new_calendars;
1265 if ($num_new_calendars == 0) {
1266 $new_calendars_info = $lang{tab2_no_new_calendars};
1267 } else {
1268 $new_calendars_info = $lang{tab2_some_new_calendars};
1269 $new_calendars_info =~ s/###num###/$num_new_calendars/;
1272 $insert_text .=<<p1;
1273 <div>
1274 <div class="info_box" style="margin-top:20px;float:left;padding-left:20px;padding-right:20px;text-align:left;">
1276 <form name="view_cal_form" action="$script_url/$name" method="GET">
1277 <input type="hidden" name = "active_tab" value="2"/>
1278 <input type="hidden" name = "add_edit_cal_action" value="edit"/>
1280 <select name="cal_id" id="cal_id">
1282 foreach $cal_id (sort {$a <=> $b} keys %calendars) {
1283 my $selected="";
1284 if ($cal_id eq $current_cal_id) {
1285 #$debug_info .= "$cal_id<br/>";
1286 $selected=" selected";
1288 $insert_text .=<<p1;
1289 <option value = "$cal_id"$selected>$calendars{$cal_id}{title}
1293 $insert_text .=<<p1;
1294 </select>
1295 </form>
1297 $writable{calendars_file} and $insert_text .=<<p1;
1298 <a href="javascript:document.view_cal_form.submit();">$lang{tab2_edit_delete}</a>
1300 if ($writable{pending_actions_file}) {
1301 $insert_text .=<<p1;
1302 </div>
1304 <div class="info_box" style="float:left;clear:left;width:90%;margin-top:20px;padding-left:20px;padding-right:20px;text-align:left;">
1305 <ul>
1307 <li><a href="$script_url/$name?active_tab=2&amp;add_edit_cal_action=add">$lang{add_new_calendar}</a></li>
1310 if ($options{ical_import} eq "1") {
1311 $insert_text .=<<p1;
1312 <li><a id="add_new_ical_link" href="javascript:add_new_ical();">$lang{add_new_ical_calendar}</a>
1313 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('add_new_ical','$lang{add_new_ical_calendar}')">$lang{help_on_this}</a></span>
1316 </li>
1321 $insert_text .=<<p1;
1322 <li><a href="$script_url/$name?active_tab=2&amp;add_edit_cal_action=view_pending">$lang{tab2_view_new_calendars}</a> $new_calendars_info</li>
1324 </ul>
1325 </div>
1327 <br style="clear:both;"/>
1328 </div>
1332 } elsif($add_edit_cal_action eq "add" || $add_edit_cal_action eq "edit") { #add/edit calendars
1334 $insert_text .=<<p1;
1335 <form id="update_cal_form" name="update_cal_form" action="$script_url/$name" method="POST" onsubmit="return validate_calendar();">
1336 <input type="hidden" name="cal_id" value="$current_cal_id"/>
1338 $insert_text .= &add_edit_calendars();
1339 $insert_text .=<<p1;
1340 </form>
1342 } elsif ($add_edit_cal_action eq "view_pending") { #view/approve/reject new pending calendars
1344 $insert_text .= &view_pending_calendars();
1348 #generate javascript for calendar info page
1349 $page_javascript.= &add_edit_calendars_javascript();
1354 #done with main active tab stuff (the stuff that's different depending
1355 #on which tab is active. The following stuff is the same regardless
1356 #of which tab is active.
1358 $html_output =~ s/###calendar area###/$insert_text/g;
1359 $html_output =~ s/###version###/$plans_version/g;
1362 my $add_event_to_current_cal_text =<<p1;
1363 <a target = "_self" href="$script_url/$name?active_tab=1&amp;cal_id=$current_cal_id">$lang{add_event_to_this_calendar}</a>
1365 chomp $add_event_to_current_cal_text;
1367 my $current_calendar_options_text =<<p1;
1368 <a target="_self" href="$script_url/$name?active_tab=2&amp;cal_id=$current_cal_id&amp;add_edit_cal_action=edit">$lang{edit_calendar_options}</a>
1370 chomp $current_calendar_options_text;
1372 my $current_calendar_subscribe_text =<<p1;
1373 <a target="_new" href="$ical_export_url/plans_calendar_$current_calendar{id}.ics">$lang{subscribe_to_this_calendar}</a>
1375 chomp $current_calendar_subscribe_text;
1378 if ($active_tab eq "0") {
1379 $html_output =~ s/###add event to current calendar link###/$add_event_to_current_cal_text/;
1380 $html_output =~ s/###edit calendar options link###/$current_calendar_options_text/;
1382 if ( !$logged_in && $options{force_login} ) {
1383 $html_output =~ s/###subscribe calendar link###//g;
1384 $html_output =~ s/###export calendar link###//;
1385 $html_output =~ s/###custom calendar link###//;
1386 } else {
1387 $html_output =~ s/###subscribe calendar link###/$current_calendar_subscribe_text/g;
1388 my $temp = &export_calendar_link();
1389 $html_output =~ s/###export calendar link###/$temp/;
1391 my $custom_calendar_link =<<p1;
1392 <a href="javascript:custom_calendar()">$lang{make_custom_calendar}</a>
1394 chomp $custom_calendar_link;
1395 $html_output =~ s/###custom calendar link###/$custom_calendar_link/;
1397 #$debug_info .= "custom calendar link: $custom_calendar_link\n";
1399 } else {
1400 $html_output =~ s/###subscribe calendar link###//g;
1401 $html_output =~ s/###add event to current calendar link###//;
1402 $html_output =~ s/###edit calendar options link###//;
1403 $html_output =~ s/###custom calendar link###//;
1404 $html_output =~ s/###export calendar link###//;
1408 # pending event stuff
1409 my $plans_messages_style = ($messages eq "")? "": " style=\"display:block;\"";
1410 my $messages_text = "<div id=\"plans_messages\"$plans_messages_style>$messages</div>";
1411 $html_output =~ s/###messages###/$messages_text/;
1413 my $logged_in_text = &generate_logged_in_stuff();
1415 if ($logged_in_text ne "") {
1416 $logged_in_text = <<p1;
1417 <div id="logged_in_stuff">
1418 $logged_in_text
1419 </div>
1423 $html_output =~ s/###logged-in stuff###/$logged_in_text/;
1426 $common_javascript .= &generate_pending_events_javascript() if (&pending_events_visible);
1427 $common_javascript .= &common_javascript();
1430 #replace javascript placeholders with actual html/javascript code
1431 $html_output =~ s/###page-specific javascript###/\n$page_javascript/;
1432 $html_output =~ s/###common javascript###/\n$common_javascript/;
1435 $debug_info = "$error_info$debug_info";
1437 if ($debug_info =~ /\S/) {
1438 $debug_info =~ s/\n/<br\/>\n/g;
1439 $debug_info = <<p1;
1440 <div style="width:100%;padding:10px;margin:10px;border:solid 1px #000;background-color:#fff;">
1441 <b>Error, Warnings, & Debug Messages:</b><br/>
1442 $debug_info
1443 <\/div>
1446 $html_output =~ s/###debug stuff###/$debug_info/g;
1447 $html_output =~ s/###cookie_text###/$cookie_header_text/;
1449 print $html_output;
1451 } #********************end default view code*****************************
1453 sub add_edit_calendars {
1454 my $temp="<link rel=\"stylesheet\" href=\"$theme_url/color_select.css\" type=\"text/css\">";
1455 $html_output =~ s/<head>/<head>\n$temp\n/;
1457 my $return_text = "";
1459 if ($q->param('update_cal_button') eq "" && $q->param('del_cal_button') eq "") { #add/edit calendar main screen
1461 $add_edit_string = $lang{add_new_calendar};
1462 #generate html for blank (default) calendar preview window
1464 $cal_details = $new_calendar_default_details;
1465 $shared_cal_select_size = scalar keys %calendars;
1466 $cal_link="http://";
1468 if ($add_edit_cal_action ne "edit") {
1469 %current_calendar = %default_cal;}
1471 $add_edit_string = "$lang{edit_calendar} ($current_calendar{title})" if ($add_edit_cal_action eq "edit");
1473 my %checked;
1474 $checked{list_background_calendars_together} = " checked" if ($current_calendar{list_background_calendars_together} eq "yes");
1475 $checked{background_events_display_style1} = " checked" if ($current_calendar{background_events_display_style} eq "normal");
1476 $checked{background_events_display_style2} = " checked" if ($current_calendar{background_events_display_style} eq "single_color");
1477 $checked{background_events_display_style3} = " checked" if ($current_calendar{background_events_display_style} eq "faded");
1479 $current_calendar{custom_stylesheet} = "http://$current_calendar{custom_stylesheet}";
1480 $current_calendar{custom_template} = "http://$current_calendar{custom_template}";
1482 $cal_details =~ s/</&lt;/g;
1483 $cal_details =~ s/>/&gt;/g;
1485 $return_text .=<<p1;
1487 <input type="hidden" name="active_tab" value="2"/>
1488 <input type="hidden" name="add_edit_cal_action" value="$add_edit_cal_action"/>
1489 <input type="hidden" name="new_remote_calandars_xml" value=""/>
1491 <p class="cal_title" style="text-align:center;">
1492 $add_edit_string
1493 </p>
1495 <div class="info_box" style="text-align:center;margin-bottom:2em;float:left;">
1496 <span class="optional_field">$lang{fields_text1} <span class="required_field">$lang{fields_text2}</span> $lang{fields_text3}</span>
1497 </div>
1499 <div style="width:90%;text-align:left;white-space:nowrap;clear:left;">
1500 <a id="tab0" href="javascript:tab_show(0)" class="info_box_tab active">$lang{add_edit_calendars_tab0}</a>
1501 <a id="tab1" href="javascript:tab_show(1)" class="info_box_tab">$lang{add_edit_calendars_tab1}</a>
1502 <a id="tab2" href="javascript:tab_show(2)" class="info_box_tab">$lang{add_edit_calendars_tab2}</a>
1503 <a id="tab3" href="javascript:tab_show(3)" class="info_box_tab">$lang{add_edit_calendars_tab3}</a>
1505 if ($options{users} eq "1") {
1506 $return_text .=<<p1;
1507 <a id="tab4" href="javascript:tab_show(4)" class="info_box_tab">$lang{add_edit_calendars_tab4}</a>
1511 $return_text .=<<p1;
1512 </div>
1514 <div id="tab_area0" class="info_box" style="width:100%;position:relative;z-index:101;padding-top:20px;">
1517 <div class="leftcol" style="">
1518 <label class="required_field" for="cal_title">$lang{calendar_title}</label>
1519 </div>
1520 <div class="rightcol" style="white-space:nowrap;">
1521 <input id="cal_title" name="cal_title" style="width:50%;" value = "$current_calendar{title}"/>
1522 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('title','$lang{calendar_title}')">$lang{help_on_this}</a></span>
1523 </div>
1525 <div class="leftcol" style="">
1526 <label class="optional_field" for="cal_link">$lang{calendar_link}</label>
1527 </div>
1528 <div class="rightcol" style="white-space:nowrap;">
1529 <input id="cal_link" name="cal_link" style="width:50%;" value = "$current_calendar{link}"/>
1530 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('link','$lang{calendar_link}')">$lang{help_on_this}</a></span>
1531 </div>
1533 <div class="leftcol" style="">
1534 <label class="optional_field" for="cal_details">$lang{calendar_details}</label>
1535 <br/>
1536 <span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('details','$lang{calendar_details}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
1537 </div>
1538 <div class="rightcol" style="white-space:nowrap;">
1539 <textarea name="cal_details" id="cal_details" rows=10 cols=0 style="width:100%;">
1540 $current_calendar{details}
1541 </textarea>
1542 </div>
1545 <div style="clear:both;text-align:center;padding-top:20px;padding-bottom:20px;">
1546 <b><a href="javascript:preview_cal()">$lang{preview_calendar_details}</a></b>
1547 </div>
1549 <br style="clear:both;"/>&nbsp;
1550 </div>
1552 <div id="tab_area1" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;">
1553 <div style="float:left;width:45%;text-align:left;">
1558 <div class="lite_box">
1560 if (scalar (keys %calendars) > 1 || $add_edit_cal_action ne "edit") {
1561 $return_text .=<<p1;
1562 <label class="optional_field" style="float:left;" for="background_calendars">$lang{background_calendars3}
1563 <span class="small_note" ><a href="javascript:display_help('background_calendars','$lang{background_calendars3}')">$lang{help_on_this}</a></span>
1564 <br/><span class="small_note">$lang{background_calendars2}</span>
1565 </label>
1566 <select multiple size=8 style="display:block;clear:left;" name="background_calendars" id="background_calendars">
1569 foreach $cal_id (sort {$a <=> $b} keys %calendars) {
1570 #don't display a choice for the calendar currently being edited
1571 if ($cal_id eq $current_calendar{id}) {
1572 next;}
1574 #$debug_info .= "$current_calendar{title} local_background_calendars{$cal_id} = $current_calendar{local_background_calendars}{$cal_id}\n";
1575 my $selected="";
1577 if ($current_calendar{local_background_calendars}{$cal_id} eq "1") {
1578 $selected = " selected";}
1580 $return_text .=<<p1;
1581 <option value = "$cal_id"$selected>$calendars{$cal_id}{title}
1585 $return_text .=<<p1;
1586 </select>
1590 $return_text .=<<p1;
1591 </div>
1592 <div class="lite_box">
1593 <label class="optional_field" style="float:left;" for="remote_background_calendars">$lang{remote_background_calendars1}</label>
1594 &nbsp;<span class="small_note" ><a href="javascript:display_help('remote_background_calendars','$lang{remote_background_calendars1}')">$lang{help_on_this}</a></span>
1596 my $remote_calendars_status = $lang{remote_background_calendars_none};
1598 if (scalar keys %{$current_calendar{remote_background_calendars}} > 0) {
1599 $remote_calendars_status="";
1600 my $temp = scalar keys %{$current_calendar{remote_background_calendars}};
1601 if ($temp>4) {$temp=4};
1602 $temp = ($temp * 20)."px";
1604 $return_text .=<<p1;
1605 <div class="scroll_surround" style="height:$temp;white-space:nowrap;">
1607 foreach $remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) {
1608 # pull in remote calendar name
1609 my $remote_calendar_url = $current_calendar{remote_background_calendars}{$remote_calendar_id}{url};
1610 $remote_calendar_complete_url = $remote_calendar_url;
1612 $remote_calendar_complete_url .= "?remote_calendar_request=1&cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}&cal_start_year=1971&cal_start_month=0&num_months=1";
1613 my $xml_results = &get_remote_file($remote_calendar_complete_url);
1615 if ($xml_results =~ /<error>/) {
1616 $xml_results =~ s/</&lt;/g;
1617 $xml_results =~ s/>/&gt;/g;
1619 $debug_info .= "Error fetching remote calendar: $xml_results\n";
1620 } else {
1621 my %remote_calendars = %{&xml2hash($xml_results)};
1623 my $remote_cal_title = $remote_calendars{'xml'}{calendar}{title};
1625 $return_text .=<<p1;
1626 <a target="_blank" href="$remote_calendar_url?cal_id=$current_calendar{remote_background_calendars}{$remote_calendar_id}{remote_id}" style="font-size:small;">$remote_cal_title</a>
1627 &nbsp;&nbsp;&nbsp;&nbsp;
1628 (<input type="checkbox" name="delete_remote_calendar_$remote_calendar_id" style="margin-top:0;margin-bottom:0;padding:0;vertical-align:bottom;" value="y"/>$lang{get_remote_calendar3})
1629 <br/>
1634 $return_text .=<<p1;
1635 </div>
1638 $return_text .=<<p1;
1639 <div id="remote_background_calendars_status" class="small_note">$remote_calendars_status</div>
1640 <div class="small_note"><a href="javascript:get_remote_calendars();">$lang{get_remote_calendars}</a></div>
1642 $return_text .=<<p1;
1643 </div> <!-- end border div -->
1646 my $temp1="";
1647 my $temp2="";
1648 my $temp3="";
1649 if ($current_calendar{allow_remote_calendar_requests} =~ /y/) {
1650 $temp1=" checked";}
1652 if ($current_calendar{remote_calendar_requests_require_password} =~ /y/) {
1653 $temp2=" checked";
1654 $temp3="$current_calendar{remote_calendar_requests_password}";
1657 $return_text .=<<p1;
1658 <div class="lite_box">
1659 <input type="checkbox" id="allow_remote_calendar_requests" name="allow_remote_calendar_requests" value="yes" $temp1 onclick="update_remote_calendar_requests()"/>
1660 <label class="optional_field" for="allow_remote_calendar_requests">$lang{allow_remote_calendar_requests}</label>
1661 <br/><span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('allow_remote_calendar_requests','$lang{allow_remote_calendar_requests}')">$lang{help_on_this}</a></span>
1662 <br/>
1663 <input type="checkbox" id="remote_calendar_requests_require_password" name="remote_calendar_requests_require_password" value="yes" $temp2 onclick="update_remote_calendar_requests()"/>
1664 <label class="optional_field" for="remote_calendar_requests_password">$lang{remote_calendar_requests_password1}</label>
1665 <input type="password" id="remote_calendar_requests_password" name="remote_calendar_requests_password" value="$temp3"/>
1666 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('remote_calendar_requests_password','$lang{remote_calendar_requests_password1}')">$lang{help_on_this}</a></span>
1667 </div>
1675 </div> <!-- end left column -->
1676 <div style="float:left;width:45%;text-align:left;">
1678 <div class="lite_box">
1680 if ($options{all_calendars_selectable} eq "1") {
1681 $return_text.=<<p1;
1682 <label class="optional_field" style="float:left;">$lang{selectable_calendars1}</label>
1683 <br/><span class="small_note">($lang{selectable_calendars3})</span>
1684 <br style="clear:both;"/>&nbsp;
1687 } else {
1688 if (scalar (keys %calendars) > 1 || $add_edit_cal_action ne "edit") {
1689 $return_text .=<<p1;
1690 <label class="optional_field" style="float:left;" for="selectable_calendars">$lang{selectable_calendars1}
1691 <br/><span class="small_note">$lang{selectable_calendars2}</span>
1692 <span class="small_note" style="margin-left:1em;white-space:nowrap;"><a href="javascript:display_help('selectable_calendars','$lang{selectable_calendars1}')">$lang{help_on_this}</a></span>
1693 </label>
1694 <select multiple size=8 style="display:block;clear:left;" name="selectable_calendars" id="selectable_calendars">
1696 foreach $cal_id (sort {$a <=> $b} keys %calendars) {
1697 #don't display a choice for the calendar currently being edited
1698 next if ($cal_id eq $current_calendar{id});
1700 my $selected="";
1702 if ($current_calendar{selectable_calendars}{$cal_id} eq "1" || $add_edit_cal_action eq "add") {
1703 $selected = " selected";}
1705 $return_text .=<<p1;
1706 <option value = "$cal_id"$selected>$calendars{$cal_id}{title}
1709 $return_text .=<<p1;
1710 </select>
1714 if ($options{new_calendars_automatically_selectable} eq "1") {
1715 my $temp="";
1716 if ($current_calendar{new_calendars_automatically_selectable} =~ /y/) {
1717 $temp=" checked";}
1718 $return_text .=<<p1;
1719 <div style="margin-top:2ex;">
1720 <input type="checkbox" id="new_calendars_automatically_selectable" name="new_calendars_automatically_selectable" value="y" $temp/>
1721 <label class="optional_field" for="new_calendars_automatically_selectable">$lang{new_calendars_automatically_selectable}</label>
1722 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('new_calendars_automatically_selectable','$lang{new_calendars_automatically_selectable}')">$lang{help_on_this}</a></span>
1723 </div>
1728 $return_text .=<<p1;
1729 </div>
1731 <div class="lite_box">
1732 <input type="checkbox" id="list_background_calendars_together" name="list_background_calendars_together" value = "yes" $checked{list_background_calendars_together}/>
1733 <label class="optional_field" for="list_background_calendars_together">$lang{bg_events_display_style8}</label>
1734 <br/><span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('list_background_calendars_together','$lang{bg_events_display_style8}')">$lang{help_on_this}</a></span>
1735 </div>
1737 </div> <!--end right column-->
1739 <br style="clear:both;"/>&nbsp;
1740 </div>
1745 <div id="tab_area2" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;">
1747 <div style="float:left;width:45%;text-align:left;">
1748 <div class="lite_box">
1750 <div class="optional_field">
1751 $lang{cal_events_display_style1}
1752 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('events_display_style','$lang{bg_events_display_style1}')">$lang{help_on_this}</a></span>
1753 </div>
1755 <div style="clear:left;margin-top:2em;">
1756 <label class="optional_field" for="cal_events_display_style2">$lang{cal_events_display_style2}</label>
1757 <input name="dummy" value="" size=1 style="display:none;">
1758 <select id="calendar_events_color" name="calendar_events_color" value = "" style="margin-left:27px;width:10ex;" onChange="update_cal_color_select_box();" onKeyPress="if (event.keyCode == 13){return false;}">
1759 <option value="" style="background-color:#fff;">none</option>
1761 my $custom_color=1;
1762 #update_bg_color_select_box()cs1.setrgb(this.value);
1764 foreach $temp (@event_bgcolors) {
1765 %possible_bgcolor = %{$temp};
1766 my $selected="";
1767 if ($possible_bgcolor{color} eq "$current_calendar{calendar_events_color}") { #default
1768 $custom_color=0;
1769 $selected=" selected";
1771 my $description = "";
1772 $description = $possible_bgcolor{title} if ($options{show_event_background_color_descriptions});
1774 $return_text .=<<p1;
1775 <option value = "$possible_bgcolor{color}" style="background-color:$possible_bgcolor{color};"$selected>$description
1779 my $color_select_icon_style="visibility:hidden;";
1780 if ($custom_color == 1 && $current_calendar{calendar_events_color} ne "") {
1781 $color_select_icon_style="";
1782 $return_text .=<<p1;
1783 <option id="custom_evt_color" value = "$current_calendar{calendar_events_color}" selected style="background-color:$current_calendar{calendar_events_color};">$lang{event_background_colorcustom}
1785 } else {
1786 $return_text .=<<p1;
1787 <option id="custom_evt_color" value="#ffffff" style="background-color:#fff;">$lang{event_background_colorcustom}
1791 $return_text .=<<p1;
1792 </select>
1796 <span id="color_select_icon1" class="color_select_icon" style="$color_select_icon_style vertical-align:top;background-image:url($graphics_url/color_select_icon.gif);" onclick="cs1.attach_to_element(this);cs1.toggle_color_select();">&nbsp;&nbsp;&nbsp;&nbsp;</span>
1797 </div>
1799 </div>
1800 </div> <!-- end left column -->
1802 <div style="float:left;width:45%;text-align:left;">
1806 <div class="lite_box">
1807 <div class="optional_field">
1808 $lang{bg_events_display_style1}
1809 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('background_events_display_style','$lang{bg_events_display_style1}')">$lang{help_on_this}</a></span>
1810 </div>
1812 <div style="clear:left;margin-top:1em;" onClick="document.update_cal_form.background_events_display_style[0].checked=true;document.getElementById('bg_preview_e1').style.background = '#ffffcc';document.getElementById('bg_preview_e2').style.background = '#ccffff';document.update_cal_form.background_events_color.value = '';">
1813 <input type="radio" id="background_events_display_style1" name="background_events_display_style" value = "normal" $checked{background_events_display_style1}/>
1814 <label class="optional_field" for="background_events_display_style1">$lang{bg_events_display_style2}</label>
1815 </div>
1817 <div style="clear:left;margin-top:2em;" onClick="document.update_cal_form.background_events_display_style[1].checked=true;">
1818 <input type="radio" id="background_events_display_style2" name="background_events_display_style" value = "single_color" $checked{background_events_display_style2}/>
1819 <label class="optional_field" for="background_events_display_style2">$lang{bg_events_display_style3}</label>
1820 <input id="background_events_color" name="background_events_color" value = "$current_calendar{background_events_color}" style="margin-left:27px;width:10ex;" onChange="cs0.setrgb(this.value);" onKeyPress="if (event.keyCode == 13){return false;}">
1821 <span id="color_select_icon0" class="color_select_icon" style="vertical-align:top;background-image:url($graphics_url/color_select_icon.gif);" onClick="cs0.attach_to_element(this);cs0.toggle_color_select();">&nbsp;&nbsp;&nbsp;&nbsp;</span>
1822 </div>
1824 <div style="clear:left;margin-top:2em;" onClick="document.update_cal_form.background_events_display_style[2].checked=true;fade_preview();document.update_cal_form.background_events_color.value = ''">
1825 <input type="radio" id="background_events_display_style3" name="background_events_display_style" value = "faded" $checked{background_events_display_style3}/>
1826 <label class="optional_field" for="background_events_display_style3">$lang{bg_events_display_style4}</label>
1827 <select id="background_events_fade_factor" name="background_events_fade_factor" onChange="fade_preview();">
1829 for ($i=1;$i<8;$i++) {
1830 my $selected="";
1831 $selected = " selected" if ($i eq $current_calendar{background_events_fade_factor});
1832 $return_text .=<<p1;
1833 <option value="$i"$selected>$i\l0\% faded
1837 $return_text .=<<p1;
1838 </select>
1839 </div>
1841 </div>
1844 </div> <!-- end right column -->
1848 <div class="lite_box" style="clear:both;">
1849 <div style="text-align:center;margin-top:20px;" class="optional_field">$lang{bg_events_display_style5}</div>
1850 <table class="calendar" summary="">
1851 <tr><td class="day" style="border-bottom-width:0;">
1852 <span class="this_month">1</span>
1853 </td><td class="day" style="border-bottom-width:0;">
1854 <div>2</div>
1855 </td></tr>
1856 <tr><td class="day" style="border-top-width:0;border-bottom-width:0;">
1857 <a id="preview_e1" class="event_box" href="" style="display:block;background-color:#ffffcc;">
1858 $lang{bg_events_display_style6}
1859 </a>
1860 </td><td class="day" style="border-top-width:0;border-bottom-width:0;">
1861 <a id="bg_preview_e1" class="event_box background" style="display:block;background-color:#ffffcc;" href="">
1862 $lang{bg_events_display_style7}
1863 </a>
1864 <a id="preview_e2" class="event_box" href="" style="display:block;background-color:#ccffcc;">
1865 $lang{bg_events_display_style6}
1866 </a>
1867 </td></tr>
1868 <tr><td class="day" colspan=2 style="border-top-width:0;">
1869 <a id="bg_preview_e2" class="event_box background" style="display:block;background-color:#ccffff;text-align:center;">
1870 $lang{bg_events_display_style7}
1871 </a>
1872 </td></tr>
1873 </table>
1874 </div>
1877 <div class="lite_box" style="clear:both;">
1880 <div class="leftcol" style="">
1881 <label class="optional_field" for="custom_stylesheet">$lang{custom_stylesheet}</label>
1882 </div>
1883 <div class="rightcol" style="white-space:nowrap;">
1884 <input id="custom_stylesheet" name="custom_stylesheet" style="width:80%;" value = "$current_calendar{custom_stylesheet}"/>
1885 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('custom_stylesheet','$lang{custom_stylesheet}')">$lang{help_on_this}</a></span>
1886 </div>
1888 <div class="leftcol" style="margin-bottom:0;">
1889 <label class="optional_field" for="custom_template">$lang{custom_template}</label>
1890 </div>
1891 <div class="rightcol" style="white-space:nowrap;margin-bottom:0;">
1892 <input id="custom_template" name="custom_template" style="width:80%;" value = "$current_calendar{custom_template}"/>
1893 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('custom_template','$lang{custom_template}')">$lang{help_on_this}</a></span>
1894 </div>
1895 <br style="clear:both;"/>&nbsp;
1897 </div>
1900 <br style="clear:both;"/>&nbsp;
1902 </div> <!-- end tab_area2-->
1906 <div id="tab_area3" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;">
1908 <div class="leftcol" style="">
1909 <label class="optional_field" for="default_number_of_months">$lang{default_number_of_months}</label>
1910 </div>
1911 <div class="rightcol" style="white-space:nowrap;">
1912 <input id="default_number_of_months" name="default_number_of_months" value = "$current_calendar{default_number_of_months}" style="width:5ex;vertical-align:bottom;"/>
1913 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('default_number_of_months','$lang{default_number_of_months}')">$lang{help_on_this}</a></span>
1914 </div>
1915 <br style="line-height:0px;height:0px;clear:both;"/>
1917 <div class="leftcol" style="margin-bottom:5ex;">
1918 <label class="optional_field" for="max_months">$lang{max_months}</label>
1919 </div>
1920 <div class="rightcol" style="white-space:nowrap;">
1921 <input id="max_months" name="max_months" style="width:5ex;" value = "$current_calendar{max_number_of_months}"/>
1922 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('max_months','$lang{max_months}')">$lang{help_on_this}</a></span>
1923 </div>
1924 <br style="line-height:0px;height:0px;clear:both;"/>
1927 if ($options{force_single_timezone} ne "1" || $current_calendar{id} eq "0") {
1928 $return_text .=<<p1;
1929 <div class="leftcol" style="">
1930 <label class="optional_field" for="gmtime_diff">$lang{timezone_offset}</label>
1931 </div>
1932 <div class="rightcol" style="white-space:nowrap;">
1933 <input id="gmtime_diff" name="gmtime_diff" style="width:5ex;" value = "$current_calendar{gmtime_diff}"/>
1934 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('gmtime_diff','$lang{timezone_offset}')">$lang{help_on_this}</a></span>
1935 </div>
1936 <br style="line-height:0px;height:0px;clear:both;"/>
1940 $return_text .=<<p1;
1942 <div class="leftcol" style="">
1943 <label class="optional_field" for="date_format">$lang{date_format}</label>
1944 </div>
1945 <div class="rightcol" style="white-space:nowrap;">
1946 <input id="date_format" name="date_format" style="width:10ex" value = "$current_calendar{date_format}"/>
1947 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('date_format','$lang{date_format}')">$lang{help_on_this}</a></span>
1948 </div>
1949 <br style="line-height:0px;height:0px;clear:both;"/>
1951 <div class="leftcol" style="margin-bottom:5ex;">
1952 <label class="optional_field" for="week_start_day">$lang{week_start_day}</label>
1953 </div>
1954 <div class="rightcol" style="white-space:nowrap;">
1955 <select id="week_start_day" name="week_start_day">
1958 for ($i=0;$i<7;$i++) {
1959 my $selected="";
1960 $selected = " selected" if ($i eq $current_calendar{week_start_day});
1961 $return_text .=<<p1;
1962 <option value="$i"$selected>$day_names[$i]
1966 $return_text .=<<p1;
1967 </select>
1968 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('week_start_day','$lang{week_start_day}')">$lang{help_on_this}</a></span>
1969 </div>
1970 <br style="line-height:0px;height:0px;clear:both;"/>
1972 <div class="leftcol" style="margin-bottom:0;">
1973 <label class="optional_field" for="event_change_email">$lang{event_change_email}</label>
1974 </div>
1975 <div class="rightcol" style="white-space:nowrap;">
1976 <input id="event_change_email" name="event_change_email" value="$current_calendar{event_change_email}"/>
1977 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('event_change_email','$lang{event_change_email}')">$lang{help_on_this}</a></span>
1978 </div>
1980 <div class="leftcol" style="margin-bottom:0;">
1981 <label class="optional_field" for="popup_window_size">$lang{popup_window_size1}</label>
1982 </div>
1983 <div class="rightcol" style="white-space:nowrap;margin-bottom:0;">
1984 <input id="popup_window_size" name="popup_window_size" style="width:12ex;" value="$current_calendar{info_window_size}"/>
1985 <span class="small_note" style="vertical-align:top;">$lang{popup_window_size2}</span>
1986 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('popup_window_size','$lang{popup_window_size1}')">$lang{help_on_this}</a></span>
1987 </div>
1989 <br style="line-height:0px;height:0px;clear:both;"/>
1990 </div>
1994 if ($options{users} eq "1") {
1995 $return_text .=<<p1;
1996 <div id="tab_area4" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:20px;text-align:left;">
1999 if ($add_edit_cal_action eq "edit") {
2000 # list users
2001 $return_text .=<<p1;
2002 <div id="select_users">
2003 </div>
2006 #if (document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].text == "custom")
2008 # add user?
2009 $return_text .=<<p1;
2010 <span id="add_user_link">
2011 <a href="javascript:add_edit_user();">$lang{add_user}</a>
2012 </span>
2013 <br/>
2014 <span class="small_note" >
2015 <a href="javascript:display_help('add_user','$lang{add_user} ')">$lang{help_on_this}</a>
2016 </span>
2020 } else {
2021 $return_text .=<<p1;
2022 <div class="optional_field">$lang{no_users_on_add}</div>
2025 $return_text .=<<p1;
2026 </div>
2030 $return_text .=<<p1;
2031 <br style="line-height:0px;height:0px;clear:both;"/>
2032 <br style="line-height:0px;height:0px;clear:both;"/>
2035 <div class="info_box" style="width:100%;margin-top:40px;">
2036 <br style="clear:both;"/>
2040 my $need_password = 1;
2041 $need_password = 0 if ($options{disable_passwords} eq "1");
2042 $need_password = 0 if ($logged_in_as_root || $logged_in_as_current_cal_admin);
2044 if ($add_edit_cal_action eq "edit") {
2045 if ($need_password eq "1") {
2046 $return_text .=<<p1;
2047 <div class="leftcol" style="clear:both;white-space:nowrap;clear:both;margin-bottom:3ex;">
2048 <label class="required_field" for="cal_password">$lang{cal_password}</label>
2049 </div>
2051 <div class="rightcol" style="white-space:nowrap;">
2052 <input type="password" name="cal_password" id="cal_password" size=12 />
2053 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('current_password','$lang{cal_password}')">$lang{help_on_this}</a></span>
2054 </div>
2056 <div class="leftcol" style="white-space:nowrap;">
2057 <label class="optional_field" for="cal_password">$lang{change_password}</label>
2058 <br/>
2059 <span class="small_note" ><a href="javascript:display_help('change_password','$lang{change_password}')">$lang{help_on_this}</a></span>
2060 </div>
2062 <div class="rightcol" style="white-space:nowrap;">
2063 <input type="password" name="new_cal_password" id="new_cal_password" size=12 />
2064 <span class="small_note" style="vertical-align:top;">$lang{new_password} </span>
2065 <br/>
2066 <input type="password" name="repeat_new_cal_password" size=12 />
2067 <span class="small_note" style="vertical-align:top;">$lang{repeat_new_password}</span>
2068 </div>
2070 } elsif ($options{disable_passwords} ne "1") {
2071 $return_text .=<<p1;
2072 <div class="leftcol">
2073 &nbsp;
2074 </div>
2075 <div class="rightcol" style="white-space:nowrap;">
2076 $lang{no_password_needed}
2077 </div>
2081 $return_text .=<<p1;
2082 <div class="leftcol">
2083 &nbsp;
2084 </div>
2085 <div class="rightcol" style="white-space:nowrap;">
2086 <input name="update_cal_button" type=submit value = "$lang{update_cal_button}"/>
2087 </div>
2089 <div class="leftcol">
2090 &nbsp;
2091 </div>
2092 <div class="rightcol" style="white-space:nowrap;">
2093 <span class="info_box_text small_note" id="preview_warning">$lang{preview_warning}</span>
2094 </div>
2096 <br style="clear:both;"/>
2099 <div style="float:left;text-align:left;">
2100 <input name="del_cal_button" class="delete_button" type="submit" value = "$lang{del_cal_button1}"
2101 onclick="return confirm('$lang{del_cal_button2}');" />
2102 <div id="delete_note">
2103 <span class="small_note">
2104 $lang{del_cal_button3}
2105 </span>
2106 </div>
2107 </div>
2109 <br style="clear:both;">
2110 <br style="clear:both;">
2113 } elsif ($add_edit_cal_action eq "add") {
2114 $return_text .=<<p1;
2115 <input id="as" name="as" type="hidden" value=""/>
2116 <div id="rt" style="display:none;">$rightnow</div>
2119 if ($options{disable_passwords} ne "1") {
2121 if ($options{anonymous_calendar_requests} ne "1" && $need_password) {
2122 $return_text .=<<p1;
2123 <div class="leftcol" style="clear:both;white-space:nowrap;clear:both;margin-bottom:3ex;">
2124 <label class="required_field" for="cal_password">$lang{existing_cal_password1}</label>
2125 <br/>$lang{existing_cal_password2}
2126 </div>
2128 <div class="rightcol" style="white-space:nowrap;">
2129 <input type="password" name="cal_password" id="cal_password" size=12 />
2130 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('current_password','$lang{cal_password}')">$lang{help_on_this}</a></span>
2131 </div>
2135 $return_text .=<<p1;
2136 <div class="leftcol" style="white-space:nowrap;">
2137 <label class="required_field" for="new_cal_password">$lang{cal_password}</label>
2138 </div>
2139 <div class="rightcol" style="white-space:nowrap;">
2140 <input type="password" name="new_cal_password" id="new_cal_password" size=12 />
2141 <span class="small_note" style="vertical-align:top;">$lang{choose_password} </span>&nbsp;
2142 <span class="small_note" style="vertical-align:top;"><a href="javascript:display_help('new_password','$lang{choose_password}')">$lang{help_on_this}</a></span>
2144 <br/>
2145 <input type="password" name="repeat_new_cal_password" size=12 />
2146 <span class="small_note" style="vertical-align:top;">$lang{repeat_password} </span>
2147 </div>
2151 $return_text .=<<p1;
2152 <div class="leftcol">
2153 &nbsp;
2154 </div>
2155 <div class="rightcol" style="white-space:nowrap;">
2156 <input name="update_cal_button" type="submit" value = "$lang{add_calendar}"/>
2157 </div>
2159 <div class="leftcol">
2160 &nbsp;
2161 </div>
2162 <div class="rightcol" style="white-space:nowrap;">
2163 <span class="info_box_text small_note" id="preview_warning">$lang{preview_warning}</span>
2164 </div>
2166 <br style="clear:both;"/>
2170 $return_text .=<<p1;
2171 </div>
2173 } else { #a user added/edited/deleted a calendar--do checks and perform resulting action
2174 my @results_messages;
2175 my $cal_id = $current_cal_id; # need to validate cal id for add/edit
2177 my $cal_valid = 1;
2178 if ($q->param('del_cal_button') ne "") {
2179 #delete calendar
2181 &load_events("all");
2182 &normalize_timezone();
2184 my $del_valid=1;
2186 #check password.
2188 if ($options{disable_passwords} ne "1" && !$logged_in_as_root && !$logged_in_as_current_cal_admin) {
2189 $del_valid=0;
2190 push @results_messages, "$lang{update_cal_error1}<b>$current_calendar{title}</b>";
2193 # prevent delete of primary calendar
2194 if ($cal_id eq "0") {
2195 $del_valid=0;
2196 push @results_messages, $lang{update_cal_error2};
2199 if ($del_valid == 1) { #actually delete the calendar.
2200 # first, delete all its events
2201 my @deleted_event_ids;
2202 my @updated_event_ids;
2203 foreach $event_id (keys %events) {
2204 # if the event is only on one calendar, delete it
2205 if (scalar@{$events{$event_id}{cal_ids}} == 1) {
2206 if ($events{$event_id}{cal_ids}[0] eq $cal_id) {
2207 push @deleted_event_ids, $event_id;}
2208 else {next;}
2209 } else { # otherwise, just remove that calendar from its cal_ids
2210 my $index=0;
2211 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
2212 if ($temp_cal_id eq $cal_id) {
2213 break;
2215 $index++;
2217 splice @{$events{$event_id}{cal_ids}}, $index, 1; {
2218 push @updated_event_ids, $event_id;}
2221 &delete_events(\@deleted_event_ids);
2222 &update_events(\@updated_event_ids);
2224 # next, delete the calendar in question
2225 &delete_calendar($cal_id); # redundant in flat-file mode, needed for sql mode
2227 # finally, delete any references in other calendars (background calendars)
2228 my @cals_to_update;
2229 foreach $calendar_id (sort {$a <=> $b} keys %calendars) {
2230 #$debug_info .= "calendar $calendar_id\n";
2231 if ($calendars{$calendar_id}{local_background_calendars}{$cal_id} eq "1") {
2232 delete $calendars{$calendar_id}{local_background_calendars}{$cal_id};
2233 push @cals_to_update, $calendar_id;
2235 if ($calendars{$calendar_id}{selectable_calendars}{$cal_id} eq "1") {
2236 delete $calendars{$calendar_id}{selectable_calendars}{$cal_id};
2237 push @cals_to_update, $calendar_id;
2240 &update_calendars(\@cals_to_update);
2242 my $temp = $lang{update_cal_error3};
2243 $temp =~ s/###title###/$current_calendar{title}/;
2244 push @results_messages, $temp;
2247 # properly format errors, warnings
2248 my @messages = split ("\n",$cal_del_results);
2249 $cal_del_results="";
2251 foreach $message (@messages) {
2252 $message =~ s/(.*$lang{Warning})/<span class="warning">$1<\/span>/i;
2253 $message =~ s/(.*$lang{Error})/<span class="error">$1<\/span>/i;
2254 $cal_del_results .= "$message<br/>\n";
2257 #$results{text} = join "\n", @messages;
2258 $cal_del_results = "<ul style=\"font-size:small;\">$cal_del_results</ul>";
2260 } else { #the user added/updated a calendar
2262 #check all input fields for validity
2263 my $cal_title = $q->param('cal_title');
2264 my $cal_link = $q->param('cal_link');
2265 my $cal_details = $q->param('cal_details');
2267 my @local_background_calendars = $q->param('background_calendars');
2268 my @selectable_calendars = $q->param('selectable_calendars');
2269 my $list_background_calendars_together = $q->param('list_background_calendars_together');
2270 my $background_events_display_style = $q->param('background_events_display_style');
2271 my $background_events_fade_factor = $q->param('background_events_fade_factor');
2272 my $background_events_color = $q->param('background_events_color');
2273 my $new_calendars_automatically_selectable = "y" if ($q->param('new_calendars_automatically_selectable') =~ "y");
2275 my $allow_remote_calendar_requests = $q->param('allow_remote_calendar_requests');
2276 my $remote_calendar_requests_require_password = $q->param('remote_calendar_requests_require_password');
2277 my $remote_calendar_requests_password = $q->param('remote_calendar_requests_password');
2279 my $new_remote_calandars_xml = $q->param('new_remote_calandars_xml');
2280 my $calendar_events_color = $q->param('calendar_events_color');
2282 my $default_number_of_months = $q->param('default_number_of_months');
2283 my $max_number_of_months = $q->param('max_months');
2284 my $gmtime_diff = $q->param('gmtime_diff');
2285 my $date_format = $q->param('date_format');
2286 $date_format = lc $date_format;
2287 my $week_start_day = $q->param('week_start_day');
2288 my $event_change_email = $q->param('event_change_email');
2289 my $info_window_size = $q->param('popup_window_size');
2291 if ($info_window_size !~ /^\d{1,}x\d{1,}$/) {
2292 $cal_valid=0;
2293 my $temp=$lang{update_cal_error4};
2294 $temp =~ s/###size###/$info_window_size/;
2295 push @results_messages, $temp;
2298 my $custom_template = $q->param('custom_template');
2299 $custom_template =~ s/http:\/\///g;
2301 my $custom_stylesheet = $q->param('custom_stylesheet');
2302 $custom_stylesheet =~ s/http:\/\///g;
2304 my $cal_password = $q->param('cal_password');
2305 my $new_cal_password = $q->param('new_cal_password');
2306 my $repeat_new_cal_password = $q->param('repeat_new_cal_password');
2308 $cal_title =~ s/\r//g; # some browsers sneak these in
2309 $cal_link =~ s/\r//g; # some browsers sneak these in
2310 $cal_details =~ s/\r//g; # some browsers sneak these in
2313 #check for required fields
2314 if ($cal_title eq "") {
2315 $cal_valid=0;
2316 push @results_messages, $lang{update_cal_error5};
2319 #strip all html from label field
2320 if ($cal_title =~ m/<(.*)>/) {
2321 push @results_messages, $lang{update_cal_error6};
2322 $cal_title =~ s/<(.*)>//g;
2325 $cal_link =~ s/http:\/\///g; #strip http:// from link field
2327 #check for date format
2328 if ($date_format !~ /^(mm|dd|yy)\W(mm|dd|yy)\W(mm|dd|yy)$/ ) {
2329 $cal_valid=0;
2330 push @results_messages, $lang{update_cal_error6_5};
2333 if ($add_edit_cal_action eq "edit") {
2334 if ($options{disable_passwords} ne "1") {
2335 #this action is an edit of an existing calendar, so we need to make a replacement.
2336 if (!(defined $calendars{$cal_id})) {
2337 $cal_valid=0;
2338 push @results_messages, $lang{update_cal_error7};
2339 } else { #check password
2340 if ($options{disable_passwords} ne "1" && !$logged_in_as_root && !$logged_in_as_current_cal_admin) {
2341 $cal_valid=0;
2342 push @results_messages, "$lang{update_cal_error1} <b>$calendars{$cal_id}{title}</b>";
2346 #check for new password
2347 if ($new_cal_password ne "" || $repeat_new_cal_password ne "") {
2348 if ($new_cal_password ne $repeat_new_cal_password) {
2349 $cal_valid=0;
2350 push @results_messages, $lang{update_cal_error8};
2351 } else {
2352 $calendars{$cal_id}{password} = crypt($new_cal_password, $options{salt});
2357 # check for gmtime_diff field
2358 if ($options{force_single_timezone} eq "1" && $cal_id ne "0") {
2359 $gmtime_diff = $calendars{0}{gmtime_diff}
2362 # encrypt remote calendar password
2363 $remote_calendar_requests_password = crypt($remote_calendar_requests_password, $options{salt});
2365 if ($cal_valid == 1) { # update calendar record
2366 my $xml_data = "";
2367 $calendars{$cal_id}{title} = $cal_title;
2368 $calendars{$cal_id}{details} = $cal_details;
2369 $calendars{$cal_id}{link} = $cal_link;
2370 $calendars{$cal_id}{new_calendars_automatically_selectable} = $new_calendars_automatically_selectable;
2371 $calendars{$cal_id}{list_background_calendars_together} = $list_background_calendars_together;
2372 $calendars{$cal_id}{calendar_events_color} = $calendar_events_color;
2373 $calendars{$cal_id}{background_events_display_style} = $background_events_display_style;
2374 $calendars{$cal_id}{background_events_fade_factor} = $background_events_fade_factor;
2375 $calendars{$cal_id}{background_events_color} = $background_events_color;
2376 $calendars{$cal_id}{default_number_of_months} = $default_number_of_months;
2377 $calendars{$cal_id}{max_number_of_months} = $max_number_of_months;
2378 $calendars{$cal_id}{gmtime_diff} = $gmtime_diff;
2379 $calendars{$cal_id}{date_format} = $date_format;
2380 $calendars{$cal_id}{week_start_day} = $week_start_day;
2381 $calendars{$cal_id}{event_change_email} = $event_change_email;
2382 $calendars{$cal_id}{info_window_size} = $info_window_size;
2383 $calendars{$cal_id}{custom_template} = $custom_template;
2384 $calendars{$cal_id}{custom_stylesheet} = $custom_stylesheet;
2385 $calendars{$cal_id}{allow_remote_calendar_requests} = $allow_remote_calendar_requests;
2386 $calendars{$cal_id}{remote_calendar_requests_require_password} = $remote_calendar_requests_require_password;
2387 $calendars{$cal_id}{remote_calendar_requests_password} = $remote_calendar_requests_password;
2389 # update local background calendars
2390 foreach $local_background_calendar (keys %{$calendars{$cal_id}{local_background_calendars}}) {
2391 delete $calendars{$cal_id}{local_background_calendars}{$local_background_calendar};
2394 foreach $local_background_calendar (@local_background_calendars) {
2395 $calendars{$cal_id}{local_background_calendars}{$local_background_calendar} = 1;
2398 #$debug_info .= "new remote calendars xml: $new_remote_calandars_xml\n";
2400 #delete existing remote background calendars
2401 foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) {
2402 if ($q->param("delete_remote_calendar_$current_remote_calendar_id") ne "") {
2403 my $temp = $lang{get_remote_calendar5};
2404 $temp =~ s/###remote url###/$current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url}/g;
2405 $temp =~ s/###remote id###/$current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id}/g;
2406 push @results_messages, $temp;
2408 delete $calendars{$current_cal_id}{remote_background_calendars}{$current_remote_calendar_id};
2412 # update remote background calendars
2413 unless ($new_remote_calandars_xml eq "") {
2414 my %new_remote_calendars = %{&xml2hash($new_remote_calandars_xml)};
2415 #$debug_info .= "$new_remote_calendars{remote_calendars}{remote_calendar}\n";
2417 my $new_remote_cal_id = &max(keys %{$calendars{$cal_id}{remote_background_calendars}}) + 1;
2418 #$debug_info .= (scalar keys %{$calendars{$cal_id}{remote_background_calendars}})." remote calendars already\n";
2419 #$debug_info .= "new_remote_cal_id: $new_remote_cal_id\n";
2421 if ($new_remote_calendars{remote_calendars}{remote_calendar} =~ /array/i) { # multiple remote background calendars
2422 foreach $temp (@{$new_remote_calendars{remote_calendars}{remote_calendar}}) {
2423 my %new_remote_calendar = %{$temp};
2425 $found=0;
2426 foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) {
2427 #$debug_info .= "comparing $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} with $new_remote_calendar{url}\n";
2428 $found=1 if ($current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} eq $new_remote_calendar{url} &&
2429 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{type} eq $new_remote_calendar{type} &&
2430 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{version} eq $new_remote_calendar{version} &&
2431 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{password} eq $new_remote_calendar{password} &&
2432 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id} eq $new_remote_calendar{remote_id});
2435 if ($found==0) {
2436 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{url} = $new_remote_calendar{url};
2437 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{type} = $new_remote_calendar{type};
2438 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{version} = $new_remote_calendar{version};
2439 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{password} = $new_remote_calendar{password};
2440 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{remote_id} = $new_remote_calendar{remote_id};
2441 $new_remote_cal_id++;
2442 } else {
2443 my $temp = $lang{get_remote_calendar4};
2444 $temp =~ s/###remote url###/$new_remote_calendar{url}/g;
2445 $temp =~ s/###remote id###/$new_remote_calendar{remote_id}/g;
2446 push @results_messages, $temp;
2449 #$debug_info .= "remote calendar: $new_remote_calendar{url}\n";
2450 #$debug_info .= "type: $new_remote_calendar{type}\n";
2452 } else { # single remote background calendar
2454 # check against existing remote background calendars.
2455 my %new_remote_calendar = %{$new_remote_calendars{remote_calendars}{remote_calendar}};
2457 $found=0;
2458 foreach $current_remote_calendar_id (keys %{$current_calendar{remote_background_calendars}}) {
2459 #$debug_info .= "comparing $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} with $new_remote_calendar{url}\n";
2460 if ($current_calendar{remote_background_calendars}{$current_remote_calendar_id}{url} eq $new_remote_calendar{url} &&
2461 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{type} eq $new_remote_calendar{type} &&
2462 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{version} eq $new_remote_calendar{version} &&
2463 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{password} eq $new_remote_calendar{password} &&
2464 $current_calendar{remote_background_calendars}{$current_remote_calendar_id}{remote_id} eq $new_remote_calendar{remote_id}) {
2465 $found=1;
2469 if ($found==0) {
2470 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{url} = $new_remote_calendar{url};
2471 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{type} = $new_remote_calendar{type};
2472 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{version} = $new_remote_calendar{version};
2473 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{password} = $new_remote_calendar{password};
2474 $calendars{$cal_id}{remote_background_calendars}{$new_remote_cal_id}{remote_id} = $new_remote_calendar{remote_id};
2475 } else {
2476 my $temp = $lang{get_remote_calendar4};
2477 $temp =~ s/###remote url###/$new_remote_calendar{url}/g;
2478 $temp =~ s/###remote id###/$new_remote_calendar{remote_id}/g;
2479 push @results_messages, $temp;
2484 #$calendars{$cal_id}{remote_background_calendars} = $remote_calendar_requests_password;
2486 # update selectable calendars
2487 foreach $selectable_calendar (keys %{$calendars{$cal_id}{selectable_calendars}}) {
2488 delete $calendars{$cal_id}{selectable_calendars}{$selectable_calendar};
2490 foreach $selectable_calendar (@selectable_calendars) {
2491 $calendars{$cal_id}{selectable_calendars}{$selectable_calendar} = 1;
2495 if ($cal_valid == 1) { #all checks successful, add/update calendar!
2496 &update_calendar($cal_id);
2497 push @results_messages, "<b>$calendars{$current_cal_id}{title}</b> $lang{update_cal_success}";
2498 } else {
2499 $cal_add_results .= $lang{update_cal_failure};
2501 } else { # add new calendar
2503 # check password, if necessary
2504 if ($options{anonymous_calendar_requests} eq "1") {
2505 my $t1 = $q->param('as');
2506 my $t2 = $rightnow;
2507 if (abs($t1 - $t2) > 3600) {
2508 $cal_valid=0;
2510 } else {
2512 if ($options{disable_passwords} ne "1" && !$logged_in_as_root && !$logged_in_as_current_cal_admin) {
2513 $cal_valid=0;
2514 push @results_messages, "$lang{update_cal_error0}";
2518 #check new password
2519 if ($options{disable_passwords} ne "1") {
2520 if ($new_cal_password ne $repeat_new_cal_password) {
2521 $cal_valid=0;
2522 push @results_messages, $lang{update_cal_error9};
2523 } elsif ($new_cal_password eq "" || $repeat_new_cal_password eq "" ) {
2524 $cal_valid=0;
2525 push @results_messages, $lang{update_cal_error10};
2526 } else {
2527 $input_password = crypt($new_cal_password, $options{salt});
2531 my $new_cal_id;
2533 if ($cal_valid == 1) {
2534 $new_cal_id = $max_action_id + int(rand(100)); # just in case several people decide to add something new at the same time.
2536 $new_calendars{$new_cal_id}{id} = $new_cal_id;
2537 $new_calendars{$new_cal_id}{title} = $cal_title;
2538 $new_calendars{$new_cal_id}{details} = $cal_details;
2539 $new_calendars{$new_cal_id}{link} = $cal_link;
2540 $new_calendars{$new_cal_id}{list_background_calendars_together} = $list_background_calendars_together;
2541 $new_calendars{$new_cal_id}{calendar_events_color} = $calendar_events_color;
2542 $new_calendars{$new_cal_id}{background_events_fade_factor} = $background_events_fade_factor;
2543 $new_calendars{$new_cal_id}{background_events_color} = $background_events_color;
2544 $new_calendars{$new_cal_id}{default_number_of_months} = $default_number_of_months;
2545 $new_calendars{$new_cal_id}{max_number_of_months} = $max_number_of_months;
2546 $new_calendars{$new_cal_id}{gmtime_diff} = $gmtime_diff;
2547 $new_calendars{$new_cal_id}{date_format} = $date_format;
2548 $new_calendars{$new_cal_id}{week_start_day} = $week_start_day;
2549 $new_calendars{$new_cal_id}{info_window_size} = $info_window_size;
2550 $new_calendars{$new_cal_id}{custom_template} = $custom_template;
2551 $new_calendars{$new_cal_id}{custom_stylesheet} = $custom_stylesheet;
2552 $new_calendars{$new_cal_id}{password} = $input_password;
2553 $new_calendars{$new_cal_id}{update_timestamp} = $rightnow;
2554 $new_calendars{$new_cal_id}{allow_remote_calendar_requests} = $allow_remote_calendar_requests;
2555 $new_calendars{$new_cal_id}{remote_calendar_requests_require_password} = $remote_calendar_requests_require_password;
2556 $new_calendars{$new_cal_id}{remote_calendar_requests_password} = $remote_calendar_requests_password;
2558 # local background calendars
2559 foreach $local_background_calendar (@local_background_calendars) {
2560 $new_calendars{$new_cal_id}{local_background_calendars}{$local_background_calendar} = 1;
2563 # selectable calendars
2564 foreach $selectable_calendar (@selectable_calendars) {
2565 $new_calendars{$new_cal_id}{selectable_calendars}{$selectable_calendar} = 1;
2569 # check for refreshes!
2570 if ($cal_valid == 1) {
2571 my %latest_new_calendar = $new_calendars{$latest_new_cal_id};
2572 if ($new_calendars{$new_cal_id}{title} eq $latest_new_calendar{title} &&
2573 $new_calendars{$new_cal_id}{details} eq $latest_new_calendar{details} &&
2574 $new_calendars{$new_cal_id}{link} eq $latest_new_calendar{link}) {
2575 $cal_valid = 0;
2576 push @results_messages, $lang{update_cal_dup};
2580 if ($cal_valid == 1) { #all checks successful, add calendar!
2581 &add_action($new_cal_id, "new_calendar");
2583 my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id});
2584 $new_cal_details =~ s/<a.+Delete this.+<\/a>//;
2585 $new_cal_details =~ s/Link directly.+<\/a>//s;
2587 if ($options{new_calendar_request_notify} ne "") {
2588 my $body = <<p1;
2589 $lang{add_cal_email_notify1}
2591 $new_cal_details
2593 <a href="$script_url/$name?active_tab=2&add_edit_cal_action=view_pending">$lang{add_cal_success3}</a>
2596 &send_email($options{new_calendar_request_notify}, $options{reply_address}, $options{reply_address}, $lang{add_cal_email_notify2}, $body);
2599 my $temp = $lang{add_cal_success1}; # add successful
2600 $temp = $lang{add_cal_success4} if ($add_edit_cal_action eq "edit"); # update successful
2602 $cal_add_results .= <<p1;
2603 <div style="text-align:left;">
2604 <p style="font-weight:bold;">
2605 $temp
2606 </p>
2608 <div class="info_box">
2609 $new_cal_details
2610 </div>
2612 <p style="margin-top:1em;">
2613 $lang{add_cal_success2}
2614 </p>
2616 <ul>
2617 <li><a href="$script_url/$name?active_tab=2&add_edit_cal_action=view_pending">$lang{add_cal_success3}</a>
2618 </ul>
2619 </div>
2621 } else {
2622 push @results_messages, $lang{add_cal_fail1};
2626 # properly format errors & warnings
2627 my $message_results="";
2628 foreach $results_message (@results_messages) {
2629 $results_message =~ s/(.*$lang{Warning})/<span class="warning">$1<\/span>/i;
2630 $results_message =~ s/(.*$lang{Error})/<span class="error">$1<\/span>/i;
2631 $message_results .= "<li>$results_message</li>\n";
2634 $cal_add_results = "<ul style=\"font-size:small;\">$message_results</ul>$cal_add_results";
2637 $return_text .=<<p1;
2638 <div style="text-align:left;">
2639 $cal_add_results
2640 $cal_del_results
2641 </div>
2643 return $return_text;
2644 } #********************end add_edit_calendars code*****************************
2647 sub view_pending_calendars {
2648 my $return_text = "";
2650 if ($q->param('approve_cal_button') eq "") { #view pending calendars main screen
2652 $cal_details ="";
2653 $shared_cal_select_size = scalar keys %calendars;
2655 $return_text.=<<p1;
2656 <p class="cal_title">
2657 $lang{view_pending_calendars1}
2658 </p>
2662 if (scalar keys %new_calendars == 0) {
2663 $return_text.=<<p1;
2664 <p class="optional_field">
2665 $lang{view_pending_calendars2}
2666 </p>
2668 } else {
2669 $return_text.=<<p1;
2670 <form name="pending_calendars_form" action="">
2671 <input type="hidden" name="active_tab" value="2">
2672 <input type="hidden" name="add_edit_cal_action" value="view_pending">
2675 foreach $new_cal_id (keys %new_calendars) {
2676 my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id});
2677 $new_cal_details =~ s/<a.+Delete this.+<\/a>//;
2678 $new_cal_details =~ s/Link directly.+<\/a>//s;
2679 #Link directly to this calendar:<br/>
2680 #<a href="$script_url/$name?cal_id=$calendar{id}">$script_url/$name?cal_id=$calendar{id}</a>
2684 $return_text.=<<p1;
2685 <div class="info_box" style="float:left;text-align:left;width:40%;margin:10px;clear:both;">
2686 $new_cal_details
2687 </div>
2688 <div style="float:left;text-align:left;margin:10px;">
2689 <br/>
2690 <input type="radio" name="new_cal_$new_cal_id" value="approve"/><span class="optional_field">$lang{view_pending_calendars3}</span><br/><br/>
2691 <input type="radio" name="new_cal_$new_cal_id" value="delete"/><span class="optional_field">$lang{view_pending_calendars4}</span><br/>
2692 </div>
2693 <br style="clear:both;"/>
2696 $return_text.=<<p1;
2697 <div style="clear:both;">
2699 <label for="main_password" class="optional_field">
2700 $calendars{0}{title} Password:
2701 </label>
2702 <input type=password id="main_password" name = "main_password" size=10>
2703 <br/>
2704 <input type=submit name="approve_cal_button" value = "$lang{view_pending_calendars5}">
2705 </form>
2706 </div>
2710 } else { #view pending calendars approve/delete results screen
2712 my @pending_calendars_to_delete;
2713 my @calendars_to_add;
2714 my @calendars_to_update;
2716 $cal_details ="";
2717 $shared_cal_select_size = scalar keys %calendars;
2719 $return_text.=<<p1;
2720 <p class="cal_title">
2721 $lang{view_pending_calendars6}
2722 </p>
2725 #check password
2726 $input_password = crypt($q->param('main_password'), $options{salt});
2728 if ($options{disable_passwords} ne "1") {
2729 if ($input_password ne $master_password) {
2730 $return_text .=<<p1;
2731 <ul>
2732 <li>$lang{view_pending_calendars7}</li>
2733 </ul>
2735 return $return_text;
2739 #go through each new calendar in the new calendars file--take appropriate action
2740 foreach $new_cal_id (keys %new_calendars) {
2741 my $new_cal_details = &generate_cal_details($new_calendars{$new_cal_id});
2743 if ($q->param("new_cal_$new_cal_id") eq "approve") {
2744 $max_cal_id+=1; #calculate new id # for the new calendar
2746 foreach $cal_id (keys %calendars) {
2747 if ($calendars{$cal_id}{new_calendars_automatically_selectable} =~ "y") {
2748 $calendars{$cal_id}{selectable_calendars}{$max_cal_id} = 1;
2749 push @calendars_to_update, $cal_id;
2753 $calendars{$max_cal_id} = $new_calendars{$new_cal_id};
2754 $calendars{$max_cal_id}{id} = $max_cal_id;
2756 # make sure the calendar can select itself.
2757 $calendars{$max_cal_id}{selectable_calendars}{$max_cal_id} = 1 if (scalar keys %{$calendars{$max_cal_id}{selectable_calendars}} > 0);
2759 delete $new_calendars{$new_cal_id};
2760 push @pending_calendars_to_delete, $new_cal_id;
2761 push @calendars_to_add, $max_cal_id;
2763 $approve_or_delete_result = $lang{view_pending_calendars8};
2764 } elsif ($q->param("new_cal_$new_cal_id") eq "delete") {
2765 delete $new_calendars{$new_cal_id};
2766 push @pending_calendars_to_delete, $new_cal_id;
2767 $approve_or_delete_result = $lang{view_pending_calendars9};
2768 } else {
2769 $approve_or_delete_result = $lang{view_pending_calendars10};
2773 $new_cal_details =~ s/<a.+Delete this.+<\/a>//;
2774 $new_cal_details =~ s/Link directly.+<\/a>//s;
2776 $return_text .= <<p1;
2777 <div style="float:left;clear:left;width:90%;">
2778 <div class="info_box" style="text-align:left;width:40%;margin:10px;clear:both;float:left;">
2779 $new_cal_details
2780 </div>
2781 <div style="text-align:left;margin:10px;float:left;">
2782 <br/>
2783 $approve_or_delete_result
2784 </div>
2785 </div>
2789 &delete_pending_actions(\@pending_calendars_to_delete);
2790 &add_calendars(\@calendars_to_add);
2791 &update_calendars(\@calendars_to_update);
2794 $return_text.=<<p1;
2795 <br style="clear:both;"/>
2798 return $return_text;
2800 } #********************end view_pending_calendars code*****************************
2803 sub do_calendar_list_view() {
2804 my $return_text = "";
2806 if ($cal_num_months> 1) {
2807 $cal_title_string .=<<p1;
2808 $months[$cal_start_month] $cal_start_year - $months[$cal_end_month] $cal_end_year
2810 } else {
2811 $cal_title_string .=<<p1;
2812 $months[$cal_start_month] $cal_start_year
2816 # previous and next month(s) link
2817 $return_text .=<<p1;
2818 <div style="text-align:center;white-space:nowrap;">
2819 $prev_month_link
2820 <span class="cal_title" style="margin-left:3em;margin-right:3em;">
2821 $cal_title_string
2822 </span>
2823 $next_month_link
2824 </div>
2827 <div style="clear:both;margin:auto;">
2830 if ($display_type == 1) { #list view
2832 $return_text .= &render_list($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
2833 } else { #calendar view
2835 $return_text .= &render_calendar($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year);
2837 $return_text .=<<p1;
2838 </div>
2841 return $return_text;
2843 } ###############end do_calendar_list_view ###################
2846 sub add_edit_events_interface() {
2847 my $temp="<link rel=\"stylesheet\" href=\"$theme_url/color_select.css\" type=\"text/css\">";
2848 $html_output =~ s/<head>/<head>\n$temp\n/;
2850 my $return_text = "";
2851 $add_edit_event = "add" if ($add_edit_event eq "");
2853 $add_edit_string = $lang{add_or_edit1};
2854 $event_details ="";
2856 $event_start_date = $current_calendar{date_format};
2858 if ($q->param('add_date_timestamp')+0 == 0) { # no date supplied--generic add event
2859 # no date supplied--generic add event
2860 if ($cal_start_year ne "") {
2861 $event_start_date =~ s/yy/$cal_start_year/;
2862 } else {
2863 $event_start_date =~ s/yy/$rightnow_year/;
2865 } else { # add event on a particular date -- calculate date
2866 my @event_start_date_array = gmtime $q->param('add_date_timestamp');
2867 my $mm = $event_start_date_array[4]+1;
2868 my $md = $event_start_date_array[3];
2869 my $yy = $event_start_date_array[5]+1900;
2871 $event_start_date =~ s/mm/$mm/;
2872 $event_start_date =~ s/dd/$md/;
2873 $event_start_date =~ s/yy/$yy/;
2876 my $recur_end_date = $current_calendar{date_format};
2877 $recur_end_date =~ s/mm/12/;
2878 $recur_end_date =~ s/dd/31/;
2879 $recur_end_date =~ s/yy/$rightnow_year/;
2881 $event_days = "1";
2882 $event_icon = "blank";
2883 my %current_event;
2885 my $unit_number_text = "";
2886 my $event_unit_number = "";
2888 $add_edit_string = $lang{add_or_edit2} if ($add_edit_event eq "edit");
2890 if ($current_event_id ne "") {
2891 #select the appropriate event to edit
2892 %current_event = %{$events{$current_event_id}};
2893 @current_cal_ids = @{$current_event{cal_ids}};
2894 %current_calendar = %{$calendars{$current_cal_ids[0]}};
2895 #$cal_title=$calendars{$current_event{cal_id}}{title};
2897 $event_name = $current_event{title};
2898 $event_details = $current_event{details};
2900 $event_start_date = $current_calendar{date_format};
2901 my @temp_date = gmtime($current_event{start});
2902 $temp_date[5] += 1900;
2903 $temp_date[4] += 1;
2905 $event_start_date =~ s/mm/$temp_date[4]/;
2906 $event_start_date =~ s/dd/$temp_date[3]/;
2907 $event_start_date =~ s/yy/$temp_date[5]/;
2909 $event_days=$current_event{days};
2910 $event_icon = $current_event{icon};
2911 $event_bgcolor = $current_event{bgcolor};
2912 $event_unit_number = $current_event{unit_number};
2913 $unit_number_text = $event_unit_number;
2914 $unit_number_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" alt="" border="0" vspace=0 hspace=0>/g;
2917 $return_text .=<<p1;
2918 <p class="cal_title" style="text-align:center;">
2919 $add_edit_string
2920 </p>
2922 <div class="info_box" style="text-align:center;margin-bottom:2em;float:left;">
2923 <span class="optional_field">$lang{fields_text1} <span class="required_field">$lang{fields_text2}</span> $lang{fields_text3}</span>
2924 </div>
2926 <div style="clear:both;width:90%;text-align:left;white-space:nowrap;clear:left;">
2927 <a id="tab0" href="javascript:tab_show(0)" class="info_box_tab active">$lang{add_edit_events_tab0}</a>
2928 <a id="tab1" href="javascript:tab_show(1)" class="info_box_tab">$lang{add_edit_events_tab1}</a>
2929 </div>
2931 <div id="tab_area0" class="info_box" style="width:100%;position:relative;z-index:101;padding-top:1em;margin-bottom:1em;">
2933 my @selectable_cal_ids;
2935 if ($options{all_calendars_selectable}) {
2936 @selectable_cal_ids = keys %calendars;
2937 } else {
2938 @selectable_cal_ids = keys %{$current_calendar{selectable_calendars}};
2939 push @selectable_cal_ids, $current_cal_id;
2942 my %evt_calendar = %{$calendars{$current_cal_id}};
2943 %evt_calendar = %{$calendars{$current_event{cal_ids}[0]}} if ($add_edit_event eq "edit");
2945 if ($add_edit_event eq "edit" || scalar @selectable_cal_ids == 0) { # force event calendar
2946 $return_text .=<<p1;
2947 <input type="hidden" name="cal_id" value="$evt_calendar{id}">
2948 <div class="leftcol">
2949 <span class="optional_field">$lang{event_calendar}</span>
2950 </div>
2951 <div class="rightcol" style="padding-left:.5em;">
2952 $evt_calendar{title}
2953 </div>
2955 } else { # user can select event calendar
2956 $return_text .=<<p1;
2957 <div class="leftcol">
2958 <span class="required_field">$lang{event_calendar}</span>
2959 </div>
2960 <div class="rightcol">
2961 <select name="cal_id" id="cal_id">
2964 foreach $cal_ref_id (sort {$calendars{$a}{title} cmp $calendars{$b}{title}} @selectable_cal_ids) {
2965 my $selected = "";
2966 $selected = " selected" if ($cal_ref_id eq $evt_calendar{id});
2967 $return_text .=<<p1;
2968 <option value = "$cal_ref_id"$selected>$calendars{$cal_ref_id}{title}
2972 $return_text .=<<p1;
2973 </select>
2974 <span class="small_note"><a href="javascript:display_help('evt_cal_id','$lang{event_calendar}')">$lang{help_on_this}</a></span>
2978 if ($options{allow_merge_blocking}) {
2980 my $block_merge_checked = ($current_event{block_merge} eq "1") ? " checked" : "";
2982 $return_text .=<<p1;
2983 &nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" name="evt_block_merge" id=evt_"block_merge" value="1"$block_merge_checked/>
2984 <span class="optional_field">$lang{block_merge}</span>
2989 $return_text .=<<p1;
2990 </div>
2993 if ($options{multi_calendar_event_mode} > 0 && $add_edit_event eq "edit") {
2994 $return_text .=<<p1;
2995 <div class="leftcol">
2996 <span class="optional_field">$lang{event_other_calendars}</span>
2997 </div>
2998 <div class="rightcol" style="padding-left:.5em;">
2999 <select multiple name="evt_other_cal_ids">
3002 foreach $cal_ref_id (sort {$calendars{$a}{title} cmp $calendars{$b}{title}} @selectable_cal_ids) {
3003 my $selected = "";
3004 next if ($cal_ref_id eq $evt_calendar{id});
3006 foreach $selected_cal_id (@{$events{$current_event_id}{cal_ids}}) {
3007 if ($cal_ref_id eq $selected_cal_id) {
3008 $selected = " selected";
3009 last;
3013 $return_text .=<<p1;
3014 <option value = "$cal_ref_id"$selected>$calendars{$cal_ref_id}{title}
3018 $return_text .=<<p1;
3019 </select>
3020 <span class="small_note"><a href="javascript:display_help('evt_other_cal_ids','$lang{event_other_calendars}')">$lang{help_on_this}</a></span>
3021 </div>
3025 my $all_day_event_checked = "";
3027 if ($options{new_events_all_day}) {
3028 $all_day_event_checked = "checked";}
3030 my $event_start_time = $options{default_event_start_time};
3031 my $event_end_time = $options{default_event_end_time};
3033 if ($current_event_id ne "") {
3034 $all_day_event_checked = "checked";
3035 $all_day_event_checked = "" if ($current_event{all_day_event} ne "1");
3036 $event_start_time = &formatted_time($current_event{start},"hh:mm ampm");
3037 $event_end_time = &formatted_time($current_event{end},"hh:mm ampm");
3038 $event_end_time = "" if ($current_event{no_end_time} eq "1");
3043 my $all_day_event_toggle0_style = "display:none;";
3044 if ($all_day_event_checked ne "checked") {
3045 $all_day_event_toggle0_style = "";
3048 my $edit_title = &escapequotes($current_event{title});
3049 $return_text .=<<p1;
3050 <div class="leftcol" style="">
3051 <label class="required_field" for="evt_title">$lang{event_title}</label>
3052 </div>
3053 <div class="rightcol" style="white-space:nowrap;">
3054 <input id="evt_title" name="evt_title" style="width:50%;" value = "$edit_title">
3055 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('evt_title','$lang{event_title}')">$lang{help_on_this}</a></span>
3056 </div>
3058 <div class="leftcol" style="">
3059 <label class="optional_field" for="evt_details">$lang{event_details}</label>
3060 <br/>
3061 <span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('evt_details','$lang{event_details}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
3062 </div>
3063 <div class="rightcol" style="white-space:nowrap;">
3064 <textarea name="evt_details" id="evt_details" rows=10 cols=0 style="width:100%;">$current_event{details}</textarea>
3065 </div>
3067 <div class="leftcol" style="margin-bottom:0;">
3068 <label class="required_field" for="evt_start_date">$lang{event_start}</label>
3069 </div>
3070 <div class="rightcol" style="margin-bottom:0;white-space:nowrap;">
3071 <input id="evt_start_date" name="evt_start_date" style="width:7em;" value = "$event_start_date" onchange="validate_event_date();">
3072 <span id="evt_start_date_warning" class="small_note"></span>
3073 </div>
3075 <div class="leftcol" style="">
3076 <label class="required_field" for="evt_days">$lang{event_length}</label>
3077 </div>
3078 <div class="rightcol" style="white-space:nowrap;">
3079 <input id="evt_days" name="evt_days" style="width:2em;" value = "$event_days">
3080 <input type="checkbox" id="all_day_event" name="all_day_event" value="1"$all_day_event_checked onChange="all_day_event_toggle(this.checked);">
3081 <label class="optional_field" for="all_day_event">$lang{all_day_event}</label>
3082 </div>
3084 <div id="all_day_event_toggle0" style="$all_day_event_toggle0_style">
3085 <div class="leftcol" style="margin-bottom:0;">
3086 <label class="required_field" for="evt_start_time">$lang{event_start_time}</label>
3087 </div>
3088 <div class="rightcol" style="margin-bottom:0;white-space:nowrap;">
3089 <input id="evt_start_time" name="evt_start_time" style="width:7em;" value = "$event_start_time">
3090 </div>
3091 <div class="leftcol" style="margin-bottom:0;">
3092 <label class="optional_field" for="evt_end_time">$lang{event_end_time}</label>
3093 </div>
3094 <div class="rightcol" style="margin-bottom:0;white-space:nowrap;">
3095 <input id="evt_end_time" name="evt_end_time" style="width:7em;" value = "$event_end_time">
3096 </div>
3097 </div>
3100 $return_text .=<<p1;
3101 <div style="float:right;width:20%;">
3102 <div class="icon_preview_box" style="float:left;">
3103 <div id="icon_preview" style="text-align:center;">
3104 <img src="$icons_url/$event_icon\l_32x32.gif" alt='event icon' border="0" vspace=0 hspace=0>
3105 </div>
3107 if ($options{unit_number_icons} == 1) {
3108 $return_text .=<<p1;
3109 <div id="unit_number_preview" style="margin:3px;">
3110 $unit_number_text
3111 </div>
3114 $return_text .=<<p1;
3115 </div>
3116 </div>
3120 $return_text .=<<p1;
3121 <div class="leftcol" style="margin-bottom:0;">
3122 <label class="optional_field" for="evt_icon">$lang{event_icon}</label>
3123 </div>
3124 <div class="rightcol" style="margin-bottom:0;white-space:nowrap;width:auto;">
3125 <select name="evt_icon" id="evt_icon" onChange="update_preview_icon()">
3127 @icon_menus_data = &assemble_icon_menus($event_icons_menu);
3128 $icon_menu_index_number = 0;
3129 $return_text .= &generate_flat_icon_menus(\@icon_menus_data, $event_icon);
3131 $return_text .=<<p1;
3132 </select>
3133 </div>
3135 if ($options{unit_number_icons} == 1) {
3136 $return_text .=<<p1;
3137 <div class="leftcol" style="margin-bottom:0;">
3138 <label class="optional_field" for="unit_number">$lang{event_unit_number} </label>
3139 </div>
3140 <div class="rightcol" style="margin-bottom:0;white-space:nowrap;width:40%">
3141 <input id="unit_number" name="unit_number" style="width:6ex;" value = "$event_unit_number" onKeyUp="update_preview_icon()">
3142 </div>
3146 $return_text .=<<p1;
3147 <div class="leftcol" style="">
3148 <label class="optional_field" for="cal_details">$lang{event_background_color}</label>
3149 </div>
3150 <div class="rightcol" style="white-space:nowrap;width:40%;">
3151 <input name="dummy" value="" size=1 style="display:none;">
3152 <select name="evt_bgcolor" onchange="update_bg_color_select_box()" style="width:7em;">
3154 my $custom_color = 1;
3156 foreach $temp (@event_bgcolors) {
3157 %possible_bgcolor = %{$temp};
3158 my $selected="";
3159 if ($possible_bgcolor{color} eq "$event_bgcolor") { # default
3160 $custom_color = 0;
3161 $selected = " selected";
3163 my $description = "";
3164 $description = $possible_bgcolor{title} if ($options{show_event_background_color_descriptions});
3166 $return_text .=<<p1;
3167 <option value = "$possible_bgcolor{color}" $selected>$description
3171 my $color_select_icon_style="visibility:hidden;";
3172 if ($custom_color == 1 && $add_edit_event eq "edit") {
3173 $color_select_icon_style = "";
3174 $return_text .=<<p1;
3175 <option id="custom_evt_color" value = "$event_bgcolor" selected>$lang{event_background_colorcustom}
3177 } else {
3178 $return_text .=<<p1;
3179 <option id="custom_evt_color" value = "#ffffff">$lang{event_background_colorcustom}
3184 $return_text .=<<p1;
3185 </select>
3186 <span id="color_select_icon0" class="color_select_icon" style="$color_select_icon_style vertical-align:top;background-image:url($graphics_url/color_select_icon.gif);" onClick="cs0.toggle_color_select();">&nbsp;&nbsp;&nbsp;&nbsp;</span>
3188 </div>
3189 <br style="clear:both;"/>
3190 <br style="clear:both;"/>
3192 </div>
3196 <div id="tab_area1" class="info_box" style="width:100%;display:none;position:relative;z-index:101;padding-top:1em;text-align:left;">
3199 if ($add_edit_event eq "edit") {
3200 if ($current_event{series_id} ne "") {
3201 $return_text .=<<p1;
3202 <input type="hidden" name="recurring_event" value="1">
3203 <input type="hidden" name="series_id" value="$current_event{series_id}">
3205 <div style="text-align:center;">
3206 $lang{recurring_event_edit1}
3207 </div>
3209 <div class="leftcol" style="margin-bottom:1em;">
3210 <span class="small_note"><a href="javascript:display_help('recurring_event_change_all','$lang{recurring_event_change_all1}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
3211 </div>
3212 <div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
3213 <input type="checkbox" name="all_in_series" value="1" onClick="recur_edit_toggle()">
3214 <label class="optional_field">$lang{recurring_event_change_all1}</label>
3215 <div class="small_note style="margin-left:17px;"">$lang{recurring_event_change_all2}</div>
3216 </div>
3218 } else {
3219 $return_text .=<<p1;
3220 $lang{recurrence_not_allowed}
3223 $return_text .=<<p1;
3224 <br style="clear:both;"/>
3227 } else {
3228 $return_text .=<<p1;
3229 <div class="leftcol" style="margin-bottom:1em;">
3230 <span class="small_note"><a href="javascript:display_help('recurring_event','$lang{recurring_event}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
3231 </div>
3232 <div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
3233 <input type="checkbox" name="recurring_event" value="1" onclick="javascript:recur_toggle();">
3234 <label class="optional_field">$lang{recurring_event}</label>
3235 </div>
3237 <div class="leftcol" style="margin-bottom:1em;vertical-align:middle;">
3238 <span class="fit_event">
3239 <i>$lang{recurrence_type}</i><br/>
3240 <span class="small_note"><a href="javascript:display_help('recurrence_type','$lang{recurrence_type}')">$lang{help_on_this}</a></span>
3241 </span>
3242 </div>
3243 <div class="rightcol" style="margin-bottom:1em;white-space:nowrap;">
3244 <input type="radio" name="recurrence_type" value="same_day_of_month" disabled checked onclick="recurrence_type_update()">
3245 <span class="optional_field">$lang{same_day_of_month}</span>
3246 <br/>
3247 <input type="radio" name="recurrence_type" value="same_day_of_week" disabled onclick="recurrence_type_update()">
3248 <span class="optional_field">
3249 $lang{same_weekday}
3250 </span>
3251 <select name = "weekday_of_month_type" disabled>
3252 <option value = "every_week">$lang{on_every_week}
3253 <option value = "only_first_week">$lang{on_first_week}
3254 <option value = "only_second_week">$lang{on_second_week}
3255 <option value = "only_third_week">$lang{on_third_week}
3256 <option value = "only_fourth_week">$lang{on_fourth_week}
3257 <option value = "only_fifth_week">$lang{on_fifth_week}
3258 <option value = "only_last_week">$lang{on_last_week}
3259 </select> $lang{of_the_month}
3260 <br/>
3262 <span class="optional_field">
3265 my $temp =<<p1;
3266 <input name = "every_x_days" disabled/ value="1" style="width:2em;">
3268 $lang{every_x_days} =~ s/###x###/$temp/;
3270 $return_text .=<<p1;
3271 <input type="radio" name="recurrence_type" value="every_x_days" disabled onclick="recurrence_type_update()">
3272 $lang{every_x_days}
3273 </span>
3274 <br/>
3276 <span class="optional_field">
3278 my $temp =<<p1;
3279 <input name = "every_x_weeks" disabled/ value="1" style="width:2em;">
3281 $lang{every_x_weeks} =~ s/###x###/$temp/;
3283 $return_text .=<<p1;
3284 <input type="radio" name="recurrence_type" value="every_x_weeks" disabled onclick="recurrence_type_update()">
3285 $lang{every_x_weeks}
3286 </span>
3290 </div>
3292 <div class="leftcol" style="">
3293 <span class="fit_event">
3294 <i>$lang{fit_into_year}</i><br/>
3295 <span class="small_note"><a href="javascript:display_help('fit_into_year','$lang{fit_into_year}')">$lang{help_on_this}</a></span>
3296 </span>
3297 </div>
3298 <div class="rightcol" style="white-space:nowrap;">
3299 <input type="radio" name="year_fit_type" value="every_month" checked disabled onclick="document.add_event_form.custom_months.disabled=true">
3300 <span class="optional_field">
3301 $lang{every_momth}
3302 </span>
3304 <div style="float:left;">
3305 <input type="radio" name="year_fit_type" value="custom_months" disabled onclick="document.add_event_form.custom_months.disabled=false">
3306 <span class="optional_field">$lang{certain_months1} </span>
3307 <br/>
3308 <span class="small_note">$lang{certain_months2}</span>
3309 </div>
3311 <div style="float:left;">
3312 <select multiple name = "custom_months" size=4 disabled>
3315 for ($l1=0;$l1<scalar @months;$l1++) {
3316 $return_text .=<<p1;
3317 <option value = $l1>$months[$l1]
3321 $return_text .=<<p1;
3322 </select>
3323 </div>
3325 </div>
3327 <div class="leftcol" style="">
3328 <label class="required_field">$lang{recurring_event_ends}</label>
3329 </div>
3330 <div class="rightcol" style="white-space:nowrap;">
3331 <input name="recur_end_date" size=12 value="$recur_end_date" disabled>
3332 </div>
3334 <br style="clear:both;"/>
3338 $return_text .=<<p1;
3339 </div>
3341 <div style="margin-top:1em;margin-bottom:1em;float:left;width:48%;text-align:center;font-weight:bold;">
3342 <a href="javascript:preview_event()">$lang{preview_event1}</a>
3343 <p class="small_note active_tab_text">
3344 $lang{preview_event2}
3345 </p>
3346 </div>
3348 <div style="margin-top:1em;margin-bottom:1em;float:left;width:48%;text-align:center;font-weight:bold;">
3349 <a href="javascript:preview_dates()">$lang{preview_dates1}</a>
3350 <p class="small_note active_tab_text">
3351 $lang{preview_dates2}
3352 </p>
3353 </div>
3355 <div class="info_box" style="clear:both;">
3357 my $need_password = 1;
3358 $need_password = 0 if ($options{disable_passwords} eq "1");
3359 $need_password = 0 if ($logged_in_as_root || $logged_in_as_current_cal_admin || $logged_in_as_current_cal_user);
3361 if ($need_password == 1) {
3362 $return_text .=<<p1;
3363 <div class="leftcol" style="">
3364 <label class="required_field" for="cal_password">$lang{cal_password}</label>
3365 </div>
3366 <div class="rightcol" style="white-space:nowrap;">
3367 <input type="password" id="cal_password" name="cal_password" style="width:30%;">
3368 <span class="small_note" style="vertical-align:top;" ><a href="javascript:display_help('cal_password','$lang{cal_password}')">$lang{help_on_this}</a>&nbsp;&nbsp;</span>
3369 </div>
3371 } else {
3372 $return_text .=<<p1;
3373 <div class="leftcol">
3374 &nbsp;
3375 </div>
3376 <div class="rightcol" style="white-space:nowrap;">
3377 $lang{no_password_needed}
3378 </div>
3385 if ($add_edit_event eq "edit") {
3386 $return_text .=<<p1;
3387 <div class="leftcol" style="">
3388 &nbsp;
3389 </div>
3390 <div class="rightcol" style="white-space:nowrap;">
3391 <input name="add_event_button" type="submit" value = "$lang{update_event}">
3392 <div class="small_note">$lang{add_event2_update}</div>
3393 </div>
3396 <div style="text-align:left;">
3397 <input name="del_event_button" class="delete_button" type="submit" value = "$lang{delete_event1}">
3398 <div class="small_note">$lang{delete_event2}</div>
3399 </div>
3402 } else {
3403 $return_text .=<<p1;
3404 <div class="leftcol" style="">
3405 &nbsp;
3406 </div>
3407 <div class="rightcol" style="white-space:nowrap;">
3408 <input name="add_event_button" type="submit" value = "$lang{add_event1}">
3409 <br/>
3410 <span id="preview_note" class="small_note">
3411 $lang{add_event2}
3412 </span>
3413 </div>
3415 <br style="clear:both;"/>
3416 <br style="clear:both;"/>
3419 $return_text .=<<p1;
3420 </div>
3425 sub add_edit_events {
3426 $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}/g;
3427 $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}/g;
3428 $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g;
3430 my %results;
3432 my $recurring_event = $q->param('recurring_event');
3433 my $all_in_series = $q->param('all_in_series');
3435 # load (reload) all events (we have to write events beyond the default time window)
3436 if ($options{data_storage_mode} == 0) {
3437 unless ($loaded_all_events eq "1") {
3438 &load_events("all");
3439 &normalize_timezone();
3443 my $login_valid = 0;
3445 if ($options{disable_passwords} eq "1") {
3446 $login_valid = 1
3447 } elsif ($current_cal_id ne "") {
3448 #$debug_info .= "current_cal_id: $current_cal_id\n";
3449 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
3450 $login_valid = 1 if ($logged_in_as_root || $logged_in_as_current_cal_admin || $logged_in_as_current_cal_user); # current calendar user
3451 } elsif ($options{multi_calendar_event_mode} == 2) { # any of the event's calendars' users or the root user are allowed
3452 if ($logged_in_as_root || $logged_in_as_current_cal_admin || $logged_in_as_current_cal_user) { # current calendar user
3453 $login_valid = 1;
3454 } else {
3455 my $cal_password_valid = 0;
3456 foreach $cal_id (@evt_other_cal_ids) {
3457 my $temp = $cal_id;
3458 $cal_password_valid = 1 if ($profile->{calendar_permissions}->{$cal_id}->{admin} eq "1"); # shared calendar admin
3459 $cal_password_valid = 1 if ($profile->{calendar_permissions}->{$cal_id}->{user} ne ""); # shared calendar user
3461 $login_valid = 1 if ($cal_password_valid == 1);
3468 if ($q->param('del_event_button') ne "" || $api_command eq "delete_event") {
3469 $del_valid = 1; #delete event.
3471 if ($login_valid == 0) {
3472 $del_valid = 0;
3473 push @{$results{messages}}, "[error]$lang{update_event_err1} '$current_calendar{title}'";
3476 if (!defined $events{$current_event_id}) {
3477 $del_valid=0;
3478 push @{$results{messages}}, "[error]$lang{update_event_err2}";
3481 if ($del_valid == 1) { #actually delete the event(s).
3482 if ($all_in_series ne "1") {
3483 my $subj = $lang{notify_subj};
3484 $subj =~ s/\$1/$script_url\/$name/;
3486 my $body = $lang{event_delete_notify};
3487 $body =~ s/\$1/$events{$current_event_id}{title}/;
3488 $body =~ s/\$2/$calendars{$current_cal_id}{title}/;
3490 foreach $email (@{$current_calendar{delete_emails}}) {
3491 #$debug_info .= "email notification sent to $email\n";
3492 &send_email($email, $options{reply_address}, $options{reply_address}, $subj, $body) if ($options{email_mode} > 0);
3495 &delete_event($current_event_id);
3496 push @{$results{messages}}, "[status]$lang{update_event_delete_successful}";
3498 } else {
3499 # get the ids of the events in the series.
3500 my @events_in_series = &get_events_in_series($q->param('series_id'));
3501 &normalize_timezone();
3502 &delete_events(\@events_in_series);
3503 push @{$results{messages}}, "[status]$lang{update_event_delete_successful_recurring}";
3505 $results{success} = 1;
3506 } else {
3507 $results{success} = 0;
3509 } else { # not a delete
3510 if (!$login_valid) {
3511 if ($options{anonymous_events}) {
3512 my $temp = $lang{update_event_err16};
3513 $temp =~ s/###calendar###/<b>$current_calendar{title}<\/b>/g;
3514 push @{$results{messages}}, ("[error]".$temp);
3515 } else {
3516 push @{$results{messages}}, "[error]".($lang{update_event_err1}."'".$current_calendar{title}."'");
3520 #check all input fields for validity
3521 my $event_valid = 1;
3522 my $event_id = $q->param('evt_id'); # only if editing.
3523 #my $event_cal_id = $current_cal_id;
3525 my @evt_other_cal_ids;
3526 @evt_other_cal_ids = $q->param('evt_other_cal_ids') if ($options{multi_calendar_event_mode} > 0);
3528 my $event_cal_password = $q->param('cal_password');
3529 my $event_title = $q->param('evt_title');
3530 my $event_icon = $q->param('evt_icon');
3531 my $event_details = $q->param('evt_details');
3532 my $event_unit_number = $q->param('unit_number');
3533 my $event_bgcolor = $q->param('evt_bgcolor');
3534 my $event_block_merge = $q->param('evt_block_merge');
3535 my $event_series_id = $q->param('series_id');
3537 my $event_duration = 0;
3538 my $event_start_timestamp = 0;
3539 my $event_end_timestamp = 0;
3541 $recur_end_date = $q->param('recur_end_date');
3542 my $all_day_event = $q->param('all_day_event');
3543 my $no_end_time = "";
3544 my $event_start_time = $q->param('evt_start_time');
3545 my $event_end_time = $q->param('evt_end_time');
3546 $event_start_date = $q->param('evt_start_date');
3547 my $event_days = $q->param('evt_days');
3549 my %recurrence_parms;
3550 $recurrence_parms{'recurrence_type'} = $q->param('recurrence_type');
3551 $recurrence_parms{'weekday_of_month_type'} = $q->param('weekday_of_month_type');
3552 $recurrence_parms{'every_x_days'} = $q->param('every_x_days');
3553 $recurrence_parms{'every_x_weeks'} = $q->param('every_x_weeks');
3554 $recurrence_parms{'year_fit_type'} = $q->param('year_fit_type');
3555 $recurrence_parms{'recur_end_date'} = $q->param('recur_end_date');
3556 my @custom_months = $q->param('custom_months');
3557 $recurrence_parms{'custom_months'} = \@custom_months;
3558 $recurrence_parms{'recur_end_timestamp'} = 0;
3560 my %input_parms; # parms that are input by the user, but not stored as final event data
3561 $input_parms{'update_all_in_series'} = $q->param('all_in_series');
3562 $input_parms{'event_days'} = $event_days;
3563 $input_parms{'event_start_time'} = $event_start_time;
3564 $input_parms{'event_end_time'} = $event_end_time;
3565 $input_parms{'all_day'} = $all_day_event;
3567 # Check data for legitimacy.
3568 # some of these checks might be a bit redundant.
3569 if ($current_cal_id eq "") {
3570 $event_valid = 0;
3571 push @{$results{messages}}, "[error]".$lang{update_event_err3};
3573 if ($event_title eq "") {
3574 $event_valid = 0;
3575 push @{$results{messages}}, "[error]".$lang{update_event_err4};
3577 if ($event_icon eq "") {
3578 $event_valid = 0;
3579 push @{$results{messages}}, "[error]".$lang{update_event_err5};
3582 $event_title =~ s/\r//g; # some browsers sneak these in
3583 $event_details =~ s/\r//g; # some browsers sneak these in
3585 #strip html
3586 if ($event_title =~ m/<(.*)>/) {
3587 my $temp = $event_title;
3588 $temp =~ s/</&lt;/g;
3589 $temp =~ s/>/&gt;/g;
3590 push @{$results{messages}}, "[warning]".$lang{update_event_err7};
3591 $event_title =~ s/<(.*)>//g;
3594 # strip out all non-numeric information from unit number
3595 my $unit_number = $event_unit_number;
3596 $unit_number =~ s/\D//g;
3598 #check event calendar name against existing calendars
3599 if (!defined == $calendars{$current_cal_id}) {
3600 $event_valid = 0;
3601 push @{$results{messages}}, "[error]".$lang{update_event_err8};
3604 $event_valid = 0 if ($login_valid == 0 && !$options{anonymous_events});
3606 #push @{$results{messages}}, "[error]".$lang{update_event_err1}."'".$current_calendar{title}."'";
3608 # check dates
3609 if ($event_valid == 1) {
3610 my $verify_date_results = &verify_date($event_start_date);
3611 if ($verify_date_results ne "") {
3612 $event_valid = 0;
3613 my @sub_results = split("\n", $verify_date_results);
3614 foreach $sub_result (@sub_results) {
3615 push @{$results{messages}}, "[error]$lang{update_event_err9} $sub_result";
3618 if ($event_days eq "") {
3619 push @{$results{messages}}, "[error]$lang{update_event_err9}$lang{date_verify_err2}";
3622 if ($event_days =~ m/\D/ || $event_days <= 0) {
3623 my $temp = $lang{date_verify_err3};
3624 $temp =~ s/\$1/$event_days/;
3625 push @{$results{messages}}, "[error]$lang{update_event_err9}$temp";
3630 # check recurring "repeat until" date
3631 if ($event_valid == 1) {
3632 if ($recurring_event ne "" && $add_edit_event eq "add") {
3633 my $verify_date_results = &verify_date($recurrence_parms{'recur_end_date'}, \%recurrence_parms);
3634 if ($verify_date_results ne "") {
3635 $event_valid = 0;
3636 my @sub_results = split("\n", $verify_date_results);
3637 foreach $sub_result (@sub_results) {
3638 push @{$results{messages}}, "[error]$lang{update_event_err10} $sub_result";
3644 # check time
3645 if ($event_valid == 1 && $all_day_event ne "1") {
3646 my $verify_time_results = &verify_time($event_start_time);
3647 if ($verify_time_results ne "") {
3648 $event_valid = 0;
3649 my @sub_results = split("\n", $verify_time_results);
3650 foreach $sub_result (@sub_results) {
3651 push @{$results{messages}}, "[error]$lang{update_event_err14} $sub_result";
3655 if ($event_end_time ne "") {
3656 my $verify_time_results = &verify_time($event_end_time);
3657 if ($verify_time_results ne "") {
3658 $event_valid = 0;
3659 my @sub_results = split("\n", $verify_time_results);
3660 foreach $sub_result (@sub_results) {
3661 push @{$results{messages}}, "[error]$lang{update_event_err15} $sub_result";
3667 if ($event_valid == 1) {
3668 my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_calendar{date_format});
3669 $start_mon--; # convert month to 0-11 format
3671 ($event_start_timestamp, $event_end_timestamp) = &timestamp_from_datetime($start_mday,$start_mon,$start_year,$event_days,$event_start_time,$event_end_time,$all_day_event);
3673 $event_end_timestamp +=1 if ($event_start_timestamp == $event_end_timestamp); # give all events a duration of at least 1 second
3675 $event_duration = $event_end_timestamp - $event_start_timestamp;
3676 $no_end_time = 1 if ($event_duration == 1);
3678 $recurrence_parms{'duration'} = $event_duration if ($recurring_event ne "");
3680 if ($recurring_event ne "" && $add_edit_event eq "add") {
3681 my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recurrence_parms{'recur_end_date'}, $current_calendar{date_format});
3682 $recur_end_mon--;
3683 $recurrence_parms{'recur_end_timestamp'} = timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year);
3686 # display warning if start timestamp is before present date
3687 if ($event_start_timestamp < $rightnow-86400) {
3688 push @{$results{messages}}, "[warning]$lang{update_event_err11}";
3692 # check for refreshes!
3693 if ($recurring_event eq "") {
3694 my %latest_event = $events{$latest_event_id};
3696 if ($latest_event{cal_ids}[0] eq $current_cal_id &&
3697 $latest_event{start} eq $event_start_timestamp &&
3698 $latest_event{end} eq $event_end_timestamp &&
3699 $latest_event{title} eq $event_title &&
3700 $latest_event{details} eq $event_details &&
3701 $latest_event{icon} eq $event_icon &&
3702 $latest_event{bgcolor} eq $event_bgcolor &&
3703 $latest_event{unit_number} eq $event_unit_number) {
3704 $event_valid = 0;
3705 push @{$results{messages}}, "[error]$lang{update_event_err12}";
3707 } else { # recurring event refresh protection is a little trickier.
3708 # it's currently not implemented
3711 if ($add_edit_event eq "edit") {
3712 #check to make sure the event id matches some event in the data structure. It always should, but we check anyway.
3713 if (!defined $events{$event_id}) {
3714 $event_valid = 0;
3715 push @{$results{messages}}, "[error]$lang{update_event_err13}";
3719 # properly format errors & warnings
3720 $message_results="";
3722 if ($event_valid == 1) {
3723 $results{successful} = 1;
3724 #$debug_info .= "(add_update_event) event_id: $event_id\n";
3725 unshift @evt_other_cal_ids, $current_cal_id;
3727 my %new_event = (recurring => $recurring_event,
3728 cal_ids => \@evt_other_cal_ids,
3729 start => $event_start_timestamp,
3730 end => $event_end_timestamp,
3731 all_day_event => $all_day_event,
3732 days => &calculate_event_days($event_start_timestamp, $event_end_timestamp),
3733 title => $event_title,
3734 details => $event_details,
3735 icon => $event_icon,
3736 bgcolor => $event_bgcolor,
3737 block_merge => $event_block_merge,
3738 unit_number => $event_unit_number,
3739 update_timestamp => $rightnow,
3740 existing_id => $event_id,
3741 recurrence_parms => \%recurrence_parms);
3743 if ($login_valid) {
3744 $results{text} .= &commit_event(\%new_event, \%input_parms);
3745 } elsif ($options{anonymous_events}) { # anonymous event -> update queue
3746 my $new_event_id = $max_action_id + int(rand(100)); # just in case several people decide to add something new at the same time.
3747 $new_event{id} = $new_event_id;
3748 #$debug_info .= "(add_edit_events) event cal id: $event_cal_id\n";
3749 # add event to %events data structure
3750 $new_events{$new_event_id} = \%new_event;
3752 # notify email(s)
3753 if ($options{email_mode} > 0) {
3754 my $subj = $lang{notify_subj};
3755 $subj =~ s/\$1/$script_url\/$name/;
3757 my $body = $lang{event_pending_notify};
3758 $body =~ s/\$1/$events{$current_event_id}{title}/;
3759 $body =~ s/\$2/$calendars{$current_cal_id}{title}/;
3760 $body =~ s/\$3/$script_url\/$name?view_pending_event=1&pending_event_id=$new_event_id/;
3762 foreach $add_email (@{$current_calendar{add_emails}}) {
3763 push @{$results{messages}}, "[status]email notification sent to $add_email";
3764 &send_email($add_email, $options{reply_address}, $options{reply_address}, $subj, $body);
3768 &add_action($new_event_id, "new_event");
3769 $event_box_text .= &generate_event_details(\%new_event);
3771 $results{text} .= <<p1;
3772 <p style="font-weight:bold;">$lang{update_event_add_pending_successful}</p>
3773 $event_box_text
3774 <ul>
3775 <li><a href="$script_url/$name?active_tab=1">$lang{update_event_add_successful_add_new}</a></li>
3776 </ul>
3782 return \%results;
3784 } #******************** end add_edit_event *****************************
3787 sub commit_event() { # commit an add or update of an event
3788 my ($new_event_ref, $input_parms_ref) = @_;
3790 my $messages = "";
3791 my $new_event_id;
3793 my %new_event = %{$new_event_ref};
3794 my %input_parms = %{$input_parms_ref};
3796 unless ($loaded_all_events eq "1") {
3797 &load_events("all");
3798 &normalize_timezone();
3801 if ($add_edit_event eq "add") { # add a new event
3802 if ($new_event{'recurring'} eq "") {
3803 my $event_box_text = "";
3804 $new_event_id = ++$max_event_id;
3806 $events{$new_event_id} = deep_copy(\%new_event);
3807 $events{$new_event_id}{id} = $new_event_id;
3809 &add_event($new_event_id);
3810 $event_box_text .= &generate_event_details($events{$new_event_id});
3812 #temporarily offset event times by calendar gmtime diff
3814 $messages .= <<p1;
3815 <p style="font-weight:bold;">$lang{update_event_add_successful}</p>
3816 $event_box_text
3817 <ul>
3818 <li><a href="$script_url/$name?active_tab=1">$lang{update_event_add_successful_add_new}</a></li>
3819 </ul>
3821 } else { # recurring events loop
3822 #$debug_info .= "in commit_event recurring events loop!\n";
3823 my %recurrence_parms = %{$new_event{'recurrence_parms'}};
3825 my $new_series_id = ++$max_series_id;
3827 my $date_text = "";
3829 my @recurring_events_timestamps = @{&calculate_recurring_events($new_event{'start'}, \%recurrence_parms)};
3831 my @recurring_event_ids = ();
3832 foreach $recurring_event_start_timestamp (@recurring_events_timestamps) {
3833 my $new_event_id = ++$max_event_id;
3834 my $recurring_event_end_timestamp = $recurring_event_start_timestamp + $recurrence_parms{'duration'};
3836 $events{$new_event_id} = deep_copy(\%new_event);
3837 $events{$new_event_id}{id} = $new_event_id;
3838 $events{$new_event_id}{series_id} = $new_series_id;
3839 $events{$new_event_id}{start} = $recurring_event_start_timestamp;
3840 $events{$new_event_id}{end} = $recurring_event_end_timestamp;
3841 $events{$new_event_id}{recurrence_parms} = [];
3843 push @recurring_event_ids, $new_event_id;
3845 my $date_range = &nice_date_range_format($recurring_event_start_timestamp, $recurring_event_end_timestamp, "-");
3847 $date_text .= <<p1;
3848 <li>$date_range</li>
3852 &add_events(\@recurring_event_ids);
3854 $event_box_text .= &generate_event_details($events{$max_event_id});
3856 $messages .= <<p1;
3857 <p style="font-weight:bold;">$lang{update_event_add_successful_recurring}</p>
3858 <ul>
3859 $date_text
3860 </ul>
3861 $event_box_text
3862 <ul>
3863 <li><a href="$script_url/$name?active_tab=1">$lang{update_event_add_successful_add_new}</a></li>
3864 <li><a href="$script_url/$name?active_tab=0">$lang{update_event_back_to_calendar}</a></li>
3865 </ul>
3868 if ($options{email_mode} > 0) {
3869 my $subj = $lang{notify_subj};
3870 $subj =~ s/\$1/$script_url\/$name/;
3872 my $body = $lang{event_add_notify};
3873 $body =~ s/\$1/$new_event{title}/;
3874 $body =~ s/\$2/$calendars{$current_cal_id}{title}/;
3875 $body =~ s/\$3/$script_url\/$name?view_event=1&evt_id=$max_event_id/;
3877 foreach $add_email (@{$current_calendar{add_emails}}) {
3878 push @{$results{messages}}, "[status]email notification sent to $add_email";
3879 &send_email($add_email, $options{reply_address}, $options{reply_address}, $subj, $body);
3882 } elsif ($add_edit_event eq "edit") { #if we need to replace an existing record
3883 my $event_id = $new_event{'existing_id'};
3885 if ($new_event{'recurring'} eq "" || $input_parms{'update_all_in_series'} ne "1") {
3886 $events{$event_id} = deep_copy(\%new_event);
3887 $events{$event_id}{id} = $event_id;
3889 &update_event($event_id);
3891 $event_box_text .= &generate_event_details($events{$event_id});
3893 $messages .= <<p1;
3894 <p style="font-weight:bold;">$lang{update_event_update_successful}</p>
3896 } else { # update recurring events
3897 # get the ids of the events in the series.
3898 my @events_in_series;
3899 foreach $event_id (keys %events) {
3900 my %event = %{$events{$event_id}};
3901 my $series_id = $event{series_id};
3902 if ($series_id eq $q->param('series_id')) {
3903 push @events_in_series, $event_id;
3904 my @temp = gmtime($event{end});
3906 ($recurring_event_start_timestamp, $recurring_event_end_timestamp) = &timestamp_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'});
3908 $events{$event_id} = deep_copy(\%new_event);
3909 $events{$event_id}{id} = $event_id;
3910 $events{$event_id}{series_id} = $series_id;
3911 $events{$event_id}{start} = $recurring_event_start_timestamp;
3912 $events{$event_id}{end} = $recurring_event_end_timestamp;
3913 $events{$event_id}{recurrence_parms} = [];
3916 &update_events(\@events_in_series);
3918 $messages .= <<p1;
3919 <p style="font-weight:bold;">$lang{update_event_update_successful_recurring}</p>
3923 if ($options{email_mode} > 0) {
3924 my $subj = $lang{notify_subj};
3925 $subj =~ s/\$1/$script_url\/$name/;
3927 my $body = "";
3928 $body = $lang{event_update_notify};
3929 $body =~ s/\$1/$new_event{title}/;
3930 $body =~ s/\$2/$calendars{$current_cal_id}{title}/;
3931 $body =~ s/\$3/$script_url\/$name?view_event=1&evt_id=$event_id/;
3933 foreach $email (@{$current_calendar{update_emails}}) {
3934 $debug_info .= "email notification sent to $email\n";
3935 &send_email($email, $options{reply_address}, $options{reply_address}, $subj, $body);
3940 return $messages;
3947 sub common_javascript {
3948 my $logged_in_boolean = ($logged_in) ? "true":"false";
3949 my $date_format = lc $current_calendar{date_format};
3950 $return_string .=<<p1;
3951 info_window_width = $info_window_width;
3952 info_window_height = $info_window_height;
3954 plans_url = '$script_url/$name';
3955 theme_url = '$theme_url';
3956 css_path = '$css_path';
3957 date_format = '$date_format';
3958 current_calendar_id = '$current_calendar{id}';
3959 logged_in = $logged_in_boolean;
3961 if (window.name == "")
3962 window.name="cal_mainwindow";
3964 var main_window_name = window.name
3966 plans_options['right_click_menus_enabled'] = $options{right_click_menus_enabled};
3967 plans_options['disable_passwords'] = $options{disable_passwords};
3968 plans_options['sessions'] = $options{sessions};
3971 return $return_string;
3972 } #********************end common_javascript **********************
3975 sub calendar_view_javascript {
3976 my ($events_start_timestamp, $events_end_timestamp) = @_;
3977 my $return_string="";
3979 # generate pre-formatted html for each event details pop-up on the
3980 # current calendar. This routine is a good example of one of the choices
3981 # made in the design of this site--gaining client-side processor cycles
3982 # at the expense of bandwidth. It would be possible to send the event details
3983 # in a javascript array or hash, and have the client's browser dynamically
3984 # genearate the appropriate html. But it should be much faster to perform
3985 # this operation on the server and simply ship html to the client. The idea is
3986 # to make the javascript processing as simple as possible, becuase javascript
3987 # is sloooow. And even with all that extra html text, each page should still be
3988 # less than 100k (not counting images)
3990 #generate pre-formatted html for each event view
3991 $return_string .= &generate_event_details_javascript($events_start_timestamp, $events_end_timestamp);
3994 $return_string .=<<p1;
3996 function custom_calendar() {
3998 var info_window_x = window_x()-400;
3999 var info_window_y = window_y();
4002 $custom_form_text .=<<p1;
4003 <div class="cal_title">
4004 $lang{custom_calendar_title}
4005 </div>
4007 <form action="$script_url/$name" method="POST">
4008 <input type="hidden" name="custom_calendar" value="1">
4010 <label for="custom_calendar_calendar" class="required_field">
4011 $lang{custom_calendar_choose_calendar}
4012 </label>
4013 <br/>
4014 <select id="custom_calendar_calendar" name="custom_calendar_calendar">
4017 foreach $cal_id (sort {$a <=> $b} keys %calendars) {
4018 $custom_form_text .=<<p1;
4019 <option value = "$cal_id">$calendars{$cal_id}{title}
4023 $custom_form_text .=<<p1;
4024 </select>
4025 <br/><br/>
4026 <label for="custom_calendar_background_calendars" class="optional_field">
4027 $lang{custom_calendar_choose_bg_calendar}
4028 </label>
4029 <br/>
4031 <select id="custom_calendar_background_calendars" name="custom_calendar_background_calendars" multiple size=6>
4034 foreach $cal_id (sort {$a <=> $b} keys %calendars) {
4035 $custom_form_text .=<<p1;
4036 <option value = "$cal_id">$calendars{$cal_id}{title}
4040 $custom_form_text .=<<p1;
4041 </select>
4042 <br/><br/>
4045 if ($display_type == 1) {$list_selected = "selected";} else {$cal_selected = "selected";}
4047 $custom_form_text .=<<p1;
4048 <label for="display_type" class="required_field">
4049 $lang{custom_calendar_display_type}
4050 </label>
4051 <select name="display_type" onChange="blink('controls_submit_button', 3, 0);">
4054 #foreach $possible_display_type (@{$options{display_types}})
4055 for (my $l1=0;$l1<scalar @{$options{display_types}};$l1++) {
4056 if ($options{display_types}[$l1] ne "1") {
4057 next};
4058 my $selected="";
4060 if ($l1 eq $display_type) {
4061 $selected = "selected";}
4063 $custom_form_text .=<<p1;
4064 <option value="$l1" $selected>$lang{controls_display_type}[$l1]
4067 $custom_form_text .=<<p1;
4068 </select>
4069 <br/><br/>
4071 <label for="cal_start_month" class="required_field">
4072 $lang{custom_calendar_time_range}
4073 </label>
4075 <table class="layout" summary="">
4076 <tr><td nowrap align=right>
4078 $lang{controls_start_month}
4079 </td><td nowrap>
4080 <select id="cal_start_month" name="cal_start_month">
4082 #list each month in the year
4083 $month_index=0;
4084 foreach $possible_month (@months) {
4085 if ($cal_start_month eq $month_index) {
4086 $custom_form_text .=<<p1;
4087 <option value="$month_index" selected>$possible_month
4089 } else {
4090 $custom_form_text .=<<p1;
4091 <option value="$month_index">$possible_month
4094 $month_index++;
4096 $custom_form_text .=<<p1;
4097 </select>
4098 <input name="cal_start_year" value = "$cal_start_year" size=4>
4099 </td></tr>
4100 <tr><td nowrap align=left colspan=2>
4102 $lang{controls_num_months}
4103 <input name="cal_num_months" value = "$cal_num_months" size=3>
4105 </td></tr>
4106 </table>
4107 <br/><br/>
4109 <input type=submit value = "$lang{custom_calendar_make_calendar}">
4111 $custom_form_text =~ s/\//\\\//g;
4112 $custom_form_text =~ s/\n/\\n/g;
4113 $custom_form_text =~ s/"/\\"/g;
4115 $return_string .=<<p1;
4116 info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=400,height=500");
4117 doc = info_window.document;
4118 doc.open('text/html');
4119 doc.write('<html>');
4120 doc.write('<title>$lang{custom_calendar_title}<\\/title>');
4121 doc.write('<base target=\\"'+main_window_name+'\\">');
4122 doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
4123 doc.write('<body>');
4124 doc.write("$custom_form_text");
4125 doc.write('<\\/body><\\/html>');
4126 doc.close();
4127 info_window.focus();
4131 return $return_string;
4132 } #***********************end calendar_view_javascript************************"
4138 sub add_edit_events_javascript {
4139 $return_string="";
4141 $return_string.=<<p1;
4142 var info_window_x = window_x()-$info_window_width;
4143 var info_window_y = window_y();
4145 // color select stuff
4146 var cs0;
4148 function color_menu0_update(new_color) {
4149 //window.status = "updating! " + new_color;
4150 document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.options.length-1].value = new_color;
4151 document.add_event_form.evt_bgcolor.style.background = new_color;
4152 document.add_event_form.evt_bgcolor.style.color = compatible_textcolor(new_color);
4153 document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.options.length-1].style.color = compatible_textcolor(new_color);
4155 document.getElementById("custom_evt_color").style.background = new_color;
4158 function do_on_load() {
4159 if (!document.add_event_form || !document.add_event_form.evt_bgcolor)
4160 return;
4162 // color select control
4163 cs0 = new color_select('cs0',document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].value);
4165 cs0.change_update_function = "color_menu0_update"; // NOTE-there are no ()
4166 cs0.hide_update_function = "color_menu0_update"; // NOTE-there are no ()
4167 cs0.attach_to_element(document.getElementById("color_select_icon0"));
4168 cs0.setrgb("$current_event{bgcolor}");
4169 cs0.update_color_box();
4171 for (i=0; i<document.add_event_form.evt_bgcolor.options.length; i++) {
4172 document.add_event_form.evt_bgcolor[i].style.background = document.add_event_form.evt_bgcolor[i].value;
4173 document.add_event_form.evt_bgcolor[i].style.color = compatible_textcolor(document.add_event_form.evt_bgcolor[i].value);
4176 // for some reason, calling this immediately doesn't always work - even if it's called after the page is loaded.
4177 // so, a 200 ms delay.
4178 setTimeout('update_bg_color_select_box()', 200);
4183 function update_bg_color_select_box() {
4184 var add_event_form = document.getElementById("add_event_form");
4186 // did the user just select custom?
4187 if (document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].text == "custom")
4188 document.getElementById("color_select_icon0").style.visibility = "visible";
4189 else
4190 document.getElementById("color_select_icon0").style.visibility = "hidden";
4192 // take focus off the select (in IE, making a selection highlights it in blue, so you cannot see the actual color you picked. Removing focus makes this go away)
4193 document.add_event_form.dummy.style.display='inline';
4194 document.add_event_form.dummy.select();
4195 document.add_event_form.dummy.style.display='none';
4197 //if (!add_event_form.evt_bgcolor)
4198 // return;
4200 //alert(add_event_form.evt_bgcolor[add_event_form.evt_bgcolor.selectedIndex].value);
4202 add_event_form.evt_bgcolor.style.background = add_event_form.evt_bgcolor[add_event_form.evt_bgcolor.selectedIndex].value
4203 //document.add_event_form.evt_title.select();
4205 add_event_form.evt_bgcolor.style.color = compatible_textcolor(add_event_form.evt_bgcolor[add_event_form.evt_bgcolor.selectedIndex].value);
4209 function update_preview_icon() {
4210 var icon_preview_area = document.getElementById("icon_preview")
4212 icon_name = document.add_event_form.evt_icon.options[document.add_event_form.evt_icon.selectedIndex].value
4213 icon_preview_area.innerHTML = "<img src=\\"$icons_url/" + icon_name + "_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>"
4215 if (!document.add_event_form.unit_number)
4216 return;
4218 var unit_number_preview_area = document.getElementById("unit_number_preview")
4220 // remove non-numeric text from the string
4221 var unit_number = document.add_event_form.unit_number.value;
4222 unit_number = unit_number.replace(/[^0-9]/g, "");
4224 // this next part might be really clever or really stupid (using a regex for something like this).
4225 // regardless, it's only one line, and that's nice.
4226 var unit_number_graphic_string = unit_number.replace(/([0-9])/g, "<img src=\\"$graphics_url/unit_number_patch_\$1_20x13.gif\\" border=\\"0\\" vspace=0 hspace=0>");
4227 unit_number_preview_area.innerHTML = unit_number_graphic_string;
4228 document.add_event_form.unit_number.value = unit_number;
4230 // it would be nice if we could do things with the DOM model, as opposed to innerHTML, but
4231 // that would be crazy cumbersome. The following is a non-working stab at it. Maybe useful someday.
4232 //preview_area.nodeValue = "unit num";
4233 //preview_area.appendChild(document.createTextNode("unit <img name=\\"event_icon\\" src=\\"$icons_url/eagle_medal_32x32.gif\\" border=\\"0\\" vspace=0 hspace=0>"));
4238 function all_day_event_toggle(value) {
4239 var el0 = document.getElementById("all_day_event_toggle0");
4240 el0.style.display="";
4242 if (value)
4243 el0.style.display="none";
4247 function preview_event() {
4248 info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,width=300,height=200");
4249 doc = info_window.document;
4250 doc.open('text/html');
4251 doc.write('<html>');
4252 doc.write('<title>$lang{event_preview_title}<\\/title>');
4253 doc.write('<body bgcolor=\\"#ffffff\\" style=\\"font-family:arial,helvetica\\">');
4254 doc.write('<font size=5><font color=\\"0049df\\">$lang{generating_preview}<\\/font>');
4255 doc.write('<\\/body><\\/html>');
4256 doc.close();
4258 document.add_event_form.special_action.value = "preview_event";
4259 document.add_event_form.target = "info_window";
4260 document.add_event_form.submit();
4261 document.add_event_form.special_action.value = "";
4262 document.add_event_form.target = "";
4264 info_window.focus();
4268 function recur_edit_toggle() {
4269 if (document.add_event_form.all_in_series.checked) {
4270 document.add_event_form.add_event_button.value="$lang{recurring_event_update_all1}";
4271 document.add_event_form.del_event_button.value="$lang{recurring_event_delete_all1}";
4272 } else {
4273 document.add_event_form.add_event_button.value="$lang{update_event}";
4274 document.add_event_form.del_event_button.value="$lang{delete_event1}";
4279 function preview_dates() {
4280 var i = 0;
4281 var j = 0;
4282 var info_window_x = window_x()-$info_window_width;
4283 var info_window_y = window_y();
4285 var evt_start_date = document.add_event_form.evt_start_date.value;
4286 var evt_days = document.add_event_form.evt_days.value;
4287 var evt_start_time = document.add_event_form.evt_start_time.value;
4288 var evt_end_time = document.add_event_form.evt_end_time.value;;
4289 var recurring_event = "";
4290 var every_x_days;
4291 var every_x_weeks;
4292 var recur_end_date;
4293 var recurrence_type = "";
4294 var year_fit_type = "";
4295 var weekday_of_month_type = "";
4296 var custom_months_string = "";
4298 if (document.add_event_form.recur_end_date) {
4299 every_x_days = document.add_event_form.every_x_days.value;
4300 every_x_weeks = document.add_event_form.every_x_weeks.value;
4301 recur_end_date = document.add_event_form.recur_end_date.value;
4303 if (document.add_event_form.recurring_event.checked)
4304 recurring_event = document.add_event_form.recurring_event.value;
4306 for (i=0; i<document.add_event_form.recurrence_type.length; i++)
4307 if (document.add_event_form.recurrence_type[i].checked)
4308 recurrence_type = document.add_event_form.recurrence_type[i].value;
4310 for (i=0; i<document.add_event_form.year_fit_type.length; i++)
4311 if (document.add_event_form.year_fit_type[i].checked)
4312 year_fit_type = document.add_event_form.year_fit_type[i].value;
4314 if (document.add_event_form.weekday_of_month_type.selectedIndex > -1)
4315 weekday_of_month_type = document.add_event_form.weekday_of_month_type.options[document.add_event_form.weekday_of_month_type.selectedIndex].value
4317 var selects = new Array();
4318 var custom_months = "";
4320 if (document.add_event_form.custom_months.selectedIndex > -1)
4321 for (j=0, i=document.add_event_form.custom_months.selectedIndex; i<document.add_event_form.custom_months.options.length;i++)
4322 if (document.add_event_form.custom_months.options[i].selected)
4323 custom_months_string +="&amp;custom_months="+document.add_event_form.custom_months.options[i].value;
4327 var URL_string="$script_url/$name?special_action=preview_date&amp;evt_start_date="+evt_start_date+
4328 "&amp;cal_id="+document.add_event_form.cal_id.value+
4329 "&amp;recur_end_date="+recur_end_date+
4330 "&amp;recurring_event="+recurring_event+
4331 "&amp;recurrence_type="+recurrence_type+
4332 "&amp;year_fit_type="+year_fit_type+
4333 "&amp;every_x_days="+every_x_days+
4334 "&amp;every_x_weeks="+every_x_weeks+
4335 "&amp;evt_start_time="+evt_start_time+
4336 "&amp;evt_start_time="+evt_start_time+
4337 "&amp;weekday_of_month_type="+weekday_of_month_type+
4338 custom_months_string+
4339 "&amp;evt_days="+evt_days;
4341 info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height");
4342 doc = info_window.document;
4343 doc.open('text/html');
4344 doc.write('<html>');
4345 doc.write('<head>');
4346 doc.write('<title>$lang{event_preview_computing}<\\/title>');
4347 doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
4348 doc.write('<\\/head>');
4349 doc.write('<body style=\\"font-family:arial;\\">');
4350 doc.write('$lang{event_preview_computing}');
4351 doc.write('<\\/body><\\/html>');
4352 doc.close();
4354 info_window = this.open(URL_string, "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width=$info_window_width,height=$info_window_height");
4355 info_window.focus();
4360 my @help_text_map = ("evt_cal_id",
4361 "evt_title",
4362 "evt_details",
4363 "help_evt_details",
4364 "recurring_event",
4365 "recurrence_type",
4366 "fit_into_year",
4367 "cal_password",
4368 "recurring_event_change_all");
4370 my $help_text_javascript = "";
4371 foreach $key (@help_text_map) {
4372 my $help_text=<<p1;
4373 <div class="help_box">
4374 $lang{'help_'.$key}
4375 </div>
4377 $help_text =~ s/\n/\\n/g;
4378 $help_text =~ s/"/\\"/g;
4379 $help_text =~ s/'/\\'/g;
4380 $help_text =~ s/\//\\\//g;
4383 $help_text_javascript .=<<p1;
4384 if (topic == "$key")
4385 help_text += "$help_text";
4390 $return_string .=<<p1;
4391 function display_help(topic, title) {
4392 help_text = "";
4393 $help_text_javascript
4394 if (help_text != "") {
4395 help_text = "<div class=\\"help_title\\">$lang{help_box_title} - "+title+"</div>" + help_text;
4396 show_help();
4402 return $return_string
4403 } #********************end add_edit_events_javascript**********************
4408 sub generate_users_javascript() {
4409 my ($cal_id) = @_;
4410 my $results = "";
4411 foreach $user_id (keys %users) {
4412 my $valid_for_current_calendar = 0;
4414 foreach $cal_id (keys %{$users{$user_id}{calendars}}) {
4415 if ($cal_id eq $current_cal_id) {
4416 $valid_for_current_calendar = 1;
4417 last;
4421 next if ($valid_for_current_calendar == 0);
4422 #next if ($user_id eq "");
4424 my %user = %{$users{$user_id}};
4425 $results .=<<p1;
4426 users['$user_id'] = new User('$user_id','$user{name}');
4429 return $results;
4432 sub generate_pending_events_javascript() {
4433 my $results = "";
4434 foreach $pending_event_id (sort {$new_events{$a}{update_timestamp} <=> $new_events{$b}{update_timestamp}} @pending_events_to_display) {
4435 my %pending_event = %{$new_events{$pending_event_id}};
4436 my $title = $pending_event{title};
4437 $title = &javascript_cleanup($title);
4439 $results .=<<p1;
4440 pending_events['$pending_event_id'] = new Event({'id':'$pending_event_id', 'title':'$title', 'icon':'$pending_event{icon}', 'start':$pending_event{start}, 'end':$pending_event{end}, 'timestamp':$pending_event{update_timestamp}});
4443 return $results."\n";
4448 sub add_edit_calendars_javascript {
4449 my $return_string = "";
4451 $return_string .= &generate_users_javascript($current_calendar{id});
4453 $return_string.=<<p1;
4454 // override generic do_on_load method from plans.js
4455 function do_on_load() {
4456 update_remote_calendar_requests();
4457 update_cal_color_select_box();
4458 list_users();
4460 if (document.getElementById("color_select_icon0")) {
4461 // color select controls
4462 cs0 = new color_select('cs0');
4463 cs0.change_update_function = "color_menu0_update"; // NOTE-there are no ()
4464 cs0.hide_update_function = "color_menu0_update"; // NOTE-there are no ()
4465 cs0.attach_to_element(document.getElementById("color_select_icon0"));
4466 cs0.setrgb("$current_event{bgcolor}");
4467 cs0.update_color_box();
4469 cs1 = new color_select('cs1');
4470 cs1.change_update_function = "color_menu1_update"; // NOTE-there are no ()
4471 cs1.hide_update_function = "color_menu1_update"; // NOTE-there are no ()
4472 cs1.attach_to_element(document.getElementById("color_select_icon1"));
4473 cs1.setrgb("$current_event{bgcolor}");
4474 cs1.update_color_box();
4479 function update_users() {
4480 if (!users || users.length == 0) return;
4485 function set_merge_xml(merge_xml) {
4486 var results = merge_xml.match(/\\/remote_calendar>/g);
4487 //var num_merged_calendars = results.length;
4489 if (results)
4490 if (results.length > 1)
4491 document.getElementById("remote_background_calendars_status").innerHTML = results.length + " $lang{get_remote_calendar2_plural} $current_calendar{title}<br/>"; else
4492 document.getElementById("remote_background_calendars_status").innerHTML = results.length + " $lang{get_remote_calendar2_singular} $current_calendar{title}<br/>";
4493 else
4494 document.getElementById("remote_background_calendars_status").innerHTML = "$lang{get_remote_calendar3}";
4496 //for(var i =0; i < results.length; i++)
4497 // document.getElementById("remote_background_calendars_status").innerHTML +="calendar "+i+"<br/>";
4500 document.update_cal_form.new_remote_calandars_xml.value = merge_xml;
4501 //alert (num_merged_calendars +" new calendars to merge!")
4502 //alert(merge_xml);
4508 my $popup_javascript_info = "";
4509 if ($browser_type eq "IE") {
4510 $popup_javascript_info .=<<p1;
4511 <script type="text/javascript" ><!--
4512 function do_onresize() {
4513 opener.info_window_width = document.body.clientWidth;
4514 opener.info_window_height = document.body.clientHeight;
4516 //-->
4517 </script>
4519 } else {
4520 $popup_javascript_info .=<<p1;
4521 <script type="text/javascript" ><!--
4522 function do_onresize() {
4523 opener.info_window_width = this.outerWidth;
4524 opener.info_window_height = this.outerHeight;
4526 //-->
4527 </script>
4531 $popup_javascript_info =~ s/\n/\\n/g;
4532 $popup_javascript_info =~ s/"/\\"/g;
4533 $popup_javascript_info =~ s/\//\\\//g;
4536 my $get_remote_calendars_html =<<p1;
4537 <br/>
4538 <form name="detect_remote_calendars" action="$script_url/$name" method="POST">
4539 <input type="hidden" name="detect_remote_calendars" value="1"/>
4540 $lang{get_remote_calendars_url}<br/>
4541 <input name="remote_calendar_url" value="http://" style="width:90%;">
4542 <br/>
4543 <input type="submit" value="Go!" style="width:5em;">
4544 </form>
4546 $get_remote_calendars_html =~ s/\n/\\n/g;
4547 $get_remote_calendars_html =~ s/"/\\"/g;
4548 $get_remote_calendars_html =~ s/\//\\\//g;
4550 $return_string.=<<p1;
4551 function get_remote_calendars() {
4552 info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
4554 doc = info_window.document;
4555 doc.open('text/html');
4556 doc.write('<html>');
4557 doc.write('<title>$lang{get_remote_calendars}<\\/title>');
4558 doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
4559 doc.write('$popup_javascript_info');
4560 doc.write('<body onResize=\\"javascript:do_onresize()\\">');
4561 doc.write("<div class=\\"info_box\\" style=\\"padding:5px;\\"><br\\/>");
4562 doc.write('$get_remote_calendars_html');
4563 doc.write("<\\/div>");
4564 doc.write('<\\/body><\\/html>');
4565 doc.close();
4566 info_window.focus();
4571 // color select stuff
4572 var cs0 = new color_select();
4573 cs0.setrgb("$current_calendar{background_events_color}");
4575 var cs1 = new color_select();
4576 cs1.setrgb("$current_calendar{calendar_events_color}");
4579 function color_menu0_update(new_color) {
4580 if (document.update_cal_form.background_events_display_style2.checked) {
4581 document.update_cal_form.background_events_color.value = new_color;
4582 document.getElementById("bg_preview_e1").style.background = new_color;
4583 document.getElementById("bg_preview_e2").style.background = new_color;
4587 function color_menu1_update(new_color) {
4588 //if (new_color == "#000000") return;
4589 if (document.getElementById("color_select_icon1").style.visibility != "visible") return;
4591 document.update_cal_form.calendar_events_color[document.update_cal_form.calendar_events_color.options.length-1].value = new_color;
4592 document.update_cal_form.calendar_events_color.style.background = new_color;
4593 document.getElementById("custom_evt_color").style.background = new_color;
4594 document.getElementById("preview_e1").style.background = new_color;
4595 document.getElementById("preview_e2").style.background = new_color;
4599 function update_cal_color_select_box() {
4600 if (!document.update_cal_form) return;
4601 if (!document.update_cal_form.calendar_events_color) return;
4603 var current_color = document.update_cal_form.calendar_events_color[document.update_cal_form.calendar_events_color.selectedIndex].value;
4605 if (current_color == "") {
4606 document.getElementById('preview_e1').style.background = '#ffffcc';
4607 document.getElementById('preview_e2').style.background = '#ccffcc';
4608 document.getElementById("color_select_icon1").style.visibility = "hidden";
4609 document.update_cal_form.calendar_events_color.style.background = "#ffffff";
4610 return;
4613 if (document.update_cal_form.calendar_events_color.selectedIndex == document.update_cal_form.calendar_events_color.options.length-1) {
4614 document.getElementById("color_select_icon1").style.visibility = "visible";
4616 var current_custom_color = document.getElementById("custom_evt_color").value;
4617 document.getElementById("preview_e1").style.background = current_custom_color;
4618 document.getElementById("preview_e2").style.background = current_custom_color;
4619 document.update_cal_form.calendar_events_color.style.background = current_custom_color;
4620 return;
4621 } else {
4622 cs1.setrgb(current_color);
4624 document.getElementById("color_select_icon1").style.visibility = "hidden";
4625 document.getElementById("preview_e1").style.background = current_color;
4626 document.getElementById("preview_e2").style.background = current_color;
4627 document.update_cal_form.calendar_events_color.style.background = current_color;
4629 // take focus off the select (in IE, making a selection highlights it in blue, so you cannot see the actual color you picked. Removing focus makes this go away)
4630 document.update_cal_form.dummy.style.display='inline';
4631 document.update_cal_form.dummy.select();
4632 document.update_cal_form.dummy.style.display='none';
4635 //document.add_event_form.evt_bgcolor.style.background = document.add_event_form.evt_bgcolor[document.add_event_form.evt_bgcolor.selectedIndex].value
4638 //document.update_cal_form.evt_title.select();
4641 // end color_select stuff
4644 $return_string.=<<p1;
4645 var info_window_x = window_x()-$info_window_width;
4646 var info_window_y = window_y() + 200;
4648 function show_help() {
4649 info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
4651 doc = info_window.document;
4652 doc.open('text/html');
4653 doc.write('<html>');
4654 doc.write('<title>$lang{help_box_title}<\\/title>');
4655 doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
4656 doc.write('$popup_javascript_info');
4658 doc.write('<body onResize=\\"javascript:do_onresize()\\">');
4659 doc.write(help_text);
4660 doc.write('<\\/body><\\/html>');
4661 doc.close();
4662 info_window.focus();
4665 function preview_cal() {
4666 var cal_title = document.update_cal_form.cal_title.value
4667 var cal_link = document.update_cal_form.cal_link.value
4668 var cal_details = document.update_cal_form.cal_details.value;
4670 if (cal_title == "") {
4671 evt_label = "<span style=\\"color:#ff0000\\">$lang{preview_calendar_temp_title}<\\/span>";
4672 add_disable = true;
4676 if (document.getElementById("preview_warning")) {
4677 document.getElementById("preview_warning").innerHTML="";
4680 info_window = this.open("", "info_window", "resizable=yes,status=yes,scrollbars=yes,top="+info_window_y+",left="+info_window_x+",width="+info_window_width+",height="+info_window_height);
4682 doc = info_window.document;
4683 doc.open('text/html');
4684 doc.write('<html>');
4685 doc.write('<title>$lang{preview_calendar_title}<\\/title>');
4686 doc.write('<link rel=\\"stylesheet\\" href=\\"$css_path\\" type=\\"text/css\\" media=screen>');
4687 doc.write('$popup_javascript_info');
4689 doc.write('<body onResize=\\"javascript:do_onresize()\\">');
4690 doc.write("<div class=\\"info_box\\" style=\\"padding:5px;\\"><br/><div style=\\"white-space:nowrap;\\"><span class=\\"cal_title\\">");
4691 doc.write("<a target=\\"_blank\\" href=\\""+cal_link+"\\">"+cal_title+"<\\/a><\\/span><\\/div><br/><div>"+cal_details+"<\\/div><\\/div>");
4692 doc.write('<\\/body><\\/html>');
4693 doc.close();
4694 info_window.focus();
4698 my @help_text_map = ("title",
4699 "link",
4700 "details",
4701 "password",
4702 "new_password",
4703 "current_password",
4704 "change_password",
4705 "selectable_calendars",
4706 "background_calendars",
4707 "remote_background_calendars",
4708 "background_events_display_style",
4709 "events_display_style",
4710 "list_background_calendars_together",
4711 "default_number_of_months",
4712 "max_months",
4713 "gmtime_diff",
4714 "date_format",
4715 "week_start_day",
4716 "new_calendars_automatically_selectable",
4717 "allow_remote_calendar_requests",
4718 "remote_calendar_requests_password",
4719 "event_change_email",
4720 "popup_window_size",
4721 "custom_stylesheet",
4722 "custom_template",
4723 "add_user",
4724 "add_new_ical");
4726 my $help_text_javascript = "";
4727 foreach $key (@help_text_map) {
4728 my $help_text=<<p1;
4729 <div class="help_box">
4730 $lang{'help_cal_'.$key}
4731 </div>
4733 $help_text =~ s/\n/\\n/g;
4734 $help_text =~ s/"/\\"/g;
4735 $help_text =~ s/'/\\'/g;
4736 $help_text =~ s/\//\\\//g;
4737 $help_text =~ s/###css file###/$css_path/g;
4739 $help_text_javascript .=<<p1;
4740 if (topic == "$key")
4741 help_text += "$help_text";
4745 $return_string .=<<p1;
4746 function display_help(topic, title) {
4747 help_text = "";
4748 $help_text_javascript
4749 if (help_text != "") {
4750 help_text = "<div class=\\"help_title\\">$lang{help_box_title} - "+title+"</div>" + help_text;
4751 show_help();
4757 return $return_string
4758 } #********************end add_edit_calendars_javascript**********************
4761 sub generate_cal_details()
4763 my ($calendar_ref) = @_;
4765 my %calendar = %{$calendar_ref};
4767 my $results = <<p1;
4768 <div class="cal_title">
4769 $calendar{title}
4770 </div>
4772 <div>
4773 $calendar{details}
4774 </div>
4777 $writable{calendar_file} and $return_text .= <<p1;
4778 <div style="white-space:nowrap;">
4779 <span class="small_note">
4780 <a href="$script_url/$name?active_tab=2&amp;add_edit_cal_action=edit&amp;cal_id=$calendar{id}">$lang{calendar_add_edit}</a>
4781 </span>
4782 </div>
4785 $return_text .= <<p1;
4786 <div style="white-space:nowrap;margin-top:2em;">
4787 <span class="small_note">
4788 $lang{calendar_direct_link}<br/>
4789 <a href="$script_url/$name?cal_id=$calendar{id}">$script_url/$name?cal_id=$calendar{id}</a>
4790 </span>
4791 </div>
4794 return $results;
4799 sub render_calendar {
4800 my $return_text = "";
4801 my $week_events = {};
4802 my $week_slots = {};
4803 my $debug = 0;
4804 my @debug_events = ("105");
4806 my $show_month_breaks = ($cal_num_months > 1 && $options{continuous_multimonth} ne '1' ? 1 : 0);
4808 my $cal_month_idx = 0;
4809 my $last_cal_month;
4810 my $is_first_cal_date = 1;
4811 my @use_other_month = (0, 1);
4813 my ($cal_start_month, $cal_start_year, $cal_end_month, $cal_end_year, $selected_events) = @_;
4814 #initialize loop variables
4815 my $cal_start_timestamp = timegm(0,0,0,1,$cal_start_month,$cal_start_year);
4816 my $cal_end_timestamp = find_end_of_month($cal_end_month, $cal_end_year);
4818 my $current_month = $cal_start_month;
4819 my $current_year = $cal_start_year;
4821 while ($current_year < $cal_end_year || ($current_year == $cal_end_year && $current_month <= $cal_end_month)) {
4822 $last_cal_month = ($current_year * 100 + $current_month) == ($cal_end_year * 100 + $cal_end_month);
4824 foreach $key (keys %week_events) {delete $week_events{$key};}
4825 foreach $key (keys %week_slots) {delete $week_slots{$key};}
4827 #for calendars with multiple months, display the name of each month above the calendar
4828 if ($show_month_breaks) {
4829 $return_text .=<<p1;
4830 <p class="cal_month_title" style="padding:5px;">
4831 $months[$current_month] $current_year
4832 </p>
4835 #calculate where to start the calendar (first sunday)
4836 #first, calculate what day of the week this month begins on
4838 #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
4840 my $cal_month_start_date = timegm(0,0,0,1, $current_month, $current_year);
4841 my @cal_month_start_date_array = gmtime $cal_month_start_date;
4843 my $cal_start_day_offset = $cal_month_start_date_array[6] - $current_calendar{week_start_day};
4844 $cal_start_day_offset += 7 if ($cal_start_day_offset < 0);
4846 my $cal_start_date = $cal_month_start_date - (86400 * $cal_start_day_offset);
4848 # in continuous_multimonth mode, skip first week if we already drew it in the previous iteration
4849 $cal_start_date = $cal_start_date + 604800 if (!$show_month_breaks && $cal_month_idx > 0 && $cal_start_day_offset != 0);
4851 # start with other_month if the first month does not start on the first day of the week (i.e there is an offset)
4852 @use_other_month = (1, 0) if (!$show_month_breaks && $cal_month_idx == 0 && $cal_start_day_offset != 0 && $current_month % 2);
4854 my @cal_start_date_array = gmtime $cal_start_date;
4856 my $cal_end_date = $cal_start_date + 86400*37;
4858 my $next_month = $current_month+1;
4859 if ($next_month == 12) {$next_month=0;}
4861 #cal_date keeps track of the date (in timestamp format)
4862 #as the calendar loop iterates through each day on the calendar page
4863 my $cal_date = $cal_start_date;
4864 my @cal_date_array = gmtime $cal_date;
4866 my %max_day_events;
4867 my %week_max_slots;
4869 #make a first pass through the month, assemble event week events structure:
4870 #week_events{week_index}{id} ={}
4871 #this hash has 4 keys--start_weekday, start_day, length and slot_order (slot_order will be calculated in the second pass)
4872 for ($l1=0;$cal_date_array[4] != $next_month;$l1++) { #each calendar has 5 or 6 weeks
4873 $week_start_timestamp = $cal_date;
4874 $week_end_timestamp = $week_start_timestamp + 604800;
4875 $max_day_events{$l1} = 0;
4877 @cal_date_array = gmtime $cal_date;
4878 foreach $event_id (keys %events) {
4879 $debug = 1 if ($debug == 1 && (&contains(\@debug_events, $event_id) || $debug_events[0] eq "all"));
4881 my %event = %{$events{$event_id}};
4883 #$debug_info .= "checking event $event_id ($event{start}, $event{end})\n";
4884 #$debug_info .= "checking event $event_id ($event{start} - $event{end}) against week $l1 ($week_start_timestamp - $week_end_timestamp)\n";
4885 $debug_info .= "week $l1 checking event $event_id ($event{start}-$event{end}}) for overlap ($week_start_timestamp-$week_end_timestamp)\n" if ($debug && &contains(\@debug_events, $event_id));
4887 if (&time_overlap($event{start}, $event{end}, $week_start_timestamp, $week_end_timestamp)) {
4888 $debug_info .= "week $l1 event $event_id overlaps\n" if ($debug);
4890 #$debug_info .= "event $event_id ($event{days} days) in week $l1\n";
4891 #$debug_info .= "check passed!\n";
4893 my @event_date_array = gmtime $event{start};
4894 my @event_end_date_array = gmtime $event{end};
4895 my $event_start_weekday = $event_date_array[6] - $current_calendar{week_start_day};
4896 my $event_end_weekday = $event_end_date_array[6] - $current_calendar{week_start_day};
4898 $event_start_weekday +=7 if ($event_start_weekday < 0);
4899 $event_end_weekday +=7 if ($event_end_weekday < 0);
4901 #$event_start_weekday = 0 if ($event_start_weekday < 0);
4902 #$event_end_weekday = 0 if ($event_end_weekday < 0);
4903 #$event_start_weekday = 6 if ($event_start_weekday > 6);
4904 #$event_end_weekday = 6 if ($event_end_weekday > 6);
4906 my $days_before_week_start = 0;
4907 my $days_after_week_end = 0;
4909 $debug_info .= "week $l1 event $event_id event_date_array[6]: $event_date_array[6]\n" if ($debug);
4910 $debug_info .= "week $l1 event $event_id event_end_date_array[6]: $event_end_date_array[6]\n" if ($debug);
4911 $debug_info .= "week $l1 event $event_id current_calendar{week_start_day}: $current_calendar{week_start_day}\n" if ($debug);
4912 $debug_info .= "week $l1 event $event_id event_start_weekday: $event_start_weekday event_end_weekday: $event_end_weekday\n" if ($debug);
4914 # the event might fall completely within the week boundary, or it
4915 # might overlap event begins or ends outside the week boundaries
4916 # (there are four possible cases):
4917 if ($event{start} < $week_start_timestamp && $event{end} > $week_end_timestamp) { # the event both starts and ends outside this week
4918 $debug_info .= "case 0\n" if ($debug);
4919 $week_events{$l1}{$event{id}}{start_weekday} = 0;
4920 $week_events{$l1}{$event{id}}{length} = 7;
4921 } elsif ($event{start} < $week_start_timestamp) { # the event starts before this week and ends within it
4922 $debug_info .= "case 1\n" if ($debug);
4923 #$days_before_week_start = int(($week_start_timestamp - $event{start})/86400);
4924 $week_events{$l1}{$event{id}}{start_weekday} = 0;
4925 #$week_events{$l1}{$event{id}}{length} = $event{days} - $days_before_week_start;
4926 $week_events{$l1}{$event{id}}{length} = $event_end_weekday+1;
4927 $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);
4928 } elsif ($event{end} > $week_end_timestamp) { # the event starts within this week and ends after it
4929 $debug_info .= "case 2\n" if ($debug);
4930 $week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
4931 $week_events{$l1}{$event{id}}{length} = 7-$event_start_weekday;
4932 if ($debug == 1) {
4933 foreach $debug_event_id (@debug_events) {
4934 next if ($debug_event_id ne $event{id});
4935 $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";
4938 } else { #the event begins and ends within the week
4939 $debug_info .= "case 3\n" if ($debug);
4940 $week_events{$l1}{$event{id}}{length} = $event{days};
4941 $week_events{$l1}{$event{id}}{start_weekday} = $event_start_weekday;
4944 if ($week_events{$l1}{$event{id}}{start_weekday} < 0) {
4945 $week_events{$l1}{$event{id}}{start_weekday} += 7;
4946 } elsif ($week_events{$l1}{$event{id}}{start_weekday} > 6) {
4947 $week_events{$l1}{$event{id}}{start_weekday} -= 7;
4949 $week_events{$l1}{$event{id}}{length} = 7 if ($week_events{$l1}{$event{id}}{length} > 7);
4951 $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);
4955 $temp_debug_info = "";
4956 $cal_date += 604800;
4958 # each day has at least two slots (the date, and a blank box beneath it)
4959 for ($l2=0;$l2<7;$l2++) {
4960 $week_slots{$l1}{$l2}{0}{width}=1;
4961 $week_slots{$l1}{$l2}{0}{depth}=1;
4962 $week_slots{$l1}{$l2}{1}{width}=1;
4963 $week_slots{$l1}{$l2}{1}{depth}=1;
4966 if ($debug == 1) {
4967 foreach $debug_event_id (@debug_events) {
4968 $debug_info .= "event $debug_event_id length: $week_events{$l1}{$debug_event_id}{length} start: $events{$debug_event_id}{start}\n";
4972 #order the week_events
4973 #fill in the %slots data structure:
4974 # $week_slots{week_index}{day_index}{slot_index}
4975 # $width = colspan
4976 # $depth = rowspan
4977 # $spacer = 1 if spacer slot.
4978 # @ids = event ids
4981 my $max_week_needed_slots = 0;
4982 my %max_day_needed_slots;
4984 # hey man, that's a sharp-lookin' sort you got there
4985 foreach $week_event_id (sort {
4986 return $week_events{$l1}{$b}{length} <=> $week_events{$l1}{$a}{length}
4987 if ($week_events{$l1}{$b}{length} != $week_events{$l1}{$a}{length});
4989 return $events{$a}{title} cmp $events{$b}{title}
4990 if ($events{$b}{all_day_event} ne "" && $events{$a}{all_day_event} ne "");
4992 return $events{$b}{all_day_event} cmp $events{$a}{all_day_event}
4993 if ($events{$b}{all_day_event} ne "" || $events{$a}{all_day_event} ne "");
4995 return $events{$a}{start} <=> $events{$b}{start};
4997 keys %{$week_events{$l1}})
4999 #$debug = 0;
5000 #$debug = 1 if (&contains(\@debug_events, $week_event_id));
5002 #$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);
5004 $empty_slot = 0;
5006 #starting at 1 leaves a row of empty slots (row 0), where the calendar dates will go.
5007 for ($l4=1; $empty_slot != 1; $l4++) {
5008 $empty_slot = 1;
5009 #check each day of the week_event, to make sure the slot is empty
5010 for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++) {
5011 $day_index=$l2+$week_events{$l1}{$week_event_id}{start_weekday};
5013 if (scalar @{$week_slots{$l1}{$day_index}{$l4}{ids}} > 0) {
5014 $empty_slot = 0;
5017 $slot_index=$l4;
5020 #$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);
5022 #fill up $week_slots with the new event (extend horizontally)
5023 for ($l2=0; $l2<$week_events{$l1}{$week_event_id}{length}; $l2++) {
5024 #$slots_in_row{$l1}{$slot_index}++;
5026 $day_index = $l2+$week_events{$l1}{$week_event_id}{start_weekday};
5027 push @{$week_slots{$l1}{$day_index}{$slot_index}{ids}}, $week_event_id;
5029 if ($l2==0) { # first slot gets the width
5030 $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)
5031 $week_slots{$l1}{$day_index}{$slot_index}{width} = 0;}
5032 $week_slots{$l1}{$day_index}{$slot_index}{depth} = 1;
5035 #keep track of the maximum number of slots each week has
5036 if ($slot_index > $week_max_slots{$l1}) {
5037 $week_max_slots{$l1} = $slot_index;
5038 $max_day_events{$l1} = $slot_index;
5042 # give all blank slots width and depth of 1
5043 for ($l2=0;$l2<7;$l2++) {
5044 for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++) { # for each slot
5045 if ($week_slots{$l1}{$l2}{$l3}{depth} eq "" || $week_slots{$l1}{$l2}{$l3}{width} eq "") {
5046 $week_slots{$l1}{$l2}{$l3}{width}=1;
5047 $week_slots{$l1}{$l2}{$l3}{depth}=1;
5052 my $total_spacers=0;
5053 # insert spacer slots below multi-day events.
5054 for ($l3=1;$l3<$week_max_slots{$l1}+1;$l3++) { # for each slot
5055 my $inserted_spacers=0;
5056 for ($l2=0;$l2<7;$l2++) {
5057 if ($week_slots{$l1}{$l2}{$l3}{width} > 1) { #multi-day event, add spacers beneath
5058 # create spacer row
5059 if ($inserted_spacers == 0) {
5060 # move everything else down and increment the number of rows
5061 $week_max_slots{$l1}++;
5062 for ($l4=0;$l4<7;$l4++) { # insert blank slots
5063 for ($l5=$week_max_slots{$l1};$l5>$l3+1;$l5--) { # count backwards
5064 $week_slots{$l1}{$l4}{$l5} = &deep_copy($week_slots{$l1}{$l4}{$l5-1});
5066 $week_slots{$l1}{$l4}{$l3+1}{width} = 1;
5067 $week_slots{$l1}{$l4}{$l3+1}{depth} = 1;
5068 $week_slots{$l1}{$l4}{$l3+1}{spacer} = 0;
5069 $week_slots{$l1}{$l4}{$l3+1}{ids} = "";
5071 $inserted_spacers=1
5074 # insert spacers into previously created row.
5075 for ($l4=$l2;$l4<$l2+$week_slots{$l1}{$l2}{$l3}{width};$l4++) {
5076 $week_slots{$l1}{$l4}{$l3+1}{spacer}=1;
5077 #$debug_info .= "inserted spacer into row: ".($l3+1).", column $l4, event ".($week_slots{$l1}{$l4}{$l3}{ids}[0])."\n";
5078 $total_spacers++;
5080 #$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n";
5086 #if ($l1 == 3) {
5087 #$debug_info .= "$total_spacers spacers inserted for week $l1.\n";
5088 #$debug_info .= "week $l1 day 0, slot 3: ".$week_slots{$l1}{0}{3}{ids}[0]."\n";
5091 #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
5093 # calculate slots in each row:
5094 for ($l3=1;$l3<$week_max_slots{$l1};$l3++) { # for each slot
5095 if ((scalar @{$week_slots{$l1}{$l2}{$l3}{ids}}) > 0 ) {
5096 $slots_in_row{$l1}{$l3} += $week_slots{$l1}{$l2}{$l3}{width};
5097 #$debug_info .= "event in row $l1. Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n";
5099 if ($week_slots{$l1}{$l2}{$l3}{spacer} == 1) {
5100 $slots_in_row{$l1}{$l3}++;
5101 #$debug_info .= "spacer in row $l1. Incrementing slots_in_row {$l1} {$l3} to $slots_in_row{$l1}{$l3}\n";
5105 %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});
5108 #$slots_in_row{$l1}{$slot_index}++;
5110 # extend event slots vertically.
5111 for ($l2=0;$l2<7;$l2++) { # for each day of the week
5112 for ($l3=1;$l3<$week_max_slots{$l1};$l3++) { # for each slot
5113 if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0 && $week_slots{$l1}{$l2}{$l3}{width} > 0) { # if this slot begins an event
5114 my $start_slot = $l3+1;
5115 for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++) {
5116 #$debug_info .= "checking slot $l4 below event slot ($l2, $l3)\n";
5117 #if ($week_slots{$l1}{$l2}{$l4}{width} == 0)
5118 # {next;}
5120 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.
5121 if ($l1 eq "3" && $debug) {
5122 $debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";}
5123 #$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of another event below with the same width.\n";
5124 #$debug_info .= "same-width event slot below week $l1, slot ($l2, $l3)\n";
5125 $week_slots{$l1}{$l2}{$l4}{width}=0;
5126 $week_slots{$l1}{$l2}{$l4}{depth}=0;
5127 $week_slots{$l1}{$l2}{$l3}{depth}++;
5128 push @{$week_slots{$l1}{$l2}{$l3}{ids}}, @{$week_slots{$l1}{$l2}{$l4}{ids}};
5130 $max_day_needed_slots{$l2}--;
5131 #$slots_in_row{$l1}{$l4}--;
5133 } 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
5134 if ($l1 eq "3" && $debug) {
5135 $debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";}
5136 #$debug_info .= "week $l1 slot ($l2, $l3) extended vertically because of a blank slot below.\n";
5137 #$debug_info .= "week $l1 slot ($l2, $l4) # ids:".scalar @{$week_slots{$l1}{$l2}{$l4}{ids}}."\n";
5138 #$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n";
5139 $week_slots{$l1}{$l2}{$l4}{width}=0;
5140 $week_slots{$l1}{$l2}{$l4}{depth}=0;
5141 $week_slots{$l1}{$l2}{$l3}{depth}++;
5142 $max_day_needed_slots{$l2}--;
5143 #$debug_info .= "week $l1, slot ($l2, $l3) depth: $week_slots{$l1}{$l2}{$l3}{depth} \n";
5144 } else {
5145 $debug_info .= "week $l1 slot ($l2, $l4) occupied. Finished attempting to extend slot $l3\n" if ($debug);
5146 last;
5152 #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
5154 # extend blank slots vertically into other blank slots.
5155 for ($l2=0;$l2<7;$l2++) { # for each day of the week
5157 for ($l3=1;$l3<$week_max_slots{$l1};$l3++) { # for each slot
5159 next if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0);
5161 if ($week_slots{$l1}{$l2}{$l3}{width} > 0 && $week_slots{$l1}{$l2}{$l3}{spacer} == 0) { # if it's blank (but not a spacer)
5163 my $start_slot = $l3+1;
5164 for ($l4=$start_slot; $l4<$week_max_slots{$l1}+1; $l4++) {
5165 if ($week_slots{$l1}{$l2}{$l4}{width} == 1 && $week_slots{$l1}{$l2}{$l4}{spacer} == 0) {
5166 #$debug_info .= "blank slot below week $l1, slot ($l2, $l3)\n" if ($debug);
5167 $week_slots{$l1}{$l2}{$l4}{width}=0;
5168 $week_slots{$l1}{$l2}{$l4}{depth}=0;
5169 $week_slots{$l1}{$l2}{$l3}{depth}++;
5170 $max_day_needed_slots{$l2}--;
5171 } else {
5172 last;
5178 #$debug_info .= "week $l1, event slots in row 1: $slots_in_row{$l1}{1}\n";
5179 #$debug_info .= "week $l1 slot (4, 1) depth: $week_slots{$l1}{4}{1}{depth}\n";
5181 # yet another pass. trim vertical depth and re-calculate max_slots
5183 # calculate trim
5184 my $trim = 0;
5185 #$debug_info .= "\n week $l1 max slots: $week_max_slots{$l1}\n";
5188 #$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);
5190 $max_week_needed_slots = max(values %max_day_needed_slots);
5191 #$debug_info .= "week $l1 max_week_needed_slots: $max_week_needed_slots\n";
5193 #if ($max_day_needed_slots >$max_week_needed_slots)
5194 # {$max_week_needed_slots = $max_day_needed_slots;}
5195 #$debug_info .= "max needed slots for week $l1, $max_week_needed_slots\n";
5197 my $trim = $week_max_slots{$l1} - $max_week_needed_slots;
5199 # apply trim
5200 #$debug_info .= "trim for week $l1, $trim\n";
5201 for ($l2=0;$l2<7;$l2++) { # for each day of the week
5203 for ($l3=$week_max_slots{$l1};$l3>0;$l3--) { # for each slot, counting backwards (upwards)
5205 if ($week_slots{$l1}{$l2}{$l3}{depth} > 0) { # blank or non-blank, with depth > 0
5207 #$debug_info .= "trimming week $l1, slot ($l2, $l3) by $trim\n";
5208 $week_slots{$l1}{$l2}{$l3}{depth} = $week_slots{$l1}{$l2}{$l3}{depth} - $trim;
5209 last;
5214 $week_max_slots{$l1} = $week_max_slots{$l1} - $trim;
5216 } # repeat for next week
5218 # print day names
5219 if ($cal_month_idx == 0 || $show_month_breaks) {
5220 my @lowercase_day_names;
5221 foreach $day_name (@day_names) {
5222 push @lowercase_day_names, lc $day_name;
5225 $return_text .=<<p1;
5226 <table class="calendar" summary="">
5227 <tr>
5228 <td class="day_names $lowercase_day_names[0]">$weekday_sequence[0]</td>
5229 <td class="day_names $lowercase_day_names[1]">$weekday_sequence[1]</td>
5230 <td class="day_names $lowercase_day_names[2]">$weekday_sequence[2]</td>
5231 <td class="day_names $lowercase_day_names[3]">$weekday_sequence[3]</td>
5232 <td class="day_names $lowercase_day_names[4]">$weekday_sequence[4]</td>
5233 <td class="day_names $lowercase_day_names[5]">$weekday_sequence[5]</td>
5234 <td class="day_names $lowercase_day_names[6]">$weekday_sequence[6]</td>
5235 </tr>
5239 #cal_date keeps track of the date (in timestamp format)
5240 #as the calendar loop iterates through each day on the calendar page
5241 $cal_date = $cal_start_date;
5242 @cal_date_array = gmtime $cal_date;
5244 #locked and loaded, data structures assembled--now it's time to kick it, calendar-style.
5245 for ($l1=0;$cal_date_array[4] != $next_month; $l1++) { #each calendar has 5 or 6 weeks
5247 my $last_week=0;
5248 my $timestamp_next_week = $cal_date+604800;
5249 my @timestamp_next_week_array = gmtime $timestamp_next_week;
5251 my $week_date_index = $cal_date;
5253 # draw the table!
5254 for ($l3=0;$l3<$week_max_slots{$l1}+1;$l3++) {
5255 $return_text .="<tr id=\"week_$cal_date\">";
5257 $week_date_index = $cal_date;
5258 for ($l2=0;$l2<7;$l2++) { # 7 days / week
5260 @cal_date_array = gmtime $week_date_index;
5261 my $td_class = "day ".lc($day_names[$l2]);
5262 $td_class .= " today" if ($cal_date_array[4] == $rightnow_month &&
5263 $cal_date_array[3] == $rightnow_mday &&
5264 $cal_date_array[5]+1900 == $rightnow_year);
5266 # display date numbers differently, depending on whether they are in the current month or not
5267 my $cal_month_name = "";
5268 if ($show_month_breaks || $cal_num_months == 1) {
5269 $td_class .= " other_month" if ($cal_date_array[4] != $current_month);
5270 } else {
5271 $td_class .= " other_month_multi" if ($use_other_month[$cal_date_array[4] % 2]);
5272 $cal_month_name = $months[$cal_date_array[4]] if ($cal_date_array[3] == 1);
5275 #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 "")
5277 if ($l3 == 0) { #if it's the top blank slot, put the date in there.
5279 $td_style="border-bottom-width:0px;";
5281 #display the cell differently if it is today.
5282 if ($cal_date_array[4] == $rightnow_month &&
5283 $cal_date_array[3] == $rightnow_mday &&
5284 $cal_date_array[5]+1900 == $rightnow_year) {
5285 # offset the date number a few pixels
5286 # (so it will be in the center of the red circle)
5287 # offset a bit more for a double-digit day number.
5288 # small touches are the difference between good and great :)
5290 my $date_div_style = "";
5291 $date_div_style = "text-indent: 11px;" if ($rightnow_mday > 10);
5293 $return_text .=<<p1;
5294 <td class="$td_class" style="$td_style" onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
5295 <div class="date today" style="$date_div_style"><a id="today"></a>$cal_date_array[3]&nbsp;$cal_month_name</div>
5296 </td>
5298 } else {
5299 $return_text .=<<p1;
5300 <td class="$td_class" style="$td_style" onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
5301 <div class="date">$cal_date_array[3]&nbsp;$cal_month_name</div>
5302 </td>
5305 } elsif ($week_slots{$l1}{$l2}{$l3}{spacer} != 0) { # spacer slot
5307 my $spacer_class = "spacer";
5308 if ($l3 == $week_max_slots{$l1}-1) {
5309 $spacer_class .= " bottom";
5311 $return_text .=<<p1;
5312 <td class="$td_class $spacer_class" style="$td_style" colspan=1 rowspan=1 onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
5313 </td>
5315 } elsif ($week_slots{$l1}{$l2}{$l3}{width} != 0) { # slot containing events
5317 $num_cols = $week_slots{$l1}{$l2}{$l3}{width};
5318 $num_rows = $week_slots{$l1}{$l2}{$l3}{depth};
5320 if (scalar @{$week_slots{$l1}{$l2}{$l3}{ids}} > 0) {
5322 $td_style="border-top-width:0px;border-bottom-width:0px;";
5323 my $event_id_list;
5324 for ( my $j = 0; $j < @{$week_slots{$l1}{$l2}{$l3}{ids}}; $j++ ) {
5325 if( $j < ( @{$week_slots{$l1}{$l2}{$l3}{ids}} - 1 ) ) {
5326 $event_id_list .= "'" . @{$week_slots{$l1}{$l2}{$l3}{ids}}[$j] . "'" . ",";
5327 } else {
5328 $event_id_list .= "'" . @{$week_slots{$l1}{$l2}{$l3}{ids}}[$j] . "'";
5331 my $events_link = "javascript:display_events($event_id_list);";
5333 #($l2,$l3) $num_cols\lx$num_rows
5334 $return_text .=<<p1;
5335 <td class="$td_class" style="$td_style" colspan=$num_cols rowspan=$num_rows onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
5336 <a href="$events_link" class="event_box" style="display:block;text-align:center;cursor:pointer;cursor:hand;"><span class="event_time" style=";"> ALL<br></a>
5339 foreach $event_id (@{$week_slots{$l1}{$l2}{$l3}{ids}}) {
5340 my $multi_day_event = ($week_slots{$l1}{$l2}{$l3}{width} > 1) ? 1:0;
5342 my $background_event = (&contains($events{$event_id}{cal_ids}, $current_calendar{id})) ? 0:1;
5344 $return_text .= &display_calendar_event($event_id, $multi_day_event, $background_event)
5347 $return_text .=<<p1;
5348 </td>
5350 } elsif ($week_slots{$l1}{$l2}{$l3}{ids} eq "" && $week_slots{$l1}{$l2}{$l3}{width} > 0) { # blank slot
5352 $td_style="border-top-width:0px;border-bottom-width:0px;";
5354 #($l2,$l3) blank $num_cols\lx$num_rows
5355 $return_text .=<<p1;
5356 <td class="$td_class" style="$td_style" colspan=$num_cols rowspan=$num_rows onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">
5357 </td>
5361 $week_date_index += 86400;
5362 } # next day (first row)
5364 #right border
5365 $return_text .=<<p1;
5366 </tr>
5368 } # event slot index
5371 # this little trick is the cat's pajamas. It's another row of
5372 # table cells that cause each calendar day to come down a little
5373 # bit below the lowest esvent. It makes the calendar look sharp.
5375 # Also, if the week has a small number of events, we expand the height of the bottom cell.
5376 # This makes all the calendar cells look square, which is the bee's knees.
5378 my $bottom_height_style = "";
5379 if ($max_day_events{$l1} < 2) {
5380 my $height = (4-$max_day_events{$l1}) . "em"; # this algorithm was developed by guess & check
5381 #my $height = "100px"; # this algorithm was developed by guess & check
5382 $bottom_height_style = "line-height:$height;";
5384 $return_text .=<<p1;
5385 <tr style="$bottom_height_style">
5387 $week_date_index = $cal_date;
5388 for ($l2=0;$l2<7;$l2++) { #each week has 7 days(!)
5390 my $td_class = "";
5391 @cal_date_array = gmtime $week_date_index;
5392 $td_class .= "day ".lc($day_names[$l2])." cell_bottom";
5394 $td_class .= " today" if ($cal_date_array[4] == $rightnow_month &&
5395 $cal_date_array[3] == $rightnow_mday &&
5396 $cal_date_array[5]+1900 == $rightnow_year);
5398 if ($show_month_breaks || $cal_num_months == 1) {
5399 $td_class .= " other_month" if ($cal_date_array[4] != $current_month);
5400 } else {
5401 $td_class .= " other_month_multi" if ($use_other_month[$cal_date_array[4] % 2]);
5404 $return_text .=<<p1;
5405 <td class="$td_class" style="line-height:5px;border-top-width:0px;$bottom_height_style" onmousedown="if (event.shiftKey) return show_day_contextmenu(event, $week_date_index); else return false;" oncontextmenu="return show_day_contextmenu(event, $week_date_index);">&nbsp;</td>
5407 $week_date_index+=86400;
5409 $return_text .=<<p1;
5410 </tr>
5412 $cal_date+=604800;
5413 @cal_date_array = gmtime $cal_date;
5416 #close table tag for each month or only for last month on continuous_multimonth mode
5417 if ($show_month_breaks || $last_cal_month) {
5418 $return_text .=<<p1;
5419 </table>
5420 <br style="page-break-after:always;">
5424 #increment to the next month--the method used
5425 #here is the most painless way of making
5426 #this work the right way in all cases.
5427 $current_month++;
5428 $cal_month_idx++;
5430 if ($current_month == 12) {
5431 $current_month=0;
5432 $current_year++;
5436 return $return_text;
5437 } #********************end render_calendar subroutine**********************
5440 sub background_event_colorize {
5441 my ($event_id, $calendar_id) = @_;
5443 my %event = %{$events{$event_id}};
5444 my %calendar = %{$calendars{$calendar_id}};
5445 my $event_bgcolor = $event{bgcolor};
5448 if ($calendars{$event{cal_ids}[0]}{calendar_events_color} ne "") {
5449 $event_bgcolor = $calendars{$event{cal_ids}[0]}{calendar_events_color};}
5452 if ($calendar{background_events_display_style} eq "single_color") {
5453 $event_bgcolor = $calendar{background_events_color};} elsif ($calendar{background_events_display_style} eq "faded") {
5454 # create "faded" look for background event
5455 my $faded_color = $event_bgcolor;
5457 #convert rgb values from hex (00-FF) to decimal integer (0-255)
5458 my $r = hex substr $faded_color,1,2;
5459 my $g = hex substr $faded_color,3,2;
5460 my $b = hex substr $faded_color,5,2;
5462 #convert integer rgb values to hsv
5463 my @hsv_array = &rgb2hsv($r,$g,$b);
5465 #convert s and v from percentages to decimal
5466 $hsv_array[1] = $hsv_array[1]/100;
5467 $hsv_array[2] = $hsv_array[2]/100;
5469 #"fade" the color (decrease saturation)
5470 $hsv_array[1] = $hsv_array[1]/$calendar{background_events_fade_factor};
5472 my @new_rgb_array = &hsv2rgb($hsv_array[0],$hsv_array[1],$hsv_array[2]);
5474 #convert back to hex
5475 $r = (sprintf ("%1.1X",$new_rgb_array[0]));
5476 $g = (sprintf ("%1.1X",$new_rgb_array[1]));
5477 $b = (sprintf ("%1.1X",$new_rgb_array[2]));
5479 $event_bgcolor = "#$r$g$b";
5482 return $event_bgcolor;
5487 sub display_calendar_event {
5488 my ($event_id, $multi_day, $background_event) = @_;
5489 my %event = %{$events{$event_id}};
5490 my $results = "";
5492 my $event_bgcolor = $event{bgcolor};
5494 # force white color if the background is dark
5495 my $textcolor_style = "";
5496 my $r = hex substr $event_bgcolor,1,2;
5497 my $g = hex substr $event_bgcolor,3,2;
5498 my $b = hex substr $event_bgcolor,5,2;
5499 my $bright = ($r*299+$g*587+$b*114)/1000;
5500 $textcolor_style = "color:#fff" if ($bright < 128);
5502 $event_bgcolor = $current_calendar{calendar_events_color} if ($current_calendar{calendar_events_color} ne "");
5504 my $event_box_class = "event_box";
5506 # handle link
5507 my $event_link = "javascript:display_event('$event_id');";
5508 $event_link = "$event{details}" if ($event{details_url} eq "1");
5510 if ($background_event) {
5511 $event_box_class .= " background";
5512 $event_bgcolor = &background_event_colorize($event_id, $current_calendar{id});
5515 # handle icon
5516 my $icon_text = "";
5517 my $unit_icon_text = "";
5518 if ($event{unit_number} ne "") {
5519 $unit_icon_text = $event{unit_number}." ";
5520 $unit_icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" border="0" alt=\"\" vspace=0 hspace=0 style="vertical-align:middle;">/g;
5523 my $link_style="";
5524 if ($event{icon} ne "blank" && $event{icon} ne "") {
5525 $icon_text = <<p1;
5526 <img align="bottom" src = "$icons_url/$event{icon}_16x16.gif" style="margin-left:-22px;margin-right:5px;margin-bottom:-5px;" alt="">
5528 chomp $icon_text;
5529 $link_style="padding-left:29px";
5532 # context menu stuff
5533 my $event_context_menu_text="onmousedown=\"if (event.shiftKey) return show_event_contextmenu(event, $event_id, '$event_bgcolor', '$event{series_id}'); else return false; \" oncontextmenu=\"return show_event_contextmenu(event, $event_id, '$event_bgcolor', '$event{series_id}');\"";
5534 $event_context_menu_text = "" if ($event_id =~ /\D/);
5536 if ($multi_day == 0) {
5537 my $event_time = "";
5538 if ($event{all_day_event} ne "1") {
5539 $event_time = &nice_time_range_format($event{start}, $event{end});
5540 $event_time = "<span class=\"event_time\" style=\"$textcolor_style;\"> $event_time </span><br/>";
5544 my $temp_item_text = $calendar_item_template;
5545 $temp_item_text =~ s/###icon###/$icon_text$unit_icon_text/g;
5546 $temp_item_text =~ s/###title###/$event{title}/g;
5547 $temp_item_text =~ s/###time###/$event_time/g;
5548 my $calendar_title = $calendars{$event{cal_ids}[0]}{title};
5549 $temp_item_text =~ s/###calendar title###/$calendar_title/g;
5551 $results .=<<p1;
5552 <a href="$event_link" class="$event_box_class" style="display:block;text-align:left;$link_style;background-color:$event_bgcolor;$textcolor_style;cursor:pointer;cursor:hand;" $event_context_menu_text>
5553 $temp_item_text</a>
5556 } else { # multi-day-event
5558 # handle the case where an event is < 24 hours and crosses midnight.
5559 my $nudge_edge="";
5560 my $event_time = "";
5562 if ($event{all_day_event} ne "1") {
5563 if ($event{end} - $event{start} < 86400) {
5564 my $offset = 25;
5565 my $width = 50;
5566 $nudge_edge = "width:$width%;position:relative;left:$offset%;";
5569 $event_time = &nice_time_range_format($event{start}, $event{end});
5570 $event_time = "<span class=\"event_time\" style=\"$textcolor_style;\"> $event_time </span>";
5573 if ($event{icon} ne "blank" && $event{icon} ne "") {
5574 $icon_text = <<p1;
5575 <img src="$icons_url/$event{icon}_16x16.gif" style="vertical-align:middle;margin-right:5px;" alt="">
5577 chomp $icon_text;
5580 my $temp_item_text = $calendar_item_template;
5581 $temp_item_text =~ s/###icon###/$icon_text$unit_icon_text/g;
5582 $temp_item_text =~ s/###title###/$event{title}/g;
5583 $temp_item_text =~ s/###time###/$event_time/g;
5584 my $calendar_title = $calendars{$event{cal_ids}[0]}{title};
5585 $temp_item_text =~ s/###calendar title###/$calendar_title/g;
5587 $results .=<<p1;
5588 <a href="$event_link" class="$event_box_class" style="display:block;text-align:center;background-color:$event_bgcolor;$textcolor_style;cursor:pointer;cursor:hand;$nudge_edge" $event_context_menu_text>
5589 $temp_item_text</a>
5597 sub display_list_event {
5598 my ($event_id, $background_event, $sameday) = @_;
5599 my %event = %{$events{$event_id}};
5600 my $results="";
5602 @event_start_timestamp_array = gmtime $event{start};
5604 my $date_string;
5605 my $weekday_string;
5607 if ($event{days} == 1) {
5608 #single-day event
5609 $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]";
5610 $weekday_string = $day_names_abv[$event_start_timestamp_array[6]]
5611 } else { #multi-day event
5613 @event_end_timestamp_array = gmtime $event{end};
5614 if ($event_start_timestamp_array[4] eq $event_end_timestamp_array[4]) {
5615 $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3]-$event_end_timestamp_array[3]";
5616 } else {
5617 $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]";
5619 $weekday_string = "$day_names_abv[$event_start_timestamp_array[6]]-$day_names_abv[$event_end_timestamp_array[6]]";
5622 # weekday abbreviations
5623 my $weekday_abv_string = $weekday_string;
5624 for ($l1=0;$l1<scalar @day_names;$l1++) {
5625 $weekday_abv_string =~ s/$day_names[$l1]/$day_names_abv[$l1]/g;
5628 my $icon_text="";
5629 my $unit_icon_text="";
5630 if ($event{unit_number} ne "") {
5631 $icon_text = $event{unit_number};
5632 $icon_text =~ s/(\d)/<img src="$graphics_url\/unit_number_patch_$1_16x10.gif" style=\"position:relative;top:5px;\" alt=\"\">/g;
5635 if ($event{icon} eq "blank" || $event{icon} eq "") {
5636 $icon_text .= "$unit_icon_text";
5637 } else {
5638 $icon_text .= "$unit_icon_text<img src = \"$icons_url/$event{icon}_16x16.gif\" style=\"position:relative;top:5px;\" alt=\"\">";
5641 my $event_bgcolor = $event{bgcolor};
5643 if ($calendars{$event{cal_ids}[0]}{calendar_events_color} ne "") {
5644 $event_bgcolor = $calendars{$event{cal_ids}[0]}{calendar_events_color};}
5646 if ($background_event eq "1") {
5647 $event_bgcolor = &background_event_colorize($event_id, $current_calendar{id});
5651 my $event_context_menu_text="onmousedown=\"if (event.shiftKey) return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$event{series_id}'); else return false;\" oncontextmenu=\"return show_event_contextmenu(event, $event{id}, '$event{bgcolor}', '$event{series_id}');\"";
5652 if ($event_id =~ /\D/) {
5653 $event_context_menu_text=""}
5655 my $day_context_menu_text = "onmousedown=\"if (event.shiftKey) return show_day_contextmenu(event, $event{start}); else return false;\" oncontextmenu=\"return show_day_contextmenu(event, $event{start});\"";
5657 # event time
5658 my $event_time = "";
5659 if ($event{all_day_event} ne "1") {
5660 $event_time = &nice_time_range_format($event{start}, $event{end});
5661 $event_time = "<span class=\"event_time\">$event_time</span>";
5664 my $event_link = "javascript:display_event('$event{id}');";
5665 if ($event{details_url} eq "1") {
5666 $event_link = "$event{details}";}
5668 my $margin_top="7px";
5669 $margin_top = "0" if ($sameday);
5672 my $temp_item_text = $list_item_template;
5675 $temp_item_text =~ s/###variable_margin###/$margin_top/g;
5676 $temp_item_text =~ s/###event_contextmenu###/$event_context_menu_text/g;
5677 $temp_item_text =~ s/###day_contextmenu###/$day_context_menu_text/g;
5678 $temp_item_text =~ s/###id###/$event_id/g;
5679 $temp_item_text =~ s/###bgcolor###/$event_bgcolor/g;
5680 $temp_item_text =~ s/###link###/$event_link/g;
5681 $temp_item_text =~ s/###details###/$event{details}/g;
5682 $temp_item_text =~ s/###icon###/$icon_text/g;
5683 $temp_item_text =~ s/###title###/$event{title}/g;
5684 $temp_item_text .= qq!<br><pre>$event{details}</pre><hr>!;
5685 $temp_item_text =~ s/###date###/$date_string/g;
5686 $temp_item_text =~ s/###weekday###/$weekday_string/g;
5687 $temp_item_text =~ s/###weekday_abv###/$weekday_abv_string/g;
5688 $temp_item_text =~ s/###time###/$event_time/g;
5691 $results .= $temp_item_text;
5693 $no_results .=<<p1;
5694 <li style="padding:0;margin:0;margin-top:$margin_top;"$event_context_menu_text>
5695 <span class="small_note" style="margin:0;border:0;vertical-align:middle;width:7em;white-space:nowrap;text-align:right;cursor:pointer;cursor:hand;" onclick="display_event('$event_id')" > $date_string </span>
5696 <a class="event_box" style="text-align:left;white-space:nowrap;background-color:$event_bgcolor;" href="$event_link"> $icon_text $event_time $event{title}</a>
5697 </li>
5703 return $results;
5708 sub render_list {
5709 my $return_text = "";
5710 ($start_month, $start_year, $end_month, $end_year) = @_;
5712 #calculate where to start and end the list
5714 #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
5715 my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
5716 my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
5718 # loop through all the events.
5720 #Create an array of events which fall
5721 # within the current list view dates
5722 my @selected_cal_events;
5724 #and a funky data structure for the background calendars
5725 # each element of this hash will be an array.
5726 my $shared_cal_events={}; #empty hash
5728 foreach $event_id (keys %events) {
5729 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
5730 my $event_in_current_calendar = 0;
5732 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
5733 if ($temp_cal_id eq $current_cal_id) {
5734 push @selected_cal_events, $event_id;}
5736 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
5737 if ($temp_cal_id eq $background_cal_id) {
5738 if ($current_calendar{list_background_calendars_together} eq "yes") {
5739 push @selected_cal_events, $event_id;
5740 } else {
5741 push @{$shared_cal_events{$background_cal_id}}, $event_id if (!&contains(\@selected_cal_events, $event_id));
5749 # initialize loop variables
5750 $current_month = $start_month;
5751 $current_year = $start_year;
5753 $return_text .=<<p1;
5756 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) {
5757 my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
5758 my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
5760 $return_text .=<<p1;
5761 <div class="list_month_box">
5764 if ($cal_num_months> 1) {
5765 $return_text .=<<p1;
5766 $months[$current_month] $current_year
5770 if ($current_calendar{list_background_calendars_together} eq "yes") {
5771 $return_text .=<<p1;
5772 <ul class="list_cal_box" style="list-style-type:none;float:left;text-align:left;">
5773 <div style="text-align:center;font-weight:bold;">$calendars{$current_cal_id}{title}</div>
5775 #display events for selected calendar
5776 my $previous_event_id;
5777 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) {
5778 my %event = %{$events{$event_id}};
5779 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
5780 my $background_event = "";
5781 $background_event = "1" if ($event{cal_ids}[0] ne $current_cal_id);
5783 my @temp1 = gmtime($event{start});
5784 my @temp2 = gmtime($events{$previous_event_id}{start});
5786 my $sameday = "";
5787 $sameday = "1" if ($temp1[3] == $temp2[3]);
5789 $return_text .= &display_list_event($event_id, $background_event, $sameday);
5790 $previous_event_id = $event_id;
5793 $return_text .=<<p1;
5794 </ul>
5796 } else {
5797 $return_text .=<<p1;
5798 <ul class="list_cal_box" style="list-style-type:none;float:left;text-align:left;">
5799 <li style="text-align:center;font-weight:bold;">$calendars{$current_cal_id}{title}</li>
5801 #display events for selected calendar
5802 my $previous_event_id;
5804 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) {
5805 my %event = %{$events{$event_id}};
5806 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
5807 my @temp1 = gmtime($event{start});
5808 my @temp2 = gmtime($events{$previous_event_id}{start});
5810 my $sameday = "";
5811 $sameday = "1" if ($temp1[3] == $temp2[3]);
5813 $return_text .= &display_list_event($event_id,0,$sameday);
5814 $previous_event_id = $event_id;
5817 $return_text .=<<p1;
5818 </ul>
5821 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
5822 $return_text .=<<p1;
5823 <ul class="list_cal_box background" style="list-style-type:none;float:left;text-align:left;">
5824 <li style="text-align:center;font-weight:bold;">$calendars{$background_cal_id}{title}</li>
5826 #list events for that calendar
5827 my $previous_event_id;
5828 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) {
5830 %event = %{$events{$event_id}};
5831 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
5832 my @temp1 = gmtime($event{start});
5833 my @temp2 = gmtime($events{$previous_event_id}{start});
5835 my $sameday = "";
5836 $sameday = "1" if ($temp1[3] == $temp2[3]);
5838 $return_text .= &display_list_event($event_id,1,$sameday);
5839 $previous_event_id = $event_id;
5843 $return_text .=<<p1;
5844 </ul>
5845 <br style="clear:both;"/> <!--needed because IE sucks-->
5850 $return_text .=<<p1;
5851 <br style="clear:both;"/> <!-- because IE sucks-->
5852 <br style="clear:both;"/> <!-- because IE sucks-->
5853 </div>
5854 <br style="clear:both;"/> <!-- because IE sucks-->
5855 <br style="clear:both;"/> <!-- because IE sucks-->
5858 #increment to the next month--the method used
5859 #here is the most painless way of making
5860 #this work the right way in all cases.
5861 $current_month +=1;
5862 if ($current_month == 12) {
5863 $current_month=0;
5864 $current_year++;
5868 $return_text .=<<p1;
5870 return $return_text;
5872 } #********************end generate_list subroutine**********************
5875 sub generate_event_details_javascript {
5876 my ($events_start_timestamp, $events_end_timestamp) = @_;
5878 my $return_string="";
5880 my $num_events = 0;
5881 my $num_remote_events = 0;
5882 my $event_defs="";
5883 my $remote_event_defs="";
5885 $index=0;
5887 #loop through the events, check to see if they fall
5888 #within the current calendar month
5889 foreach $event_id (keys %events) {
5890 my %event = %{$events{$event_id}};
5891 if (&time_overlap($event{start},$event{end},$events_start_timestamp,$events_end_timestamp)) {
5893 if ($event_id =~ /^r/) {
5894 $num_remote_events++;
5895 $remote_event_defs .= <<p1;
5896 remote_event_details["$event_id"] = new Object;
5897 remote_event_details["$event_id"].url = "$event{remote_calendar}{url}?view_event=1&evt_id=$event{remote_event_id}";
5904 $return_string .=<<p1;
5905 var remote_event_details = new Array($num_remote_events);
5906 $remote_event_defs
5907 var event_details = new Array($num_events);
5908 $event_defs
5910 return $return_string;
5912 } #********************end generate_event_details_javascript subroutine**********************
5916 sub pending_events_visible {
5917 # display pending events for this calendar?
5918 if ($options{pending_events_display} eq '0' || $options{pending_events_display} eq '1' ||
5919 ($options{pending_events_display} eq '2' && $logged_in_as_current_cal_user) || # logged-in user of this calendar
5920 ($options{pending_events_display} eq '3' && $logged_in_as_current_cal_user) || # logged-in user of this calendar
5921 ($options{pending_events_display} eq '3' && $logged_in_as_current_cal_admin) || # logged-in admin of this calendar
5922 $logged_in_as_root # root
5923 ) {return 1};
5925 return undef;
5928 sub forced_login {
5929 my $results = "";
5931 $results .= <<p1;
5932 <form name="forced_login_form" id="update_cal_form" action="" method="POST">
5933 <input type="hidden" name="active_tab" value="$active_tab">
5934 <input type="hidden" name="cal_id" value="$current_cal_id"/>
5935 <div class="info_box" style="clear:both;">
5936 <p class="cal_title" style="text-align:center;">
5937 $lang{login}
5938 </p>
5939 <div class="leftcol" style="">
5940 <label class="required_field" for="cal_password">$lang{cal_password}</label>
5941 </div>
5943 <div class="rightcol" style="white-space:nowrap;">
5944 <input type="password" name="cal_password" id="cal_password" size=12 />
5945 <span class="small_note" ><a style="vertical-align:top;" href="javascript:display_help('current_password','$lang{cal_password}')">$lang{help_on_this}</a></span>
5946 </div>
5948 <div class="leftcol">
5949 &nbsp;
5950 </div>
5951 <div class="rightcol" style="white-space:nowrap;">
5952 <input type="submit" value="$lang{submit}"/>
5953 </div>
5954 <br style="clear:both;"/>
5955 </div>
5956 </form>
5959 return $results;
5962 sub generate_logged_in_stuff {
5963 # events & calendars pending approval, etc.
5965 my $results = "";
5967 #if ($options{pending_events_display} > 1)
5971 my $pending_events_text = "";
5972 # display pending events for this calendar?
5973 #$debug_info .= "pending_events_visible: ".(&pending_events_visible)."\n";
5975 if (&pending_events_visible) {
5976 foreach $new_event_id (keys %new_events) {
5977 push @pending_events_to_display, $new_event_id;
5980 #$debug_info .= "scalar @ pending_events_to_display: ".(scalar @pending_events_to_display)."\n";
5982 if (scalar @pending_events_to_display > 0) {
5983 $pending_events_text .= "<a href=\"javascript:approve_pending_events_toggle()\">";
5984 $pending_events_text .= (scalar @pending_events_to_display)." ";
5986 if (scalar @pending_events_to_display == 1) {
5987 $pending_events_text .= $lang{pending_event1};
5988 } else {
5989 $pending_events_text .= $lang{pending_event2};
5991 $pending_events_text .= "</a>";
5995 # display pending events for other calendars?
5996 #if ($options{pending_events_display}) {
5999 if ($pending_events_text ne "") {
6000 $results .= "$pending_events_text <div style=\"text-align:right;\" id=\"pending_events\"></div>";
6003 return $results;
6010 sub csv_file_palm {
6012 ($start_month, $start_year, $end_month, $end_year) = @_;
6014 #calculate where to start and end the list
6016 #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
6017 my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
6018 my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
6020 #@cal_month_start_date_array = gmtime $cal_month_start_date;
6022 # loop through all the events.
6024 #Create an array of events which fall
6025 # within the current list view dates
6026 my @selected_cal_events;
6028 #and a funky data structure for the background calendars
6029 # each element of this hash will be an array.
6030 my $shared_cal_events={}; #empty hash
6032 foreach $event_id (keys %events) {
6033 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
6034 my $event_in_current_calendar = 0;
6036 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
6037 if ($temp_cal_id eq $current_cal_id) {
6038 push @selected_cal_events, $event_id;}
6039 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6040 if ($temp_cal_id eq $background_cal_id) {
6041 push @{$shared_cal_events{$background_cal_id}}, $event_id;}
6047 $html_output =<<p1;
6048 Cache-control: no-cache,no-store,private
6049 Content-disposition: filename="events.csv"
6050 Content-Type: text/csv; charset=$lang{charset}\n
6052 #initialize loop variables
6053 #$current_timestamp = $list_start_timestamp;
6054 $current_month = $start_month;
6055 $current_year = $start_year;
6057 $html_output .=<<p1;
6058 CSV datebook: Category, Private, Description, Note, Event, Begin, End, Alarm, Advance, Advance Units, Repeat Type, Repeat Forever, Repeat End, Repeat Frequency, Repeat Day, Repeat Days, Week Start, Number of Exceptions, Exceptions
6062 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) {
6063 my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
6064 my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
6065 #display events for selected calendar
6066 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) {
6067 my %event = %{$events{$event_id}};
6069 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6070 my $csv_subject = "$event{title}";
6072 @event_start_timestamp_array = gmtime $event{start};
6073 my $csv_start_date = ($event_start_timestamp_array[5]+1900)." ".($event_start_timestamp_array[4]+1)." ".($event_start_timestamp_array[3]);
6074 my $csv_start_time = "$event_start_timestamp_array[2]:$event_start_timestamp_array[1]";
6076 @event_end_timestamp_array = gmtime $event{end};
6077 my $csv_end_date = ($event_end_timestamp_array[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
6078 my $csv_end_time = "$event_end_timestamp_array[2]:$event_end_timestamp_array[1]";
6080 my $csv_description = $event{details};
6081 $csv_description =~ s/"/""/g;
6082 $csv_description =~ s/\n/\\n/g;
6084 if ($event{days} != 1) {
6085 @event_end_timestamp_array = gmtime $event{end};
6086 $csv_end_date = ($event_end_timestamp_array[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
6089 $html_output .=<<p1;
6090 "$calendars{$current_cal_id}{title}","0","$csv_subject","$csv_description","1","$csv_start_date $csv_start_time","$csv_end_date $csv_end_time","0","0","0","0","1","$csv_end_date","0","0","0000000","0","0",""
6094 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6095 #list events for that calendar
6096 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) {
6097 my %event = %{$events{$event_id}};
6099 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6100 my $csv_subject = "$event{title}";
6102 @event_start_timestamp_array = gmtime $event{start};
6103 my $csv_start_date = ($event_start_timestamp_array[5]+1900)." ".($event_start_timestamp_array[4]+1)." ".($event_start_timestamp_array[3]);
6104 my $csv_start_time = "$event_start_timestamp_array[2]:$event_start_timestamp_array[1]";
6106 @event_end_timestamp_array = gmtime $event{end};
6107 my $csv_end_date = ($event_end_timestamp_array[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
6108 my $csv_end_time = "$event_end_timestamp_array[2]:$event_end_timestamp_array[1]";
6110 my $csv_description = $event{details};
6111 $csv_description =~ s/"/""/g;
6112 $csv_description =~ s/\n/\\n/g;
6114 $csv_description =~ s/"/""/g;
6115 $csv_description =~ s/\n/\\n/g;
6118 if ($event{days} != 1) {
6119 @event_end_timestamp_array = gmtime $event{end};
6120 $csv_end_date = ($event_end_timestamp_array[5]+1900)." ".($event_end_timestamp_array[4]+1)." ".($event_end_timestamp_array[3]);
6123 $html_output .=<<p1;
6124 "$calendars{$background_cal_id}{title}","0","$csv_subject","$csv_description","1","$csv_start_date $csv_start_time","$csv_end_date $csv_end_time","0","0","0","0","1","$csv_end_date","0","0","0000000","0","0",""
6130 #increment to the next month--the method used
6131 #here is the most painless way of making
6132 #this work the right way in all cases.
6133 $current_month +=1;
6134 if ($current_month == 12) {
6135 $current_month=0;
6137 $current_year++;
6140 $html_output .= $debug_info;
6141 print $html_output;
6147 sub csv_file {
6149 ($start_month, $start_year, $end_month, $end_year) = @_;
6151 #calculate where to start and end the list
6153 #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
6154 my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
6155 my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
6157 #@cal_month_start_date_array = gmtime $cal_month_start_date;
6159 # loop through all the events.
6161 #Create an array of events which fall
6162 # within the current list view dates
6163 my @selected_cal_events;
6165 #and a funky data structure for the background calendars
6166 # each element of this hash will be an array.
6167 my $shared_cal_events={}; #empty hash
6169 foreach $event_id (keys %events) {
6170 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
6171 my $event_in_current_calendar = 0;
6173 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
6174 if ($temp_cal_id eq $current_cal_id) {
6175 push @selected_cal_events, $event_id;}
6176 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6177 if ($temp_cal_id eq $background_cal_id) {
6178 push @{$shared_cal_events{$background_cal_id}}, $event_id;}
6184 $html_output =<<p1;
6185 Cache-control: no-cache,no-store,private
6186 Content-disposition: filename="events.csv"
6187 Content-Type: text/plain; charset=$lang{charset}\n\n
6189 #initialize loop variables
6190 #$current_timestamp = $list_start_timestamp;
6191 $current_month = $start_month;
6192 $current_year = $start_year;
6194 $html_output .=<<p1;
6195 "Subject","Start Date","Start Time","End Date","End Time","All day event","Reminder on/off","Reminder Date","Reminder Time","Meeting Organizer","Required Attendees","Optional Attendees","Meeting Resources","Billing Information","Categories","Description","Location","Mileage","Priority","Private","Sensitivity","Show time as"
6199 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) {
6200 my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
6201 my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
6202 #display events for selected calendar
6203 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) {
6204 my %event = %{$events{$event_id}};
6206 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6207 my $csv_subject = "$event{title} ($calendars{$current_cal_id}{title})";
6209 @event_start_timestamp_array = gmtime $event{start};
6210 my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
6211 my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]);
6213 @event_end_timestamp_array = gmtime $event{end};
6214 my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
6215 my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]);
6217 my $csv_description = $event{details};
6218 $csv_description =~ s/"/""/g;
6219 $csv_description =~ s/\n/\\n/g;
6221 if ($event{days} != 1) {
6222 @event_end_timestamp_array = gmtime $event{end};
6223 $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
6226 $html_output .=<<p1;
6227 "$csv_subject","$csv_start_date","$csv_start_time",$csv_end_date,"$csv_end_time","True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1"
6231 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6232 #list events for that calendar
6233 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) {
6234 my %event = %{$events{$event_id}};
6236 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6237 my $csv_subject = "$event{title} ($calendars{$background_cal_id}{title})";
6239 @event_start_timestamp_array = gmtime $event{start};
6240 my $csv_start_date = ($event_start_timestamp_array[4]+1)."/$event_start_timestamp_array[3]/".($event_start_timestamp_array[5]+1900);
6241 my $csv_start_time = ($event_start_timestamp_array[2]).":$event_start_timestamp_array[1]:".($event_start_timestamp_array[0]);
6243 @event_end_timestamp_array = gmtime $event{end};
6244 my $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
6245 my $csv_end_time = ($event_end_timestamp_array[2]).":$event_end_timestamp_array[1]:".($event_end_timestamp_array[0]);
6247 my $csv_description = $event{details};
6248 $csv_description =~ s/"/""/g;
6249 $csv_description =~ s/\n/\\n/g;
6251 $csv_description =~ s/"/""/g;
6252 $csv_description =~ s/\n/\\n/g;
6255 if ($event{days} != 1) {
6256 @event_end_timestamp_array = gmtime $event{end};
6257 $csv_end_date = ($event_end_timestamp_array[4]+1)."/$event_end_timestamp_array[3]/".($event_end_timestamp_array[5]+1900);
6260 $html_output .=<<p1;
6261 "$csv_subject","$csv_start_date","$csv_start_time",$csv_end_date,"$csv_end_time","True","True","$csv_start_date","12:00:00 AM",,,,,,,"$csv_description",,,"Normal","False","Normal","1"
6267 #increment to the next month--the method used
6268 #here is the most painless way of making
6269 #this work the right way in all cases.
6270 $current_month +=1;
6271 if ($current_month == 12) {
6272 $current_month=0;
6274 $current_year++;
6277 $html_output .= $debug_info;
6278 print $html_output;
6284 sub vcalendar_export_cal {
6285 ($start_month, $start_year, $end_month, $end_year) = @_;
6287 #calculate where to start and end the list
6289 #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
6290 my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
6291 my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
6293 # loop through all the events.
6295 #Create an array of events which fall
6296 # within the current list view dates
6297 my @selected_cal_events;
6299 #and a funky data structure for the background calendars
6300 # each element of this hash will be an array.
6301 my $shared_cal_events={}; #empty hash
6303 foreach $event_id (keys %events) {
6304 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
6305 my $event_in_current_calendar = 0;
6307 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
6308 if ($temp_cal_id eq $current_cal_id) {
6309 push @selected_cal_events, $event_id;}
6310 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6311 if ($temp_cal_id eq $background_cal_id) {
6312 push @{$shared_cal_events{$background_cal_id}}, $event_id;}
6320 $html_output =<<p1;
6321 Cache-control: no-cache,no-store,private
6322 Content-disposition: filename="events.vcs"
6323 Content-Type: text/csv; charset=$lang{charset}
6325 BEGIN:VCALENDAR
6326 PRODID:-//Plans//EN
6327 VERSION:1.0
6328 METHOD:PUBLISH
6330 #initialize loop variables
6331 #$current_timestamp = $list_start_timestamp;
6332 $current_month = $start_month;
6333 $current_year = $start_year;
6336 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) {
6337 my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
6338 my $current_month_end_timestamp = &find_end_of_month($current_month, $current_year);
6339 #display events for selected calendar
6340 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) {
6341 my %event = %{$events{$event_id}};
6343 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6344 $html_output .= &event2vcal(\%event)."\n";
6347 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6348 #list events for that calendar
6349 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) {
6350 my %event = %{$events{$event_id}};
6352 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6353 $html_output .= &event2vcal(\%event)."\n";
6358 #increment to the next month--the method used
6359 #here is the most painless way of making
6360 #this work the right way in all cases.
6361 $current_month +=1;
6362 if ($current_month == 12) {
6363 $current_month=0;
6365 $current_year++;
6369 $html_output .=<<p1;
6370 END:VCALENDAR
6373 $html_output .= $debug_info;
6374 print $html_output;
6380 sub ascii_text_cal {
6381 ($start_month, $start_year, $end_month, $end_year) = @_;
6383 #calculate where to start and end the list
6385 #format for timegm: timegm($sec,$min,$hour,$mday,$mon,$year);
6386 my $list_start_timestamp = timegm(0,0,0,1,$start_month,$start_year);
6387 my $list_end_timestamp = &find_end_of_month($end_month, $end_year);
6389 # loop through all the events.
6391 #Create an array of events which fall
6392 # within the current list view dates
6393 my @selected_cal_events;
6395 #and a funky data structure for the background calendars
6396 # each element of this hash will be an array.
6397 my $shared_cal_events={}; #empty hash
6399 foreach $event_id (keys %events) {
6400 if (&time_overlap($events{$event_id}{start},$events{$event_id}{end},$list_start_timestamp,$list_end_timestamp)) {
6401 my $done = 0;
6402 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
6403 if ($temp_cal_id eq $current_cal_id) {
6404 push @selected_cal_events, $event_id;}
6405 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6406 if ($temp_cal_id eq $background_cal_id) {
6407 push @{$shared_cal_events{$background_cal_id}}, $event_id;
6408 $done = 1;
6409 last;
6412 if ($done == 1) {last;}
6417 $html_output =<<p1;
6418 Cache-control: no-cache,no-store,private
6419 Content-Type: text/plain; charset=$lang{charset}\n\n
6421 #initialize loop variables
6422 #$current_timestamp = $list_start_timestamp;
6424 $current_month = $start_month;
6425 $current_year = $start_year;
6427 while ($current_year < $end_year || ($current_year == $end_year && $current_month <= $end_month)) {
6428 my $current_month_start_timestamp = timegm(0,0,0,1,$current_month,$current_year);
6429 my $current_month_end_timestamp = &find_end_of_month($current_month,$current_year);
6431 $html_output .=<<p1;
6433 *******************************************
6434 $months[$current_month] $current_year
6435 *******************************************
6437 * $current_calendar{title}
6439 #display events for selected calendar
6440 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @selected_cal_events) {
6441 %event = %{$events{$event_id}};
6443 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6444 @event_start_timestamp_array = gmtime $event{start};
6445 my $event_time = "";
6446 if ($event{days} == 1) {
6447 #single-day event
6448 $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] ".($event_start_timestamp_array[5]+1900);
6449 if ($event{all_day_event} ne "1") {
6450 $event_time = &nice_time_range_format($event{start}, $event{end});
6451 $event_time = " ($event_time)";
6453 } else { #multi-day event
6455 $date_string = &nice_date_range_format($event{start}, $event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
6457 my $event_details = $event{details};
6458 $event_details =~ s/\n[ \t\r\f]+/\n/g;
6459 chomp $event_details;
6461 #indent each line of the details
6462 $event_details =~ s/\n/\n /g;
6465 $html_output .=" $date_string$event_time: $event{title}\n";
6466 if ($event_details ne "") {
6467 $html_output .= " $event_details\n";
6469 $html_output .= "\n";
6473 foreach $background_cal_id (keys %{$current_calendar{local_background_calendars}}) {
6474 $html_output .=<<p1;
6475 * $calendars{$background_cal_id}{title}
6477 #list events for that calendar
6478 foreach $event_id (sort {$events{$a}{start} <=> $events{$b}{start}} @{$shared_cal_events{$background_cal_id}}) {
6479 my %event = %{$events{$event_id}};
6481 if (&time_overlap($event{start},$event{end},$current_month_start_timestamp, $current_month_end_timestamp)) {
6482 @event_start_timestamp_array = gmtime $event{start};
6483 my $event_time = "";
6484 if ($event{days} == 1) {
6485 #single-day event
6486 $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] ".($event_start_timestamp_array[5]+1900);
6487 if ($event{all_day_event} ne "1") {
6488 $event_time = &nice_time_range_format($event{start}, $event{end});
6489 $event_time = " ($event_time)";
6491 } else { #multi-day event
6493 $date_string = &nice_date_range_format($event{start}, $event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
6495 my $event_details = $event{details};
6496 $event_details =~ s/\n[ \t\r\f]+/\n/g;
6497 chomp $event_details;
6499 #indent each line of the details
6500 $event_details =~ s/\n/\n /g;
6503 $html_output .=" $date_string$event_time: $event{title}\n";
6504 if ($event_details ne "") {
6505 $html_output .= " $event_details\n";
6507 $html_output .= "\n";
6512 #increment to the next month--the method used
6513 #here is the most painless way of making
6514 #this work the right way in all cases.
6515 $current_month +=1;
6516 if ($current_month == 12) {
6517 $current_month=0;
6518 $current_year++;
6521 $html_output .= $debug_info;
6522 print $html_output;
6524 } #********************end ascii_text_cal subroutine**********************
6526 sub ascii_text_event {
6527 my %current_event = %{$events{$current_event_id}};
6529 $html_output =<<p1;
6530 Cache-control: no-cache,no-store,private
6531 Content-Type: text/plain; charset=$lang{charset}\n\n
6535 my @event_start_timestamp_array = gmtime $current_event{start};
6536 my $date_string="";
6538 my $event_time = "";
6539 if ($current_event{days} == 1) {
6540 #single-day event
6541 $date_string="$months_abv[$event_start_timestamp_array[4]] $event_start_timestamp_array[3] ".($event_start_timestamp_array[5]+1900);
6542 if ($current_event{all_day_event} ne "1") {
6543 $event_time = &nice_time_range_format($current_event{start}, $current_event{end});
6544 $event_time = "($event_time)";
6546 } else { #multi-day event
6548 $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, "-")." ".($event_start_timestamp_array[5]+1900);
6550 my $event_details = $current_event{details};
6551 $event_details =~ s/\n\s+/\n/g;
6552 $event_details =~ s/\n{2,}/\n/g;
6553 chomp $event_details;
6555 #indent each line of the details
6556 $event_details =~ s/\n/\n /g;
6559 $html_output .=" $date_string$event_time: $current_event{title}\n";
6560 if ($event_details ne "") {
6561 $html_output .= " $event_details\n\n";
6563 $html_output .= $debug_info;
6564 print $html_output;
6566 } #********************end ascii_text_event subroutine**********************
6570 sub icalendar_export_event { # only for 1 event
6572 # when exporting to outlook, plans uses the vcalendar standard.
6573 # (http://www.imc.org/rfc2445)
6574 # This standard is horribly supported by MS outlook (outlook 2000, at the
6575 # time of this writing. Outlook refuses to correctly interpret the
6576 # date-time strings in the following ways:
6578 # 1. If the date-time parameter does not specify a time (only a date), do you
6579 # think outlook sets its "all-day event" flag? Nope. It just assumes the
6580 # event occurs at 000000 hours (12 midnight).
6582 # 2. if no time zone is specified, the date-time string is supposed to be
6583 # interpreted as if it applied to the *current* timezone the user's computer
6584 # is in (according to the standard). Do you think outlook does this? Nope.
6585 # If no timezone is specified, outlook assumes the time zone is GMT. As if this
6586 # weren't enough, outlook "helpfully" adjusts the time to the user's time zone.
6587 # Depending on how far a user is from GMT, this may cause the day to change.
6589 # Since there's no way to predict what time zone a user is in, it is impossible
6590 # to compensate on the server side for outlook's stupidity. The workaround is
6591 # to generate event times for each event (even though this is misleading because
6592 # the events are all-day events), and force all the event times to 12 noon.
6593 # This puts them as far from the previous and next days as possible, giving the
6594 # least chance for outlook to screw up the day when it does its adjustment.
6596 my %current_event = %{$events{$current_event_id}};
6598 my $ical_string = &event2ical(\%current_event);
6600 #Content-type: text/plain
6601 #Last-modified: Wed, 30 Jan 2002 22:43:12 GMT
6602 $html_output =<<p1;
6603 Content-type: text/x-vcalendar
6604 Content-disposition: filename="event.ics"
6606 BEGIN:VCALENDAR
6607 PRODID:-//Plans//EN
6608 VERSION:2.0
6609 METHOD:PUBLISH
6610 $ical_string
6611 END:VCALENDAR
6614 print $html_output;
6616 } #********************end vcalendar_export subroutine**********************
6623 sub vcalendar_export_event { # only for 1 event
6625 my %current_event = %{$events{$current_event_id}};
6627 $vcal_string .= &event2vcal(\%current_event);
6629 #my $last_modified = &formatted_time($rightnow, "md mn yy hh:mm:ss GMT");
6630 #Last-modified: $last_modified
6632 #Content-type: text/plain
6633 $html_output =<<p1;
6634 Content-type: text/vcs
6635 Content-disposition: filename="event.vcs"
6637 BEGIN:VCALENDAR
6638 PRODID:-//Plans//EN
6639 VERSION:1.0
6640 METHOD:PUBLISH
6641 $vcal_string
6642 END:VCALENDAR
6645 print $html_output;
6647 } #********************end vcalendar_export_event subroutine**********************
6651 sub calculate_recurring_events {
6652 my ($start_timestamp, $recurrence_parms_ref) = @_;
6654 my %recurrence_parms = %{$recurrence_parms_ref};
6655 my @recurring_events_array = ();
6656 my @custom_months = @{$recurrence_parms{'custom_months'}};
6658 my @timestamp_array = gmtime $start_timestamp;
6660 #$debug_info .= "start timestamp: $start_timestamp\n";
6661 #foreach $custom_month (@custom_months)
6662 # {$debug_info .= "custom month: $custom_month\n";}
6664 #my $start_timestamp = $start_timestamp+50;
6665 #calculate the weekday_in_month_count for the start timestamp
6666 # (is it the first tuesday? second saturday? This is required for
6667 # things to work right.
6669 $real_year = 1900 + $timestamp_array[5];
6670 $temp_start_timestamp = timegm(0,0,0,1,$timestamp_array[4],$real_year);
6671 #$debug_info .= "month_start_timestamp: $temp_start_timestamp\n";
6672 @temp_start_timestamp_array = gmtime($temp_start_timestamp);
6674 # $debug_info .= <<p1;
6675 #start timestamp: $start_timestamp<br/>
6676 #end timestamp: $recurrence_parms{'recur_end_timestamp'}<br/>
6677 #the start timestamp ($months[$timestamp_array[4]] $timestamp_array[3], $real_year) <br/>
6678 #the temp start timestamp ($months[$temp_start_timestamp_array[4]] $temp_start_timestamp_array[3], $temp_start_timestamp_array[5]) <br/>
6681 my $weekday_in_month_count = 0;
6682 #figure out what weekday of the month the start timestamp is
6683 for (;$temp_start_timestamp < $start_timestamp;$temp_start_timestamp+=86400) {
6684 @temp_start_timestamp_array = gmtime($temp_start_timestamp);
6685 if ($temp_start_timestamp_array[6] == $timestamp_array[6]) {
6686 $weekday_in_month_count++;
6690 #this must be done, or the week-of-month recurring dates will be hosed
6691 #@temp_array = gmtime $start_timestamp;
6692 #my $current_month = $temp_array[4];
6693 my $last_week=0;
6696 # set the start timestamp to a day boundary.
6697 my $boundary_timestamp = timegm(0,0,0,$timestamp_array[3],$timestamp_array[4],$real_year);
6699 my $timed_event_diff = $start_timestamp - $boundary_timestamp;
6700 $start_timestamp = $boundary_timestamp;
6702 #$debug_info .= "start timestamp (day boundary): $start_timestamp\n";
6706 # The recurring event algorithm loops through each day in the timeframe
6707 # and tests its validity against the recurrence parameters.
6709 # These tests take the form of "assumed valid unless proven otherwise"
6710 # Doing it this way lets the various recurrence type tests operate
6711 # independently of each other, while looping only once through the timeframe
6713 for ($recur_timestamp = $start_timestamp; $recur_timestamp <= $recurrence_parms{'recur_end_timestamp'}; $recur_timestamp += 86400) {
6714 $last_week=0;
6715 my @recur_timestamp_array = gmtime $recur_timestamp;
6716 my $current_month = $recur_timestamp_array[4];
6718 #look a week ahead, to see if the current weekday is the last one in the month
6719 my $recur_timestamp_next_week = $recur_timestamp+604800;
6720 my @recur_timestamp_next_week_array = gmtime $recur_timestamp_next_week;
6722 $last_week = 1 if ($current_month != $recur_timestamp_next_week_array[4]);
6724 $real_year = 1900 + $recur_timestamp_array[5];
6726 $recur_timestamp_valid=1;
6727 if ($recurrence_parms{'recurrence_type'} eq "same_day_of_month") {
6728 $recur_timestamp_valid=0 if ($recur_timestamp_array[3] != $timestamp_array[3]);
6729 } elsif ($recurrence_parms{'recurrence_type'} eq "same_day_of_week") {
6730 if ($recur_timestamp_array[6] != $timestamp_array[6]) {
6731 $recur_timestamp_valid=0;
6732 } elsif ($recurrence_parms{'weekday_of_month_type'} eq "only_first_week") {
6733 $recur_timestamp_valid=0 if ($weekday_in_month_count != 0);
6734 } elsif ($recurrence_parms{'weekday_of_month_type'} eq "only_second_week") {
6735 $recur_timestamp_valid=0 if ($weekday_in_month_count != 1);
6736 } elsif ($recurrence_parms{'weekday_of_month_type'} eq "only_third_week") {
6737 $recur_timestamp_valid=0 if ($weekday_in_month_count != 2);
6738 } elsif ($recurrence_parms{'weekday_of_month_type'} eq "only_fourth_week") {
6739 $recur_timestamp_valid=0 if ($weekday_in_month_count != 3);
6740 } elsif ($recurrence_parms{'weekday_of_month_type'} eq "only_fifth_week") {
6741 $recur_timestamp_valid=0 if ($weekday_in_month_count != 4);
6742 } elsif ($recurrence_parms{'weekday_of_month_type'} eq "only_last_week") {
6743 if ($last_week != 1) {
6744 $recur_timestamp_valid=0;
6745 } else {
6746 #$debug_info .= "timestamp: $recur_timestamp\n";
6747 #$debug_info .= "current month: $current_month\n";
6748 #$debug_info .= "lookahead timestamp: $recur_timestamp_next_week\n";
6749 #$debug_info .= "lookahead month: $recur_timestamp_next_week_array[4]\n";
6752 } elsif ($recurrence_parms{'recurrence_type'} eq "every_x_days") {
6753 #$debug_info .= $q->param('every_x_days');
6754 #$debug_info .= "\n";
6755 $recur_timestamp_valid=0 if (($recur_timestamp - $start_timestamp) % (86400 * $recurrence_parms{'every_x_days'}) !=0);
6756 } elsif ($recurrence_parms{'recurrence_type'} eq "every_x_weeks") {
6757 #$debug_info .= ($q->param('every_x_weeks')."\n");
6758 $recur_timestamp_valid=0 if (($recur_timestamp - $start_timestamp) % (86400 * 7 * $recurrence_parms{'every_x_weeks'}) !=0);
6761 if ($recurrence_parms{'year_fit_type'} eq "custom_months") {
6762 my $month_valid=0;
6763 foreach $custom_month (@custom_months) {
6764 $month_valid=1 if ($custom_month == $recur_timestamp_array[4]);
6766 $recur_timestamp_valid=0 if ($month_valid == 0);
6769 if ($recur_timestamp_valid == 1) {
6770 push @recurring_events_array, $recur_timestamp+$timed_event_diff;
6771 my $real_year = $recur_timestamp_array[5]+1900;
6774 #count how many of the event's weekdays we have come across in
6775 #each month. This is for validating events that occur on the
6776 #second tuesday, fifth monday, etc.
6777 if ($recur_timestamp_array[6] == $timestamp_array[6]) {
6778 $weekday_in_month_count++;
6781 #reset week_in_month count if this is the last week in the month
6782 $weekday_in_month_count=0 if ($last_week == 1 && $recur_timestamp_array[6] == $timestamp_array[6]);
6785 if (scalar @recurring_events_array == 0) {
6786 $debug_info .= "Error! No valid recurring event dates found!\n";
6789 #$debug_info .= "returning ".(scalar @recurring_events_array)." recurring events\n";
6791 return \@recurring_events_array;
6795 sub verify_date() {
6796 # $date is of the format similar to mm/dd/yy (or a permutation like dd/mm/yy)
6797 my ($date, $recurrence_parms_ref) = @_;
6798 my %recurrence_parms = %{$recurrence_parms_ref};
6800 my $results="";
6802 if ($date !~ /^(\w{1,2}\W\w{1,2}\W\w{2,4}|\w{1,2}\W\w{2,4}\W\w{1,2}|\w{2,4}\W\w{1,2}\W\w{1,2})$/) {
6803 $lang{date_verify_err0} =~ s/###date###/$date/;
6804 $lang{date_verify_err0} =~ s/###format###/$current_calendar{date_format}/;
6805 $results .= $lang{date_verify_err0}."\n";
6808 if ($recurrence_parms{'recurrence_type'} eq "every_x_days") {
6809 if ($recurrence_parms{'every_x_days'} == 0) {
6810 $results .= $lang{date_verify_err7}."\n"};
6811 } elsif ($recurrence_parms{'recurrence_type'} eq "every_x_weeks") {
6812 if ($recurrence_parms{'every_x_weeks'} == 0) {
6813 $results .= $lang{date_verify_err8}."\n"};
6818 if ($date eq "") {
6819 $results .= $lang{date_verify_err1}."\n";
6822 my ($mon, $day, $year) = &format2mdy($date, $current_calendar{date_format});
6824 if ($mon < 1 || $mon > 12) {
6825 $lang{date_verify_err4} =~ s/###month###/$mon/;
6826 $results .= $lang{date_verify_err4}."\n";
6829 $mon --; # convert month to 0-11 format
6831 if ($day < 1 || $day > 31) {
6832 $lang{date_verify_err5} =~ s/###day###/$day/;
6833 $results .= $lang{date_verify_err5}."\n";
6836 if ($year < 100) {$year+=2000;}
6838 if ($year < 1902 || $year > 2037) {
6839 $lang{date_verify_err6} =~ s/###year###/$year/;
6840 $results .= $lang{date_verify_err6}."\n";
6844 return $results;
6847 sub verify_time {
6848 my ($time) = @_;
6849 my $results="";
6850 if($options{twentyfour_hour_format}) {
6851 if ($time !~ /(\d+):(\d+)/) {
6852 $lang{time_verify_err0} =~ s/\{0\}/$time/;
6853 $results .= $lang{time_verify_err0};
6854 } else {
6855 my $hours = $1;
6856 my $minutes = $2;
6857 if ($hours > 23 || $hours < 0){
6858 $lang{time_verify_err1} =~ s/\{0\}/$hours/;
6859 $results .= $lang{time_verify_err1};
6862 if ($minutes > 59 || $minutes < 0){
6863 $lang{time_verify_err2} =~ s/\{0\}/$minutes/;
6864 $results .= $lang{time_verify_err2};
6867 } else {
6869 if ($time !~ /(\d+):(\d+)\s*($lang{am}|$lang{pm})/) {
6870 $lang{time_verify_err0} =~ s/\{0\}/$time/;
6871 $results .= $lang{time_verify_err0};
6872 } else {
6873 my $hours = $1;
6874 my $minutes = $2;
6875 my $ampm = $3;
6877 if ($hours > 12 || $hours < 0) {
6878 $lang{time_verify_err1} =~ s/\{0\}/$hours/;
6879 $results .= $lang{time_verify_err1};
6882 if ($minutes > 60 || $minutes < 0) {
6883 $lang{time_verify_err2} =~ s/\{0\}/$minutes/;
6884 $results .= $lang{time_verify_err2};
6889 return $results;
6894 sub preview_date {
6895 my $html_output .=<<p1;
6896 Cache-control: no-cache,no-store,private
6897 Content-Type: text/html; charset=$lang{charset}\n
6898 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
6900 <html>
6901 <head>
6902 <meta http-equiv="pragma" content="no-cache">
6903 <link rel="stylesheet" href="$css_path" type="text/css" media=screen>
6904 <title>$lang{date_preview_title}</title>
6905 </head>
6906 <body>
6908 <div class="info_box">
6909 <span class="cal_title">
6910 $lang{date_preview_title}
6911 </span>
6914 my %recurrence_parms;
6915 $recurrence_parms{'recurrence_type'} = $q->param('recurrence_type');
6916 $recurrence_parms{'weekday_of_month_type'} = $q->param('weekday_of_month_type');
6917 $recurrence_parms{'every_x_days'} = $q->param('every_x_days');
6918 $recurrence_parms{'every_x_weeks'} = $q->param('every_x_weeks');
6919 $recurrence_parms{'year_fit_type'} = $q->param('year_fit_type');
6920 $recurrence_parms{'recur_end_date'} = $q->param('recur_end_date');
6921 $recurrence_parms{'recur_end_timestamp'} = 0;
6923 my @custom_months = $q->param('custom_months');
6925 #my @custom_months = split(/\D+/, $q->param('custom_months'));
6926 #$debug_info .= (scalar @custom_months)." custom months\n";
6927 #$debug_info .= "q->param('custom_months'): ".$q->param('custom_months')."\n";
6929 $recurrence_parms{'custom_months'} = \@custom_months;
6931 my $recurring_event = $q->param('recurring_event');
6932 my $event_start_date = $q->param('evt_start_date');
6933 my $recur_end_date = $q->param('recur_end_date');
6934 my $event_days = $q->param('evt_days');
6935 my $event_start_time = $q->param('evt_start_time');
6936 my $event_end_time = $q->param('evt_end_time');
6937 my $all_day_event = $q->param('all_day_event');
6939 #my $event_cal_id = $current_cal_id;
6940 #my %current_calendar = %{$calendars{$event_cal_id}};
6942 my $date_valid = &verify_date($event_start_date);
6944 if ($event_days eq "") {
6945 $date_valid = $lang{date_verify_err2};
6947 if ($event_days =~ m/\D/ || $event_days <= 0) {
6948 my $temp = $lang{date_verify_err3};
6949 $temp =~ s/\$1/$event_days/;
6950 $date_valid = $temp;
6954 if ($recurring_event) {
6955 my $temp .= &verify_date($recurrence_parms{'recur_end_date'}, \%recurrence_parms);
6956 if ($temp ne "") {
6957 $date_valid .= "\n$lang{date_verify_for_recurring_end_date}\n<p style=\"margin:0;padding-left:1em;\">$temp</p>";
6961 if ($date_valid eq "") {
6962 my ($start_mon, $start_mday, $start_year) = &format2mdy($event_start_date, $current_calendar{date_format});
6963 my ($recur_end_mon, $recur_end_mday, $recur_end_year) = &format2mdy($recurrence_parms{'recur_end_date'}, $current_calendar{date_format});
6964 $start_mon--;
6965 $recur_end_mon--;
6967 #calculate start timestamp
6968 #$event_start_timestamp = timegm(0,0,0,$start_mday,$start_mon,$start_year);
6970 #$debug_info .= "(preview_date) start_mday: $start_mday\n";
6971 #$debug_info .= "(preview_date) start_mon: $start_mon\n";
6972 #$debug_info .= "(preview_date) start_year: $start_year\n";
6973 #$debug_info .= "(preview_date) event_days: $event_days\n";
6974 #$debug_info .= "(preview_date) event_start_time: $event_start_time\n";
6975 #$debug_info .= "(preview_date) event_end_time: $event_end_time\n";
6976 #$debug_info .= "(preview_date) all_day_event: $all_day_event\n";
6978 my ($event_start_timestamp, $event_end_timestamp) = &timestamp_from_datetime($start_mday,$start_mon,$start_year,$event_days,$event_start_time,$event_end_time,$all_day_event);
6981 @timestamp_array = gmtime $event_start_timestamp;
6982 my $real_year = $timestamp_array[5]+1900;
6984 if ($recurring_event == 1) {
6985 #calculate end timestamp
6986 $recurrence_parms{'recur_end_timestamp'} = timegm(0,0,0,$recur_end_mday,$recur_end_mon,$recur_end_year);
6988 $html_output .= <<p1;
6989 <p>$lang{date_preview_recurring_event_falls_on}</p>
6992 my @recurring_events_array = @{&calculate_recurring_events($event_start_timestamp, \%recurrence_parms)};
6993 foreach $recurring_event_timestamp (@recurring_events_array) {
6994 $timestamp1 = $recurring_event_timestamp;
6995 $timestamp2 = $recurring_event_timestamp + 86400 * ($event_days-1);
6996 if ($timestamp1 == $timestamp2) {$timestamp2++;}
6998 $date_range = &nice_date_range_format($timestamp1, $timestamp2, "-");
6999 $html_output .= <<p1;
7000 <p style="font-weight:bold;">$date_range</p>
7005 } else {
7006 my $date = "";
7007 $timestamp1 = $event_start_timestamp;
7008 $timestamp2 = $event_start_timestamp + 86400 * ($event_days-1);
7009 if ($timestamp1 == $timestamp2) {$timestamp2++;}
7010 $date_range = &nice_date_range_format($timestamp1, $timestamp2, "-");
7012 $html_output .= <<p1;
7013 <p>$lang{date_preview_this_event_falls_on}</p>
7014 <p style="font-weight:bold;">
7015 $date_range
7016 </p>
7020 } else {
7021 $date_valid =~ s/\n/<br\/>/g;
7022 $html_output .= "<p>$date_valid</p>";
7027 $html_output .=<<p1;
7028 </div>
7031 #$html_output .="$debug_info";
7032 $debug_info =~ s/\n/<br\/>/g;
7034 $html_output .=<<p1;
7035 $debug_info
7036 </body>
7037 </html>
7040 print $html_output;
7041 } # end preview date subroutine
7045 sub validate_event {
7046 my $results = "";
7047 my $event_title = $q->param('evt_title');
7048 my $all_day_event = $q->param('all_day_event');
7049 my $event_start_date = $q->param('evt_start_date');
7050 my $event_start_time = $q->param('evt_start_time');
7051 my $event_end_time = $q->param('evt_end_time');
7052 my $event_days = $q->param('evt_days');
7054 my $date_valid = &verify_date($event_start_date);
7056 if ($date_valid eq "") {
7057 if ($all_day_event ne "1") {
7058 my $verify_time_results = &verify_time($event_start_time);
7059 if ($verify_time_results ne "") {
7060 my @sub_results = split("\n", $verify_time_results);
7061 foreach $sub_result (@sub_results) {
7062 $date_valid .= "[error]$lang{update_event_err14} $sub_result<br/>";
7066 my $verify_time_results = &verify_time($event_end_time);
7067 if ($verify_time_results ne "") {
7068 my @sub_results = split("\n", $verify_time_results);
7069 foreach $sub_result (@sub_results) {
7070 $date_valid .= "[error]$lang{update_event_err15} $sub_result<br/>";
7077 if ($event_title eq "") {
7078 $date_valid = $lang{update_event_err4};
7081 if ($event_days eq "") {
7082 $date_valid = $lang{date_verify_err2};
7085 if ($event_days =~ m/\D/ || $event_days <= 0) {
7086 my $temp = $lang{date_verify_err3};
7087 $temp =~ s/\$1/$event_days/;
7088 $date_valid = $temp;
7091 if ($date_valid eq "") {
7092 $results .= <<p1;
7093 success = true;
7094 messages = '';
7096 } else {
7097 $date_valid =~ s/\//\\\//g;
7098 $date_valid =~ s/\n/<br\/>/g;
7099 $date_valid =~ s/"/\\"/g;
7100 $date_valid =~ s/'/\\'/g;
7102 $results .= <<p1;
7103 success = false;
7104 messages = '$date_valid';
7109 $debug_info =~ s/\//\\\//g;
7110 $debug_info =~ s/\n/<br\/>/g;
7111 $debug_info =~ s/"/\\"/g;
7112 $debug_info =~ s/'/\\'/g;
7113 $results =~ s/###debug_info###/$debug_info/;
7115 print <<p1;
7116 Cache-control: no-cache,no-store,private
7117 Content-Type: text/html; charset=iso-8859-1\n
7119 $results
7135 sub preview_event {
7137 $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}/g;
7138 $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}/g;
7139 $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g;
7141 my $event_info = &generate_event_details({title => $q->param('evt_title'),
7142 details => $q->param('evt_details'),
7143 cal_id => $current_cal_id,
7144 icon => $q->param('evt_icon'),
7145 bgcolor => $q->param('evt_bgcolor'),
7146 start => "",
7147 end => "",
7148 unit_number => $q->param('unit_number')}, 1);
7150 my $html_output .=<<p1;
7151 Cache-control: no-cache,no-store,private
7152 Content-Type: text/html; charset=$lang{charset}\n
7153 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7155 <html>
7156 <head>
7157 <meta http-equiv="pragma" content="no-cache">
7158 <link rel="stylesheet" href="$css_path" type="text/css" media=screen>
7159 <title>$lang{event_preview_title}</title>
7160 </head>
7161 <body>
7162 <span class="cal_title">
7163 $lang{event_preview_title}
7164 </span>
7165 $event_info
7166 $debug_info
7167 </body>
7168 </html>
7171 print $html_output;
7172 } # preview_event
7174 sub view_event {
7175 #$debug_info .= "(view_event) event $current_event{id} start: $current_event{start} \n" if ($current_event{id} eq "1815");
7176 my %current_event = %{$events{$current_event_id}};
7178 my $event_info = &generate_event_details(\%current_event);
7179 $debug_info =~ s/\n/<br\/>\n/g;
7181 my $html_output .=<<p1;
7182 Cache-control: no-cache,no-store,private
7183 Content-Type: text/html; charset=$lang{charset}\n
7184 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7186 <html>
7187 <head>
7188 <meta http-equiv="pragma" content="no-cache">
7189 <link rel="stylesheet" href="$css_path" type="text/css" media=screen>
7190 <script type="text/javascript" src="$theme_url/lpd.js"></script>
7191 <script type="text/javascript" src="$theme_url/plans.js"></script>
7192 <script type="text/javascript" src="$theme_url/plans_lang.js"></script>
7193 <title>$current_event{title}</title>
7194 </head>
7195 <body onResize="do_onresize()">
7197 $event_info
7198 $debug_info
7199 </body>
7200 </html>
7203 print $html_output;
7204 } # view_event
7206 sub view_events {
7207 #$debug_info .= "(view_event) event $current_event{id} start: $current_event{start} \n" if ($current_event{id} eq "1815");
7209 my @event_id_arr = split (',', $current_event_ids);
7211 my $html_output .=<<p1;
7212 Cache-control: no-cache,no-store,private
7213 Content-Type: text/html; charset=$lang{charset}\n
7214 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7216 <html>
7217 <head>
7218 <meta http-equiv="pragma" content="no-cache">
7219 <link rel="stylesheet" href="$css_path" type="text/css" media=screen> <script type="text/javascript" src="$theme_url/lpd.js"></script> <script type="text/javascript" src="$theme_url/plans.js"></script> <script type="text/javascript" src="$theme_url/plans_lang.js"></script>
7220 <title>@current_event_ids</title>
7221 </head>
7222 <body onResize="do_onresize()">
7225 foreach my $current_event_id ( @event_id_arr ) {
7226 my %current_event = %{$events{$current_event_id}};
7228 my $event_info = &generate_events_details(\%current_event);
7229 $debug_info =~ s/\n/<br\/>\n/g;
7230 $html_output .=<<p2;
7231 $event_info
7232 $debug_info
7236 $html_output .=<<p3;
7237 </body>
7238 </html>
7241 print $html_output;
7242 } # view_events
7244 sub view_pending_event {
7245 my ($pending_event_ref) = @_;
7246 my %pending_event = %{$pending_event_ref};
7248 $event_details_template =~ s/###export event link###/$lang{event_details_export_disable}/g;
7249 $event_details_template =~ s/###edit event link###/$lang{event_details_edit_disable}/g;
7250 $event_details_template =~ s/###email reminder link###/$lang{event_email_reminder_disable}/g;
7253 my $event_info = &generate_event_details(\%pending_event);
7254 $debug_info =~ s/\n/<br\/>\n/g;
7256 my $html_output .=<<p1;
7257 Cache-control: no-cache,no-store,private
7258 Content-Type: text/html; charset=$lang{charset}\n
7259 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7261 <html>
7262 <head>
7263 <meta http-equiv="pragma" content="no-cache">
7264 <link rel="stylesheet" href="$css_path" type="text/css" media=screen>
7265 <script type="text/javascript" src="$theme_url/lpd.js"></script>
7266 <script type="text/javascript" src="$theme_url/plans.js"></script>
7267 <script type="text/javascript" src="$theme_url/plans_lang.js"></script>
7269 <title>$current_event{title}</title>
7270 </head>
7271 <body onResize="do_onresize()">
7273 $event_info
7274 $debug_info
7275 </body>
7276 </html>
7279 print $html_output;
7280 } # view_pending_event
7283 sub email_reminder_prompt {
7284 my %current_event = %{$events{$current_event_id}};
7285 my %previous_current_calendar = %current_calendar;
7286 %current_calendar = %{$calendars{$current_event{cal_ids}[0]}};
7287 $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, " - ");
7288 %current_calendar = %previous_current_calendar;
7291 my $title = "<title>$current_event{title}$lang{email_reminder_title}</title>";
7293 my $results .=<<p1;
7294 <script type="text/javascript" ><!--
7295 var clicked = false;
7297 function address_focus() {
7298 if (!clicked) {
7299 document.email_reminder_submit.email_address.value = "";
7300 clicked=1;
7303 </script>
7305 <body>
7306 <div class="event_details" style="background-color:$current_event{bgcolor};text-align:left;">
7307 <p class="title">
7308 $current_event{title}
7309 </p><p>
7310 $lang{email_reminder_text1}
7311 <br/><span class="date">$date_string</span>
7312 </p><p>
7313 <br/><br/>$lang{email_reminder_text2}
7314 </p>
7316 <form name="email_reminder_submit" action="$script_url/$name" method="POST">
7317 <input type="hidden" name="evt_id" value="$current_event{id}"/>
7318 <input type="hidden" name="email_reminder_confirm" value="1"/>
7319 <input name="email_address" style="width:90%;" value="your_email\@address.com"/ onfocus="address_focus()">
7320 <br/><br/>
7321 <select name="reminder_time">
7322 <option value="604800, $lang{email_reminder_option1}">$lang{email_reminder_option1}</option>
7323 <option value="172800, $lang{email_reminder_option2}">$lang{email_reminder_option2}</option>
7324 <option value="86400, $lang{email_reminder_option3}">$lang{email_reminder_option3}</option>
7325 <option value="3600, $lang{email_reminder_option4}">$lang{email_reminder_option4}</option>
7326 <option value="1800, $lang{email_reminder_option5}">$lang{email_reminder_option5}</option>
7327 <option value="900, $lang{email_reminder_option6}">$lang{email_reminder_option6}</option>
7328 </select>
7329 $lang{email_reminder_text3}
7330 <br/><br/>
7331 $lang{email_reminder_text7}
7332 <textarea name="extra_text" style="width:90%" rows="4">
7333 </textarea>
7334 <br/><br/>
7335 <input type="checkbox" name="send_test_now" value="1"> $lang{email_reminder_text4}
7336 <br/><br/>
7339 if ($current_event{series_id} ne "") {
7340 $results .=<<p1;
7341 <input type="checkbox" name="all_in_series" value="1"/> $lang{email_reminder_text6}
7342 <br/><br/>
7345 $results .=<<p1;
7346 <input type="submit" value="$lang{email_reminder_text5}"/>
7347 </form>
7348 </div>
7349 </body>
7352 $template_html =~ s/<title>.*<\/title>/$title/s;
7353 $template_html =~ s/<body.*>.*<\/body>/$results/s;
7354 $template_html =~ s/###css file###/$css_path/g;
7356 print <<p1;
7357 Cache-control: no-cache,no-store,private
7358 Content-Type: text/html; charset=$lang{charset}\n
7359 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7360 $template_html
7362 } # email_reminder_prompt
7365 sub email_reminder_confirm {
7366 my %current_event = %{$events{$current_event_id}};
7368 my $reminder_results = "";
7369 my $to_address = $q->param('email_address');
7370 my $extra_text = $q->param('extra_text');
7371 $to_address =~ s/\s//g;
7372 $to_address =~ s/;/,/g;
7373 chomp $to_address;
7375 my ($reminder_seconds, $reminder_time) = split(/, ?/,$q->param('reminder_time'));
7376 $reminder_time = lc $reminder_time;
7378 my $email_valid = &validate_emails($to_address);
7380 if ($email_valid ne "") {
7381 $reminder_results = $lang{email_reminder_invalid_address};
7382 $reminder_results =~ s/###address###/$email_valid/g;
7383 } else {
7384 my @event_reminder_ids = ($current_event{id});
7385 my @future_event_reminder_ids;
7386 if ($q->param('all_in_series') ne "") {
7387 @event_reminder_ids = &get_events_in_series($current_event{series_id});
7388 &normalize_timezone();
7391 foreach $event_reminder_id (@event_reminder_ids) {
7392 if ($events{$event_reminder_id}{start} > $rightnow) {
7393 push @future_event_reminder_ids, $event_reminder_id;
7397 foreach $event_reminder_id (@future_event_reminder_ids) {
7398 # assemble email reminder xml
7399 my $reminder_xml = "";
7400 $reminder_xml .= &xml_store($event_reminder_id, "evt_id").
7401 &xml_store($reminder_seconds, "before").
7402 &xml_store($to_address, "email_address").
7403 &xml_store($extra_text, "extra_text").
7404 &xml_store("$script_url/$name", "script_url").
7405 &xml_store($rightnow, "timestamp");
7406 $reminder_xml = "<email_reminder>$reminder_xml</email_reminder>\n";
7408 # write email reminder to file
7409 open (FH, ">>$options{email_reminders_datafile}") || ($debug_info .="<br/>Unable to open email reminders data file $options{email_reminders_datafile} for writing<br/>");
7410 print FH $reminder_xml;
7411 close FH;
7414 my $test_reminder_results = "";
7415 if ($q->param('send_test_now') == 1) {
7416 my $reminder_text = $lang{email_reminder_test_text};
7417 $reminder_text =~ s/###reminder_time###/$reminder_time/g;
7419 my $date_string = &nice_date_range_format($current_event{start}, $current_event{end}, " - ");
7421 my $event_time = "";
7422 if ($current_event{all_day_event} ne "1") {
7423 $event_time = &nice_time_range_format($current_event{start}, $current_event{end});
7425 $reminder_text =~ s/###time###/$event_time/g;
7426 $reminder_text =~ s/###title###/$current_event{title}/g;
7427 $reminder_text =~ s/###date###/$date_string/g;
7428 $reminder_text =~ s/###extra text###/$extra_text/g;
7429 $reminder_text =~ s/###details###/$current_event{details}/g;
7430 $reminder_text =~ s/###link###/$script_url\/$name?view_event=1&evt_id=$current_event{id}/g;
7432 #$debug_info .= "$reminder_text\n";
7434 $test_reminder_results = &send_email_reminder(\%current_event, $to_address, $reminder_text);
7435 if ($test_reminder_results eq "1") {
7436 $test_reminder_results = $lang{email_reminder_test_success};
7437 $test_reminder_results =~ s/###address###/$to_address/g;
7438 } else {
7439 $test_reminder_results = $lang{email_reminder_test_fail};
7440 $test_reminder_results =~ s/###results###/$test_reminder_results/g;
7444 $lang{email_reminder_results1} =~ s/###address###/$to_address/g;
7445 $lang{email_reminder_results1} =~ s/###reminder time###/$reminder_time/g;
7447 if ($q->param('send_test_now') == 1) {
7448 $lang{email_reminder_results1} .= $lang{email_reminder_results3}} else {
7449 $lang{email_reminder_results1} .= $lang{email_reminder_results2}}
7452 $reminder_results = <<p1;
7453 $lang{email_reminder_results1}
7454 <br/><br/>
7455 $test_reminder_results
7459 $debug_info =~ s/\n/<br\/>\n/g;
7461 my $html_output .=<<p1;
7462 Cache-control: no-cache,no-store,private
7463 Content-Type: text/html; charset=$lang{charset}\n
7464 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7466 <html>
7467 <head>
7468 <meta http-equiv="pragma" content="no-cache">
7469 <link rel="stylesheet" href="$css_path" type="text/css" media=screen>
7470 <title>$current_event{title}$lang{email_reminder_title}</title>
7471 </head>
7473 <body>
7474 <div class="event_details" style="background-color:$current_event{bgcolor};text-align:left;">
7475 <p style="margin-top:20px;margin-bottom:20px;">
7476 $reminder_results
7477 </p>
7478 </div>
7479 $debug_info
7480 </body>
7481 </html>
7484 print $html_output;
7485 } # email_reminder_confirm
7487 sub detect_remote_calendars() {
7488 my $remote_calendar_url = $q->param('remote_calendar_url');
7489 $remote_calendar_url =~ s/\?.+//;
7490 #$debug_info .= "url: $remote_calendar_url\n";
7492 $remote_calendar_url .= "/" if ($remote_calendar_url !~ /\.cgi$/);
7493 $remote_calendar_base_url = $remote_calendar_url;
7494 $remote_calendar_url .= "?remote_calendar_request=1&get_public_calendars=1";
7495 #$debug_info .= "remote_calendar_url: $remote_calendar_url\n";
7497 my $xml_results = &get_remote_file($remote_calendar_url);
7499 #$debug_info .= "xml results: ".&xml2html($xml_results)."\n";
7500 #$results =~ s/>/&gt;/g;
7501 #$results =~ s/</&lt;/g;
7503 my %remote_calendars = %{&xml2hash($xml_results)};
7505 my @public_calendars;
7507 if (ref $remote_calendars{'xml'}{public_calendar} eq "ARRAY") {
7508 #$debug_info .= "found remote calendars!\n";
7509 @public_calendars = @{$remote_calendars{'xml'}{public_calendar}};
7510 } else {
7511 #$debug_info .= "found remote calendar: $remote_calendars{'xml'}{public_calendar})\n";
7512 #$debug_info .= "found remote calendar: ".&xml2html($remote_calendars{'xml'}{public_calendar})."\n";
7513 push @public_calendars, $remote_calendars{'xml'}{public_calendar};
7516 $remote_calendar_info .= <<p1;
7517 <p style="clear:both;">
7518 $lang{detect_remote_calendars1} <a target="_blank" href="$remote_calendar_base_url">$remote_calendar_base_url</a>:
7519 </p>
7520 <div style="float:left;width:95%;border:solid 1px #000;">
7521 <form name="cal_merge_form">
7525 my $index = 0;
7526 foreach $temp (@public_calendars) {
7527 my %public_calendar = %{$temp};
7528 my $list_class="list_odd";
7530 my $merge_xml = <<p1;
7531 <remote_calendar>
7532 <type>plans</type><version>$remote_calendars{'xml'}{'plans_version'}</version>
7533 <url>$remote_calendar_base_url</url>
7534 <remote_id>$public_calendar{id}</remote_id>
7535 <password>###password###</password>
7536 </remote_calendar>
7539 #$merge_xml =~ s/\//\\\//g;
7540 $merge_xml =~ s/\n//g;
7541 $merge_xml =~ s/"/\\"/g;
7544 if ($index%2 == 0) {
7545 $list_class="list_even"}
7547 $remote_calendar_info .= <<p1;
7548 <div class="$list_class" style="float:left;clear:left;width:100%;">
7550 #$remote_calendar_info .= "public calendar: ".$remote_calendars{'xml'}{public_calendar}."<br/>";
7551 $remote_calendar_info .= <<p1;
7552 <div style="float:left;font-weight:bold;padding:3px;white-space:nowrap;">$public_calendar{title}</div>
7555 $remote_calendar_info .= <<p1;
7556 <div style="float:left;padding:3px;white-space:nowrap;">$lang{detect_remote_calendars2}<input type="checkbox" id="remote_cal_$index" name="remote_cal_$index" value = "$merge_xml">
7558 if ($public_calendar{requires_password} ne "") {
7559 $remote_calendar_info .= <<p1;
7560 <span style="margin-left:1em;white-space:nowrap;">($lang{detect_remote_calendars3}): <input id="password_$index" name="password_$index" style="width:6em;"></span>
7563 $remote_calendar_info .= <<p1;
7564 </div>
7568 $remote_calendar_info .= <<p1;
7569 </div>
7571 $index++;
7573 $remote_calendar_info .= <<p1;
7574 </form>
7575 </div>
7578 if ($index > 0) {
7579 $remote_calendar_info .= <<p1;
7580 <p style="clear:both;padding-top:1em;"><a href="javascript:merge_selected()">$lang{detect_remote_calendars4}</a></p>
7581 <br/><br/>
7583 } else {
7584 $remote_calendar_info .= <<p1;
7585 <p style="clear:both;padding-top:1em;">$lang{detect_remote_calendars5}</p>
7586 <br/><br/>
7589 #<br style="clear:both;"/>
7590 #<br style="clear:both;"/>
7593 #my $temp_xml_results = $xml_results;
7594 #$temp_xml_results =~ s/>/&gt;/g;
7595 #$temp_xml_results =~ s/</&lt;/g;
7596 #$debug_info .= $temp_xml_results;
7599 my $popup_javascript_info = "";
7601 $popup_javascript_info .=<<p1;
7602 <script type="text/javascript" ><!--
7605 if ($browser_type eq "IE") {
7606 $popup_javascript_info .=<<p1;
7607 function do_onresize() {
7608 opener.info_window_width = document.body.clientWidth;
7609 opener.info_window_height = document.body.clientHeight;
7612 } else {
7613 $popup_javascript_info .=<<p1;
7614 function do_onresize() {
7615 opener.info_window_width = this.outerWidth;
7616 opener.info_window_height = this.outerHeight;
7621 $popup_javascript_info .=<<p1;
7622 function opener_test() {
7623 //alert("about to test opener " + opener.info_window_width);
7624 //opener.test();
7627 function merge_selected() {
7628 var l1=0;
7629 var merge_xml="";
7630 while (document.getElementById("remote_cal_"+l1)) {
7631 var el = document.getElementById("remote_cal_"+l1);
7633 if (el.checked) {
7634 var temp = "";
7635 if (document.getElementById("password_"+l1))
7636 temp = el.value.replace(/###password###/, document.getElementById("password_"+l1).value); else
7637 temp = el.value.replace(/###password###/, "");
7638 merge_xml += temp;
7641 l1++;
7643 if (merge_xml != "")
7644 opener.set_merge_xml("<remote_calendars>"+merge_xml+"</remote_calendars>");
7646 window.close();
7649 //-->
7650 </script>
7654 my $html_output .=<<p1;
7655 Cache-control: no-cache,no-store,private
7656 Content-Type: text/html; charset=$lang{charset}\n
7660 $debug_info =~ s/\n/<br\/>\n/g;
7662 $html_output .=<<p1;
7663 <html>
7664 <head>
7665 <title>$lang{get_remote_calendars}</title>
7666 <link rel="stylesheet" href="$css_path" type="text/css" media="screen"/>
7667 </head>
7668 <body onResize="javascript:do_onresize();">
7669 $popup_javascript_info
7670 <div class="info_box" style="padding:5px;"><br/>
7675 $html_output .=<<p1;
7676 $remote_calendar_info
7677 <br/><br/>
7678 $debug_info
7679 </div>
7680 </body></html>
7682 print $html_output;
7687 sub remote_calendar_request() {
7688 my $html_output .=<<p1;
7689 Cache-control: no-cache,no-store,private
7690 Content-Type: text/xml; charset=$lang{charset}\n
7693 my $results = "";
7694 my $current_cal_ids_string = $q->param('cal_id');
7696 $results .=<<p1;
7697 <plans_version>$plans_version</plans_version>
7700 #$debug_info .= "remote calendar request!";
7702 # if the client requests a list of all calendars that are publically share-able.
7703 if ($q->param('get_public_calendars') eq "1") {
7704 foreach $cal_id (keys %calendars) {
7705 if ($calendars{$cal_id}{allow_remote_calendar_requests}) {
7706 my $temp=$calendars{$cal_id}{remote_calendar_requests_require_password};
7707 $results .=<<p1;
7708 <public_calendar><id>$cal_id</id><title>$calendars{$cal_id}{title}</title><requires_password>$temp</requires_password></public_calendar>
7712 } else { # return xml data for the events.
7714 my @current_cal_ids = ();
7715 my @temp = split (",",$current_cal_ids_string);
7717 my $cal_id_valid=1;
7719 foreach $cal_id (@temp) {
7720 if ($cal_id !~ /\D/) {
7721 push @current_cal_ids, $cal_id;
7722 } else {
7723 $cal_id_valid=0;
7724 $results .= "<error>Invalid calendar ID: $cal_id</error>";
7725 last;
7728 if ($cal_id_valid) {
7729 foreach $current_cal_id (@current_cal_ids) {
7730 $results .=<<p1;
7731 <calendar><id>$current_cal_id</id><title>$calendars{$current_cal_id}{title}</title><gmtime_diff>$calendars{$current_cal_id}{gmtime_diff}</gmtime_diff></calendar>
7735 foreach $current_cal_id (@current_cal_ids) {
7736 foreach $event_id (keys %events) {
7738 my $event_in_current_calendar = 0;
7740 foreach $temp_cal_id (@{$events{$event_id}{cal_ids}}) {
7741 if ($temp_cal_id eq $current_cal_id) {
7742 $event_in_current_calendar = 1;
7743 last;
7747 next if ($event_in_current_calendar == 0);
7749 my $xml_data = &event2xml($events{$event_id});
7750 $results .=<<p1;
7751 $xml_data
7758 if ($debug_info ne "") {
7759 $results .= "<debug_info>$debug_info</debug_info>";}
7761 $html_output .= "<xml>$results</xml>";
7763 print $html_output;
7770 #******************* the following subroutines don't display any HTML **********
7775 sub diagnostic_info() {
7776 my $results = "";
7778 $results .= <<p1;
7779 <b>Script Name:</b>$name<br/>
7780 <br/>
7783 if ($options{email_mode} && !$writable{email_reminders_datafile}) {
7784 $results .=<<p1;
7785 <b>Warning:</b> The email reminders data file: $options{email_reminders_datafile} is not writable. This will
7786 cause some email functions to be disabled or not work correctly.<br/>
7789 if ($options{data_storage_mode} == 0 && !$writable{calendars_file}) {
7790 $results .=<<p1;
7791 <b>Warning:</b> The calendars data file: $options{calendars_file} is not writable. The add/edit calendars tab won't appear
7792 unless this file is writable.<br/>
7795 if ($options{data_storage_mode} == 0 && !$writable{pending_actions_file}) {
7796 $results .=<<p1;
7797 <b>Warning:</b> The pending actions data file: $options{pending_actions_file} is not writable. The add/edit calendars tab won't appear
7798 unless this file is writable.<br/>
7801 if ($options{data_storage_mode} == 0 && !$writable{events_file}) {
7802 $results .=<<p1;
7803 <b>Warning:</b> The events data file: $options{events_file} is not writable. The add/edit events tab won't appear
7804 unless this file is writable.<br/>
7808 my $cwd = `pwd`;
7810 $results .=<<p1;
7811 <b>Plans version:</b> $plans_version<br/>
7812 <b>Perl version:</b> $perl_version<br/>
7813 <b>script name:</b> $name<br/>
7814 <b>script file path:</b> <span style="color:#00f;">$cwd</span><br/>
7815 <b>script url path:</b> $script_url<br/>
7816 <br/>
7817 <b>Theme url:</b> $theme_url<br/>
7818 <b>graphics url:</b> $graphics_url<br/>
7819 <b>icons url:</b> $icons_url<br/>
7820 <br/>
7821 <b>Options:</b><br/>
7824 # blank out options that we don't want public
7825 delete $options{db_name};
7826 delete $options{db_hostname};
7827 delete $options{db_username};
7828 delete $options{db_password_file};
7829 delete $options{mysql_password};
7830 delete $options{salt};
7832 foreach $option (keys %options) {
7833 $results .=<<p1;
7834 <b>$option:</b> $options{$option}<br/>
7837 return $results;
7839 } # end diagnostic subroutine
7842 sub assemble_icon_menus() {
7843 # this function extracts a data structure for the icon menus from the xml definition
7844 my ($data)= @_;
7846 # first, get the menuitems
7847 my @new_menuitems=();
7849 my @menuitems = &xml_extract($data, "menuitem", 0);
7850 if (scalar @menuitems == 0) {
7851 $debug_info .= "Warning. There's a menu with no menuitems. This may be caused by an older version of Perl ( < 5.6).\n";
7852 $debug_info .= "$data";
7853 } else {
7854 foreach my $menuitem (@menuitems) {
7855 #$debug_info .= "menuitem: $menuitem->{data} ($menuitem->{position})<br/>";
7856 my $icon_name = $menuitem->{attributes}{"value"};
7857 my $icon_description = $menuitem->{data};
7858 $icon_description = &encode($icon_description);
7859 $new_menuitems[$menuitem->{position}] = [$icon_name,$icon_description];
7860 #$new_menuitems[$menuitem->{position}] = "name,description";
7864 # then get the submenus
7865 my @submenus = &xml_extract($data, "menu", 0);
7866 foreach $submenu (@submenus) {
7867 my $temp = $submenu->{data};
7868 my $temp2 = $submenu->{attributes}{name};
7869 my @submenuitems = assemble_icon_menus($temp);
7870 #$debug_info .= "submenu: $temp2 ($submenu->{position})<br/>";
7871 $new_menuitems[$submenu->{position}] = [$temp2, \@submenuitems];
7874 return @new_menuitems;
7875 } #******************** end assemble_icon_menus **********************
7878 sub generate_flat_icon_menus {
7879 my ($icons_list, $selected_icon) = @_;
7880 my $return_text="";
7881 #$debug_info .= "selected icon: $selected_icon<br/>";
7883 my $indent = " ";
7884 for ($l1=0;$l1<$index_number;$l1++) {
7885 $indent .= " ";
7888 foreach $icon_ref (@{$icons_list}) {
7889 my $identifier = @{$icon_ref}[1];
7891 if ($identifier =~ /ARRAY/) { # if it's a submenu
7892 $icon_menu_index_number++;
7893 my $submenu_name = @{$icon_ref}[0];
7895 #$debug_info .= "submenu $submenu_name<br/>";
7897 $return_text .= <<p1;
7898 <optgroup label="$submenu_name">
7900 $return_text .= &generate_flat_icon_menus(@{$icon_ref}[1], $selected_icon);
7901 $return_text .= <<p1;
7902 </optgroup>
7904 } else { # if it's a menu item
7905 my $icon_filename = @{$icon_ref}[0];
7906 my $icon_name = @{$icon_ref}[1];
7908 $icon_name = &decode($icon_name);
7909 #$debug_info .= "icon name: $icon_name <br/>";
7910 #$debug_info .= "icon filename: $icon_filename <br/>";
7911 #$debug_info .= "<br/>";
7913 if ($icon_filename eq $selected_icon) {
7914 $return_text .= <<p1;
7915 <option value = "$icon_filename" selected>$icon_name</option>
7917 } else {
7918 $return_text .= <<p1;
7919 <option value = "$icon_filename">$icon_name</option>
7924 return $return_text;
7926 } #******************** end generate_flat_icon_menus **********************
7929 sub get_upcoming_events() {
7930 my $days_before = $q->param('days_before')+0;
7931 my $days_after = $q->param('days_after')+0;
7932 my $background_calendars_mode = $q->param('background_calendars_mode');
7933 my $upcoming_events_id = $q->param('upcoming_events_id');
7934 my $results = "";
7936 my $start = $rightnow - $days_before*86400;
7937 my $end = $rightnow + $days_after*86400;
7938 #$debug_info .= "start: $start\n";
7939 #$debug_info .= "end: $end\n";
7941 #$debug_info .= (scalar keys %events)." events\n";
7942 # clear events
7943 %events = ();
7944 #$debug_info .= (scalar keys %events)." events\n";
7946 my @cal_ids = split(',',$q->param('cal_ids'));
7947 #$debug_info .= "cal_ids[0]: $cal_ids[0]\n";
7948 #$debug_info .= "cal_ids[1]: $cal_ids[1]\n";
7951 #&load_events("all");
7953 #$debug_info .= (scalar keys %events)." events\n";
7956 #$results .= &common_javascript();
7957 my $date_format = lc $current_calendar{date_format};
7958 $results .= "date_format = '$date_format';\n";
7960 my %all_calendar_ids;
7962 foreach $calendar_id (@cal_ids) {
7963 next if ($calendars{$calendar_id}{id} eq "");
7965 foreach $local_background_calendar_id (keys %{$calendars{$calendar_id}{local_background_calendars}}) {
7966 $all_calendar_ids{$local_background_calendar_id} = 1;
7968 $all_calendar_ids{$calendar_id} = 1;
7971 foreach $calendar_id (keys %all_calendar_ids) {
7972 $results .= "calendars['$calendar_id'] = new Calendar({".&calendar2javascript($calendars{$calendar_id})."});\n";
7975 my @temp;
7976 if ($background_calendars_mode ne "none") {
7977 @temp = keys %all_calendar_ids;
7978 } else {
7979 @temp = @cal_ids;
7982 &load_events($start, $end, \@temp);
7983 &normalize_timezone;
7985 $results .= "all_calendars = new Array('".(join "','", keys %all_calendar_ids)."');\n";
7987 foreach $event_id (keys %events) {
7988 $results .= "upcoming_events['$event_id'] = new Event({".&event2javascript($events{$event_id})."});\n";
7989 $results .= "upcoming_events_order.push('$event_id'); \n";
7992 if ($debug_info ne "") {
7993 $debug_info = &javascript_cleanup($debug_info);
7994 #$debug_info = "debug_info = '$debug_info';\n";
7995 $results .= "if ($upcoming_events_id.debug) debug('$debug_info');\n";
7998 $results .= "$upcoming_events_id.plans_theme_url='$theme_url';\n";
7999 $results .= "$upcoming_events_id.show();\n";
8001 my $nice_expires = $rightnow + $options{upcoming_events_cache_seconds};
8002 $nice_expires = uc &formatted_time($nice_expires, "mn/md/yy hh:mm:ss AMPM");
8004 my $cache_line = "Cache-control: no-cache,no-store,private";
8005 $cache_line = "Cache-Control: max-age=$options{upcoming_events_cache_seconds};\nExpires: $nice_expires;" if ($options{upcoming_events_cache_seconds} > 0);
8008 my $html_output .=<<p1;
8009 $cache_line
8010 Content-Type: text/html; charset=$lang{charset}\n
8011 $results
8014 print $html_output;
8023 sub export_calendar_link() {
8024 my $results = "";
8026 $results .=<<p1;
8027 <a href="javascript:document.export_cal_form.submit();">$lang{export}</a> $lang{these_events_to}
8028 <form name="export_cal_form" target="_blank" action="$script_url/$name" method="POST">
8029 <input type="hidden" name="export_calendar" value=1>
8031 <select name="export_type">
8032 <option value="ascii_text">$lang{text_option}
8033 <option value="csv_file">$lang{csv_file}
8034 <option value="csv_file_palm">$lang{csv_file_palm}
8035 <option value="icalendar">$lang{icalendar_option}
8036 <option value="vcalendar">$lang{vcalendar_option}
8037 </select>
8038 </form>
8046 sub add_edit_user() {
8047 my $results = "";
8048 my $status = 1;
8050 my $id = $q->param('user_id');
8051 my $name = $q->param('name');
8052 my $notes = $q->param('notes');
8053 my $password = $q->param('password');
8054 my $new_password = $q->param('new_password');
8055 my $repeat_password = $q->param('repeat_password');
8056 my $delete_flag = $q->param('delete');
8059 #$results .= "add/edit user!";
8060 #$debug_info .= "cal_password: ".$q->param('cal_password')."\n";
8061 #$debug_info .= "logged_in_as_root: $logged_in_as_root\n";
8062 #$debug_info .= "logged_in_as_current_cal_admin: $logged_in_as_current_cal_admin\n";
8064 $results .= "success = false;";
8066 my $login_valid = 0;
8067 # validate password
8068 if ($logged_in_as_root) { # plans 'root' password
8069 $login_valid = 1;} elsif ($logged_in_as_current_cal_admin) { # current calendar admin
8070 $login_valid = 1;}
8072 #$debug_info .= "login_valid: $login_valid\n";
8074 if (!$login_valid) {
8075 if ($delete_flag eq "1") {
8076 $results .= "messages = '$lang{user_not_deleted}';";} else {
8077 $results .= "messages = '$lang{user_not_added}';";}
8078 } else {
8079 # delete?
8080 if ($delete_flag eq "1") {
8081 my $temp = $lang{user_deleted};
8082 $temp =~ s/\$1/$users{$id}{name}/;
8083 $results .= "messages = '$temps';";
8085 delete $user{calendars}{$calendar_id};
8087 #$debug_info .= "user $user_id, ".(scalar keys %{$user{calendars}})." calendars\n";
8089 if (scalar keys %{$user{calendars}} == 0) {
8090 delete $users{$user_id};
8092 &update_user($user_id);
8094 &delete_user($id);
8095 $results .= "success = true;";
8096 $results .= "users = new Array();";
8097 $results .= &generate_users_javascript();
8098 } else {
8099 # add or update?
8100 if ($id eq "") { # add
8102 $password = crypt($password, $options{salt});
8104 my $new_id = $max_user_id+1;
8105 my %cal_refs;
8106 $cal_refs{$current_cal_id}{edit_events} = 1;
8108 $users{$new_id} = {id => $new_id,
8109 name => $name,
8110 notes => $notes,
8111 password => $password,
8112 calendars => \%cal_refs
8114 &add_user($new_id);
8116 $results .= "success = true;";
8117 $results .= "users = new Array();";
8118 $results .= &generate_users_javascript();
8120 $results .= "messages += '$lang{user_added}';";
8121 } else { # update
8122 $password = crypt($password, $options{salt});
8124 my %cal_refs;
8125 $cal_refs{$current_cal_id}{edit_events} = 1;
8127 $users{$id} = {id => $id,
8128 name => $name,
8129 notes => $notes,
8130 password => $password,
8131 calendars => \%cal_refs
8133 &update_user($id);
8135 $results .= "success = true;";
8136 $results .= "users = new Array();";
8137 $results .= &generate_users_javascript();
8139 $results .= "messages += '$lang{user_updated}';";
8143 $results .= "messages += '###debug_info###';";
8146 $debug_info =~ s/\//\\\//g;
8147 $debug_info =~ s/\n/<br\/>/g;
8148 $debug_info =~ s/"/\\"/g;
8149 $debug_info =~ s/'/\\'/g;
8150 $results =~ s/###debug_info###/$debug_info/;
8152 print <<p1;
8153 Cache-control: no-cache,no-store,private
8154 Content-Type: text/html; charset=iso-8859-1\n
8155 $results
8158 exit(0);
8161 sub add_new_ical {
8162 my $ical_url = &decode($q->param('ical_url'));
8163 my $results = "";
8165 if (!$logged_in_as_root) {
8166 $results .= "messages = 'You must be logged in to add an iCal!';";
8167 $results .= "var successful = false;";
8168 } else {
8169 # try getting the URL
8170 my $url_results = &get_remote_file($ical_url);
8171 $debug_info .= $url_results;
8173 if ($url_results eq "404 not found!" || $url_results =~ /cannot connect/i) {
8174 $results .= "messages = 'iCal calendar <b>not</b> added! (invalid url)';";
8175 $results .= "var successful = false;";
8176 } else {
8177 my %new_calendar = &deep_copy(\%default_cal);
8178 my $new_cal_id = $max_cal_id + 1;
8180 $new_calendar{id} = $new_cal_id;
8181 $new_calendar{title} = "($ical_url)";
8182 $new_calendar{type} = "ical";
8183 $new_calendar{url} = $ical_url;
8185 $calendars{$new_cal_id} = &deep_copy(\%new_calendar);
8187 &add_calendars([$new_calendar{id}]);
8189 $results .= "messages = 'iCal calendar ($ical_url) added!';";
8190 $results .= "success = true;";
8194 $debug_info =~ s/\//\\\//g;
8195 $debug_info =~ s/\n/<br\/>/g;
8196 $debug_info =~ s/"/\\"/g;
8197 $debug_info =~ s/'/\\'/g;
8198 #$results .= "\ndebug_info: $debug_info";
8200 print <<p1;
8201 Cache-control: no-cache,no-store,private
8202 Content-Type: text/html; charset=iso-8859-1\n
8203 $results
8210 sub js_login() {
8211 my $results = "";
8212 my $status = 1;
8214 if ($logged_in) {
8215 $results .= "logged_in = true;";
8216 $results .= "messages = get_lang('logged_in1')+'<br/>###debug_info###';";
8217 $results .= "setcookie('plans_sid','".$session->id."', null, '$cookie_path');";
8218 } elsif( $q->param('logout') eq "1") {
8219 $results .= "logged_in = false;";
8220 $results .= "messages = get_lang('logged_in2')+'<br/>###debug_info###';";
8221 } else {
8222 $results .= "logged_in = false;";
8223 $results .= "messages = get_lang('logged_in3')+'<br/>###debug_info###';";
8226 $debug_info =~ s/\//\\\//g;
8227 $debug_info =~ s/\n/<br\/>/g;
8228 $debug_info =~ s/"/\\"/g;
8229 $debug_info =~ s/'/\\'/g;
8230 $results =~ s/###debug_info###/$debug_info/;
8232 print <<p1;
8233 Cache-control: no-cache,no-store,private
8234 Content-Type: text/html; charset=iso-8859-1\n
8236 $results
8239 exit(0);
8243 sub manage_pending_events() {
8244 &normalize_timezone();
8246 my $approve = $q->param('approve');
8247 my $delete = $q->param('delete');
8248 my $results = "";
8249 my $messages = "";
8251 if ($logged_in_as_root || $logged_in_as_current_cal_admin) {
8252 $add_edit_event = "add";
8254 $approve =~ s/[^(\d|,)]//g;
8255 $approve =~ s/[^(\d|,)]//g;
8257 my @events_to_approve = split(',', $q->param('approve'));
8258 my @events_to_delete = split(',', $q->param('delete'));
8260 foreach $event_to_approve (@events_to_approve) {
8261 &commit_event($new_events{$event_to_approve});
8263 my $temp = $lang{pending_event_approved};
8264 $temp =~ s/\$1/$event_to_approve/;
8265 $messages .= "$temp\n";
8267 foreach $event_to_delete (@events_to_delete) {
8268 my $temp = $lang{pending_event_deleted};
8269 $temp =~ s/\$1/$event_to_delete/;
8270 $messages .= "$temp\n";
8273 push @events_to_delete, @events_to_approve;
8274 &delete_pending_actions(\@events_to_delete);
8276 $debug_info =~ s/\//\\\//g;
8277 $debug_info =~ s/\n/<br\/>/g;
8278 $debug_info =~ s/"/\\"/g;
8279 $debug_info =~ s/'/\\'/g;
8281 if ($debug_info != "") {$messages = "Debug info: $debug_info";}
8283 $messages =~ s/\//\\\//g;
8284 $messages =~ s/\n/<br\/>/g;
8285 $messages =~ s/"/\\"/g;
8286 $messages =~ s/'/\\'/g;
8287 #$results .= "messages = '$messages';\n";
8289 $results .= "window.location='$script_url/$name?messages=".&encode($messages)."';";
8290 #$results .= "alert(\"window.location=$script_url/$name&messages=".&encode($messages)."\");";
8291 } else {
8292 $results .= "messages = '$lang{invalid_password}';update_messages();";
8293 $results .= "cal_password = '';";
8296 print <<p1;
8297 Cache-control: no-cache,no-store,private
8298 Content-Type: text/html; charset=iso-8859-1\n
8300 $results
8308 sub generate_calendars_javascript() {
8309 my $results = "";
8311 foreach $calendar_id (sort {$a <=> $b} keys %calendars) {
8312 my %calendar = %{$calendars{$calendar_id}};
8313 $results .= "calendars[$calendar_id] = new Object;";
8314 $results .= "calendars[$calendar_id].users = new Array();";
8316 foreach $user_ref (@{$calendar{users}}) {
8317 my %user = %{$user_ref};
8318 $results .= "calendars[$calendar_id].users[$user{id}] = new Object;";
8321 return $results;
8325 sub api_add_delete_events() {
8326 my $results = "";
8328 #$debug_info .= "(api_add_delete_events) before add_edit_events $events{159}{start} - $events{159}{end}\n";
8329 my %add_edit_events_results = %{&add_edit_events()};
8330 #$debug_info .= "(api_add_delete_events) after add_edit_events $events{159}{start} - $events{159}{end}\n";
8333 if ($api_output_format eq "javascript") {
8334 if ($add_edit_events_results{success} eq "1") {
8335 $results .= "success=true;\n";
8336 } else {
8337 $results .= "success=false;\n";
8340 my $messages = "";
8341 foreach $results_message (@{$add_edit_events_results{messages}}) {
8342 $messages .= &javascript_cleanup($results_message);
8345 $debug_info = &javascript_cleanup($debug_info);
8346 $debug_info =~ s/\\n/<br\/>/g;
8349 $rightnow_messages = "messages='$debug_info\\n$messages';\n";
8351 $results .= $rightnow_messages;
8352 $results .= "update_messages(messages);";
8353 $results .= "dialog_box.close();";
8355 if ($add_edit_events_results{success} eq "1") {
8356 $results .= "window.location='$script_url/$name?messages=".&encode($messages)."';";
8359 print <<p1;
8360 Cache-control: no-cache,no-store,private
8361 Content-Type: text/html; charset=iso-8859-1\n
8363 $results
8369 sub fatal_error() {
8370 my $diagnostic_results = &diagnostic_info();
8373 $error_info =~ s/\n/<br>/g;
8375 $html_output .=<<p1;
8376 Cache-control: no-cache,no-store,private
8377 Content-Type: text/html; charset=iso-8859-1\n
8378 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
8379 <html>
8380 <head>
8381 <title>Plans error!</title>
8382 </head>
8383 <body>
8385 <b>Plans error:</b><br/>
8386 $error_info
8387 <br/><br/>
8388 <b>Diagnostic information:</b><br/>
8389 $diagnostic_results
8392 if ($debug_info ne "") {
8393 $debug_info =~ s/\n/<br>/g;
8394 $html_output .=<<p1;
8395 <hr>
8396 Debug info:<br/>
8397 $debug_info
8401 $html_output .=<<p1;
8402 </body>
8403 </html>
8406 print $html_output;
8407 exit(0);