1<?php 2 3/** 4 * SquirrelMail Calendar Plugin File Backend 5 * Copyright (C) 2004-2005 Paul Lesneiwski <pdontthink@angrynerds.com> 6 * This program is licensed under GPL. See COPYING for details 7 * 8 */ 9 10 11include_once(SM_PATH . 'plugins/calendar/functions.php'); 12include_once(SM_PATH . 'plugins/calendar_file_backend/constants.php'); 13include_once(SM_PATH . 'plugins/calendar_file_backend/functions.php'); 14 15 16 17/** 18 * Retrieves all events, holidays, and other for the given calendar 19 * for all time periods. 20 * 21 * @param string $calID The ID of the calendar for which to retrieve events 22 * @param string $user The user for which events are being retrieved 23 * 24 * @return array An array of calendar events. This array is keyed by 25 * event id, where associated values are Event objects 26 * 27 */ 28function cal_file_get_all_events_do($calID, $user) 29{ 30 31 global $EVENT_DIR; 32 33 34 $event_dir = $EVENT_DIR . '/' . $calID; 35 $events = array(); 36 37 38 // get all events 39 // 40 if (is_dir($event_dir)) 41 $events = array_merge($events, 42 cal_file_get_all_events_in_dir($user, $event_dir)); 43 44 45 return $events; 46 47} 48 49 50 51/** 52 * Retrieves all one-time events for the given calendar 53 * for the given month, including any that overlap 54 * into previous/next months. 55 * 56 * @param string $calID The ID of the calendar for which to retrieve events 57 * @param int $year The year of the month for which to retrieve events 58 * @param int $month The month for which to retrieve events 59 * @param string $user The user for which events are being retrieved 60 * 61 * @return array An array of calendar events. This array is keyed by 62 * event id, where associated values are Event objects 63 * 64 */ 65function cal_file_get_events_for_month_do($calID, $year, $month, $user) 66{ 67 68 global $EVENT_DIR; 69 70 71 $event_dir = $EVENT_DIR . '/' . $calID; 72 $events = array(); 73 74 75 // get events for the given month 76 // we assume that missing directory simply means no events exist yet for that month 77 // 78 $this_month_event_dir = $event_dir . '/' . $year . '/' . $month; 79 if (is_dir($this_month_event_dir)) 80 $events = array_merge($events, 81 cal_file_get_all_events_in_dir($user, $this_month_event_dir)); 82 83 84 return $events; 85 86} 87 88 89 90/** 91 * Retrieves all recurring events for the given calendar. 92 * 93 * @param string $calID The ID of the calendar for which to retrieve events 94 * @param string $user The user for which events are being retrieved 95 * 96 * @return array An array of calendar events. This array is keyed by 97 * event id, where associated values are Event objects 98 * 99 */ 100function cal_file_get_recurring_events_do($calID, $user) 101{ 102 103 global $EVENT_DIR; 104 105 106 $event_dir = $EVENT_DIR . '/' . $calID; 107 $events = array(); 108 109 110 // get recurring events 111 // we assume that missing directory simply means no recurring events exist yet 112 // 113 $recurring_event_dir = $event_dir . '/recurring'; 114 if (is_dir($recurring_event_dir)) 115 $events = array_merge($events, 116 cal_file_get_all_events_in_dir($user, $recurring_event_dir)); 117 118 119 return $events; 120 121} 122 123 124 125/** 126 * Get all holidays for the given calendar 127 * 128 * Retrieves all the holidays for the given calendar from the backend 129 * 130 * @param string $calID The ID of the calendar whose holidays 131 * are being retrieved 132 * @param string $user The user for which to retrieve holidays 133 * 134 * @return array An array of holidays. This array is keyed by 135 * holiday id, where associated values are Event objects 136 * 137 */ 138function cal_file_get_calendar_holidays_do($calID, $user) 139{ 140 141 global $EVENT_DIR; 142 143 144 $event_dir = $EVENT_DIR . '/' . $calID; 145 $holidays = array(); 146 147 148 // get holiday events 149 // we assume that missing directory simply means no holidays exist yet 150 // 151 $holiday_dir = $event_dir . '/holidays'; 152 if (is_dir($holiday_dir)) 153 $holidays = array_merge($holidays, 154 cal_file_get_all_events_in_dir($user, $holiday_dir)); 155 156 157 return $holidays; 158 159} 160 161 162 163/** 164 * Retrieves all events in the given directory 165 * 166 * Calls itself recursively if need to parse multiple dirs. 167 * 168 * @param string $user The user for which events are being retrieved 169 * @param string $event_dir The directory where the search for events 170 * should begin 171 * @param string $eventID If given, *ONLY* the event with the given 172 * ID will be returned. (optional) 173 * 174 * @return array An array of Event objects 175 * 176 */ 177function cal_file_get_all_events_in_dir($user, $event_dir, $eventID='') 178{ 179 180 global $CAL_FILE_EXTENSION; 181 182 183 if (empty($event_dir)) 184 { 185 global $color; 186 plain_error_message('CAL FILE BACKEND ERROR (cal_file_get_all_events_in_dir): no event directory given', $color); 187 exit; 188 } 189 190 191 // iterate through each event and pull the right ones 192 // 193 $eventList = array(); 194 $DIR = opendir($event_dir); 195 while (($dirfile = readdir($DIR)) !== FALSE) 196 { 197 198 $file = $event_dir . '/' . $dirfile; 199 200 201 // call recursively into child directories 202 // 203 if (is_dir($file) && $dirfile != '.' && $dirfile != '..') 204 { 205 $childList = cal_file_get_all_events_in_dir($user, $file, $eventID); 206 $eventList = array_merge($eventList, $childList); 207 continue; 208 } 209 210 211 // all event files are prefaced with "sm_cal_evt" 212// NOTE: not true for imported calendar events 213 // and end with ".ics" 214 // 215 if (/*strpos($dirfile, 'sm_cal_evt') !== 0 ||*/ strpos($dirfile, $CAL_FILE_EXTENSION) != strlen($dirfile) - 4) 216 continue; 217 218 219 // check each event for user access 220 // 221 else if (is_file($file)) 222 { 223 224 // if we are only looking for one event, skip all others 225 // 226 if (!empty($eventID) && $dirfile != $eventID . $CAL_FILE_EXTENSION) 227 continue; 228 229 230 $event = getEventFromFile($file); 231 232 233 // check access 234 // 235 if (!$event->canRead($user) && !$event->canWrite($user) && !$event->isOwner($user)) 236 continue; 237 238 239 // instantiate and add event to return array 240 // 241 $eventList[$event->getID()] = $event; 242 243 244 // if we are only looking for one event, we're done! 245 // 246 if (!empty($eventID)) 247 break; 248 249 } 250 251 } 252 253 closedir($DIR); 254 return $eventList; 255 256} 257 258 259 260/** 261 * Retrieves event attributes from the given file into 262 * an Event object, which it then returns. 263 * 264 * Note: assumes file exists and is readable! 265 * 266 * @param string $file The full file path to the desired event 267 * attributes file. 268 * 269 * @return object An Event object corresponding to the given file. 270 * 271 */ 272function getEventFromFile($file) 273{ 274 275 // read the file all at once 276 // 277 $fileContents = file($file); 278 279 280 return Event::getEventFromICal($fileContents); 281 282} 283 284 285 286/** 287 * Stores event attributes from the given Event object 288 * into the given file. 289 * 290 * Note: overwrites whatever data might already be in the file! 291 * 292 * @param object $event The Event object to be written to file 293 * @param string $file The full file path to the desired event 294 * attributes file. 295 * 296 */ 297function writeEventToFile($event, $file) 298{ 299 300 global $color; 301 $EVENT_FILE = @fopen($file, 'w'); 302 if (!$EVENT_FILE) 303 { 304 @fclose($EVENT_FILE); 305 plain_error_message('ERROR IN CALENDAR FILE BACKEND (writeEventToFile): cannot open event file', $color); 306 exit; 307 } 308 309 310 //get iCal text 311 // 312 $iCalText = $event->getICal(TRUE); 313 314 315 // write event 316 // 317 if (!fwrite($EVENT_FILE, $iCalText)) 318 { 319 fclose($EVENT_FILE); 320 plain_error_message('ERROR IN CALENDAR FILE BACKEND (writeEventToFile): cannot write to event file', $color); 321 exit; 322 } 323 324 325 fclose($EVENT_FILE); 326 327} 328 329 330 331/** 332 * Creates a new event 333 * 334 * Takes the given event object and inserts it into the 335 * backend as a new event with the ID as given in the 336 * event object. 337 * 338 * @param string $calendarID The ID of the calendar having an event added 339 * @param object $event The new event object 340 * 341 * @return string The ID of the newly created event 342 * 343 */ 344function cal_file_create_event_do($calendarID, $event) 345{ 346 347 348 global $EVENT_DIR, $CAL_FILE_EXTENSION, $color; 349 $calendar_events_dir = $EVENT_DIR . '/' . $calendarID; 350 $recurring_event_dir = $calendar_events_dir . '/recurring'; 351 $task_event_dir = $calendar_events_dir . '/tasks'; 352 353 354 355 // make sure main event directory is there; create it if not 356 // 357 if (!is_dir($EVENT_DIR)) 358 if (!mkdir($EVENT_DIR, 0770)) 359 { 360 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event directory', $color); 361 exit; 362 } 363 364 365 // make sure main calendar events directory, recurring events 366 // directory, task/todo events directory are there; create them if not 367 // 368 if (!is_dir($calendar_events_dir)) 369 { 370 if (!mkdir($calendar_events_dir, 0770)) 371 { 372 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create calendar events directory', $color); 373 exit; 374 } 375 376 377 if (!mkdir($recurring_event_dir, 0770)) 378 { 379 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create calendar recurring events directory', $color); 380 exit; 381 } 382 383 384 if (!mkdir($task_event_dir, 0770)) 385 { 386 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create calendar todo/task events directory', $color); 387 exit; 388 } 389 } 390 391 392 393 $filename = $event->getID() . $CAL_FILE_EXTENSION; 394 395 396 397 // todo/task events are easy - they go in just one place 398 // 399 if ($event->isTask()) 400 { 401 402 $eventFile = $task_event_dir . '/' . $filename; 403 404 405 if (file_exists($eventFile)) 406 { 407 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): event ' . $filename . ' already exists!', $color); 408 exit; 409 } 410 411 412 // ready to write the event to disk 413 // 414 writeEventToFile($event, $eventFile); 415 return $event->getID(); 416 417 } 418 419 420 421 // recurring events (but not recurring todo's) are easy - they go in just one place 422 // 423 else if ($event->isRecurring()) 424 { 425 426 $eventFile = $recurring_event_dir . '/' . $filename; 427 428 429 if (file_exists($eventFile)) 430 { 431 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): event ' . $filename . ' already exists!', $color); 432 exit; 433 } 434 435 436 // ready to write the event to disk 437 // 438 writeEventToFile($event, $eventFile); 439 return $event->getID(); 440 441 } 442 443 444 445 // one-time events are the most difficult... 446 // 447 else if ($event->isOneTime()) 448 { 449 450 list($year, $month, $day) = $event->startDate(); 451 452 453 // store it on start day 454 // 455 if (!is_dir($calendar_events_dir . '/' . $year)) 456 if (!mkdir($calendar_events_dir . '/' . $year, 0770)) 457 { 458 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event year directory', $color); 459 exit; 460 } 461 462 463 if (!is_dir($calendar_events_dir . '/' . $year . '/' . $month)) 464 if (!mkdir($calendar_events_dir . '/' . $year . '/' . $month, 0770)) 465 { 466 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event month directory', $color); 467 exit; 468 } 469 470 471 if (!is_dir($calendar_events_dir . '/' . $year . '/' . $month . '/' . $day)) 472 if (!mkdir($calendar_events_dir . '/' . $year . '/' . $month . '/' . $day, 0770)) 473 { 474 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event day directory', $color); 475 exit; 476 } 477 478 479 if (file_exists($calendar_events_dir . '/' . $year . '/' . $month . '/' . $day . '/' . $filename)) 480 { 481 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): event ' . $filename . ' already exists!', $color); 482 exit; 483 } 484 485 486 // ready to write the event to disk 487 // 488 writeEventToFile($event, $calendar_events_dir . '/' . $year . '/' . $month . '/' . $day . '/' . $filename); 489 490 491 492 // iterate through all the months that this event occurs in 493 // and save it on the first of evey month past the month 494 // it actually starts in 495 // 496 $month++; 497 if ($month == 13) 498 { 499 $month = 1; 500 $year++; 501 } 502 while ($event->occursOnDay($year, $month, 1)) 503 { 504 505 // store event on first of this month 506 // 507 if (!is_dir($calendar_events_dir . '/' . $year)) 508 if (!mkdir($calendar_events_dir . '/' . $year, 0770)) 509 { 510 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event year directory', $color); 511 exit; 512 } 513 514 515 if (!is_dir($calendar_events_dir . '/' . $year . '/' . $month)) 516 if (!mkdir($calendar_events_dir . '/' . $year . '/' . $month, 0770)) 517 { 518 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event month directory', $color); 519 exit; 520 } 521 522 523 if (!is_dir($calendar_events_dir . '/' . $year . '/' . $month . '/1')) 524 if (!mkdir($calendar_events_dir . '/' . $year . '/' . $month . '/1', 0770)) 525 { 526 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): cannot create event day directory', $color); 527 exit; 528 } 529 530 531 if (file_exists($calendar_events_dir . '/' . $year . '/' . $month . '/1/' . $filename)) 532 { 533 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): event ' . $filename . ' already exists!', $color); 534 exit; 535 } 536 537 538 // ready to write the event to disk 539 // 540 writeEventToFile($event, $calendar_events_dir . '/' . $year . '/' . $month . '/1/' . $filename); 541 542 543 544 $month++; 545 if ($month == 13) 546 { 547 $month = 1; 548 $year++; 549 } 550 551 } 552 553 554 555 return $event->getID(); 556 557 } 558 559 560 561 else 562 { 563 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_event_do): bad event type', $color); 564 exit; 565 } 566 567} 568 569 570 571/** 572 * Delete event 573 * 574 * Removes the given event from the given calendar. 575 * 576 * @param string $calendarID The ID of the calendar whose event is being removed 577 * @param string $eventID The ID of the event to be removed 578 * 579 */ 580function cal_file_delete_event_do($calendarID, $eventID) 581{ 582 583 global $EVENT_DIR, $CAL_FILE_EXTENSION, $color; 584 $calendar_events_dir = $EVENT_DIR . '/' . $calendarID; 585 $recurring_event_dir = $calendar_events_dir . '/recurring'; 586 $task_event_dir = $calendar_events_dir . '/tasks'; 587 $event = cal_file_get_event_do($calendarID, $eventID); 588 589 590 // todo/task events are easy - they are in just one place 591 // 592 if ($event->isTask()) 593 { 594 595 $eventFile = $task_event_dir . '/' . $eventID . $CAL_FILE_EXTENSION; 596 597 598 if (!unlink($eventFile)) 599 { 600 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_event_do): cannot delete event', $color); 601 exit; 602 } 603 604 } 605 606 607 608 // recurring events (but not recurring todo's) are easy - they are in just one place 609 // 610 if ($event->isRecurring()) 611 { 612 613 $eventFile = $recurring_event_dir . '/' . $eventID . $CAL_FILE_EXTENSION; 614 615 616 if (!unlink($eventFile)) 617 { 618 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_event_do): cannot delete event', $color); 619 exit; 620 } 621 622 } 623 624 625 626 // one-time events are the most difficult... 627 // 628 else if ($event->isOneTime()) 629 { 630 631 list($year, $month, $day) = $event->startDate(); 632 633 634 if (!unlink($calendar_events_dir . '/' . $year . '/' . $month . '/' . $day . '/' . $eventID . $CAL_FILE_EXTENSION)) 635 { 636 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_event_do): cannot delete event', $color); 637 exit; 638 } 639 640 641 // iterate through all the months that this event occurs in 642 // and remove it from the first of evey month past the month 643 // it actually starts in 644 // 645 $month++; 646 if ($month == 13) 647 { 648 $month = 1; 649 $year++; 650 } 651 while ($event->occursOnDay($year, $month, 1)) 652 { 653 654 if (!unlink($calendar_events_dir . '/' . $year . '/' . $month . '/1/' . $eventID . $CAL_FILE_EXTENSION)) 655 { 656 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_event_do): cannot delete event', $color); 657 exit; 658 } 659 660 661 $month++; 662 if ($month == 13) 663 { 664 $month = 1; 665 $year++; 666 } 667 668 } 669 670 } 671 672 673 674 else 675 { 676 plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_event_do): bad event type', $color); 677 exit; 678 } 679 680} 681 682 683 684/** 685 * Updates an event 686 * 687 * Updates the given event by replacing it in the backend 688 * with the given event object. 689 * 690 * @param string $calendarID The ID of the calendar whose event is being updated 691 * @param object $event The updated event object 692 * 693 */ 694function cal_file_update_event_do($calendarID, $event) 695{ 696 697 // just delete and create anew, since we have no easy way to know 698 // how many copies of this event we'd need to delete from various 699 // directories 700 // 701 cal_file_delete_event_do($calendarID, $event->getID()); 702 cal_file_create_event_do($calendarID, $event); 703 704} 705 706 707 708/** 709 * Get event 710 * 711 * Retrieves the given event from the backend 712 * 713 * @param string $calendarID The ID of the calendar whose event is to be retrieved 714 * @param string $eventID The ID of the event to be retrieved 715 * 716 * @return object A Event object corresponding to the desired event or FALSE if not found 717 * 718 */ 719function cal_file_get_event_do($calendarID, $eventID) 720{ 721 722 global $EVENT_DIR, $username; 723 $user = $username; 724 725 726 $event_dir = $EVENT_DIR . '/' . $calendarID; 727 728 729 if (is_dir($event_dir)) 730 { 731 $events = cal_file_get_all_events_in_dir($user, $event_dir, $eventID); 732 733 if (!empty($events)) 734 return array_shift($events); 735 } 736 737 738 // not found! 739 // 740 return FALSE; 741 742 global $color; 743 plain_error_message('ERROR IN EVENT FILE BACKEND (cal_file_get_event_do): cannot find event file for calendar ID/event ID ' . $calendarID . ' / ' . $eventID, $color); 744 exit; 745 746} 747 748 749 750?> 751