[ Index ] |
|
Code source de WebCalendar 1.0.5 |
1 <?php 2 /** 3 * All of WebCalendar's functions 4 * 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 8 * @package WebCalendar 9 */ 10 11 if ( empty ( $PHP_SELF ) && ! empty ( $_SERVER ) && 12 ! empty ( $_SERVER['PHP_SELF'] ) ) { 13 $PHP_SELF = $_SERVER['PHP_SELF']; 14 } 15 if ( ! empty ( $PHP_SELF ) && preg_match ( "/\/includes\//", $PHP_SELF ) ) { 16 die ( "You can't access this file directly!" ); 17 } 18 19 /**#@+ 20 * Used for activity log 21 * @global string 22 */ 23 $LOG_CREATE = "C"; 24 $LOG_APPROVE = "A"; 25 $LOG_REJECT = "X"; 26 $LOG_UPDATE = "U"; 27 $LOG_DELETE = "D"; 28 $LOG_NOTIFICATION = "N"; 29 $LOG_REMINDER = "R"; 30 /**#@-*/ 31 32 /** 33 * Number of seconds in a day 34 * 35 * @global int $ONE_DAY 36 */ 37 $ONE_DAY = 86400; 38 39 /** 40 * Array containing the number of days in each month in a non-leap year 41 * 42 * @global array $days_per_month 43 */ 44 $days_per_month = array ( 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); 45 46 /** 47 * Array containing the number of days in each month in a leap year 48 * 49 * @global array $ldays_per_month 50 */ 51 $ldays_per_month = array ( 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); 52 53 /** 54 * Array of global variables which are not allowed to by set via HTTP GET/POST 55 * 56 * This is a security precaution to prevent users from overriding any global 57 * variables 58 * 59 * @global array $noSet 60 */ 61 $noSet = array ( 62 "is_admin" => 1, 63 "db_type" => 1, 64 "db_host" => 1, 65 "db_login" => 1, 66 "db_password" => 1, 67 "db_persistent" => 1, 68 "PROGRAM_NAME" => 1, 69 "PROGRAM_URL" => 1, 70 "readonly" => 1, 71 "single_user" => 1, 72 "single_user_login" => 1, 73 "use_http_auth" => 1, 74 "user_inc" => 1, 75 "includedir" => 1, 76 "NONUSER_PREFIX" => 1, 77 "languages" => 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, 83 "noSet" => 1, 84 ); 85 86 // This code is a temporary hack to make the application work when 87 // register_globals is set to Off in php.ini (the default setting in 88 // PHP 4.2.0 and after). 89 if ( empty ( $HTTP_GET_VARS ) ) $HTTP_GET_VARS = $_GET; 90 if ( ! empty ( $HTTP_GET_VARS ) ) { 91 while (list($key, $val) = @each($HTTP_GET_VARS)) { 92 // don't allow anything to have <script> in it... 93 if ( ! is_array ( $val ) ) { 94 if ( preg_match ( "/<\s*script/i", $val ) ) { 95 echo "Security violation!"; exit; 96 } 97 } 98 if ( $key == "login" ) { 99 if ( strstr ( $PHP_SELF, "login.php" ) ) { 100 //$GLOBALS[$key] = $val; 101 $GLOBALS[$key] = $val; 102 } 103 } else { 104 if ( empty ( $noSet[$key] ) ) { 105 $GLOBALS[$key] = $val; 106 //echo "XXX $key<br />\n"; 107 } 108 } 109 //echo "GET var '$key' = '$val' <br />\n"; 110 } 111 reset ( $HTTP_GET_VARS ); 112 } 113 114 if ( empty ( $HTTP_POST_VARS ) ) $HTTP_POST_VARS = $_POST; 115 if ( ! empty ( $HTTP_POST_VARS ) ) { 116 while (list($key, $val) = @each($HTTP_POST_VARS)) { 117 // don't allow anything to have <script> in it... except 'template' 118 if ( ! is_array ( $val ) && $key != 'template' ) { 119 if ( preg_match ( "/<\s*script/i", $val ) ) { 120 echo "Security violation!"; exit; 121 } 122 } 123 if ( empty ( $noSet[$key] ) ) { 124 $GLOBALS[$key] = $val; 125 } 126 } 127 reset ( $HTTP_POST_VARS ); 128 } 129 //while (list($key, $val) = @each($HTTP_POST_FILES)) { 130 // $GLOBALS[$key] = $val; 131 //} 132 //while (list($key, $val) = @each($HTTP_SESSION_VARS)) { 133 // $GLOBALS[$key] = $val; 134 //} 135 if ( empty ( $HTTP_COOKIE_VARS ) ) $HTTP_COOKIE_VARS = $_COOKIE; 136 if ( ! empty ( $HTTP_COOKIE_VARS ) ) { 137 while (list($key, $val) = @each($HTTP_COOKIE_VARS)) { 138 if ( empty ( $noSet[$key] ) && substr($key,0,12) == "webcalendar_" ) { 139 $GLOBALS[$key] = $val; 140 } 141 //echo "COOKIE var '$key' = '$val' <br />\n"; 142 } 143 reset ( $HTTP_COOKIE_VARS ); 144 } 145 146 // Don't allow a user to put "login=XXX" in the URL if they are not 147 // coming from the login.php page. 148 if ( empty ( $PHP_SELF ) && ! empty ( $_SERVER['PHP_SELF'] ) ) 149 $PHP_SELF = $_SERVER['PHP_SELF']; // backward compatibility 150 if ( empty ( $PHP_SELF ) ) 151 $PHP_SELF = ''; // this happens when running send_reminders.php from CL 152 if ( ! strstr ( $PHP_SELF, "login.php" ) && ! empty ( $GLOBALS["login"] ) ) { 153 $GLOBALS["login"] = ""; 154 } 155 156 // Define an array to use to jumble up the key: $offsets 157 // We define a unique key to scramble the cookie we generate. 158 // We use the admin install password that the user set to make 159 // the salt unique for each WebCalendar install. 160 if ( ! empty ( $settings ) && ! empty ( $settings['install_password'] ) ) { 161 $salt = $settings['install_password']; 162 } else { 163 $salt = md5 ( $db_login ); 164 } 165 $salt_len = strlen ( $salt ); 166 167 if ( ! empty ( $db_password ) ) { 168 $salt2 = md5 ( $db_password ); 169 } else { 170 $salt2 = md5 ( "oogabooga" ); 171 } 172 $salt2_len = strlen ( $salt2 ); 173 174 $offsets = array (); 175 for ( $i = 0; $i < $salt_len || $i < $salt2_len; $i++ ) { 176 $offsets[$i] = 0; 177 if ( $i < $salt_len ) 178 $offsets[$i] += ord ( substr ( $salt, $i, 1 ) ); 179 if ( $i < $salt2_len ) 180 $offsets[$i] += ord ( substr ( $salt2, $i, 1 ) ); 181 $offsets[$i] %= 128; 182 } 183 /* debugging code... 184 for ( $i = 0; $i < count ( $offsets ); $i++ ) { 185 echo "offset $i: $offsets[$i] <br />\n"; 186 } 187 */ 188 189 /* 190 * Functions start here. All non-function code should be above this 191 * 192 * Note to developers: 193 * Documentation is generated from the function comments below. 194 * When adding/updating functions, please follow the following conventions 195 * seen below. Your cooperation in this matter is appreciated :-) 196 * 197 * If you want your documentation to link to the db documentation, 198 * just make sure you mention the db table name followed by "table" 199 * on the same line. Here's an example: 200 * Retrieve preferences from the webcal_user_pref table. 201 * 202 */ 203 204 /** 205 * Gets the value resulting from an HTTP POST method. 206 * 207 * <b>Note:</b> The return value will be affected by the value of 208 * <var>magic_quotes_gpc</var> in the php.ini file. 209 * 210 * @param string $name Name used in the HTML form 211 * 212 * @return string The value used in the HTML form 213 * 214 * @see getGetValue 215 */ 216 function getPostValue ( $name ) { 217 global $HTTP_POST_VARS; 218 219 if ( isset ( $_POST ) && is_array ( $_POST ) && ! empty ( $_POST[$name] ) ) { 220 $HTTP_POST_VARS[$name] = $_POST[$name]; 221 return $_POST[$name]; 222 } else if ( ! isset ( $HTTP_POST_VARS ) ) { 223 return null; 224 } else if ( ! isset ( $HTTP_POST_VARS[$name] ) ) { 225 return null; 226 } 227 return ( $HTTP_POST_VARS[$name] ); 228 } 229 230 /** 231 * Gets the value resulting from an HTTP GET method. 232 * 233 * <b>Note:</b> The return value will be affected by the value of 234 * <var>magic_quotes_gpc</var> in the php.ini file. 235 * 236 * If you need to enforce a specific input format (such as numeric input), then 237 * use the {@link getValue()} function. 238 * 239 * @param string $name Name used in the HTML form or found in the URL 240 * 241 * @return string The value used in the HTML form (or URL) 242 * 243 * @see getPostValue 244 */ 245 function getGetValue ( $name ) { 246 global $HTTP_GET_VARS; 247 248 if ( isset ( $_GET ) && is_array ( $_GET ) && ! empty ( $_GET[$name] ) ) { 249 $HTTP_GET_VARS[$name] = $_GET[$name]; 250 return $_GET[$name]; 251 } else if ( ! isset ( $HTTP_GET_VARS ) ) { 252 return null; 253 } else if ( ! isset ( $HTTP_GET_VARS[$name] ) ) { 254 return null; 255 } 256 return ( $HTTP_GET_VARS[$name] ); 257 } 258 259 /** 260 * Gets the value resulting from either HTTP GET method or HTTP POST method. 261 * 262 * <b>Note:</b> The return value will be affected by the value of 263 * <var>magic_quotes_gpc</var> in the php.ini file. 264 * 265 * <b>Note:</b> If you need to get an integer value, yuou can use the 266 * getIntValue function. 267 * 268 * @param string $name Name used in the HTML form or found in the URL 269 * @param string $format A regular expression format that the input must match. 270 * If the input does not match, an empty string is 271 * returned and a warning is sent to the browser. If The 272 * <var>$fatal</var> parameter is true, then execution 273 * will also stop when the input does not match the 274 * format. 275 * @param bool $fatal Is it considered a fatal error requiring execution to 276 * stop if the value retrieved does not match the format 277 * regular expression? 278 * 279 * @return string The value used in the HTML form (or URL) 280 * 281 * @uses getGetValue 282 * @uses getPostValue 283 */ 284 function getValue ( $name, $format="", $fatal=false ) { 285 $val = getPostValue ( $name ); 286 if ( ! isset ( $val ) ) 287 $val = getGetValue ( $name ); 288 // for older PHP versions... 289 if ( ! isset ( $val ) && get_magic_quotes_gpc () == 1 && 290 ! empty ( $GLOBALS[$name] ) ) 291 $val = $GLOBALS[$name]; 292 if ( ! isset ( $val ) ) 293 return ""; 294 if ( ! empty ( $format ) && ! preg_match ( "/^" . $format . "$/", $val ) ) { 295 // does not match 296 if ( $fatal ) { 297 die_miserable_death ( "Fatal Error: Invalid data format for $name" ); 298 } 299 // ignore value 300 return ""; 301 } 302 return $val; 303 } 304 305 /** 306 * Gets an integer value resulting from an HTTP GET or HTTP POST method. 307 * 308 * <b>Note:</b> The return value will be affected by the value of 309 * <var>magic_quotes_gpc</var> in the php.ini file. 310 * 311 * @param string $name Name used in the HTML form or found in the URL 312 * @param bool $fatal Is it considered a fatal error requiring execution to 313 * stop if the value retrieved does not match the format 314 * regular expression? 315 * 316 * @return string The value used in the HTML form (or URL) 317 * 318 * @uses getValue 319 */ 320 function getIntValue ( $name, $fatal=false ) { 321 $val = getValue ( $name, "-?[0-9]+", $fatal ); 322 return $val; 323 } 324 325 /** 326 * Loads default system settings (which can be updated via admin.php). 327 * 328 * System settings are stored in the webcal_config table. 329 * 330 * <b>Note:</b> If the setting for <var>server_url</var> is not set, the value 331 * will be calculated and stored in the database. 332 * 333 * @global string User's login name 334 * @global bool Readonly 335 * @global string HTTP hostname 336 * @global int Server's port number 337 * @global string Request string 338 * @global array Server variables 339 */ 340 function load_global_settings () { 341 global $login, $readonly, $HTTP_HOST, $SERVER_PORT, $REQUEST_URI, $_SERVER; 342 343 // Note: when running from the command line (send_reminders.php), 344 // these variables are (obviously) not set. 345 // TODO: This type of checking should be moved to a central locationm 346 // like init.php. 347 if ( isset ( $_SERVER ) && is_array ( $_SERVER ) ) { 348 if ( empty ( $HTTP_HOST ) && isset ( $_SERVER["HTTP_POST"] ) ) 349 $HTTP_HOST = $_SERVER["HTTP_HOST"]; 350 if ( empty ( $SERVER_PORT ) && isset ( $_SERVER["SERVER_PORT"] ) ) 351 $SERVER_PORT = $_SERVER["SERVER_PORT"]; 352 if ( empty ( $REQUEST_URI ) && isset ( $_SERVER["REQUEST_URI"] ) ) 353 $REQUEST_URI = $_SERVER["REQUEST_URI"]; 354 } 355 356 $res = dbi_query ( "SELECT cal_setting, cal_value FROM webcal_config" ); 357 if ( $res ) { 358 while ( $row = dbi_fetch_row ( $res ) ) { 359 $setting = $row[0]; 360 $value = $row[1]; 361 //echo "Setting '$setting' to '$value' <br />\n"; 362 $GLOBALS[$setting] = $value; 363 } 364 dbi_free_result ( $res ); 365 } 366 367 // If app name not set.... default to "Title". This gets translated 368 // later since this function is typically called before translate.php 369 // is included. 370 // Note: We usually use translate($application_name) instead of 371 // translate("Title"). 372 if ( empty ( $GLOBALS["application_name"] ) ) 373 $GLOBALS["application_name"] = "Title"; 374 375 // If $server_url not set, then calculate one for them, then store it 376 // in the database. 377 if ( empty ( $GLOBALS["server_url"] ) ) { 378 if ( ! empty ( $HTTP_HOST ) && ! empty ( $REQUEST_URI ) ) { 379 $ptr = strrpos ( $REQUEST_URI, "/" ); 380 if ( $ptr > 0 ) { 381 $uri = substr ( $REQUEST_URI, 0, $ptr + 1 ); 382 $server_url = "http://" . $HTTP_HOST; 383 if ( ! empty ( $SERVER_PORT ) && $SERVER_PORT != 80 ) 384 $server_url .= ":" . $SERVER_PORT; 385 $server_url .= $uri; 386 387 dbi_query ( "INSERT INTO webcal_config ( cal_setting, cal_value ) ". 388 "VALUES ( 'server_url', '$server_url' )" ); 389 $GLOBALS["server_url"] = $server_url; 390 } 391 } 392 } 393 394 // If no font settings, then set some 395 if ( empty ( $GLOBALS["FONTS"] ) ) { 396 if ( $GLOBALS["LANGUAGE"] == "Japanese" ) 397 $GLOBALS["FONTS"] = "Osaka, Arial, Helvetica, sans-serif"; 398 else 399 $GLOBALS["FONTS"] = "Arial, Helvetica, sans-serif"; 400 } 401 } 402 403 /** 404 * Gets the list of active plugins. 405 * 406 * Should be called after {@link load_global_settings()} and {@link load_user_preferences()}. 407 * 408 * @internal cek: ignored since I am not sure this will ever be used... 409 * 410 * @return array Active plugins 411 * 412 * @ignore 413 */ 414 function get_plugin_list ( $include_disabled=false ) { 415 // first get list of available plugins 416 $sql = "SELECT cal_setting FROM webcal_config " . 417 "WHERE cal_setting LIKE '%.plugin_status'"; 418 if ( ! $include_disabled ) 419 $sql .= " AND cal_value = 'Y'"; 420 $sql .= " ORDER BY cal_setting"; 421 $res = dbi_query ( $sql ); 422 $plugins = array (); 423 if ( $res ) { 424 while ( $row = dbi_fetch_row ( $res ) ) { 425 $e = explode ( ".", $row[0] ); 426 if ( $e[0] != "" ) { 427 $plugins[] = $e[0]; 428 } 429 } 430 dbi_free_result ( $res ); 431 } else { 432 echo translate("Database error") . ": " . dbi_error (); exit; 433 } 434 if ( count ( $plugins ) == 0 ) { 435 $plugins[] = "webcalendar"; 436 } 437 return $plugins; 438 } 439 440 /** 441 * Get plugins available to the current user. 442 * 443 * Do this by getting a list of all plugins that are not disabled by the 444 * administrator and make sure this user has not disabled any of them. 445 * 446 * It's done this was so that when an admin adds a new plugin, it shows up on 447 * each users system automatically (until they disable it). 448 * 449 * @return array Plugins available to current user 450 * 451 * @ignore 452 */ 453 function get_user_plugin_list () { 454 $ret = array (); 455 $all_plugins = get_plugin_list (); 456 for ( $i = 0; $i < count ( $all_plugins ); $i++ ) { 457 if ( $GLOBALS[$all_plugins[$i] . ".disabled"] != "N" ) 458 $ret[] = $all_plugins[$i]; 459 } 460 return $ret; 461 } 462 463 /** 464 * Identify user's browser. 465 * 466 * Returned value will be one of: 467 * - "Mozilla/5" = Mozilla (open source Mozilla 5.0) 468 * - "Mozilla/[3,4]" = Netscape (3.X, 4.X) 469 * - "MSIE 4" = MSIE (4.X) 470 * 471 * @return string String identifying browser 472 * 473 * @ignore 474 */ 475 function get_web_browser () { 476 if ( ereg ( "MSIE [0-9]", getenv ( "HTTP_USER_AGENT" ) ) ) 477 return "MSIE"; 478 if ( ereg ( "Mozilla/[234]", getenv ( "HTTP_USER_AGENT" ) ) ) 479 return "Netscape"; 480 if ( ereg ( "Mozilla/[5678]", getenv ( "HTTP_USER_AGENT" ) ) ) 481 return "Mozilla"; 482 return "Unknown"; 483 } 484 485 486 /** 487 * Logs a debug message. 488 * 489 * Generally, we do not leave calls to this function in the code. It is used 490 * for debugging only. 491 * 492 * @param string $msg Text to be logged 493 */ 494 function do_debug ( $msg ) { 495 // log to /tmp/webcal-debug.log 496 //error_log ( date ( "Y-m-d H:i:s" ) . "> $msg\n", 497 // 3, "/tmp/webcal-debug.log" ); 498 //error_log ( date ( "Y-m-d H:i:s" ) . "> $msg\n", 499 // 2, "sockieman:2000" ); 500 } 501 502 /** 503 * Gets user's preferred view. 504 * 505 * The user's preferred view is stored in the $STARTVIEW global variable. This 506 * is loaded from the user preferences (or system settings if there are no user 507 * prefererences.) 508 * 509 * @param string $indate Date to pass to preferred view in YYYYMMDD format 510 * @param string $args Arguments to include in the URL (such as "user=joe") 511 * 512 * @return string URL of the user's preferred view 513 */ 514 function get_preferred_view ( $indate="", $args="" ) { 515 global $STARTVIEW, $thisdate; 516 517 $url = empty ( $STARTVIEW ) ? "month.php" : $STARTVIEW; 518 // We used to just store "month" in $STARTVIEW without the ".php" 519 // This is just to prevent users from getting a "404 not found" if 520 // they have not updated their preferences. 521 if ( $url == "month" || $url == "day" || $url == "week" || $url == "year" ) 522 $url .= ".php"; 523 524 $url = str_replace ( '&', '&', $url ); 525 $url = str_replace ( '&', '&', $url ); 526 527 $xdate = empty ( $indate ) ? $thisdate : $indate; 528 if ( ! empty ( $xdate ) ) { 529 if ( strstr ( $url, "?" ) ) 530 $url .= '&' . "date=$xdate"; 531 else 532 $url .= '?' . "date=$xdate"; 533 } 534 535 if ( ! empty ( $args ) ) { 536 if ( strstr ( $url, "?" ) ) 537 $url .= '&' . $args; 538 else 539 $url .= '?' . $args; 540 } 541 542 return $url; 543 } 544 545 /** 546 * Sends a redirect to the user's preferred view. 547 * 548 * The user's preferred view is stored in the $STARTVIEW global variable. This 549 * is loaded from the user preferences (or system settings if there are no user 550 * prefererences.) 551 * 552 * @param string $indate Date to pass to preferred view in YYYYMMDD format 553 * @param string $args Arguments to include in the URL (such as "user=joe") 554 */ 555 function send_to_preferred_view ( $indate="", $args="" ) { 556 $url = get_preferred_view ( $indate, $args ); 557 do_redirect ( $url ); 558 } 559 560 /** Sends a redirect to the specified page. 561 * 562 * The database connection is closed and execution terminates in this function. 563 * 564 * <b>Note:</b> MS IIS/PWS has a bug in which it does not allow us to send a 565 * cookie and a redirect in the same HTTP header. When we detect that the web 566 * server is IIS, we accomplish the redirect using meta-refresh. See the 567 * following for more info on the IIS bug: 568 * 569 * {@link http://www.faqts.com/knowledge_base/view.phtml/aid/9316/fid/4} 570 * 571 * @param string $url The page to redirect to. In theory, this should be an 572 * absolute URL, but all browsers accept relative URLs (like 573 * "month.php"). 574 * 575 * @global string Type of webserver 576 * @global array Server variables 577 * @global resource Database connection 578 */ 579 function do_redirect ( $url ) { 580 global $SERVER_SOFTWARE, $_SERVER, $c; 581 582 // Replace any '&' with '&' since we don't want that in the HTTP 583 // header. 584 $url = str_replace ( '&', '&', $url ); 585 586 if ( empty ( $SERVER_SOFTWARE ) ) 587 $SERVER_SOFTWARE = $_SERVER["SERVER_SOFTWARE"]; 588 //echo "SERVER_SOFTWARE = $SERVER_SOFTWARE <br />\n"; exit; 589 if ( ( substr ( $SERVER_SOFTWARE, 0, 5 ) == "Micro" ) || 590 ( substr ( $SERVER_SOFTWARE, 0, 3 ) == "WN/" ) ) { 591 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html 592 PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" 593 \"DTD/xhtml1-transitional.dtd\"> 594 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"> 595 <head>\n<title>Redirect</title>\n" . 596 "<meta http-equiv=\"refresh\" content=\"0; url=$url\" />\n</head>\n<body>\n" . 597 "Redirecting to.. <a href=\"" . $url . "\">here</a>.</body>\n</html>"; 598 } else { 599 Header ( "Location: $url" ); 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 ... <a href=\"" . $url . "\">here</a>.</body>\n</html>"; 606 } 607 dbi_close ( $c ); 608 exit; 609 } 610 611 /** 612 * Sends an HTTP login request to the browser and stops execution. 613 */ 614 function send_http_login () { 615 global $lang_file, $application_name; 616 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>"; 628 } else { 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>"; 639 } 640 exit; 641 } 642 643 /** 644 * Generates a cookie that saves the last calendar view. 645 * 646 * Cookie is based on the current <var>$REQUEST_URI</var>. 647 * 648 * We save this cookie so we can return to this same page after a user 649 * edits/deletes/etc an event. 650 * 651 * @global string Request string 652 */ 653 function remember_this_view () { 654 global $REQUEST_URI; 655 if ( empty ( $REQUEST_URI ) ) 656 $REQUEST_URI = $_SERVER["REQUEST_URI"]; 657 658 // do not use anything with friendly in the URI 659 if ( strstr ( $REQUEST_URI, "friendly=" ) ) 660 return; 661 662 SetCookie ( "webcalendar_last_view", $REQUEST_URI ); 663 } 664 665 /** 666 * Gets the last page stored using {@link remember_this_view()}. 667 * 668 * @return string The URL of the last view or an empty string if it cannot be 669 * determined. 670 * 671 * @global array Cookies 672 */ 673 function get_last_view () { 674 global $HTTP_COOKIE_VARS; 675 $val = ''; 676 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"]; 682 } 683 $val = str_replace ( "&", "&", $val ); 684 return $val; 685 } 686 687 /** 688 * Sends HTTP headers that tell the browser not to cache this page. 689 * 690 * Different browser use different mechanisms for this, so a series of HTTP 691 * header directives are sent. 692 * 693 * <b>Note:</b> This function needs to be called before any HTML output is sent 694 * to the browser. 695 */ 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" ); 702 } 703 704 /** 705 * Loads the current user's preferences as global variables from the webcal_user_pref table. 706 * 707 * Also loads the list of views for this user (not really a preference, but 708 * this is a convenient place to put this...) 709 * 710 * <b>Notes:</b> 711 * - If <var>$allow_color_customization</var> is set to 'N', then we ignore any 712 * color preferences. 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 715 * system settings. 716 */ 717 function load_user_preferences () { 718 global $login, $browser, $views, $prefarray, $is_assistant, 719 $has_boss, $user, $is_nonuser_admin, $allow_color_customization; 720 $lang_found = false; 721 $colors = array ( 722 "BGCOLOR" => 1, 723 "H2COLOR" => 1, 724 "THBG" => 1, 725 "THFG" => 1, 726 "CELLBG" => 1, 727 "TODAYCELLBG" => 1, 728 "WEEKENDBG" => 1, 729 "POPUP_BG" => 1, 730 "POPUP_FG" => 1, 731 ); 732 733 $browser = get_web_browser (); 734 $browser_lang = get_browser_language (); 735 $prefarray = array (); 736 737 // Note: default values are set in config.php 738 $res = dbi_query ( 739 "SELECT cal_setting, cal_value FROM webcal_user_pref " . 740 "WHERE cal_login = '$login'" ); 741 if ( $res ) { 742 while ( $row = dbi_fetch_row ( $res ) ) { 743 $setting = $row[0]; 744 $value = $row[1]; 745 if ( $allow_color_customization == 'N' ) { 746 if ( isset ( $colors[$setting] ) ) 747 continue; 748 } 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" ) 756 $lang_found = true; 757 } 758 dbi_free_result ( $res ); 759 } 760 // get views for this user and global views 761 $res = dbi_query ( 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" ); 766 if ( $res ) { 767 $views = array (); 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]"; 773 else 774 $url = "view_" . strtolower ( $row[2] ) . ".php?id=$row[0]"; 775 $v = array ( 776 "cal_view_id" => $row[0], 777 "cal_name" => $row[1], 778 "cal_view_type" => $row[2], 779 "cal_is_global" => $row[3], 780 "url" => $url 781 ); 782 $views[] = $v; 783 } 784 dbi_free_result ( $res ); 785 } 786 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' )" ); 795 } 796 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); 806 } 807 808 /** 809 * Gets the list of external users for an event from the webcal_entry_ext_user table in an HTML format. 810 * 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. 814 * 815 * @return string The list of external users for an event formatte in HTML. 816 */ 817 function event_get_external_users ( $event_id, $use_mailto=0 ) { 818 global $error; 819 $ret = ""; 820 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" ); 825 if ( $res ) { 826 while ( $row = dbi_fetch_row ( $res ) ) { 827 if ( strlen ( $ret ) ) 828 $ret .= "\n"; 829 // Remove [\d] if duplicate name 830 $trow = trim( preg_replace( '/\[[\d]]/' , "", $row[0] ) ); 831 $ret .= $trow; 832 if ( strlen ( $row[1] ) ) { 833 if ( $use_mailto ) { 834 $ret .= " <a href=\"mailto:$row[1]\"><" . 835 htmlentities ( $row[1] ) . "></a>"; 836 } else { 837 $ret .= " <". htmlentities ( $row[1] ) . ">"; 838 } 839 } 840 } 841 dbi_free_result ( $res ); 842 } else { 843 echo translate("Database error") .": " . dbi_error (); 844 echo "<br />\nSQL:<br />\n$sql"; 845 exit; 846 } 847 return $ret; 848 } 849 850 /** 851 * Adds something to the activity log for an event. 852 * 853 * The information will be saved to the webcal_entry_log table. 854 * 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: 859 * - $LOG_CREATE 860 * - $LOG_APPROVE 861 * - $LOG_REJECT 862 * - $LOG_UPDATE 863 * - $LOG_DELETE 864 * - $LOG_NOTIFICATION 865 * - $LOG_REMINDER 866 * @param string $text Text comment to add with activity log entry 867 */ 868 function activity_log ( $event_id, $user, $user_cal, $type, $text ) { 869 $next_id = 1; 870 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 874 return; 875 } 876 877 $res = dbi_query ( "SELECT MAX(cal_log_id) FROM webcal_entry_log" ); 878 if ( $res ) { 879 if ( $row = dbi_fetch_row ( $res ) ) { 880 $next_id = $row[0] + 1; 881 } 882 dbi_free_result ( $res ); 883 } 884 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'"; 889 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"; 897 exit; 898 } 899 } 900 901 /** 902 * Gets a list of users. 903 * 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). 909 * 910 * @return array Array of users, where each element in the array is an array 911 * with the following keys: 912 * - cal_login 913 * - cal_lastname 914 * - cal_firstname 915 * - cal_is_admin 916 * - cal_is_admin 917 * - cal_email 918 * - cal_password 919 * - cal_fullname 920 */ 921 function get_my_users () { 922 global $login, $is_admin, $groups_enabled, $user_sees_only_his_groups; 923 924 if ( $groups_enabled == "Y" && $user_sees_only_his_groups == "Y" && 925 ! $is_admin ) { 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'" ); 929 $groups = array (); 930 if ( $res ) { 931 while ( $row = dbi_fetch_row ( $res ) ) { 932 $groups[] = $row[0]; 933 } 934 dbi_fetch_row ( $res ); 935 } 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]; 941 } 942 $ret = array (); 943 if ( count ( $groups ) == 0 ) { 944 // Eek. User is in no groups... Return only themselves 945 $ret[] = $u_byname[$login]; 946 return $ret; 947 } 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]; 954 else { 955 $sql .= "IN ( " . implode ( ", ", $groups ) . " )"; 956 } 957 $sql .= " ORDER BY cal_lastname, cal_firstname, webcal_group_user.cal_login"; 958 //echo "SQL: $sql <br />\n"; 959 $res = dbi_query ( $sql ); 960 if ( $res ) { 961 while ( $row = dbi_fetch_row ( $res ) ) { 962 $ret[] = $u_byname[$row[0]]; 963 } 964 dbi_free_result ( $res ); 965 } 966 return $ret; 967 } else { 968 // groups not enabled... return all users 969 //echo "No groups. "; 970 return user_get_users (); 971 } 972 } 973 974 /** 975 * Gets a preference setting for the specified user. 976 * 977 * If no value is found in the database, then the system default setting will 978 * be returned. 979 * 980 * @param string $user User login we are getting preference for 981 * @param string $setting Name of the setting 982 * 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 985 * was found. 986 */ 987 function get_pref_setting ( $user, $setting ) { 988 $ret = ''; 989 // set default 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]; 994 } else { 995 $ret = $GLOBALS["sys_" .$setting]; 996 } 997 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 ); 1003 if ( $res ) { 1004 if ( $row = dbi_fetch_row ( $res ) ) 1005 $ret = $row[0]; 1006 dbi_free_result ( $res ); 1007 } 1008 return $ret; 1009 } 1010 1011 /** 1012 * Gets browser-specified language preference. 1013 * 1014 * @return string Preferred language 1015 * 1016 * @ignore 1017 */ 1018 function get_browser_language () { 1019 global $HTTP_ACCEPT_LANGUAGE, $browser_languages; 1020 $ret = ""; 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 ) ) { 1025 return "none"; 1026 } else { 1027 $langs = explode ( ",", $HTTP_ACCEPT_LANGUAGE ); 1028 for ( $i = 0; $i < count ( $langs ); $i++ ) { 1029 $l = strtolower ( trim ( ereg_replace(';.*', '', $langs[$i] ) ) ); 1030 $ret .= "\"$l\" "; 1031 if ( ! empty ( $browser_languages[$l] ) ) { 1032 return $browser_languages[$l]; 1033 } 1034 } 1035 } 1036 //if ( strlen ( $HTTP_ACCEPT_LANGUAGE ) ) 1037 // return "none ($HTTP_ACCEPT_LANGUAGE not supported)"; 1038 //else 1039 return "none"; 1040 } 1041 1042 /** 1043 * Loads current user's layer info into layer global variable. 1044 * 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. 1048 * 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. 1052 */ 1053 function load_user_layers ($user="",$force=0) { 1054 global $login; 1055 global $layers; 1056 global $LAYERS_STATUS, $allow_view_other; 1057 1058 if ( $user == "" ) 1059 $user = $login; 1060 1061 $layers = array (); 1062 1063 if ( empty ( $allow_view_other ) || $allow_view_other != 'Y' ) 1064 return; // not allowed to view others' calendars, so cannot use layers 1065 1066 if ( $force || ( ! empty ( $LAYERS_STATUS ) && $LAYERS_STATUS != "N" ) ) { 1067 $res = dbi_query ( 1068 "SELECT cal_layerid, cal_layeruser, cal_color, cal_dups " . 1069 "FROM webcal_user_layers " . 1070 "WHERE cal_login = '$user' ORDER BY cal_layerid" ); 1071 if ( $res ) { 1072 $count = 1; 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] 1079 ); 1080 $count++; 1081 } 1082 dbi_free_result ( $res ); 1083 } 1084 } else { 1085 //echo "Not loading!"; 1086 } 1087 } 1088 1089 /** 1090 * Generates the HTML used in an event popup for the site_extras fields of an event. 1091 * 1092 * @param int $id Event ID 1093 * 1094 * @return string The HTML to be used within the event popup for any site_extra 1095 * fields found for the specified event 1096 */ 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 1100 // included. 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; 1105 1106 $ret = ''; 1107 1108 if ( $site_extras_in_popup != 'Y' ) 1109 return ''; 1110 1111 include_once 'includes/site_extras.php'; 1112 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" ); 1130 else { 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 ); 1142 if ( $d > 0 ) 1143 $ret .= $d . " " . translate("days") . " "; 1144 if ( $h > 0 ) 1145 $ret .= $h . " " . translate("hours") . " "; 1146 if ( $minutes > 0 ) 1147 $ret .= $minutes . " " . translate("minutes"); 1148 $ret .= " " . translate("before event" ); 1149 } 1150 } 1151 } else { 1152 $ret .= $extras[$extra_name]['cal_data']; 1153 } 1154 $ret .= "</dd>\n"; 1155 } 1156 } 1157 return $ret; 1158 } 1159 1160 /** 1161 * Builds the HTML for the event popup. 1162 * 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 1168 * 1169 * @return string The HTML for the event popup 1170 */ 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"; 1174 1175 if ( empty ( $popup_fullnames ) ) 1176 $popup_fullnames = array (); 1177 1178 if ( $user != $login ) { 1179 if ( empty ( $popup_fullnames[$user] ) ) { 1180 user_load_variables ( $user, "popuptemp_" ); 1181 $popup_fullnames[$user] = $popuptemp_fullname; 1182 } 1183 $ret .= "<dt>" . translate ("User") . 1184 ":</dt>\n<dd>$popup_fullnames[$user]</dd>\n"; 1185 } 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... 1197 $ret .= $str; 1198 } else { 1199 // no html, replace line breaks 1200 $ret .= nl2br ( $str ); 1201 } 1202 } else { 1203 // html not allowed in description, escape everything 1204 $ret .= nl2br ( htmlspecialchars ( $description ) ); 1205 } 1206 $ret .= "</dd>\n"; 1207 if ( ! empty ( $site_extras ) ) 1208 $ret .= $site_extras; 1209 $ret .= "</dl>\n"; 1210 return $ret; 1211 } 1212 1213 /** 1214 * Prints out a date selection box for use in a form. 1215 * 1216 * @param string $prefix Prefix to use in front of form element names 1217 * @param int $date Currently selected date (in YYYYMMDD format) 1218 * 1219 * @uses date_selection_html 1220 */ 1221 function print_date_selection ( $prefix, $date ) { 1222 print date_selection_html ( $prefix, $date ); 1223 } 1224 1225 /** 1226 * Generate HTML for a date selection for use in a form. 1227 * 1228 * @param string $prefix Prefix to use in front of form element names 1229 * @param int $date Currently selected date (in YYYYMMDD format) 1230 * 1231 * @return string HTML for the selection box 1232 */ 1233 function date_selection_html ( $prefix, $date ) { 1234 $ret = ""; 1235 $num_years = 20; 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"; 1252 } 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"; 1258 } 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"; 1263 1264 return $ret; 1265 } 1266 1267 /** 1268 * Prints out a minicalendar for a month. 1269 * 1270 * @todo Make day.php NOT be a special case 1271 * 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&) 1280 */ 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; 1287 1288 if ( $user != $login && ! empty ( $user ) ) { 1289 $u_url = "user=$user" . "&"; 1290 } else { 1291 $u_url = ''; 1292 } 1293 1294 //start the minical table for each month 1295 echo "\n<table class=\"minical\""; 1296 if ( $minical_id != '' ) { 1297 echo " id=\"$minical_id\""; 1298 } 1299 echo ">\n"; 1300 1301 $monthstart = mktime(2,0,0,$thismonth,1,$thisyear); 1302 $monthend = mktime(2,0,0,$thismonth + 1,0,$thisyear); 1303 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 ) ); 1309 1310 echo "<caption>$thisday</caption>\n"; 1311 echo "<thead>\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 != '' ) { 1323 echo " $thisyear"; 1324 } 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"; 1332 1333 echo "<thead>\n<tr>\n"; 1334 } 1335 1336 //determine if the week starts on sunday or monday 1337 if ( $WEEK_START == "1" ) { 1338 $wkstart = get_monday_before ( $thisyear, $thismonth, 1 ); 1339 } else { 1340 $wkstart = get_sunday_before ( $thisyear, $thismonth, 1 ); 1341 } 1342 //print the headers to display the day of the week (sun, mon, tues, etc.) 1343 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"; 1353 } 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) ) { 1361 echo "<tr>\n"; 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"; 1365 } 1366 for ($j = 0; $j < 7; $j++) { 1367 $date = $i + ($j * 24 * 3600); 1368 $dateYmd = date ( "Ymd", $date ); 1369 $hasEvents = false; 1370 if ( $boldDays ) { 1371 $ev = get_entries ( $user, $dateYmd, $get_unapproved ); 1372 if ( count ( $ev ) > 0 ) { 1373 $hasEvents = true; 1374 } else { 1375 $rep = get_repeating_entries ( $user, $dateYmd, $get_unapproved ); 1376 if ( count ( $rep ) > 0 ) 1377 $hasEvents = true; 1378 } 1379 } 1380 if ( $dateYmd >= date ("Ymd",$monthstart) && 1381 $dateYmd <= date ("Ymd",$monthend) ) { 1382 echo "<td"; 1383 $wday = date ( 'w', $date ); 1384 $class = ''; 1385 //add class="weekend" if it's saturday or sunday 1386 if ( $wday == 0 || $wday == 6 ) { 1387 $class = "weekend"; 1388 } 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 != '' ) { 1394 $class .= ' '; 1395 } 1396 $class .= "selectedday"; 1397 } 1398 if ( $hasEvents ) { 1399 if ( $class != '' ) { 1400 $class .= ' '; 1401 } 1402 $class .= "hasevents"; 1403 } 1404 if ( $class != '' ) { 1405 echo " class=\"$class\""; 1406 } 1407 if ( date ( "Ymd", $date ) == date ( "Ymd", $today ) ){ 1408 echo " id=\"today\""; 1409 } 1410 echo "><a href=\"day.php?" .$u_url . "date=" . $dateYmd . 1411 "\">"; 1412 echo date ( "d", $date ) . "</a></td>\n"; 1413 } else { 1414 echo "<td class=\"empty\"> </td>\n"; 1415 } 1416 } // end for $j 1417 echo "</tr>\n"; 1418 } // end for $i 1419 echo "</tbody>\n</table>\n"; 1420 } 1421 1422 /** 1423 * Prints the HTML for one day's events in the month view. 1424 * 1425 * @param int $id Event ID 1426 * @param int $date Date of event (relevant in repeating events) in 1427 * YYYYMMDD format 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> 1437 * 1438 * @staticvar int Used to ensure all event popups have a unique id 1439 * 1440 * @uses build_event_popup 1441 */ 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; 1446 static $key = 0; 1447 1448 global $layers; 1449 1450 if ( $login != $event_owner && strlen ( $event_owner ) ) { 1451 $class = "layerentry"; 1452 } else { 1453 $class = "entry"; 1454 if ( $status == "W" ) $class = "unapprovedentry"; 1455 } 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" ) ) 1461 $class = "entry"; 1462 1463 if ( $pri == 3 ) echo "<strong>"; 1464 $popupid = "eventinfo-$id-$key"; 1465 $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"; 1474 $catIcon = ''; 1475 if ( $event_cat > 0 ) { 1476 $catIcon = "icons/cat-" . $event_cat . ".gif"; 1477 if ( ! file_exists ( $catIcon ) ) 1478 $catIcon = ''; 1479 } 1480 1481 if ( empty ( $catIcon ) ) { 1482 echo "<img src=\"$icon\" class=\"bullet\" alt=\"" . 1483 translate("View this entry") . "\" />"; 1484 } else { 1485 // Use category icon 1486 echo "<img src=\"$catIcon\" alt=\"" . 1487 translate("View this entry") . "\" /><br />"; 1488 } 1489 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'] . ";\">"); 1494 } 1495 } 1496 } 1497 1498 1499 $timestr = ""; 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 ) { 1507 // calc end time 1508 $h = (int) ( $time / 10000 ); 1509 $m = ( $time / 100 ) % 100; 1510 $m += $duration; 1511 $d = $duration; 1512 while ( $m >= 60 ) { 1513 $h++; 1514 $m -= 60; 1515 } 1516 $end_time = sprintf ( "%02d%02d00", $h, $m ); 1517 $timestr .= " - " . display_time ( $end_time ); 1518 } 1519 } 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") . ")"; 1525 } else { 1526 echo htmlspecialchars ( $name ); 1527 } 1528 1529 if ( $login != $event_owner && strlen ( $event_owner ) ) { 1530 if ($layers) foreach ($layers as $layer) { 1531 if($layer['cal_layeruser'] == $event_owner) { 1532 echo "</span>"; 1533 } 1534 } 1535 } 1536 echo "</a>\n"; 1537 if ( $pri == 3 ) echo "</strong>\n"; //end font-weight span 1538 echo "<br />"; 1539 if ( $login != $user && $access == 'R' && strlen ( $user ) ) 1540 $eventinfo .= build_event_popup ( $popupid, $event_owner, 1541 translate("This event is confidential"), "" ); 1542 else 1543 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) ) 1544 $eventinfo .= build_event_popup ( $popupid, $event_owner, 1545 translate("This event is confidential"), "" ); 1546 else 1547 $eventinfo .= build_event_popup ( $popupid, $event_owner, 1548 $description, $timestr, site_extras_for_popup ( $id ) ); 1549 } 1550 1551 /** 1552 * Gets any site-specific fields for an entry that are stored in the database in the webcal_site_extras table. 1553 * 1554 * @param int $eventid Event ID 1555 * 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> 1562 */ 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 ); 1568 $extras = array (); 1569 if ( $res ) { 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] 1578 ); 1579 } 1580 dbi_free_result ( $res ); 1581 } 1582 return $extras; 1583 } 1584 1585 /** 1586 * Reads all the events for a user for the specified range of dates. 1587 * 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 1590 * (not date). 1591 * 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 1596 * 1597 * @return array Array of events 1598 * 1599 * @uses query_events 1600 */ 1601 function read_events ( $user, $startdate, $enddate, $cat_id = '' ) { 1602 global $login; 1603 global $layers; 1604 global $TZ_OFFSET; 1605 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 ) )"; 1623 } else { 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 ) )"; 1631 } 1632 } else { 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 ) )"; 1649 } else { 1650 // TZ_OFFSET < 0 1651 $next_day = date ( ( "Ymd" ), mktime ( 3, 0, 0, $sm, $sd + 1, $sy ) ); 1652 $enddate_plus1 = 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 ) )"; 1664 } 1665 } 1666 return query_events ( $user, false, $date_filter, $cat_id ); 1667 } 1668 1669 /** 1670 * Gets all the events for a specific date. 1671 * 1672 * Events are retreived from the array of pre-loaded events (which was loaded 1673 * all at once to improve performance). 1674 * 1675 * The returned events will be sorted by time of day. 1676 * 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? 1680 * 1681 * @return array Array of events 1682 */ 1683 function get_entries ( $user, $date, $get_unapproved=true ) { 1684 global $events, $TZ_OFFSET; 1685 $n = 0; 1686 $ret = array (); 1687 1688 //echo "<br />\nChecking " . count ( $events ) . " events. TZ_OFFSET = $TZ_OFFSET, get_unapproved=" . $get_unapproved . "<br />\n"; 1689 1690 //print_r ( $events ); 1691 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'] ) ) 1695 continue; 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"; 1722 } 1723 } else { 1724 //TZ < 0 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"; 1736 } 1737 } else { 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"; 1746 } 1747 } 1748 } 1749 } 1750 return $ret; 1751 } 1752 1753 /** 1754 * Reads events visible to a user. 1755 * 1756 * Includes layers and possibly public access if enabled 1757 * 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. 1763 * 1764 * @return array Array of events sorted by time of day 1765 */ 1766 function query_events ( $user, $want_repeated, $date_filter, $cat_id = '' ) { 1767 global $login; 1768 global $layers, $public_access_default_visible; 1769 $result = array (); 1770 $layers_byuser = array (); 1771 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 ) { 1781 $sql .= ", " 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 "; 1786 } else { 1787 $sql .= "FROM webcal_entry, webcal_entry_user WHERE "; 1788 } 1789 $sql .= "webcal_entry.cal_id = webcal_entry_user.cal_id " . 1790 "AND webcal_entry_user.cal_status IN ('A','W') "; 1791 1792 if ( $cat_id != '' ) $sql .= "AND webcal_entry_user.cal_category LIKE '$cat_id' "; 1793 1794 if ( strlen ( $user ) > 0 ) 1795 $sql .= "AND (webcal_entry_user.cal_login = '" . $user . "' "; 1796 1797 if ( $user == $login && strlen ( $user ) > 0 ) { 1798 if ($layers) foreach ($layers as $layer) { 1799 $layeruser = $layer['cal_layeruser']; 1800 1801 $sql .= "OR webcal_entry_user.cal_login = '" . $layeruser . "' "; 1802 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']; 1806 } 1807 } 1808 if ( $user == $login && strlen ( $user ) && 1809 $public_access_default_visible == 'Y' ) { 1810 $sql .= "OR webcal_entry_user.cal_login = '__public__' "; 1811 } 1812 if ( strlen ( $user ) > 0 ) 1813 $sql .= ") "; 1814 $sql .= $date_filter; 1815 1816 // now order the results by time and by entry id. 1817 $sql .= " ORDER BY webcal_entry.cal_time, webcal_entry.cal_id"; 1818 1819 //echo "<strong>SQL:</strong> $sql<br />\n"; 1820 1821 $res = dbi_query ( $sql ); 1822 if ( $res ) { 1823 $i = 0; 1824 $checkdup_id = -1; 1825 $first_i_this_id = -1; 1826 1827 while ( $row = dbi_fetch_row ( $res ) ) { 1828 1829 if ($row[9] == 'R' || $row[9] == 'D') { 1830 continue; // don't show rejected/deleted ones 1831 } 1832 $item = array ( 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() 1846 ); 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]; 1852 } 1853 1854 if ( $item['cal_id'] != $checkdup_id ) { 1855 $checkdup_id = $item['cal_id']; 1856 $first_i_this_id = $i; 1857 } 1858 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) ); 1862 $i++; 1863 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, "" ); 1871 $i--; 1872 } 1873 } 1874 } else { 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; 1881 } 1882 } 1883 } 1884 dbi_free_result ( $res ); 1885 } 1886 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]; 1895 } 1896 } 1897 } 1898 } 1899 1900 return $result; 1901 } 1902 1903 /** 1904 * Reads all the repeated events for a user. 1905 * 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 1908 * date). 1909 * 1910 * This will load all the repeated events into memory. 1911 * 1912 * <b>Notes:</b> 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()}. 1917 * 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) 1922 * 1923 * @return Array of repeating events sorted by time of day 1924 * 1925 * @uses query_events 1926 */ 1927 function read_repeated_events ( $user, $cat_id = '', $date = '' ) { 1928 global $login; 1929 global $layers; 1930 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 ); 1933 } 1934 1935 /** 1936 * Returns all the dates a specific event will fall on accounting for the repeating. 1937 * 1938 * Any event with no end will be assigned one. 1939 * 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 1946 * 1947 * @return array Array of dates (in UNIX time format) 1948 */ 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; 1951 global $ONE_DAY; 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 ); 1956 if ($end=='NULL') { 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) { 1963 $thisyear++; 1964 $thismonth -= 12; 1965 } 1966 $realend = mktime(3,0,0,$thismonth,$thisday,$thisyear); 1967 } 1968 $ret = array(); 1969 $ret[0] = $date; 1970 //do iterative checking here. 1971 //I floored the $realend so I check it against the floored date 1972 if ($rpt_type && $currentdate < $realend) { 1973 $cdate = $date; 1974 if (!$freq) $freq = 1; 1975 $n = 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 ) ) 1981 $ret[$n++]=$cdate; 1982 $cdate += $ONE_DAY * $freq; 1983 } 1984 } else if ($rpt_type == 'weekly') { 1985 $daysarray = array(); 1986 $r=0; 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; 1993 } 1994 } 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]; 2000 if ($td >= $date) { 2001 if ( ! is_exception ( $td, $ex_days ) ) 2002 $ret[$n++] = $td; 2003 } 2004 } 2005 //skip to the next week in question. 2006 $cdate += ( $ONE_DAY * 7 ) * $freq; 2007 } 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); 2013 $thismonth+=$freq; 2014 //dow1 is the weekday that the 1st of the month falls on 2015 $dow1 = date('w',mktime (3,0,0,$thismonth,1,$thisyear)); 2016 $t = $dow - $dow1; 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; 2023 $thismonth+=$freq; 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 ); 2027 $t = $dow - $dow1; 2028 if ($t < 0) $t += 7; 2029 $day = 7*$week + $t + 1; 2030 $cdate = mktime (3,0,0,$thismonth,$day,$thisyear); 2031 } 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 ) { 2047 $thisyear++; 2048 $thismonth -= 12; 2049 } 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 ) - 2055 ( 7 * $whichWeek ); 2056 } else { 2057 // last weekday is NOT in last week of this month 2058 $day = $daysthismonth - ( $dowLast - $dow ) - 2059 ( 7 * ( $whichWeek + 1 ) ); 2060 } 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 ) { 2067 $thisyear++; 2068 $thismonth -= 12; 2069 } 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 ) - 2075 ( 7 * $whichWeek ); 2076 } else { 2077 // last weekday is NOT in last week of this month 2078 $day = $daysthismonth - ( $dowLast - $dow ) - 2079 ( 7 * ( $whichWeek + 1 ) ); 2080 } 2081 $cdate = mktime (3,0,0,$thismonth,$day,$thisyear); 2082 } 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); 2089 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); 2097 } 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); 2104 2105 $thisyear += $freq; 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; 2110 $thisyear += $freq; 2111 $cdate = mktime (3,0,0,$thismonth,$thisday,$thisyear); 2112 } 2113 } 2114 } 2115 return $ret; 2116 } 2117 2118 /** 2119 * Gets all the repeating events for the specified date. 2120 * 2121 * <b>Note:</b> 2122 * The global variable <var>$repeated_events</var> needs to be 2123 * set by calling {@link read_repeated_events()} first. 2124 * 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? 2128 * 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. 2132 * 2133 * @global array Array of repeating events retreived using {@link read_repeated_events()} 2134 */ 2135 function get_repeating_entries ( $user, $dateYmd, $get_unapproved=true ) { 2136 global $repeated_events; 2137 $n = 0; 2138 $ret = array (); 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]; 2147 } 2148 } 2149 } 2150 return $ret; 2151 } 2152 2153 /** 2154 * Determines whether the event passed in will fall on the date passed. 2155 * 2156 * @param array $event The event as an array 2157 * @param string $dateYmd Date to check in YYYYMMDD format 2158 * 2159 * @return bool Does <var>$event</var> occur on <var>$dateYmd</var>? 2160 */ 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 2164 // before the 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) ) 2172 return false; 2173 if ( $dateYmd <= date("Ymd",$start) ) 2174 return false; 2175 $id = $event['cal_id']; 2176 2177 if ($event['cal_type'] == 'daily') { 2178 if ( (floor(($date - $start)/$ONE_DAY)%$freq) ) 2179 return false; 2180 return true; 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) 2187 return false; 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 ) 2194 return false; 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 ) 2202 $whichWeekS++; 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 ) 2211 $whichWeek++; 2212 //echo "day=$day;dow=$dow;dow1=$dow1;wW=$whichWeek<br />\n"; 2213 2214 if ((($yr - $yrS)*12 + $mth - $mthS) % $freq) 2215 return false; 2216 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 ) 2223 return false; 2224 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 ); 2231 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 ); 2238 2239 if ((($yr - $yrS)*12 + $mth - $mthS) % $freq) 2240 return false; 2241 2242 return ( $whichWeekS == $whichWeek ); 2243 } else if ($event['cal_type'] == 'monthlyByDate') { 2244 $mthS = date("m", $start); 2245 $yrS = date("Y", $start); 2246 2247 $mth = date("m", $date); 2248 $yr = date("Y", $date); 2249 2250 if ((($yr - $yrS)*12 + $mth - $mthS) % $freq) 2251 return false; 2252 2253 return (date("d", $date) == date("d", $start)); 2254 } 2255 else if ($event['cal_type'] == 'yearly') { 2256 $yrS = date("Y", $start); 2257 $yr = date("Y", $date); 2258 2259 if (($yr - $yrS)%$freq) 2260 return false; 2261 2262 return (date("dm", $date) == date("dm", $start)); 2263 } else { 2264 // unknown repeat type 2265 return false; 2266 } 2267 return false; 2268 } 2269 2270 /** 2271 * Converts a date to a timestamp. 2272 * 2273 * @param string $d Date in YYYYMMDD format 2274 * 2275 * @return int Timestamp representing 3:00 (or 4:00 if during Daylight Saving 2276 * Time) in the morning on that day 2277 */ 2278 function date_to_epoch ( $d ) { 2279 if ( $d == 0 ) 2280 return 0; 2281 $T = mktime ( 3, 0, 0, substr ( $d, 4, 2 ), substr ( $d, 6, 2 ), substr ( $d, 0, 4 ) ); 2282 $lt = localtime($T); 2283 if ($lt[8]) { 2284 return mktime ( 4, 0, 0, substr ( $d, 4, 2 ), substr ( $d, 6, 2 ), substr ( $d, 0, 4 ) ); 2285 } else { 2286 return $T; 2287 } 2288 } 2289 2290 /** 2291 * Checks if a date is an exception for an event. 2292 * 2293 * @param string $date Date in YYYYMMDD format 2294 * @param array $exdays Array of dates in YYYYMMDD format 2295 * 2296 * @ignore 2297 */ 2298 function is_exception ( $date, $ex_days ) { 2299 $size = count ( $ex_days ); 2300 $count = 0; 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++] ) 2306 return true; 2307 } 2308 return false; 2309 } 2310 2311 /** 2312 * Gets the Sunday of the week that the specified date is in. 2313 * 2314 * If the date specified is a Sunday, then that date is returned. 2315 * 2316 * @param int $year Year 2317 * @param int $month Month (1-12) 2318 * @param int $day Day of the month 2319 * 2320 * @return int The date (in UNIX timestamp format) 2321 * 2322 * @see get_monday_before 2323 */ 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 ); 2327 return $newdate; 2328 } 2329 2330 /** 2331 * Gets the Monday of the week that the specified date is in. 2332 * 2333 * If the date specified is a Monday, then that date is returned. 2334 * 2335 * @param int $year Year 2336 * @param int $month Month (1-12) 2337 * @param int $day Day of the month 2338 * 2339 * @return int The date (in UNIX timestamp format) 2340 * 2341 * @see get_sunday_before 2342 */ 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 ); 2350 } 2351 2352 /** 2353 * Returns the week number for specified date. 2354 * 2355 * Depends on week numbering settings. 2356 * 2357 * @param int $date Date in UNIX timestamp format 2358 * 2359 * @return string The week number of the specified date 2360 */ 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); 2367 } 2368 2369 /** 2370 * Generates the HTML for an add/edit/delete icon. 2371 * 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. 2375 * 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? 2379 * 2380 * @return HTML for add/edit/delete icon. 2381 * 2382 * @ignore 2383 */ 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>"; 2399 return $ret; 2400 } 2401 2402 /** 2403 * Prints all the calendar entries for the specified user for the specified date. 2404 * 2405 * If we are displaying data from someone other than 2406 * the logged in user, then check the access permission of the entry. 2407 * 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? 2411 */ 2412 function print_date_entries ( $date, $user, $ssi ) { 2413 global $events, $readonly, $is_admin, $login, 2414 $public_access, $public_access_can_add, $cat_id; 2415 $cnt = 0; 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; 2420 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__" ) 2428 $can_add = false; 2429 if ( $readonly == 'Y' ) 2430 $can_add = false; 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>"; 2440 $cnt++; 2441 } 2442 if ( ! $ssi ) { 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\">"; 2458 echo "(" . 2459 translate("Week") . " " . week_number ( $dateu ) . ")</a>"; 2460 } 2461 print "<br />\n"; 2462 $cnt++; 2463 } 2464 2465 // get all the repeating events for this date and store in array $rep 2466 $rep = get_repeating_entries ( $user, $date, $get_unapproved ); 2467 $cur_rep = 0; 2468 2469 // get all the non-repeating events for this date and store in $ev 2470 $ev = get_entries ( $user, $date, $get_unapproved ); 2471 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.") . ")"; 2481 } else { 2482 $viewid = $rep[$cur_rep]['cal_id']; 2483 $viewname = $rep[$cur_rep]['cal_name']; 2484 } 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'] ); 2491 $cnt++; 2492 } 2493 $cur_rep++; 2494 } 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.") . ")"; 2500 } else { 2501 $viewid = $ev[$i]['cal_id']; 2502 $viewname = $ev[$i]['cal_name']; 2503 } 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'] ); 2510 $cnt++; 2511 } 2512 } 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.") . ")"; 2520 } else { 2521 $viewid = $rep[$cur_rep]['cal_id']; 2522 $viewname = $rep[$cur_rep]['cal_name']; 2523 } 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'] ); 2530 $cnt++; 2531 } 2532 $cur_rep++; 2533 } 2534 if ( $cnt == 0 ) 2535 echo " "; // so the table cell has at least something 2536 } 2537 2538 /** 2539 * Checks to see if two events overlap. 2540 * 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 2545 * 2546 * @return bool True if the two times overlap, false if they do not 2547 */ 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 ) 2557 $duration1 -= 1; 2558 if ( $duration2 > 0 ) 2559 $duration2 -= 1; 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 ) ) 2566 return false; 2567 return true; 2568 } 2569 2570 /** 2571 * Checks for conflicts. 2572 * 2573 * Find overlaps between an array of dates and the other dates in the database. 2574 * 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. 2578 * 2579 * @todo Update this to handle exceptions to repeating events 2580 * 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) 2590 * 2591 * @return Empty string for no conflicts or return the HTML of the 2592 * conflicts when one or more are found. 2593 */ 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; 2599 2600 $evtcnt = array (); 2601 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 " . 2609 "AND ("; 2610 for ($x = 0; $x < count($dates); $x++) { 2611 if ($x != 0) $sql .= " OR "; 2612 $sql.="webcal_entry.cal_date = " . date ( "Ymd", $dates[$x] ); 2613 } 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; 2621 } 2622 for ( $i = 0; $i < count ( $participants ); $i++ ) { 2623 if ( $i > 0 ) 2624 $sql .= " OR "; 2625 $sql .= " webcal_entry_user.cal_login = '" . $participants[$i] . "'"; 2626 } 2627 $sql .= " )"; 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"; 2631 $conflicts = ""; 2632 $res = dbi_query ( $sql ); 2633 $found = array(); 2634 $count = 0; 2635 if ( $res ) { 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 ) ) { 2643 $time2 = $row[1]; 2644 $duration2 = $row[2]; 2645 $cntkey = $row[0] . "-" . $row[8]; 2646 if ( empty ( $evtcnt[$cntkey] ) ) 2647 $evtcnt[$cntkey] = 0; 2648 else 2649 $evtcnt[$cntkey]++; 2650 $over_limit = 0; 2651 if ( $limit_appts == "Y" && $limit_appts_number > 0 2652 && $evtcnt[$cntkey] >= $limit_appts_number ) { 2653 $over_limit = 1; 2654 } 2655 if ( $over_limit || 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") . ")"; 2662 else { 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>"; 2667 } 2668 if ( $duration2 == ( 24 * 60 ) ) { 2669 $conflicts .= " (" . translate("All day event") . ")"; 2670 } else { 2671 $conflicts .= " (" . display_time ( $time2 ); 2672 if ( $duration2 > 0 ) 2673 $conflicts .= "-" . 2674 display_time ( add_duration ( $time2, $duration2 ) ); 2675 $conflicts .= ")"; 2676 } 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 . ")"; 2682 } 2683 $conflicts .= "</li>\n"; 2684 } 2685 } 2686 } 2687 dbi_free_result ( $res ); 2688 } else { 2689 echo translate("Database error") . ": " . dbi_error (); exit; 2690 } 2691 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 />"; 2707 //} 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... 2716 $row = $list[$j]; 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") . ")"; 2727 else { 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>"; 2732 } 2733 $conflicts .= " (" . display_time ( $time2 ); 2734 if ( $duration2 > 0 ) 2735 $conflicts .= "-" . 2736 display_time ( add_duration ( $time2, $duration2 ) ); 2737 $conflicts .= ")"; 2738 $conflicts .= " on " . date("l, F j, Y", $dates[$i]); 2739 $conflicts .= "</li>\n"; 2740 } 2741 } 2742 } 2743 } 2744 } 2745 2746 return $conflicts; 2747 } 2748 2749 /** 2750 * Converts a time format HHMMSS (like 130000 for 1PM) into number of minutes past midnight. 2751 * 2752 * @param string $time Input time in HHMMSS format 2753 * 2754 * @return int The number of minutes since midnight 2755 */ 2756 function time_to_minutes ( $time ) { 2757 $h = (int) ( $time / 10000 ); 2758 $m = (int) ( $time / 100 ) % 100; 2759 $num = $h * 60 + $m; 2760 return $num; 2761 } 2762 2763 /** 2764 * Calculates which row/slot this time represents. 2765 * 2766 * This is used in day and week views where hours of the time are separeted 2767 * into different cells in a table. 2768 * 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). 2772 * 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 2777 * also.) 2778 * 2779 * @return int The time slot index 2780 */ 2781 function calc_time_slot ( $time, $round_down = false ) { 2782 global $TIME_SLOTS, $TZ_OFFSET; 2783 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 ) 2789 $ret--; 2790 } 2791 //echo "$mins_since_midnight / $interval = $ret <br />\n"; 2792 if ( $ret > $TIME_SLOTS ) 2793 $ret = $TIME_SLOTS; 2794 2795 //echo "<br />\ncalc_time_slot($time) = $ret <br />\nTIME_SLOTS = $TIME_SLOTS<br />\n"; 2796 return $ret; 2797 } 2798 2799 /** 2800 * Generates the HTML for an icon to add a new event. 2801 * 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 2806 * 2807 * @return string The HTML for the add event icon 2808 */ 2809 function html_for_add_icon ( $date=0,$hour="", $minute="", $user="" ) { 2810 global $TZ_OFFSET; 2811 global $login, $readonly, $cat_id; 2812 $u_url = ''; 2813 2814 if ( $readonly == 'Y' ) 2815 return ''; 2816 2817 if ( $minute < 0 ) { 2818 $minute = abs($minute); 2819 $hour = $hour -1; 2820 } 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"; 2833 } 2834 2835 /** 2836 * Generates the HTML for an event to be viewed in the week-at-glance (week.php). 2837 * 2838 * The HTML will be stored in an array (global variable $hour_arr) 2839 * indexed on the event's starting hour. 2840 * 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 2852 */ 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; 2858 static $key = 0; 2859 global $DISPLAY_ICONS, $PHP_SELF, $TIME_SLOTS; 2860 global $layers; 2861 2862 $popupid = "eventinfo-day-$id-$key"; 2863 $key++; 2864 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 ) 2869 $first_slot = $ind; 2870 if ( $ind > $last_slot ) 2871 $last_slot = $ind; 2872 } else 2873 $ind = 9999; 2874 2875 if ( $login != $event_owner && strlen ( $event_owner ) ) { 2876 $class = "layerentry"; 2877 } else { 2878 $class = "entry"; 2879 if ( $status == "W" ) $class = "unapprovedentry"; 2880 } 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" ) ) 2886 $class = "entry"; 2887 2888 // avoid php warning for undefined array index 2889 if ( empty ( $hour_arr[$ind] ) ) 2890 $hour_arr[$ind] = ""; 2891 2892 $catIcon = "icons/cat-" . $event_category . ".gif"; 2893 if ( $event_category > 0 && file_exists ( $catIcon ) ) { 2894 $hour_arr[$ind] .= "<img src=\"$catIcon\" alt=\"$catIcon\" />"; 2895 } 2896 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;\">"; 2903 if ( $pri == 3 ) 2904 $hour_arr[$ind] .= "<strong>"; 2905 2906 if ( $login != $event_owner && strlen ( $event_owner ) ) { 2907 if ($layers) foreach ($layers as $layer) { 2908 if ( $layer['cal_layeruser'] == $event_owner ) { 2909 $in_span = true; 2910 $hour_arr[$ind] .= "<span style=\"color:" . $layer['cal_color'] . ";\">"; 2911 } 2912 } 2913 } 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 ) { 2920 // calc end time 2921 $h = (int) ( $time / 10000 ); 2922 $m = ( $time / 100 ) % 100; 2923 $m += $duration; 2924 $d = $duration; 2925 while ( $m >= 60 ) { 2926 $h++; 2927 $m -= 60; 2928 } 2929 $end_time = sprintf ( "%02d%02d00", $h, $m ); 2930 $timestr .= "-" . display_time ( $end_time ); 2931 } else { 2932 $end_time = 0; 2933 } 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 ) 2940 $rowspan = 0; 2941 else 2942 $rowspan = $endind - $ind + 1; 2943 if ( $rowspan > $rowspan_arr[$ind] && $rowspan > 1 ) 2944 $rowspan_arr[$ind] = $rowspan; 2945 } else { 2946 $timestr = ""; 2947 } 2948 2949 // avoid php warning of undefined index when using .= below 2950 if ( empty ( $hour_arr[$ind] ) ) 2951 $hour_arr[$ind] = ""; 2952 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 2962 } else { 2963 $hour_arr[$ind] .= htmlspecialchars ( $name ); 2964 } 2965 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 ); 2970 //} 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"), "" ); 2979 } else { 2980 $eventinfo .= build_event_popup ( $popupid, $event_owner, 2981 $description, $timestr, site_extras_for_popup ( $id ) ); 2982 } 2983 } 2984 2985 /** 2986 * Generates the HTML for an event to be viewed in the day-at-glance (day.php). 2987 * 2988 * The HTML will be stored in an array (global variable $hour_arr) 2989 * indexed on the event's starting hour. 2990 * 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 3002 */ 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; 3008 static $key = 0; 3009 global $layers, $PHP_SELF, $TIME_SLOTS, $TZ_OFFSET; 3010 3011 $popupid = "eventinfo-day-$id-$key"; 3012 $key++; 3013 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"), "" ); 3021 else 3022 $eventinfo .= build_event_popup ( $popupid, $event_owner, $description, 3023 "", site_extras_for_popup ( $id ) ); 3024 3025 // calculate slot length in minutes 3026 $interval = ( 60 * 24 ) / $TIME_SLOTS; 3027 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 ) 3032 $time -= 240000; 3033 else if ( $time + ( $TZ_OFFSET * 10000 ) < 0 ) 3034 $time += 240000; 3035 $ind = calc_time_slot ( $time ); 3036 if ( $ind < $first_slot ) 3037 $first_slot = $ind; 3038 if ( $ind > $last_slot ) 3039 $last_slot = $ind; 3040 } else 3041 $ind = 9999; 3042 //echo "time = $time <br />\nind = $ind <br />\nfirst_slot = $first_slot<br />\n"; 3043 3044 if ( empty ( $hour_arr[$ind] ) ) 3045 $hour_arr[$ind] = ""; 3046 3047 if ( $login != $event_owner && strlen ( $event_owner ) ) { 3048 $class = "layerentry"; 3049 } else { 3050 $class = "entry"; 3051 if ( $status == "W" ) 3052 $class = "unapprovedentry"; 3053 } 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" ) ) 3059 $class = "entry"; 3060 3061 $catIcon = "icons/cat-" . $event_category . ".gif"; 3062 if ( $event_category > 0 && file_exists ( $catIcon ) ) { 3063 $hour_arr[$ind] .= "<img src=\"$catIcon\" alt=\"$catIcon\" />"; 3064 } 3065 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>"; 3073 3074 if ( $login != $event_owner && strlen ( $event_owner ) ) { 3075 if ($layers) foreach ($layers as $layer) { 3076 if ( $layer['cal_layeruser'] == $event_owner) { 3077 $in_span = true; 3078 $hour_arr[$ind] .= "<span style=\"color:" . $layer['cal_color'] . ";\">"; 3079 } 3080 } 3081 } 3082 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 ) { 3088 // calc end time 3089 $h = (int) ( $time / 10000 ); 3090 $m = ( $time / 100 ) % 100; 3091 $m += $duration; 3092 $d = $duration; 3093 while ( $m >= 60 ) { 3094 $h++; 3095 $m -= 60; 3096 } 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 ) 3103 $rowspan = 0; 3104 else 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; 3110 } 3111 $hour_arr[$ind] .= "] "; 3112 } 3113 if ( $login != $user && $access == 'R' && strlen ( $user ) ) 3114 $hour_arr[$ind] .= "(" . translate("Private") . ")"; 3115 else 3116 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) ) 3117 $hour_arr[$ind] .= "(" . translate("Private") . ")"; 3118 else 3119 if ( $login != $event_owner && strlen ( $event_owner ) ) 3120 { 3121 $hour_arr[$ind] .= htmlspecialchars ( $name ); 3122 if ( ! empty ( $in_span ) ) 3123 $hour_arr[$ind] .= "</span>"; //end color span 3124 } 3125 3126 else 3127 $hour_arr[$ind] .= htmlspecialchars ( $name ); 3128 if ( $pri == 3 ) $hour_arr[$ind] .= "</strong>"; //end font-weight span 3129 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; 3143 } else { 3144 // no html, replace line breaks 3145 $hour_arr[$ind] .= nl2br ( $str ); 3146 } 3147 } else { 3148 // html not allowed in description, escape everything 3149 $hour_arr[$ind] .= nl2br ( htmlspecialchars ( $description ) ); 3150 } 3151 $hour_arr[$ind] .= "</dd>\n</dl>\n"; 3152 } 3153 3154 $hour_arr[$ind] .= "<br />\n"; 3155 } 3156 3157 /** 3158 * Prints all the calendar entries for the specified user for the specified date in day-at-a-glance format. 3159 * 3160 * If we are displaying data from someone other than 3161 * the logged in user, then check the access permission of the entry. 3162 * 3163 * @param string $date Date in YYYYMMDD format 3164 * @param string $user Username of calendar 3165 */ 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"; 3176 return; 3177 } 3178 3179 // $interval is number of minutes per slot 3180 $interval = ( 24 * 60 ) / $TIME_SLOTS; 3181 3182 $rowspan_arr = array (); 3183 for ( $i = 0; $i < $TIME_SLOTS; $i++ ) { 3184 $rowspan_arr[$i] = 0; 3185 } 3186 3187 // get all the repeating events for this date and store in array $rep 3188 $rep = get_repeating_entries ( $user, $date ); 3189 $cur_rep = 0; 3190 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 (); 3199 $all_day = 0; 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.") . ")"; 3209 } else { 3210 $viewid = $rep[$cur_rep]['cal_id']; 3211 $viewname = $rep[$cur_rep]['cal_name']; 3212 } 3213 if ( $rep[$cur_rep]['cal_duration'] == ( 24 * 60 ) ) 3214 $all_day = 1; 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'] ); 3221 } 3222 $cur_rep++; 3223 } 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.") . ")"; 3229 } else { 3230 $viewid = $ev[$i]['cal_id']; 3231 $viewname = $ev[$i]['cal_name']; 3232 } 3233 if ( $ev[$i]['cal_duration'] == ( 24 * 60 ) ) 3234 $all_day = 1; 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'] ); 3241 } 3242 } 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.") . ")"; 3250 } else { 3251 $viewid = $rep[$cur_rep]['cal_id']; 3252 $viewname = $rep[$cur_rep]['cal_name']; 3253 } 3254 if ( $rep[$cur_rep]['cal_duration'] == ( 24 * 60 ) ) 3255 $all_day = 1; 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'] ); 3262 } 3263 $cur_rep++; 3264 } 3265 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. 3269 $rowspan = 0; 3270 $last_row = -1; 3271 //echo "First SLot: $first_slot; Last Slot: $last_slot<br />\n"; 3272 $i = 0; 3273 if ( $first_slot < 0 ) 3274 $i = $first_slot; 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 ) ); 3282 } 3283 $rowspan += ( $rowspan_arr[$i] - 1 ); 3284 } else { 3285 $rowspan_arr[$last_row] += $rowspan_arr[$i]; 3286 } 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"; 3291 } 3292 $hour_arr[$last_row] .= $hour_arr[$i]; 3293 $hour_arr[$i] = ""; 3294 $rowspan_arr[$i] = 0; 3295 } 3296 $rowspan--; 3297 } else if ( ! empty ( $rowspan_arr[$i] ) && $rowspan_arr[$i] > 1 ) { 3298 $rowspan = $rowspan_arr[$i]; 3299 $last_row = $i; 3300 } 3301 } 3302 if ( ! empty ( $hour_arr[9999] ) ) { 3303 echo "<tr><th class=\"empty\"> </th>\n" . 3304 "<td class=\"hasevents\">$hour_arr[9999]</td></tr>\n"; 3305 } 3306 $rowspan = 0; 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\">"; 3318 if ( $can_add ) 3319 echo html_for_add_icon ( $date, $time_h, $time_m, $user ); 3320 echo "$hour_arr[$i]</td>\n"; 3321 } 3322 $rowspan--; 3323 } else { 3324 if ( empty ( $hour_arr[$i] ) ) { 3325 echo "<td>"; 3326 if ( $can_add ) { 3327 echo html_for_add_icon ( $date, $time_h, $time_m, $user ) . "</td>"; 3328 } else { 3329 echo " </td>"; 3330 } 3331 echo "</tr>\n"; 3332 } else { 3333 if ( empty ( $rowspan_arr[$i] ) ) 3334 $rowspan = ''; 3335 else 3336 $rowspan = $rowspan_arr[$i]; 3337 if ( $rowspan > 1 ) { 3338 echo "<td rowspan=\"$rowspan\" class=\"hasevents\">"; 3339 if ( $can_add ) 3340 echo html_for_add_icon ( $date, $time_h, $time_m, $user ); 3341 echo "$hour_arr[$i]</td></tr>\n"; 3342 } else { 3343 echo "<td class=\"hasevents\">"; 3344 if ( $can_add ) 3345 echo html_for_add_icon ( $date, $time_h, $time_m, $user ); 3346 echo "$hour_arr[$i]</td></tr>\n"; 3347 } 3348 } 3349 } 3350 } 3351 } 3352 3353 /** 3354 * Checks for any unnaproved events. 3355 * 3356 * If any are found, display a link to the unapproved events (where they can be 3357 * approved). 3358 * 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. 3361 * 3362 * @param string $user Current user login 3363 */ 3364 function display_unapproved_events ( $user ) { 3365 global $public_access, $is_admin, $nonuser_enabled, $login; 3366 3367 // Don't do this for public access login, admin user must approve public 3368 // events 3369 if ( $user == "__public__" ) 3370 return; 3371 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__'"; 3381 } 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'] . "'"; 3387 } 3388 } 3389 $sql .= " )"; 3390 //print "SQL: $sql<br />\n"; 3391 $res = dbi_query ( $sql ); 3392 if ( $res ) { 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"; 3401 } 3402 } 3403 dbi_free_result ( $res ); 3404 } 3405 } 3406 3407 /** 3408 * Looks for URLs in the given text, and makes them into links. 3409 * 3410 * @param string $text Input text 3411 * 3412 * @return string The text altered to have HTML links for any web links 3413 * (http or https) 3414 */ 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 ); 3420 return $str; 3421 } 3422 3423 /** 3424 * Displays a time in either 12 or 24 hour format. 3425 * 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. 3430 * 3431 * @param string $time Input time in HHMMSS format 3432 * @param bool $ignore_offset If true, then do not use the timezone offset 3433 * 3434 * @return string The time in the user's timezone and preferred format 3435 * 3436 * @global int The user's timezone offset from the server 3437 */ 3438 function display_time ( $time, $ignore_offset=0 ) { 3439 global $TZ_OFFSET; 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; 3446 while ( $hour < 0 ) 3447 $hour += 24; 3448 while ( $hour > 23 ) 3449 $hour -= 24; 3450 if ( $GLOBALS["TIME_FORMAT"] == "12" ) { 3451 $ampm = ( $hour >= 12 ) ? translate("pm") : translate("am"); 3452 $hour %= 12; 3453 if ( $hour == 0 ) 3454 $hour = 12; 3455 $ret = sprintf ( "%d:%02d%s", $hour, $min, $ampm ); 3456 } else { 3457 $ret = sprintf ( "%d:%02d", $hour, $min ); 3458 } 3459 return $ret; 3460 } 3461 3462 /** 3463 * Returns the full name of the specified month. 3464 * 3465 * Use {@link month_short_name()} to get the abbreviated name of the month. 3466 * 3467 * @param int $m Number of the month (0-11) 3468 * 3469 * @return string The full name of the specified month 3470 * 3471 * @see month_short_name 3472 */ 3473 function month_name ( $m ) { 3474 switch ( $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"); 3487 } 3488 return "unknown-month($m)"; 3489 } 3490 3491 /** 3492 * Returns the abbreviated name of the specified month (such as "Jan"). 3493 * 3494 * Use {@link month_name()} to get the full name of the month. 3495 * 3496 * @param int $m Number of the month (0-11) 3497 * 3498 * @return string The abbreviated name of the specified month (example: "Jan") 3499 * 3500 * @see month_name 3501 */ 3502 function month_short_name ( $m ) { 3503 switch ( $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"); 3516 } 3517 return "unknown-month($m)"; 3518 } 3519 3520 /** 3521 * Returns the full weekday name. 3522 * 3523 * Use {@link weekday_short_name()} to get the abbreviated weekday name. 3524 * 3525 * @param int $w Number of the day in the week (0=Sunday,...,6=Saturday) 3526 * 3527 * @return string The full weekday name ("Sunday") 3528 * 3529 * @see weekday_short_name 3530 */ 3531 function weekday_name ( $w ) { 3532 switch ( $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"); 3540 } 3541 return "unknown-weekday($w)"; 3542 } 3543 3544 /** 3545 * Returns the abbreviated weekday name. 3546 * 3547 * Use {@link weekday_name()} to get the full weekday name. 3548 * 3549 * @param int $w Number of the day in the week (0=Sunday,...,6=Saturday) 3550 * 3551 * @return string The abbreviated weekday name ("Sun") 3552 */ 3553 function weekday_short_name ( $w ) { 3554 switch ( $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"); 3562 } 3563 return "unknown-weekday($w)"; 3564 } 3565 3566 /** 3567 * Converts a date in YYYYMMDD format into "Friday, December 31, 1999", 3568 * "Friday, 12-31-1999" or whatever format the user prefers. 3569 * 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 ??? 3577 * 3578 * @return string Date in the specified format 3579 * 3580 * @global string Preferred date format 3581 * @global int User's timezone offset from the server 3582 */ 3583 function date_to_str ( $indate, $format="", $show_weekday=true, $short_months=false, $server_time="" ) { 3584 global $DATE_FORMAT, $TZ_OFFSET; 3585 3586 if ( strlen ( $indate ) == 0 ) { 3587 $indate = date ( "Ymd" ); 3588 } 3589 3590 $newdate = $indate; 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 ) ); 3599 } 3600 } 3601 3602 // if they have not set a preference yet... 3603 if ( $DATE_FORMAT == "" ) 3604 $DATE_FORMAT = "__month__ __dd__, __yyyy__"; 3605 3606 if ( empty ( $format ) ) 3607 $format = $DATE_FORMAT; 3608 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 ); 3614 3615 if ( $short_months ) { 3616 $weekday = weekday_short_name ( $wday ); 3617 $month = month_short_name ( $m - 1 ); 3618 } else { 3619 $weekday = weekday_name ( $wday ); 3620 $month = month_name ( $m - 1 ); 3621 } 3622 $yyyy = $y; 3623 $yy = sprintf ( "%02d", $y %= 100 ); 3624 3625 $ret = $format; 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 ); 3632 3633 if ( $show_weekday ) 3634 return "$weekday, $ret"; 3635 else 3636 return $ret; 3637 } 3638 3639 3640 /** 3641 * Converts a hexadecimal digit to an integer. 3642 * 3643 * @param string $val Hexadecimal digit 3644 * 3645 * @return int Equivalent integer in base-10 3646 * 3647 * @ignore 3648 */ 3649 function hextoint ( $val ) { 3650 if ( empty ( $val ) ) 3651 return 0; 3652 switch ( strtoupper ( $val ) ) { 3653 case "0": return 0; 3654 case "1": return 1; 3655 case "2": return 2; 3656 case "3": return 3; 3657 case "4": return 4; 3658 case "5": return 5; 3659 case "6": return 6; 3660 case "7": return 7; 3661 case "8": return 8; 3662 case "9": return 9; 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; 3669 } 3670 return 0; 3671 } 3672 3673 /** 3674 * Extracts a user's name from a session id. 3675 * 3676 * This prevents users from begin able to edit their cookies.txt file and set 3677 * the username in plain text. 3678 * 3679 * @param string $instr A hex-encoded string. "Hello" would be "678ea786a5". 3680 * 3681 * @return string The decoded string 3682 * 3683 * @global array Array of offsets 3684 * 3685 * @see encode_string 3686 */ 3687 function decode_string ( $instr ) { 3688 global $offsets; 3689 //echo "<br />\nDECODE<br />\n"; 3690 $orig = ""; 3691 for ( $i = 0; $i < strlen ( $instr ); $i += 2 ) { 3692 //echo "<br />\n"; 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; 3700 $newval %= 256; 3701 //echo " neval \"$newval\"<br />\n"; 3702 $dec_ch = chr ( $newval ); 3703 //echo " which is \"$dec_ch\"<br />\n"; 3704 $orig .= $dec_ch; 3705 } 3706 //echo "Decode string: '$orig' <br/>\n"; 3707 return $orig; 3708 } 3709 3710 /** 3711 * Takes an input string and encode it into a slightly encoded hexval that we 3712 * can use as a session cookie. 3713 * 3714 * @param string $instr Text to encode 3715 * 3716 * @return string The encoded text 3717 * 3718 * @global array Array of offsets 3719 * 3720 * @see decode_string 3721 */ 3722 function encode_string ( $instr ) { 3723 global $offsets; 3724 //echo "<br />\nENCODE<br />\n"; 3725 $ret = ""; 3726 for ( $i = 0; $i < strlen ( $instr ); $i++ ) { 3727 //echo "<br />\n"; 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]; 3734 $newval %= 256; 3735 //echo "newval = $newval for \"$ch1\"<br />\n"; 3736 $ret .= bin2hex ( chr ( $newval ) ); 3737 } 3738 return $ret; 3739 } 3740 3741 /** 3742 * An implementatin of array_splice() for PHP3. 3743 * 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 3748 * 3749 * @ignore 3750 */ 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 3754 if ( $offset < 0 ) 3755 $offset = count($input) + $offset; 3756 3757 for ($i=0;$i<$offset;$i++) { 3758 $new_array[] = $input[$i]; 3759 } 3760 3761 // if we have a replacement, insert it 3762 for ($i=0;$i<count($replacement);$i++) { 3763 $new_array[] = $replacement[$i]; 3764 } 3765 3766 // now tack on the rest of the original array 3767 for ($i=$offset+$length;$i<count($input);$i++) { 3768 $new_array[] = $input[$i]; 3769 } 3770 3771 $input = $new_array; 3772 } else { 3773 array_splice($input,$offset,$length,$replacement); 3774 } 3775 } 3776 3777 /** 3778 * Loads current user's category info and stuff it into category global 3779 * variable. 3780 * 3781 * @param string $ex_global Don't include global categories ('' or '1') 3782 */ 3783 function load_user_categories ($ex_global = '') { 3784 global $login, $user, $is_assistant; 3785 global $categories, $category_owners; 3786 global $categories_enabled, $is_admin; 3787 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"; 3795 3796 $res = dbi_query ( $sql ); 3797 if ( $res ) { 3798 while ( $row = dbi_fetch_row ( $res ) ) { 3799 $cat_id = $row[0]; 3800 $categories[$cat_id] = $row[1]; 3801 $category_owners[$cat_id] = $row[2]; 3802 } 3803 dbi_free_result ( $res ); 3804 } 3805 } else { 3806 //echo "Categories disabled."; 3807 } 3808 } 3809 3810 /** 3811 * Prints dropdown HTML for categories. 3812 * 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 3816 */ 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 ){ 3830 if ( $cat_owner || 3831 empty ( $category_owners[$K] ) ) { 3832 echo "<option value=\"$K\""; 3833 if ( $cat_id == $K ) echo " selected=\"selected\""; 3834 echo ">$V</option>\n"; 3835 } 3836 } 3837 } 3838 echo "</select>\n"; 3839 echo "</form>\n"; 3840 echo "<span id=\"cat\">" . translate ("Category") . ": "; 3841 echo ( strlen ( $cat_id ) ? $categories[$cat_id] : translate ('All') ) . "</span>\n"; 3842 } 3843 3844 /** 3845 * Converts HTML entities in 8bit. 3846 * 3847 * <b>Note:</b> Only supported for PHP4 (not PHP3). 3848 * 3849 * @param string $html HTML text 3850 * 3851 * @return string The converted text 3852 */ 3853 function html_to_8bits ( $html ) { 3854 if ( floor(phpversion()) < 4 ) { 3855 return $html; 3856 } else { 3857 return strtr ( $html, array_flip ( 3858 get_html_translation_table (HTML_ENTITIES) ) ); 3859 } 3860 } 3861 3862 // *********************************************************************** 3863 // Functions for getting information about boss and their assistant. 3864 // *********************************************************************** 3865 3866 /** 3867 * Gets a list of an assistant's boss from the webcal_asst table. 3868 * 3869 * @param string $assistant Login of assistant 3870 * 3871 * @return array Array of bosses, where each boss is an array with the following 3872 * fields: 3873 * - <var>cal_login</var> 3874 * - <var>cal_fullname</var> 3875 */ 3876 function user_get_boss_list ( $assistant ) { 3877 global $bosstemp_fullname; 3878 3879 $res = dbi_query ( 3880 "SELECT cal_boss " . 3881 "FROM webcal_asst " . 3882 "WHERE cal_assistant = '$assistant'" ); 3883 $count = 0; 3884 $ret = array (); 3885 if ( $res ) { 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 3891 ); 3892 } 3893 dbi_free_result ( $res ); 3894 } 3895 return $ret; 3896 } 3897 3898 /** 3899 * Is this user an assistant of this boss? 3900 * 3901 * @param string $assistant Login of potential assistant 3902 * @param string $boss Login of potential boss 3903 * 3904 * @return bool True or false 3905 */ 3906 function user_is_assistant ( $assistant, $boss ) { 3907 $ret = false; 3908 3909 if ( empty ( $boss ) ) 3910 return false; 3911 $res = dbi_query ( "SELECT * FROM webcal_asst " . 3912 "WHERE cal_assistant = '$assistant' AND cal_boss = '$boss'" ); 3913 if ( $res ) { 3914 if ( dbi_fetch_row ( $res ) ) 3915 $ret = true; 3916 dbi_free_result ( $res ); 3917 } 3918 return $ret; 3919 } 3920 3921 /** 3922 * Is this user an assistant? 3923 * 3924 * @param string $assistant Login for user 3925 * 3926 * @return bool true if the user is an assistant to one or more bosses 3927 */ 3928 function user_has_boss ( $assistant ) { 3929 $ret = false; 3930 $res = dbi_query ( "SELECT * FROM webcal_asst " . 3931 "WHERE cal_assistant = '$assistant'" ); 3932 if ( $res ) { 3933 if ( dbi_fetch_row ( $res ) ) 3934 $ret = true; 3935 dbi_free_result ( $res ); 3936 } 3937 return $ret; 3938 } 3939 3940 /** 3941 * Checks the boss user preferences to see if the boss wants to be notified via 3942 * email on changes to their calendar. 3943 * 3944 * @param string $assistant Assistant login 3945 * @param string $boss Boss login 3946 * 3947 * @return bool True if the boss wants email notifications 3948 */ 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 ); 3952 return true; 3953 } 3954 3955 /** 3956 * Checks the boss user preferences to see if the boss must approve events 3957 * added to their calendar. 3958 * 3959 * @param string $assistant Assistant login 3960 * @param string $boss Boss login 3961 * 3962 * @return bool True if the boss must approve new events 3963 */ 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 ); 3967 return true; 3968 } 3969 3970 /** 3971 * Fakes an email for testing purposes. 3972 * 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 3977 * 3978 * @ignore 3979 */ 3980 function fake_mail ( $mailto, $subj, $text, $hdrs ) { 3981 echo "To: $mailto <br />\n" . 3982 "Subject: $subj <br />\n" . 3983 nl2br ( $hdrs ) . "<br />\n" . 3984 nl2br ( $text ); 3985 } 3986 3987 /** 3988 * Prints all the entries in a time bar format for the specified user for the 3989 * specified date. 3990 * 3991 * If we are displaying data from someone other than the logged in user, then 3992 * check the access permission of the entry. 3993 * 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? 3997 */ 3998 function print_date_entries_timebar ( $date, $user, $ssi ) { 3999 global $events, $readonly, $is_admin, 4000 $public_access, $public_access_can_add; 4001 $cnt = 0; 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; 4006 4007 $year = substr ( $date, 0, 4 ); 4008 $month = substr ( $date, 4, 2 ); 4009 $day = substr ( $date, 6, 2 ); 4010 4011 $dateu = mktime ( 3, 0, 0, $month, $day, $year ); 4012 4013 $can_add = ( $readonly == "N" || $is_admin ); 4014 if ( $public_access == "Y" && $public_access_can_add != "Y" && 4015 $GLOBALS["login"] == "__public__" ) 4016 $can_add = false; 4017 4018 // get all the repeating events for this date and store in array $rep 4019 $rep = get_repeating_entries ( $user, $date ) ; 4020 $cur_rep = 0; 4021 4022 // get all the non-repeating events for this date and store in $ev 4023 $ev = get_entries ( $user, $date, $get_unapproved ); 4024 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'] ); 4036 $cnt++; 4037 } 4038 $cur_rep++; 4039 } 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'] ); 4047 $cnt++; 4048 } 4049 } 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'] ); 4059 $cnt++; 4060 } 4061 $cur_rep++; 4062 } 4063 if ( $cnt == 0 ) 4064 echo " "; // so the table cell has at least something 4065 } 4066 4067 /** 4068 * Prints the HTML for an events with a timebar. 4069 * 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 4081 * 4082 * @staticvar int Used to ensure all event popups have a unique id 4083 */ 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; 4088 static $key = 0; 4089 $insidespan = false; 4090 global $layers; 4091 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 4098 4099 if ($time >= 0) { 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); 4102 }else{ 4103 $ev_start= 0; 4104 } 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; 4110 } 4111 } else { 4112 if ($time >= 0) { 4113 $ev_duration = 1; 4114 } else { 4115 $ev_duration=100-$ev_start; 4116 } 4117 } 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; } 4122 else { $pos = 0; } 4123 4124 echo "\n<!-- ENTRY BAR -->\n<table class=\"entrycont\" cellpadding=\"0\" cellspacing=\"0\">\n"; 4125 echo "<tr>\n"; 4126 echo ($ev_start > 0 ? "<td style=\"text-align:right; width:$ev_start%;\">" : "" ); 4127 if ( $pos > 0 ) { 4128 echo ($ev_start > 0 ? " </td>\n": "" ) ; 4129 echo "<td style=\"width:$ev_duration%;\">\n<table class=\"entrybar\">\n<tr>\n<td class=\"entry\">"; 4130 if ( $pos > 1 ) { 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%;\">" : ""); 4133 } 4134 }; 4135 4136 if ( $login != $event_owner && strlen ( $event_owner ) ) { 4137 $class = "layerentry"; 4138 } else { 4139 $class = "entry"; 4140 if ( $status == "W" ) $class = "unapprovedentry"; 4141 } 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" ) ) 4147 $class = "entry"; 4148 4149 if ( $pri == 3 ) echo "<strong>"; 4150 $popupid = "eventinfo-$id-$key"; 4151 $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;\">"; 4157 4158 if ( $login != $event_owner && strlen ( $event_owner ) ) { 4159 if ($layers) foreach ($layers as $layer) { 4160 if($layer['cal_layeruser'] == $event_owner) { 4161 $insidespan = true; 4162 echo("<span style=\"color:" . $layer['cal_color'] . ";\">"); 4163 } 4164 } 4165 } 4166 4167 echo "[$event_owner] "; 4168 $timestr = ""; 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 ) { 4174 // calc end time 4175 $h = (int) ( $time / 10000 ); 4176 $m = ( $time / 100 ) % 100; 4177 $m += $duration; 4178 $d = $duration; 4179 while ( $m >= 60 ) { 4180 $h++; 4181 $m -= 60; 4182 } 4183 $end_time = sprintf ( "%02d%02d00", $h, $m ); 4184 $timestr .= " - " . display_time ( $end_time ); 4185 } 4186 } 4187 if ( $login != $user && $access == 'R' && strlen ( $user ) ) 4188 echo "(" . translate("Private") . ")"; 4189 else 4190 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) ) 4191 echo "(" . translate("Private") . ")"; 4192 else 4193 if ( $login != $event_owner && strlen ( $event_owner ) ) 4194 { 4195 echo htmlspecialchars ( $name ); 4196 if ( $insidespan ) { echo ("</span>"); } //end color span 4197 } 4198 else 4199 echo htmlspecialchars ( $name ); 4200 echo "</a>"; 4201 if ( $pri == 3 ) echo "</strong>"; //end font-weight span 4202 echo "</td>\n"; 4203 if ( $pos < 2 ) { 4204 if ( $pos < 1 ) { 4205 echo "<td style=\"width:$ev_duration%;\"><table class=\"entrybar\">\n<tr>\n<td class=\"entry\"> </td>\n"; 4206 } 4207 echo "</tr>\n</table></td>\n"; 4208 echo ($ev_padding > 0 ? "<td style=\"text-align:left; width:$ev_padding%;\"> </td>\n" : "" ); 4209 } 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"), "" ); 4214 else 4215 if ( $login != $event_owner && $access == 'R' && strlen ( $event_owner ) ) 4216 $eventinfo .= build_event_popup ( $popupid, $event_owner, 4217 translate("This event is confidential"), "" ); 4218 else 4219 $eventinfo .= build_event_popup ( $popupid, $event_owner, 4220 $description, $timestr, site_extras_for_popup ( $id ) ); 4221 } 4222 4223 /** 4224 * Prints the header for the timebar. 4225 * 4226 * @param int $start_hour Start hour 4227 * @param int $end_hour End hour 4228 */ 4229 function print_header_timebar($start_hour, $end_hour) { 4230 // sh+1 ... eh-1 4231 // +------+----....----+------+ 4232 // | | | | 4233 4234 // print hours 4235 if ( ($end_hour - $start_hour) == 0 ) 4236 $offset = 0; 4237 else 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)); 4244 $width = $offset; 4245 echo "<td style=\"width:$width%;text-align:left;\">$i</td>\n"; 4246 } 4247 // $width = 100 - $offset; 4248 // echo "<td style=\"width:$width%;\"> </td>\n"; 4249 echo "</tr>\n</table>\n<!-- /TIMEBAR -->\n"; 4250 4251 // print yardstick 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"; 4256 } 4257 echo "</tr>\n</table>\n<!-- /YARDSTICK -->\n"; 4258 } 4259 4260 /** 4261 * Gets a list of nonuser calendars and return info in an array. 4262 * 4263 * @param string $user Login of admin of the nonuser calendars 4264 * 4265 * @return array Array of nonuser cals, where each is an array with the 4266 * following fields: 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> 4272 */ 4273 function get_nonuser_cals ($user = '') { 4274 $count = 0; 4275 $ret = array (); 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 ); 4281 if ( $res ) { 4282 while ( $row = dbi_fetch_row ( $res ) ) { 4283 if ( strlen ( $row[1] ) || strlen ( $row[2] ) ) 4284 $fullname = "$row[2] $row[1]"; 4285 else 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 4293 ); 4294 } 4295 dbi_free_result ( $res ); 4296 } 4297 return $ret; 4298 } 4299 4300 /** 4301 * Loads nonuser variables (login, firstname, etc.). 4302 * 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> 4310 * 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. 4315 */ 4316 function nonuser_load_variables ( $login, $prefix ) { 4317 global $error,$nuloadtmp_email; 4318 $ret = false; 4319 $res = dbi_query ( "SELECT cal_login, cal_lastname, cal_firstname, " . 4320 "cal_admin FROM webcal_nonuser_cals WHERE cal_login = '$login'" ); 4321 if ( $res ) { 4322 while ( $row = dbi_fetch_row ( $res ) ) { 4323 if ( strlen ( $row[1] ) || strlen ( $row[2] ) ) 4324 $fullname = "$row[2] $row[1]"; 4325 else 4326 $fullname = $row[0]; 4327 4328 // We need the email address for the admin 4329 user_load_variables ( $row[3], 'nuloadtmp_' ); 4330 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; 4337 $ret = true; 4338 } 4339 dbi_free_result ( $res ); 4340 } 4341 return $ret; 4342 } 4343 4344 /** 4345 * Checks the webcal_nonuser_cals table to determine if the user is the 4346 * administrator for the nonuser calendar. 4347 * 4348 * @param string $login Login of user that is the potential administrator 4349 * @param string $nonuser Login name for nonuser calendar 4350 * 4351 * @return bool True if the user is the administrator for the nonuser calendar 4352 */ 4353 function user_is_nonuser_admin ( $login, $nonuser ) { 4354 $ret = false; 4355 4356 $res = dbi_query ( "SELECT * FROM webcal_nonuser_cals " . 4357 "WHERE cal_login = '$nonuser' AND cal_admin = '$login'" ); 4358 if ( $res ) { 4359 if ( dbi_fetch_row ( $res ) ) 4360 $ret = true; 4361 dbi_free_result ( $res ); 4362 } 4363 return $ret; 4364 } 4365 4366 /** 4367 * Loads nonuser preferences from the webcal_user_pref table if on a nonuser 4368 * admin page. 4369 * 4370 * @param string $nonuser Login name for nonuser calendar 4371 */ 4372 function load_nonuser_preferences ($nonuser) { 4373 global $prefarray; 4374 $res = dbi_query ( 4375 "SELECT cal_setting, cal_value FROM webcal_user_pref " . 4376 "WHERE cal_login = '$nonuser'" ); 4377 if ( $res ) { 4378 while ( $row = dbi_fetch_row ( $res ) ) { 4379 $setting = $row[0]; 4380 $value = $row[1]; 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; 4388 } 4389 dbi_free_result ( $res ); 4390 } 4391 } 4392 4393 /** 4394 * Determines what the day is after the <var>$TZ_OFFSET</var> and sets it globally. 4395 * 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> 4402 * 4403 * @param string $date The date in YYYYMMDD format 4404 */ 4405 function set_today($date) { 4406 global $thisyear, $thisday, $thismonth, $thisdate, $today; 4407 global $TZ_OFFSET, $month, $day, $year, $thisday; 4408 4409 // Adjust for TimeZone 4410 $today = time() + ($TZ_OFFSET * 60 * 60); 4411 4412 if ( ! empty ( $date ) && ! empty ( $date ) ) { 4413 $thisyear = substr ( $date, 0, 4 ); 4414 $thismonth = substr ( $date, 4, 2 ); 4415 $thisday = substr ( $date, 6, 2 ); 4416 } else { 4417 if ( empty ( $month ) || $month == 0 ) 4418 $thismonth = date("m", $today); 4419 else 4420 $thismonth = $month; 4421 if ( empty ( $year ) || $year == 0 ) 4422 $thisyear = date("Y", $today); 4423 else 4424 $thisyear = $year; 4425 if ( empty ( $day ) || $day == 0 ) 4426 $thisday = date("d", $today); 4427 else 4428 $thisday = $day; 4429 } 4430 $thisdate = sprintf ( "%04d%02d%02d", $thisyear, $thismonth, $thisday ); 4431 } 4432 4433 /** 4434 * Converts from Gregorian Year-Month-Day to ISO YearNumber-WeekNumber-WeekDay. 4435 * 4436 * @internal JGH borrowed gregorianToISO from PEAR Date_Calc Class and added 4437 * $GLOBALS["WEEK_START"] (change noted) 4438 * 4439 * @param int $day Day of month 4440 * @param int $month Number of month 4441 * @param int $year Year 4442 * 4443 * @return string Date in ISO YearNumber-WeekNumber-WeekDay format 4444 * 4445 * @ignore 4446 */ 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++; 4454 } 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); 4460 4461 4462 // JGH added next if/else to compensate for week begins on Sunday 4463 if (! $GLOBALS["WEEK_START"] && $jan1_weekday < 7) { 4464 $jan1_weekday++; 4465 } elseif (! $GLOBALS["WEEK_START"] && $jan1_weekday == 7) { 4466 $jan1_weekday=1; 4467 } 4468 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)) { 4476 $weeknumber = 53; 4477 } else { 4478 $weeknumber = 52; 4479 } 4480 } else { 4481 $yearnumber = $year; 4482 } 4483 // find if Y M D falls in YearNumber Y+1, WeekNumber 1 4484 if ($yearnumber == $year) { 4485 if ($y_isleap) { 4486 $i = 366; 4487 } else { 4488 $i = 365; 4489 } 4490 if (($i - $day_of_year_number) < (4 - $weekday)) { 4491 $yearnumber++; 4492 $weeknumber = 1; 4493 } 4494 } 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) { 4500 $weeknumber--; 4501 } 4502 } 4503 // put it all together 4504 if ($weeknumber < 10) 4505 $weeknumber = '0'.$weeknumber; 4506 return "{$yearnumber}-{$weeknumber}-{$weekday}"; 4507 } 4508 4509 /** 4510 * Is this a leap year? 4511 * 4512 * @internal JGH Borrowed isLeapYear from PEAR Date_Calc Class 4513 * 4514 * @param int $year Year 4515 * 4516 * @return bool True for a leap year, else false 4517 * 4518 * @ignore 4519 */ 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); 4525 } 4526 4527 /** 4528 * Replaces unsafe characters with HTML encoded equivalents. 4529 * 4530 * @param string $value Input text 4531 * 4532 * @return string The cleaned text 4533 */ 4534 function clean_html($value){ 4535 $value = htmlspecialchars($value, ENT_QUOTES); 4536 $value = strtr($value, array( 4537 '(' => '(', 4538 ')' => ')' 4539 )); 4540 return $value; 4541 } 4542 4543 /** 4544 * Removes non-word characters from the specified text. 4545 * 4546 * @param string $data Input text 4547 * 4548 * @return string The converted text 4549 */ 4550 function clean_word($data) { 4551 return preg_replace("/\W/", '', $data); 4552 } 4553 4554 /** 4555 * Removes non-digits from the specified text. 4556 * 4557 * @param string $data Input text 4558 * 4559 * @return string The converted text 4560 */ 4561 function clean_int($data) { 4562 return preg_replace("/\D/", '', $data); 4563 } 4564 4565 /** 4566 * Removes whitespace from the specified text. 4567 * 4568 * @param string $data Input text 4569 * 4570 * @return string The converted text 4571 */ 4572 function clean_whitespace($data) { 4573 return preg_replace("/\s/", '', $data); 4574 } 4575 4576 /** 4577 * Converts language names to their abbreviation. 4578 * 4579 * @param string $name Name of the language (such as "French") 4580 * 4581 * @return string The abbreviation ("fr" for "French") 4582 */ 4583 function languageToAbbrev ( $name ) { 4584 global $browser_languages; 4585 foreach ( $browser_languages as $abbrev => $langname ) { 4586 if ( $langname == $name ) 4587 return $abbrev; 4588 } 4589 return false; 4590 } 4591 4592 /** 4593 * Creates the CSS for using gradient.php, if the appropriate GD functions are 4594 * available. 4595 * 4596 * A one-pixel wide image will be used for the background image. 4597 * 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 4600 * instead. 4601 * 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 4606 * 4607 * @return string The style sheet text to use 4608 */ 4609 function background_css ( $color, $height = '', $percent = '' ) { 4610 $ret = ''; 4611 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 ); 4616 4617 if ( $height != '' ) { 4618 $ret .= "&height=$height"; 4619 } 4620 4621 if ( $percent != '' ) { 4622 $ret .= "&percent=$percent"; 4623 } 4624 4625 $ret .= "\") repeat-x;\n"; 4626 } else { 4627 $ret = "background-color: $color;\n"; 4628 } 4629 4630 return $ret; 4631 } 4632 4633 /** 4634 * Draws a daily outlook style availability grid showing events that are 4635 * approved and awaiting approval. 4636 * 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 4640 */ 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; 4645 4646 $increment = 15; 4647 $interval = 4; 4648 $participant_pct = '20%'; //use percentage 4649 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); 4654 $total_pct = '80%'; 4655 $cell_pct = 80 /($hours * $interval); 4656 $master = array(); 4657 4658 // Build a master array containing all events for $participants 4659 for ( $i = 0; $i < count ( $participants ); $i++ ) { 4660 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 ); 4665 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 ); 4670 4671 // combine into a single array for easy processing 4672 $ALL = array_merge ( $rep, $ev ); 4673 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 ); 4678 } else { 4679 $E['cal_time'] = sprintf ( "%06d", $E['cal_time']); 4680 } 4681 4682 $hour = substr($E['cal_time'], 0, 2 ); 4683 $mins = substr($E['cal_time'], 2, 2 ); 4684 4685 // Timezone Offset 4686 if ( ! $ignore_offset ) $hour += $TZ_OFFSET; 4687 while ( $hour < 0 ) $hour += 24; 4688 while ( $hour > 23 ) $hour -= 24; 4689 4690 // Make sure hour is 2 digits 4691 $hour = sprintf ( "%02d",$hour); 4692 4693 // convert cal_time to slot 4694 if ($mins < 15) { 4695 $slot = $hour.''; 4696 } elseif ($mins >= 15 && $mins < 30) { 4697 $slot = $hour.'.25'; 4698 } elseif ($mins >= 30 && $mins < 45) { 4699 $slot = $hour.'.5'; 4700 } elseif ($mins >= 45) { 4701 $slot = $hour.'.75'; 4702 } 4703 4704 // convert cal_duration to bars 4705 $bars = $E['cal_duration'] / $increment; 4706 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']; 4715 } 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']; 4720 } 4721 $slot = $slot + '0.25'; 4722 } 4723 4724 } 4725 } 4726 ?> 4727 <br /> 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> 4732 <?php 4733 $str = ''; 4734 $MouseOut = "onmouseout=\"window.status=''; this.style.backgroundColor='".$THBG."';\""; 4735 $CC = 1; 4736 for($i=$first_hour;$i<$last_hour;$i++) { 4737 $hour = $i; 4738 if ( $GLOBALS["TIME_FORMAT"] == "12" ) { 4739 $hour %= 12; 4740 if ( $hour == 0 ) $hour = 12; 4741 } 4742 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)).');"'; 4746 switch($j) { 4747 case 1: 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"; 4751 break; 4752 case 2: 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"; 4756 break; 4757 default: 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"; 4760 break; 4761 } 4762 $CC++; 4763 } 4764 } 4765 echo $str . 4766 "</tr>\n<tr><td class=\"matrix\" colspan=\"$cols\"></td></tr>\n"; 4767 4768 // Add user _all_ to beginning of $participants array 4769 array_unshift($participants, '_all_'); 4770 4771 // Javascript for cells 4772 $MouseOver = "onmouseover=\"this.style.backgroundColor='#CCFFCC';\""; 4773 $MouseOut = "onmouseout=\"this.style.backgroundColor='".$CELLBG."';\""; 4774 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_" ); 4780 4781 // exchange space for to keep from breaking 4782 $user_nospace = preg_replace ( '/\s/', ' ', $user_fullname ); 4783 } else { 4784 $user_nospace = translate("All Attendees"); 4785 $user_nospace = preg_replace ( '/\s/', ' ', $user_nospace ); 4786 } 4787 4788 echo "<tr>\n<th class=\"row\" style=\"width:{$participant_pct};\">".$user_nospace."</th>\n"; 4789 $col = 1; 4790 $viewMsg = translate ( "View this entry" ); 4791 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)).');"'; 4797 $RC = $CELLBG; 4798 //$space = ''; 4799 $space = " "; 4800 4801 $r = sprintf ("%02d",$j) . '.' . sprintf ("%02d", (25 * $k)).''; 4802 if ( empty ( $master[$participants[$i]][$r] ) ) { 4803 // ignore this.. 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>"; 4811 } 4812 4813 echo "<td class=\"matrixappts\" style=\"width:{$cell_pct}%;$border\" "; 4814 if ($space == " ") echo "$MouseDown $MouseOver $MouseOut"; 4815 echo ">$space</td>\n"; 4816 $col++; 4817 } 4818 } 4819 4820 echo "</tr><tr>\n<td class=\"matrix\" colspan=\"$cols\">" . 4821 "<img src=\"pix.gif\" alt=\"-\" /></td></tr>\n"; 4822 } // End foreach participant 4823 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"; 4831 } 4832 4833 /** 4834 * Return the time in HHMMSS format of input time + duration 4835 * 4836 * 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 4839 * instead. 4840 * 4841 * @param string $time format "235900" 4842 * @param int $duration number of minutes 4843 * 4844 * @return string The time in HHMMSS format 4845 */ 4846 function add_duration ( $time, $duration ) { 4847 $hour = (int) ( $time / 10000 ); 4848 $min = ( $time / 100 ) % 100; 4849 $minutes = $hour * 60 + $min + $duration; 4850 $h = $minutes / 60; 4851 $m = $minutes % 60; 4852 $ret = sprintf ( "%d%02d00", $h, $m ); 4853 //echo "add_duration ( $time, $duration ) = $ret <br />\n"; 4854 return $ret; 4855 } 4856 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 19:09:19 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |