<?php

/**
  * SquirrelMail Calendar Plugin File Backend
  * Copyright (C) 2004-2005 Paul Lesneiwski <pdontthink@angrynerds.com>
  * This program is licensed under GPL. See COPYING for details
  *
  */


include_once(SM_PATH . 'plugins/calendar/functions.php');
include_once(SM_PATH . 'plugins/calendar_file_backend/constants.php');
include_once(SM_PATH . 'plugins/calendar_file_backend/functions.php');


/**
  * Returns a listing of all public calendars.
  *
  * @return array An array of calendar objects
  *
  */
function cal_file_get_all_public_calendars_do()
{

   global $PUBLIC_CAL_DIR, $CAL_FILE_EXTENSION;


   // we assume that missing directory simply means
   // no calendars are set up yet
   //
   if (!is_dir($PUBLIC_CAL_DIR)) return array();


   // iterate through each calendar and pull the right ones
   //
   $calList = array();
   $DIR = opendir($PUBLIC_CAL_DIR);
   while (($dirfile = readdir($DIR)) !== FALSE)
   {

      // all calendar files are prefaced with "sm_cal"
// NOTE: not true for imported calendars
      // and end with ".ics"
      //
      if (/*strpos($dirfile, 'sm_cal') !== 0 ||*/ strpos($dirfile, $CAL_FILE_EXTENSION) != strlen($dirfile) - 4)
         continue;


      $file = $PUBLIC_CAL_DIR . '/' . $dirfile;


      if (is_file($file))
      {

         $cal = getCalendarFromFile($file);


         // double check that we have a public calendar
         //
         if ($cal->getCalendarType() != SM_CAL_TYPE_PUBLIC)
            continue;


         // instantiate and add calendar to return array
         //
         $calList[] = $cal;

      }
      
   }

   closedir($DIR);
   return $calList;

}



/**
  * Returns a listing of all shared and private (but not public)
  * calendars that the given user has read or write access to
  * EXCEPT the user's default private calendar.
  *
  * @param string $user The user for which to retrieve calendars
  * @param string $domain The user's domain
  *
  * @return array An array of calendar objects
  *
  */
function cal_file_get_all_accessible_calendars_do($user, $domain)
{

   global $SHARED_CAL_DIR, $PRIVATE_CAL_DIR;


   $cal_dir = $PRIVATE_CAL_DIR;


   // we assume that missing directory simply means
   // no calendars are set up yet
   //
   if (!is_dir($cal_dir))
      $privateCals = array();
   else
      $privateCals = cal_file_get_all_accessible_calendars_in_dir($user, $cal_dir);


   // remove default personal calendar from private cal list
   //
   $privateCalID = get_personal_cal_id($user, $domain);
   $calList = array();
   foreach ($privateCals as $cal)
      if ($cal->getID() != $privateCalID)
         $calList[] = $cal;


   $cal_dir = $SHARED_CAL_DIR;


   // we assume that missing directory simply means
   // no calendars are set up yet
   //
   if (!is_dir($cal_dir))
      $sharedCals = array();
   else
      $sharedCals = cal_file_get_all_accessible_calendars_in_dir($user, $cal_dir);


   return array_merge($sharedCals, $calList);

}



/**
  * Returns a listing of all calendars that are either readable
  * or writeable to the given user in the given directory.
  *
  * Calls itself recursively if need to parse multiple dirs,
  * but we currently are not using hierarchical directories
  * for the calendar files. 
  * 
  * @param string $user The user for which to retrieve calendars
  * @param string $cal_dir The directory where the search for calendars
  *                        should begin
  *
  * @return array An array of calendar objects
  *
  */
function cal_file_get_all_accessible_calendars_in_dir($user, $cal_dir)
{

   global $CAL_FILE_EXTENSION;


   if (empty($cal_dir))
   {
      global $color;
      plain_error_message('CAL FILE BACKEND ERROR (cal_file_get_all_accessible_calendars_in_dir): no calendar directory given', $color);
      exit;
   }


   // iterate through each calendar and pull the right ones
   //
   $calList = array();
   $DIR = opendir($cal_dir);
   while (($dirfile = readdir($DIR)) !== FALSE)
   {

      $file = $cal_dir . '/' . $dirfile;


      // call recursively into child directories
      //
      if (is_dir($file) && $dirfile != '.' && $dirfile != '..')
      {
         $childList = cal_file_get_all_accessible_calendars_in_dir($user, $file);
         $calList = array_merge($calList, $childList);
         continue;
      }


      // all calendar files are prefaced with "sm_cal"
// NOTE: not true for imported calendars
      // and end with ".ics"
      //
      if (/*strpos($dirfile, 'sm_cal') !== 0 ||*/ strpos($dirfile, $CAL_FILE_EXTENSION) != strlen($dirfile) - 4)
         continue;


      // check each calendar for user access
      //
      else if (is_file($file))
      {

         $cal = getCalendarFromFile($file);


/*
         // but first, don't even allow personal or public calendars here
         //
         if ($cal->getCalendarType() == SM_CAL_TYPE_PUBLIC && $cal->getCalendarType() == SM_CAL_TYPE_PERSONAL)
            continue;
*/


         // check access
         //
         if (!$cal->canRead($user) && !$cal->canWrite($user) && !$cal->isOwner($user))
            continue;


         // instantiate and add calendar to return array
         //
         $calList[] = $cal;

      }

   }

   closedir($DIR);
   return $calList;

}



/**
  * Returns a listing of all calendars that the given user
  * owns.  If the user is a superuser, all calendars are 
  * returned (regardless of actual ownership); if the user 
  * is a limited administrator, the calendars owned by that 
  * user are returned; and if the user is an unpriveleged 
  * user, just that user's private calendars are returned.
  * 
  * @param string $user The user for which to retrieve calendars
  * @param string $userType The type of user this is, which 
  *                         corresponds to the constants defined
  *                         in the {@link calendar/calendar_constants.php} 
  *                         file
  *
  * @return array An array of calendar objects
  *
  */
function cal_file_get_all_owned_calendars_do($user, $userType)
{

   global $SHARED_CAL_DIR, $PRIVATE_CAL_DIR, $PUBLIC_CAL_DIR, 
          $CAL_FILE_EXTENSION, $domain;


   $cal_dir = $PRIVATE_CAL_DIR;


   // we assume that missing directory simply means
   // no calendars are set up yet
   //
   if (!is_dir($cal_dir))
      $privateCals = array();
   else
      $privateCals = cal_file_get_all_owned_calendars_in_dir($user, $userType, $cal_dir);


   // unpriveleged users just get their private calendars
   //
   if ($userType == SM_CAL_REGULAR_USER)
   {
      return $privateCals;
//      $privateCalID = get_personal_cal_id($user, $domain);
//      if (is_file("$PRIVATE_CAL_DIR/$privateCalID"))
//         return array(getCalendarFromFile("$PRIVATE_CAL_DIR/$privateCalID$CAL_FILE_EXTENSION"));
//      else
//         return array();
   }


   $cal_dir = $SHARED_CAL_DIR;


   // we assume that missing directory simply means
   // no calendars are set up yet
   //
   if (!is_dir($cal_dir)) 
      $sharedCals = array();
   else
      $sharedCals = cal_file_get_all_owned_calendars_in_dir($user, $userType, $cal_dir);


   $cal_dir = $PUBLIC_CAL_DIR;


   // we assume that missing directory simply means
   // no calendars are set up yet
   //
   if (!is_dir($cal_dir)) 
      $publicCals = array();
   else
      $publicCals = cal_file_get_all_owned_calendars_in_dir($user, $userType, $cal_dir);


   $calList = array_merge($privateCals, $sharedCals, $publicCals);
   return $calList;

}



/**
  * Returns a listing of all calendars that the user has
  * ownership of in the given directory (and all child
  * directories).  If the user is a superuser, all 
  * calendars are returned (regardless of actual 
  * ownership); if the user is a limited administrator, 
  * the calendars owned by that user are returned; 
  * and if the user is an unpriveleged
  * user, just that user's private calendar is returned
  * (the latter is the only case when a private calendar
  * is returned from this function).
TODO: that's inconsistent.  maybe nothing should be returned in that case
  *
  * Calls itself recursively if need to parse multiple dirs,
  * but we currently are not using hierarchical directories
  * for the calendar owners files.
  *
  * @param string $user The user for which to retrieve calendars
  * @param string $userType The type of user this is, which
  *                         corresponds to the constants defined
  *                         in the {@link calendar/calendar_constants.php}
  *                         file
  * @param string $cal_dir The directory where the search for calendars
  *                        should begin
  *
  * @return array An array of calendar objects
  *
  */
function cal_file_get_all_owned_calendars_in_dir($user, $userType, $cal_dir)
{

   global $CAL_FILE_EXTENSION;


   if (empty($cal_dir))
   {
      global $color;
      plain_error_message('CAL FILE BACKEND ERROR (cal_file_get_all_owned_calendars_in_dir): no calendar directory given', $color);
      exit;
   }


   // iterate through each calendar and pull the right ones
   //
   $calList = array();
   $DIR = opendir($cal_dir);
   while (($dirfile = readdir($DIR)) !== FALSE)
   {

      $file = $cal_dir . '/' . $dirfile;


      // call recursively into child directories
      //
      if (is_dir($file) && $dirfile != '.' && $dirfile != '..')
      {
         $childList = cal_file_get_all_owned_calendars_in_dir($user, $userType, $file);
         $calList = array_merge($calList, $childList);
         continue;
      }


      // all calendar files are prefaced with "sm_cal"
// NOTE: not true for imported calendars
      // and end with ".ics"
      //
      if (/*strpos($dirfile, 'sm_cal') !== 0 ||*/ strpos($dirfile, $CAL_FILE_EXTENSION) != strlen($dirfile) - 4)
         continue;


      // limited admins who are not owners of 
      // a calendar skip to the next one
      //
      else if (is_file($file))
      {

         $cal = getCalendarFromFile($file);


         // but first, don't even allow personal calendars here
         //
// this is no longer the case
//         if ($cal->getCalendarType() != SM_CAL_TYPE_PUBLIC && $cal->getCalendarType() != SM_CAL_TYPE_SHARED)
//            continue;


         if ($userType == SM_CAL_LIMITED_ADMIN)
         {
            if (!$cal->isOwner($user))
               continue;
         }


         // instantiate and add calendar to return array
         //
         $calList[] = $cal;

      }
      
   }

   closedir($DIR);
   return $calList;

}



/**
  * Get calendar
  *
  * Retrieves the given calendar from the backend
  *
  * @param string $calendarID The ID of the calendar to be retrieved
  * @param boolean $quiet When FALSE, if the requested calendar isn't 
  *                       found, an error is shown and execution halts;
  *                       otherwise, FALSE is just returned quietly 
  *                       (optional; default = FALSE)
  *
  * @return mixed A Calendar object corresponding to the desired
  *               calendar, or FALSE if the calendar is not found
  *               and the $quiet parameter is TRUE
  *
  */
function cal_file_get_calendar_do($calendarID, $quiet=FALSE)
{

   global $SHARED_CAL_DIR, $PUBLIC_CAL_DIR, $PRIVATE_CAL_DIR, $CAL_FILE_EXTENSION;
          
   if (file_exists($PUBLIC_CAL_DIR . '/' . $calendarID . $CAL_FILE_EXTENSION))
      return getCalendarFromFile($PUBLIC_CAL_DIR . '/' . $calendarID . $CAL_FILE_EXTENSION);

   if (file_exists($SHARED_CAL_DIR . '/' . $calendarID . $CAL_FILE_EXTENSION))
      return getCalendarFromFile($SHARED_CAL_DIR . '/' . $calendarID . $CAL_FILE_EXTENSION);

   if (file_exists($PRIVATE_CAL_DIR . '/' . $calendarID . $CAL_FILE_EXTENSION))
      return getCalendarFromFile($PRIVATE_CAL_DIR . '/' . $calendarID . $CAL_FILE_EXTENSION);


   if (!$quiet)
   {

      global $color;
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_get_calendar_do): cannot find calendar file for calendar ID ' . $calendarID, $color);
      exit;
   }


   return FALSE;

}



/**
  * Retrieves calendar attributes from the given file into
  * a Calendar object, which it then returns.
  *
  * Note: assumes file exists and is readable!
  *
  * @param string $file The full file path to the desired calendar
  *                     attributes file.
  *
  * @return object A Calendar object corresponding to the given file.
  *
  */
function getCalendarFromFile($file)
{

   // read the file all at once
   //
   $fileContents = file($file);


   return Calendar::getCalendarFromICal($fileContents);

}



/**
  * Creates a new calendar
  *
  * Takes the given calendar object and inserts it into the
  * backend as a new calendar.  The ID contained in the given
  * calendar is expected to be a correct unique ID value.
  *
  * @param object $calendar The new calendar object
  *
  */
function cal_file_create_calendar_do($calendar)
{

   global $SHARED_CAL_DIR, $PUBLIC_CAL_DIR, $PRIVATE_CAL_DIR, 
          $EVENT_DIR, $MAIN_CAL_DIR, $CAL_FILE_EXTENSION, $color;



   // make sure main calendar directory is there; create it if not
   //
   if (!is_dir($MAIN_CAL_DIR))
   {
      if (!mkdir($MAIN_CAL_DIR, 0770))
      {
         plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_calendar_do): cannot create calendar directory ' . $MAIN_CAL_DIR, $color);
         exit;
      }
   }


   // make sure main calendar events directory is there; create it if not
   //
   if (!is_dir($EVENT_DIR))
      if (!mkdir($EVENT_DIR, 0770))
      {
         plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_calendar_do): cannot create calendar events directory', $color);
         exit;
      }



   $event_dir = $EVENT_DIR . '/' . $calendar->getID();
   $cal_dir = '';
   if ($calendar->getCalendarType() == SM_CAL_TYPE_PERSONAL)
      $cal_dir = $PRIVATE_CAL_DIR;
   else if ($calendar->getCalendarType() == SM_CAL_TYPE_SHARED)
      $cal_dir = $SHARED_CAL_DIR;
   else if ($calendar->getCalendarType() == SM_CAL_TYPE_PUBLIC)
      $cal_dir = $PUBLIC_CAL_DIR;
   else
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_calendar_do): bad calendar type', $color);
      exit;
   }


   // create new calendar file and events directories
   //
   if (!is_dir($cal_dir))
      if (!mkdir($cal_dir, 0770))
      {
         plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_calendar_do): cannot create calendar subdirectory', $color);
         exit;
      }


/* nah, wait to do this when user creates first event... if we do this here,
   we also need to create holiday and recurring subdirectories 

   if (!is_dir($event_dir))
      if (!mkdir($event_dir, 0770))
      {
         plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_calendar_do): cannot create calendar subdirectory', $color);
         exit;
      }
*/


   $calFile = $cal_dir . '/' . $calendar->getID() . $CAL_FILE_EXTENSION;


   if (file_exists($calFile))
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_create_calendar_do): calendar ' . $calendar->getID() .  ' already exists!', $color);
      exit;
   }


   // write calendar out to file
   //
   writeCalendarToFile($calendar, $calFile);

}



/**
  * Updates a calendar
  *
  * Updates the given calendar by replacing it in the backend
  * with the given calendar object.
  *
  * @param object $calendar The updated calendar object
  *
  */
function cal_file_update_calendar_do($calendar)
{
      
   global $SHARED_CAL_DIR, $PUBLIC_CAL_DIR, $PRIVATE_CAL_DIR, 
          $CAL_FILE_EXTENSION, $color;

         
   $cal_dir = '';
   if ($calendar->getCalendarType() == SM_CAL_TYPE_PERSONAL)
      $cal_dir = $PRIVATE_CAL_DIR;
   else if ($calendar->getCalendarType() == SM_CAL_TYPE_SHARED)
      $cal_dir = $SHARED_CAL_DIR;
   else if ($calendar->getCalendarType() == SM_CAL_TYPE_PUBLIC)
      $cal_dir = $PUBLIC_CAL_DIR;
   else
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_update_calendar_do): bad calendar type', $color);
      exit;
   }


   // make sure the calendar exists
   //
   if (!file_exists($cal_dir . '/' . $calendar->getID() . $CAL_FILE_EXTENSION))
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_update_calendar_do): calendar ' . $calendar->getID() . ' does not exist', $color);
      exit;
   }


   // write calendar out to file
   //
   writeCalendarToFile($calendar, $cal_dir . '/' . $calendar->getID() . $CAL_FILE_EXTENSION);

}



/**
  * Stores calendar attributes from the given Calendar object 
  * into the given file.
  * 
  * Note: overwrites whatever data might already be in the file!
  *
  * @param object $calendar The Calendar object to be written to file
  * @param string $file The full file path to the desired calendar
  *                     attributes file.
  *
  */
function writeCalendarToFile($calendar, $file)
{

   global $color;
   $CAL_FILE = @fopen($file, 'w');
   if (!$CAL_FILE)
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (writeCalendarToFile): cannot open calendar file', $color);
      @fclose($CAL_FILE);
      exit;
   }


   // get iCal text
   //
   $iCalText = $calendar->getICal(TRUE);


   // write calendar
   //
   if (!fwrite($CAL_FILE, $iCalText))
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (writeCalendarToFile): cannot write to calendar file', $color);
      fclose($CAL_FILE);
      exit;
   }


   fclose($CAL_FILE);

}



/**
  * Delete calendar
  *
  * Removes the given calendar from the system.
  *
  * @param string $calendarID The ID of the calendar to be removed
  *
  */
function cal_file_delete_calendar_do($calendarID)
{

   global $SHARED_CAL_DIR, $PUBLIC_CAL_DIR, $PRIVATE_CAL_DIR, 
          $EVENT_DIR, $CAL_FILE_EXTENSION, $color;


   $calendar = cal_file_get_calendar_do($calendarID);
   if ($calendar->getCalendarType() == SM_CAL_TYPE_PERSONAL)
      $cal_file = $PRIVATE_CAL_DIR . '/' . $calendar->getID() . $CAL_FILE_EXTENSION;
   else if ($calendar->getCalendarType() == SM_CAL_TYPE_SHARED)
      $cal_file = $SHARED_CAL_DIR . '/' . $calendar->getID() . $CAL_FILE_EXTENSION;
   else if ($calendar->getCalendarType() == SM_CAL_TYPE_PUBLIC)
      $cal_file = $PUBLIC_CAL_DIR . '/' . $calendar->getID() . $CAL_FILE_EXTENSION;
   else
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_calendar_do): cannot determine calendar type for calendar ID ' . $calendarID, $color);
      exit;
   }


   // recursively remove all events
   //
   if (is_dir($EVENT_DIR . '/' . $calendar->getID())) 
      cal_file_rmdir($EVENT_DIR . '/' . $calendar->getID());


   // remove calendar data file 
   //
   if (!unlink($cal_file))
   {
      plain_error_message('ERROR IN CALENDAR FILE BACKEND (cal_file_delete_calendar_do): cannot delete calendar file', $color);
      exit;
   }

}



?>
