summaryrefslogtreecommitdiff
path: root/wcald
blob: 0d7b8d2831a9baa717f78e6ddb306e63c9498ef3 (plain)
  1. #!/usr/bin/perl -w
  2. #
  3. # Wcal 2.0 copyright by Joël Savignon <js@neosystem.com>.
  4. #
  5. # Released under GNU General Public License (GPL).
  6. #
  7. # TAB size 4
  8. #
  9. require 5.004;
  10. use Data::Dumper;
  11. use Date::Manip;
  12. use Socket;
  13. use strict;
  14. no strict 'refs';
  15. # These you can edit
  16. $::CONF_FILE = '/etc/wcal.conf';
  17. $::MSG_FILE = '/etc/wcal.msg';
  18. $::DIRECTORY = '/var/www/VIRTUAL/www.homebase.dk/www/wcal';
  19. $::DB_DIR = '/var/wcal'; # settable in wcal.conf in 1.x versions
  20. $::REFRESH_DELAY = 900; # view refreshed every 900 seconds = 15 minutes
  21. $::PATH_BASENAME = 'wcal'; # last component of the wcal directory name
  22. # Values below affect the proportions of the frames
  23. $::FIRST_HOUR = 8;
  24. $::LAST_HOUR = 23;
  25. $::MANY_WEEKS_VERT = 2;
  26. $::MANY_WEEKS_HOR = 7;
  27. $::FIRST_DAY = 'monday';
  28. # Colors
  29. $::THCOLOR = '#E2E3FC';
  30. $::TDCOLOR = '#D9F4F4';
  31. $::NOW_THCOLOR = '#CAFFD0';
  32. $::NOW_TDCOLOR = '#CAFFD0';
  33. $::REPEAT_WEEK_TEXTCOLOR = '#C02090';
  34. $::REPEAT_MONTH_TEXTCOLOR = '#008844';
  35. $::BG_TDCOLOR = '#F2F3FC';
  36. $::ERROR_COLOR = '#e06060';
  37. @::EVENT_COLS = ('#D9F4F4','#FFFFAA','#AAFFFF','#FFAAFF','#FFAAAA','#AAAAFF','#AAFFAA','#80FFE0','#E080E0','#C0DCC0','#C0C0C0','#FF0080','#A4C8F0','#FF8000','#FF80C0','#8080C0','#FFFFFF');
  38. # No need to touch these
  39. $::MAX_DURATION = 21; # maximum duration of an event in days
  40. $::CURRENT_DB_VERSION = 2; # Wcal 1.00 had version 1 databases
  41. $::HTTP_HEADER = "Content-Type: text/html\n\n";
  42. # internationalization
  43. sub __
  44. {
  45. my $str = shift;
  46. return $::msgs->{$str}->{$::REMOTE_LANG} || $str;
  47. }
  48. # fusion
  49. sub strcal
  50. {
  51. if ($::query->{'cal'})
  52. {
  53. return "&cal=".join("&cal=",split(/\n/,$::query->{'cal'}));
  54. }
  55. else
  56. {
  57. return "";
  58. }
  59. }
  60. sub lncal
  61. {
  62. my $year = shift;
  63. my $week = shift;
  64. if ($::query->{'cal'})
  65. {
  66. my $str = $::BASE_URL.'/fusion.cgi?t=links&cal='.join("&cal=",split(/\n/,$::query->{'cal'}));
  67. if ($year && $week)
  68. {
  69. $str .= '&year='.$year.'&week='.$week;
  70. }
  71. return "<a onClick='window.open(\"$str\", \"links\", \"toolbar=no,menubar=no,scrollbars=yes,width=250,height=200,resizable=yes\"); return false' href=\"$str\" target=\"_top\">$::LONG_NAME</a>";
  72. }
  73. else
  74. {
  75. return $::LONG_NAME;
  76. }
  77. }
  78. # Query string decoder, ripped from CGI_Lite
  79. sub decode_url_encoded_data ($) {
  80. my ($reference_data) = @_;
  81. my ($code, $self);
  82. $code = <<'End_of_URL_Decode';
  83. my (@key_value_pairs, $delimiter, $key_value, $key, $value);
  84. @key_value_pairs = ();
  85. return unless ($$reference_data);
  86. $delimiter = '&';
  87. $$reference_data =~ tr/+/ /;
  88. @key_value_pairs = split (/$delimiter/, $$reference_data);
  89. foreach $key_value (@key_value_pairs) {
  90. ($key, $value) = split (/=/, $key_value, 2);
  91. $key =~ s/%([\da-fA-F]{2})/chr (hex ($1))/eg;
  92. $value =~ s/%([\da-fA-F]{2})/chr (hex ($1))/eg;
  93. # print Socket "'$key':'$value'\n";
  94. if ($self->{$key})
  95. {
  96. $self->{$key} .= "\n$value";
  97. }
  98. else
  99. {
  100. $self->{$key} = $value;
  101. }
  102. }
  103. End_of_URL_Decode
  104. eval ($code);
  105. return $self;
  106. }
  107. # And encoder, ripped too
  108. sub url_encode
  109. {
  110. my $string = shift;
  111. my $str1 = '([\x00-\x20"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF])';
  112. $string =~ s/$str1/
  113. sprintf ('%%%x', ord ($1))/eg;
  114. return $string;
  115. }
  116. sub strip_space ($) {
  117. my ($s) = @_;
  118. $s =~ s/^\s*(.*?)\s*$/$1/;
  119. return $s;
  120. }
  121. sub wday_to_dmwday ($) {
  122. my ($wday) = @_;
  123. if ($::FIRST_DAY eq 'monday') {
  124. return ($wday + 1);
  125. } else {
  126. if ($wday == 0) {
  127. return 7;
  128. } else {
  129. return $wday;
  130. }
  131. }
  132. }
  133. sub dmwday_to_wday ($) {
  134. my ($dmwday) = @_;
  135. return ($::FIRST_DAY eq 'monday' ?
  136. $dmwday - 1 :
  137. $dmwday % 7);
  138. }
  139. sub get_now () {
  140. if (! defined $::now_cache) {
  141. my (@n);
  142. @n = &UnixDate (&ParseDate ('now'), $::FIRST_DAY eq 'monday' ? "%G": "%L", "%m", "%d", $::FIRST_DAY eq 'monday' ? "%W" : "%U", "%w");
  143. $::now_cache = {
  144. 'year' => $n[0] + 0,
  145. 'month' => $n[1] + 0,
  146. 'day' => $n[2] + 0,
  147. 'week' => $n[3] + 0,
  148. 'wday' => dmwday_to_wday ($n[4]) };
  149. }
  150. return $::now_cache;
  151. }
  152. sub get_next_year_week ($$) {
  153. my ($year, $week) = @_;
  154. my ($cacheid);
  155. $cacheid = sprintf ("%04d%02d", $year, $week);
  156. if (! defined $::nyw_cache{$cacheid}) {
  157. my ($y, $w);
  158. ($y, $w) = &UnixDate (&DateCalc ("$::FIRST_DAY week $week in $year", "+ 7 days"), $::FIRST_DAY eq 'monday' ? "%G": "%L", $::FIRST_DAY eq 'monday' ? "%W" : "%U");
  159. $::nyw_cache{$cacheid} = [$y + 0, $w + 0];
  160. }
  161. return @{$::nyw_cache{$cacheid}};
  162. }
  163. sub get_prev_year_week ($$) {
  164. my ($year, $week) = @_;
  165. my ($cacheid);
  166. $cacheid = sprintf ("%04d%02d", $year, $week);
  167. if (! defined $::pyw_cache{$cacheid}) {
  168. my ($y, $w);
  169. ($y, $w) = &UnixDate (&DateCalc ("$::FIRST_DAY week $week in $year", "- 7 days"), $::FIRST_DAY eq 'monday' ? "%G": "%L", $::FIRST_DAY eq 'monday' ? "%W" : "%U");
  170. $::pyw_cache{$cacheid} = [$y + 0, $w + 0];
  171. }
  172. return @{$::pyw_cache{$cacheid}};
  173. }
  174. sub get_month_day_by_firstday_year_week ($$) {
  175. my ($year, $week) = @_;
  176. my ($cacheid);
  177. $cacheid = sprintf ("%04d%02d", $year, $week);
  178. if (! defined $::md_cache{$cacheid}) {
  179. my ($month, $day);
  180. ($month, $day) = &UnixDate (&ParseDate ("$::FIRST_DAY week $week in $year"), "%m", "%d");
  181. $::md_cache{$cacheid} = [$month + 0, $day + 0];
  182. }
  183. return @{$::md_cache{$cacheid}};
  184. }
  185. sub get_month_day_by_wday_year_week ($$$) {
  186. my ($wday, $year, $week) = @_;
  187. my ($cacheid);
  188. $cacheid = sprintf ("%04d%02d%1d", $year, $week, $wday);
  189. if (! defined $::md2_cache{$cacheid}) {
  190. my ($month, $day);
  191. ($month, $day) = &UnixDate (&ParseDate ($::weekdays2[$wday] . " week $week in $year"), "%m", "%d");
  192. $::md2_cache{$cacheid} = [$month + 0, $day + 0];
  193. }
  194. return @{$::md2_cache{$cacheid}};
  195. }
  196. sub get_year_week_by_firstday_year_week_minus_days ($$$) {
  197. my ($year, $week, $days) = @_;
  198. my ($cacheid);
  199. $cacheid = sprintf ("%04d%02d%10d", $year, $week, $days);
  200. if (! defined $::yw_cache{$cacheid}) {
  201. my ($ryear, $rweek);
  202. ($ryear, $rweek) = &UnixDate (&DateCalc ("$::FIRST_DAY week $week in $year", "- $days days"), $::FIRST_DAY eq 'monday' ? "%G": "%L", $::FIRST_DAY eq 'monday' ? "%W" : "%U");
  203. $::yw_cache{$cacheid} = [$ryear + 0, $rweek + 0];
  204. }
  205. return @{$::yw_cache{$cacheid}};
  206. }
  207. sub week_wday_by_year_month_day ($$$) {
  208. my ($year, $month, $day) = @_;
  209. my ($cacheid);
  210. $cacheid = sprintf ("%04d%02d%2d", $year, $month, $day);
  211. if (! defined $::ww_cache{$cacheid}) {
  212. my ($week, $wday);
  213. ($week, $wday) = &UnixDate (&ParseDate ("$month/$day/$year"), $::FIRST_DAY eq 'monday' ? "%W" : "%U", "%w");
  214. $::ww_cache{$cacheid} = [$week + 0, dmwday_to_wday ($wday)];
  215. }
  216. return @{$::ww_cache{$cacheid}};
  217. }
  218. sub get_start_end_by_year_week_wday_duration ($$$$) {
  219. my ($startyear, $startweek, $startwday, $duration) = @_;
  220. my ($cacheid);
  221. $cacheid = sprintf ("%04d%02d%2d%03d", $startyear, $startweek, $startwday, $duration);
  222. if (! defined $::se_cache{$cacheid}) {
  223. my ($startmonth, $startday, $endyear, $endweek, $endwday, $endmonth, $endday);
  224. ($startmonth, $startday) = get_month_day_by_wday_year_week ($startwday, $startyear, $startweek);
  225. ($endyear, $endweek, $endwday) =
  226. &UnixDate (&DateCalc (&ParseDate (sprintf ("%04d-W%02d-%1d", $startyear, $startweek, wday_to_dmwday ($startwday))),
  227. "+ " . ($duration - 1) . " days"),
  228. $::FIRST_DAY eq 'monday' ? "%G": "%L", $::FIRST_DAY eq 'monday' ? "%W" : "%U", "%w");
  229. $endwday = dmwday_to_wday ($endwday);
  230. ($endmonth, $endday) = get_month_day_by_wday_year_week ($endwday, $endyear, $endweek);
  231. $::se_cache{$cacheid} =
  232. [
  233. $startmonth + 0, $startday + 0,
  234. $endyear + 0, $endweek + 0, dmwday_to_wday ($endwday),
  235. $endmonth + 0, $endday + 0
  236. ];
  237. }
  238. return @{$::se_cache{$cacheid}};
  239. }
  240. sub get_year_week_wday_by_year_week_wday_plus_days ($$$$) {
  241. my ($year, $week, $wday, $days) = @_;
  242. my ($cacheid);
  243. $cacheid = sprintf ("%04d%02d%02d%10d", $year, $week, $wday, $days);
  244. if (! defined $::yww_cache{$cacheid}) {
  245. my ($nyear, $nweek, $nwday);
  246. ($nyear, $nweek, $nwday) =
  247. &UnixDate (&DateCalc (sprintf ("%04d-W%02d-%1d", $year, $week, wday_to_dmwday ($wday)),
  248. "+ $days days"),
  249. $::FIRST_DAY eq 'monday' ? "%G": "%L",
  250. $::FIRST_DAY eq 'monday' ? "%W" : "%U",
  251. "%w");
  252. $::yww_cache{$cacheid} = [$nyear + 0, $nweek + 0, dmwday_to_wday ($nwday)];
  253. }
  254. return @{$::yww_cache{$cacheid}};
  255. }
  256. sub fit_in_week ($$$$) {
  257. my ($year, $week, $wday, $duration) = @_;
  258. my ($endyear, $endweek, $endwday);
  259. ($endyear, $endweek, $endwday) =
  260. get_year_week_wday_by_year_week_wday_plus_days
  261. ($year, $week, $wday, $duration-1);
  262. if ($endyear != $year or $endweek != $week) {
  263. return 0;
  264. } else {
  265. return 1;
  266. }
  267. }
  268. sub fit_in_month ($$$$) {
  269. my ($year, $week, $wday, $duration) = @_;
  270. my ($month, $day);
  271. my ($endyear, $endweek, $endwday);
  272. my ($endmonth, $endday);
  273. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  274. ($endyear, $endweek, $endwday) =
  275. get_year_week_wday_by_year_week_wday_plus_days
  276. ($year, $week, $wday, $duration-1);
  277. ($endmonth, $endday) = get_month_day_by_wday_year_week ($endwday, $endyear, $endweek);
  278. if ($endyear != $year or $endmonth != $month) {
  279. return 0;
  280. } else {
  281. return 1;
  282. }
  283. }
  284. sub clipboard_set ($$) {
  285. my ($key, $data_ref) = @_;
  286. $::clipboard{$key} = $data_ref;
  287. return;
  288. }
  289. sub clipboard_get ($) {
  290. my ($key) = @_;
  291. if (defined $::clipboard{$key}) {
  292. return $::clipboard{$key};
  293. } else {
  294. return '';
  295. }
  296. }
  297. sub format_hour ($) {
  298. my ($hour) = @_;
  299. if ($::CLOCK eq '24-hour') {
  300. return ($hour + 0);
  301. } else {
  302. my ($newhour);
  303. $newhour = $hour;
  304. $newhour = 24 if $hour == 0;
  305. $newhour -= 12 if $hour > 12;
  306. return ($newhour + 0) . ($hour < 12 ? "am" : "pm");
  307. }
  308. }
  309. sub format_hour_padded ($) {
  310. my ($hour) = @_;
  311. if ($::CLOCK eq '24-hour') {
  312. return sprintf ("%02d", $hour);
  313. } else {
  314. my ($newhour);
  315. $newhour = $hour;
  316. $newhour = 24 if $hour == 0;
  317. $newhour -= 12 if $hour > 12;
  318. return sprintf ("%02d", $newhour) . ($hour < 12 ? "am" : "pm");
  319. }
  320. }
  321. sub format_time ($$) {
  322. my ($hour, $min) = @_;
  323. if ($::CLOCK eq '24-hour') {
  324. return ($hour + 0) . ":" . sprintf ("%02d", $min);
  325. } else {
  326. my ($newhour);
  327. $newhour = $hour;
  328. $newhour = 24 if $hour == 0;
  329. $newhour -= 12 if $hour > 12;
  330. return ($newhour + 0) . ":" . sprintf ("%02d", $min) . ($hour < 12 ? "am" : "pm");
  331. }
  332. }
  333. sub format_time_padded ($$) {
  334. my ($hour, $min) = @_;
  335. if ($::CLOCK eq '24-hour') {
  336. return sprintf ("%02d", $hour) . ":" . sprintf ("%02d", $min);
  337. } else {
  338. my ($newhour);
  339. $newhour = $hour;
  340. $newhour = 24 if $hour == 0;
  341. $newhour -= 12 if $hour > 12;
  342. return sprintf ("%02d", $newhour) . ":" . sprintf ("%02d", $min) . ($hour < 12 ? "am" : "pm");
  343. }
  344. }
  345. sub format_alarm_type {
  346. my ($type, $single) = @_;
  347. if ($type == 1)
  348. {
  349. if ($single)
  350. {
  351. return __("minute");
  352. }
  353. else
  354. {
  355. return __("minutes");
  356. }
  357. }
  358. elsif ($type == 2)
  359. {
  360. if ($single)
  361. {
  362. return __("heure");
  363. }
  364. else
  365. {
  366. return __("heures");
  367. }
  368. }
  369. elsif ($type == 3)
  370. {
  371. if ($single)
  372. {
  373. return __("jour");
  374. }
  375. else
  376. {
  377. return __("jours");
  378. }
  379. }
  380. else
  381. {
  382. return "";
  383. }
  384. }
  385. sub img_alarm {
  386. my ($val, $type, $chk) = @_;
  387. if ($val)
  388. {
  389. my $img = ($chk ? "alarm2" : "alarm");
  390. return ' <IMG SRC="'. $::IMG_URL . '/' . $img . '.gif" ALT="'.__("Alarme")." : ".$val." ".format_alarm_type($type, ($val == 1)).'">';
  391. }
  392. else
  393. {
  394. return "";
  395. }
  396. }
  397. sub img_note {
  398. my ($data) = @_;
  399. if ($data)
  400. {
  401. $data =~ s/<BR>/ /mg;
  402. return ' <IMG SRC="' . $::IMG_URL . '/note.gif" ALT="'.__("Note")." : ".$data.'">';
  403. }
  404. else
  405. {
  406. return "";
  407. }
  408. }
  409. sub txt_alarm {
  410. my ($val, $type, $chk) = @_;
  411. if ($val)
  412. {
  413. my $col = ($chk ? "#00AA00" : "#FF0000");
  414. return '<BR><FONT COLOR="'.$col.'">'.__("Alarme")." : ".$val." ".format_alarm_type($type, ($val == 1)).'</FONT>';
  415. }
  416. else
  417. {
  418. return "";
  419. }
  420. }
  421. sub has_html ($) {
  422. my ($text) = @_;
  423. return $text =~ /[<>&]/;
  424. }
  425. sub newline_to_html ($) {
  426. my ($text) = @_;
  427. $text =~ s/\015\012/<BR>/sg;
  428. return $text;
  429. }
  430. sub html_to_newline ($) {
  431. my ($text) = @_;
  432. $text =~ s/<BR>/\015\012/sg;
  433. return $text;
  434. }
  435. sub events_version ($) {
  436. my ($events) = @_;
  437. my ($version);
  438. $version = $events->[0];
  439. if (ref $version) {
  440. $version = 1;
  441. }
  442. return $version;
  443. }
  444. sub convert_events_from_v1_to_v2 ($$$) {
  445. my ($events, $year, $week) = @_;
  446. my ($dayid, $eventhour, $eventid);
  447. for $dayid (0 .. $#$events) {
  448. for $eventhour (keys %{$events->[$dayid]}) {
  449. for $eventid (0 .. $#{$events->[$dayid]->{$eventhour}}) {
  450. my (@old_event, %new_event);
  451. @old_event = @{$events->[$dayid]->{$eventhour}->[$eventid]};
  452. %new_event = (
  453. 'id' => $old_event[0],
  454. 'min' => $old_event[1],
  455. 'lengthmin' => $old_event[2],
  456. 'title' => $old_event[3],
  457. 'data' => $old_event[4],
  458. 'rt' => $old_event[5],
  459. 'startyear' => $year,
  460. 'startweek' => $week,
  461. 'startwday' => $dayid,
  462. 'duration' => 1
  463. );
  464. $events->[$dayid]->{$eventhour}->[$eventid] = \%new_event;
  465. }
  466. }
  467. }
  468. # insert version number into beginning of the array
  469. unshift (@$events, $::CURRENT_DB_VERSION);
  470. return;
  471. }
  472. sub read_events ($;$$) {
  473. my ($rt, $year, $week) = @_;
  474. my ($filename, $now);
  475. my @filenames;
  476. my $id;
  477. my ($refs, $ref, $old_slash);
  478. if ($main::DATA_ID)
  479. {
  480. if ($rt eq 'n') {
  481. $filename = sprintf "$::DB_DIR/w-$main::DATA_ID-%04d%02d.db", $year, $week;
  482. } else {
  483. $filename = "$::DB_DIR/r$rt-$main::DATA_ID.db";
  484. }
  485. if (open F, $filename) {
  486. $old_slash = $/;
  487. undef $/;
  488. $refs = eval (<F>);
  489. $/ = $old_slash;
  490. close F;
  491. # backwards compatibility
  492. if (events_version ($refs) < 2) {
  493. $now = get_now ();
  494. convert_events_from_v1_to_v2 ($refs, $year || $now->{'year'}, $week || $now->{'week'});
  495. }
  496. shift @$refs;
  497. }
  498. }
  499. elsif ($main::DATA_IDS)
  500. {
  501. my $cl = 0;
  502. foreach $id (split(/\n/,$main::DATA_IDS))
  503. {
  504. $cl++;
  505. if ($rt eq 'n') {
  506. $filename = sprintf "$::DB_DIR/w-$id-%04d%02d.db", $year, $week;
  507. } else {
  508. $filename = "$::DB_DIR/r$rt-$id.db";
  509. }
  510. if (open F, $filename) {
  511. $old_slash = $/;
  512. undef $/;
  513. $ref = eval (<F>);
  514. $/ = $old_slash;
  515. close F;
  516. # backwards compatibility
  517. if (events_version ($ref) < 2) {
  518. $now = get_now ();
  519. convert_events_from_v1_to_v2 ($ref, $year || $now->{'year'}, $week || $now->{'week'});
  520. }
  521. shift @$ref;
  522. # add cal index
  523. my $i;
  524. my $key;
  525. my $val;
  526. my $vl;
  527. for ($i=0; $i < ($rt eq 'm' ? 32 : 7); $i++)
  528. {
  529. while (($key, $val) = each (%{@{$ref}[$i]}))
  530. {
  531. foreach $vl (@{$val})
  532. {
  533. %{$vl}->{cal} = $cl;
  534. }
  535. }
  536. }
  537. if (!$refs)
  538. {
  539. $refs = $ref;
  540. next;
  541. }
  542. # fusion
  543. for ($i=0; $i < ($rt eq 'm' ? 32 : 7); $i++)
  544. {
  545. while (($key, $val) = each (%{@{$ref}[$i]}))
  546. {
  547. if (%{@{$refs}[$i]}->{$key})
  548. {
  549. push @{%{@{$refs}[$i]}->{$key}}, @{$val};
  550. }
  551. else
  552. {
  553. @{%{@{$refs}[$i]}->{$key}} = @{$val};
  554. }
  555. }
  556. }
  557. }
  558. }
  559. }
  560. if ($refs)
  561. {
  562. return $refs;
  563. } elsif ($rt eq 'n' or $rt eq 'w') {
  564. return [ {}, {}, {}, {}, {}, {}, {} ];
  565. } elsif ($rt eq 'm') {
  566. # let's give month 32 days to make sure
  567. return [ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} ]
  568. }
  569. # can't happen
  570. }
  571. sub write_events ($$;$$) {
  572. my ($weekdata, $rt, $year, $week) = @_;
  573. my ($filename);
  574. if ($rt eq 'n') {
  575. if (! defined $year or ! $year or ! defined $week or ! $week) {
  576. return "The file type is no-repeat, but week or year not given, or zero.";
  577. }
  578. $filename = sprintf "$::DB_DIR/w-${main::DATA_ID}-%04d%02d.db", $year, $week;
  579. # Remove cached week file
  580. unlink sprintf ("$::DB_DIR/cache/w-${main::DATA_ID}-%04d%02d.html", $year, $week);
  581. } else {
  582. my (@files);
  583. $filename = "$::DB_DIR/r$rt-${main::DATA_ID}.db";
  584. # Remove all cached week files
  585. if (opendir (TDH, "$::DB_DIR/cache")) {
  586. @files = grep { /^w-${main::DATA_ID}-\d{6}\.html$/ } readdir (TDH);
  587. closedir TDH;
  588. for (@files) {
  589. unlink "$::DB_DIR/cache/$_";
  590. }
  591. }
  592. }
  593. # add the version identifier
  594. unshift (@$weekdata, $::CURRENT_DB_VERSION);
  595. if (open F, ">$filename") {
  596. $Data::Dumper::Terse = 1;
  597. flock (F, 2);
  598. print F Dumper ($weekdata);
  599. flock (F, 8);
  600. close F;
  601. return '';
  602. } else {
  603. return "File $filename can't be opened for writing: $!";
  604. }
  605. # and remove the version identifier again
  606. shift @$weekdata;
  607. }
  608. sub read_general () {
  609. my ($week) = @_;
  610. if (-f "$::DB_DIR/general.db" and ! -r "$::DB_DIR/general.db") {
  611. return "No write permission for file $::DB_DIR/general.db";
  612. }
  613. if (open F, "$::DB_DIR/general.db") {
  614. my ($ref, $old_slash);
  615. $old_slash = $/;
  616. undef $/;
  617. $ref = eval (<F>);
  618. $/ = $old_slash;
  619. close F;
  620. if ($@) {
  621. return "Error in processing file $::DB_DIR/general.db: $@";
  622. } else {
  623. return $ref;
  624. }
  625. } else {
  626. return { 'highid' => 56 };
  627. }
  628. }
  629. sub write_general ($) {
  630. my ($gendata) = @_;
  631. if (open F, ">$::DB_DIR/general.db") {
  632. $Data::Dumper::Terse = 1;
  633. flock (F, 2);
  634. print F Dumper ($gendata);
  635. flock (F, 8);
  636. close F;
  637. return '';
  638. } else {
  639. return "File $::DB_DIR/general.db can't be opened for writing: $!";
  640. }
  641. }
  642. # Print year, month and day in chosen date format
  643. sub pd_year_month_day ($$$) {
  644. my ($year, $month, $day) = @_;
  645. my ($t);
  646. $t = $::DATE_FORMAT;
  647. if ($t == 1) {
  648. return "$day.$month.$year";
  649. } elsif ($t == 2) {
  650. return "$month/$day/$year";
  651. } elsif ($t == 3) {
  652. return "$day/$month/$year";
  653. } elsif ($t == 4) {
  654. return "$year/$month/$day";
  655. } elsif ($t == 5) {
  656. return "$year-$month-$day";
  657. } elsif ($t == 5) {
  658. return sprintf ("%04d%02d%02d", $year, $month, $day);
  659. } else {
  660. return "[DATE TYPE $t]";
  661. }
  662. }
  663. sub pd_month_day ($$) {
  664. my ($month, $day) = @_;
  665. my ($t);
  666. $t = $::DATE_FORMAT;
  667. if ($t == 1) {
  668. return "$day.$month";
  669. } elsif ($t == 2) {
  670. return "$month/$day";
  671. } elsif ($t == 3) {
  672. return "$day/$month";
  673. } elsif ($t == 4) {
  674. return "$month/$day";
  675. } elsif ($t == 5) {
  676. return "$month-$day";
  677. } elsif ($t == 6) {
  678. return sprintf ("%02d%02d", $month, $day);
  679. } else {
  680. return "[DATE TYPE $t]";
  681. }
  682. }
  683. sub pd_month_day_padded ($$) {
  684. my ($month, $day) = @_;
  685. my ($t);
  686. $t = $::DATE_FORMAT;
  687. if ($t == 1) {
  688. return sprintf "%02d.%02d", $day, $month;
  689. } elsif ($t == 2) {
  690. return sprintf "%02d/%02d", $month, $day;
  691. } elsif ($t == 3) {
  692. return sprintf "%02d/%02d", $day, $month;
  693. } elsif ($t == 4) {
  694. return sprintf "%02d/%02d", $month, $day;
  695. } elsif ($t == 5) {
  696. return sprintf "%02d-%02d", $month, $day;
  697. } elsif ($t == 6) {
  698. return sprintf "%02d%02d", $month, $day;
  699. } else {
  700. return "[DATE TYPE $t]";
  701. }
  702. }
  703. sub pd_single_event_date ($$$$) {
  704. my ($rt, $year, $week, $wday) = @_;
  705. my ($month, $day);
  706. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  707. if ($rt eq 'n') {
  708. return pd_year_month_day ($year, $month, $day);
  709. } elsif ($rt eq 'w') {
  710. return __($::weekdays[$wday]);
  711. } else {
  712. return $day . ".";
  713. }
  714. }
  715. sub pd_event_date ($$$$$) {
  716. my ($rt, $startyear, $startweek, $startwday, $duration) = @_;
  717. my ($ret);
  718. $ret = '';
  719. $ret .= pd_single_event_date ($rt, $startyear, $startweek, $startwday);
  720. if ($duration > 1) {
  721. ($startyear, $startweek, $startwday) =
  722. get_year_week_wday_by_year_week_wday_plus_days
  723. ($startyear, $startweek, $startwday, $duration - 1);
  724. $ret .= " to " . pd_single_event_date ($rt, $startyear, $startweek, $startwday);
  725. }
  726. if ($rt eq 'w') {
  727. $ret .= " ".__("hebdomadaire");
  728. } elsif ($rt eq 'm') {
  729. $ret .= " ".__("mensuelle");
  730. }
  731. return $ret;
  732. }
  733. sub join_days (@) {
  734. my (@daylist) = @_;
  735. my (%sum_day, $day_ref, $hour, $event_ref);
  736. %sum_day = ();
  737. for $day_ref (@daylist) {
  738. for $hour (keys %$day_ref) {
  739. for $event_ref (@{$day_ref->{$hour}}) {
  740. push @{$sum_day{$hour}}, $event_ref;
  741. }
  742. }
  743. }
  744. return \%sum_day;
  745. }
  746. sub build_day ($$$$) {
  747. my ($year, $week, $wday, $day) = @_;
  748. my ($e_n, $e_rw, $e_rm, $sum_day_ref);
  749. $e_n = read_events ('n', $year, $week);
  750. $e_rw = read_events ('w');
  751. $e_rm = read_events ('m');
  752. $sum_day_ref = join_days ($e_n->[$wday], $e_rw->[$wday], $e_rm->[$day]);
  753. return $sum_day_ref;
  754. }
  755. sub build_week ($$) {
  756. my ($year, $week) = @_;
  757. my ($e_n, $e_rw, $e_rm, @sum_week, $wday);
  758. $e_n = read_events ('n', $year, $week);
  759. $e_rw = read_events ('w');
  760. $e_rm = read_events ('m');
  761. for $wday (0 .. 6) {
  762. my ($month, $day);
  763. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  764. $sum_week[$wday] = join_days ($e_n->[$wday], $e_rw->[$wday], $e_rm->[$day]);
  765. }
  766. return \@sum_week;
  767. }
  768. sub build_week_list ($$) {
  769. my ($start_year, $start_week) = @_;
  770. my ($week_filename, @weeks, @ret, %weeks);
  771. my ($e_n, $e_rw, $e_rm, @sum_week);
  772. my ($cyear, $cweek, $cdate);
  773. my ($end_year, $end_week, $end_date);
  774. $e_rw = read_events ('w');
  775. $e_rm = read_events ('m');
  776. if ($main::DATA_ID)
  777. {
  778. if (! opendir (DIR, $::DB_DIR)) {
  779. return "can't open $::DB_DIR for reading: $!";
  780. }
  781. # gather all week filenames, 199805, 199806, 199807 ... 199851
  782. @weeks = map { /^w-$main::DATA_ID-(\d{4}\d{2})\.db$/ && $1 }
  783. grep { /^w-$main::DATA_ID-(\d{4}\d{2})\.db$/ &&
  784. $1 >= sprintf ("%04d%02d", $start_year, $start_week) }
  785. sort readdir(DIR);
  786. close DIR;
  787. }
  788. else
  789. {
  790. my $id;
  791. my @wks;
  792. foreach $id (split(/\n/,$main::DATA_IDS))
  793. {
  794. if (! opendir (DIR, $::DB_DIR)) {
  795. return "can't open $::DB_DIR for reading: $!";
  796. }
  797. # gather all week filenames, 199805, 199806, 199807 ... 199851
  798. @wks = map { /^w-$id-(\d{4}\d{2})\.db$/ && $1 }
  799. grep { /^w-$id-(\d{4}\d{2})\.db$/ &&
  800. $1 >= sprintf ("%04d%02d", $start_year, $start_week) }
  801. sort readdir(DIR);
  802. close DIR;
  803. push @weeks, @wks;
  804. }
  805. }
  806. # return immediately if no events
  807. if (scalar @weeks == 0) {
  808. return [];
  809. }
  810. # figure out the filename of the last week file
  811. $weeks[$#weeks] =~ /^(....)(..)$/;
  812. ($end_year, $end_week) = ($1, $2);
  813. $end_date = sprintf ("%04d%02d", $end_year, $end_week);
  814. # generate an array of filenames between first and last week filename into %weeks
  815. $cyear = $start_year; $cweek = $start_week;
  816. $cdate = sprintf "%04d%02d", $cyear, $cweek;
  817. do {
  818. $weeks{$cdate} = $weeks[0] == $cdate ? shift @weeks : 0;
  819. ($cyear, $cweek) = get_next_year_week ($cyear, $cweek);
  820. $cdate = sprintf "%04d%02d", $cyear, $cweek;
  821. } while ($cdate le $end_date);
  822. @ret = ();
  823. for $week_filename (sort keys %weeks) {
  824. my ($year, $week, @sum_week);
  825. $week_filename =~ /^(\d\d\d\d)(\d\d)/;
  826. ($year, $week) = ($1, $2);
  827. # if $weeks{$week_filename} has true value, then there are week
  828. # events for that week - only in that case we will use the repeat events
  829. if ($weeks{$week_filename}) {
  830. my ($e_n, $wday);
  831. $e_n = read_events ('n', $year, $week);
  832. # Combine week files and repeat files
  833. @sum_week = ();
  834. for $wday (0 .. 6) {
  835. my ($day, $month);
  836. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  837. $sum_week[$wday] = join_days ($e_n->[$wday], $e_rw->[$wday], $e_rm->[$day]);
  838. }
  839. } else {
  840. @sum_week = ( {}, {}, {}, {}, {}, {}, {} ); # ignore repeat events too
  841. }
  842. push @ret, [\@sum_week, $year, $week];
  843. }
  844. return \@ret;
  845. }
  846. sub week_cache_read ($$) {
  847. my ($year, $week) = @_;
  848. my ($filename, $data, $old_slash);
  849. local (*CRFH);
  850. if (!$main::DATA_ID)
  851. {
  852. return undef;
  853. }
  854. $filename = sprintf "$::DB_DIR/cache/w-%s-%04d%02d.html", $main::DATA_ID, $year, $week;
  855. if (! open (CRFH, $filename)) {
  856. return undef;
  857. }
  858. $old_slash = $/;
  859. undef $/;
  860. $data = <CRFH>;
  861. $/ = $old_slash;
  862. close CRFH;
  863. return \$data;
  864. }
  865. sub week_cache_write_open ($$) {
  866. my ($year, $week) = @_;
  867. my ($dirname, $filename, $cfh);
  868. $cfh = 'this_is_a_filehandle';
  869. $dirname = "$::DB_DIR/cache";
  870. if ($main::DATA_ID)
  871. {
  872. $filename = sprintf "%s/w-%s-%04d%02d.html", $dirname, $main::DATA_ID, $year, $week;
  873. }
  874. else
  875. {
  876. $filename = sprintf "%s/w-fusion-%04d%02d.html", $dirname, $year, $week;
  877. }
  878. if (! -e $dirname) {
  879. if (! mkdir ($dirname, 0770)) {
  880. my $str1 = "can't create directory $dirname: $!";
  881. return \$str1;
  882. }
  883. }
  884. if (! open ($cfh, ">$filename")) {
  885. my $str2 = "can't open file $filename for writing: $!";
  886. return \$str2;
  887. }
  888. flock ($cfh, 2);
  889. return $cfh;
  890. }
  891. sub header_body ($) {
  892. return \$::H_BODY;
  893. }
  894. sub week_cache_write_close ($) {
  895. my ($fh) = @_;
  896. if (fileno(F))
  897. {
  898. flock (F, 8);
  899. }
  900. close $fh;
  901. }
  902. sub week_split_events_noon ($) {
  903. my ($events_ref) = @_;
  904. my ($e1, $e2, $e3, $day, $hour);
  905. for (@$events_ref) {
  906. for $day (0 .. 6) {
  907. my (%hours);
  908. %hours = %{$events_ref->[$day]};
  909. $e1->[$day] = {}; $e2->[$day] = {}; $e3->[$day] = {};
  910. if (%hours) {
  911. for $hour (keys %hours) {
  912. if ($hour == -1)
  913. {
  914. $e3->[$day]->{$hour} = $events_ref->[$day]->{$hour};
  915. }
  916. elsif ($hour < 12)
  917. {
  918. $e1->[$day]->{$hour} = $events_ref->[$day]->{$hour};
  919. } else
  920. {
  921. $e2->[$day]->{$hour} = $events_ref->[$day]->{$hour};
  922. }
  923. }
  924. }
  925. }
  926. }
  927. return ($e1, $e2, $e3);
  928. }
  929. sub week_print_events ($$$$$$) {
  930. my ($fh, $events_ref, $use_now_wday, $year, $week, $weekdays_ref) = @_;
  931. my ($day_offset, $day_ref, $hour, $event_ref);
  932. $day_offset = 0;
  933. for $day_ref (@$events_ref) {
  934. if (%$day_ref) {
  935. print $fh "<TD BGCOLOR=\"$::TDCOLOR\" VALIGN=top>\n";
  936. print $fh "<table width=100% cellpadding=0 cellspacing=0 border=0>\n";
  937. for $hour (sort { $a <=> $b } keys %$day_ref) {
  938. for $event_ref (@{$day_ref->{$hour}}) {
  939. print $fh '<tr><td bgcolor="'.$::EVENT_COLS[$event_ref->{'cal'} || 0].'">';
  940. my ($id, $min, $title, $data, $lengthmin, $rt, $color, $color_end);
  941. my ($startyear, $startweek, $startwday, $duration);
  942. my ($alval, $altype, $alchk, $strike);
  943. $id = $event_ref->{'id'};
  944. $min = $event_ref->{'min'};
  945. $lengthmin = $event_ref->{'lengthmin'};
  946. $title = $event_ref->{'title'};
  947. $data = $event_ref->{'data'};
  948. $rt = $event_ref->{'rt'};
  949. $startyear = $event_ref->{'startyear'};
  950. $startweek = $event_ref->{'startweek'};
  951. $startwday = $event_ref->{'startwday'};
  952. $duration = $event_ref->{'duration'};
  953. $alval = $event_ref->{'alval'} || 0;
  954. $altype = $event_ref->{'altype'} || 0;
  955. $alchk = $event_ref->{'alchk'} || "";
  956. $strike = $event_ref->{'strike'} || 0;
  957. if ($rt eq 'w') {
  958. $color = "<FONT COLOR=\"$::REPEAT_WEEK_TEXTCOLOR\" SIZE=2>";
  959. } elsif ($rt eq 'm') {
  960. $color = "<FONT COLOR=\"$::REPEAT_MONTH_TEXTCOLOR\" SIZE=2>";
  961. } else {
  962. $color = '<FONT SIZE=2>';
  963. }
  964. $color_end = "</FONT>";
  965. my $st = strcal();
  966. print $fh "<A TARGET=fevent HREF=\"$::MY_URL_XUSER/?t=event$st",
  967. "&id=", $id,
  968. "&year=", $year, "&week=", $week, "&wday=", $day_offset,
  969. "&hour=", $hour,
  970. "&min=", $min,
  971. "&lengthmin=", $lengthmin,
  972. "&title=", url_encode ($title),
  973. "&data=", url_encode ($data),
  974. "&rt=", $rt,
  975. "&startyear=", $startyear,
  976. "&startweek=", $startweek,
  977. "&startwday=", $startwday,
  978. "&duration=", $duration,
  979. "&alval=", $alval,
  980. "&altype=", $altype,
  981. "&alchk=", $alchk,
  982. "&strike=", $strike,
  983. "\">$color",
  984. $strike ? "<strike><i>" : "",
  985. $hour == -1 ? "" : ("<b>",format_time ($hour, $min)," - ",format_time (int ($hour + ($min + $lengthmin)/60) % 24, ($min + $lengthmin) % 60),"</b> "),
  986. $title,
  987. $strike ? "</i></strike>" : "",
  988. $color_end, "</A>",
  989. img_note($data),
  990. img_alarm($alval, $altype, $alchk),
  991. "</td></tr>\n";
  992. }
  993. }
  994. print $fh "</table>\n";
  995. } else {
  996. print $fh "<TD BGCOLOR=\"$::BG_TDCOLOR\"><FONT SIZE=2>&nbsp;</FONT>\n";
  997. }
  998. $day_offset++;
  999. }
  1000. return;
  1001. }
  1002. # CGI input: year, week OR nothing, in which case current date is used
  1003. sub show_week (;$) {
  1004. my ($cacheonly) = @_;
  1005. my ($week, $month, $day, $year, $first_day);
  1006. my ($weekdata, $i, @weekdays, $cached_week_ref, $cache_fh);
  1007. my ($now_date, $now_year, $now_week, $now_wday, $use_now_wday);
  1008. my ($events1, $events2, $events3, $wday_name, $now_ref);
  1009. $year = $::query->{'year'};
  1010. $week = $::query->{'week'};
  1011. if (! defined $year or ! defined $week) {
  1012. my ($ref);
  1013. $ref = get_now ();
  1014. ($year, $week) = ($ref->{'year'}, $ref->{'week'});
  1015. }
  1016. # If the week is in cache, return it
  1017. sw_check_cache:
  1018. $cached_week_ref = week_cache_read ($year, $week);
  1019. if (defined $cached_week_ref) {
  1020. $$cached_week_ref =~ s/X_USER_X/$main::USER/g;
  1021. print Socket $$cached_week_ref;
  1022. return;
  1023. }
  1024. # Find the current day to mark it in the output
  1025. $now_ref = get_now ();
  1026. ($now_year, $now_week, $now_wday) = ($now_ref->{'year'}, $now_ref->{'week'}, $now_ref->{'wday'});
  1027. if ($year == $now_year and $week == $now_week) {
  1028. $use_now_wday = $now_wday + 0;
  1029. } else {
  1030. $use_now_wday = -1;
  1031. }
  1032. if (defined $main::DATA_ID && $main::DATA_ID)
  1033. {
  1034. # Start writing the week into cache
  1035. $cache_fh = week_cache_write_open ($year, $week);
  1036. if (ref $cache_fh) {
  1037. print Socket "<BODY>Internal error: $$cache_fh</BODY>\n";
  1038. return;
  1039. }
  1040. }
  1041. else # fusion
  1042. {
  1043. $cache_fh = "Socket";
  1044. }
  1045. # Build year/month/day information of the required week
  1046. ($month, $day) = get_month_day_by_firstday_year_week ($year, $week);
  1047. $weekdays[0] = [$month, $day];
  1048. for $i (1..6) {
  1049. my ($month, $day);
  1050. ($month, $day) = get_month_day_by_wday_year_week ($i, $year, $week);
  1051. $weekdays[$i] = [$month, $day];
  1052. }
  1053. my $st = strcal();
  1054. print $cache_fh "<HEAD><META HTTP-EQUIV=refresh CONTENT=\"$::REFRESH_DELAY; url=$::MY_URL_XUSER/?t=week&year=$year&week=$week$st\"></HEAD>\n";
  1055. print $cache_fh $::H_BODY;
  1056. # Determine previous and next year & week
  1057. my ($prev_week, $next_week, $prev_year, $next_year);
  1058. $prev_week = $week - 1; $next_week = $week + 1;
  1059. $prev_year = $next_year = $year;
  1060. if ($prev_week < 2) {
  1061. ($prev_year, $prev_week )= get_prev_year_week ($year, $week);
  1062. } elsif ($next_week > 50) {
  1063. ($next_year, $next_week )= get_next_year_week ($year, $week);
  1064. }
  1065. # cal links for fusion
  1066. my $stl = lncal($year, $week);
  1067. # Output title line
  1068. print $cache_fh "<TABLE COLS=4 BORDER=0 WIDTH=\"100%\" ALIGN=center>\n";
  1069. print $cache_fh "<TR><TH ALIGN=center><FONT SIZE=6><B>$stl</B></FONT></TH>\n";
  1070. print $cache_fh "<TH COLSPAN=2 ALIGN=center><A TARGET=fweek HREF=\"$::MY_URL_XUSER/?t=week&year=$prev_year&week=$prev_week$st\"><IMG ALT=\"".__("Semaine précédente")."\" SRC=\"$::IMG_URL/left-arrow.gif\" ALIGN=middle BORDER=0></A>\n";
  1071. print $cache_fh " <A TARGET=fweek HREF=\"$::MY_URL_XUSER/?t=week&year=$now_year&week=$now_week$st\"><FONT SIZE=4><B>",sprintf(__("%s Semaine %s Année %s"),__($::months[$month]),$week,$year),"</B></FONT></A> \n";
  1072. print $cache_fh "<A TARGET=fweek HREF=\"$::MY_URL_XUSER/?t=week&year=$next_year&week=$next_week$st\"><IMG ALT=\"".__("Semaine suivante")."\" SRC=\"$::IMG_URL/right-arrow.gif\" ALIGN=middle BORDER=0></A></TH>\n";
  1073. print $cache_fh "<TH ALIGN=center><A TARGET=fevent HREF=\"$::MY_URL_XUSER/?t=views&year=$year&week=$week$st\">".__("Autres vues")."</A></TH>\n";
  1074. print $cache_fh "</TR></TABLE>\n\n";
  1075. print $cache_fh "<TABLE COLS=7 BORDER=1 WIDTH=\"100%\">\n";
  1076. print $cache_fh "<TR>\n";
  1077. # Print weekday names
  1078. $i = 0;
  1079. for $wday_name (@main::weekdays_short) {
  1080. my ($color);
  1081. if ($i == $use_now_wday) {
  1082. $color = $::NOW_THCOLOR;
  1083. } else {
  1084. $color = $::THCOLOR;
  1085. }
  1086. if ($i <= 4) {
  1087. print $cache_fh "<TH BGCOLOR=\"$color\">";
  1088. } else {
  1089. print $cache_fh "<TH BGCOLOR=\"$color\">";
  1090. }
  1091. my $st = strcal();
  1092. print $cache_fh "<A TARGET=fday HREF=\"$::MY_URL_XUSER/?t=day&year=", $year, "&week=", $week, "&wday=", $i, "$st\">", pd_month_day ($weekdays[$i]->[0], $weekdays[$i]->[1]), " ", __($wday_name), "</A>\n";
  1093. $i++;
  1094. }
  1095. $weekdata = build_week ($year, $week);
  1096. ($events1, $events2, $events3) = week_split_events_noon ($weekdata);
  1097. print $cache_fh "<TR>\n";
  1098. week_print_events ($cache_fh, $events1, $use_now_wday, $year, $week, \@weekdays);
  1099. print $cache_fh "<TR>\n";
  1100. week_print_events ($cache_fh, $events2, $use_now_wday, $year, $week, \@weekdays);
  1101. print $cache_fh "<TR>\n";
  1102. week_print_events ($cache_fh, $events3, $use_now_wday, $year, $week, \@weekdays);
  1103. print $cache_fh "</TABLE>\n</CENTER>\n</BODY>";
  1104. if (defined $main::DATA_ID && $main::DATA_ID)
  1105. {
  1106. # Now the cache should exist, so retry (someone may have removed it meanwhile, but then we just retry)
  1107. week_cache_write_close ($cache_fh);
  1108. goto sw_check_cache;
  1109. }
  1110. }
  1111. sub show_day () {
  1112. my ($day, $month, $week, $year, $wday, $wday_name, $eventsdata, @hours, @thours, $day_ref, $rt);
  1113. my ($now_ref, $now_thcolor, $is_now_day, $hour, $event_ref);
  1114. # see if we are given the day or not - if year exists, assume yes
  1115. $year = $::query->{'year'};
  1116. if (! defined $year) {
  1117. my ($now_ref);
  1118. $now_ref = get_now ();
  1119. ($year, $month, $day, $week, $wday) =
  1120. ($now_ref->{'year'}, $now_ref->{'month'}, $now_ref->{'day'}, $now_ref->{'week'}, $now_ref->{'wday'});
  1121. } else {
  1122. $week = $::query->{'week'};
  1123. $wday = $::query->{'wday'};
  1124. }
  1125. $wday_name = $::weekdays[$wday];
  1126. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  1127. $day_ref = build_day ($year, $week, $wday, $day);
  1128. # Build list of events on each hour
  1129. @hours = ();
  1130. for $hour (sort { $a <=> $b } keys %$day_ref) {
  1131. if ($hour == -1)
  1132. {
  1133. for $event_ref (@{$day_ref->{$hour}}) {
  1134. push @{$hours[24]}, $event_ref;
  1135. }
  1136. }
  1137. else
  1138. {
  1139. for $event_ref (@{$day_ref->{$hour}}) {
  1140. push @{$hours[$hour]}, $event_ref;
  1141. }
  1142. }
  1143. }
  1144. # Count how many events will be on each row
  1145. my ($max_c, $cols, @rows);
  1146. $max_c = 0;
  1147. @rows = (0) x ($::LAST_HOUR + 1);
  1148. for $hour ($::FIRST_HOUR .. $::LAST_HOUR) {
  1149. if ($hours[$hour]) {
  1150. for $event_ref (@{$hours[$hour]}) {
  1151. my ($lengthmin, $min, $end_hour, $h);
  1152. $lengthmin = $event_ref->{'lengthmin'};
  1153. $min = $event_ref->{'min'};
  1154. $end_hour = $hour + int (($lengthmin + $min - 1) / 60) % 24;
  1155. for $h ($hour .. $end_hour) {
  1156. my ($c);
  1157. $c = ++$rows[$h];
  1158. if ($c > $max_c) {
  1159. $max_c = $c;
  1160. }
  1161. }
  1162. }
  1163. }
  1164. }
  1165. $max_c = 1 if $max_c == 0;
  1166. $cols = $max_c + 1;
  1167. $now_ref = get_now ();
  1168. if ($now_ref->{'year'} == $year and $now_ref->{'month'} == $month and $now_ref->{'day'} == $day) {
  1169. $is_now_day = 1;
  1170. } else {
  1171. $is_now_day = 0;
  1172. }
  1173. if ($is_now_day) {
  1174. $now_thcolor = $::NOW_THCOLOR;
  1175. } else {
  1176. $now_thcolor = $::THCOLOR;
  1177. }
  1178. my $st = strcal();
  1179. print Socket "<HEAD><META HTTP-EQUIV=refresh CONTENT=\"$::REFRESH_DELAY; url=$::MY_URL/?t=day&year=$year&week=$week&wday=$wday$st\"></HEAD>\n";
  1180. print Socket "<BASE TARGET=fevent>\n";
  1181. print Socket $::H_BODY;
  1182. print Socket "<TABLE BORDER=2 CELLSPACING=0 WIDTH=\"90%\">\n";
  1183. print Socket "<TR><TH WIDTH=10><TH COLSPAN=$max_c WIDTH=\"100%\" BGCOLOR=\"$::THCOLOR\">\n";
  1184. print Socket "<TR><TD COLSPAN=$cols BGCOLOR=\"$now_thcolor\" ALIGN=center><B>", pd_year_month_day ($year, $month, $day), " ", __("$wday_name")."</B>\n";
  1185. if (defined $::READ_ONLY and $::READ_ONLY ne 'true' and clipboard_get ($::REMOTE_USER)) {
  1186. print Socket "&nbsp;&nbsp;<A TARGET=_top HREF=\"$::MY_URL/?t=redraw&view=paste_event&year=$year&week=$week&wday=$wday$st\">[".__("Coller")."]</A>\n";
  1187. }
  1188. print Socket "</TD>\n";
  1189. print Socket "<TR><TD BGCOLOR=\"$::THCOLOR\">\n";
  1190. if ($::READ_ONLY ne 'true') {
  1191. print Socket "<A HREF=\"$::MY_URL/?t=add_edit$st",
  1192. "&year=", $year, "&week=", $week, "&wday=", $wday, "&hour=-1\">";
  1193. print Socket "&gt;</A>\n";
  1194. }
  1195. else
  1196. {
  1197. print Socket "&gt;\n";
  1198. }
  1199. print Socket "</TD><TD BGCOLOR=\"$::BG_TDCOLOR\"";
  1200. if ($max_c > 1)
  1201. {
  1202. print Socket "COLSPAN=\"$max_c\"";
  1203. }
  1204. print Socket "><table width=100% cellpadding=0 cellspacing=0 border=0>\n";
  1205. my $isev = 0;
  1206. my $sthour;
  1207. my $sttime;
  1208. for $hour (0 .. $::FIRST_HOUR-1, $::LAST_HOUR+1 .. 25)
  1209. {
  1210. if ($hours[$hour])
  1211. {
  1212. $isev = 1;
  1213. my (@events, $event_ref);
  1214. @events = @{$hours[$hour]};
  1215. for $event_ref (@events) {
  1216. my ($id, $min, $title, $data, $lengthmin, $rcolor, $rcolor_end);
  1217. my ($startyear, $startweek, $startwday, $duration);
  1218. my ($alval, $altype, $alchk, $strike);
  1219. $id = $event_ref->{'id'};
  1220. $min = $event_ref->{'min'};
  1221. $lengthmin = $event_ref->{'lengthmin'};
  1222. $title = $event_ref->{'title'};
  1223. $data = $event_ref->{'data'};
  1224. $rt = $event_ref->{'rt'};
  1225. $startyear = $event_ref->{'startyear'};
  1226. $startweek = $event_ref->{'startweek'};
  1227. $startwday = $event_ref->{'startwday'};
  1228. $duration = $event_ref->{'duration'};
  1229. $alval = $event_ref->{'alval'} || 0;
  1230. $altype = $event_ref->{'altype'} || 0;
  1231. $alchk = $event_ref->{'alchk'} || "";
  1232. $strike = $event_ref->{'strike'} || 0;
  1233. if ($rt eq 'w') {
  1234. $rcolor = "<FONT COLOR=\"$::REPEAT_WEEK_TEXTCOLOR\">";
  1235. $rcolor_end = "</FONT>";
  1236. } elsif ($rt eq 'm') {
  1237. $rcolor = "<FONT COLOR=\"$::REPEAT_MONTH_TEXTCOLOR\">";
  1238. $rcolor_end = "</FONT>";
  1239. } else {
  1240. $rcolor = $rcolor_end = '';
  1241. }
  1242. if ($hour == 24)
  1243. {
  1244. $sthour = -1;
  1245. $sttime = "";
  1246. }
  1247. else
  1248. {
  1249. $sthour = $hour;
  1250. $sttime = "<b>".format_time($hour, $min)." - ".format_time(int($hour + ($min + $lengthmin)/60) % 24, ($min + $lengthmin) % 60)."</b> ";
  1251. }
  1252. print Socket '<TR><TD BGCOLOR="'.$::EVENT_COLS[$event_ref->{'cal'} || 0].'" ROWSPAN=', int (($lengthmin + $min + 59) / 60) % 24, "><FONT SIZE=2>",
  1253. "<P><A HREF=\"$::MY_URL/?t=event&id=", $id,
  1254. "&year=", $year, "&week=", $week, "&wday=", $wday,
  1255. "&hour=", $sthour, "&min=", $min,
  1256. "&lengthmin=", $lengthmin,
  1257. "&title=", url_encode ($title),
  1258. "&data=", url_encode ($data),
  1259. "&rt=", $rt,
  1260. "&startyear=", $startyear,
  1261. "&startweek=", $startweek,
  1262. "&startwday=", $startwday,
  1263. "&duration=", $duration,
  1264. "&alval=", $alval,
  1265. "&altype=", $altype,
  1266. "&alchk=", $alchk,
  1267. "&strike=", $strike,
  1268. "$st\">", $rcolor,
  1269. $strike ? "<strike><i>" : "",
  1270. $sttime, $title,
  1271. $strike ? "</i></strike>" : "",
  1272. $rcolor_end, "</A>",
  1273. img_note($data), img_alarm($alval, $altype, $alchk), "</TD></TR>\n";
  1274. }
  1275. }
  1276. }
  1277. print Socket "</table>";
  1278. if (!$isev)
  1279. {
  1280. print Socket "&nbsp;\n";
  1281. }
  1282. print Socket "</TD></TR>\n";
  1283. for $hour ($::FIRST_HOUR .. $::LAST_HOUR) {
  1284. #
  1285. # Print hour
  1286. #
  1287. print Socket "<TR><TD BGCOLOR=\"$::THCOLOR\"><FONT SIZE=2>";
  1288. if ($::READ_ONLY ne 'true') {
  1289. print Socket "<A HREF=\"$::MY_URL/?t=add_edit$st",
  1290. "&year=", $year, "&week=", $week, "&wday=", $wday, "&hour=", $hour, "\">";
  1291. }
  1292. print Socket format_hour_padded ($hour);
  1293. if ($::READ_ONLY ne 'true') {
  1294. print Socket "</A>\n";
  1295. }
  1296. #
  1297. # Print events for this hour
  1298. #
  1299. if ($hours[$hour]) {
  1300. my (@events, $event_ref);
  1301. @events = @{$hours[$hour]};
  1302. for $event_ref (@events) {
  1303. my ($id, $min, $title, $data, $lengthmin, $rcolor, $rcolor_end);
  1304. my ($startyear, $startweek, $startwday, $duration);
  1305. my ($alval, $altype, $alchk, $strike);
  1306. $id = $event_ref->{'id'};
  1307. $min = $event_ref->{'min'};
  1308. $lengthmin = $event_ref->{'lengthmin'};
  1309. $title = $event_ref->{'title'};
  1310. $data = $event_ref->{'data'};
  1311. $rt = $event_ref->{'rt'};
  1312. $startyear = $event_ref->{'startyear'};
  1313. $startweek = $event_ref->{'startweek'};
  1314. $startwday = $event_ref->{'startwday'};
  1315. $duration = $event_ref->{'duration'};
  1316. $alval = $event_ref->{'alval'} || 0;
  1317. $altype = $event_ref->{'altype'} || 0;
  1318. $alchk = $event_ref->{'alchk'} || "";
  1319. $strike = $event_ref->{'strike'} || 0;
  1320. if ($rt eq 'w') {
  1321. $rcolor = "<FONT COLOR=\"$::REPEAT_WEEK_TEXTCOLOR\">";
  1322. $rcolor_end = "</FONT>";
  1323. } elsif ($rt eq 'm') {
  1324. $rcolor = "<FONT COLOR=\"$::REPEAT_MONTH_TEXTCOLOR\">";
  1325. $rcolor_end = "</FONT>";
  1326. } else {
  1327. $rcolor = $rcolor_end = '';
  1328. }
  1329. print Socket '<TD BGCOLOR="'.$::EVENT_COLS[$event_ref->{'cal'} || 0].'" ROWSPAN=', int (($lengthmin + $min + 59) / 60) % 24, "><FONT SIZE=2>",
  1330. "<P><A HREF=\"$::MY_URL/?t=event&id=", $id,
  1331. "&year=", $year, "&week=", $week, "&wday=", $wday,
  1332. "&hour=", $hour, "&min=", $min,
  1333. "&lengthmin=", $lengthmin,
  1334. "&title=", url_encode ($title),
  1335. "&data=", url_encode ($data),
  1336. "&rt=", $rt,
  1337. "&startyear=", $startyear,
  1338. "&startweek=", $startweek,
  1339. "&startwday=", $startwday,
  1340. "&duration=", $duration,
  1341. "&alval=", $alval,
  1342. "&altype=", $altype,
  1343. "&alchk=", $alchk,
  1344. "&strike=", $strike,
  1345. "$st\">", $rcolor,
  1346. $strike ? "<strike><i>" : "",
  1347. $title,
  1348. $strike ? "</i></strike>" : "",
  1349. $rcolor_end, "</A>",
  1350. img_note($data), img_alarm($alval, $altype, $alchk), "\n";
  1351. }
  1352. }
  1353. print Socket "<TD BGCOLOR=\"$::BG_TDCOLOR\">&nbsp;" x ($max_c - $rows[$hour]), "\n";
  1354. }
  1355. sd_end:
  1356. print Socket "</TABLE></CENTER>\n</BODY>\n";
  1357. }
  1358. sub show_event () {
  1359. my ($year, $month, $day, $week, $wday, $wday_name, $weekdata, @hours, $day_ref, $rt);
  1360. my ($hour, $min, $lengthmin, $title, $data, $endhour, $endmin, $id, $is_now, $now_thcolor, $rcolor);
  1361. my ($startyear, $startweek, $startwday, $duration);
  1362. my ($alval, $altype, $alchk, $strike);
  1363. $id = $::query->{'id'};
  1364. $year = $::query->{'year'};
  1365. $week = $::query->{'week'};
  1366. $wday = $::query->{'wday'} || 0;
  1367. $wday_name = $::weekdays[$wday];
  1368. $hour = $::query->{'hour'} || 0;
  1369. $min = $::query->{'min'} || 0;
  1370. $lengthmin = $::query->{'lengthmin'} || 0;
  1371. $title = $::query->{'title'};
  1372. $data = $::query->{'data'};
  1373. $rt = $::query->{'rt'};
  1374. $is_now = $::query->{'is_now'};
  1375. $startyear = $::query->{'startyear'};
  1376. $startweek = $::query->{'startweek'};
  1377. $startwday = $::query->{'startwday'};
  1378. $duration = $::query->{'duration'};
  1379. $alval = $::query->{'alval'} || 0;
  1380. $altype = $::query->{'altype'} || 0;
  1381. $alchk = $::query->{'alchk'} || "";
  1382. $strike = $::query->{'strike'} || 0;
  1383. if (! defined $year or ! defined $title) {
  1384. my ($n);
  1385. $n = get_now ();
  1386. show_other_views ($n->{'year'}, $n->{'week'});
  1387. return;
  1388. }
  1389. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  1390. $endhour = int ($hour + ($min + $lengthmin) / 60) % 24;
  1391. $endmin = int (($min + $lengthmin) % 60);
  1392. print Socket $::H_BODY;
  1393. if ($is_now) {
  1394. $now_thcolor = $::NOW_THCOLOR;
  1395. } else {
  1396. $now_thcolor = $::THCOLOR;
  1397. }
  1398. if ($rt eq 'w') {
  1399. $rcolor = "COLOR=\"$::REPEAT_WEEK_TEXTCOLOR\"";
  1400. } elsif ($rt eq 'm') {
  1401. $rcolor = "COLOR=\"$::REPEAT_MONTH_TEXTCOLOR\"";
  1402. } else {
  1403. $rcolor = '';
  1404. }
  1405. print Socket "<CENTER>\n<TABLE BORDER=1 COLS=1 CELLPADDING=10 ALIGN=center VALIGN=middle WIDTH=\"80%\" BGCOLOR=\"$::TDCOLOR\">\n";
  1406. print Socket "<TR><TH ALIGN=center BGCOLOR=\"$now_thcolor\">".__("Tâche le")." ", pd_event_date ($rt, $startyear, $startweek, $startwday, $duration);
  1407. print Socket "\n<TR><TD BGCOLOR=\"$::TDCOLOR\" ALIGN=left>\n";
  1408. my ($stk1, $stk2) = $strike ? ("<strike><i>","</i></strike>") : ("","");
  1409. if ($hour == -1)
  1410. {
  1411. printf Socket "<P><CENTER><FONT SIZE=\"4\" $rcolor><B>$stk1$title$stk2";
  1412. }
  1413. else
  1414. {
  1415. printf Socket "<P><CENTER><FONT SIZE=\"4\" $rcolor><B>$stk1%s - %s $title$stk2", format_time ($hour, $min), format_time ($endhour, $endmin);
  1416. }
  1417. print Socket (($rt eq 'w') ? ' ('.__("hebdomadaire").')' : ( ( $rt eq 'm' ) ? ' ('.__("mensuelle").')' : '' ));
  1418. print Socket "</B></FONT>", txt_alarm($alval, $altype, $alchk), "</CENTER>\n";
  1419. print Socket "<P>$data\n";
  1420. print Socket "</TABLE>\n";
  1421. my $st = strcal();
  1422. if ($::READ_ONLY ne 'true') {
  1423. my ($enc_title, $enc_data);
  1424. $enc_title = url_encode ($title);
  1425. $enc_data = url_encode ($data);
  1426. my $stk3 = $strike ? __("Activer") : __("Désactiver");
  1427. print Socket "<A HREF=\"$::MY_URL/?t=add_edit&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&min=$min&lengthmin=$lengthmin&title=$enc_title&data=$enc_data&rt=$rt&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike$st\">",
  1428. "[".__("Editer")."]</A>\n";
  1429. print Socket "&nbsp;&nbsp;&nbsp;<A TARGET=\"_top\" HREF=\"$::MY_URL/?t=redraw&view=after_remove_event&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&title=$enc_title&data=$enc_data&rt=$rt&min=$min&lengthmin=$lengthmin&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike$st\">",
  1430. "[".__("Couper")."]</A>\n";
  1431. print Socket "&nbsp;&nbsp;&nbsp;<A HREF=\"$::MY_URL/?t=copy_event&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&min=$min&lengthmin=$lengthmin&title=$enc_title&data=$enc_data&rt=$rt&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike$st\">",
  1432. "[".__("Copier")."]</A>\n";
  1433. print Socket "&nbsp;&nbsp;&nbsp;<A TARGET=\"_top\" HREF=\"$::MY_URL/?t=redraw&view=after_delete_event&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&title=$enc_title&data=$enc_data&rt=$rt&min=$min&lengthmin=$lengthmin&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike$st\">",
  1434. "[".__("Supprimer")."]</A>\n";
  1435. print Socket "&nbsp;&nbsp;&nbsp;<A TARGET=\"_top\" HREF=\"$::MY_URL/?t=redraw&view=after_strike_event&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&title=$enc_title&data=$enc_data&rt=$rt&min=$min&lengthmin=$lengthmin&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike$st\">",
  1436. "[$stk3]</A>\n";
  1437. }
  1438. print Socket "</CENTER></BODY>\n";
  1439. }
  1440. sub add_edit_event_ask () {
  1441. my ($id, $year, $month, $day, $week, $wday, $wday_name, $weekdata, @hours, $day_ref);
  1442. my ($hour, $min, $lengthmin, $title, $data, $endhour, $endmin, $rt, $duration);
  1443. my ($startyear, $startweek, $startwday, $startmonth, $startday);
  1444. my ($endyear, $endweek, $endwday, $endmonth, $endday);
  1445. $id = $::query->{'id'} || '';
  1446. $year = $::query->{'year'};
  1447. $week = $::query->{'week'};
  1448. $wday = $::query->{'wday'};
  1449. $wday_name = $::weekdays[$wday];
  1450. $hour = $::query->{'hour'};
  1451. $min = $::query->{'min'} || 0;
  1452. $lengthmin = $::query->{'lengthmin'};
  1453. $rt = $::query->{'rt'} || 'n';
  1454. $title = $::query->{'title'} || '';
  1455. $data = $::query->{'data'} || '';
  1456. $startyear = $::query->{'startyear'} || $year;
  1457. $startweek = $::query->{'startweek'} || $week;
  1458. $startwday = defined $::query->{'startwday'} ? $::query->{'startwday'} : $wday;
  1459. $duration = $::query->{'duration'} || 1;
  1460. my $strike = $::query->{'strike'} || 0;
  1461. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  1462. if ($id) {
  1463. if ($hour == -1)
  1464. {
  1465. $endhour = -1;
  1466. $endmin = -1;
  1467. }
  1468. else
  1469. {
  1470. $endhour = int ($hour + ($min + $lengthmin) / 60) % 24;
  1471. $endmin = int (($min + $lengthmin) % 60);
  1472. }
  1473. } else {
  1474. $endhour = $hour+1;
  1475. $endmin = 0;
  1476. }
  1477. ($startmonth, $startday, $endyear, $endweek, $endwday, $endmonth, $endday) =
  1478. get_start_end_by_year_week_wday_duration ($startyear, $startweek, $startwday, $duration);
  1479. print Socket $::H_BODY;
  1480. print Socket "<CENTER>\n";
  1481. print Socket "<TABLE BORDER=1 COLS=1 CELLPADDING=3 ALIGN=center WIDTH=\"100%\" BGCOLOR=\"$::TDCOLOR\">\n";
  1482. print Socket "<TR><TH ALIGN=center BGCOLOR=\"$::THCOLOR\"><B>";
  1483. if ($id) {
  1484. print Socket __("Editer tâche");
  1485. } else {
  1486. print Socket __("Ajouter tâche");
  1487. }
  1488. print Socket " ".pd_event_date ($rt, $startyear, $startweek, $startwday, $duration);
  1489. print Socket "</B></TH></TR>\n";
  1490. print Socket "<TR><TD BGCOLOR=\"$::TDCOLOR\">\n";
  1491. print Socket "<CENTER><TABLE BORDER=0 BGCOLOR=\"$::TDCOLOR\" CELLSPACING=0 CELLPADDING=0>\n\n";
  1492. print Socket "<FORM TARGET=_top ACTION=\"$::MY_URL\" METHOD=GET>\n";
  1493. print Socket "<INPUT TYPE=HIDDEN NAME=oldrt VALUE=$rt>\n";
  1494. print Socket "<INPUT TYPE=HIDDEN NAME=oldhour VALUE=$hour>\n";
  1495. print Socket "<INPUT TYPE=HIDDEN NAME=oldduration VALUE=$duration>\n";
  1496. print Socket "<INPUT TYPE=HIDDEN NAME=year VALUE=$year>\n";
  1497. print Socket "<INPUT TYPE=HIDDEN NAME=week VALUE=$week>\n";
  1498. print Socket "<INPUT TYPE=HIDDEN NAME=wday VALUE=$wday>\n";
  1499. print Socket "<INPUT TYPE=HIDDEN NAME=startyear VALUE=$startyear>\n";
  1500. print Socket "<INPUT TYPE=HIDDEN NAME=startweek VALUE=$startweek>\n";
  1501. print Socket "<INPUT TYPE=HIDDEN NAME=startwday VALUE=$startwday>\n";
  1502. print Socket "<INPUT TYPE=HIDDEN NAME=t VALUE=redraw>\n";
  1503. print Socket "<INPUT TYPE=HIDDEN NAME=view VALUE=add_event>\n";
  1504. print Socket "<INPUT TYPE=HIDDEN NAME=id VALUE=$id>\n";
  1505. print Socket "<INPUT TYPE=HIDDEN NAME=strike VALUE=$strike>\n";
  1506. # Event time
  1507. print Socket "<TR><TD ALIGN=left>\n";
  1508. print Socket __("Heure début")."</TD><TD><SELECT NAME=hour1>\n";
  1509. print Socket "<OPTION VALUE=-1 ", ($hour == -1 ? 'SELECTED' : ''), ">\n";
  1510. for (0 .. 23) {
  1511. print Socket "<OPTION VALUE=$_ ", (($_ == $hour) ? 'SELECTED' : ''), ">", format_hour_padded ($_), "\n";
  1512. }
  1513. print Socket "</SELECT>\n";
  1514. print Socket "<SELECT NAME=min1>\n";
  1515. print Socket "<OPTION VALUE=-1 ", ($min == -1 ? 'SELECTED' : ''), ">\n";
  1516. for (qw (00 15 30 45)) {
  1517. print Socket "<OPTION VALUE=$_ ", (($_ == $min) ? 'SELECTED' : ''), ">$_\n";
  1518. }
  1519. print Socket "</SELECT>\n";
  1520. print Socket " - \n";
  1521. print Socket "<SELECT NAME=hour2>\n";
  1522. print Socket "<OPTION VALUE=-1 ", ($endhour == -1 ? 'SELECTED' : ''), ">\n";
  1523. for (0 .. 23) {
  1524. print Socket "<OPTION VALUE=$_ ", (($_ == $endhour) ? 'SELECTED' : ''), ">", format_hour_padded ($_), "\n";
  1525. }
  1526. print Socket "</SELECT>\n";
  1527. print Socket "<SELECT NAME=min2>\n";
  1528. print Socket "<OPTION VALUE=-1 ", ($endmin == -1 ? 'SELECTED' : ''), ">\n";
  1529. for (qw (00 15 30 45)) {
  1530. print Socket "<OPTION VALUE=$_ ", (($_ == $endmin) ? 'SELECTED' : ''), ">$_\n";
  1531. }
  1532. print Socket "</SELECT>\n</TD></TR>\n";
  1533. # Duration (days)
  1534. print Socket "<TR><TD>".__("Durée")."</TD><TD><SELECT NAME=duration>\n";
  1535. for (1 .. $::MAX_DURATION) {
  1536. print Socket "<OPTION VALUE=$_ ", (($_ == $duration) ? 'SELECTED' : ''), ">$_ ", ($_ == 1 ? __("jour") : __("jours")), "\n";
  1537. }
  1538. print Socket "</SELECT>\n";
  1539. # Repeat
  1540. my ($sn, $sw, $sm);
  1541. $sn = $sw = $sm = '';
  1542. if ($rt eq 'n') {
  1543. $sn = 'SELECTED';
  1544. } elsif ($rt eq 'w') {
  1545. $sw = 'SELECTED';
  1546. } elsif ($rt eq 'm') {
  1547. $sm = 'SELECTED';
  1548. }
  1549. print Socket "<SELECT NAME=rt>";
  1550. print Socket "<OPTION VALUE=n $sn>".__("Sans répétition");
  1551. print Socket "<OPTION VALUE=w $sw>".__("Répéter toutes les semaines");
  1552. print Socket "<OPTION VALUE=m $sm>".__("Répéter tous les mois");
  1553. print Socket "</SELECT>\n</TD></TR>\n";
  1554. # Alarm
  1555. print Socket "<TR><TD ALIGN=left>".__("Alarme")."</TD>";
  1556. my $alval = $::query->{'alval'} || 0;
  1557. print Socket "<TD><SELECT NAME=alval>\n";
  1558. for (0 .. 23) {
  1559. print Socket "<OPTION VALUE=$_ ", (($_ == $alval) ? 'SELECTED' : ''), ">", ($_) ? $_ : '' ,"\n";
  1560. }
  1561. print Socket "</SELECT>\n";
  1562. my $altype = $::query->{'altype'} || 0;
  1563. print Socket "<SELECT NAME=altype>\n";
  1564. for (0 .. 3) {
  1565. print Socket "<OPTION VALUE=$_ ", (($_ == $altype) ? 'SELECTED' : ''), ">".format_alarm_type($_)."\n";
  1566. }
  1567. my $alchk = $::query->{'alchk'} || "";
  1568. print Socket "</SELECT>\n";
  1569. print Socket '<INPUT TYPE="checkbox" NAME="alchk" VALUE="'.$alchk.'"';
  1570. if ($alchk)
  1571. {
  1572. print Socket ' CHECKED';
  1573. }
  1574. print Socket "> ".__("lancée");
  1575. print Socket "</TD>\n";
  1576. # Title
  1577. print Socket "<TR><TD ALIGN=left>".__("Titre")."</TD><TD>";
  1578. print Socket "<INPUT SIZE=51 NAME=title VALUE=\"", html_to_newline ($title), "\"></TD></TR>";
  1579. # Data
  1580. print Socket "<TR><TD ALIGN=left COLSPAN=2><TEXTAREA ROWS=", ($::SCREEN_RESOLUTION eq '800x600' ? 2 : 4) ," COLS=58 NAME=\"data\">", html_to_newline ($data), "</TEXTAREA></TD></TR>";
  1581. print Socket "</TABLE>\n";
  1582. # Submit
  1583. my ($submit_value);
  1584. $submit_value = ($id ? __("Valider") : __("Ajouter"));
  1585. print Socket "<INPUT TYPE=submit VALUE=\"$submit_value\">\n";
  1586. print Socket "</FORM></CENTER>\n";
  1587. print Socket "</TABLE>\n";
  1588. print Socket "</FORM></CENTER>\n";
  1589. print Socket "</BODY>\n";
  1590. }
  1591. sub print_event_error_start () {
  1592. print Socket $::H_BODY;
  1593. print Socket "<DIV ALIGN=center VALIGN=middle>\n";
  1594. print Socket "<TABLE BORDER=1 CELLPADDING=10 ALIGN=center VALIGN=middle BGCOLOR=\"$::TDCOLOR\" WIDTH=\"80%\">\n<TR><TD><BR><BR>\n\n";
  1595. }
  1596. sub print_event_error_end () {
  1597. print Socket "<BR><BR></TABLE>\n</BODY>\n";
  1598. }
  1599. sub day_index ($$$$) {
  1600. my ($rt, $year, $week, $wday) = @_;
  1601. my ($index);
  1602. # Index by day or wday, depending on repeat type
  1603. if ($rt eq 'n' or $rt eq 'w') {
  1604. $index = $wday + 0;
  1605. } else {
  1606. my ($month, $day);
  1607. ($month, $day) = get_month_day_by_wday_year_week ($wday, $year, $week);
  1608. $index = $day + 0;
  1609. }
  1610. return $index;
  1611. }
  1612. # Read, update, and write new highest event id into general database
  1613. # Return the (id, possible error or false)
  1614. sub next_id () {
  1615. my ($id, $gendata, $err);
  1616. $gendata = read_general ();
  1617. if (! ref $gendata eq 'HASH') {
  1618. $err = $gendata;
  1619. return ('', $err);
  1620. }
  1621. $id = $gendata->{'highid'} + 1;
  1622. $gendata->{'highid'} = $id;
  1623. $err = write_general ($gendata);
  1624. if ($err) {
  1625. return ('', $err);
  1626. }
  1627. return ($id, '');
  1628. }
  1629. sub remove_events ($$$$$$$) {
  1630. my ($rt, $year, $week, $wday, $duration, $hour, $id) = @_;
  1631. my ($i);
  1632. for $i (0 .. $duration - 1) {
  1633. my ($cyear, $cweek, $cwday, $index_day, $hour_ref, $eventsdata, @hour, $err);
  1634. ($cyear, $cweek, $cwday) = get_year_week_wday_by_year_week_wday_plus_days ($year, $week, $wday, $i);
  1635. $index_day = day_index ($rt, $cyear, $cweek, $cwday);
  1636. $eventsdata = read_events ($rt, $cyear, $cweek);
  1637. $hour_ref = $eventsdata->[$index_day]->{$hour};
  1638. if (ref $hour_ref eq 'ARRAY') {
  1639. my ($i);
  1640. @hour = @$hour_ref;
  1641. for $i (0 .. $#hour) {
  1642. if ($hour[$i]->{'id'} == $id) {
  1643. splice (@hour, $i, 1);
  1644. goto re_found;
  1645. }
  1646. }
  1647. }
  1648. return "internal error: the event isn't in the database (user ${main::DATA_ID}, year $cyear, week $cweek, wday $cwday, id $id, rt $rt)";
  1649. re_found:
  1650. if (@hour) {
  1651. $eventsdata->[$index_day]->{$hour+0} = \@hour;
  1652. } else {
  1653. # no events left for this hour, so remove whole hour
  1654. delete $eventsdata->[$index_day]->{$hour};
  1655. }
  1656. $err = write_events ($eventsdata, $rt, $cyear, $cweek);
  1657. if ($err) {
  1658. return $err;
  1659. }
  1660. }
  1661. return '';
  1662. }
  1663. sub add_events {
  1664. my ($rt, $year, $week, $wday, $duration, $hour, $id, $min, $lengthmin, $title, $data, $alval, $altype, $alchk, $strike) = @_;
  1665. my ($i, $err);
  1666. if (!$alval)
  1667. {
  1668. $alval = 0;
  1669. }
  1670. if (!$altype)
  1671. {
  1672. $altype = 0;
  1673. }
  1674. if (!$alchk)
  1675. {
  1676. $alchk = "";
  1677. }
  1678. if (!$strike)
  1679. {
  1680. $strike = 0;
  1681. }
  1682. # Figure out the new $id
  1683. if (! $id) {
  1684. my ($gendata);
  1685. # Read, update, and write new highest event id into general database
  1686. $gendata = read_general ();
  1687. if (! ref $gendata eq 'HASH') {
  1688. $err = $gendata;
  1689. return $err;
  1690. }
  1691. $id = $gendata->{'highid'} + 1;
  1692. $gendata->{'highid'} = $id;
  1693. $err = write_general ($gendata);
  1694. if ($err) {
  1695. return $err;
  1696. }
  1697. }
  1698. for $i (0 .. $duration - 1) {
  1699. my ($cyear, $cweek, $cwday, $index_day, $eventsdata);
  1700. ($cyear, $cweek, $cwday) = get_year_week_wday_by_year_week_wday_plus_days ($year, $week, $wday, $i);
  1701. $index_day = day_index ($rt, $cyear, $cweek, $cwday);
  1702. # Read events, add, write back
  1703. $eventsdata = read_events ($rt, $cyear, $cweek);
  1704. push @{$eventsdata->[$index_day]->{$hour+0}},
  1705. {
  1706. 'id' => $id + 0,
  1707. 'min' => $min + 0,
  1708. 'lengthmin' => $lengthmin + 0,
  1709. 'title' => $title,
  1710. 'data' => $data,
  1711. 'rt' => $rt,
  1712. 'startyear' => $year + 0,
  1713. 'startweek' => $week + 0,
  1714. 'startwday' => $wday + 0,
  1715. 'duration' => $duration + 0,
  1716. 'alval' => $alval + 0,
  1717. 'altype' => $altype + 0,
  1718. 'alchk' => $alchk,
  1719. 'strike' => $strike,
  1720. };
  1721. $err = write_events ($eventsdata, $rt, $cyear, $cweek);
  1722. if ($err) {
  1723. return $err;
  1724. }
  1725. }
  1726. return '';
  1727. }
  1728. sub add_event_commit () {
  1729. my ($id, $year, $month, $day, $week, $wday, $wday_name, $rt);
  1730. my ($hour1, $min1, $hour2, $min2, $lengthmin, $title, $data, $endhour, $endmin);
  1731. my ($err, $i);
  1732. my ($oldrt, $oldhour);
  1733. my ($oldhour_ref, @hour, $oldduration, $duration);
  1734. my ($startyear, $startweek, $startwday, $startmonth, $startday);
  1735. my ($alval, $altype, $alchk, $strike);
  1736. $oldrt = $::query->{'oldrt'};
  1737. $oldhour = $::query->{'oldhour'};
  1738. $oldduration = $::query->{'oldduration'};
  1739. $id = $::query->{'id'} || '';
  1740. $year = $::query->{'year'};
  1741. $week = $::query->{'week'};
  1742. $wday = $::query->{'wday'};
  1743. $startyear = $::query->{'startyear'};
  1744. $startweek = $::query->{'startweek'};
  1745. $startwday = $::query->{'startwday'};
  1746. $duration = $::query->{'duration'};
  1747. $hour1 = $::query->{'hour1'};
  1748. $min1 = $::query->{'min1'};
  1749. $hour2 = $::query->{'hour2'};
  1750. $min2 = $::query->{'min2'};
  1751. $rt = $::query->{'rt'};
  1752. $title = strip_space $::query->{'title'};
  1753. $data = strip_space $::query->{'data'} || '';
  1754. $alval = $::query->{'alval'} || 0;
  1755. $altype = $::query->{'altype'} || 0;
  1756. $alchk = $::query->{'alchk'} || "";
  1757. $strike = $::query->{'strike'} || 0;
  1758. ($startmonth, $startday) = get_month_day_by_wday_year_week ($startwday, $startyear, $startweek);
  1759. if ($hour1 == -1)
  1760. {
  1761. $min1 = -1;
  1762. $hour2 = -1;
  1763. $min2 = -1;
  1764. $lengthmin = -1;
  1765. }
  1766. else
  1767. {
  1768. $lengthmin = $hour2*60 + $min2 - $hour1*60 - $min1;
  1769. }
  1770. if (! defined $title or ! $title) {
  1771. return "The title of the event must be entered.";
  1772. } elsif (! &ParseDate ("$startmonth/$startday/$startyear")) {
  1773. return "Date $startday.$startmonth.$startyear is invalid."
  1774. } elsif ($duration < 1 or $duration > $::MAX_DURATION) {
  1775. return "You chose impossible duration \"$duration\"."
  1776. } elsif ($rt eq 'w' and ! fit_in_week ($startyear, $startweek, $startwday, $duration)) {
  1777. return "Weekly repeating event must fit entirely in one week."
  1778. } elsif ($rt eq 'm' and ! fit_in_month ($startyear, $startweek, $startwday, $duration)) {
  1779. return "Monthly repeating event must fit entirely in one month (the month you placed it in specifically)."
  1780. } elsif ($rt ne 'n' and $rt ne 'w' and $rt ne 'm') {
  1781. return "You chose impossible repeat type \"$rt\"."
  1782. } elsif (has_html $title or has_html $data) {
  1783. return "Text contains one more more of the illegal characters <, > and &."
  1784. } elsif ($lengthmin <= 0 && $hour1 != -1) {
  1785. return "The start of the event ($hour1:$min1) must be before its end ($hour2:$min2)."
  1786. }
  1787. $title = newline_to_html $title;
  1788. $data = newline_to_html $data;
  1789. #
  1790. # Remove the old event. The old one only exists if $id is set so this is
  1791. # an edit command.
  1792. #
  1793. if ($id) {
  1794. $err = remove_events ($oldrt, $startyear, $startweek, $startwday, $oldduration, $oldhour, $id);
  1795. if ($err) {
  1796. return $err;
  1797. }
  1798. }
  1799. #
  1800. # Figure out the new $id
  1801. #
  1802. if (! $id) {
  1803. ($id, $err) = next_id ();
  1804. if ($err) {
  1805. return $err;
  1806. }
  1807. }
  1808. #
  1809. # Add event for each day
  1810. #
  1811. $err = add_events ($rt, $startyear, $startweek, $startwday, $duration, $hour1, $id,
  1812. $min1, $lengthmin, $title, $data, $alval, $altype, $alchk, $strike);
  1813. if ($err) {
  1814. return $err;
  1815. }
  1816. #
  1817. # When we get here, add has been succesful.
  1818. #
  1819. # Return the id and some other items to redraw(), since he doesn't know
  1820. # them otherwise.
  1821. #
  1822. return { 'id' => $id, 'lengthmin' => $lengthmin, 'data' => $data, 'title' => $title };
  1823. }
  1824. sub remove_event_commit ($$$$$$$$$$$$$$) {
  1825. my ($year, $week, $wday, $id, $hour, $rt, $min, $lengthmin, $title, $data, $startyear, $startweek, $startwday, $duration) = @_;
  1826. my ($err);
  1827. if (! defined $id or ! defined $week or ! defined $wday or ! defined $rt or ! defined $duration) {
  1828. return "some data of the event to be removed not given";
  1829. }
  1830. #
  1831. # Copy data into clipboard
  1832. #
  1833. clipboard_set ($::REMOTE_USER,
  1834. { 'hour' => $hour, 'min' => $min, 'lengthmin' => $lengthmin,
  1835. 'title' => $title, 'data' => $data, 'rt' => $rt,
  1836. 'startyear' => $startyear, 'startweek' => $startweek, 'startwday' => $startwday, 'duration' => $duration } );
  1837. #
  1838. # Remove the event from the database
  1839. #
  1840. $err = remove_events ($rt, $startyear, $startweek, $startwday, $duration, $hour, $id);
  1841. if ($err) {
  1842. return $err;
  1843. }
  1844. return '';
  1845. }
  1846. sub delete_event_commit ($$$$$$$$$$$$$$) {
  1847. my ($year, $week, $wday, $id, $hour, $rt, $min, $lengthmin, $title, $data, $startyear, $startweek, $startwday, $duration) = @_;
  1848. my ($err);
  1849. if (! defined $id or ! defined $week or ! defined $wday or ! defined $rt or ! defined $duration) {
  1850. return "some data of the event to be removed not given";
  1851. }
  1852. #
  1853. # Remove the event from the database
  1854. #
  1855. $err = remove_events ($rt, $startyear, $startweek, $startwday, $duration, $hour, $id);
  1856. if ($err) {
  1857. return $err;
  1858. }
  1859. return '';
  1860. }
  1861. sub switch_strike_event_commit {
  1862. my ($year, $week, $wday, $id, $hour, $rt, $min, $lengthmin, $title, $data, $startyear, $startweek, $startwday, $duration, $alval, $altype, $alchk, $strike) = @_;
  1863. my ($err);
  1864. if (! defined $id or ! defined $week or ! defined $wday or ! defined $rt or ! defined $duration) {
  1865. return "some data of the event to be striked not given";
  1866. }
  1867. #
  1868. # Strike/unstrike the event in the database
  1869. #
  1870. $strike = 1 - $strike;
  1871. $err = remove_events ($rt, $startyear, $startweek, $startwday, $duration, $hour, $id);
  1872. if ($err) { return $err; }
  1873. $err = add_events ($rt, $startyear, $startweek, $startwday, $duration, $hour, $id, $min, $lengthmin, $title, $data, $alval, $altype, $alchk, $strike);
  1874. if ($err) { return $err; }
  1875. return '';
  1876. }
  1877. sub copy_event () {
  1878. my ($hour, $min, $lengthmin, $title, $data, $rt, $startyear, $startweek, $startwday, $duration);
  1879. $hour = $::query->{'hour'};
  1880. $min = $::query->{'min'};
  1881. $lengthmin = $::query->{'lengthmin'};
  1882. $title = $::query->{'title'};
  1883. $data = $::query->{'data'};
  1884. $rt = $::query->{'rt'};
  1885. $startyear = $::query->{'startyear'};
  1886. $startweek = $::query->{'startweek'};
  1887. $startwday = $::query->{'startwday'};
  1888. $duration = $::query->{'duration'};
  1889. return if ! check_write_access ();
  1890. clipboard_set ($::REMOTE_USER,
  1891. { 'hour' => $hour, 'min' => $min, 'lengthmin' => $lengthmin,
  1892. 'title' => $title, 'data' => $data, 'rt' => $rt,
  1893. 'startyear' => $startyear, 'startweek' => $startweek, 'startwday' => $startwday, 'duration' => $duration } );
  1894. # Show_even() re-reads the variables from %$::query
  1895. show_event ();
  1896. }
  1897. sub paste_event_commit ($$$) {
  1898. my ($year, $week, $wday) = @_;
  1899. my ($event_ref, $err, $id);
  1900. # Read the event data from clipboard
  1901. $event_ref = clipboard_get ($::REMOTE_USER);
  1902. if (! $event_ref) {
  1903. return "There is no event in clipboard for your computer $::REMOTE_USER.";
  1904. }
  1905. #
  1906. # Find new id
  1907. #
  1908. ($id, $err) = next_id ();
  1909. if ($err) {
  1910. return $err;
  1911. }
  1912. #
  1913. # Update some fields
  1914. #
  1915. $event_ref->{'startyear'} = $year;
  1916. $event_ref->{'startweek'} = $week;
  1917. $event_ref->{'startwday'} = $wday;
  1918. $event_ref->{'id'} = $id;
  1919. #
  1920. # Make some sanity checks
  1921. #
  1922. my ($startmonth, $startday, $startyear, $startweek, $startwday, $duration, $rt);
  1923. ($startmonth, $startday) = get_month_day_by_wday_year_week ($wday, $year, $week);
  1924. $startyear = $year; $startweek = $week; $startwday = $wday;
  1925. $duration = $event_ref->{'duration'};
  1926. $rt = $event_ref->{'rt'};
  1927. if (! &ParseDate ("$startmonth/$startday/$startyear")) {
  1928. return "Date $startday.$startmonth.$startyear is invalid."
  1929. } elsif ($rt eq 'w' and ! fit_in_week ($startyear, $startweek, $startwday, $duration)) {
  1930. return "Weekly repeating event must fit entirely in one week."
  1931. } elsif ($rt eq 'm' and ! fit_in_month ($startyear, $startweek, $startwday, $duration)) {
  1932. return "Monthly repeating event must fit entirely in one month (the month you placed it in, specifically)."
  1933. }
  1934. #
  1935. # Add event for each day
  1936. #
  1937. $err = add_events (
  1938. $event_ref->{'rt'},
  1939. $event_ref->{'startyear'},
  1940. $event_ref->{'startweek'},
  1941. $event_ref->{'startwday'},
  1942. $event_ref->{'duration'},
  1943. $event_ref->{'hour'},
  1944. $event_ref->{'id'},
  1945. $event_ref->{'min'},
  1946. $event_ref->{'lengthmin'},
  1947. $event_ref->{'title'},
  1948. $event_ref->{'data'} );
  1949. if ($err) {
  1950. return $err;
  1951. }
  1952. # When we get here, add has been succesful
  1953. return $event_ref;
  1954. }
  1955. sub xxx_event_error () {
  1956. my ($error1, $error2);
  1957. $error1 = $::query->{'error1'};
  1958. $error2 = $::query->{'error2'};
  1959. print Socket $::H_BODY;
  1960. print Socket "<DIV ALIGN=center VALIGN=middle>\n";
  1961. print Socket "<TABLE BORDER=3 ROWS=1 COLS=1 CELLPADDING=20 ALIGN=center VALIGN=middle WIDTH=\"70%\" BGCOLOR=$::ERROR_COLOR>\n";
  1962. print Socket "<TR><TD ALIGN=center VALIGN=middle>\n";
  1963. print Socket "<H1>$error1</H1>\n";
  1964. print Socket "<P>$error2\n</TD></TR>";
  1965. print Socket "</TABLE>\n";
  1966. print Socket "</BODY>\n";
  1967. return;
  1968. }
  1969. sub show_event_list () {
  1970. my ($year, $week, $alldata_ref, $lastweek);
  1971. my ($cweek, $cyear, $cmonth, $cday, $end_cmonth, $end_cday);
  1972. my ($now_ref, $now_year, $now_week, $now_wday, $week_ref, $wday, $hour);
  1973. $year = $::query->{'year'};
  1974. $week = $::query->{'week'};
  1975. $alldata_ref = build_week_list ($year, $week);
  1976. if (ref $alldata_ref ne 'ARRAY') {
  1977. print Socket "<DIV ALIGN=center VALIGN=middle><H1>Listing events failed: $alldata_ref</H1></DIV>\n";
  1978. return;
  1979. }
  1980. $now_ref = get_now ();
  1981. ($now_year, $now_week, $now_wday) = ($now_ref->{'year'}, $now_ref->{'week'}, $now_ref->{'wday'});
  1982. print Socket $::H_BODY;
  1983. print Socket "<PRE>\n</PRE>\n<P>\n";
  1984. print Socket "<TABLE BORDER=1 WIDTH=\"100%\">\n";
  1985. my $str = sprintf(__("Tâches depuis la semaine %d de l'année %d"), $week, $year);
  1986. print Socket "<TR><TH COLSPAN=3 BGCOLOR=\"$::THCOLOR\"><FONT SIZE=\"+1\">$str\n";
  1987. print Socket "<TR><TH COLSPAN=3>\n";
  1988. my $st = strcal();
  1989. $lastweek = -1;
  1990. for $week_ref (@$alldata_ref) {
  1991. for $wday (0..6) {
  1992. for $hour (sort {$a <=> $b} keys %{$week_ref->[0]->[$wday]}) {
  1993. my ($event_ref);
  1994. $cyear = $week_ref->[1];
  1995. $cweek = $week_ref->[2];
  1996. # Change of week
  1997. if ($cweek != $lastweek) {
  1998. my ($b_month, $b_day, $e_month, $e_day, $color);
  1999. $lastweek = $cweek;
  2000. ($b_month, $b_day) = get_month_day_by_firstday_year_week ($cyear, $cweek);
  2001. ($e_month, $e_day) = get_month_day_by_wday_year_week (6, $cyear, $cweek);
  2002. if ($cyear == $now_year and $cweek == $now_week) {
  2003. $color = $::NOW_TDCOLOR;
  2004. } else {
  2005. $color = $::TDCOLOR;
  2006. }
  2007. print Socket "<TR><TD COLSPAN=3 BGCOLOR=\"$color\"><A TARGET=_top HREF=\"$::MY_URL/?t=redraw&view=week&year=$cyear&week=$cweek$st\"><B>".sprintf(__("Semaine %s"), $cweek).", ", pd_year_month_day ($cyear, $b_month, $b_day), " - ", pd_year_month_day ($cyear, $e_month, $e_day), "</B></A>\n";
  2008. }
  2009. for $event_ref (@{$week_ref->[0]->[$wday]->{$hour}}) {
  2010. my (%e, $hour1, $min1, $hour2, $min2, $lengthmin);
  2011. my ($tmonth, $tday, $twday, $id, $min, $title, $data, $rt, $day, $color, $rcolor);
  2012. my ($startyear, $startweek, $startwday, $duration);
  2013. %e = %$event_ref;
  2014. $hour1 = $hour;
  2015. $id = $e{'id'};
  2016. $min1 = $e{'min'};
  2017. $lengthmin = $e{'lengthmin'};
  2018. $title = $e{'title'};
  2019. $data = $e{'data'};
  2020. $rt = $e{'rt'};
  2021. $startyear = $event_ref->{'startyear'};
  2022. $startweek = $event_ref->{'startweek'};
  2023. $startwday = $event_ref->{'startwday'};
  2024. $duration = $event_ref->{'duration'};
  2025. $hour2 = ($hour1 + int (($min1+$lengthmin) / 60)) % 24;
  2026. $min2 = ($min1 + $lengthmin) % 60;
  2027. ($cmonth, $cday) = get_month_day_by_wday_year_week ($wday, $cyear, $cweek);
  2028. if ($cyear == $now_year and $cweek == $now_week and $wday == $now_wday) {
  2029. $color = " BGCOLOR=\"$::NOW_TDCOLOR\"";
  2030. } else {
  2031. $color = " BGCOLOR=\"$::BG_TDCOLOR\"";
  2032. }
  2033. if ($rt eq 'w') {
  2034. $rcolor = "COLOR=\"$::REPEAT_WEEK_TEXTCOLOR\"";
  2035. } elsif ($rt eq 'm') {
  2036. $rcolor = "COLOR=\"$::REPEAT_MONTH_TEXTCOLOR\"";
  2037. } else {
  2038. $rcolor = '';
  2039. }
  2040. print Socket "<TR><TD$color><A TARGET=_top HREF=\"$::MY_URL/?t=redraw&view=event$st",
  2041. "&id=", $id,
  2042. "&year=", $cyear, "&week=", $cweek, "&wday=", $wday,
  2043. "&hour=", $hour,
  2044. "&min=", $min1,
  2045. "&lengthmin=", $lengthmin,
  2046. "&title=", url_encode ($title),
  2047. "&data=", url_encode ($data),
  2048. "&rt=", $rt,
  2049. "&startyear=", $startyear,
  2050. "&startweek=", $startweek,
  2051. "&startwday=", $startwday,
  2052. "&duration=", $duration,
  2053. "\"><FONT $rcolor SIZE=\"2\">";
  2054. printf Socket "<TT>%s %s - %s</TT></A>\n",
  2055. __($::weekdays_short[$wday]),
  2056. format_time_padded ($hour1, $min1),
  2057. format_time_padded ($hour2, $min2);
  2058. print Socket "</FONT><TD BGCOLOR=\"$::BG_TDCOLOR\"><FONT SIZE=\"2\">", $e{'title'}, "</FONT><TD BGCOLOR=\"$::BG_TDCOLOR\"><FONT SIZE=\"2\">", $data || "&nbsp;", "</FONT>\n";
  2059. }
  2060. }
  2061. }
  2062. }
  2063. print Socket "</TABLE><BR CLEAR=all>\n";
  2064. return;
  2065. }
  2066. sub show_other_views (;$$) {
  2067. my ($year, $week) = @_;
  2068. my ($month, $moffset);
  2069. $year = $year || $::query->{'year'};
  2070. $week = $week || $::query->{'week'};
  2071. print Socket $::H_BODY;
  2072. print Socket "<CENTER>\n<TABLE BORDER=1 CELLPADDING=5 ALIGN=center VALIGN=middle WIDTH=\"95%\" BGCOLOR=\"$::TDCOLOR\">\n";
  2073. print Socket "<TR><TH ALIGN=center BGCOLOR=\"$::THCOLOR\"><B>".__("Autres vues")."</B>";
  2074. print Socket "\n<TR><TD BGCOLOR=\"$::TDCOLOR\" ALIGN=left>\n";
  2075. print Socket "<TABLE><TR>\n";
  2076. print Socket "<TD><UL><FONT SIZE=2>\n";
  2077. my $str = sprintf(__("Agendas %s"), $::ORGANIZATION);
  2078. my $st = strcal();
  2079. print Socket "<LI><A TARGET=_top HREF=\"$::BASE_URL/\">$str</A>\n";
  2080. $str = sprintf(__("Tâches depuis la semaine %d de l'année %d"), $week, $year);
  2081. print Socket "<LI><A HREF=\"$::MY_URL/?t=event_list&year=$year&week=$week$st\">$str</A>";
  2082. print Socket "</FONT></UL></TD>\n";
  2083. print Socket "<TD><UL><FONT SIZE=2>\n";
  2084. $str = sprintf(__("Purger l'agenda jusqu'à la semaine %d de l'année %d"), , $week, $year);
  2085. if (!$st && $::USER !~ /^\wo_/ && -e "/dev/pilot")
  2086. {
  2087. print Socket "<LI><A HREF=\"$::MY_URL/?t=purge&year=$year&week=$week\">$str</A>";
  2088. }
  2089. print Socket "</FONT></UL></TD>\n";
  2090. print Socket "</TR></TABLE>\n";
  2091. print Socket "<CENTER><TABLE BORDER=1 COLS=$::MANY_WEEKS_HOR WIDTH=\"98%\" BGCOLOR=\"$::BG_TDCOLOR\">\n";
  2092. my ($cyear, $cweek, $cmonth, $cday, $now_year, $now_week, $n);
  2093. $n = get_now ();
  2094. $now_year = $n->{'year'}; $now_week = $n->{'week'};
  2095. ($cyear, $cweek) = get_year_week_by_firstday_year_week_minus_days ($year, $week,
  2096. ($::MANY_WEEKS_VERT * $::MANY_WEEKS_HOR + int ($::MANY_WEEKS_HOR / 2)) * 7);
  2097. for $moffset (-$::MANY_WEEKS_VERT .. $::MANY_WEEKS_VERT) {
  2098. my ($m);
  2099. print Socket "<TR>\n";
  2100. for $m (0 .. $::MANY_WEEKS_HOR-1) {
  2101. ($cmonth, $cday) = get_month_day_by_firstday_year_week ($cyear, $cweek);
  2102. if ($cweek == $now_week and $cyear == $now_year) {
  2103. printf Socket "<TD BGCOLOR=\"$::NOW_TDCOLOR\"><FONT SIZE=2><A TARGET=fweek HREF=\"$::MY_URL/?t=week&year=$cyear&week=$cweek$st\">%02d : %s</A></FONT></TD>\n", $cweek, pd_month_day_padded ($cmonth, $cday);
  2104. } else {
  2105. printf Socket "<TD><FONT SIZE=2><A TARGET=fweek HREF=\"$::MY_URL/?t=week&year=$cyear&week=$cweek$st\">%02d : %s</A></FONT></TD>\n", $cweek, pd_month_day_padded ($cmonth, $cday);
  2106. }
  2107. $cweek++;
  2108. if ($cweek > 50) {
  2109. $cweek--;
  2110. ($cyear, $cweek) = get_next_year_week ($cyear, $cweek);
  2111. }
  2112. }
  2113. print Socket "</TR>\n";
  2114. }
  2115. print Socket "</TABLE></CENTER>\n";
  2116. print Socket "</TABLE>\n";
  2117. print Socket "</CENTER>\n</BODY>\n";
  2118. return;
  2119. }
  2120. sub redraw_print_frameset ($$$) {
  2121. my ($tweek, $tday, $tevent) = @_;
  2122. my ($top_y, $left_x);
  2123. if ($::SCREEN_RESOLUTION eq '800x600') {
  2124. $top_y = 200;
  2125. $left_x = 250;
  2126. } else {
  2127. $top_y = 250;
  2128. $left_x = 320
  2129. }
  2130. my $title = sprintf(__("Agenda %s"), $::LONG_NAME);
  2131. my $st = "";
  2132. if ($::query->{'cal'})
  2133. {
  2134. $st .= "&cal=".join("&cal=", split(/\n/, $::query->{'cal'}));
  2135. }
  2136. print Socket <<END;
  2137. <HEAD><TITLE>$title</TITLE></HEAD>
  2138. <frameset framespacing="0" border="false" rows="$top_y,*" frameborder="0">
  2139. frameborder="0" marginheight="0" marginwidth="3" name="fhead" scrolling="no" target="fday" noresize>
  2140. <frame src="$tweek$st" bordercolor="#ffffff"
  2141. frameborder="0" marginheight="3" marginwidth="3" name="fweek" scrolling="auto" target="fday" noresize>
  2142. <frameset cols="$left_x,*">
  2143. <frame src="$tday$st" frameborder="0" marginheight="3"
  2144. marginwidth="3" name="fday" scrolling="auto" target="fevent" noresize>
  2145. <frame src="$tevent$st" frameborder="0" marginheight="3"
  2146. marginwidth="3" name="fevent" scrolling="auto" noresize>
  2147. </frameset>
  2148. <noframes>
  2149. <body>
  2150. </body>
  2151. </noframes>
  2152. </frameset>
  2153. END
  2154. return;
  2155. }
  2156. sub check_write_access () {
  2157. if ($::READ_ONLY eq 'true') {
  2158. print Socket $::H_BODY;
  2159. print Socket "<CENTER><TABLE BORDER=2 COLS=1 CELLPADDING=5 WIDTH=\"80%\" ALIGN=center VALIGN=middle BGCOLOR=\"$::ERROR_COLOR\">\n";
  2160. print Socket "<TR><TD><BGCOLOR=\"$::THCOLOR\">&nbsp;<P><CENTER><FONT COLOR=\"#ffffff\" SIZE=4><B>This user has no write permission.</B></FONT></CENTER><P>&nbsp;</TD></TR>\n";
  2161. print Socket "</TABLE></CENTER>\n";
  2162. print Socket "</BODY>\n";
  2163. return 0;
  2164. }
  2165. return 1;
  2166. }
  2167. sub redraw () {
  2168. my ($view, $id, $year, $week, $wday, $wday_name);
  2169. my ($hour, $min, $lengthmin, $title, $data, $rt);
  2170. my ($tweek, $tday, $tevent);
  2171. my ($startyear, $startweek, $startwday, $duration);
  2172. my ($alval, $altype, $alchk, $strike);
  2173. $view = $::query->{'view'};
  2174. $id = $::query->{'id'};
  2175. $year = $::query->{'year'};
  2176. $week = $::query->{'week'};
  2177. $wday = $::query->{'wday'} || 0;
  2178. $wday_name = $::weekdays[$wday];
  2179. $hour = $::query->{'hour'};
  2180. $min = $::query->{'min'};
  2181. $lengthmin = $::query->{'lengthmin'};
  2182. $title = $::query->{'title'};
  2183. $data = $::query->{'data'};
  2184. $rt = $::query->{'rt'} || 'n';
  2185. $startyear = $::query->{'startyear'};
  2186. $startweek = $::query->{'startweek'};
  2187. $startwday = $::query->{'startwday'};
  2188. $duration = $::query->{'duration'};
  2189. $alval = $::query->{'alval'};
  2190. $altype = $::query->{'altype'};
  2191. $alchk = $::query->{'alchk'} || "";
  2192. $strike = $::query->{'strike'} || 0;
  2193. if (! defined $view or $view eq '' or $view eq 'default') {
  2194. $tweek = "$::MY_URL/?t=week";
  2195. $tday = "$::MY_URL/?t=day";
  2196. $tevent = "$::MY_URL/?t=event";
  2197. redraw_print_frameset ($tweek, $tday, $tevent);
  2198. } elsif ($view eq 'week') {
  2199. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2200. $tday = "$::MY_URL/?t=day";
  2201. $tevent = "$::MY_URL/?t=event";
  2202. redraw_print_frameset ($tweek, $tday, $tevent);
  2203. } elsif ($view eq 'event') {
  2204. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2205. $tday = "$::MY_URL/?t=day&year=$year&week=$week&wday=$wday";
  2206. $tevent = "$::MY_URL/?t=event&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&min=$min&lengthmin=$lengthmin&title=" . url_encode ($title) . "&data=" . url_encode ($data) . "&rt=$rt&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration";
  2207. redraw_print_frameset ($tweek, $tday, $tevent);
  2208. } elsif ($view eq 'after_remove_event') {
  2209. my ($err);
  2210. return if ! check_write_access ();
  2211. $err = remove_event_commit ($year, $week, $wday, $id, $hour, $rt, $min, $lengthmin, $title, $data, $startyear, $startweek, $startwday, $duration);
  2212. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2213. $tday = "$::MY_URL/?t=day&year=$year&week=$week&wday=$wday&rt=$rt";
  2214. if ($err) {
  2215. $tevent = "$::MY_URL/?t=xxx_event_error&error1=" . url_encode ("Error removing event") . "&error2=" . (url_encode $err);
  2216. } else {
  2217. $tevent = "$::MY_URL/?t=event";
  2218. }
  2219. redraw_print_frameset ($tweek, $tday, $tevent);
  2220. } elsif ($view eq 'after_delete_event') {
  2221. my ($err);
  2222. return if ! check_write_access ();
  2223. $err = delete_event_commit ($year, $week, $wday, $id, $hour, $rt, $min, $lengthmin, $title, $data, $startyear, $startweek, $startwday, $duration);
  2224. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2225. $tday = "$::MY_URL/?t=day&year=$year&week=$week&wday=$wday&rt=$rt";
  2226. if ($err) {
  2227. $tevent = "$::MY_URL/?t=xxx_event_error&error1=" . url_encode ("Error removing event") . "&error2=" . (url_encode $err);
  2228. } else {
  2229. $tevent = "$::MY_URL/?t=event";
  2230. }
  2231. redraw_print_frameset ($tweek, $tday, $tevent);
  2232. } elsif ($view eq 'paste_event') {
  2233. my ($err);
  2234. return if ! check_write_access ();
  2235. $err = paste_event_commit ($year, $week, $wday);
  2236. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2237. $tday = "$::MY_URL/?t=day&year=$year&week=$week&wday=$wday&rt=$rt";
  2238. if (ref $err ne 'HASH') {
  2239. $tevent = "$::MY_URL/?t=xxx_event_error&error1=" . url_encode ("Error pasting event from clipboard") . "&error2=" . (url_encode $err);
  2240. } else {
  2241. $tevent = "$::MY_URL/?t=event&id=" . $err->{'id'} . "&year=$year&week=$week&wday=$wday&hour=" . $err->{'hour'} . "&min=" . $err->{'min'} . "&lengthmin=" . $err->{'lengthmin'} . "&title=" . url_encode ($err->{'title'}) . "&data=" . url_encode ($err->{'data'}) . "&rt=" . $err->{'rt'} . "&startyear=" . $err->{'startyear'} . "&startweek=" . $err->{'startweek'} . "&startwday=" . $err->{'startwday'} . "&duration=" . $err->{'duration'};
  2242. }
  2243. redraw_print_frameset ($tweek, $tday, $tevent);
  2244. } elsif ($view eq 'add_event') {
  2245. my ($err);
  2246. return if ! check_write_access ();
  2247. $err = add_event_commit ();
  2248. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2249. $tday = "$::MY_URL/?t=day&year=$year&week=$week&wday=$wday&rt=$rt";
  2250. if (ref $err ne 'HASH') {
  2251. $tevent = "$::MY_URL/?t=xxx_event_error&error1=" . url_encode ("Error adding an event") . "&error2=" . (url_encode $err);
  2252. } else {
  2253. $tevent = "$::MY_URL/?t=event&id=" . $err->{'id'} . "&year=$year&week=$week&wday=$wday&hour=" . $::query->{'hour1'} . "&min=" . $::query->{'min1'} . "&lengthmin=" . $err->{'lengthmin'} . "&title=" . url_encode ($err->{'title'}) . "&data=" . url_encode ($err->{'data'}) . "&rt=$rt&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike";
  2254. }
  2255. redraw_print_frameset ($tweek, $tday, $tevent);
  2256. } elsif ($view eq 'after_strike_event') {
  2257. my ($err);
  2258. return if ! check_write_access ();
  2259. $err = switch_strike_event_commit ($year, $week, $wday, $id, $hour, $rt, $min, $lengthmin, $title, $data, $startyear, $startweek, $startwday, $duration, $alval, $altype, $alchk, $strike);
  2260. $tweek = "$::MY_URL/?t=week&year=$year&week=$week";
  2261. $tday = "$::MY_URL/?t=day&year=$year&week=$week&wday=$wday&rt=$rt";
  2262. if ($err) {
  2263. $tevent = "$::MY_URL/?t=xxx_event_error&error1=" . url_encode ("Error striking event") . "&error2=" . (url_encode $err);
  2264. } else {
  2265. $strike = 1 - $strike;
  2266. $tevent = "$::MY_URL/?t=event&id=$id&year=$year&week=$week&wday=$wday&hour=$hour&min=$min&lengthmin=$lengthmin&title=" . url_encode ($title) . "&data=" . url_encode ($data) . "&rt=$rt&startyear=$startyear&startweek=$startweek&startwday=$startwday&duration=$duration&alval=$alval&altype=$altype&alchk=$alchk&strike=$strike";
  2267. }
  2268. redraw_print_frameset ($tweek, $tday, $tevent);
  2269. } else {
  2270. print Socket "<CENTER><H1>Redraw: Unknown view \"$view\".\n";
  2271. }
  2272. return;
  2273. }
  2274. sub create_users () {
  2275. my (@users, $user);
  2276. if (! chdir ($::DIRECTORY)) {
  2277. return "Can't change into directory $::DIRECTORY: $!<P>Make sure it exists, and its permissions are as explained in file INSTALL of the Wcal distribution.";
  2278. }
  2279. @users = sort (keys (%$::USER_CONFS));
  2280. for $user (@users) {
  2281. my ($desc);
  2282. $desc = $::USER_CONFS->{$user}->{'long name'};
  2283. if (-d $user and -M $user > -M $::CONF_FILE) {
  2284. system "/bin/rm -rf $user";
  2285. }
  2286. if (! -d $user) {
  2287. my ($access_file, $access_file_name);
  2288. if (! mkdir ($user, 0755)) {
  2289. return "Internal error: can't create user '$user': $!";
  2290. }
  2291. if (! link ('index.cgi', $user . '/index.cgi')) {
  2292. return "Internal error: can't create hard link 'index.cgi -> $user/index.cgi': $!";
  2293. }
  2294. $access_file_name = $::USER_CONFS->{$user}->{'access file name'};
  2295. $access_file = $::USER_CONFS->{$user}->{'access file'};
  2296. if ($access_file and $access_file_name) {
  2297. if (! open (AF, ">$user/$access_file_name")) {
  2298. return "Internal error: can't create access file $user/$access_file_name: $!";
  2299. }
  2300. print AF "# This file is automatically generated from $::CONF_FILE - do not edit\n";
  2301. print AF $access_file;
  2302. close AF;
  2303. }
  2304. }
  2305. }
  2306. return '';
  2307. }
  2308. # Removes all cache files.
  2309. sub purge_cache_all () {
  2310. my (@files);
  2311. if (! opendir (DIR, "$::DB_DIR/cache")) {
  2312. return;
  2313. }
  2314. @files = grep { /^w-[^-]+-\d\d\d\d\d\d\.html$/ } readdir (DIR);
  2315. closedir DIR;
  2316. for (@files) {
  2317. unlink "$::DB_DIR/cache/$_" or warn "can't remove $::DB_DIR/cache/$_: $!\n";
  2318. }
  2319. }
  2320. # Removes cached week views and Date::Manip wrapper caches.
  2321. # Supposed to be called at first request after midnight.
  2322. sub purge_cache_newday () {
  2323. my (@files);
  2324. my ($now_ref, $foo, $week1, $week2);
  2325. #
  2326. # Cached dates.
  2327. # Other date caches stay valid accross date change.
  2328. #
  2329. undef $::now_cache;
  2330. #
  2331. # Cached week for this week, or all weeks if the week has changed
  2332. #
  2333. $now_ref = get_now ();
  2334. $week1 = sprintf ("%02d", $now_ref->{'week'});
  2335. ($foo, $week2) = get_prev_year_week ($now_ref->{'year'}, $week1);
  2336. $week2 = sprintf ("%02d", $week2);
  2337. if (! opendir (DIR, "$::DB_DIR/cache")) {
  2338. return;
  2339. }
  2340. if ($week1 == $week2) {
  2341. @files = grep { /^w-[^-]+-\d\d\d\d$week1\.html$/ } readdir (DIR);
  2342. } else {
  2343. @files = grep { /^w-[^-]+-\d\d\d\d\d\d\.html$/ } readdir (DIR);
  2344. }
  2345. closedir DIR;
  2346. for (@files) {
  2347. unlink "$::DB_DIR/cache/$_" or warn "can't remove $::DB_DIR/cache/$_: $!\n";
  2348. }
  2349. return;
  2350. }
  2351. # Create socket and make it listen
  2352. sub init_socket () {
  2353. if (! socket (SSocket, PF_INET, SOCK_STREAM, getprotobyname('tcp')) ) {
  2354. print STDERR "$0: can't create socket: $!";
  2355. exit 1;
  2356. }
  2357. if (! setsockopt(SSocket, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) ) {
  2358. print STDERR "$0: can't set socketopt SO_REUSEADDR: $!";
  2359. exit 1;
  2360. }
  2361. if (! bind(SSocket, sockaddr_in($::PORT, INADDR_ANY)) ) {
  2362. print STDERR "$0: can't bind socket to INADDR_ANY: $!";
  2363. exit 1;
  2364. }
  2365. if (! listen(SSocket, SOMAXCONN) ) {
  2366. print STDERR "$0: can't make socket listen: $!";
  2367. exit 1;
  2368. }
  2369. }
  2370. sub parse_config_line ($) {
  2371. my ($line) = @_;
  2372. my ($key, $value);
  2373. if ($line =~ /^#/ or $line =~ /^\s*$/) {
  2374. return '';
  2375. }
  2376. if ($line =~ /=/) {
  2377. ($key, $value) = split (/=/, $_, 2);
  2378. } else {
  2379. ($key, $value) = ($_, '');
  2380. }
  2381. $key =~ s/^\s*(.*?)\s*$/$1/;
  2382. $key = lc $key;
  2383. $key =~ tr/ \t/ /s;
  2384. if ($key !~ /^[a-z0-9_ ]+$/) {
  2385. return "Config file line $. key '$key' has invalid characters";
  2386. }
  2387. $value =~ s/^\s*(.*?)\s*$/$1/;
  2388. return {'key' => $key, 'value' => $value};
  2389. }
  2390. sub import_settings ($) {
  2391. my ($s_ref) = @_;
  2392. $::PASSWORD = $s_ref->{'password'};
  2393. $::PORT = $s_ref->{'port'};
  2394. $::BASE_URL = $s_ref->{'base url'};
  2395. $::IMG_URL = $::BASE_URL . '/images';
  2396. $::ORGANIZATION = $s_ref->{'organization'};
  2397. $::LONG_NAME = $s_ref->{'long name'};
  2398. $::READ_ONLY = $s_ref->{'read only'};
  2399. $::DATA_ID = $s_ref->{'data id'};
  2400. $::FIRST_DAY = $s_ref->{'first day'};
  2401. $::DATE_FORMAT = $s_ref->{'date format'};
  2402. $::CLOCK = $s_ref->{'clock'};
  2403. $::SCREEN_RESOLUTION = $s_ref->{'screen resolution'};
  2404. $::MY_URL = $::BASE_URL . "/" . (defined $::USER ? $::USER.'/index.cgi' : 'index.cgi');
  2405. $::MY_URL_XUSER = $::BASE_URL . "/" . (defined $::USER ? 'X_USER_X/index.cgi' : 'index.cgi');
  2406. $::REMOTE_LANG = $s_ref->{'remote lang'} || "en";
  2407. $::REMOTE_MAIL = $s_ref->{'remote mail'} || "root";
  2408. $::REMOTE_CAL = $s_ref->{'remote cal'} || "all";
  2409. $::H_BODY = "<BODY BGCOLOR=\"#ffffff\" TEXT=\"#000000\" LINK=\"#0000b0\" VLINK=\"#0000b0\" ALINK=\"#0000b0\" BACKGROUND=\"$::BASE_URL/images/background.jpg\">\n";
  2410. return;
  2411. }
  2412. # Reads global config data from /etc/wcal.conf
  2413. sub read_config () {
  2414. my ($key, $value, $line, $line_ref, %global_conf, %user_confs, $cuser, $conf_ref);
  2415. my (@current_access_file, $reading_access_file);
  2416. my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks);
  2417. my ($valid_line);
  2418. if (! open (CONF, "<$::CONF_FILE")) {
  2419. my $str1 = "can't open $::CONF_FILE for reading: $!";
  2420. return \$str1;
  2421. }
  2422. # Conf file must not be read/writeable by 'other'
  2423. ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat (CONF);
  2424. if ($mode & 6) {
  2425. close CONF;
  2426. my $str2 = "Configuration file $::CONF_FILE must not have read or write permission for 'other' (do 'chmod o= $::CONF_FILE)'.\n";
  2427. return \$str2;
  2428. }
  2429. # Empty the settings from the last run
  2430. %global_conf = (); %user_confs = ();
  2431. $conf_ref = \%global_conf;
  2432. $cuser = '';
  2433. $reading_access_file = 0;
  2434. # Set some defaults
  2435. $global_conf{'host'} = 'localhost';
  2436. $global_conf{'port'} = '13134';
  2437. $global_conf{'base url'} = '/wcal';
  2438. $global_conf{'access file name'} = '.htaccess';
  2439. $global_conf{'access file'} = '';
  2440. $global_conf{'organization'} = 'My Organization';
  2441. $global_conf{'read only'} = 'false';
  2442. $global_conf{'first day'} = 'monday';
  2443. $global_conf{'date format'} = 1;
  2444. $global_conf{'clock'} = '24-hour';
  2445. $global_conf{'screen resolution'} = '1024x768';
  2446. $global_conf{'top left corner'} = '&nbsp;';
  2447. $global_conf{'remote lang'} = 'en';
  2448. $global_conf{'remote mail'} = 'root';
  2449. $global_conf{'remote cal'} = 'all';
  2450. while (<CONF>) {
  2451. chomp;
  2452. $line = $_;
  2453. # If we are reading access file, do special processing
  2454. if ($reading_access_file) {
  2455. $line =~ s/^\s*(.*?)\s*$/$1/;
  2456. if ($line =~ /^end access file$/i) {
  2457. $conf_ref->{'access file'} = join ("\n", @current_access_file) . "\n";
  2458. $reading_access_file = 0;
  2459. } else {
  2460. push @current_access_file, $line;
  2461. }
  2462. next;
  2463. }
  2464. # Else do the normal processing
  2465. $line_ref = parse_config_line ($line);
  2466. next if ! $line_ref; # skip comments and empty lines
  2467. if (! ref $line_ref) { # if return value not empty, and not a reference, it's an error
  2468. close CONF;
  2469. return \$line_ref;
  2470. }
  2471. $key = $line_ref->{'key'};
  2472. $value = $line_ref->{'value'};
  2473. # 'user' field starts user definition
  2474. if ($key eq 'user') {
  2475. if (! defined $global_conf{'password'}) {
  2476. close CONF;
  2477. my $str2 = "Configuration file $::CONF_FILE line $. starts user definition, but the password field hasn't yet occured (password must be given in global section before any user definitions)";
  2478. return \$str2;
  2479. }
  2480. $cuser = $value;
  2481. $conf_ref = {};
  2482. next;
  2483. }
  2484. # 'end user' field ends user definition
  2485. if ($key eq 'end user') {
  2486. my ($gkey);
  2487. # Copy each global conf field into user definition if it isn't given in user definition
  2488. for $gkey (keys %global_conf) {
  2489. if (! defined $conf_ref->{$gkey}) {
  2490. $conf_ref->{$gkey} = $global_conf{$gkey};
  2491. }
  2492. }
  2493. # Long name = user, if not explicitely given
  2494. if (! defined $conf_ref->{'long name'}) {
  2495. $conf_ref->{'long name'} = $cuser;
  2496. }
  2497. # Data id = user, if not explicitely given
  2498. if (! defined $conf_ref->{'data id'}) {
  2499. $conf_ref->{'data id'} = $cuser;
  2500. }
  2501. # Empty 'top left corner' replaced with &nbsp;, to make browsers happier.
  2502. if ($conf_ref->{'top left corner'} eq '') {
  2503. $conf_ref->{'top left corner'} = '&nbsp;';
  2504. }
  2505. $user_confs{$cuser} = $conf_ref;
  2506. $cuser = '';
  2507. $conf_ref = \%global_conf;
  2508. next;
  2509. }
  2510. # 'access file' starts (default / user) access file definition
  2511. if ($key eq 'access file') {
  2512. if ($value) {
  2513. close CONF;
  2514. my $str3 = "Configuration file $::CONF_FILE line $. starts access file definition, but has value field";
  2515. return \$str3;
  2516. }
  2517. @current_access_file = ();
  2518. $reading_access_file = 1;
  2519. next;
  2520. }
  2521. $valid_line = 0;
  2522. # Some fields can only occur in global section
  2523. if ($cuser and ($key eq 'port' or $key eq 'address')) {
  2524. close CONF;
  2525. my $str4 = "Configuration file $::CONF_FILE line $. has in user $cuser definition parameter '$key' that can only occur in global section";
  2526. return \$str4;
  2527. }
  2528. # And some only in user definition
  2529. if (! $cuser and ($key eq 'long name' or $key eq 'read only')) {
  2530. close CONF;
  2531. my $str5 = "Configuration file $::CONF_FILE line $. has in global section parameter '$key' that can only occur in user definition";
  2532. return \$str5;
  2533. }
  2534. # READ ONLY field can have only values true or false
  2535. if ($key eq 'read only') {
  2536. $value = lc $value;
  2537. if ($value ne 'true' and $value ne 'false') {
  2538. close CONF;
  2539. my $str6 = "Configuration file $::CONF_FILE line $. has invalid value for option 'read only'. Allowed values are true and false (default false).";
  2540. return \$str6;
  2541. }
  2542. $valid_line = 1;
  2543. }
  2544. # FIRST DAY can be only monday or sunday
  2545. elsif ($key eq 'first day') {
  2546. if ($value ne 'monday' and $value ne 'sunday') {
  2547. close CONF;
  2548. my $str7 = "Configuration file $::CONF_FILE line $. has invalid value for option 'first day'. Allowed values are monday and sunday (default monday).";
  2549. return \$str7;
  2550. }
  2551. $value = lc $value;
  2552. $valid_line = 1;
  2553. }
  2554. # DATE FORMAT must be between 1 and 5
  2555. elsif ($key eq 'date format') {
  2556. if ($value < 1 or $value > 6) {
  2557. close CONF;
  2558. my $str8 = "Configuration file $::CONF_FILE line $. has invalid value for option 'date format'. Allowed values are 1 to 6 (default 1).";
  2559. return \$str8;
  2560. }
  2561. $valid_line = 1;
  2562. }
  2563. # PORT must be a integer number
  2564. elsif ($key eq 'port') {
  2565. if ($value !~ /^\d+$/ or $value < 1 or $value > 65535) {
  2566. close CONF;
  2567. my $str9 = "Configuration file $::CONF_FILE line $. has invalid value for option 'port'. Allowed values are integer numbers between 1 and 65535 (default 13134).";
  2568. return \$str9;
  2569. }
  2570. $valid_line = 1;
  2571. }
  2572. # CLOCK must be 24-hour or 12-hour
  2573. elsif ($key eq 'clock') {
  2574. $value = lc $value;
  2575. if ($value ne '24-hour' and $value ne '12-hour') {
  2576. close CONF;
  2577. my $str10 = "Configuration file $::CONF_FILE line $. has invalid value for option 'clock'. Allowed values are '24-hour' and '12-hour' (default 24-hour).";
  2578. return \$str10;
  2579. }
  2580. $valid_line = 1;
  2581. }
  2582. # SCREEN RESOLUTION must be 800x600 or 1024x768
  2583. elsif ($key eq 'screen resolution') {
  2584. $value = lc $value;
  2585. if ($value ne '800x600' and $value ne '1024x768') {
  2586. close CONF;
  2587. my $str11 = "Configuration file $::CONF_FILE line $. has invalid value for option 'screen resolution'. Allowed values are '800x600' and '1024x768' (default 1024x768).";
  2588. return \$str11;
  2589. }
  2590. $valid_line = 1;
  2591. }
  2592. # DATABASE DIRECTORY is deprecated
  2593. elsif ($key eq 'database directory') {
  2594. print STDERR "Configuration variable 'database directory' is deprecated and won't be used.";
  2595. print STDERR "If you have database in a place other than $::DB_DIR, move it there now.";
  2596. $valid_line = 1;
  2597. }
  2598. # OTHERS - no particular syntax required, but must be a valid key
  2599. elsif ($key eq 'base url' or $key eq 'password' or
  2600. $key eq 'organization' or $key eq 'access file name' or $key eq 'data id' or
  2601. $key eq 'long name' or $key eq 'address' or $key eq 'top left corner' or
  2602. $key eq 'lang' or $key eq 'remote lang' or $key eq 'remote mail' or $key eq 'remote cal' or $key eq 'install dir') {
  2603. $valid_line = 1;
  2604. }
  2605. if (! $valid_line) {
  2606. close CONF;
  2607. my $str12 = "Configuration file $::CONF_FILE line $. has unknown option '$key'.";
  2608. return \$str12;
  2609. }
  2610. $conf_ref->{$key} = $value;
  2611. }
  2612. close CONF;
  2613. if ($reading_access_file or $cuser) {
  2614. my $str13 = "End of configuration file $::CONF_FILE while reading access file or user definition";
  2615. return \$str13;
  2616. }
  2617. $::GLOBAL_CONF = \%global_conf;
  2618. $::USER_CONFS = \%user_confs;
  2619. import_settings ($::GLOBAL_CONF);
  2620. purge_cache_all ();
  2621. return 1;
  2622. }
  2623. # Read CGI environment and conf option from Socket (sent by the cgi-proxy)
  2624. sub read_environment () {
  2625. my ($key, $value, $user);
  2626. while (<Socket>) {
  2627. chomp;
  2628. last if /^$/;
  2629. my ($key, $value);
  2630. ($key, $value) = split (/=/, $_, 2);
  2631. $key =~ tr/\x00-\x1f\x80-\x9f//d; # filter out control characters,
  2632. $value =~ tr/\x00-\x1f\x80-\x9f//d; # including infamous NUL
  2633. if ($key eq 'QUERY_STRING') {
  2634. $::query = decode_url_encoded_data \$value;
  2635. } elsif ($key eq 'REMOTE_USER') {
  2636. $::REMOTE_USER = $value;
  2637. $ENV{REMOTE_USER} = $::REMOTE_USER;
  2638. } elsif ($key eq 'REMOTE_PASS') {
  2639. $::REMOTE_PASS = $value;
  2640. $ENV{REMOTE_PASS} = $::REMOTE_PASS;
  2641. } elsif ($key eq 'REMOTE_MAIL') {
  2642. $::REMOTE_MAIL = $value;
  2643. } elsif ($key eq 'REMOTE_CAL') {
  2644. $::REMOTE_CAL = $value;
  2645. } elsif ($key eq 'REMOTE_LANG') {
  2646. $::REMOTE_LANG = $value;
  2647. } elsif ($key =~ /^__/) {
  2648. $key = lc $key;
  2649. if ($key eq '__password') {
  2650. # print Socket "<P>got: '$value', correct is '$::PASSWORD'\n";
  2651. if ($value ne $::PASSWORD) {
  2652. print Socket "<P>Invalid password\n";
  2653. return 0;
  2654. }
  2655. } elsif ($key eq '__user') {
  2656. $::USER = $value;
  2657. } elsif ($key eq '__gid') {
  2658. $::GID = $value;
  2659. } else {
  2660. print Socket "<P>Unknown configuration option '$key'\n";
  2661. return 0;
  2662. }
  2663. }
  2664. }
  2665. # print Socket "<P>$::MY_URL\n";
  2666. # Make sure we received all the mandatory options
  2667. if (! $::USER) {
  2668. print Socket "<P>User not sent by cgi-proxy\n";
  2669. return 0;
  2670. }
  2671. return 1;
  2672. }
  2673. sub siginthandler {
  2674. exit (1);
  2675. }
  2676. sub sighuphandler {
  2677. my ($res);
  2678. return; # do nothing, this is just a kludge that doesn't work
  2679. $::GID = 60;
  2680. $res = read_config ();
  2681. if (ref $res) {
  2682. print STDERR "<P>Re-reading configureation failed: ", $$res, " - configuration not changed.\n";
  2683. } else {
  2684. $res = create_users ();
  2685. if ($res) {
  2686. print STDERR "<P>Error creating new users: $res\n";
  2687. }
  2688. }
  2689. return;
  2690. }
  2691. sub check_and_set_first_day () {
  2692. my ($gen);
  2693. $gen = read_general ();
  2694. if (! ref $gen) {
  2695. print "error: $gen\n";
  2696. exit (1);
  2697. }
  2698. if (defined $gen->{'first day'} and $gen->{'first day'} ne $::FIRST_DAY) {
  2699. print <<EOD;
  2700. Current database ($::DB_DIR/*.db) is created using different 'first day'
  2701. value than defined in current configuration file $::CONF_FILE.
  2702. If you want to change 'first day' setting, you must first destroy the
  2703. current database (by doing 'rm $::DB_DIR/*.db').
  2704. EOD
  2705. exit (1);
  2706. }
  2707. if (! defined $gen->{'first day'}) {
  2708. my ($err);
  2709. $gen->{'first day'} = $::FIRST_DAY;
  2710. $err = write_general ($gen);
  2711. if ($err) {
  2712. print "error: $err\n";
  2713. exit (1);
  2714. }
  2715. }
  2716. return;
  2717. }
  2718. sub show_links () {
  2719. print Socket $::H_BODY;
  2720. my @cals = split(/\n/, $::query->{'cal'});
  2721. my $st = "";
  2722. if ($::query->{'year'} && $::query->{'week'})
  2723. {
  2724. $st = '&year='.$::query->{'year'}.'&week='.$::query->{'week'};
  2725. }
  2726. print Socket '<h1><a href="'.$::BASE_URL.'/fusion.cgi/?t=week&cal='.join("&cal=", @cals).$st;
  2727. print Socket '" target="fweek">'.$::LONG_NAME."</a></h1>\n";
  2728. print Socket "<table width=100% border=0 cellspacing=0 cellpadding=5>\n";
  2729. my $cal;
  2730. my $i = 1;
  2731. foreach $cal (@cals)
  2732. {
  2733. print Socket '<tr bgcolor="'.$::EVENT_COLS[$i++].'"><td><font size=4><b><a href="'.$::BASE_URL.'/'.$cal.'/index.cgi/?t=week'.$st.'"target="fweek">'.%{$::USER_CONFS->{$cal}}->{'long name'}."</b></font></a>\n";
  2734. }
  2735. print Socket "</table>";
  2736. }
  2737. sub clear_events {
  2738. my $week = shift;
  2739. my $year = shift;
  2740. if ($week)
  2741. {
  2742. my $file;
  2743. opendir(DIR, $::DB_DIR);
  2744. while ($file = readdir(DIR))
  2745. {
  2746. if ($file =~ /^w\-$::USER\-(\d\d\d\d)(\d\d)\.db$/)
  2747. {
  2748. if (($1 < $year) || (($1 == $year) && ($2 <= $week)))
  2749. {
  2750. unlink($::DB_DIR."/".$file);
  2751. }
  2752. }
  2753. }
  2754. closedir(DIR);
  2755. opendir(DIR, $::DB_DIR."/cache");
  2756. while ($file = readdir(DIR))
  2757. {
  2758. if ($file =~ /^w\-$::USER\-(\d\d\d\d)(\d\d)\.html$/)
  2759. {
  2760. if (($1 < $year) || (($1 == $year) && ($2 <= $week)))
  2761. {
  2762. unlink($::DB_DIR."/cache/".$file);
  2763. }
  2764. }
  2765. }
  2766. closedir(DIR);
  2767. }
  2768. else
  2769. {
  2770. system('\rm '.$::DB_DIR.'/*'.$::USER.'*');
  2771. system('\rm '.$::DB_DIR.'/cache/*'.$::USER.'*');
  2772. }
  2773. }
  2774. sub all_events () {
  2775. opendir(DIR, $::DB_DIR);
  2776. my @events;
  2777. my $event;
  2778. my $evw;
  2779. my $i;
  2780. my $key;
  2781. my $val;
  2782. my $file;
  2783. while ($file = readdir(DIR))
  2784. {
  2785. if ($file =~ /^w\-$::USER\-(\d\d\d\d)(\d\d)\.db$/)
  2786. {
  2787. $evw = read_events('n', $1, $2);
  2788. for ($i=0; $i<7; $i++)
  2789. {
  2790. while (($key, $val) = each(%{@{$evw}[$i]}))
  2791. {
  2792. foreach $event (@{$val})
  2793. {
  2794. $event->{hour} = $key;
  2795. push @events, $event;
  2796. }
  2797. }
  2798. }
  2799. }
  2800. }
  2801. return \@events;
  2802. }
  2803. sub show_purge () {
  2804. my $str;
  2805. my $week = $::query->{'week'};
  2806. my $year = $::query->{'year'};
  2807. print Socket $::H_BODY;
  2808. print Socket "<TABLE BORDER=1 WIDTH=\"100%\" BGCOLOR=\"$::TDCOLOR\">\n";
  2809. print Socket "<TR><TH ALIGN=center BGCOLOR=\"$::THCOLOR\"><B>";
  2810. print Socket __("Transfert Palm Pilot");
  2811. print Socket "</B></TH></TR>\n";
  2812. print Socket "<TR><TD BGCOLOR=\"$::TDCOLOR\">\n";
  2813. if ($::query->{'purge'})
  2814. {
  2815. clear_events($week, $year);
  2816. $str = sprintf(__("Agenda %s purgé jusqu'à la semaine %d de l'année %d"), '<A HREF="'.$::MY_URL.'" TARGET="_top">'.$::LONG_NAME.'</A>', $week, $year);
  2817. print Socket "<H1>$str</H1>\n";
  2818. }
  2819. elsif ($::query->{'cancel'})
  2820. {
  2821. $str = sprintf(__("Purge de l'agenda %s annulée"), '<A HREF="'.$::MY_URL.'" TARGET="_top">'.$::LONG_NAME.'</A>');
  2822. print Socket "<H1>$str</H1>\n";
  2823. }
  2824. else
  2825. {
  2826. print Socket "<TABLE><TR align=center>\n";
  2827. print Socket "<TD colspan=2><h1>".sprintf(__("Voulez-vous réellement purger l'agenda %s jusqu'à la semaine %d de l'année %d ?"), $::LONG_NAME, $::query->{'week'}, $::query->{'year'})."\n";
  2828. print Socket "<TR align=center>\n";
  2829. print Socket "<FORM ACTION=\"$::MY_URL\" METHOD=GET>\n";
  2830. print Socket "<INPUT TYPE=HIDDEN NAME=t VALUE=purge>\n";
  2831. print Socket "<INPUT TYPE=HIDDEN NAME=week VALUE=$::query->{'week'}>\n";
  2832. print Socket "<INPUT TYPE=HIDDEN NAME=year VALUE=$::query->{'year'}>\n";
  2833. my $submit_value = __("Oui");
  2834. print Socket "<TD><INPUT TYPE=submit NAME=purge VALUE=\"$submit_value\">\n";
  2835. $submit_value = __("Non");
  2836. print Socket "<TD><INPUT TYPE=submit NAME=cancel VALUE=\"$submit_value\">\n";
  2837. print Socket "</FORM></TABLE>\n";
  2838. }
  2839. print Socket "</TABLE>\n";
  2840. }
  2841. sub checkAlarm
  2842. {
  2843. my $event = shift;
  2844. my $cal = shift;
  2845. my $hour = shift;
  2846. my $day = shift;
  2847. my $et = shift;
  2848. my $week = shift;
  2849. my $year = shift;
  2850. my @types = ("", "minutes", "hours" , "days");
  2851. # compute start date
  2852. my $now=&ParseDate("today");
  2853. my $begin;
  2854. my $end;
  2855. my $alarm;
  2856. my $strdate;
  2857. my @format;
  2858. my @tab;
  2859. my $chk = 1;
  2860. my $min = $event->{min};
  2861. my $notime;
  2862. if ($hour == -1)
  2863. {
  2864. $hour = 0;
  2865. $min = 0;
  2866. $notime = 1;
  2867. }
  2868. if ($et eq "w")
  2869. {
  2870. $begin = &DateCalc(&ParseDate(sprintf("%04d-w%02d-%d", $event->{startyear}, $event->{startweek}, $event->{startwday}+1)), sprintf("+%dhours +%dminutes", $hour, $min));
  2871. $alarm = &DateCalc($begin, sprintf("-%d%s", $event->{alval}, $types[$event->{altype}]));
  2872. if ($alarm gt $now)
  2873. {
  2874. return 0;
  2875. }
  2876. }
  2877. elsif ($et eq "rw")
  2878. {
  2879. $alarm = &DateCalc($now, sprintf("+%d%s", $event->{alval}, $types[$event->{altype}]));
  2880. @format = ("%w");
  2881. my $wday = &UnixDate($alarm, @format);
  2882. $wday = 1 + $event->{startwday} - $wday;
  2883. if ($wday > 0)
  2884. {
  2885. return 0;
  2886. }
  2887. elsif ($wday < 0)
  2888. {
  2889. $begin = &DateCalc($alarm, $wday."days");
  2890. }
  2891. else
  2892. {
  2893. $begin = $alarm;
  2894. }
  2895. $begin = substr($begin,0,8).sprintf("%02d:%02d:00", $hour, $min);
  2896. if ($begin gt $alarm || ($event->{alchk} && $begin le $event->{alchk}))
  2897. {
  2898. return 0;
  2899. }
  2900. $chk = $begin;
  2901. }
  2902. elsif ($et eq "rm")
  2903. {
  2904. $alarm = &DateCalc($now, sprintf("+%d%s", $event->{alval}, $types[$event->{altype}]));
  2905. @format = ("%d");
  2906. my $mday = &UnixDate($alarm, @format);
  2907. $mday = $day - $mday;
  2908. if ($mday > 0)
  2909. {
  2910. return 0;
  2911. }
  2912. elsif ($mday < 0)
  2913. {
  2914. $begin = &DateCalc($alarm, $mday."days");
  2915. }
  2916. else
  2917. {
  2918. $begin = $alarm;
  2919. }
  2920. $begin = substr($begin,0,8).sprintf("%02d:%02d:00", $hour, $min);
  2921. if ($begin gt $alarm || ($event->{alchk} && $begin le $event->{alchk}))
  2922. {
  2923. return 0;
  2924. }
  2925. $chk = $begin;
  2926. }
  2927. my $email = "root";
  2928. my $head;
  2929. my $body;
  2930. $email = $::REMOTE_MAIL;
  2931. $head = sprintf(__("Agenda %s"), %{$::USER_CONFS->{$cal}}->{'long name'});
  2932. if ($notime)
  2933. {
  2934. @format = ("%d","%m","%y");
  2935. @tab = &UnixDate($begin, @format);
  2936. $strdate = sprintf("%02d/%02d/%02d", @tab);
  2937. }
  2938. else
  2939. {
  2940. @format = ("%d","%m","%y","%H","%M");
  2941. @tab = &UnixDate($begin, @format);
  2942. $strdate = sprintf("%02d/%02d/%02d %02d:%02d", @tab);
  2943. $end = &DateCalc($begin, sprintf("+%dminutes", $event->{lengthmin}));
  2944. @format = ("%H","%M");
  2945. @tab = &UnixDate($end, @format);
  2946. $strdate .= sprintf(" - %02d:%02d", @tab);
  2947. }
  2948. my $data = $event->{data};
  2949. $data =~ s/<BR>/\n\t /mg;
  2950. $body = $head."\n";
  2951. $head .= " : ".$event->{title}."\n";
  2952. $body .= "************************************************************\n";
  2953. $body .= __("Date")."\t: ".$strdate."\n";
  2954. $body .= __("Titre")."\t: ".$event->{title}."\n";
  2955. if ($data)
  2956. {
  2957. $body .= __("Note")."\t: ".$data."\n";
  2958. }
  2959. $body .= "************************************************************\n";
  2960. system('mail -s "'.$head.'" '.$email." <<EOF\n".$body."\nEOF");
  2961. return $chk;
  2962. }
  2963. sub check_alarm () {
  2964. opendir(DIR, $::DB_DIR);
  2965. my $file;
  2966. my $et;
  2967. my $cal;
  2968. my $week;
  2969. my $year;
  2970. my $refs;
  2971. my $hour;
  2972. my $day;
  2973. my $devents;
  2974. my $events;
  2975. my $event;
  2976. my $old_slash;
  2977. my $err;
  2978. my $chk;
  2979. while ($file = readdir(DIR))
  2980. {
  2981. if ($file =~ /^(\w+)-(.+)\.db$/)
  2982. {
  2983. $et = $1;
  2984. $cal = $2;
  2985. if ($cal =~ /^(.+)-(\d\d\d\d)(\d\d)$/)
  2986. {
  2987. $cal = $1;
  2988. $year = $2;
  2989. $week = $3;
  2990. }
  2991. else
  2992. {
  2993. $year = "";
  2994. $week = "";
  2995. }
  2996. if ($::REMOTE_CAL ne "all" && $::REMOTE_CAL ne $cal)
  2997. {
  2998. next;
  2999. }
  3000. if (open F, "$::DB_DIR/$file")
  3001. {
  3002. $old_slash = $/;
  3003. undef $/;
  3004. $refs = eval (<F>);
  3005. $/ = $old_slash;
  3006. close F;
  3007. shift @$refs;
  3008. $day = 0;
  3009. foreach $devents (@$refs)
  3010. {
  3011. while (($hour,$events) = each (%$devents))
  3012. {
  3013. foreach $event (@$events)
  3014. {
  3015. if ($event->{alval} && !$event->{strike} && (!$event->{alchk} || $event->{alchk} ne "1"))
  3016. {
  3017. if ($chk = checkAlarm($event, $cal, $hour, $day, $et, $week, $year))
  3018. {
  3019. $::USER = $cal;
  3020. $::DATA_ID = $cal;
  3021. print Socket "$event->{'title'} ($event->{'id'}) checked\n";
  3022. $err = remove_events(
  3023. $event->{'rt'},
  3024. $event->{'startyear'},
  3025. $event->{'startweek'},
  3026. $event->{'startwday'},
  3027. $event->{'duration'},
  3028. $hour,
  3029. $event->{'id'});
  3030. if (!$err)
  3031. {
  3032. $err = add_events(
  3033. $event->{'rt'},
  3034. $event->{'startyear'},
  3035. $event->{'startweek'},
  3036. $event->{'startwday'},
  3037. $event->{'duration'},
  3038. $hour,
  3039. $event->{'id'},
  3040. $event->{'min'},
  3041. $event->{'lengthmin'},
  3042. $event->{'title'},
  3043. $event->{'data'},
  3044. $event->{'alval'},
  3045. $event->{'altype'},
  3046. $chk);
  3047. }
  3048. }
  3049. }
  3050. }
  3051. }
  3052. $day++;
  3053. }
  3054. }
  3055. }
  3056. }
  3057. closedir(DIR);
  3058. }
  3059. sub list_users () {
  3060. my (@users, $user);
  3061. my $str = sprintf(__("Agendas %s"), $::ORGANIZATION);
  3062. print Socket "<HEAD><TITLE>$str</TITLE></HEAD>\n";
  3063. print Socket $::H_BODY;
  3064. if (! chdir ($::DIRECTORY)) {
  3065. print Socket "<P>Can't change into directory $::DIRECTORY: $!";
  3066. print Socket "<P>Make sure it exists, and its permissions are as explained in file INSTALL of the Wcal distribution.";
  3067. exit (1);
  3068. }
  3069. print Socket "<CENTER><H1>$str</H1></CENTER>";
  3070. print Socket sprintf(__("Cliquez sur un calendrier ou sélectionnez les calendriers pour la %s"), '<a href="fusion-'.$::REMOTE_LANG.'.html">'.__("Fusion")."</a>");
  3071. print Socket '<form action="'.$::BASE_URL.'/fusion.cgi">'."\n";
  3072. print Socket "<P><UL>\n";
  3073. @users = sort (keys (%$::USER_CONFS));
  3074. for $user (@users) {
  3075. my ($desc);
  3076. $desc = $::USER_CONFS->{$user}->{'long name'};
  3077. print Socket '<input type="checkbox" name="cal" value="'.$user.'"> ';
  3078. print Socket "<A TARGET=_top HREF=\"$::BASE_URL/$user/?t=redraw&view=default\">$desc</A><br>\n";
  3079. }
  3080. print Socket "</UL>\n";
  3081. print Socket '<input type="submit" name="fusion" value="'.__("Fusion").'"></form action>'."\n";
  3082. print Socket "</BODY>\n";
  3083. return;
  3084. }
  3085. sub main () {
  3086. my ($config_result, $last_run, $last_conf, $res);
  3087. $SIG{HUP} = $SIG{PIPE} = 'IGNORE';
  3088. $SIG{ALRM} = \&purge_cache_all;
  3089. $ENV{'PATH'} = '/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin'; # To pass taint checks
  3090. #
  3091. # Make sure the $::DIRECTORY variable is set
  3092. #
  3093. if ($::DIRECTORY =~ /^_X_DIRECTOR/) {
  3094. print "You haven't set the variable $::DIRECTORY at top of wcald.\n";
  3095. print "It is automatically set by Makefile. If you're installing manually,\n";
  3096. print "set the variable the name directory you installed wcald to.\n";
  3097. exit 1;
  3098. }
  3099. #
  3100. # Refuse to run as root
  3101. #
  3102. if ($> == 0) {
  3103. die "Won't run as root.\n";
  3104. }
  3105. #
  3106. # Check some file permissions
  3107. #
  3108. if (! -d $::DB_DIR or ! -w $::DB_DIR or (sprintf "%04o", ((stat ($::DB_DIR))[2]) & 07777) ne '0700') {
  3109. die "$::DB_DIR must exist, be writable and have mode 0700.\n";
  3110. }
  3111. if (! -d "$::DB_DIR/cache") {
  3112. mkdir ("$::DB_DIR/cache", 0700) or die "mkdir (\"$::DB_DIR/cache\", 0700): $!\n";
  3113. }
  3114. if (! -d $::DIRECTORY or ! -w $::DIRECTORY or (sprintf "%04o", ((stat ($::DIRECTORY))[2]) & 07777) ne '0750') {
  3115. die "$::DIRECTORY must exist, be writable and have mode 0750.\n";
  3116. }
  3117. #
  3118. # Read in wcal.msg
  3119. #
  3120. open(MSG, $::MSG_FILE) or die "Can't open $::MSG_FILE for reading: $!";
  3121. my $old_slash = $/;
  3122. undef $/;
  3123. $::msgs = eval (<MSG>);
  3124. $/ = $old_slash;
  3125. close(MSG);
  3126. #
  3127. # Read configuration and create users
  3128. #
  3129. $config_result = read_config ();
  3130. if (ref $config_result) {
  3131. die "$0: error: ", $$config_result, "\n";
  3132. }
  3133. $res = create_users ();
  3134. if ($res) {
  3135. die "$0: error creating users: $res\n";
  3136. }
  3137. #
  3138. # Make sure current database (if one exists) uses same 'first day'
  3139. # parameter as we're currently using.
  3140. #
  3141. check_and_set_first_day ();
  3142. #
  3143. # Set the date constants
  3144. #
  3145. if ($::FIRST_DAY eq 'monday') {
  3146. @::weekdays = qw (Lundi Mardi Mercredi Jeudi Vendredi Samedi Dimanche);
  3147. @::weekdays_short = qw (lun mar mer jeu ven sam dim);
  3148. @::weekdays2 = qw (Monday Tuesday Wednesday Thursday Friday Saturday Sunday);
  3149. &Date_Init ('FirstDay=1');
  3150. } else {
  3151. @::weekdays = qw (Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi);
  3152. @::weekdays_short = qw (dim lun mar mer jeu ven sam);
  3153. @::weekdays2 = qw (Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
  3154. &Date_Init ('FirstDay=7');
  3155. }
  3156. @::months = qw (Erreur Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre);
  3157. init_socket ();
  3158. $last_run = (localtime(time))[7];
  3159. $last_conf = 0;
  3160. while (1) {
  3161. my ($query_type, $pid, $paddr, $cgi, %user, $now_run, $now_conf);
  3162. $SIG{'INT'} = $SIG{'TERM'} = \&siginthandler;
  3163. $SIG{'HUP'} = \&sighuphandler;
  3164. $paddr = accept (Socket, SSocket);
  3165. $SIG{'INT'} = $SIG{'TERM'} = $SIG{'HUP'} = 'IGNORE';
  3166. #
  3167. # Purge cache when day changes
  3168. #
  3169. $now_run = (localtime(time))[7];
  3170. if ($now_run != $last_run) {
  3171. $last_run = $now_run;
  3172. purge_cache_newday ();
  3173. }
  3174. #
  3175. # Start outputing HTML
  3176. #
  3177. print Socket $::HTTP_HEADER;
  3178. print Socket "<HTML>\n";
  3179. #
  3180. # Read CGI environment and the config options that cgi-proxy passes to us
  3181. # Includes QUERY_STRING (decoded into $::query),
  3182. # __password (checked) and __user (stored in $::USER)
  3183. #
  3184. if (! read_environment ()) {
  3185. next;
  3186. }
  3187. #
  3188. # Re-read config if it has changed
  3189. #
  3190. $now_conf = (stat($::CONF_FILE))[9];
  3191. if ($now_conf != $last_conf) {
  3192. $last_conf = $now_conf;
  3193. $config_result = read_config ();
  3194. if (ref $config_result) {
  3195. while (<Socket>) { chomp; last if /^$/; }; # Read environment to make cgi-proxy happy
  3196. print Socket $::H_BODY;
  3197. print Socket "<P><H2>Configuration has changed.</H2>";
  3198. print Socket "<P>Re-reading configureation failed: ", $$config_result, " - configuration not changed.\n";
  3199. print Socket "<P><A TARGET=\"_top\" HREF=\"$::BASE_URL/\">Click me</A> to go to the main view\n";
  3200. print Socket "</BODY>\n";
  3201. next;
  3202. } else {
  3203. $res = create_users ();
  3204. if ($res) {
  3205. print Socket $::H_BODY;
  3206. print Socket "<P><H2>Configuration has changed.</H2>";
  3207. print Socket "<P>Error creating new users: $res\n";
  3208. print Socket "<P><A TARGET=\"_top\" HREF=\"$::BASE_URL/\">Click me</A> to go to the main view\n";
  3209. print Socket "</BODY>\n";
  3210. next;
  3211. }
  3212. # fall through: just serve the request
  3213. }
  3214. }
  3215. # show a list of users
  3216. if (!$::query->{'cal'} && $::USER eq $::PATH_BASENAME) {
  3217. list_users ();
  3218. next;
  3219. }
  3220. #
  3221. # Dispatch the operation
  3222. #
  3223. # Make sure the users exists
  3224. if ($::USER_CONFS->{$::USER}) {
  3225. import_settings ($::USER_CONFS->{$::USER});
  3226. $::DATA_IDS = 0;
  3227. }
  3228. else # fusion
  3229. {
  3230. $::READ_ONLY = 'true';
  3231. $::DATA_ID = 0;
  3232. $::DATA_IDS = $::query->{'cal'};
  3233. $::LONG_NAME = __('Fusion');
  3234. $::MY_URL = $::BASE_URL.'/fusion.cgi';
  3235. $::MY_URL_XUSER = $::BASE_URL.'/fusion.cgi';
  3236. }
  3237. $::query->{'u'} = $::USER;
  3238. $query_type = $::query->{'t'} || '';
  3239. if ($query_type eq 'redraw' or $query_type eq '') {
  3240. redraw ();
  3241. } elsif ($query_type eq 'week') {
  3242. show_week ();
  3243. } elsif ($query_type eq 'day') {
  3244. show_day ();
  3245. } elsif ($query_type eq 'event') {
  3246. show_event ();
  3247. } elsif ($query_type eq 'copy_event') {
  3248. copy_event ();
  3249. } elsif ($query_type eq 'add_edit') {
  3250. add_edit_event_ask () if check_write_access ();
  3251. } elsif ($query_type eq 'add_edit_confirm') {
  3252. add_edit_event_confirm () if check_write_access ();
  3253. } elsif ($query_type eq 'remove') {
  3254. remove_event_confirm () if check_write_access ();
  3255. } elsif ($query_type eq 'xxx_event_error') {
  3256. xxx_event_error ();
  3257. } elsif ($query_type eq 'event_list') {
  3258. show_event_list ();
  3259. } elsif ($query_type eq 'views') {
  3260. show_other_views ();
  3261. } elsif ($query_type eq 'links') {
  3262. show_links ();
  3263. } elsif ($query_type eq 'purge') {
  3264. show_purge ();
  3265. } elsif ($query_type eq 'checkalarm') {
  3266. check_alarm ();
  3267. } else {
  3268. print Socket "<H2><P>Unknown command '$query_type'.</H2>\n";
  3269. }
  3270. undef $::query;
  3271. } continue {
  3272. print Socket "</HTML>\n";
  3273. close Socket;
  3274. }
  3275. # not reached
  3276. }
  3277. main();