3 * All of WebCalendar's functions
5 * @author Craig Knudsen <cknudsen@cknudsen.com>
6 * @copyright Craig Knudsen, <cknudsen@cknudsen.com>, http://www.k5n.us/cknudsen
7 * @license http://www.gnu.org/licenses/gpl.html GNU GPL
11 if ( empty ( $PHP_SELF ) && ! empty ( $_SERVER ) &&
12 ! empty ( $_SERVER['PHP_SELF'] ) ) {
13 $PHP_SELF = $_SERVER['PHP_SELF'];
15 if ( ! empty ( $PHP_SELF ) && preg_match ( "/\/includes\//", $PHP_SELF ) ) {
16 die ( "You can't access this file directly!" );
20 * Used for activity log
28 $LOG_NOTIFICATION = "N";
33 * Number of seconds in a day
35 * @global int $ONE_DAY
40 * Array containing the number of days in each month in a non-leap year
42 * @global array $days_per_month
44 $days_per_month = array ( 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
47 * Array containing the number of days in each month in a leap year
49 * @global array $ldays_per_month
51 $ldays_per_month = array ( 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
54 * Array of global variables which are not allowed to by set via HTTP GET/POST
56 * This is a security precaution to prevent users from overriding any global
59 * @global array $noSet
72 "single_user_login" => 1,
76 "NONUSER_PREFIX" => 1,
78 "browser_languages" => 1,
79 "pub_acc_enabled" => 1,
80 "user_can_update_password" => 1,
81 "admin_can_add_user" => 1,
82 "admin_can_delete_user" => 1,
85 // This code is a temporary hack to make the application work when
86 // register_globals is set to Off in php.ini (the default setting in
87 // PHP 4.2.0 and after).
88 if ( empty ( $HTTP_GET_VARS ) ) $HTTP_GET_VARS = $_GET;
89 if ( ! empty ( $HTTP_GET_VARS ) ) {
90 while (list($key, $val) = @each($HTTP_GET_VARS)) {
91 // don't allow anything to have <script> in it...
92 if ( ! is_array ( $val ) ) {
93 if ( preg_match ( "/<\s*script/i", $val ) ) {
94 echo "Security violation!"; exit;
97 if ( $key == "login" ) {
98 if ( strstr ( $PHP_SELF, "login.php" ) ) {
99 //$GLOBALS[$key] = $val;
100 $GLOBALS[$key] = $val;
103 if ( empty ( $noSet[$key] ) ) {
104 $GLOBALS[$key] = $val;
105 //echo "XXX $key<br />\n";
108 //echo "GET var '$key' = '$val' <br />\n";
110 reset ( $HTTP_GET_VARS );
113 if ( empty ( $HTTP_POST_VARS ) ) $HTTP_POST_VARS = $_POST;
114 if ( ! empty ( $HTTP_POST_VARS ) ) {
115 while (list($key, $val) = @each($HTTP_POST_VARS)) {
116 // don't allow anything to have <script> in it... except 'template'
117 if ( ! is_array ( $val ) && $key != 'template' ) {
118 if ( preg_match ( "/<\s*script/i", $val ) ) {
119 echo "Security violation!"; exit;
122 if ( empty ( $noSet[$key] ) ) {
123 $GLOBALS[$key] = $val;
126 reset ( $HTTP_POST_VARS );
128 //while (list($key, $val) = @each($HTTP_POST_FILES)) {
129 // $GLOBALS[$key] = $val;
131 //while (list($key, $val) = @each($HTTP_SESSION_VARS)) {
132 // $GLOBALS[$key] = $val;
134 if ( empty ( $HTTP_COOKIE_VARS ) ) $HTTP_COOKIE_VARS = $_COOKIE;
135 if ( ! empty ( $HTTP_COOKIE_VARS ) ) {
136 while (list($key, $val) = @each($HTTP_COOKIE_VARS)) {
137 if ( empty ( $noSet[$key] ) && substr($key,0,12) == "webcalendar_" ) {
138 $GLOBALS[$key] = $val;
140 //echo "COOKIE var '$key' = '$val' <br />\n";
142 reset ( $HTTP_COOKIE_VARS );
145 // Don't allow a user to put "login=XXX" in the URL if they are not
146 // coming from the login.php page.
147 if ( empty ( $PHP_SELF ) && ! empty ( $_SERVER['PHP_SELF'] ) )
148 $PHP_SELF = $_SERVER['PHP_SELF']; // backward compatibility
149 if ( empty ( $PHP_SELF ) )
150 $PHP_SELF = ''; // this happens when running send_reminders.php from CL
151 if ( ! strstr ( $PHP_SELF, "login.php" ) && ! empty ( $GLOBALS["login"] ) ) {
152 $GLOBALS["login"] = "";
155 // Define an array to use to jumble up the key: $offsets
156 // We define a unique key to scramble the cookie we generate.
157 // We use the admin install password that the user set to make
158 // the salt unique for each WebCalendar install.
159 if ( ! empty ( $settings ) && ! empty ( $settings['install_password'] ) ) {
160 $salt = $settings['install_password'];
162 $salt = md5 ( $db_login );
164 $salt_len = strlen ( $salt );
166 if ( ! empty ( $db_password ) ) {
167 $salt2 = md5 ( $db_password );
169 $salt2 = md5 ( "oogabooga" );
171 $salt2_len = strlen ( $salt2 );
174 for ( $i = 0; $i < $salt_len || $i < $salt2_len; $i++ ) {
176 if ( $i < $salt_len )
177 $offsets[$i] += ord ( substr ( $salt, $i, 1 ) );
178 if ( $i < $salt2_len )
179 $offsets[$i] += ord ( substr ( $salt2, $i, 1 ) );
183 for ( $i = 0; $i < count ( $offsets ); $i++ ) {
184 echo "offset $i: $offsets[$i] <br />\n";
189 * Functions start here. All non-function code should be above this
191 * Note to developers:
192 * Documentation is generated from the function comments below.
193 * When adding/updating functions, please follow the following conventions
194 * seen below. Your cooperation in this matter is appreciated :-)
196 * If you want your documentation to link to the db documentation,
197 * just make sure you mention the db table name followed by "table"
198 * on the same line. Here's an example:
199 * Retrieve preferences from the webcal_user_pref table.
204 * Gets the value resulting from an HTTP POST method.
206 * <b>Note:</b> The return value will be affected by the value of
207 * <var>magic_quotes_gpc</var> in the php.ini file.
209 * @param string $name Name used in the HTML form
211 * @return string The value used in the HTML form
215 function getPostValue ( $name ) {
216 global $HTTP_POST_VARS;
218 if ( isset ( $_POST ) && is_array ( $_POST ) && ! empty ( $_POST[$name] ) ) {
219 $HTTP_POST_VARS[$name] = $_POST[$name];
220 return $_POST[$name];
221 } else if ( ! isset ( $HTTP_POST_VARS ) ) {
223 } else if ( ! isset ( $HTTP_POST_VARS[$name] ) ) {
226 return ( $HTTP_POST_VARS[$name] );
230 * Gets the value resulting from an HTTP GET method.
232 * <b>Note:</b> The return value will be affected by the value of
233 * <var>magic_quotes_gpc</var> in the php.ini file.
235 * If you need to enforce a specific input format (such as numeric input), then
236 * use the {@link getValue()} function.
238 * @param string $name Name used in the HTML form or found in the URL
240 * @return string The value used in the HTML form (or URL)
244 function getGetValue ( $name ) {
245 global $HTTP_GET_VARS;
247 if ( isset ( $_GET ) && is_array ( $_GET ) && ! empty ( $_GET[$name] ) ) {
248 $HTTP_GET_VARS[$name] = $_GET[$name];
250 } else if ( ! isset ( $HTTP_GET_VARS ) ) {
252 } else if ( ! isset ( $HTTP_GET_VARS[$name] ) ) {
255 return ( $HTTP_GET_VARS[$name] );
259 * Gets the value resulting from either HTTP GET method or HTTP POST method.
261 * <b>Note:</b> The return value will be affected by the value of
262 * <var>magic_quotes_gpc</var> in the php.ini file.
264 * <b>Note:</b> If you need to get an integer value, yuou can use the
265 * getIntValue function.
267 * @param string $name Name used in the HTML form or found in the URL
268 * @param string $format A regular expression format that the input must match.
269 * If the input does not match, an empty string is
270 * returned and a warning is sent to the browser. If The
271 * <var>$fatal</var> parameter is true, then execution
272 * will also stop when the input does not match the
274 * @param bool $fatal Is it considered a fatal error requiring execution to
275 * stop if the value retrieved does not match the format
276 * regular expression?
278 * @return string The value used in the HTML form (or URL)
283 function getValue ( $name, $format="", $fatal=false ) {
284 $val = getPostValue ( $name );
285 if ( ! isset ( $val ) )
286 $val = getGetValue ( $name );
287 // for older PHP versions...
288 if ( ! isset ( $val ) && get_magic_quotes_gpc () == 1 &&
289 ! empty ( $GLOBALS[$name] ) )
290 $val = $GLOBALS[$name];
291 if ( ! isset ( $val ) )
293 if ( ! empty ( $format ) && ! preg_match ( "/^" . $format . "$/", $val ) ) {
296 die_miserable_death ( "Fatal Error: Invalid data format for $name" );
305 * Gets an integer value resulting from an HTTP GET or HTTP POST method.
307 * <b>Note:</b> The return value will be affected by the value of
308 * <var>magic_quotes_gpc</var> in the php.ini file.
310 * @param string $name Name used in the HTML form or found in the URL
311 * @param bool $fatal Is it considered a fatal error requiring execution to
312 * stop if the value retrieved does not match the format
313 * regular expression?
315 * @return string The value used in the HTML form (or URL)
319 function getIntValue ( $name, $fatal=false ) {
320 $val = getValue ( $name, "-?[0-9]+", $fatal );
325 * Loads default system settings (which can be updated via admin.php).
327 * System settings are stored in the webcal_config table.
329 * <b>Note:</b> If the setting for <var>server_url</var> is not set, the value
330 * will be calculated and stored in the database.
332 * @global string User's login name
333 * @global bool Readonly
334 * @global string HTTP hostname
335 * @global int Server's port number
336 * @global string Request string
337 * @global array Server variables
339 function load_global_settings () {
340 global $login, $readonly, $HTTP_HOST, $SERVER_PORT, $REQUEST_URI, $_SERVER;
342 // Note: when running from the command line (send_reminders.php),
343 // these variables are (obviously) not set.
344 // TODO: This type of checking should be moved to a central locationm
346 if ( isset ( $_SERVER ) && is_array ( $_SERVER ) ) {
347 if ( empty ( $HTTP_HOST ) && isset ( $_SERVER["HTTP_POST"] ) )
348 $HTTP_HOST = $_SERVER["HTTP_HOST"];
349 if ( empty ( $SERVER_PORT ) && isset ( $_SERVER["SERVER_PORT"] ) )
350 $SERVER_PORT = $_SERVER["SERVER_PORT"];
351 if ( empty ( $REQUEST_URI ) && isset ( $_SERVER["REQUEST_URI"] ) )
352 $REQUEST_URI = $_SERVER["REQUEST_URI"];
355 $res = dbi_query ( "SELECT cal_setting, cal_value FROM webcal_config" );
357 while ( $row = dbi_fetch_row ( $res ) ) {
360 //echo "Setting '$setting' to '$value' <br />\n";
361 $GLOBALS[$setting] = $value;
363 dbi_free_result ( $res );
366 // If app name not set.... default to "Title". This gets translated
367 // later since this function is typically called before translate.php
369 // Note: We usually use translate($application_name) instead of
370 // translate("Title").
371 if ( empty ( $GLOBALS["application_name"] ) )
372 $GLOBALS["application_name"] = "Title";
374 // If $server_url not set, then calculate one for them, then store it
376 if ( empty ( $GLOBALS["server_url"] ) ) {
377 if ( ! empty ( $HTTP_HOST ) && ! empty ( $REQUEST_URI ) ) {
378 $ptr = strrpos ( $REQUEST_URI, "/" );
380 $uri = substr ( $REQUEST_URI, 0, $ptr + 1 );
381 $server_url = "http://" . $HTTP_HOST;
382 if ( ! empty ( $SERVER_PORT ) && $SERVER_PORT != 80 )
383 $server_url .= ":" . $SERVER_PORT;
386 dbi_query ( "INSERT INTO webcal_config ( cal_setting, cal_value ) ".
387 "VALUES ( 'server_url', '$server_url' )" );
388 $GLOBALS["server_url"] = $server_url;
393 // If no font settings, then set some
394 if ( empty ( $GLOBALS["FONTS"] ) ) {
395 if ( $GLOBALS["LANGUAGE"] == "Japanese" )
396 $GLOBALS["FONTS"] = "Osaka, Arial, Helvetica, sans-serif";
398 $GLOBALS["FONTS"] = "Arial, Helvetica, sans-serif";
403 * Gets the list of active plugins.
405 * Should be called after {@link load_global_settings()} and {@link load_user_preferences()}.
407 * @internal cek: ignored since I am not sure this will ever be used...
409 * @return array Active plugins
413 function get_plugin_list ( $include_disabled=false ) {
414 // first get list of available plugins
415 $sql = "SELECT cal_setting FROM webcal_config " .
416 "WHERE cal_setting LIKE '%.plugin_status'";
417 if ( ! $include_disabled )
418 $sql .= " AND cal_value = 'Y'";
419 $sql .= " ORDER BY cal_setting";
420 $res = dbi_query ( $sql );
423 while ( $row = dbi_fetch_row ( $res ) ) {
424 $e = explode ( ".", $row[0] );
429 dbi_free_result ( $res );
431 echo translate("Database error") . ": " . dbi_error (); exit;
433 if ( count ( $plugins ) == 0 ) {
434 $plugins[] = "webcalendar";
440 * Get plugins available to the current user.
442 * Do this by getting a list of all plugins that are not disabled by the
443 * administrator and make sure this user has not disabled any of them.
445 * It's done this was so that when an admin adds a new plugin, it shows up on
446 * each users system automatically (until they disable it).
448 * @return array Plugins available to current user
452 function get_user_plugin_list () {
454 $all_plugins = get_plugin_list ();
455 for ( $i = 0; $i < count ( $all_plugins ); $i++ ) {
456 if ( $GLOBALS[$all_plugins[$i] . ".disabled"] != "N" )
457 $ret[] = $all_plugins[$i];
463 * Identify user's browser.
465 * Returned value will be one of:
466 * - "Mozilla/5" = Mozilla (open source Mozilla 5.0)
467 * - "Mozilla/[3,4]" = Netscape (3.X, 4.X)
468 * - "MSIE 4" = MSIE (4.X)
470 * @return string String identifying browser
474 function get_web_browser () {
475 if ( ereg ( "MSIE [0-9]", getenv ( "HTTP_USER_AGENT" ) ) )
477 if ( ereg ( "Mozilla/[234]", getenv ( "HTTP_USER_AGENT" ) ) )
479 if ( ereg ( "Mozilla/[5678]", getenv ( "HTTP_USER_AGENT" ) ) )
486 * Logs a debug message.
488 * Generally, we do not leave calls to this function in the code. It is used
489 * for debugging only.
491 * @param string $msg Text to be logged
493 function do_debug ( $msg ) {
494 // log to /tmp/webcal-debug.log
495 //error_log ( date ( "Y-m-d H:i:s" ) . "> $msg\n",
496 // 3, "/tmp/webcal-debug.log" );
497 //error_log ( date ( "Y-m-d H:i:s" ) . "> $msg\n",
498 // 2, "sockieman:2000" );
502 * Gets user's preferred view.
504 * The user's preferred view is stored in the $STARTVIEW global variable. This
505 * is loaded from the user preferences (or system settings if there are no user
508 * @param string $indate Date to pass to preferred view in YYYYMMDD format
509 * @param string $args Arguments to include in the URL (such as "user=joe")
511 * @return string URL of the user's preferred view
513 function get_preferred_view ( $indate="", $args="" ) {
514 global $STARTVIEW, $thisdate;
516 $url = empty ( $STARTVIEW ) ? "month.php" : $STARTVIEW;
517 // We used to just store "month" in $STARTVIEW without the ".php"
518 // This is just to prevent users from getting a "404 not found" if
519 // they have not updated their preferences.
520 if ( $url == "month" || $url == "day" || $url == "week" || $url == "year" )
523 $url = str_replace ( '&', '&', $url );
524 $url = str_replace ( '&', '&', $url );
526 $xdate = empty ( $indate ) ? $thisdate : $indate;
527 if ( ! empty ( $xdate ) ) {
528 if ( strstr ( $url, "?" ) )
529 $url .= '&' . "date=$xdate";
531 $url .= '?' . "date=$xdate";
534 if ( ! empty ( $args ) ) {
535 if ( strstr ( $url, "?" ) )
536 $url .= '&' . $args;
545 * Sends a redirect to the user's preferred view.
547 * The user's preferred view is stored in the $STARTVIEW global variable. This
548 * is loaded from the user preferences (or system settings if there are no user
551 * @param string $indate Date to pass to preferred view in YYYYMMDD format
552 * @param string $args Arguments to include in the URL (such as "user=joe")
554 function send_to_preferred_view ( $indate="", $args="" ) {
555 $url = get_preferred_view ( $indate, $args );
556 do_redirect ( $url );
559 /** Sends a redirect to the specified page.
561 * The database connection is closed and execution terminates in this function.
563 * <b>Note:</b> MS IIS/PWS has a bug in which it does not allow us to send a
564 * cookie and a redirect in the same HTTP header. When we detect that the web
565 * server is IIS, we accomplish the redirect using meta-refresh. See the
566 * following for more info on the IIS bug:
568 * {@link http://www.faqts.com/knowledge_base/view.phtml/aid/9316/fid/4}
570 * @param string $url The page to redirect to. In theory, this should be an
571 * absolute URL, but all browsers accept relative URLs (like
574 * @global string Type of webserver
575 * @global array Server variables
576 * @global resource Database connection
578 function do_redirect ( $url ) {
579 global $SERVER_SOFTWARE, $_SERVER, $c;
581 // Replace any '&' with '&' since we don't want that in the HTTP
583 $url = str_replace ( '&', '&', $url );
585 if ( empty ( $SERVER_SOFTWARE ) )
586 $SERVER_SOFTWARE = $_SERVER["SERVER_SOFTWARE"];
587 //echo "SERVER_SOFTWARE = $SERVER_SOFTWARE <br />\n"; exit;
588 if ( ( substr ( $SERVER_SOFTWARE, 0, 5 ) == "Micro" ) ||
589 ( substr ( $SERVER_SOFTWARE, 0, 3 ) == "WN/" ) ) {
590 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html
591 PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
592 \"DTD/xhtml1-transitional.dtd\">
593 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
594 <head>\n<title>Redirect</title>\n" .
595 "<meta http-equiv=\"refresh\" content=\"0; url=$url\" />\n</head>\n<body>\n" .
596 "Redirecting to.. <a href=\"" . $url . "\">here</a>.</body>\n</html>";
598 Header ( "Location: $url" );
599 //print "<javascript>window.location.href='index.php';</script>" ;
600 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html
601 PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
602 \"DTD/xhtml1-transitional.dtd\">
603 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
604 <head>\n<title>Redirect</title>\n</head>\n<body>\n" .
605 "Redirecting to aa... <a href=\"" . $url . "\">here</a>.</body>\n</html>";
612 * Sends an HTTP login request to the browser and stops execution.
614 function send_http_login () {
615 global $lang_file, $application_name;
617 if ( strlen ( $lang_file ) ) {
618 Header ( "WWW-Authenticate: Basic realm=\"" . translate("Title") . "\"");
619 Header ( "HTTP/1.0 401 Unauthorized" );
620 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html
621 PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
622 \"DTD/xhtml1-transitional.dtd\">
623 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
624 <head>\n<title>Unauthorized</title>\n</head>\n<body>\n" .
625 "<h2>" . translate("Title") . "</h2>\n" .
626 translate("You are not authorized") .
627 "\n</body>\n</html>";
629 Header ( "WWW-Authenticate: Basic realm=\"WebCalendar\"");
630 Header ( "HTTP/1.0 401 Unauthorized" );
631 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html
632 PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
633 \"DTD/xhtml1-transitional.dtd\">
634 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
635 <head>\n<title>Unauthorized</title>\n</head>\n<body>\n" .
636 "<h2>WebCalendar</h2>\n" .
637 "You are not authorized" .
638 "\n</body>\n</html>";
644 * Generates a cookie that saves the last calendar view.
646 * Cookie is based on the current <var>$REQUEST_URI</var>.
648 * We save this cookie so we can return to this same page after a user
649 * edits/deletes/etc an event.
651 * @global string Request string
653 function remember_this_view () {
655 if ( empty ( $REQUEST_URI ) )
656 $REQUEST_URI = $_SERVER["REQUEST_URI"];
658 // do not use anything with friendly in the URI
659 if ( strstr ( $REQUEST_URI, "friendly=" ) )
662 SetCookie ( "webcalendar_last_view", $REQUEST_URI );
666 * Gets the last page stored using {@link remember_this_view()}.
668 * @return string The URL of the last view or an empty string if it cannot be
671 * @global array Cookies
673 function get_last_view () {
674 global $HTTP_COOKIE_VARS;
677 if ( isset ( $_COOKIE["webcalendar_last_view"] ) ) {
678 $HTTP_COOKIE_VARS["webcalendar_last_view"] = $_COOKIE["webcalendar_last_view"];
679 $val = $_COOKIE["webcalendar_last_view"];
680 } else if ( isset ( $HTTP_COOKIE_VARS["webcalendar_last_view"] ) ) {
681 $val = $HTTP_COOKIE_VARS["webcalendar_last_view"];
683 $val = str_replace ( "&", "&", $val );
688 * Sends HTTP headers that tell the browser not to cache this page.
690 * Different browser use different mechanisms for this, so a series of HTTP
691 * header directives are sent.
693 * <b>Note:</b> This function needs to be called before any HTML output is sent
696 function send_no_cache_header () {
697 header ( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" );
698 header ( "Last-Modified: " . gmdate ( "D, d M Y H:i:s" ) . " GMT" );
699 header ( "Cache-Control: no-store, no-cache, must-revalidate" );
700 header ( "Cache-Control: post-check=0, pre-check=0", false );
701 header ( "Pragma: no-cache" );
705 * Loads the current user's preferences as global variables from the webcal_user_pref table.
707 * Also loads the list of views for this user (not really a preference, but
708 * this is a convenient place to put this...)
711 * - If <var>$allow_color_customization</var> is set to 'N', then we ignore any
713 * - Other default values will also be set if the user has not saved a
714 * preference and no global value has been set by the administrator in the
717 function load_user_preferences () {
718 global $login, $browser, $views, $prefarray, $is_assistant,
719 $has_boss, $user, $is_nonuser_admin, $allow_color_customization;
733 $browser = get_web_browser ();
734 $browser_lang = get_browser_language ();
735 $prefarray = array ();
737 // Note: default values are set in config.php
739 "SELECT cal_setting, cal_value FROM webcal_user_pref " .
740 "WHERE cal_login = '$login'" );
742 while ( $row = dbi_fetch_row ( $res ) ) {
745 if ( $allow_color_customization == 'N' ) {
746 if ( isset ( $colors[$setting] ) )
749 $sys_setting = "sys_" . $setting;
750 // save system defaults
751 if ( ! empty ( $GLOBALS[$setting] ) )
752 $GLOBALS["sys_" . $setting] = $GLOBALS[$setting];
753 $GLOBALS[$setting] = $value;
754 $prefarray[$setting] = $value;
755 if ( $setting == "LANGUAGE" )
758 dbi_free_result ( $res );
760 // get views for this user and global views
762 "SELECT cal_view_id, cal_name, cal_view_type, cal_is_global " .
763 "FROM webcal_view " .
764 "WHERE cal_owner = '$login' OR cal_is_global = 'Y' " .
765 "ORDER BY cal_name" );
768 while ( $row = dbi_fetch_row ( $res ) ) {
769 if ( $row[2] == 'S' )
770 $url = "view_t.php?timeb=1&id=$row[0]";
771 else if ( $row[2] == 'T' )
772 $url = "view_t.php?timeb=0&id=$row[0]";
774 $url = "view_" . strtolower ( $row[2] ) . ".php?id=$row[0]";
776 "cal_view_id" => $row[0],
777 "cal_name" => $row[1],
778 "cal_view_type" => $row[2],
779 "cal_is_global" => $row[3],
784 dbi_free_result ( $res );
787 // If user has not set a language preference, then use their browser
788 // settings to figure it out, and save it in the database for future
789 // use (email reminders).
790 if ( ! $lang_found && strlen ( $login ) && $login != "__public__" ) {
791 $LANGUAGE = $browser_lang;
792 dbi_query ( "INSERT INTO webcal_user_pref " .
793 "( cal_login, cal_setting, cal_value ) VALUES " .
794 "( '$login', 'LANGUAGE', '$LANGUAGE' )" );
797 if ( empty ( $GLOBALS["DATE_FORMAT_MY"] ) )
798 $GLOBALS["DATE_FORMAT_MY"] = "__month__ __yyyy__";
799 if ( empty ( $GLOBALS["DATE_FORMAT_MD"] ) )
800 $GLOBALS["DATE_FORMAT_MD"] = "__month__ __dd__";
801 $is_assistant = empty ( $user ) ? false :
802 user_is_assistant ( $login, $user );
803 $has_boss = user_has_boss ( $login );
804 $is_nonuser_admin = ($user) ? user_is_nonuser_admin ( $login, $user ) : false;
805 if ( $is_nonuser_admin ) load_nonuser_preferences ($user);
809 * Gets the list of external users for an event from the webcal_entry_ext_user table in an HTML format.
811 * @param int $event_id Event ID
812 * @param int $use_mailto When set to 1, email address will contain an href
813 * link with a mailto URL.
815 * @return string The list of external users for an event formatte in HTML.
817 function event_get_external_users ( $event_id, $use_mailto=0 ) {
821 $res = dbi_query ( "SELECT cal_fullname, cal_email " .
822 "FROM webcal_entry_ext_user " .
823 "WHERE cal_id = $event_id " .
824 "ORDER by cal_fullname" );
826 while ( $row = dbi_fetch_row ( $res ) ) {
827 if ( strlen ( $ret ) )
829 // Remove [\d] if duplicate name
830 $trow = trim( preg_replace( '/\[[\d]]/' , "", $row[0] ) );
832 if ( strlen ( $row[1] ) ) {
834 $ret .= " <a href=\"mailto:$row[1]\"><" .
835 htmlentities ( $row[1] ) . "></a>";
837 $ret .= " <". htmlentities ( $row[1] ) . ">";
841 dbi_free_result ( $res );
843 echo translate("Database error") .": " . dbi_error ();
844 echo "<br />\nSQL:<br />\n$sql";
851 * Adds something to the activity log for an event.
853 * The information will be saved to the webcal_entry_log table.
855 * @param int $event_id Event ID
856 * @param string $user Username of user doing this
857 * @param string $user_cal Username of user whose calendar is affected
858 * @param string $type Type of activity we are logging:
864 * - $LOG_NOTIFICATION
866 * @param string $text Text comment to add with activity log entry
868 function activity_log ( $event_id, $user, $user_cal, $type, $text ) {
871 if ( empty ( $type ) ) {
872 echo "Error: type not set for activity log!";
873 // but don't exit since we may be in mid-transaction
877 $res = dbi_query ( "SELECT MAX(cal_log_id) FROM webcal_entry_log" );
879 if ( $row = dbi_fetch_row ( $res ) ) {
880 $next_id = $row[0] + 1;
882 dbi_free_result ( $res );
885 $date = date ( "Ymd" );
886 $time = date ( "Gis" );
887 $sql_text = empty ( $text ) ? "NULL" : "'$text'";
888 $sql_user_cal = empty ( $user_cal ) ? "NULL" : "'$user_cal'";
890 $sql = "INSERT INTO webcal_entry_log ( " .
891 "cal_log_id, cal_entry_id, cal_login, cal_user_cal, cal_type, " .
892 "cal_date, cal_time, cal_text ) VALUES ( $next_id, $event_id, " .
893 "'$user', $sql_user_cal, '$type', $date, $time, $sql_text )";
894 if ( ! dbi_query ( $sql ) ) {
895 echo "Database error: " . dbi_error ();
896 echo "<br />\nSQL:<br />\n$sql";
902 * Gets a list of users.
904 * If groups are enabled, this will restrict the list of users to only those
905 * users who are in the same group(s) as the user (unless the user is an admin
906 * user). We allow admin users to see all users because they can also edit
907 * someone else's events (so they may need access to users who are not in the
908 * same groups that they are in).
910 * @return array Array of users, where each element in the array is an array
911 * with the following keys:
921 function get_my_users () {
922 global $login, $is_admin, $groups_enabled, $user_sees_only_his_groups;
924 if ( $groups_enabled == "Y" && $user_sees_only_his_groups == "Y" &&
926 // get groups that current user is in
927 $res = dbi_query ( "SELECT cal_group_id FROM webcal_group_user " .
928 "WHERE cal_login = '$login'" );
931 while ( $row = dbi_fetch_row ( $res ) ) {
934 dbi_fetch_row ( $res );
936 $u = user_get_users ();
937 $u_byname = array ();
938 for ( $i = 0; $i < count ( $u ); $i++ ) {
939 $name = $u[$i]['cal_login'];
940 $u_byname[$name] = $u[$i];
943 if ( count ( $groups ) == 0 ) {
944 // Eek. User is in no groups... Return only themselves
945 $ret[] = $u_byname[$login];
948 // get list of users in the same groups as current user
949 $sql = "SELECT DISTINCT(webcal_group_user.cal_login), cal_lastname, cal_firstname from webcal_group_user " .
950 "LEFT JOIN webcal_user ON webcal_group_user.cal_login = webcal_user.cal_login " .
951 "WHERE cal_group_id ";
952 if ( count ( $groups ) == 1 )
953 $sql .= "= " . $groups[0];
955 $sql .= "IN ( " . implode ( ", ", $groups ) . " )";
957 $sql .= " ORDER BY cal_lastname, cal_firstname, webcal_group_user.cal_login";
958 //echo "SQL: $sql <br />\n";
959 $res = dbi_query ( $sql );
961 while ( $row = dbi_fetch_row ( $res ) ) {
962 $ret[] = $u_byname[$row[0]];
964 dbi_free_result ( $res );
968 // groups not enabled... return all users
969 //echo "No groups. ";
970 return user_get_users ();
975 * Gets a preference setting for the specified user.
977 * If no value is found in the database, then the system default setting will
980 * @param string $user User login we are getting preference for
981 * @param string $setting Name of the setting
983 * @return string The value found in the webcal_user_pref table for the
984 * specified setting or the sytem default if no user settings
987 function get_pref_setting ( $user, $setting ) {
990 if ( ! isset ( $GLOBALS["sys_" .$setting] ) ) {
991 // this could happen if the current user has not saved any pref. yet
992 if ( ! empty ( $GLOBALS[$setting] ) )
993 $ret = $GLOBALS[$setting];
995 $ret = $GLOBALS["sys_" .$setting];
998 $sql = "SELECT cal_value FROM webcal_user_pref " .
999 "WHERE cal_login = '" . $user . "' AND " .
1000 "cal_setting = '" . $setting . "'";
1001 //echo "SQL: $sql <br />\n";
1002 $res = dbi_query ( $sql );
1004 if ( $row = dbi_fetch_row ( $res ) )
1006 dbi_free_result ( $res );
1012 * Gets browser-specified language preference.
1014 * @return string Preferred language
1018 function get_browser_language () {
1019 global $HTTP_ACCEPT_LANGUAGE, $browser_languages;
1021 if ( empty ( $HTTP_ACCEPT_LANGUAGE ) &&
1022 isset ( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) )
1023 $HTTP_ACCEPT_LANGUAGE = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
1024 if ( empty ( $HTTP_ACCEPT_LANGUAGE ) ) {
1027 $langs = explode ( ",", $HTTP_ACCEPT_LANGUAGE );
1028 for ( $i = 0; $i < count ( $langs ); $i++ ) {
1029 $l = strtolower ( trim ( ereg_replace(';.*', '', $langs[$i] ) ) );
1031 if ( ! empty ( $browser_languages[$l] ) ) {
1032 return $browser_languages[$l];
1036 //if ( strlen ( $HTTP_ACCEPT_LANGUAGE ) )
1037 // return "none ($HTTP_ACCEPT_LANGUAGE not supported)";
1043 * Loads current user's layer info into layer global variable.
1045 * If the system setting <var>$allow_view_other</var> is not set to 'Y', then
1046 * we ignore all layer functionality. If <var>$force</var> is 0, we only load
1047 * layers if the current user preferences have layers turned on.
1049 * @param string $user Username of user to load layers for
1050 * @param int $force If set to 1, then load layers for this user even if
1051 * user preferences have layers turned off.
1053 function load_user_layers ($user="",$force=0) {
1056 global $LAYERS_STATUS, $allow_view_other;
1063 if ( empty ( $allow_view_other ) || $allow_view_other != 'Y' )
1064 return; // not allowed to view others' calendars, so cannot use layers
1066 if ( $force || ( ! empty ( $LAYERS_STATUS ) && $LAYERS_STATUS != "N" ) ) {
1068 "SELECT cal_layerid, cal_layeruser, cal_color, cal_dups " .
1069 "FROM webcal_user_layers " .
1070 "WHERE cal_login = '$user' ORDER BY cal_layerid" );
1073 while ( $row = dbi_fetch_row ( $res ) ) {
1074 $layers[$row[0]] = array (
1075 "cal_layerid" => $row[0],
1076 "cal_layeruser" => $row[1],
1077 "cal_color" => $row[2],
1078 "cal_dups" => $row[3]
1082 dbi_free_result ( $res );
1085 //echo "Not loading!";
1090 * Generates the HTML used in an event popup for the site_extras fields of an event.
1092 * @param int $id Event ID
1094 * @return string The HTML to be used within the event popup for any site_extra
1095 * fields found for the specified event
1097 function site_extras_for_popup ( $id ) {
1098 global $site_extras_in_popup, $site_extras;
1099 // These are needed in case the site_extras.php file was already
1101 global $EXTRA_TEXT, $EXTRA_MULTILINETEXT, $EXTRA_URL, $EXTRA_DATE,
1102 $EXTRA_EMAIL, $EXTRA_USER, $EXTRA_REMINDER, $EXTRA_SELECTLIST;
1103 global $EXTRA_REMINDER_WITH_DATE, $EXTRA_REMINDER_WITH_OFFSET,
1104 $EXTRA_REMINDER_DEFAULT_YES;
1108 if ( $site_extras_in_popup != 'Y' )
1111 include_once 'includes/site_extras.php';
1113 $extras = get_site_extra_fields ( $id );
1114 for ( $i = 0; $i < count ( $site_extras ); $i++ ) {
1115 $extra_name = $site_extras[$i][0];
1116 $extra_type = $site_extras[$i][2];
1117 $extra_arg1 = $site_extras[$i][3];
1118 $extra_arg2 = $site_extras[$i][4];
1119 if ( ! empty ( $extras[$extra_name]['cal_name'] ) ) {
1120 $ret .= "<dt>" . translate ( $site_extras[$i][1] ) . ":</dt>\n<dd>";
1121 if ( $extra_type == $EXTRA_DATE ) {
1122 if ( $extras[$extra_name]['cal_date'] > 0 )
1123 $ret .= date_to_str ( $extras[$extra_name]['cal_date'] );
1124 } else if ( $extra_type == $EXTRA_TEXT ||
1125 $extra_type == $EXTRA_MULTILINETEXT ) {
1126 $ret .= nl2br ( $extras[$extra_name]['cal_data'] );
1127 } else if ( $extra_type == $EXTRA_REMINDER ) {
1128 if ( $extras[$extra_name]['cal_remind'] <= 0 )
1129 $ret .= translate ( "No" );
1131 $ret .= translate ( "Yes" );
1132 if ( ( $extra_arg2 & $EXTRA_REMINDER_WITH_DATE ) > 0 ) {
1133 $ret .= " - ";
1134 $ret .= date_to_str ( $extras[$extra_name]['cal_date'] );
1135 } else if ( ( $extra_arg2 & $EXTRA_REMINDER_WITH_OFFSET ) > 0 ) {
1136 $ret .= " - ";
1137 $minutes = $extras[$extra_name]['cal_data'];
1138 $d = (int) ( $minutes / ( 24 * 60 ) );
1139 $minutes -= ( $d * 24 * 60 );
1140 $h = (int) ( $minutes / 60 );
1141 $minutes -= ( $h * 60 );
1143 $ret .= $d . " " . translate("days") . " ";
1145 $ret .= $h . " " . translate("hours") . " ";
1147 $ret .= $minutes . " " . translate("minutes");
1148 $ret .= " " . translate("before event" );
1152 $ret .= $extras[$extra_name]['cal_data'];
1161 * Builds the HTML for the event popup.
1163 * @param string $popupid CSS id to use for event popup
1164 * @param string $user Username of user the event pertains to
1165 * @param string $description Event description
1166 * @param string $time Time of the event (already formatted in a display format)
1167 * @param string $site_extras HTML for any site_extras for this event
1169 * @return string The HTML for the event popup
1171 function build_event_popup ( $popupid, $user, $description, $time, $site_extras='' ) {
1172 global $login, $popup_fullnames, $popuptemp_fullname;
1173 $ret = "<dl id=\"$popupid\" class=\"popup\">\n";
1175 if ( empty ( $popup_fullnames ) )
1176 $popup_fullnames = array ();
1178 if ( $user != $login ) {
1179 if ( empty ( $popup_fullnames[$user] ) ) {
1180 user_load_variables ( $user, "popuptemp_" );
1181 $popup_fullnames[$user] = $popuptemp_fullname;
1183 $ret .= "<dt>" . translate ("User") .
1184 ":</dt>\n<dd>$popup_fullnames[$user]</dd>\n";
1186 if ( strlen ( $time ) )
1187 $ret .= "<dt>" . translate ("Time") . ":</dt>\n<dd>$time</dd>\n";
1188 $ret .= "<dt>" . translate ("Description") . ":</dt>\n<dd>";
1189 if ( ! empty ( $GLOBALS['allow_html_description'] ) &&
1190 $GLOBALS['allow_html_description'] == 'Y' ) {
1191 $str = str_replace ( "&", "&", $description );
1192 $str = str_replace ( "&amp;", "&", $str );
1193 // If there is no html found, then go ahead and replace
1194 // the line breaks ("\n") with the html break.
1195 if ( strstr ( $str, "<" ) && strstr ( $str, ">" ) ) {
1196 // found some html...
1199 // no html, replace line breaks
1200 $ret .= nl2br ( $str );
1203 // html not allowed in description, escape everything
1204 $ret .= nl2br ( htmlspecialchars ( $description ) );
1207 if ( ! empty ( $site_extras ) )
1208 $ret .= $site_extras;
1214 * Prints out a date selection box for use in a form.
1216 * @param string $prefix Prefix to use in front of form element names
1217 * @param int $date Currently selected date (in YYYYMMDD format)
1219 * @uses date_selection_html
1221 function print_date_selection ( $prefix, $date ) {
1222 print date_selection_html ( $prefix, $date );
1226 * Generate HTML for a date selection for use in a form.
1228 * @param string $prefix Prefix to use in front of form element names
1229 * @param int $date Currently selected date (in YYYYMMDD format)
1231 * @return string HTML for the selection box
1233 function date_selection_html ( $prefix, $date ) {
1236 if ( strlen ( $date ) != 8 )
1237 $date = date ( "Ymd" );
1238 $thisyear = $year = substr ( $date, 0, 4 );
1239 $thismonth = $month = substr ( $date, 4, 2 );
1240 $thisday = $day = substr ( $date, 6, 2 );
1241 if ( $thisyear - date ( "Y" ) >= ( $num_years - 1 ) )
1242 $num_years = $thisyear - date ( "Y" ) + 2;
1243 $ret .= "<select name=\"" . $prefix . "day\">\n";
1244 for ( $i = 1; $i <= 31; $i++ )
1245 $ret .= "<option value=\"$i\"" .
1246 ( $i == $thisday ? " selected=\"selected\"" : "" ) . ">$i</option>\n";
1247 $ret .= "</select>\n<select name=\"" . $prefix . "month\">\n";
1248 for ( $i = 1; $i <= 12; $i++ ) {
1249 $m = month_short_name ( $i - 1 );
1250 $ret .= "<option value=\"$i\"" .
1251 ( $i == $thismonth ? " selected=\"selected\"" : "" ) . ">$m</option>\n";
1253 $ret .= "</select>\n<select name=\"" . $prefix . "year\">\n";
1254 for ( $i = -10; $i < $num_years; $i++ ) {
1255 $y = $thisyear + $i;
1256 $ret .= "<option value=\"$y\"" .
1257 ( $y == $thisyear ? " selected=\"selected\"" : "" ) . ">$y</option>\n";
1259 $ret .= "</select>\n";
1260 $ret .= "<input type=\"button\" onclick=\"selectDate( '" .
1261 $prefix . "day','" . $prefix . "month','" . $prefix . "year',$date, event)\" value=\"" .
1262 translate("Select") . "...\" />\n";
1268 * Prints out a minicalendar for a month.
1270 * @todo Make day.php NOT be a special case
1272 * @param int $thismonth Number of the month to print
1273 * @param int $thisyear Number of the year
1274 * @param bool $showyear Show the year in the calendar's title?
1275 * @param bool $show_weeknums Show week numbers to the left of each row?
1276 * @param string $minical_id id attribute for the minical table
1277 * @param string $month_link URL and query string for month link that should
1278 * come before the date specification (e.g.
1279 * month.php? or view_l.php?id=7&)
1281 function display_small_month ( $thismonth, $thisyear, $showyear,
1282 $show_weeknums=false, $minical_id='', $month_link='month.php?' ) {
1283 global $WEEK_START, $user, $login, $boldDays, $get_unapproved;
1284 global $DISPLAY_WEEKNUMBER;
1285 global $SCRIPT, $thisday; // Needed for day.php
1286 global $caturl, $today;
1288 if ( $user != $login && ! empty ( $user ) ) {
1289 $u_url = "user=$user" . "&";
1294 //start the minical table for each month
1295 echo "\n<table class=\"minical\"";
1296 if ( $minical_id != '' ) {
1297 echo " id=\"$minical_id\"";
1301 $monthstart = mktime(2,0,0,$thismonth,1,$thisyear);
1302 $monthend = mktime(2,0,0,$thismonth + 1,0,$thisyear);
1304 if ( $SCRIPT == 'day.php' ) {
1305 $month_ago = date ( "Ymd",
1306 mktime ( 3, 0, 0, $thismonth - 1, $thisday, $thisyear ) );
1307 $month_ahead = date ( "Ymd",
1308 mktime ( 3, 0, 0, $thismonth + 1, $thisday, $thisyear ) );
1310 echo "<caption>$thisday</caption>\n";
1312 echo "<tr class=\"monthnav\"><th colspan=\"7\">\n";
1313 echo "<a title=\"" .
1314 translate("Previous") . "\" class=\"prev\" href=\"day.php?" . $u_url .
1315 "date=$month_ago$caturl\"><img src=\"leftarrowsmall.gif\" alt=\"" .
1316 translate("Previous") . "\" /></a>\n";
1317 echo "<a title=\"" .
1318 translate("Next") . "\" class=\"next\" href=\"day.php?" . $u_url .
1319 "date=$month_ahead$caturl\"><img src=\"rightarrowsmall.gif\" alt=\"" .
1320 translate("Next") . "\" /></a>\n";
1321 echo month_name ( $thismonth - 1 );
1322 if ( $showyear != '' ) {
1325 echo "</th></tr>\n<tr>\n";
1326 } else { //not day script
1327 //print the month name
1328 echo "<caption><a href=\"{$month_link}{$u_url}year=$thisyear&month=$thismonth\">";
1329 echo month_name ( $thismonth - 1 ) .
1330 ( $showyear ? " $thisyear" : "" );
1331 echo "</a></caption>\n";
1333 echo "<thead>\n<tr>\n";
1336 //determine if the week starts on sunday or monday
1337 if ( $WEEK_START == "1" ) {
1338 $wkstart = get_monday_before ( $thisyear, $thismonth, 1 );
1340 $wkstart = get_sunday_before ( $thisyear, $thismonth, 1 );
1342 //print the headers to display the day of the week (sun, mon, tues, etc.)
1344 // if we're showing week numbers we need an extra column
1345 if ( $show_weeknums && $DISPLAY_WEEKNUMBER == 'Y' )
1346 echo "<th class=\"empty\"> </th>\n";
1347 //if the week doesn't start on monday, print the day
1348 if ( $WEEK_START == 0 ) echo "<th>" .
1349 weekday_short_name ( 0 ) . "</th>\n";
1350 //cycle through each day of the week until gone
1351 for ( $i = 1; $i < 7; $i++ ) {
1352 echo "<th>" . weekday_short_name ( $i ) . "</th>\n";
1354 //if the week DOES start on monday, print sunday
1355 if ( $WEEK_START == 1 )
1356 echo "<th>" . weekday_short_name ( 0 ) . "</th>\n";
1357 //end the header row
1358 echo "</tr>\n</thead>\n<tbody>\n";
1359 for ($i = $wkstart; date("Ymd",$i) <= date ("Ymd",$monthend);
1360 $i += (24 * 3600 * 7) ) {
1362 if ( $show_weeknums && $DISPLAY_WEEKNUMBER == 'Y' ) {
1363 echo "<td class=\"weeknumber\"><a href=\"week.php?" . $u_url .
1364 "date=".date("Ymd", $i)."\">(" . week_number($i) . ")</a></td>\n";
1366 for ($j = 0; $j < 7; $j++) {
1367 $date = $i + ($j * 24 * 3600);
1368 $dateYmd = date ( "Ymd", $date );
1371 $ev = get_entries ( $user, $dateYmd, $get_unapproved );
1372 if ( count ( $ev ) > 0 ) {
1375 $rep = get_repeating_entries ( $user, $dateYmd, $get_unapproved );
1376 if ( count ( $rep ) > 0 )
1380 if ( $dateYmd >= date ("Ymd",$monthstart) &&
1381 $dateYmd <= date ("Ymd",$monthend) ) {
1383 $wday = date ( 'w', $date );
1385 //add class="weekend" if it's saturday or sunday
1386 if ( $wday == 0 || $wday == 6 ) {
1389 //if the day being viewed is today's date AND script = day.php
1390 if ( $dateYmd == $thisyear . $thismonth . $thisday &&
1391 $SCRIPT == 'day.php' ) {
1392 //if it's also a weekend, add a space between class names to combine styles
1393 if ( $class != '' ) {
1396 $class .= "selectedday";
1399 if ( $class != '' ) {
1402 $class .= "hasevents";
1404 if ( $class != '' ) {
1405 echo " class=\"$class\"";
1407 if ( date ( "Ymd", $date ) == date ( "Ymd", $today ) ){
1408 echo " id=\"today\"";
1410 echo "><a href=\"day.php?" .$u_url . "date=" . $dateYmd .
1412 echo date ( "d", $date ) . "</a></td>\n";
1414 echo "<td class=\"empty\"> </td>\n";
1419 echo "</tbody>\n</table>\n";
1423 * Prints the HTML for one day's events in the month view.
1425 * @param int $id Event ID
1426 * @param int $date Date of event (relevant in repeating events) in
1428 * @param int $time Time (in HHMMSS format)
1429 * @param int $duration Event duration in minutes
1430 * @param string $name Event name
1431 * @param string $description Long description of event
1432 * @param string $status Event status
1433 * @param int $pri Event priority
1434 * @param string $access Event access
1435 * @param string $event_owner Username of user associated with this event
1436 * @param int $event_cat Category of event for <var>$event_owner</var>
1438 * @staticvar int Used to ensure all event popups have a unique id
1440 * @uses build_event_popup
1442 function print_entry ( $id, $date, $time, $duration,
1443 $name, $description, $status,
1444 $pri, $access, $event_owner, $event_cat=-1 ) {
1445 global $eventinfo, $login, $user, $PHP_SELF, $TZ_OFFSET;
1450 if ( $login != $event_owner && strlen ( $event_owner ) ) {
1451 $class = "layerentry";
1454 if ( $status == "W" ) $class = "unapprovedentry";
1456 // if we are looking at a view, then always use "entry"
1457 if ( strstr ( $PHP_SELF, "view_m.php" ) ||
1458 strstr ( $PHP_SELF, "view_w.php" ) ||
1459 strstr ( $PHP_SELF, "view_v.php" ) ||
1460 strstr ( $PHP_SELF, "view_t.php" ) )
1463 if ( $pri == 3 ) echo "<strong>";
1464 $popupid = "eventinfo-$id-$key";
1466 echo "<a title=\"" .
1467 translate("View this entry") . "\" class=\"$class\" href=\"view_entry.php?id=$id&date=$date";
1468 if ( strlen ( $user ) > 0 )
1469 echo "&user=" . $user;
1470 echo "\" onmouseover=\"window.status='" .
1471 translate("View this entry") .
1472 "'; show(event, '$popupid'); return true;\" onmouseout=\"window.status=''; hide('$popupid'); return true;\">";
1473 $icon = "circle.gif";
1475 if ( $event_cat > 0 ) {
1476 $catIcon = "icons/cat-" . $event_cat . ".gif";
1477 if ( ! file_exists ( $catIcon ) )
1481 if ( empty ( $catIcon ) ) {
1482 echo "<img src=\"$icon\" class=\"bullet\" alt=\"" .
1483 translate("View this entry") . "\" />";
1485 // Use category icon
1486 echo "<img src=\"$catIcon\" alt=\"" .
1487 translate("View this entry") . "\" /><br />";
1490 if ( $login != $event_owner && strlen ( $event_owner ) ) {
1491 if ($layers) foreach ($layers as $layer) {
1492 if ($layer['cal_layeruser'] == $event_owner) {
1493 echo("<span style=\"color:" . $layer['cal_color'] . ";\">");
1500 if ( $duration == ( 24 * 60 ) ) {
1501 $timestr = translate("All day event");
1502 } else if ( $time != -1 ) {
1503 $timestr = display_time ( $time );
1504 $time_short = preg_replace ("/(:00)/", '', $timestr);
1505 echo $time_short . "» ";
1506 if ( $duration > 0 ) {
1508 $h = (int) ( $time / 10000 );
1509 $m = ( $time / 100 ) % 100;
1512 while ( $m >= 60 ) {
1516 $end_time = sprintf ( "%02d%02d00", $h, $m );
1517 $timestr .= " - " . display_time ( $end_time );
1520 if ( $login != $user && $access == 'R' && strlen ( $user ) ) {
1521 echo "(" . translate("Private") . ")";
1522 } else if ( $login != $event_owner && $access == 'R' &&
1523 strlen ( $event_owner ) ) {
1524 echo "(" . translate("Private") . ")";
1526 echo htmlspecialchars ( $name );
1529 if ( $login != $event_owner && strlen ( $event_owner ) ) {
1530 if ($layers) foreach ($layers as $layer) {
1531 if($layer['cal_layeruser'] == $event_owner) {
1537 if ( $pri == 3 ) echo "</strong>\n"; //end font-weight span
1539 if ( $login != $user && $access == 'R' && strlen ( $user ) )
1540 $eventinfo .= build_event_popup ( $popupid, $event_owner,
1541 translate("This event is confidential"), "" );
1543 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) )
1544 $eventinfo .= build_event_popup ( $popupid, $event_owner,
1545 translate("This event is confidential"), "" );
1547 $eventinfo .= build_event_popup ( $popupid, $event_owner,
1548 $description, $timestr, site_extras_for_popup ( $id ) );
1552 * Gets any site-specific fields for an entry that are stored in the database in the webcal_site_extras table.
1554 * @param int $eventid Event ID
1556 * @return array Array with the keys as follows:
1557 * - <var>cal_name</var>
1558 * - <var>cal_type</var>
1559 * - <var>cal_date</var>
1560 * - <var>cal_remind</var>
1561 * - <var>cal_data</var>
1563 function get_site_extra_fields ( $eventid ) {
1564 $sql = "SELECT cal_name, cal_type, cal_date, cal_remind, cal_data " .
1565 "FROM webcal_site_extras " .
1566 "WHERE cal_id = $eventid";
1567 $res = dbi_query ( $sql );
1570 while ( $row = dbi_fetch_row ( $res ) ) {
1571 // save by cal_name (e.g. "URL")
1572 $extras[$row[0]] = array (
1573 "cal_name" => $row[0],
1574 "cal_type" => $row[1],
1575 "cal_date" => $row[2],
1576 "cal_remind" => $row[3],
1577 "cal_data" => $row[4]
1580 dbi_free_result ( $res );
1586 * Reads all the events for a user for the specified range of dates.
1588 * This is only called once per page request to improve performance. All the
1589 * events get loaded into the array <var>$events</var> sorted by time of day
1592 * @param string $user Username
1593 * @param string $startdate Start date range, inclusive (in YYYYMMDD format)
1594 * @param string $enddate End date range, inclusive (in YYYYMMDD format)
1595 * @param int $cat_id Category ID to filter on
1597 * @return array Array of events
1599 * @uses query_events
1601 function read_events ( $user, $startdate, $enddate, $cat_id = '' ) {
1606 $sy = substr ( $startdate, 0, 4 );
1607 $sm = substr ( $startdate, 4, 2 );
1608 $sd = substr ( $startdate, 6, 2 );
1609 $ey = substr ( $enddate, 0, 4 );
1610 $em = substr ( $enddate, 4, 2 );
1611 $ed = substr ( $enddate, 6, 2 );
1612 if ( $startdate == $enddate ) {
1613 if ( $TZ_OFFSET == 0 ) {
1614 $date_filter = " AND webcal_entry.cal_date = $startdate";
1615 } else if ( $TZ_OFFSET > 0 ) {
1616 $prev_day = mktime ( 3, 0, 0, $sm, $sd - 1, $sy );
1617 $cutoff = 24 - $TZ_OFFSET . "0000";
1618 $date_filter = " AND ( ( webcal_entry.cal_date = $startdate AND " .
1619 "( webcal_entry.cal_time <= $cutoff OR " .
1620 "webcal_entry.cal_time = -1 ) ) OR " .
1621 "( webcal_entry.cal_date = " . date("Ymd", $prev_day ) .
1622 " AND webcal_entry.cal_time >= $cutoff ) )";
1624 $next_day = mktime ( 3, 0, 0, $sm, $sd + 1, $sy );
1625 $cutoff = ( 0 - $TZ_OFFSET ) * 10000;
1626 $date_filter = " AND ( ( webcal_entry.cal_date = $startdate AND " .
1627 "( webcal_entry.cal_time > $cutoff OR " .
1628 "webcal_entry.cal_time = -1 ) ) OR " .
1629 "( webcal_entry.cal_date = " . date("Ymd", $next_day ) .
1630 " AND webcal_entry.cal_time <= $cutoff ) )";
1633 if ( $TZ_OFFSET == 0 ) {
1634 $date_filter = " AND webcal_entry.cal_date >= $startdate " .
1635 "AND webcal_entry.cal_date <= $enddate";
1636 } else if ( $TZ_OFFSET > 0 ) {
1637 $prev_day = date ( ( "Ymd" ), mktime ( 3, 0, 0, $sm, $sd - 1, $sy ) );
1638 $enddate_minus1 = date ( ( "Ymd" ), mktime ( 3, 0, 0, $em, $ed - 1, $ey ) );
1639 $cutoff = 24 - $TZ_OFFSET . "0000";
1640 $date_filter = " AND ( ( webcal_entry.cal_date >= $startdate " .
1641 "AND webcal_entry.cal_date <= $enddate AND " .
1642 "webcal_entry.cal_time = -1 ) OR " .
1643 "( webcal_entry.cal_date = $prev_day AND " .
1644 "webcal_entry.cal_time >= $cutoff ) OR " .
1645 "( webcal_entry.cal_date = $enddate AND " .
1646 "webcal_entry.cal_time < $cutoff ) OR " .
1647 "( webcal_entry.cal_date >= $startdate AND " .
1648 "webcal_entry.cal_date <= $enddate_minus1 ) )";
1651 $next_day = date ( ( "Ymd" ), mktime ( 3, 0, 0, $sm, $sd + 1, $sy ) );
1653 date ( ( "Ymd" ), mktime ( 3, 0, 0, $em, $ed + 1, $ey ) );
1654 $cutoff = ( 0 - $TZ_OFFSET ) * 10000;
1655 $date_filter = " AND ( ( webcal_entry.cal_date >= $startdate " .
1656 "AND webcal_entry.cal_date <= $enddate AND " .
1657 "webcal_entry.cal_time = -1 ) OR " .
1658 "( webcal_entry.cal_date = $startdate AND " .
1659 "webcal_entry.cal_time > $cutoff ) OR " .
1660 "( webcal_entry.cal_date = $enddate_plus1 AND " .
1661 "webcal_entry.cal_time <= $cutoff ) OR " .
1662 "( webcal_entry.cal_date > $startdate AND " .
1663 "webcal_entry.cal_date < $enddate_plus1 ) )";
1666 return query_events ( $user, false, $date_filter, $cat_id );
1670 * Gets all the events for a specific date.
1672 * Events are retreived from the array of pre-loaded events (which was loaded
1673 * all at once to improve performance).
1675 * The returned events will be sorted by time of day.
1677 * @param string $user Username
1678 * @param string $date Date to get events for in YYYYMMDD format
1679 * @param bool $get_unapproved Load unapproved events?
1681 * @return array Array of events
1683 function get_entries ( $user, $date, $get_unapproved=true ) {
1684 global $events, $TZ_OFFSET;
1688 //echo "<br />\nChecking " . count ( $events ) . " events. TZ_OFFSET = $TZ_OFFSET, get_unapproved=" . $get_unapproved . "<br />\n";
1690 //print_r ( $events );
1692 for ( $i = 0; $i < count ( $events ); $i++ ) {
1693 // In case of data corruption (or some other bug...)
1694 if ( empty ( $events[$i] ) || empty ( $events[$i]['cal_id'] ) )
1696 if ( ( ! $get_unapproved ) && $events[$i]['cal_status'] == 'W' ) {
1697 // ignore this event
1698 //don't adjust anything if no TZ offset or ALL Day Event or Untimed
1699 } else if ( empty ( $TZ_OFFSET) || ( $events[$i]['cal_time'] <= 0 ) ) {
1700 if ( $events[$i]['cal_date'] == $date )
1701 $ret[$n++] = $events[$i];
1702 } else if ( $TZ_OFFSET > 0 ) {
1703 $cutoff = ( 24 - $TZ_OFFSET ) * 10000;
1704 //echo "<br /> cal_time " . $events[$i]['cal_time'] . "<br />\n";
1705 $sy = substr ( $date, 0, 4 );
1706 $sm = substr ( $date, 4, 2 );
1707 $sd = substr ( $date, 6, 2 );
1708 $prev_day = date ( ( "Ymd" ), mktime ( 3, 0, 0, $sm, $sd - 1, $sy ) );
1709 //echo "prev_date = $prev_day <br />\n";
1710 if ( $events[$i]['cal_date'] == $date &&
1711 $events[$i]['cal_time'] == -1 ) {
1712 $ret[$n++] = $events[$i];
1713 //echo "added event $events[$i][cal_id] <br />\n";
1714 } else if ( $events[$i]['cal_date'] == $date &&
1715 $events[$i]['cal_time'] < $cutoff ) {
1716 $ret[$n++] = $events[$i];
1717 //echo "added event {$events[$i][cal_id]} <br />\n";
1718 } else if ( $events[$i]['cal_date'] == $prev_day &&
1719 $events[$i]['cal_time'] >= $cutoff ) {
1720 $ret[$n++] = $events[$i];
1721 //echo "added event {$events[$i][cal_id]} <br />\n";
1725 $cutoff = ( 0 - $TZ_OFFSET ) * 10000;
1726 //echo "<br />\ncal_time " . $events[$i]['cal_time'] . "<br />\n";
1727 $sy = substr ( $date, 0, 4 );
1728 $sm = substr ( $date, 4, 2 );
1729 $sd = substr ( $date, 6, 2 );
1730 $next_day = date ( ( "Ymd" ), mktime ( 3, 0, 0, $sm, $sd + 1, $sy ) );
1731 //echo "next_date = $next_day <br />\n";
1732 if ( $events[$i]['cal_time'] == -1 ) {
1733 if ( $events[$i]['cal_date'] == $date ) {
1734 $ret[$n++] = $events[$i];
1735 //echo "added event $events[$i][cal_id] <br />\n";
1738 if ( $events[$i]['cal_date'] == $date &&
1739 $events[$i]['cal_time'] > $cutoff ) {
1740 $ret[$n++] = $events[$i];
1741 //echo "added event $events[$i][cal_id] <br />\n";
1742 } else if ( $events[$i]['cal_date'] == $next_day &&
1743 $events[$i]['cal_time'] <= $cutoff ) {
1744 $ret[$n++] = $events[$i];
1745 //echo "added event $events[$i][cal_id] <br />\n";
1754 * Reads events visible to a user.
1756 * Includes layers and possibly public access if enabled
1758 * @param string $user Username
1759 * @param bool $want_repeated Get repeating events?
1760 * @param string $date_filter SQL phrase starting with AND, to be appended to
1761 * the WHERE clause. May be empty string.
1762 * @param int $cat_id Category ID to filter on. May be empty.
1764 * @return array Array of events sorted by time of day
1766 function query_events ( $user, $want_repeated, $date_filter, $cat_id = '' ) {
1768 global $layers, $public_access_default_visible;
1770 $layers_byuser = array ();
1772 $sql = "SELECT webcal_entry.cal_name, webcal_entry.cal_description, "
1773 . "webcal_entry.cal_date, webcal_entry.cal_time, "
1774 . "webcal_entry.cal_id, webcal_entry.cal_ext_for_id, "
1775 . "webcal_entry.cal_priority, "
1776 . "webcal_entry.cal_access, webcal_entry.cal_duration, "
1777 . "webcal_entry_user.cal_status, "
1778 . "webcal_entry_user.cal_category, "
1779 . "webcal_entry_user.cal_login ";
1780 if ( $want_repeated ) {
1782 . "webcal_entry_repeats.cal_type, webcal_entry_repeats.cal_end, "
1783 . "webcal_entry_repeats.cal_frequency, webcal_entry_repeats.cal_days "
1784 . "FROM webcal_entry, webcal_entry_repeats, webcal_entry_user "
1785 . "WHERE webcal_entry.cal_id = webcal_entry_repeats.cal_id AND ";
1787 $sql .= "FROM webcal_entry, webcal_entry_user WHERE ";
1789 $sql .= "webcal_entry.cal_id = webcal_entry_user.cal_id " .
1790 "AND webcal_entry_user.cal_status IN ('A','W') ";
1792 if ( $cat_id != '' ) $sql .= "AND webcal_entry_user.cal_category LIKE '$cat_id' ";
1794 if ( strlen ( $user ) > 0 )
1795 $sql .= "AND (webcal_entry_user.cal_login = '" . $user . "' ";
1797 if ( $user == $login && strlen ( $user ) > 0 ) {
1798 if ($layers) foreach ($layers as $layer) {
1799 $layeruser = $layer['cal_layeruser'];
1801 $sql .= "OR webcal_entry_user.cal_login = '" . $layeruser . "' ";
1803 // while we are parsing the whole layers array, build ourselves
1804 // a new array that will help when we have to check for dups
1805 $layers_byuser["$layeruser"] = $layer['cal_dups'];
1808 if ( $user == $login && strlen ( $user ) &&
1809 $public_access_default_visible == 'Y' ) {
1810 $sql .= "OR webcal_entry_user.cal_login = '__public__' ";
1812 if ( strlen ( $user ) > 0 )
1814 $sql .= $date_filter;
1816 // now order the results by time and by entry id.
1817 $sql .= " ORDER BY webcal_entry.cal_time, webcal_entry.cal_id";
1819 //echo "<strong>SQL:</strong> $sql<br />\n";
1821 $res = dbi_query ( $sql );
1825 $first_i_this_id = -1;
1827 while ( $row = dbi_fetch_row ( $res ) ) {
1829 if ($row[9] == 'R' || $row[9] == 'D') {
1830 continue; // don't show rejected/deleted ones
1833 "cal_name" => $row[0],
1834 "cal_description" => $row[1],
1835 "cal_date" => $row[2],
1836 "cal_time" => $row[3],
1837 "cal_id" => $row[4],
1838 "cal_ext_for_id" => $row[5],
1839 "cal_priority" => $row[6],
1840 "cal_access" => $row[7],
1841 "cal_duration" => $row[8],
1842 "cal_status" => $row[9],
1843 "cal_category" => $row[10],
1844 "cal_login" => $row[11],
1845 "cal_exceptions" => array()
1847 if ( $want_repeated && ! empty ( $row[12] ) ) {
1848 $item['cal_type'] = empty ( $row[12] ) ? "" : $row[12];
1849 $item['cal_end'] = empty ( $row[13] ) ? "" : $row[13];
1850 $item['cal_frequency'] = empty ( $row[14] ) ? "" : $row[14];
1851 $item['cal_days'] = empty ( $row[15] ) ? "" : $row[15];
1854 if ( $item['cal_id'] != $checkdup_id ) {
1855 $checkdup_id = $item['cal_id'];
1856 $first_i_this_id = $i;
1859 if ( $item['cal_login'] == $user ) {
1860 // Insert this one before all other ones with this ID.
1861 my_array_splice ( $result, $first_i_this_id, 0, array($item) );
1864 if ($first_i_this_id + 1 < $i) {
1865 // There's another one with the same ID as the one we inserted.
1866 // Check for dup and if so, delete it.
1867 $other_item = $result[$first_i_this_id + 1];
1868 if ($layers_byuser[$other_item['cal_login']] == 'N') {
1869 // NOTE: array_splice requires PHP4
1870 my_array_splice ( $result, $first_i_this_id + 1, 1, "" );
1875 if ($i == $first_i_this_id
1876 || ( ! empty ( $layers_byuser[$item['cal_login']] ) &&
1877 $layers_byuser[$item['cal_login']] != 'N' ) ) {
1878 // This item either is the first one with its ID, or allows dups.
1879 // Add it to the end of the array.
1880 $result [$i++] = $item;
1884 dbi_free_result ( $res );
1887 // Now load event exceptions and store as array in 'cal_exceptions' field
1888 if ( $want_repeated ) {
1889 for ( $i = 0; $i < count ( $result ); $i++ ) {
1890 if ( ! empty ( $result[$i]['cal_id'] ) ) {
1891 $res = dbi_query ( "SELECT cal_date FROM webcal_entry_repeats_not " .
1892 "WHERE cal_id = " . $result[$i]['cal_id'] );
1893 while ( $row = dbi_fetch_row ( $res ) ) {
1894 $result[$i]['cal_exceptions'][] = $row[0];
1904 * Reads all the repeated events for a user.
1906 * This is only called once per page request to improve performance. All the
1907 * events get loaded into the array <var>$repeated_events</var> sorted by time of day (not
1910 * This will load all the repeated events into memory.
1913 * - To get which events repeat on a specific date, use
1914 * {@link get_repeating_entries()}.
1915 * - To get all the dates that one specific event repeats on, call
1916 * {@link get_all_dates()}.
1918 * @param string $user Username
1919 * @param int $cat_id Category ID to filter on (May be empty)
1920 * @param string $date Cutoff date for repeating event endtimes in YYYYMMDD
1921 * format (may be empty)
1923 * @return Array of repeating events sorted by time of day
1925 * @uses query_events
1927 function read_repeated_events ( $user, $cat_id = '', $date = '' ) {
1931 $filter = ($date != '') ? "AND (webcal_entry_repeats.cal_end >= $date OR webcal_entry_repeats.cal_end IS NULL) " : '';
1932 return query_events ( $user, true, $filter, $cat_id );
1936 * Returns all the dates a specific event will fall on accounting for the repeating.
1938 * Any event with no end will be assigned one.
1940 * @param string $date Initial date in raw format
1941 * @param string $rpt_type Repeating type as stored in the database
1942 * @param string $end End date
1943 * @param string $days Days events occurs on (for weekly)
1944 * @param array $ex_dates Array of exception dates for this event in YYYYMMDD format
1945 * @param int $freq Frequency of repetition
1947 * @return array Array of dates (in UNIX time format)
1949 function get_all_dates ( $date, $rpt_type, $end, $days, $ex_days, $freq=1 ) {
1950 global $conflict_repeat_months, $days_per_month, $ldays_per_month;
1952 //echo "get_all_dates ( $date, '$rpt_type', $end, '$days', [array], $freq ) <br>\n";
1953 $currentdate = floor($date/$ONE_DAY)*$ONE_DAY;
1954 $realend = floor($end/$ONE_DAY)*$ONE_DAY;
1955 $dateYmd = date ( "Ymd", $date );
1957 // Check for $conflict_repeat_months months into future for conflicts
1958 $thismonth = substr($dateYmd, 4, 2);
1959 $thisyear = substr($dateYmd, 0, 4);
1960 $thisday = substr($dateYmd, 6, 2);
1961 $thismonth += $conflict_repeat_months;
1962 if ($thismonth > 12) {
1966 $realend = mktime(3,0,0,$thismonth,$thisday,$thisyear);
1970 //do iterative checking here.
1971 //I floored the $realend so I check it against the floored date
1972 if ($rpt_type && $currentdate < $realend) {
1974 if (!$freq) $freq = 1;
1976 if ($rpt_type == 'daily') {
1977 //we do inclusive counting on end dates.
1978 $cdate += $ONE_DAY * $freq;
1979 while ($cdate <= $realend+$ONE_DAY) {
1980 if ( ! is_exception ( $cdate, $ex_days ) )
1982 $cdate += $ONE_DAY * $freq;
1984 } else if ($rpt_type == 'weekly') {
1985 $daysarray = array();
1987 $dow = date("w",$date);
1988 $cdate = $date - ($dow * $ONE_DAY);
1989 for ($i = 0; $i < 7; $i++) {
1990 $isDay = substr($days, $i, 1);
1991 if (strcmp($isDay,"y")==0) {
1992 $daysarray[$r++]=$i * $ONE_DAY;
1995 //we do inclusive counting on end dates.
1996 while ($cdate <= $realend+$ONE_DAY) {
1997 //add all of the days of the week.
1998 for ($j=0; $j<$r;$j++) {
1999 $td = $cdate + $daysarray[$j];
2001 if ( ! is_exception ( $td, $ex_days ) )
2005 //skip to the next week in question.
2006 $cdate += ( $ONE_DAY * 7 ) * $freq;
2008 } else if ($rpt_type == 'monthlyByDay') {
2009 $dow = date('w', $date);
2010 $thismonth = substr($dateYmd, 4, 2);
2011 $thisyear = substr($dateYmd, 0, 4);
2012 $week = floor(date("d", $date)/7);
2014 //dow1 is the weekday that the 1st of the month falls on
2015 $dow1 = date('w',mktime (3,0,0,$thismonth,1,$thisyear));
2017 if ($t < 0) $t += 7;
2018 $day = 7*$week + $t + 1;
2019 $cdate = mktime (3,0,0,$thismonth,$day,$thisyear);
2020 while ($cdate <= $realend+$ONE_DAY) {
2021 if ( ! is_exception ( $cdate, $ex_days ) )
2022 $ret[$n++] = $cdate;
2024 //dow1 is the weekday that the 1st of the month falls on
2025 $dow1time = mktime ( 3, 0, 0, $thismonth, 1, $thisyear );
2026 $dow1 = date ( 'w', $dow1time );
2028 if ($t < 0) $t += 7;
2029 $day = 7*$week + $t + 1;
2030 $cdate = mktime (3,0,0,$thismonth,$day,$thisyear);
2032 } else if ($rpt_type == 'monthlyByDayR') {
2033 // by weekday of month reversed (i.e., last Monday of month)
2034 $dow = date('w', $date);
2035 $thisday = substr($dateYmd, 6, 2);
2036 $thismonth = substr($dateYmd, 4, 2);
2037 $thisyear = substr($dateYmd, 0, 4);
2038 // get number of days in this month
2039 $daysthismonth = $thisyear % 4 == 0 ? $ldays_per_month[$thismonth] :
2040 $days_per_month[$thismonth];
2041 // how many weekdays like this one remain in the month?
2042 // 0=last one, 1=one more after this one, etc.
2043 $whichWeek = floor ( ( $daysthismonth - $thisday ) / 7 );
2044 // find first repeat date
2045 $thismonth += $freq;
2046 if ( $thismonth > 12 ) {
2050 // get weekday for last day of month
2051 $dowLast += date('w',mktime (3,0,0,$thismonth + 1, -1,$thisyear));
2052 if ( $dowLast >= $dow ) {
2053 // last weekday is in last week of this month
2054 $day = $daysthismonth - ( $dowLast - $dow ) -
2057 // last weekday is NOT in last week of this month
2058 $day = $daysthismonth - ( $dowLast - $dow ) -
2059 ( 7 * ( $whichWeek + 1 ) );
2061 $cdate = mktime (3,0,0,$thismonth,$day,$thisyear);
2062 while ($cdate <= $realend+$ONE_DAY) {
2063 if ( ! is_exception ( $cdate, $ex_days ) )
2064 $ret[$n++] = $cdate;
2065 $thismonth += $freq;
2066 if ( $thismonth > 12 ) {
2070 // get weekday for last day of month
2071 $dowLast += date('w',mktime (3,0,0,$thismonth + 1, -1,$thisyear));
2072 if ( $dowLast >= $dow ) {
2073 // last weekday is in last week of this month
2074 $day = $daysthismonth - ( $dowLast - $dow ) -
2077 // last weekday is NOT in last week of this month
2078 $day = $daysthismonth - ( $dowLast - $dow ) -
2079 ( 7 * ( $whichWeek + 1 ) );
2081 $cdate = mktime (3,0,0,$thismonth,$day,$thisyear);
2083 } else if ($rpt_type == 'monthlyByDate') {
2084 $thismonth = substr($dateYmd, 4, 2);
2085 $thisyear = substr($dateYmd, 0, 4);
2086 $thisday = substr($dateYmd, 6, 2);
2087 $hour = date('H',$date);
2088 $minute = date('i',$date);
2090 $thismonth += $freq;
2091 $cdate = mktime (3,0,0,$thismonth,$thisday,$thisyear);
2092 while ($cdate <= $realend+$ONE_DAY) {
2093 if ( ! is_exception ( $cdate, $ex_days ) )
2094 $ret[$n++] = $cdate;
2095 $thismonth += $freq;
2096 $cdate = mktime (3,0,0,$thismonth,$thisday,$thisyear);
2098 } else if ($rpt_type == 'yearly') {
2099 $thismonth = substr($dateYmd, 4, 2);
2100 $thisyear = substr($dateYmd, 0, 4);
2101 $thisday = substr($dateYmd, 6, 2);
2102 $hour = date('H',$date);
2103 $minute = date('i',$date);
2106 $cdate = mktime (3,0,0,$thismonth,$thisday,$thisyear);
2107 while ($cdate <= $realend+$ONE_DAY) {
2108 if ( ! is_exception ( $cdate, $ex_days ) )
2109 $ret[$n++] = $cdate;
2111 $cdate = mktime (3,0,0,$thismonth,$thisday,$thisyear);
2119 * Gets all the repeating events for the specified date.
2122 * The global variable <var>$repeated_events</var> needs to be
2123 * set by calling {@link read_repeated_events()} first.
2125 * @param string $user Username
2126 * @param string $date Date to get events for in YYYYMMDD format
2127 * @param bool $get_unapproved Include unapproved events in results?
2129 * @return mixed The query result resource on queries (which can then be
2130 * passed to {@link dbi_fetch_row()} to obtain the results), or
2131 * true/false on insert or delete queries.
2133 * @global array Array of repeating events retreived using {@link read_repeated_events()}
2135 function get_repeating_entries ( $user, $dateYmd, $get_unapproved=true ) {
2136 global $repeated_events;
2139 //echo count($repeated_events)."<br />\n";
2140 for ( $i = 0; $i < count ( $repeated_events ); $i++ ) {
2141 if ( $repeated_events[$i]['cal_status'] == 'A' || $get_unapproved ) {
2142 if ( repeated_event_matches_date ( $repeated_events[$i], $dateYmd ) ) {
2143 // make sure this is not an exception date...
2144 $unixtime = date_to_epoch ( $dateYmd );
2145 if ( ! is_exception ( $unixtime, $repeated_events[$i]['cal_exceptions'] ) )
2146 $ret[$n++] = $repeated_events[$i];
2154 * Determines whether the event passed in will fall on the date passed.
2156 * @param array $event The event as an array
2157 * @param string $dateYmd Date to check in YYYYMMDD format
2159 * @return bool Does <var>$event</var> occur on <var>$dateYmd</var>?
2161 function repeated_event_matches_date($event,$dateYmd) {
2162 global $days_per_month, $ldays_per_month, $ONE_DAY;
2163 // only repeat after the beginning, and if there is an end
2165 $date = date_to_epoch ( $dateYmd );
2166 $thisyear = substr($dateYmd, 0, 4);
2167 $start = date_to_epoch ( $event['cal_date'] );
2168 $end = date_to_epoch ( $event['cal_end'] );
2169 $freq = $event['cal_frequency'];
2170 $thismonth = substr($dateYmd, 4, 2);
2171 if ($event['cal_end'] && $dateYmd > date("Ymd",$end) )
2173 if ( $dateYmd <= date("Ymd",$start) )
2175 $id = $event['cal_id'];
2177 if ($event['cal_type'] == 'daily') {
2178 if ( (floor(($date - $start)/$ONE_DAY)%$freq) )
2181 } else if ($event['cal_type'] == 'weekly') {
2182 $dow = date("w", $date);
2183 $dow1 = date("w", $start);
2184 $isDay = substr($event['cal_days'], $dow, 1);
2185 $wstart = $start - ($dow1 * $ONE_DAY);
2186 if (floor(($date - $wstart)/604800)%$freq)
2188 return (strcmp($isDay,"y") == 0);
2189 } else if ($event['cal_type'] == 'monthlyByDay') {
2190 $dowS = date("w", $start);
2191 $dow = date("w", $date);
2192 // do this comparison first in hopes of best performance
2193 if ( $dowS != $dow )
2195 $mthS = date("m", $start);
2196 $yrS = date("Y", $start);
2197 $dayS = floor(date("d", $start));
2198 $dowS1 = ( date ( "w", $start - ( $ONE_DAY * ( $dayS - 1 ) ) ) + 35 ) % 7;
2199 $days_in_first_weekS = ( 7 - $dowS1 ) % 7;
2200 $whichWeekS = floor ( ( $dayS - $days_in_first_weekS ) / 7 );
2201 if ( $dowS >= $dowS1 && $days_in_first_weekS )
2203 //echo "dayS=$dayS;dowS=$dowS;dowS1=$dowS1;wWS=$whichWeekS<br />\n";
2204 $mth = date("m", $date);
2205 $yr = date("Y", $date);
2206 $day = date("d", $date);
2207 $dow1 = ( date ( "w", $date - ( $ONE_DAY * ( $day - 1 ) ) ) + 35 ) % 7;
2208 $days_in_first_week = ( 7 - $dow1 ) % 7;
2209 $whichWeek = floor ( ( $day - $days_in_first_week ) / 7 );
2210 if ( $dow >= $dow1 && $days_in_first_week )
2212 //echo "day=$day;dow=$dow;dow1=$dow1;wW=$whichWeek<br />\n";
2214 if ((($yr - $yrS)*12 + $mth - $mthS) % $freq)
2217 return ( $whichWeek == $whichWeekS );
2218 } else if ($event['cal_type'] == 'monthlyByDayR') {
2219 $dowS = date("w", $start);
2220 $dow = date("w", $date);
2221 // do this comparison first in hopes of best performance
2222 if ( $dowS != $dow )
2225 $dayS = ceil(date("d", $start));
2226 $mthS = ceil(date("m", $start));
2227 $yrS = date("Y", $start);
2228 $daysthismonthS = $mthS % 4 == 0 ? $ldays_per_month[$mthS] :
2229 $days_per_month[$mthS];
2230 $whichWeekS = floor ( ( $daysthismonthS - $dayS ) / 7 );
2232 $day = ceil(date("d", $date));
2233 $mth = ceil(date("m", $date));
2234 $yr = date("Y", $date);
2235 $daysthismonth = $mth % 4 == 0 ? $ldays_per_month[$mth] :
2236 $days_per_month[$mth];
2237 $whichWeek = floor ( ( $daysthismonth - $day ) / 7 );
2239 if ((($yr - $yrS)*12 + $mth - $mthS) % $freq)
2242 return ( $whichWeekS == $whichWeek );
2243 } else if ($event['cal_type'] == 'monthlyByDate') {
2244 $mthS = date("m", $start);
2245 $yrS = date("Y", $start);
2247 $mth = date("m", $date);
2248 $yr = date("Y", $date);
2250 if ((($yr - $yrS)*12 + $mth - $mthS) % $freq)
2253 return (date("d", $date) == date("d", $start));
2255 else if ($event['cal_type'] == 'yearly') {
2256 $yrS = date("Y", $start);
2257 $yr = date("Y", $date);
2259 if (($yr - $yrS)%$freq)
2262 return (date("dm", $date) == date("dm", $start));
2264 // unknown repeat type
2271 * Converts a date to a timestamp.
2273 * @param string $d Date in YYYYMMDD format
2275 * @return int Timestamp representing 3:00 (or 4:00 if during Daylight Saving
2276 * Time) in the morning on that day
2278 function date_to_epoch ( $d ) {
2281 $T = mktime ( 3, 0, 0, substr ( $d, 4, 2 ), substr ( $d, 6, 2 ), substr ( $d, 0, 4 ) );
2282 $lt = localtime($T);
2284 return mktime ( 4, 0, 0, substr ( $d, 4, 2 ), substr ( $d, 6, 2 ), substr ( $d, 0, 4 ) );
2291 * Checks if a date is an exception for an event.
2293 * @param string $date Date in YYYYMMDD format
2294 * @param array $exdays Array of dates in YYYYMMDD format
2298 function is_exception ( $date, $ex_days ) {
2299 $size = count ( $ex_days );
2301 $date = date ( "Ymd", $date );
2302 //echo "Exception $date check.. count is $size <br />\n";
2303 while ( $count < $size ) {
2304 //echo "Exception date: $ex_days[$count] <br />\n";
2305 if ( $date == $ex_days[$count++] )
2312 * Gets the Sunday of the week that the specified date is in.
2314 * If the date specified is a Sunday, then that date is returned.
2316 * @param int $year Year
2317 * @param int $month Month (1-12)
2318 * @param int $day Day of the month
2320 * @return int The date (in UNIX timestamp format)
2322 * @see get_monday_before
2324 function get_sunday_before ( $year, $month, $day ) {
2325 $weekday = date ( "w", mktime ( 3, 0, 0, $month, $day, $year ) );
2326 $newdate = mktime ( 3, 0, 0, $month, $day - $weekday, $year );
2331 * Gets the Monday of the week that the specified date is in.
2333 * If the date specified is a Monday, then that date is returned.
2335 * @param int $year Year
2336 * @param int $month Month (1-12)
2337 * @param int $day Day of the month
2339 * @return int The date (in UNIX timestamp format)
2341 * @see get_sunday_before
2343 function get_monday_before ( $year, $month, $day ) {
2344 $weekday = date ( "w", mktime ( 3, 0, 0, $month, $day, $year ) );
2345 if ( $weekday == 0 )
2346 return mktime ( 3, 0, 0, $month, $day - 6, $year );
2347 if ( $weekday == 1 )
2348 return mktime ( 3, 0, 0, $month, $day, $year );
2349 return mktime ( 3, 0, 0, $month, $day - ( $weekday - 1 ), $year );
2353 * Returns the week number for specified date.
2355 * Depends on week numbering settings.
2357 * @param int $date Date in UNIX timestamp format
2359 * @return string The week number of the specified date
2361 function week_number ( $date ) {
2362 $tmp = getdate($date);
2363 $iso = gregorianToISO($tmp['mday'], $tmp['mon'], $tmp['year']);
2364 $parts = explode('-',$iso);
2365 $week_number = intval($parts[1]);
2366 return sprintf("%02d",$week_number);
2370 * Generates the HTML for an add/edit/delete icon.
2372 * This function is not yet used. Some of the places that will call it have to
2373 * be updated to also get the event owner so we know if the current user has
2374 * access to edit and delete.
2376 * @param int $id Event ID
2377 * @param bool $can_edit Can this user edit this event?
2378 * @param bool $can_delete Can this user delete this event?
2380 * @return HTML for add/edit/delete icon.
2384 function icon_text ( $id, $can_edit, $can_delete ) {
2385 global $readonly, $is_admin;
2386 $ret = "<a title=\"" .
2387 translate("View this entry") . "\" href=\"view_entry.php?id=$id\"><img src=\"view.gif\" alt=\"" .
2388 translate("View this entry") . "\" style=\"border-width:0px; width:10px; height:10px;\" /></a>";
2389 if ( $can_edit && $readonly == "N" )
2390 $ret .= "<a title=\"" .
2391 translate("Edit entry") . "\" href=\"edit_entry.php?id=$id\"><img src=\"edit.gif\" alt=\"" .
2392 translate("Edit entry") . "\" style=\"border-width:0px; width:10px; height:10px;\" /></a>";
2393 if ( $can_delete && ( $readonly == "N" || $is_admin ) )
2394 $ret .= "<a title=\"" .
2395 translate("Delete entry") . "\" href=\"del_entry.php?id=$id\" onclick=\"return confirm('" .
2396 translate("Are you sure you want to delete this entry?") . "\\n\\n" .
2397 translate("This will delete this entry for all users.") . "');\"><img src=\"delete.gif\" alt=\"" .
2398 translate("Delete entry") . "\" style=\"border-width:0px; width:10px; height:10px;\" /></a>";
2403 * Prints all the calendar entries for the specified user for the specified date.
2405 * If we are displaying data from someone other than
2406 * the logged in user, then check the access permission of the entry.
2408 * @param string $date Date in YYYYMMDD format
2409 * @param string $user Username
2410 * @param bool $ssi Is this being called from week_ssi.php?
2412 function print_date_entries ( $date, $user, $ssi ) {
2413 global $events, $readonly, $is_admin, $login,
2414 $public_access, $public_access_can_add, $cat_id;
2416 $get_unapproved = ( $GLOBALS["DISPLAY_UNAPPROVED"] == "Y" );
2417 // public access events always must be approved before being displayed
2418 if ( $user == "__public__" )
2419 $get_unapproved = false;
2421 $year = substr ( $date, 0, 4 );
2422 $month = substr ( $date, 4, 2 );
2423 $day = substr ( $date, 6, 2 );
2424 $dateu = mktime ( 3, 0, 0, $month, $day, $year );
2425 $can_add = ( $readonly == "N" || $is_admin );
2426 if ( $public_access == "Y" && $public_access_can_add != "Y" &&
2427 $login == "__public__" )
2429 if ( $readonly == 'Y' )
2431 if ( ! $ssi && $can_add ) {
2432 print "<a title=\"" .
2433 translate("New Entry") . "\" href=\"edit_entry.php?";
2434 if ( strcmp ( $user, $GLOBALS["login"] ) )
2435 print "user=$user&";
2436 if ( ! empty ( $cat_id ) )
2437 print "cat_id=$cat_id&";
2438 print "date=$date\"><img src=\"new.gif\" alt=\"" .
2439 translate("New Entry") . "\" class=\"new\" /></a>";
2443 echo "<a class=\"dayofmonth\" href=\"day.php?";
2444 if ( strcmp ( $user, $GLOBALS["login"] ) )
2445 echo "user=$user&";
2446 if ( ! empty ( $cat_id ) )
2447 echo "cat_id=$cat_id&";
2448 echo "date=$date\">$day</a>";
2449 if ( $GLOBALS["DISPLAY_WEEKNUMBER"] == "Y" &&
2450 date ( "w", $dateu ) == $GLOBALS["WEEK_START"] ) {
2451 echo " <a title=\"" .
2452 translate("Week") . " " . week_number ( $dateu ) . "\" href=\"week.php?date=$date";
2453 if ( strcmp ( $user, $GLOBALS["login"] ) )
2454 echo "&user=$user";
2455 if ( ! empty ( $cat_id ) )
2456 echo "&cat_id=$cat_id";
2457 echo "\" class=\"weeknumber\">";
2459 translate("Week") . " " . week_number ( $dateu ) . ")</a>";
2465 // get all the repeating events for this date and store in array $rep
2466 $rep = get_repeating_entries ( $user, $date, $get_unapproved );
2469 // get all the non-repeating events for this date and store in $ev
2470 $ev = get_entries ( $user, $date, $get_unapproved );
2472 for ( $i = 0; $i < count ( $ev ); $i++ ) {
2473 // print out any repeating events that are before this one...
2474 while ( $cur_rep < count ( $rep ) &&
2475 $rep[$cur_rep]['cal_time'] < $ev[$i]['cal_time'] ) {
2476 if ( $get_unapproved || $rep[$cur_rep]['cal_status'] == 'A' ) {
2477 if ( ! empty ( $rep[$cur_rep]['cal_ext_for_id'] ) ) {
2478 $viewid = $rep[$cur_rep]['cal_ext_for_id'];
2479 $viewname = $rep[$cur_rep]['cal_name'] . " (" .
2480 translate("cont.") . ")";
2482 $viewid = $rep[$cur_rep]['cal_id'];
2483 $viewname = $rep[$cur_rep]['cal_name'];
2485 print_entry ( $viewid,
2486 $date, $rep[$cur_rep]['cal_time'], $rep[$cur_rep]['cal_duration'],
2487 $viewname, $rep[$cur_rep]['cal_description'],
2488 $rep[$cur_rep]['cal_status'], $rep[$cur_rep]['cal_priority'],
2489 $rep[$cur_rep]['cal_access'], $rep[$cur_rep]['cal_login'],
2490 $rep[$cur_rep]['cal_category'] );
2495 if ( $get_unapproved || $ev[$i]['cal_status'] == 'A' ) {
2496 if ( ! empty ( $ev[$i]['cal_ext_for_id'] ) ) {
2497 $viewid = $ev[$i]['cal_ext_for_id'];
2498 $viewname = $ev[$i]['cal_name'] . " (" .
2499 translate("cont.") . ")";
2501 $viewid = $ev[$i]['cal_id'];
2502 $viewname = $ev[$i]['cal_name'];
2504 print_entry ( $viewid,
2505 $date, $ev[$i]['cal_time'], $ev[$i]['cal_duration'],
2506 $viewname, $ev[$i]['cal_description'],
2507 $ev[$i]['cal_status'], $ev[$i]['cal_priority'],
2508 $ev[$i]['cal_access'], $ev[$i]['cal_login'],
2509 $ev[$i]['cal_category'] );
2513 // print out any remaining repeating events
2514 while ( $cur_rep < count ( $rep ) ) {
2515 if ( $get_unapproved || $rep[$cur_rep]['cal_status'] == 'A' ) {
2516 if ( ! empty ( $rep[$cur_rep]['cal_ext_for_id'] ) ) {
2517 $viewid = $rep[$cur_rep]['cal_ext_for_id'];
2518 $viewname = $rep[$cur_rep]['cal_name'] . " (" .
2519 translate("cont.") . ")";
2521 $viewid = $rep[$cur_rep]['cal_id'];
2522 $viewname = $rep[$cur_rep]['cal_name'];
2524 print_entry ( $viewid,
2525 $date, $rep[$cur_rep]['cal_time'], $rep[$cur_rep]['cal_duration'],
2526 $viewname, $rep[$cur_rep]['cal_description'],
2527 $rep[$cur_rep]['cal_status'], $rep[$cur_rep]['cal_priority'],
2528 $rep[$cur_rep]['cal_access'], $rep[$cur_rep]['cal_login'],
2529 $rep[$cur_rep]['cal_category'] );
2535 echo " "; // so the table cell has at least something
2539 * Checks to see if two events overlap.
2541 * @param string $time1 Time 1 in HHMMSS format
2542 * @param int $duration1 Duration 1 in minutes
2543 * @param string $time2 Time 2 in HHMMSS format
2544 * @param int $duration2 Duration 2 in minutes
2546 * @return bool True if the two times overlap, false if they do not
2548 function times_overlap ( $time1, $duration1, $time2, $duration2 ) {
2549 //echo "times_overlap ( $time1, $duration1, $time2, $duration2 )<br />\n";
2550 $hour1 = (int) ( $time1 / 10000 );
2551 $min1 = ( $time1 / 100 ) % 100;
2552 $hour2 = (int) ( $time2 / 10000 );
2553 $min2 = ( $time2 / 100 ) % 100;
2554 // convert to minutes since midnight
2555 // remove 1 minute from duration so 9AM-10AM will not conflict with 10AM-11AM
2556 if ( $duration1 > 0 )
2558 if ( $duration2 > 0 )
2560 $tmins1start = $hour1 * 60 + $min1;
2561 $tmins1end = $tmins1start + $duration1;
2562 $tmins2start = $hour2 * 60 + $min2;
2563 $tmins2end = $tmins2start + $duration2;
2564 //echo "tmins1start=$tmins1start, tmins1end=$tmins1end, tmins2start=$tmins2start, tmins2end=$tmins2end<br />\n";
2565 if ( ( $tmins1start >= $tmins2end ) || ( $tmins2start >= $tmins1end ) )
2571 * Checks for conflicts.
2573 * Find overlaps between an array of dates and the other dates in the database.
2575 * Limits on number of appointments: if enabled in System Settings
2576 * (<var>$limit_appts</var> global variable), too many appointments can also
2577 * generate a scheduling conflict.
2579 * @todo Update this to handle exceptions to repeating events
2581 * @param array $dates Array of dates in YYYYMMDD format that is
2582 * checked for overlaps.
2583 * @param int $duration Event duration in minutes
2584 * @param int $hour Hour of event (0-23)
2585 * @param int $minute Minute of the event (0-59)
2586 * @param array $participants Array of users whose calendars are to be checked
2587 * @param string $login The current user name
2588 * @param int $id Current event id (this keeps overlaps from
2589 * wrongly checking an event against itself)
2591 * @return Empty string for no conflicts or return the HTML of the
2592 * conflicts when one or more are found.
2594 function check_for_conflicts ( $dates, $duration, $hour, $minute,
2595 $participants, $login, $id ) {
2596 global $single_user_login, $single_user;
2597 global $repeated_events, $limit_appts, $limit_appts_number;
2598 if (!count($dates)) return false;
2602 $sql = "SELECT distinct webcal_entry_user.cal_login, webcal_entry.cal_time," .
2603 "webcal_entry.cal_duration, webcal_entry.cal_name, " .
2604 "webcal_entry.cal_id, webcal_entry.cal_ext_for_id, " .
2605 "webcal_entry.cal_access, " .
2606 "webcal_entry_user.cal_status, webcal_entry.cal_date " .
2607 "FROM webcal_entry, webcal_entry_user " .
2608 "WHERE webcal_entry.cal_id = webcal_entry_user.cal_id " .
2610 for ($x = 0; $x < count($dates); $x++) {
2611 if ($x != 0) $sql .= " OR ";
2612 $sql.="webcal_entry.cal_date = " . date ( "Ymd", $dates[$x] );
2614 $sql .= ") AND webcal_entry.cal_time >= 0 " .
2615 "AND webcal_entry_user.cal_status IN ('A','W') AND ( ";
2616 if ( $single_user == "Y" ) {
2617 $participants[0] = $single_user_login;
2618 } else if ( strlen ( $participants[0] ) == 0 ) {
2619 // likely called from a form with 1 user
2620 $participants[0] = $login;
2622 for ( $i = 0; $i < count ( $participants ); $i++ ) {
2625 $sql .= " webcal_entry_user.cal_login = '" . $participants[$i] . "'";
2628 // make sure we don't get something past the end date of the
2629 // event we are saving.
2630 //echo "SQL: $sql<br />\n";
2632 $res = dbi_query ( $sql );
2636 $time1 = sprintf ( "%d%02d00", $hour, $minute );
2637 $duration1 = sprintf ( "%d", $duration );
2638 while ( $row = dbi_fetch_row ( $res ) ) {
2639 //Add to an array to see if it has been found already for the next part.
2640 $found[$count++] = $row[4];
2641 // see if either event overlaps one another
2642 if ( $row[4] != $id && ( empty ( $row[5] ) || $row[5] != $id ) ) {
2644 $duration2 = $row[2];
2645 $cntkey = $row[0] . "-" . $row[8];
2646 if ( empty ( $evtcnt[$cntkey] ) )
2647 $evtcnt[$cntkey] = 0;
2651 if ( $limit_appts == "Y" && $limit_appts_number > 0
2652 && $evtcnt[$cntkey] >= $limit_appts_number ) {
2656 times_overlap ( $time1, $duration1, $time2, $duration2 ) ) {
2657 $conflicts .= "<li>";
2658 if ( $single_user != "Y" )
2659 $conflicts .= "$row[0]: ";
2660 if ( $row[6] == 'R' && $row[0] != $login )
2661 $conflicts .= "(" . translate("Private") . ")";
2663 $conflicts .= "<a href=\"view_entry.php?id=$row[4]";
2664 if ( $row[0] != $login )
2665 $conflicts .= "&user=$row[0]";
2666 $conflicts .= "\">$row[3]</a>";
2668 if ( $duration2 == ( 24 * 60 ) ) {
2669 $conflicts .= " (" . translate("All day event") . ")";
2671 $conflicts .= " (" . display_time ( $time2 );
2672 if ( $duration2 > 0 )
2674 display_time ( add_duration ( $time2, $duration2 ) );
2677 $conflicts .= " on " . date_to_str( $row[8] );
2678 if ( $over_limit ) {
2679 $tmp = translate ( "exceeds limit of XXX events per day" );
2680 $tmp = str_replace ( "XXX", $limit_appts_number, $tmp );
2681 $conflicts .= " (" . $tmp . ")";
2683 $conflicts .= "</li>\n";
2687 dbi_free_result ( $res );
2689 echo translate("Database error") . ": " . dbi_error (); exit;
2692 //echo "<br />\nhello";
2693 for ($q=0;$q<count($participants);$q++) {
2694 $time1 = sprintf ( "%d%02d00", $hour, $minute );
2695 $duration1 = sprintf ( "%d", $duration );
2696 //This date filter is not necessary for functional reasons, but it eliminates some of the
2697 //events that couldn't possibly match. This could be made much more complex to put more
2698 //of the searching work onto the database server, or it could be dropped all together to put
2699 //the searching work onto the client.
2700 $date_filter = "AND (webcal_entry.cal_date <= " . date("Ymd",$dates[count($dates)-1]);
2701 $date_filter .= " AND (webcal_entry_repeats.cal_end IS NULL OR webcal_entry_repeats.cal_end >= " . date("Ymd",$dates[0]) . "))";
2702 //Read repeated events for the participants only once for a participant for
2703 //for performance reasons.
2704 $repeated_events=query_events($participants[$q],true,$date_filter);
2705 //for ($dd=0; $dd<count($repeated_events); $dd++) {
2706 // echo $repeated_events[$dd]['cal_id'] . "<br />";
2708 for ($i=0; $i < count($dates); $i++) {
2709 $dateYmd = date ( "Ymd", $dates[$i] );
2710 $list = get_repeating_entries($participants[$q],$dateYmd);
2711 $thisyear = substr($dateYmd, 0, 4);
2712 $thismonth = substr($dateYmd, 4, 2);
2713 for ($j=0; $j < count($list);$j++) {
2714 //okay we've narrowed it down to a day, now I just gotta check the time...
2715 //I hope this is right...
2717 if ( $row['cal_id'] != $id && ( empty ( $row['cal_ext_for_id'] ) ||
2718 $row['cal_ext_for_id'] != $id ) ) {
2719 $time2 = $row['cal_time'];
2720 $duration2 = $row['cal_duration'];
2721 if ( times_overlap ( $time1, $duration1, $time2, $duration2 ) ) {
2722 $conflicts .= "<li>";
2723 if ( $single_user != "Y" )
2724 $conflicts .= $row['cal_login'] . ": ";
2725 if ( $row['cal_access'] == 'R' && $row['cal_login'] != $login )
2726 $conflicts .= "(" . translate("Private") . ")";
2728 $conflicts .= "<a href=\"view_entry.php?id=" . $row['cal_id'];
2729 if ( ! empty ( $user ) && $user != $login )
2730 $conflicts .= "&user=$user";
2731 $conflicts .= "\">" . $row['cal_name'] . "</a>";
2733 $conflicts .= " (" . display_time ( $time2 );
2734 if ( $duration2 > 0 )
2736 display_time ( add_duration ( $time2, $duration2 ) );
2738 $conflicts .= " on " . date("l, F j, Y", $dates[$i]);
2739 $conflicts .= "</li>\n";
2750 * Converts a time format HHMMSS (like 130000 for 1PM) into number of minutes past midnight.
2752 * @param string $time Input time in HHMMSS format
2754 * @return int The number of minutes since midnight
2756 function time_to_minutes ( $time ) {
2757 $h = (int) ( $time / 10000 );
2758 $m = (int) ( $time / 100 ) % 100;
2759 $num = $h * 60 + $m;
2764 * Calculates which row/slot this time represents.
2766 * This is used in day and week views where hours of the time are separeted
2767 * into different cells in a table.
2769 * <b>Note:</b> the global variable <var>$TIME_SLOTS</var> is used to determine
2770 * how many time slots there are and how many minutes each is. This variable
2771 * is defined user preferences (or defaulted to admin system settings).
2773 * @param string $time Input time in HHMMSS format
2774 * @param bool $round_down Should we change 1100 to 1059?
2775 * (This will make sure a 10AM-100AM appointment just
2776 * shows up in the 10AM slow and not in the 11AM slot
2779 * @return int The time slot index
2781 function calc_time_slot ( $time, $round_down = false ) {
2782 global $TIME_SLOTS, $TZ_OFFSET;
2784 $interval = ( 24 * 60 ) / $TIME_SLOTS;
2785 $mins_since_midnight = time_to_minutes ( $time );
2786 $ret = (int) ( $mins_since_midnight / $interval );
2787 if ( $round_down ) {
2788 if ( $ret * $interval == $mins_since_midnight )
2791 //echo "$mins_since_midnight / $interval = $ret <br />\n";
2792 if ( $ret > $TIME_SLOTS )
2795 //echo "<br />\ncalc_time_slot($time) = $ret <br />\nTIME_SLOTS = $TIME_SLOTS<br />\n";
2800 * Generates the HTML for an icon to add a new event.
2802 * @param string $date Date for new event in YYYYMMDD format
2803 * @param int $hour Hour of day (0-23)
2804 * @param int $minute Minute of the hour (0-59)
2805 * @param string $user Participant to initially select for new event
2807 * @return string The HTML for the add event icon
2809 function html_for_add_icon ( $date=0,$hour="", $minute="", $user="" ) {
2811 global $login, $readonly, $cat_id;
2814 if ( $readonly == 'Y' )
2817 if ( $minute < 0 ) {
2818 $minute = abs($minute);
2821 if ( ! empty ( $user ) && $user != $login )
2822 $u_url = "user=$user&";
2823 if ( isset ( $hour ) && $hour != NULL )
2824 $hour += $TZ_OFFSET;
2825 return "<a title=\"" .
2826 translate("New Entry") . "\" href=\"edit_entry.php?" . $u_url .
2827 "date=$date" . ( isset ( $hour ) && $hour != NULL && $hour >= 0 ? "&hour=$hour" : "" ) .
2828 ( $minute > 0 ? "&minute=$minute" : "" ) .
2829 ( empty ( $user ) ? "" : "&defusers=$user" ) .
2830 ( empty ( $cat_id ) ? "" : "&cat_id=$cat_id" ) .
2831 "\"><img src=\"new.gif\" class=\"new\" alt=\"" .
2832 translate("New Entry") . "\" /></a>\n";
2836 * Generates the HTML for an event to be viewed in the week-at-glance (week.php).
2838 * The HTML will be stored in an array (global variable $hour_arr)
2839 * indexed on the event's starting hour.
2841 * @param int $id Event id
2842 * @param string $date Date of event in YYYYMMDD format
2843 * @param string $time Time of event in HHMM format
2844 * @param string $name Brief description of event
2845 * @param string $description Full description of event
2846 * @param string $status Status of event ('A', 'W')
2847 * @param int $pri Priority of event
2848 * @param string $access Access to event by others ('P', 'R')
2849 * @param int $duration Duration of event in minutes
2850 * @param string $event_owner User who created event
2851 * @param int $event_category Category id for event
2853 function html_for_event_week_at_a_glance ( $id, $date, $time,
2854 $name, $description, $status, $pri, $access, $duration, $event_owner,
2855 $event_category=-1 ) {
2856 global $first_slot, $last_slot, $hour_arr, $rowspan_arr, $rowspan,
2857 $eventinfo, $login, $user;
2859 global $DISPLAY_ICONS, $PHP_SELF, $TIME_SLOTS;
2862 $popupid = "eventinfo-day-$id-$key";
2865 // Figure out which time slot it goes in.
2866 if ( $time >= 0 && $duration != ( 24 * 60 ) ) {
2867 $ind = calc_time_slot ( $time );
2868 if ( $ind < $first_slot )
2870 if ( $ind > $last_slot )
2875 if ( $login != $event_owner && strlen ( $event_owner ) ) {
2876 $class = "layerentry";
2879 if ( $status == "W" ) $class = "unapprovedentry";
2881 // if we are looking at a view, then always use "entry"
2882 if ( strstr ( $PHP_SELF, "view_m.php" ) ||
2883 strstr ( $PHP_SELF, "view_w.php" ) ||
2884 strstr ( $PHP_SELF, "view_v.php" ) ||
2885 strstr ( $PHP_SELF, "view_t.php" ) )
2888 // avoid php warning for undefined array index
2889 if ( empty ( $hour_arr[$ind] ) )
2890 $hour_arr[$ind] = "";
2892 $catIcon = "icons/cat-" . $event_category . ".gif";
2893 if ( $event_category > 0 && file_exists ( $catIcon ) ) {
2894 $hour_arr[$ind] .= "<img src=\"$catIcon\" alt=\"$catIcon\" />";
2897 $hour_arr[$ind] .= "<a title=\"" .
2898 translate("View this entry") . "\" class=\"$class\" href=\"view_entry.php?id=$id&date=$date";
2899 if ( strlen ( $GLOBALS["user"] ) > 0 )
2900 $hour_arr[$ind] .= "&user=" . $GLOBALS["user"];
2901 $hour_arr[$ind] .= "\" onmouseover=\"window.status='" .
2902 translate("View this entry") . "'; show(event, '$popupid'); return true;\" onmouseout=\"hide('$popupid'); return true;\">";
2904 $hour_arr[$ind] .= "<strong>";
2906 if ( $login != $event_owner && strlen ( $event_owner ) ) {
2907 if ($layers) foreach ($layers as $layer) {
2908 if ( $layer['cal_layeruser'] == $event_owner ) {
2910 $hour_arr[$ind] .= "<span style=\"color:" . $layer['cal_color'] . ";\">";
2914 if ( $duration == ( 24 * 60 ) ) {
2915 $timestr = translate("All day event");
2916 } else if ( $time >= 0 ) {
2917 $hour_arr[$ind] .= display_time ( $time ) . "» ";
2918 $timestr = display_time ( $time );
2919 if ( $duration > 0 ) {
2921 $h = (int) ( $time / 10000 );
2922 $m = ( $time / 100 ) % 100;
2925 while ( $m >= 60 ) {
2929 $end_time = sprintf ( "%02d%02d00", $h, $m );
2930 $timestr .= "-" . display_time ( $end_time );
2934 if ( empty ( $rowspan_arr[$ind] ) )
2935 $rowspan_arr[$ind] = 0; // avoid warning below
2936 // which slot is end time in? take one off so we don't
2937 // show 11:00-12:00 as taking up both 11 and 12 slots.
2938 $endind = calc_time_slot ( $end_time, true );
2939 if ( $endind == $ind )
2942 $rowspan = $endind - $ind + 1;
2943 if ( $rowspan > $rowspan_arr[$ind] && $rowspan > 1 )
2944 $rowspan_arr[$ind] = $rowspan;
2949 // avoid php warning of undefined index when using .= below
2950 if ( empty ( $hour_arr[$ind] ) )
2951 $hour_arr[$ind] = "";
2953 if ( $login != $user && $access == 'R' && strlen ( $user ) ) {
2954 $hour_arr[$ind] .= "(" . translate("Private") . ")";
2955 } else if ( $login != $event_owner && $access == 'R' &&
2956 strlen ( $event_owner ) ) {
2957 $hour_arr[$ind] .= "(" . translate("Private") . ")";
2958 } else if ( $login != $event_owner && strlen ( $event_owner ) ) {
2959 $hour_arr[$ind] .= htmlspecialchars ( $name );
2960 if ( ! empty ( $in_span ) )
2961 $hour_arr[$ind] .= "</span>"; //end color span
2963 $hour_arr[$ind] .= htmlspecialchars ( $name );
2966 if ( $pri == 3 ) $hour_arr[$ind] .= "</strong>"; //end font-weight span
2967 $hour_arr[$ind] .= "</a>";
2968 //if ( $DISPLAY_ICONS == "Y" ) {
2969 // $hour_arr[$ind] .= icon_text ( $id, true, true );
2971 $hour_arr[$ind] .= "<br />\n";
2972 if ( $login != $user && $access == 'R' && strlen ( $user ) ) {
2973 $eventinfo .= build_event_popup ( $popupid, $event_owner,
2974 translate("This event is confidential"), "" );
2975 } else if ( $login != $event_owner && $access == 'R' &&
2976 strlen ( $event_owner ) ) {
2977 $eventinfo .= build_event_popup ( $popupid, $event_owner,
2978 translate("This event is confidential"), "" );
2980 $eventinfo .= build_event_popup ( $popupid, $event_owner,
2981 $description, $timestr, site_extras_for_popup ( $id ) );
2986 * Generates the HTML for an event to be viewed in the day-at-glance (day.php).
2988 * The HTML will be stored in an array (global variable $hour_arr)
2989 * indexed on the event's starting hour.
2991 * @param int $id Event id
2992 * @param string $date Date of event in YYYYMMDD format
2993 * @param string $time Time of event in HHMM format
2994 * @param string $name Brief description of event
2995 * @param string $description Full description of event
2996 * @param string $status Status of event ('A', 'W')
2997 * @param int $pri Priority of event
2998 * @param string $access Access to event by others ('P', 'R')
2999 * @param int $duration Duration of event in minutes
3000 * @param string $event_owner User who created event
3001 * @param int $event_category Category id for event
3003 function html_for_event_day_at_a_glance ( $id, $date, $time,
3004 $name, $description, $status, $pri, $access, $duration, $event_owner,
3005 $event_category=-1 ) {
3006 global $first_slot, $last_slot, $hour_arr, $rowspan_arr, $rowspan,
3007 $eventinfo, $login, $user;
3009 global $layers, $PHP_SELF, $TIME_SLOTS, $TZ_OFFSET;
3011 $popupid = "eventinfo-day-$id-$key";
3014 if ( $login != $user && $access == 'R' && strlen ( $user ) )
3015 $eventinfo .= build_event_popup ( $popupid, $event_owner,
3016 translate("This event is confidential"), "" );
3017 else if ( $login != $event_owner && $access == 'R' &&
3018 strlen ( $event_owner ) )
3019 $eventinfo .= build_event_popup ( $popupid, $event_owner,
3020 translate("This event is confidential"), "" );
3022 $eventinfo .= build_event_popup ( $popupid, $event_owner, $description,
3023 "", site_extras_for_popup ( $id ) );
3025 // calculate slot length in minutes
3026 $interval = ( 60 * 24 ) / $TIME_SLOTS;
3028 // If TZ_OFFSET make this event before the start of the day or
3029 // after the end of the day, adjust the time slot accordingly.
3030 if ( $time >= 0 && $duration != ( 24 * 60 ) ) {
3031 if ( $time + ( $TZ_OFFSET * 10000 ) > 240000 )
3033 else if ( $time + ( $TZ_OFFSET * 10000 ) < 0 )
3035 $ind = calc_time_slot ( $time );
3036 if ( $ind < $first_slot )
3038 if ( $ind > $last_slot )
3042 //echo "time = $time <br />\nind = $ind <br />\nfirst_slot = $first_slot<br />\n";
3044 if ( empty ( $hour_arr[$ind] ) )
3045 $hour_arr[$ind] = "";
3047 if ( $login != $event_owner && strlen ( $event_owner ) ) {
3048 $class = "layerentry";
3051 if ( $status == "W" )
3052 $class = "unapprovedentry";
3054 // if we are looking at a view, then always use "entry"
3055 if ( strstr ( $PHP_SELF, "view_m.php" ) ||
3056 strstr ( $PHP_SELF, "view_w.php" ) ||
3057 strstr ( $PHP_SELF, "view_v.php" ) ||
3058 strstr ( $PHP_SELF, "view_t.php" ) )
3061 $catIcon = "icons/cat-" . $event_category . ".gif";
3062 if ( $event_category > 0 && file_exists ( $catIcon ) ) {
3063 $hour_arr[$ind] .= "<img src=\"$catIcon\" alt=\"$catIcon\" />";
3066 $hour_arr[$ind] .= "<a title=\"" .
3067 translate("View this entry") . "\" class=\"$class\" href=\"view_entry.php?id=$id&date=$date";
3068 if ( strlen ( $GLOBALS["user"] ) > 0 )
3069 $hour_arr[$ind] .= "&user=" . $GLOBALS["user"];
3070 $hour_arr[$ind] .= "\" onmouseover=\"window.status='" .
3071 translate("View this entry") . "'; show(event, '$popupid'); return true;\" onmouseout=\"hide('$popupid'); return true;\">";
3072 if ( $pri == 3 ) $hour_arr[$ind] .= "<strong>";
3074 if ( $login != $event_owner && strlen ( $event_owner ) ) {
3075 if ($layers) foreach ($layers as $layer) {
3076 if ( $layer['cal_layeruser'] == $event_owner) {
3078 $hour_arr[$ind] .= "<span style=\"color:" . $layer['cal_color'] . ";\">";
3083 if ( $duration == ( 24 * 60 ) ) {
3084 $hour_arr[$ind] .= "[" . translate("All day event") . "] ";
3085 } else if ( $time >= 0 ) {
3086 $hour_arr[$ind] .= "[" . display_time ( $time );
3087 if ( $duration > 0 ) {
3089 $h = (int) ( $time / 10000 );
3090 $m = ( $time / 100 ) % 100;
3093 while ( $m >= 60 ) {
3097 $end_time = sprintf ( "%02d%02d00", $h, $m );
3098 $hour_arr[$ind] .= "-" . display_time ( $end_time );
3099 // which slot is end time in? take one off so we don't
3100 // show 11:00-12:00 as taking up both 11 and 12 slots.
3101 $endind = calc_time_slot ( $end_time, true );
3102 if ( $endind == $ind )
3105 $rowspan = $endind - $ind + 1;
3106 if ( ! isset ( $rowspan_arr[$ind] ) )
3107 $rowspan_arr[$ind] = 0;
3108 if ( $rowspan > $rowspan_arr[$ind] && $rowspan > 1 )
3109 $rowspan_arr[$ind] = $rowspan;
3111 $hour_arr[$ind] .= "] ";
3113 if ( $login != $user && $access == 'R' && strlen ( $user ) )
3114 $hour_arr[$ind] .= "(" . translate("Private") . ")";
3116 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) )
3117 $hour_arr[$ind] .= "(" . translate("Private") . ")";
3119 if ( $login != $event_owner && strlen ( $event_owner ) )
3121 $hour_arr[$ind] .= htmlspecialchars ( $name );
3122 if ( ! empty ( $in_span ) )
3123 $hour_arr[$ind] .= "</span>"; //end color span
3127 $hour_arr[$ind] .= htmlspecialchars ( $name );
3128 if ( $pri == 3 ) $hour_arr[$ind] .= "</strong>"; //end font-weight span
3130 $hour_arr[$ind] .= "</a>";
3131 if ( $GLOBALS["DISPLAY_DESC_PRINT_DAY"] == "Y" ) {
3132 $hour_arr[$ind] .= "\n<dl class=\"desc\">\n";
3133 $hour_arr[$ind] .= "<dt>" . translate("Description") . ":</dt>\n<dd>";
3134 if ( ! empty ( $GLOBALS['allow_html_description'] ) &&
3135 $GLOBALS['allow_html_description'] == 'Y' ) {
3136 $str = str_replace ( "&", "&", $description );
3137 $str = str_replace ( "&amp;", "&", $str );
3138 // If there is no html found, then go ahead and replace
3139 // the line breaks ("\n") with the html break.
3140 if ( strstr ( $str, "<" ) && strstr ( $str, ">" ) ) {
3141 // found some html...
3142 $hour_arr[$ind] .= $str;
3144 // no html, replace line breaks
3145 $hour_arr[$ind] .= nl2br ( $str );
3148 // html not allowed in description, escape everything
3149 $hour_arr[$ind] .= nl2br ( htmlspecialchars ( $description ) );
3151 $hour_arr[$ind] .= "</dd>\n</dl>\n";
3154 $hour_arr[$ind] .= "<br />\n";
3158 * Prints all the calendar entries for the specified user for the specified date in day-at-a-glance format.
3160 * If we are displaying data from someone other than
3161 * the logged in user, then check the access permission of the entry.
3163 * @param string $date Date in YYYYMMDD format
3164 * @param string $user Username of calendar
3166 function print_day_at_a_glance ( $date, $user, $can_add=0 ) {
3167 global $first_slot, $last_slot, $hour_arr, $rowspan_arr, $rowspan;
3168 global $TABLEBG, $CELLBG, $TODAYCELLBG, $THFG, $THBG, $TIME_SLOTS, $TZ_OFFSET;
3169 global $WORK_DAY_START_HOUR, $WORK_DAY_END_HOUR;
3170 global $repeated_events;
3171 $get_unapproved = ( $GLOBALS["DISPLAY_UNAPPROVED"] == "Y" );
3172 if ( $user == "__public__" )
3173 $get_unapproved = false;
3174 if ( empty ( $TIME_SLOTS ) ) {
3175 echo "Error: TIME_SLOTS undefined!<br />\n";
3179 // $interval is number of minutes per slot
3180 $interval = ( 24 * 60 ) / $TIME_SLOTS;
3182 $rowspan_arr = array ();
3183 for ( $i = 0; $i < $TIME_SLOTS; $i++ ) {
3184 $rowspan_arr[$i] = 0;
3187 // get all the repeating events for this date and store in array $rep
3188 $rep = get_repeating_entries ( $user, $date );
3191 // Get static non-repeating events
3192 $ev = get_entries ( $user, $date, $get_unapproved );
3193 $hour_arr = array ();
3194 $interval = ( 24 * 60 ) / $TIME_SLOTS;
3195 $first_slot = (int) ( ( ( $WORK_DAY_START_HOUR - $TZ_OFFSET ) * 60 ) / $interval );
3196 $last_slot = (int) ( ( ( $WORK_DAY_END_HOUR - $TZ_OFFSET ) * 60 ) / $interval);
3197 //echo "first_slot = $first_slot<br />\nlast_slot = $last_slot<br />\ninterval = $interval<br />\nTIME_SLOTS = $TIME_SLOTS<br />\n";
3198 $rowspan_arr = array ();
3200 for ( $i = 0; $i < count ( $ev ); $i++ ) {
3201 // print out any repeating events that are before this one...
3202 while ( $cur_rep < count ( $rep ) &&
3203 $rep[$cur_rep]['cal_time'] < $ev[$i]['cal_time'] ) {
3204 if ( $get_unapproved || $rep[$cur_rep]['cal_status'] == 'A' ) {
3205 if ( ! empty ( $rep[$cur_rep]['cal_ext_for_id'] ) ) {
3206 $viewid = $rep[$cur_rep]['cal_ext_for_id'];
3207 $viewname = $rep[$cur_rep]['cal_name'] . " (" .
3208 translate("cont.") . ")";
3210 $viewid = $rep[$cur_rep]['cal_id'];
3211 $viewname = $rep[$cur_rep]['cal_name'];
3213 if ( $rep[$cur_rep]['cal_duration'] == ( 24 * 60 ) )
3215 html_for_event_day_at_a_glance ( $viewid,
3216 $date, $rep[$cur_rep]['cal_time'],
3217 $viewname, $rep[$cur_rep]['cal_description'],
3218 $rep[$cur_rep]['cal_status'], $rep[$cur_rep]['cal_priority'],
3219 $rep[$cur_rep]['cal_access'], $rep[$cur_rep]['cal_duration'],
3220 $rep[$cur_rep]['cal_login'], $rep[$cur_rep]['cal_category'] );
3224 if ( $get_unapproved || $ev[$i]['cal_status'] == 'A' ) {
3225 if ( ! empty ( $ev[$i]['cal_ext_for_id'] ) ) {
3226 $viewid = $ev[$i]['cal_ext_for_id'];
3227 $viewname = $ev[$i]['cal_name'] . " (" .
3228 translate("cont.") . ")";
3230 $viewid = $ev[$i]['cal_id'];
3231 $viewname = $ev[$i]['cal_name'];
3233 if ( $ev[$i]['cal_duration'] == ( 24 * 60 ) )
3235 html_for_event_day_at_a_glance ( $viewid,
3236 $date, $ev[$i]['cal_time'],
3237 $viewname, $ev[$i]['cal_description'],
3238 $ev[$i]['cal_status'], $ev[$i]['cal_priority'],
3239 $ev[$i]['cal_access'], $ev[$i]['cal_duration'],
3240 $ev[$i]['cal_login'], $ev[$i]['cal_category'] );
3243 // print out any remaining repeating events
3244 while ( $cur_rep < count ( $rep ) ) {
3245 if ( $get_unapproved || $rep[$cur_rep]['cal_status'] == 'A' ) {
3246 if ( ! empty ( $rep[$cur_rep]['cal_ext_for_id'] ) ) {
3247 $viewid = $rep[$cur_rep]['cal_ext_for_id'];
3248 $viewname = $rep[$cur_rep]['cal_name'] . " (" .
3249 translate("cont.") . ")";
3251 $viewid = $rep[$cur_rep]['cal_id'];
3252 $viewname = $rep[$cur_rep]['cal_name'];
3254 if ( $rep[$cur_rep]['cal_duration'] == ( 24 * 60 ) )
3256 html_for_event_day_at_a_glance ( $viewid,
3257 $date, $rep[$cur_rep]['cal_time'],
3258 $viewname, $rep[$cur_rep]['cal_description'],
3259 $rep[$cur_rep]['cal_status'], $rep[$cur_rep]['cal_priority'],
3260 $rep[$cur_rep]['cal_access'], $rep[$cur_rep]['cal_duration'],
3261 $rep[$cur_rep]['cal_login'], $rep[$cur_rep]['cal_category'] );
3266 // squish events that use the same cell into the same cell.
3267 // For example, an event from 8:00-9:15 and another from 9:30-9:45 both
3268 // want to show up in the 8:00-9:59 cell.
3271 //echo "First SLot: $first_slot; Last Slot: $last_slot<br />\n";
3273 if ( $first_slot < 0 )
3275 for ( ; $i < $TIME_SLOTS; $i++ ) {
3276 if ( $rowspan > 1 ) {
3277 if ( ! empty ( $hour_arr[$i] ) ) {
3278 $diff_start_time = $i - $last_row;
3279 if ( $rowspan_arr[$i] > 1 ) {
3280 if ( $rowspan_arr[$i] + ( $diff_start_time ) > $rowspan_arr[$last_row] ) {
3281 $rowspan_arr[$last_row] = ( $rowspan_arr[$i] + ( $diff_start_time ) );
3283 $rowspan += ( $rowspan_arr[$i] - 1 );
3285 $rowspan_arr[$last_row] += $rowspan_arr[$i];
3287 // this will move entries apart that appear in one field,
3288 // yet start on different hours
3289 for ( $u = $diff_start_time ; $u > 0 ; $u-- ) {
3290 $hour_arr[$last_row] .= "<br />\n";
3292 $hour_arr[$last_row] .= $hour_arr[$i];
3294 $rowspan_arr[$i] = 0;
3297 } else if ( ! empty ( $rowspan_arr[$i] ) && $rowspan_arr[$i] > 1 ) {
3298 $rowspan = $rowspan_arr[$i];
3302 if ( ! empty ( $hour_arr[9999] ) ) {
3303 echo "<tr><th class=\"empty\"> </th>\n" .
3304 "<td class=\"hasevents\">$hour_arr[9999]</td></tr>\n";
3307 //echo "first_slot = $first_slot<br />\nlast_slot = $last_slot<br />\ninterval = $interval<br />\n";
3308 for ( $i = $first_slot; $i <= $last_slot; $i++ ) {
3309 $time_h = (int) ( ( $i * $interval ) / 60 );
3310 $time_m = ( $i * $interval ) % 60;
3311 $time = display_time ( ( $time_h * 100 + $time_m ) * 100 );
3312 echo "<tr>\n<th class=\"row\">" . $time . "</th>\n";
3313 if ( $rowspan > 1 ) {
3314 // this might mean there's an overlap, or it could mean one event
3315 // ends at 11:15 and another starts at 11:30.
3316 if ( ! empty ( $hour_arr[$i] ) ) {
3317 echo "<td class=\"hasevents\">";
3319 echo html_for_add_icon ( $date, $time_h, $time_m, $user );
3320 echo "$hour_arr[$i]</td>\n";
3324 if ( empty ( $hour_arr[$i] ) ) {
3327 echo html_for_add_icon ( $date, $time_h, $time_m, $user ) . "</td>";
3333 if ( empty ( $rowspan_arr[$i] ) )
3336 $rowspan = $rowspan_arr[$i];
3337 if ( $rowspan > 1 ) {
3338 echo "<td rowspan=\"$rowspan\" class=\"hasevents\">";
3340 echo html_for_add_icon ( $date, $time_h, $time_m, $user );
3341 echo "$hour_arr[$i]</td></tr>\n";
3343 echo "<td class=\"hasevents\">";
3345 echo html_for_add_icon ( $date, $time_h, $time_m, $user );
3346 echo "$hour_arr[$i]</td></tr>\n";
3354 * Checks for any unnaproved events.
3356 * If any are found, display a link to the unapproved events (where they can be
3359 * If the user is an admin user, also count up any public events.
3360 * If the user is a nonuser admin, count up events on the nonuser calendar.
3362 * @param string $user Current user login
3364 function display_unapproved_events ( $user ) {
3365 global $public_access, $is_admin, $nonuser_enabled, $login;
3367 // Don't do this for public access login, admin user must approve public
3369 if ( $user == "__public__" )
3372 $sql = "SELECT COUNT(webcal_entry_user.cal_id) " .
3373 "FROM webcal_entry_user, webcal_entry " .
3374 "WHERE webcal_entry_user.cal_id = webcal_entry.cal_id " .
3375 "AND webcal_entry_user.cal_status = 'W' " .
3376 "AND ( webcal_entry.cal_ext_for_id IS NULL " .
3377 "OR webcal_entry.cal_ext_for_id = 0 ) " .
3378 "AND ( webcal_entry_user.cal_login = '$user'";
3379 if ( $public_access == "Y" && $is_admin ) {
3380 $sql .= " OR webcal_entry_user.cal_login = '__public__'";
3382 if ( $nonuser_enabled == 'Y' ) {
3383 $admincals = get_nonuser_cals ( $login );
3384 for ( $i = 0; $i < count ( $admincals ); $i++ ) {
3385 $sql .= " OR webcal_entry_user.cal_login = '" .
3386 $admincals[$i]['cal_login'] . "'";
3390 //print "SQL: $sql<br />\n";
3391 $res = dbi_query ( $sql );
3393 if ( $row = dbi_fetch_row ( $res ) ) {
3394 if ( $row[0] > 0 ) {
3395 $str = translate ("You have XXX unapproved events");
3396 $str = str_replace ( "XXX", $row[0], $str );
3397 echo "<a class=\"nav\" href=\"list_unapproved.php";
3398 if ( $user != $login )
3399 echo "?user=$user\"";
3400 echo "\">" . $str . "</a><br />\n";
3403 dbi_free_result ( $res );
3408 * Looks for URLs in the given text, and makes them into links.
3410 * @param string $text Input text
3412 * @return string The text altered to have HTML links for any web links
3415 function activate_urls ( $text ) {
3416 $str = eregi_replace ( "(http://[^[:space:]$]+)",
3417 "<a href=\"\\1\">\\1</a>", $text );
3418 $str = eregi_replace ( "(https://[^[:space:]$]+)",
3419 "<a href=\"\\1\">\\1</a>", $str );
3424 * Displays a time in either 12 or 24 hour format.
3426 * The global variable $TZ_OFFSET is used to adjust the time. Note that this
3427 * is somewhat of a kludge for timezone support. If an event is set for 11PM
3428 * server time and the user is 2 hours ahead, it will show up as 1AM, but the
3429 * date will not be adjusted to the next day.
3431 * @param string $time Input time in HHMMSS format
3432 * @param bool $ignore_offset If true, then do not use the timezone offset
3434 * @return string The time in the user's timezone and preferred format
3436 * @global int The user's timezone offset from the server
3438 function display_time ( $time, $ignore_offset=0 ) {
3440 $hour = (int) ( $time / 10000 );
3441 if ( ! $ignore_offset )
3442 $hour += $TZ_OFFSET;
3443 $min = abs( ( $time / 100 ) % 100 );
3444 //Prevent goofy times like 8:00 9:30 9:00 10:30 10:00
3445 if ( $time < 0 && $min > 0 ) $hour = $hour - 1;
3448 while ( $hour > 23 )
3450 if ( $GLOBALS["TIME_FORMAT"] == "12" ) {
3451 $ampm = ( $hour >= 12 ) ? translate("pm") : translate("am");
3455 $ret = sprintf ( "%d:%02d%s", $hour, $min, $ampm );
3457 $ret = sprintf ( "%d:%02d", $hour, $min );
3463 * Returns the full name of the specified month.
3465 * Use {@link month_short_name()} to get the abbreviated name of the month.
3467 * @param int $m Number of the month (0-11)
3469 * @return string The full name of the specified month
3471 * @see month_short_name
3473 function month_name ( $m ) {
3475 case 0: return translate("January");
3476 case 1: return translate("February");
3477 case 2: return translate("March");
3478 case 3: return translate("April");
3479 case 4: return translate("May_"); // needs to be different than "May"
3480 case 5: return translate("June");
3481 case 6: return translate("July");
3482 case 7: return translate("August");
3483 case 8: return translate("September");
3484 case 9: return translate("October");
3485 case 10: return translate("November");
3486 case 11: return translate("December");
3488 return "unknown-month($m)";
3492 * Returns the abbreviated name of the specified month (such as "Jan").
3494 * Use {@link month_name()} to get the full name of the month.
3496 * @param int $m Number of the month (0-11)
3498 * @return string The abbreviated name of the specified month (example: "Jan")
3502 function month_short_name ( $m ) {
3504 case 0: return translate("Jan");
3505 case 1: return translate("Feb");
3506 case 2: return translate("Mar");
3507 case 3: return translate("Apr");
3508 case 4: return translate("May");
3509 case 5: return translate("Jun");
3510 case 6: return translate("Jul");
3511 case 7: return translate("Aug");
3512 case 8: return translate("Sep");
3513 case 9: return translate("Oct");
3514 case 10: return translate("Nov");
3515 case 11: return translate("Dec");
3517 return "unknown-month($m)";
3521 * Returns the full weekday name.
3523 * Use {@link weekday_short_name()} to get the abbreviated weekday name.
3525 * @param int $w Number of the day in the week (0=Sunday,...,6=Saturday)
3527 * @return string The full weekday name ("Sunday")
3529 * @see weekday_short_name
3531 function weekday_name ( $w ) {
3533 case 0: return translate("Sunday");
3534 case 1: return translate("Monday");
3535 case 2: return translate("Tuesday");
3536 case 3: return translate("Wednesday");
3537 case 4: return translate("Thursday");
3538 case 5: return translate("Friday");
3539 case 6: return translate("Saturday");
3541 return "unknown-weekday($w)";
3545 * Returns the abbreviated weekday name.
3547 * Use {@link weekday_name()} to get the full weekday name.
3549 * @param int $w Number of the day in the week (0=Sunday,...,6=Saturday)
3551 * @return string The abbreviated weekday name ("Sun")
3553 function weekday_short_name ( $w ) {
3555 case 0: return translate("Sun");
3556 case 1: return translate("Mon");
3557 case 2: return translate("Tue");
3558 case 3: return translate("Wed");
3559 case 4: return translate("Thu");
3560 case 5: return translate("Fri");
3561 case 6: return translate("Sat");
3563 return "unknown-weekday($w)";
3567 * Converts a date in YYYYMMDD format into "Friday, December 31, 1999",
3568 * "Friday, 12-31-1999" or whatever format the user prefers.
3570 * @param string $indate Date in YYYYMMDD format
3571 * @param string $format Format to use for date (default is "__month__
3572 * __dd__, __yyyy__")
3573 * @param bool $show_weekday Should the day of week also be included?
3574 * @param bool $short_months Should the abbreviated month names be used
3575 * instead of the full month names?
3576 * @param int $server_time ???
3578 * @return string Date in the specified format
3580 * @global string Preferred date format
3581 * @global int User's timezone offset from the server
3583 function date_to_str ( $indate, $format="", $show_weekday=true, $short_months=false, $server_time="" ) {
3584 global $DATE_FORMAT, $TZ_OFFSET;
3586 if ( strlen ( $indate ) == 0 ) {
3587 $indate = date ( "Ymd" );
3591 if ( $server_time != "" && $server_time >= 0 ) {
3592 $y = substr ( $indate, 0, 4 );
3593 $m = substr ( $indate, 4, 2 );
3594 $d = substr ( $indate, 6, 2 );
3595 if ( $server_time + $TZ_OFFSET * 10000 > 240000 ) {
3596 $newdate = date ( "Ymd", mktime ( 3, 0, 0, $m, $d + 1, $y ) );
3597 } else if ( $server_time + $TZ_OFFSET * 10000 < 0 ) {
3598 $newdate = date ( "Ymd", mktime ( 3, 0, 0, $m, $d - 1, $y ) );
3602 // if they have not set a preference yet...
3603 if ( $DATE_FORMAT == "" )
3604 $DATE_FORMAT = "__month__ __dd__, __yyyy__";
3606 if ( empty ( $format ) )
3607 $format = $DATE_FORMAT;
3609 $y = (int) ( $newdate / 10000 );
3610 $m = (int) ( $newdate / 100 ) % 100;
3611 $d = $newdate % 100;
3612 $date = mktime ( 3, 0, 0, $m, $d, $y );
3613 $wday = strftime ( "%w", $date );
3615 if ( $short_months ) {
3616 $weekday = weekday_short_name ( $wday );
3617 $month = month_short_name ( $m - 1 );
3619 $weekday = weekday_name ( $wday );
3620 $month = month_name ( $m - 1 );
3623 $yy = sprintf ( "%02d", $y %= 100 );
3626 $ret = str_replace ( "__yyyy__", $yyyy, $ret );
3627 $ret = str_replace ( "__yy__", $yy, $ret );
3628 $ret = str_replace ( "__month__", $month, $ret );
3629 $ret = str_replace ( "__mon__", $month, $ret );
3630 $ret = str_replace ( "__dd__", $d, $ret );
3631 $ret = str_replace ( "__mm__", $m, $ret );
3633 if ( $show_weekday )
3634 return "$weekday, $ret";
3641 * Converts a hexadecimal digit to an integer.
3643 * @param string $val Hexadecimal digit
3645 * @return int Equivalent integer in base-10
3649 function hextoint ( $val ) {
3650 if ( empty ( $val ) )
3652 switch ( strtoupper ( $val ) ) {
3663 case "A": return 10;
3664 case "B": return 11;
3665 case "C": return 12;
3666 case "D": return 13;
3667 case "E": return 14;
3668 case "F": return 15;
3674 * Extracts a user's name from a session id.
3676 * This prevents users from begin able to edit their cookies.txt file and set
3677 * the username in plain text.
3679 * @param string $instr A hex-encoded string. "Hello" would be "678ea786a5".
3681 * @return string The decoded string
3683 * @global array Array of offsets
3685 * @see encode_string
3687 function decode_string ( $instr ) {
3689 //echo "<br />\nDECODE<br />\n";
3691 for ( $i = 0; $i < strlen ( $instr ); $i += 2 ) {
3693 $ch1 = substr ( $instr, $i, 1 );
3694 $ch2 = substr ( $instr, $i + 1, 1 );
3695 $val = hextoint ( $ch1 ) * 16 + hextoint ( $ch2 );
3696 //echo "decoding \"" . $ch1 . $ch2 . "\" = $val<br />\n";
3697 $j = ( $i / 2 ) % count ( $offsets );
3698 //echo "Using offsets $j = " . $offsets[$j] . "<br />\n";
3699 $newval = $val - $offsets[$j] + 256;
3701 //echo " neval \"$newval\"<br />\n";
3702 $dec_ch = chr ( $newval );
3703 //echo " which is \"$dec_ch\"<br />\n";
3706 //echo "Decode string: '$orig' <br/>\n";
3711 * Takes an input string and encode it into a slightly encoded hexval that we
3712 * can use as a session cookie.
3714 * @param string $instr Text to encode
3716 * @return string The encoded text
3718 * @global array Array of offsets
3720 * @see decode_string
3722 function encode_string ( $instr ) {
3724 //echo "<br />\nENCODE<br />\n";
3726 for ( $i = 0; $i < strlen ( $instr ); $i++ ) {
3728 $ch1 = substr ( $instr, $i, 1 );
3729 $val = ord ( $ch1 );
3730 //echo "val = $val for \"$ch1\"<br />\n";
3731 $j = $i % count ( $offsets );
3732 //echo "Using offsets $j = $offsets[$j]<br />\n";
3733 $newval = $val + $offsets[$j];
3735 //echo "newval = $newval for \"$ch1\"<br />\n";
3736 $ret .= bin2hex ( chr ( $newval ) );
3742 * An implementatin of array_splice() for PHP3.
3744 * @param array $input Array to be spliced into
3745 * @param int $offset Where to begin the splice
3746 * @param int $length How long the splice should be
3747 * @param array $replacement What to splice in
3751 function my_array_splice(&$input,$offset,$length,$replacement) {
3752 if ( floor(phpversion()) < 4 ) {
3753 // if offset is negative, then it starts at the end of array
3755 $offset = count($input) + $offset;
3757 for ($i=0;$i<$offset;$i++) {
3758 $new_array[] = $input[$i];
3761 // if we have a replacement, insert it
3762 for ($i=0;$i<count($replacement);$i++) {
3763 $new_array[] = $replacement[$i];
3766 // now tack on the rest of the original array
3767 for ($i=$offset+$length;$i<count($input);$i++) {
3768 $new_array[] = $input[$i];
3771 $input = $new_array;
3773 array_splice($input,$offset,$length,$replacement);
3778 * Loads current user's category info and stuff it into category global
3781 * @param string $ex_global Don't include global categories ('' or '1')
3783 function load_user_categories ($ex_global = '') {
3784 global $login, $user, $is_assistant;
3785 global $categories, $category_owners;
3786 global $categories_enabled, $is_admin;
3788 $cat_owner = ( ( ! empty ( $user ) && strlen ( $user ) ) && ( $is_assistant ||
3789 $is_admin ) ) ? $user : $login;
3790 $categories = array ();
3791 $category_owners = array ();
3792 if ( $categories_enabled == "Y" ) {
3793 $sql = "SELECT cat_id, cat_name, cat_owner FROM webcal_categories WHERE ";
3794 $sql .= ($ex_global == '') ? " (cat_owner = '$cat_owner') OR (cat_owner IS NULL) ORDER BY cat_owner, cat_name" : " cat_owner = '$cat_owner' ORDER BY cat_name";
3796 $res = dbi_query ( $sql );
3798 while ( $row = dbi_fetch_row ( $res ) ) {
3800 $categories[$cat_id] = $row[1];
3801 $category_owners[$cat_id] = $row[2];
3803 dbi_free_result ( $res );
3806 //echo "Categories disabled.";
3811 * Prints dropdown HTML for categories.
3813 * @param string $form The page to submit data to (without .php)
3814 * @param string $date Date in YYYYMMDD format
3815 * @param int $cat_id Category id that should be pre-selected
3817 function print_category_menu ( $form, $date = '', $cat_id = '' ) {
3818 global $categories, $category_owners, $user, $login;
3819 echo "<form action=\"{$form}.php\" method=\"get\" name=\"SelectCategory\" class=\"categories\">\n";
3820 if ( ! empty($date) ) echo "<input type=\"hidden\" name=\"date\" value=\"$date\" />\n";
3821 if ( ! empty ( $user ) && $user != $login )
3822 echo "<input type=\"hidden\" name=\"user\" value=\"$user\" />\n";
3823 echo translate ("Category") . ": <select name=\"cat_id\" onchange=\"document.SelectCategory.submit()\">\n";
3824 echo "<option value=\"\"";
3825 if ( $cat_id == '' ) echo " selected=\"selected\"";
3826 echo ">" . translate("All") . "</option>\n";
3827 $cat_owner = ( ! empty ( $user ) && strlen ( $user ) ) ? $user : $login;
3828 if ( is_array ( $categories ) ) {
3829 foreach ( $categories as $K => $V ){
3831 empty ( $category_owners[$K] ) ) {
3832 echo "<option value=\"$K\"";
3833 if ( $cat_id == $K ) echo " selected=\"selected\"";
3834 echo ">$V</option>\n";
3840 echo "<span id=\"cat\">" . translate ("Category") . ": ";
3841 echo ( strlen ( $cat_id ) ? $categories[$cat_id] : translate ('All') ) . "</span>\n";
3845 * Converts HTML entities in 8bit.
3847 * <b>Note:</b> Only supported for PHP4 (not PHP3).
3849 * @param string $html HTML text
3851 * @return string The converted text
3853 function html_to_8bits ( $html ) {
3854 if ( floor(phpversion()) < 4 ) {
3857 return strtr ( $html, array_flip (
3858 get_html_translation_table (HTML_ENTITIES) ) );
3862 // ***********************************************************************
3863 // Functions for getting information about boss and their assistant.
3864 // ***********************************************************************
3867 * Gets a list of an assistant's boss from the webcal_asst table.
3869 * @param string $assistant Login of assistant
3871 * @return array Array of bosses, where each boss is an array with the following
3873 * - <var>cal_login</var>
3874 * - <var>cal_fullname</var>
3876 function user_get_boss_list ( $assistant ) {
3877 global $bosstemp_fullname;
3880 "SELECT cal_boss " .
3881 "FROM webcal_asst " .
3882 "WHERE cal_assistant = '$assistant'" );
3886 while ( $row = dbi_fetch_row ( $res ) ) {
3887 user_load_variables ( $row[0], "bosstemp_" );
3888 $ret[$count++] = array (
3889 "cal_login" => $row[0],
3890 "cal_fullname" => $bosstemp_fullname
3893 dbi_free_result ( $res );
3899 * Is this user an assistant of this boss?
3901 * @param string $assistant Login of potential assistant
3902 * @param string $boss Login of potential boss
3904 * @return bool True or false
3906 function user_is_assistant ( $assistant, $boss ) {
3909 if ( empty ( $boss ) )
3911 $res = dbi_query ( "SELECT * FROM webcal_asst " .
3912 "WHERE cal_assistant = '$assistant' AND cal_boss = '$boss'" );
3914 if ( dbi_fetch_row ( $res ) )
3916 dbi_free_result ( $res );
3922 * Is this user an assistant?
3924 * @param string $assistant Login for user
3926 * @return bool true if the user is an assistant to one or more bosses
3928 function user_has_boss ( $assistant ) {
3930 $res = dbi_query ( "SELECT * FROM webcal_asst " .
3931 "WHERE cal_assistant = '$assistant'" );
3933 if ( dbi_fetch_row ( $res ) )
3935 dbi_free_result ( $res );
3941 * Checks the boss user preferences to see if the boss wants to be notified via
3942 * email on changes to their calendar.
3944 * @param string $assistant Assistant login
3945 * @param string $boss Boss login
3947 * @return bool True if the boss wants email notifications
3949 function boss_must_be_notified ( $assistant, $boss ) {
3950 if (user_is_assistant ( $assistant, $boss ) )
3951 return ( get_pref_setting ( $boss, "EMAIL_ASSISTANT_EVENTS" )=="Y" ? true : false );
3956 * Checks the boss user preferences to see if the boss must approve events
3957 * added to their calendar.
3959 * @param string $assistant Assistant login
3960 * @param string $boss Boss login
3962 * @return bool True if the boss must approve new events
3964 function boss_must_approve_event ( $assistant, $boss ) {
3965 if (user_is_assistant ( $assistant, $boss ) )
3966 return ( get_pref_setting ( $boss, "APPROVE_ASSISTANT_EVENT" )=="Y" ? true : false );
3971 * Fakes an email for testing purposes.
3973 * @param string $mailto Email address to send mail to
3974 * @param string $subj Subject of email
3975 * @param string $text Email body
3976 * @param string $hdrs Other email headers
3980 function fake_mail ( $mailto, $subj, $text, $hdrs ) {
3981 echo "To: $mailto <br />\n" .
3982 "Subject: $subj <br />\n" .
3983 nl2br ( $hdrs ) . "<br />\n" .
3988 * Prints all the entries in a time bar format for the specified user for the
3991 * If we are displaying data from someone other than the logged in user, then
3992 * check the access permission of the entry.
3994 * @param string $date Date in YYYYMMDD format
3995 * @param string $user Username
3996 * @param bool $ssi Should we not include links to add new events?
3998 function print_date_entries_timebar ( $date, $user, $ssi ) {
3999 global $events, $readonly, $is_admin,
4000 $public_access, $public_access_can_add;
4002 $get_unapproved = ( $GLOBALS["DISPLAY_UNAPPROVED"] == "Y" );
4003 // public access events always must be approved before being displayed
4004 if ( $GLOBALS["login"] == "__public__" )
4005 $get_unapproved = false;
4007 $year = substr ( $date, 0, 4 );
4008 $month = substr ( $date, 4, 2 );
4009 $day = substr ( $date, 6, 2 );
4011 $dateu = mktime ( 3, 0, 0, $month, $day, $year );
4013 $can_add = ( $readonly == "N" || $is_admin );
4014 if ( $public_access == "Y" && $public_access_can_add != "Y" &&
4015 $GLOBALS["login"] == "__public__" )
4018 // get all the repeating events for this date and store in array $rep
4019 $rep = get_repeating_entries ( $user, $date ) ;
4022 // get all the non-repeating events for this date and store in $ev
4023 $ev = get_entries ( $user, $date, $get_unapproved );
4025 for ( $i = 0; $i < count ( $ev ); $i++ ) {
4026 // print out any repeating events that are before this one...
4027 while ( $cur_rep < count ( $rep ) &&
4028 $rep[$cur_rep]['cal_time'] < $ev[$i]['cal_time'] ) {
4029 if ( $get_unapproved || $rep[$cur_rep]['cal_status'] == 'A' ) {
4030 print_entry_timebar ( $rep[$cur_rep]['cal_id'],
4031 $date, $rep[$cur_rep]['cal_time'], $rep[$cur_rep]['cal_duration'],
4032 $rep[$cur_rep]['cal_name'], $rep[$cur_rep]['cal_description'],
4033 $rep[$cur_rep]['cal_status'], $rep[$cur_rep]['cal_priority'],
4034 $rep[$cur_rep]['cal_access'], $rep[$cur_rep]['cal_login'],
4035 $rep[$cur_rep]['cal_category'] );
4040 if ( $get_unapproved || $ev[$i]['cal_status'] == 'A' ) {
4041 print_entry_timebar ( $ev[$i]['cal_id'],
4042 $date, $ev[$i]['cal_time'], $ev[$i]['cal_duration'],
4043 $ev[$i]['cal_name'], $ev[$i]['cal_description'],
4044 $ev[$i]['cal_status'], $ev[$i]['cal_priority'],
4045 $ev[$i]['cal_access'], $ev[$i]['cal_login'],
4046 $ev[$i]['cal_category'] );
4050 // print out any remaining repeating events
4051 while ( $cur_rep < count ( $rep ) ) {
4052 if ( $get_unapproved || $rep[$cur_rep]['cal_status'] == 'A' ) {
4053 print_entry_timebar ( $rep[$cur_rep]['cal_id'],
4054 $date, $rep[$cur_rep]['cal_time'], $rep[$cur_rep]['cal_duration'],
4055 $rep[$cur_rep]['cal_name'], $rep[$cur_rep]['cal_description'],
4056 $rep[$cur_rep]['cal_status'], $rep[$cur_rep]['cal_priority'],
4057 $rep[$cur_rep]['cal_access'], $rep[$cur_rep]['cal_login'],
4058 $rep[$cur_rep]['cal_category'] );
4064 echo " "; // so the table cell has at least something
4068 * Prints the HTML for an events with a timebar.
4070 * @param int $id Event id
4071 * @param string $date Date of event in YYYYMMDD format
4072 * @param string $time Time of event in HHMM format
4073 * @param int $duration Duration of event in minutes
4074 * @param string $name Brief description of event
4075 * @param string $description Full description of event
4076 * @param string $status Status of event ('A', 'W')
4077 * @param int $pri Priority of event
4078 * @param string $access Access to event by others ('P', 'R')
4079 * @param string $event_owner User who created event
4080 * @param int $event_category Category id for event
4082 * @staticvar int Used to ensure all event popups have a unique id
4084 function print_entry_timebar ( $id, $date, $time, $duration,
4085 $name, $description, $status,
4086 $pri, $access, $event_owner, $event_category=-1 ) {
4087 global $eventinfo, $login, $user, $PHP_SELF, $prefarray;
4089 $insidespan = false;
4092 // compute time offsets in % of total table width
4093 $day_start=$prefarray["WORK_DAY_START_HOUR"] * 60;
4094 if ( $day_start == 0 ) $day_start = 9*60;
4095 $day_end=$prefarray["WORK_DAY_END_HOUR"] * 60;
4096 if ( $day_end == 0 ) $day_end = 19*60;
4097 if ( $day_end <= $day_start ) $day_end = $day_start + 60; //avoid exceptions
4100 $bar_units= 100/(($day_end - $day_start)/60) ; // Percentage each hour occupies
4101 $ev_start = round((floor(($time/10000) - ($day_start/60)) + (($time/100)%100)/60) * $bar_units);
4105 if ($ev_start < 0) $ev_start = 0;
4106 if ($duration > 0) {
4107 $ev_duration = round(100 * $duration / ($day_end - $day_start)) ;
4108 if ($ev_start + $ev_duration > 100 ) {
4109 $ev_duration = 100 - $ev_start;
4115 $ev_duration=100-$ev_start;
4118 $ev_padding = 100 - $ev_start - $ev_duration;
4119 // choose where to position the text (pos=0->before,pos=1->on,pos=2->after)
4120 if ($ev_duration > 20) { $pos = 1; }
4121 elseif ($ev_padding > 20) { $pos = 2; }
4124 echo "\n<!-- ENTRY BAR -->\n<table class=\"entrycont\" cellpadding=\"0\" cellspacing=\"0\">\n";
4126 echo ($ev_start > 0 ? "<td style=\"text-align:right; width:$ev_start%;\">" : "" );
4128 echo ($ev_start > 0 ? " </td>\n": "" ) ;
4129 echo "<td style=\"width:$ev_duration%;\">\n<table class=\"entrybar\">\n<tr>\n<td class=\"entry\">";
4131 echo ($ev_padding > 0 ? " </td>\n": "" ) . "</tr>\n</table></td>\n";
4132 echo ($ev_padding > 0 ? "<td style=\"text-align:left; width:$ev_padding%;\">" : "");
4136 if ( $login != $event_owner && strlen ( $event_owner ) ) {
4137 $class = "layerentry";
4140 if ( $status == "W" ) $class = "unapprovedentry";
4142 // if we are looking at a view, then always use "entry"
4143 if ( strstr ( $PHP_SELF, "view_m.php" ) ||
4144 strstr ( $PHP_SELF, "view_w.php" ) ||
4145 strstr ( $PHP_SELF, "view_v.php" ) ||
4146 strstr ( $PHP_SELF, "view_t.php" ) )
4149 if ( $pri == 3 ) echo "<strong>";
4150 $popupid = "eventinfo-$id-$key";
4152 echo "<a class=\"$class\" href=\"view_entry.php?id=$id&date=$date";
4153 if ( strlen ( $user ) > 0 )
4154 echo "&user=" . $user;
4155 echo "\" onmouseover=\"window.status='" .
4156 translate("View this entry") . "'; show(event, '$popupid'); return true;\" onmouseout=\"hide('$popupid'); return true;\">";
4158 if ( $login != $event_owner && strlen ( $event_owner ) ) {
4159 if ($layers) foreach ($layers as $layer) {
4160 if($layer['cal_layeruser'] == $event_owner) {
4162 echo("<span style=\"color:" . $layer['cal_color'] . ";\">");
4167 echo "[$event_owner] ";
4169 if ( $duration == ( 24 * 60 ) ) {
4170 $timestr = translate("All day event");
4171 } else if ( $time >= 0 ) {
4172 $timestr = display_time ( $time );
4173 if ( $duration > 0 ) {
4175 $h = (int) ( $time / 10000 );
4176 $m = ( $time / 100 ) % 100;
4179 while ( $m >= 60 ) {
4183 $end_time = sprintf ( "%02d%02d00", $h, $m );
4184 $timestr .= " - " . display_time ( $end_time );
4187 if ( $login != $user && $access == 'R' && strlen ( $user ) )
4188 echo "(" . translate("Private") . ")";
4190 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) )
4191 echo "(" . translate("Private") . ")";
4193 if ( $login != $event_owner && strlen ( $event_owner ) )
4195 echo htmlspecialchars ( $name );
4196 if ( $insidespan ) { echo ("</span>"); } //end color span
4199 echo htmlspecialchars ( $name );
4201 if ( $pri == 3 ) echo "</strong>"; //end font-weight span
4205 echo "<td style=\"width:$ev_duration%;\"><table class=\"entrybar\">\n<tr>\n<td class=\"entry\"> </td>\n";
4207 echo "</tr>\n</table></td>\n";
4208 echo ($ev_padding > 0 ? "<td style=\"text-align:left; width:$ev_padding%;\"> </td>\n" : "" );
4210 echo "</tr>\n</table>\n";
4211 if ( $login != $user && $access == 'R' && strlen ( $user ) )
4212 $eventinfo .= build_event_popup ( $popupid, $event_owner,
4213 translate("This event is confidential"), "" );
4215 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) )
4216 $eventinfo .= build_event_popup ( $popupid, $event_owner,
4217 translate("This event is confidential"), "" );
4219 $eventinfo .= build_event_popup ( $popupid, $event_owner,
4220 $description, $timestr, site_extras_for_popup ( $id ) );
4224 * Prints the header for the timebar.
4226 * @param int $start_hour Start hour
4227 * @param int $end_hour End hour
4229 function print_header_timebar($start_hour, $end_hour) {
4231 // +------+----....----+------+
4235 if ( ($end_hour - $start_hour) == 0 )
4238 $offset = round(100/($end_hour - $start_hour));
4239 echo "\n<!-- TIMEBAR -->\n<table class=\"timebar\">\n<tr><td style=\"width:$offset%;\"> </td>\n";
4240 for ($i = $start_hour+1; $i < $end_hour; $i++) {
4241 // $prev_offset = $offset;
4242 // $offset = round(100/($end_hour - $start_hour)*($i - $start_hour + .5));
4243 $offset = round(100/($end_hour - $start_hour));
4245 echo "<td style=\"width:$width%;text-align:left;\">$i</td>\n";
4247 // $width = 100 - $offset;
4248 // echo "<td style=\"width:$width%;\"> </td>\n";
4249 echo "</tr>\n</table>\n<!-- /TIMEBAR -->\n";
4252 echo "\n<!-- YARDSTICK -->\n<table class=\"yardstick\">\n<tr>\n";
4253 $width = round(100/($end_hour - $start_hour));
4254 for ($i = $start_hour; $i < $end_hour; $i++) {
4255 echo "<td style=\"width:$width%;\"> </td>\n";
4257 echo "</tr>\n</table>\n<!-- /YARDSTICK -->\n";
4261 * Gets a list of nonuser calendars and return info in an array.
4263 * @param string $user Login of admin of the nonuser calendars
4265 * @return array Array of nonuser cals, where each is an array with the
4267 * - <var>cal_login</var>
4268 * - <var>cal_lastname</var>
4269 * - <var>cal_firstname</var>
4270 * - <var>cal_admin</var>
4271 * - <var>cal_fullname</var>
4273 function get_nonuser_cals ($user = '') {
4276 $sql = "SELECT cal_login, cal_lastname, cal_firstname, " .
4277 "cal_admin FROM webcal_nonuser_cals ";
4278 if ($user != '') $sql .= "WHERE cal_admin = '$user' ";
4279 $sql .= "ORDER BY cal_lastname, cal_firstname, cal_login";
4280 $res = dbi_query ( $sql );
4282 while ( $row = dbi_fetch_row ( $res ) ) {
4283 if ( strlen ( $row[1] ) || strlen ( $row[2] ) )
4284 $fullname = "$row[2] $row[1]";
4286 $fullname = $row[0];
4287 $ret[$count++] = array (
4288 "cal_login" => $row[0],
4289 "cal_lastname" => $row[1],
4290 "cal_firstname" => $row[2],
4291 "cal_admin" => $row[3],
4292 "cal_fullname" => $fullname
4295 dbi_free_result ( $res );
4301 * Loads nonuser variables (login, firstname, etc.).
4303 * The following variables will be set:
4304 * - <var>login</var>
4305 * - <var>firstname</var>
4306 * - <var>lastname</var>
4307 * - <var>fullname</var>
4308 * - <var>admin</var>
4309 * - <var>email</var>
4311 * @param string $login Login name of nonuser calendar
4312 * @param string $prefix Prefix to use for variables that will be set.
4313 * For example, if prefix is "temp", then the login will
4314 * be stored in the <var>$templogin</var> global variable.
4316 function nonuser_load_variables ( $login, $prefix ) {
4317 global $error,$nuloadtmp_email;
4319 $res = dbi_query ( "SELECT cal_login, cal_lastname, cal_firstname, " .
4320 "cal_admin FROM webcal_nonuser_cals WHERE cal_login = '$login'" );
4322 while ( $row = dbi_fetch_row ( $res ) ) {
4323 if ( strlen ( $row[1] ) || strlen ( $row[2] ) )
4324 $fullname = "$row[2] $row[1]";
4326 $fullname = $row[0];
4328 // We need the email address for the admin
4329 user_load_variables ( $row[3], 'nuloadtmp_' );
4331 $GLOBALS[$prefix . "login"] = $row[0];
4332 $GLOBALS[$prefix . "firstname"] = $row[2];
4333 $GLOBALS[$prefix . "lastname"] = $row[1];
4334 $GLOBALS[$prefix . "fullname"] = $fullname;
4335 $GLOBALS[$prefix . "admin"] = $row[3];
4336 $GLOBALS[$prefix . "email"] = $nuloadtmp_email;
4339 dbi_free_result ( $res );
4345 * Checks the webcal_nonuser_cals table to determine if the user is the
4346 * administrator for the nonuser calendar.
4348 * @param string $login Login of user that is the potential administrator
4349 * @param string $nonuser Login name for nonuser calendar
4351 * @return bool True if the user is the administrator for the nonuser calendar
4353 function user_is_nonuser_admin ( $login, $nonuser ) {
4356 $res = dbi_query ( "SELECT * FROM webcal_nonuser_cals " .
4357 "WHERE cal_login = '$nonuser' AND cal_admin = '$login'" );
4359 if ( dbi_fetch_row ( $res ) )
4361 dbi_free_result ( $res );
4367 * Loads nonuser preferences from the webcal_user_pref table if on a nonuser
4370 * @param string $nonuser Login name for nonuser calendar
4372 function load_nonuser_preferences ($nonuser) {
4375 "SELECT cal_setting, cal_value FROM webcal_user_pref " .
4376 "WHERE cal_login = '$nonuser'" );
4378 while ( $row = dbi_fetch_row ( $res ) ) {
4381 $sys_setting = "sys_" . $setting;
4382 // save system defaults
4383 // ** don't override ones set by load_user_prefs
4384 if ( ! empty ( $GLOBALS[$setting] ) && empty ( $GLOBALS["sys_" . $setting] ))
4385 $GLOBALS["sys_" . $setting] = $GLOBALS[$setting];
4386 $GLOBALS[$setting] = $value;
4387 $prefarray[$setting] = $value;
4389 dbi_free_result ( $res );
4394 * Determines what the day is after the <var>$TZ_OFFSET</var> and sets it globally.
4396 * The following global variables will be set:
4397 * - <var>$thisyear</var>
4398 * - <var>$thismonth</var>
4399 * - <var>$thisday</var>
4400 * - <var>$thisdate</var>
4401 * - <var>$today</var>
4403 * @param string $date The date in YYYYMMDD format
4405 function set_today($date) {
4406 global $thisyear, $thisday, $thismonth, $thisdate, $today;
4407 global $TZ_OFFSET, $month, $day, $year, $thisday;
4409 // Adjust for TimeZone
4410 $today = time() + ($TZ_OFFSET * 60 * 60);
4412 if ( ! empty ( $date ) && ! empty ( $date ) ) {
4413 $thisyear = substr ( $date, 0, 4 );
4414 $thismonth = substr ( $date, 4, 2 );
4415 $thisday = substr ( $date, 6, 2 );
4417 if ( empty ( $month ) || $month == 0 )
4418 $thismonth = date("m", $today);
4420 $thismonth = $month;
4421 if ( empty ( $year ) || $year == 0 )
4422 $thisyear = date("Y", $today);
4425 if ( empty ( $day ) || $day == 0 )
4426 $thisday = date("d", $today);
4430 $thisdate = sprintf ( "%04d%02d%02d", $thisyear, $thismonth, $thisday );
4434 * Converts from Gregorian Year-Month-Day to ISO YearNumber-WeekNumber-WeekDay.
4436 * @internal JGH borrowed gregorianToISO from PEAR Date_Calc Class and added
4437 * $GLOBALS["WEEK_START"] (change noted)
4439 * @param int $day Day of month
4440 * @param int $month Number of month
4441 * @param int $year Year
4443 * @return string Date in ISO YearNumber-WeekNumber-WeekDay format
4447 function gregorianToISO($day,$month,$year) {
4448 $mnth = array (0,31,59,90,120,151,181,212,243,273,304,334);
4449 $y_isleap = isLeapYear($year);
4450 $y_1_isleap = isLeapYear($year - 1);
4451 $day_of_year_number = $day + $mnth[$month - 1];
4452 if ($y_isleap && $month > 2) {
4453 $day_of_year_number++;
4455 // find Jan 1 weekday (monday = 1, sunday = 7)
4456 $yy = ($year - 1) % 100;
4457 $c = ($year - 1) - $yy;
4458 $g = $yy + intval($yy/4);
4459 $jan1_weekday = 1 + intval((((($c / 100) % 4) * 5) + $g) % 7);
4462 // JGH added next if/else to compensate for week begins on Sunday
4463 if (! $GLOBALS["WEEK_START"] && $jan1_weekday < 7) {
4465 } elseif (! $GLOBALS["WEEK_START"] && $jan1_weekday == 7) {
4469 // weekday for year-month-day
4470 $h = $day_of_year_number + ($jan1_weekday - 1);
4471 $weekday = 1 + intval(($h - 1) % 7);
4472 // find if Y M D falls in YearNumber Y-1, WeekNumber 52 or
4473 if ($day_of_year_number <= (8 - $jan1_weekday) && $jan1_weekday > 4){
4474 $yearnumber = $year - 1;
4475 if ($jan1_weekday == 5 || ($jan1_weekday == 6 && $y_1_isleap)) {
4481 $yearnumber = $year;
4483 // find if Y M D falls in YearNumber Y+1, WeekNumber 1
4484 if ($yearnumber == $year) {
4490 if (($i - $day_of_year_number) < (4 - $weekday)) {
4495 // find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
4496 if ($yearnumber == $year) {
4497 $j = $day_of_year_number + (7 - $weekday) + ($jan1_weekday - 1);
4498 $weeknumber = intval($j / 7);
4499 if ($jan1_weekday > 4) {
4503 // put it all together
4504 if ($weeknumber < 10)
4505 $weeknumber = '0'.$weeknumber;
4506 return "{$yearnumber}-{$weeknumber}-{$weekday}";
4510 * Is this a leap year?
4512 * @internal JGH Borrowed isLeapYear from PEAR Date_Calc Class
4514 * @param int $year Year
4516 * @return bool True for a leap year, else false
4520 function isLeapYear($year='') {
4521 if (empty($year)) $year = strftime("%Y",time());
4522 if (strlen($year) != 4) return false;
4523 if (preg_match('/\D/',$year)) return false;
4524 return (($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0);
4528 * Replaces unsafe characters with HTML encoded equivalents.
4530 * @param string $value Input text
4532 * @return string The cleaned text
4534 function clean_html($value){
4535 $value = htmlspecialchars($value, ENT_QUOTES);
4536 $value = strtr($value, array(
4544 * Removes non-word characters from the specified text.
4546 * @param string $data Input text
4548 * @return string The converted text
4550 function clean_word($data) {
4551 return preg_replace("/\W/", '', $data);
4555 * Removes non-digits from the specified text.
4557 * @param string $data Input text
4559 * @return string The converted text
4561 function clean_int($data) {
4562 return preg_replace("/\D/", '', $data);
4566 * Removes whitespace from the specified text.
4568 * @param string $data Input text
4570 * @return string The converted text
4572 function clean_whitespace($data) {
4573 return preg_replace("/\s/", '', $data);
4577 * Converts language names to their abbreviation.
4579 * @param string $name Name of the language (such as "French")
4581 * @return string The abbreviation ("fr" for "French")
4583 function languageToAbbrev ( $name ) {
4584 global $browser_languages;
4585 foreach ( $browser_languages as $abbrev => $langname ) {
4586 if ( $langname == $name )
4593 * Creates the CSS for using gradient.php, if the appropriate GD functions are
4596 * A one-pixel wide image will be used for the background image.
4598 * <b>Note:</b> The gd library module needs to be available to use gradient
4599 * images. If it is not available, a single background color will be used
4602 * @param string $color Base color
4603 * @param int $height Height of gradient image
4604 * @param int $percent How many percent lighter the top color should be
4605 * than the base color at the bottom of the image
4607 * @return string The style sheet text to use
4609 function background_css ( $color, $height = '', $percent = '' ) {
4612 if ( ( function_exists ( 'imagepng' ) || function_exists ( 'imagegif' ) )
4613 && ( empty ( $GLOBALS['enable_gradients'] ) ||
4614 $GLOBALS['enable_gradients'] == 'Y' ) ) {
4615 $ret = "background: $color url(\"gradient.php?base=" . substr ( $color, 1 );
4617 if ( $height != '' ) {
4618 $ret .= "&height=$height";
4621 if ( $percent != '' ) {
4622 $ret .= "&percent=$percent";
4625 $ret .= "\") repeat-x;\n";
4627 $ret = "background-color: $color;\n";
4634 * Draws a daily outlook style availability grid showing events that are
4635 * approved and awaiting approval.
4637 * @param string $date Date to show the grid for
4638 * @param array $participants Which users should be included in the grid
4639 * @param string $popup Not used
4641 function daily_matrix ( $date, $participants, $popup = '' ) {
4642 global $CELLBG, $TODAYCELLBG, $THFG, $THBG, $TABLEBG;
4643 global $user_fullname, $repeated_events, $events;
4644 global $WORK_DAY_START_HOUR, $WORK_DAY_END_HOUR, $TZ_OFFSET,$ignore_offset;
4648 $participant_pct = '20%'; //use percentage
4650 $first_hour = $WORK_DAY_START_HOUR;
4651 $last_hour = $WORK_DAY_END_HOUR;
4652 $hours = $last_hour - $first_hour;
4653 $cols = (($hours * $interval) + 1);
4655 $cell_pct = 80 /($hours * $interval);
4658 // Build a master array containing all events for $participants
4659 for ( $i = 0; $i < count ( $participants ); $i++ ) {
4661 /* Pre-Load the repeated events for quckier access */
4662 $repeated_events = read_repeated_events ( $participants[$i], "", $date );
4663 /* Pre-load the non-repeating events for quicker access */
4664 $events = read_events ( $participants[$i], $date, $date );
4666 // get all the repeating events for this date and store in array $rep
4667 $rep = get_repeating_entries ( $participants[$i], $date );
4668 // get all the non-repeating events for this date and store in $ev
4669 $ev = get_entries ( $participants[$i], $date );
4671 // combine into a single array for easy processing
4672 $ALL = array_merge ( $rep, $ev );
4674 foreach ( $ALL as $E ) {
4675 if ($E['cal_time'] == 0) {
4676 $E['cal_time'] = $first_hour."0000";
4677 $E['cal_duration'] = 60 * ( $last_hour - $first_hour );
4679 $E['cal_time'] = sprintf ( "%06d", $E['cal_time']);
4682 $hour = substr($E['cal_time'], 0, 2 );
4683 $mins = substr($E['cal_time'], 2, 2 );
4686 if ( ! $ignore_offset ) $hour += $TZ_OFFSET;
4687 while ( $hour < 0 ) $hour += 24;
4688 while ( $hour > 23 ) $hour -= 24;
4690 // Make sure hour is 2 digits
4691 $hour = sprintf ( "%02d",$hour);
4693 // convert cal_time to slot
4696 } elseif ($mins >= 15 && $mins < 30) {
4697 $slot = $hour.'.25';
4698 } elseif ($mins >= 30 && $mins < 45) {
4700 } elseif ($mins >= 45) {
4701 $slot = $hour.'.75';
4704 // convert cal_duration to bars
4705 $bars = $E['cal_duration'] / $increment;
4707 // never replace 'A' with 'W'
4708 for ($q = 0; $bars > $q; $q++) {
4709 $slot = sprintf ("%02.2f",$slot);
4710 if (strlen($slot) == 4) $slot = '0'.$slot; // add leading zeros
4711 $slot = $slot.''; // convert to a string
4712 if ( empty ( $master['_all_'][$slot] ) ||
4713 $master['_all_'][$slot]['stat'] != 'A') {
4714 $master['_all_'][$slot]['stat'] = $E['cal_status'];
4716 if ( empty ( $master[$participants[$i]][$slot] ) ||
4717 $master[$participants[$i]][$slot]['stat'] != 'A' ) {
4718 $master[$participants[$i]][$slot]['stat'] = $E['cal_status'];
4719 $master[$participants[$i]][$slot]['ID'] = $E['cal_id'];
4721 $slot = $slot + '0.25';
4728 <table align="center" class="matrixd" style="width:<?php echo $total_pct;?>;" cellspacing="0" cellpadding="0">
4729 <tr><td class="matrix" colspan="<?php echo $cols;?>"></td></tr>
4730 <tr><th style="width:<?php echo $participant_pct;?>;">
4731 <?php etranslate("Participants");?></th>
4734 $MouseOut = "onmouseout=\"window.status=''; this.style.backgroundColor='".$THBG."';\"";
4736 for($i=$first_hour;$i<$last_hour;$i++) {
4738 if ( $GLOBALS["TIME_FORMAT"] == "12" ) {
4740 if ( $hour == 0 ) $hour = 12;
4743 for($j=0;$j<$interval;$j++) {
4744 $str .= ' <td id="C'.$CC.'" class="dailymatrix" ';
4745 $MouseDown = 'onmousedown="schedule_event('.$i.','.sprintf ("%02d",($increment * $j)).');"';
4748 if($interval == 4) { $k = ($hour<=9?'0':substr($hour,0,1)); }
4749 $str .= 'style="width:'.$cell_pct.'%; text-align:right;" '.$MouseDown." onmouseover=\"window.status='Schedule a ".$hour.':'.($increment * $j<=9?'0':'').($increment * $j)." appointment.'; this.style.backgroundColor='#CCFFCC'; return true;\" ".$MouseOut." title=\"Schedule an appointment for ".$hour.':'.($increment * $j<=9?'0':'').($increment * $j).".\">";
4750 $str .= $k."</td>\n";
4753 if($interval == 4) { $k = ($hour<=9?substr($hour,0,1):substr($hour,1,2)); }
4754 $str .= 'style="width:'.$cell_pct.'%; text-align:left;" '.$MouseDown." onmouseover=\"window.status='Schedule a ".$hour.':'.($increment * $j)." appointment.'; this.style.backgroundColor='#CCFFCC'; return true;\" ".$MouseOut." title=\"Schedule an appointment for ".$hour.':'.($increment * $j<=9?'0':'').($increment * $j).".\">";
4755 $str .= $k."</td>\n";
4758 $str .= 'style="width:'.$cell_pct.'%;" '.$MouseDown." onmouseover=\"window.status='Schedule a ".$hour.':'.($increment * $j<=9?'0':'').($increment * $j)." appointment.'; this.style.backgroundColor='#CCFFCC'; return true;\" ".$MouseOut." title=\"Schedule an appointment for ".$hour.':'.($increment * $j<=9?'0':'').($increment * $j).".\">";
4759 $str .= " </td>\n";
4766 "</tr>\n<tr><td class=\"matrix\" colspan=\"$cols\"></td></tr>\n";
4768 // Add user _all_ to beginning of $participants array
4769 array_unshift($participants, '_all_');
4771 // Javascript for cells
4772 $MouseOver = "onmouseover=\"this.style.backgroundColor='#CCFFCC';\"";
4773 $MouseOut = "onmouseout=\"this.style.backgroundColor='".$CELLBG."';\"";
4775 // Display each participant
4776 for ( $i = 0; $i < count ( $participants ); $i++ ) {
4777 if ($participants[$i] != '_all_') {
4778 // Load full name of user
4779 user_load_variables ( $participants[$i], "user_" );
4781 // exchange space for to keep from breaking
4782 $user_nospace = preg_replace ( '/\s/', ' ', $user_fullname );
4784 $user_nospace = translate("All Attendees");
4785 $user_nospace = preg_replace ( '/\s/', ' ', $user_nospace );
4788 echo "<tr>\n<th class=\"row\" style=\"width:{$participant_pct};\">".$user_nospace."</th>\n";
4790 $viewMsg = translate ( "View this entry" );
4792 // check each timebar
4793 for ( $j = $first_hour; $j < $last_hour; $j++ ) {
4794 for ( $k = 0; $k < $interval; $k++ ) {
4795 $border = ($k == '0') ? ' border-left: 1px solid #000000;' : "";
4796 $MouseDown = 'onmousedown="schedule_event('.$j.','.sprintf ("%02d",($increment * $k)).');"';
4801 $r = sprintf ("%02d",$j) . '.' . sprintf ("%02d", (25 * $k)).'';
4802 if ( empty ( $master[$participants[$i]][$r] ) ) {
4804 } else if ( empty ( $master[$participants[$i]][$r]['ID'] ) ) {
4805 // This is the first line for 'all' users. No event here.
4806 $space = "<span class=\"matrix\"><img src=\"pix.gif\" alt=\"\" style=\"height: 8px\" /></span>";
4807 } else if ($master[$participants[$i]][$r]['stat'] == "A") {
4808 $space = "<a class=\"matrix\" href=\"view_entry.php?id={$master[$participants[$i]][$r]['ID']}\"><img src=\"pix.gif\" title=\"$viewMsg\" alt=\"$viewMsg\" /></a>";
4809 } else if ($master[$participants[$i]][$r]['stat'] == "W") {
4810 $space = "<a class=\"matrix\" href=\"view_entry.php?id={$master[$participants[$i]][$r]['ID']}\"><img src=\"pixb.gif\" title=\"$viewMsg\" alt=\"$viewMsg\" /></a>";
4813 echo "<td class=\"matrixappts\" style=\"width:{$cell_pct}%;$border\" ";
4814 if ($space == " ") echo "$MouseDown $MouseOver $MouseOut";
4815 echo ">$space</td>\n";
4820 echo "</tr><tr>\n<td class=\"matrix\" colspan=\"$cols\">" .
4821 "<img src=\"pix.gif\" alt=\"-\" /></td></tr>\n";
4822 } // End foreach participant
4824 echo "</table><br />\n";
4825 $busy = translate ("Busy");
4826 $tentative = translate ("Tentative");
4827 echo "<table align=\"center\"><tr><td class=\"matrixlegend\" >\n";
4828 echo "<img src=\"pix.gif\" title=\"$busy\" alt=\"$busy\" /> $busy \n";
4829 echo "<img src=\"pixb.gif\" title=\"$tentative\" alt=\"$tentative\" /> $tentative\n";
4830 echo "</td></tr></table>\n";
4834 * Return the time in HHMMSS format of input time + duration
4837 * <b>Note:</b> The gd library module needs to be available to use gradient
4838 * images. If it is not available, a single background color will be used
4841 * @param string $time format "235900"
4842 * @param int $duration number of minutes
4844 * @return string The time in HHMMSS format
4846 function add_duration ( $time, $duration ) {
4847 $hour = (int) ( $time / 10000 );
4848 $min = ( $time / 100 ) % 100;
4849 $minutes = $hour * 60 + $min + $duration;
4852 $ret = sprintf ( "%d%02d00", $h, $m );
4853 //echo "add_duration ( $time, $duration ) = $ret <br />\n";