[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/calendar/inc/ -> class.uiforms.inc.php (source)

   1  <?php
   2  /**************************************************************************\
   3  * eGroupWare - Calendar - forms of the UserInterface                       *
   4  * http://www.egroupware.org                                                *
   5  * Written and (c) 2004/5 by Ralf Becker <RalfBecker@outdoor-training.de>   *
   6  * --------------------------------------------                             *
   7  *  This program is free software; you can redistribute it and/or modify it *
   8  *  under the terms of the GNU General Public License as published by the   *
   9  *  Free Software Foundation; either version 2 of the License, or (at your  *
  10  *  option) any later version.                                              *
  11  \**************************************************************************/
  12  
  13  /* $Id: class.uiforms.inc.php 23142 2006-12-27 15:04:37Z ralfbecker $ */
  14  
  15  include_once (EGW_INCLUDE_ROOT . '/calendar/inc/class.uical.inc.php');
  16  
  17  /**
  18   * calendar UserInterface forms: view and edit events, freetime search
  19   *
  20   * The new UI, BO and SO classes have a strikt definition, in which time-zone they operate:
  21   *  UI only operates in user-time, so there have to be no conversation at all !!!
  22   *  BO's functions take and return user-time only (!), they convert internaly everything to servertime, because
  23   *  SO operates only on server-time
  24   *
  25   * The state of the UI elements is managed in the uical class, which all UI classes extend.
  26   *
  27   * All permanent debug messages of the calendar-code should done via the debug-message method of the bocal class !!!
  28   *
  29   * @package calendar
  30   * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
  31   * @copyright (c) 2004/5 by RalfBecker-At-outdoor-training.de
  32   * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
  33   */
  34  class uiforms extends uical
  35  {
  36      var $public_functions = array(
  37          'freetimesearch'  => True,
  38          'edit' => true,
  39          'view' => true,
  40          'export' => true,
  41          'import' => true,
  42      );
  43      
  44      /**
  45       * Standard durations used in edit and freetime search
  46       *
  47       * @var array
  48       */
  49      var $durations = array();
  50      
  51      /**
  52       * Constructor
  53       */
  54  	function uiforms()
  55      {
  56          $this->uical(true);    // call the parent's constructor
  57          
  58          $this->link =& $this->bo->link;
  59          
  60          for ($n=15; $n <= 8*60; $n+=($n < 60 ? 15 : ($n < 240 ? 30 : 60)))
  61          {
  62              $this->durations[$n*60] = sprintf('%d:%02d',$n/60,$n%60);
  63          }
  64      }
  65      
  66      /**
  67       * View a calendar event
  68       */
  69  	function view()
  70      {
  71          return $this->edit(null,array('view' => true));
  72      }
  73  
  74      /**
  75       * Create a default event (adding a new event) by evaluating certain _GET vars
  76       *
  77       * @return array event-array
  78       */ 
  79      function &default_add_event()
  80      {
  81          $extra_participants = $_GET['participants'] ? explode(',',$_GET['participants']) : array();
  82  
  83          if (isset($_GET['owner']))
  84          {
  85              $owner = $_GET['owner'];
  86          }
  87          // dont set the planner start group as owner/participants if called from planner
  88          elseif ($this->view != 'planner' || $this->owner != $this->cal_prefs['planner_start_with_group'])
  89          {
  90              $owner = $this->owner;
  91          }
  92          if (!$owner || !is_numeric($owner) || $GLOBALS['egw']->accounts->get_type($owner) != 'u' || 
  93              !$this->bo->check_perms(EGW_ACL_ADD,0,$owner))
  94          {
  95              if ($owner)    // make an owner who is no user or we have no add-rights a participant
  96              {
  97                  $extra_participants += explode(',',$owner);
  98              }
  99              $owner = $this->user;
 100          }
 101          //echo "<p>this->owner=$this->owner, _GET[owner]=$_GET[owner], user=$this->user => owner=$owner, extra_participants=".implode(',',$extra_participants)."</p>\n";
 102  
 103          // by default include the owner as participant (the user can remove him)
 104          $extra_participants[] = $owner;
 105  
 106          $start = $this->bo->date2ts(array(
 107              'full' => isset($_GET['date']) && (int) $_GET['date'] ? (int) $_GET['date'] : $this->date,
 108              'hour' => (int) (isset($_GET['hour']) && (int) $_GET['hour'] ? $_GET['hour'] : $this->bo->cal_prefs['workdaystarts']),
 109              'minute' => (int) $_GET['minute'],
 110          ));
 111          //echo "<p>_GET[date]=$_GET[date], _GET[hour]=$_GET[hour], _GET[minute]=$_GET[minute], this->date=$this->date ==> start=$start=".date('Y-m-d H:i',$start)."</p>\n";
 112          
 113          $participant_types['u'] = $participant_types = $participants = array();
 114          foreach($extra_participants as $uid)
 115          {
 116              if (isset($participants[$uid])) continue;    // already included
 117  
 118              if (is_numeric($uid))
 119              {
 120                  $participants[$uid] = $participant_types['u'][$uid] = $uid == $this->user ? 'A' : 'U';
 121              }
 122              elseif (is_array($this->bo->resources[$uid{0}]))
 123              {
 124                  $res_data = $this->bo->resources[$uid{0}];
 125                  list($id,$quantity) = explode(':',substr($uid,1));
 126                  $participants[$uid] = $participant_types[$uid{0}][$id] = ($res_data['new_status'] ? ExecMethod($res_data['new_status'],$id) : 'U').
 127                      ((int) $quantity > 1 ? (int)$quantity : '');
 128                  // if new_status == 'x', resource is not bookable
 129                  if(strstr($participant_types[$uid{0}][$id],'x')) 
 130                  {
 131                      unset($participant_types[$uid{0}][$id]);
 132                      unset($participants[$uid]);
 133                  }
 134              }
 135          }
 136          return array(
 137              'participant_types' => $participant_types,
 138              'participants' => $participants,
 139              'owner' => $owner,
 140              'start' => $start,
 141              'end'   => $start + (int) $this->bo->cal_prefs['defaultlength']*60,
 142              'priority' => 2,    // normal
 143              'public'=> $this->cal_prefs['default_private'] ? 0 : 1,
 144              'alarm' => array(),
 145          );
 146      }
 147      
 148      /**
 149       * Process the edited event and evtl. call edit to redisplay it
 150       *
 151       * @param array $content posted eTemplate content
 152       */
 153  	function process_edit($content)
 154      {
 155          //echo "content submitted="; _debug_array($content);
 156          list($button) = @each($content['button']);
 157          unset($content['button']);
 158  
 159          $view = $content['view'] && $button != 'edit' && $button != 'exception';
 160          if ($view && $button == 'vcal')
 161          {
 162              $msg = $this->export($content['id'],true);
 163          }
 164          // delete a recur-exception
 165          if ($content['recur_exception']['delete_exception'])
 166          {
 167              list($date) = each($content['recur_exception']['delete_exception']);
 168              unset($content['recur_exception']['delete_exception']);
 169              if (($key = array_search($date,$content['recur_exception'])) !== false)
 170              {
 171                  unset($content['recur_exception'][$key]);
 172                  $content['recur_exception'] = array_values($content['recur_exception']);
 173              }
 174          }
 175          // delete an alarm
 176          if ($content['alarm']['delete_alarm'])
 177          {
 178              list($id) = each($content['alarm']['delete_alarm']);
 179              //echo "delete alarm $id"; _debug_array($content['alarm']['delete_alarm']);
 180              
 181              if ($content['id'])
 182              {
 183                  if ($this->bo->delete_alarm($id))
 184                  {
 185                      $msg = lang('Alarm deleted');
 186                      unset($content['alarm'][$id]);
 187                  }
 188                  else
 189                  {
 190                      $msg = lang('Permission denied');                
 191                  }
 192              }
 193              else
 194              {
 195                  unset($content['alarm'][$id]);
 196              }
 197          }
 198          if ($content['duration'])
 199          {
 200              $content['end'] = $content['start'] + $content['duration'];
 201          }
 202          $event = $content;
 203          unset($event['new_alarm']);
 204          unset($event['alarm']['delete_alarm']);
 205          unset($event['duration']);
 206  
 207          if (in_array($button,array('ignore','freetime','reedit')))    // called from conflict display
 208          {
 209              // no conversation necessary, event is already in the right format
 210          }
 211          elseif (isset($content['participants']) && !(isset($content['view']) && $content['view']))    // convert content => event
 212          {
 213              //echo "participants="; _debug_array($content['participants']);
 214              $event['participants'] = $event['participant_types'] = array();
 215              foreach($content['participants'] as $app => $participants)
 216              {
 217                  if (!$participants) continue;
 218  
 219                  $type = 'u';
 220                  foreach($this->bo->resources as $t => $data)
 221                  {
 222                      if ($data['app'] == $app)
 223                      {
 224                          $type = $t;
 225                          break;
 226                      }
 227                  }
 228                  foreach(is_array($participants) ? $participants : explode(',',$participants) as $id)
 229                  {
 230                      if (is_array($id)) continue;    // ignore the status
 231                      list($id,$quantity) = explode(':',$id);
 232                      $event['participants'][$type == 'u' ? (int) $id : $type.$id] = $event['participant_types'][$type][$id] = 
 233                          // for existing participants use their old status (dont change it)
 234                          (isset($content['participant_types'][$type][$id]) ? $content['participant_types'][$type][$id]{0} : 
 235                          // for new participants check if they have a 'new_status' resource-methode to determine the status
 236                          (isset($this->bo->resources[$type]['new_status']) ? ExecMethod($this->bo->resources[$type]['new_status'],$id) : 
 237                          // if not use 'A'=accepted for the current user and 'U' otherwise
 238                          ($type == 'u' && $id == $this->bo->user ? 'A' : 'U'))).((int) $quantity > 1 ? (int)$quantity : '');
 239                          // ToDo: move this logic into bocal
 240                  }
 241              }
 242              if ($content['whole_day'])
 243              {
 244                  $event['start'] = $this->bo->date2array($event['start']);
 245                  $event['start']['hour'] = $event['start']['minute'] = 0; unset($event['start']['raw']);
 246                  $event['start'] = $this->bo->date2ts($event['start']);
 247                  $event['end'] = $this->bo->date2array($event['end']);
 248                  $event['end']['hour'] = 23; $event['end']['minute'] = $event['end']['second'] = 59; unset($event['end']['raw']);
 249                  $event['end'] = $this->bo->date2ts($event['end']);
 250              }
 251              // some checks for recurances, if you give a date, make it a weekly repeating event and visa versa
 252              if ($event['recur_type'] == MCAL_RECUR_NONE && $event['recur_data']) $event['recur_type'] = MCAL_RECUR_WEEKLY;
 253              if ($event['recur_type'] == MCAL_RECUR_WEEKLY && !$event['recur_data'])
 254              {
 255                  $event['recur_data'] = 1 << (int)date('w',$event['start']);
 256              }
 257          }
 258          else    // status change view
 259          {
 260              foreach($event['participants'] as $name => $data)
 261              {
 262                  if (!is_array($data)) continue;
 263  
 264                  $type = 'u';
 265                  foreach($this->bo->resources as $t => $d)
 266                  {
 267                      if ($d['app'] == $name)
 268                      {
 269                          $type = $t;
 270                          break;
 271                      }
 272                  }
 273                  // checking for status changes
 274                  foreach($data[$name.'_status'] as $uid => $status)
 275                  {
 276                      list($uid,$quantity) = explode(':',$uid);
 277                      //echo "checking $type: $uid $status against old ".$event['participant_types'][$type][$uid]."<br />\n";
 278                      if ($event['participant_types'][$type][$uid]{0} != $status{0})    // status changed by user
 279                      {
 280                          if ($this->bo->set_status($event['id'],$type,$uid,$status,$event['recur_type'] != MCAL_RECUR_NONE ? $event['start'] : 0))
 281                          {
 282                              $event['participants'][$type == 'u' ? (int) $uid : $type.$uid] = 
 283                                  $event['participant_types'][$type][$uid] = $status.$quantity;
 284                              // refreshing the calendar-view with the changed participant-status
 285                              $msg = lang('Status changed');
 286                              if (!$preserv['no_popup'])
 287                              {
 288                                  $js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
 289                                      'menuaction' => $content['referer'],
 290                                      'msg' => $msg,
 291                                  ))).'\';';
 292                              }
 293                          }
 294                      }
 295                  }
 296                  unset($event['participants'][$name]);    // unset the status-changes from the event
 297              }
 298          }
 299          $preserv = array(
 300              'view'        => $view,
 301              'edit_single' => $content['edit_single'],
 302              'referer'     => $content['referer'],
 303              'no_popup'    => $content['no_popup'],
 304          );
 305          switch($button)
 306          {
 307          case 'exception':    // create an exception in a recuring event
 308              $preserv['edit_single'] = $content['start'];
 309              $event['recur_type'] = MCAL_RECUR_NONE;
 310              foreach(array('recur_enddate','recur_interval','recur_exception','recur_data') as $name)
 311              {
 312                  unset($event[$name]);
 313              }
 314              break;
 315  
 316          case 'edit':
 317              if ($content['recur_type'] != MCAL_RECUR_NONE)
 318              {
 319                  // need to reload start and end of the serie
 320                  $event = $this->bo->read($event['id'],0);
 321              }
 322              break;
 323                  
 324          case 'copy':    // create new event with copied content, some content need to be unset to make a "new" event
 325              unset($event['id']);
 326              unset($event['uid']);
 327              unset($event['alarm']);
 328              unset($event['reference']);
 329              unset($event['recur_exception']);
 330              unset($event['edit_single']);    // in case it has been set
 331              unset($event['modified']);
 332              unset($event['modifier']);
 333              $event['owner'] = !(int)$this->owner || !$this->bo->check_perms(EGW_ACL_ADD,0,$this->owner) ? $this->user : $this->owner;
 334              $preserv['view'] = $preserv['edit_single'] = false;
 335              $msg = lang('Event copied - the copy can now be edited');
 336              $event['title'] = lang('Copy of:').' '.$event['title'];
 337              break;
 338              
 339          case 'ignore':
 340              $ignore_conflicts = true;
 341              $button = $event['button_was'];    // save or apply
 342              unset($event['button_was']);
 343              // fall through
 344          case 'save':
 345          case 'apply':
 346              if ($event['id'] && !$this->bo->check_perms(EGW_ACL_EDIT,$event)) 
 347              { 
 348                  $msg = lang('Permission denied'); 
 349                  break; 
 350              }
 351              if ($event['start'] > $event['end'])
 352              {
 353                  $msg = lang('Error: Starttime has to be before the endtime !!!');
 354                  $button = '';
 355                  break;
 356              }
 357              if (!$event['participants'])
 358              {
 359                  $msg = lang('Error: no participants selected !!!');
 360                  $button = '';
 361                  break;
 362              }
 363              if ($content['edit_single'])    // we edited a single event from a series
 364              {
 365                  $event['reference'] = $event['id'];
 366                  unset($event['id']);
 367                  unset($event['uid']);
 368                  $conflicts = $this->bo->update($event,$ignore_conflicts);
 369                  if (!is_array($conflicts) && $conflicts)
 370                  {
 371                      // now we need to add the original start as recur-execption to the series
 372                      $recur_event = $this->bo->read($event['reference']);
 373                      $recur_event['recur_exception'][] = $content['edit_single'];
 374                      unset($recur_event['start']); unset($recur_event['end']);    // no update necessary
 375                      $this->bo->update($recur_event,true);    // no conflict check here
 376                      unset($recur_event);
 377                      unset($event['edit_single']);            // if we further edit it, it's just a single event
 378                      unset($preserv['edit_single']);
 379                  }
 380                  else    // conflict or error, we need to reset everything to the state befor we tried to save it
 381                  {
 382                      $event['id'] = $event['reference'];
 383                      unset($event['reference']);
 384                      $event['uid'] = $content['uid'];
 385                  }
 386              }
 387              else    // we edited a non-reccuring event or the whole series
 388              {
 389                  $conflicts = $this->bo->update($event,$ignore_conflicts);
 390                  unset($event['ignore']);
 391              }
 392              if (is_array($conflicts))
 393              {
 394                  $event['button_was'] = $button;    // remember for ignore
 395                  return $this->conflicts($event,$conflicts,$preserv);
 396              }
 397              elseif($conflicts)    // true and non-array means Ok ;-)
 398              {
 399                  $msg .= ($msg ? ', ' : '') . lang('Event saved');
 400  
 401                  // writing links for new entry, existing ones are handled by the widget itself
 402                  if (!$content['id'] && is_array($content['link_to']['to_id']))    
 403                  {
 404                      $this->link->link('calendar',$event['id'],$content['link_to']['to_id']);
 405                  }
 406                  $js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
 407                      'menuaction' => $content['referer'],
 408                      'msg' => $msg,
 409                  ))).'\';';
 410  
 411                  if ($content['custom_mail'])
 412                  {
 413                      $js = $this->custom_mail($event,!$content['id'])."\n".$js;    // first open the new window and then update the view
 414                      unset($event['custom_mail']);
 415                  }
 416              }
 417              else
 418              {
 419                  $msg = lang('Error: saving the event !!!');
 420              }
 421              break;
 422              
 423          case 'delete':
 424              if ($this->bo->delete($event['id'],(int)$content['edit_single']))
 425              {
 426                  $msg = lang('Event deleted');
 427                  $js = 'opener.location.href=\''.addslashes($GLOBALS['egw']->link('/index.php',array(
 428                      'menuaction' => $content['referer'],
 429                      'msg' => $msg,
 430                  ))).'\';';
 431              }
 432              break;
 433              
 434          case 'freetime':
 435              if (!is_object($GLOBALS['egw']->js))
 436              {
 437                  $GLOBALS['egw']->js =& CreateObject('phpgwapi.javascript');
 438              }
 439              // the "click" has to be in onload, to make sure the button is already created
 440              $GLOBALS['egw']->js->set_onload("document.getElementsByName('exec[freetime]')[0].click();");
 441              break;
 442              
 443          case 'add_alarm':
 444              if ($this->bo->check_perms(EGW_ACL_EDIT,!$content['new_alarm']['owner'] ? $event : 0,$content['new_alarm']['owner']))
 445              {
 446                  $offset = DAY_s * $content['new_alarm']['days'] + HOUR_s * $content['new_alarm']['hours'] + 60 * $content['new_alarm']['mins'];
 447                  $alarm = array(
 448                      'offset' => $offset,
 449                      'time'   => $content['start'] - $offset,
 450                      'all'    => !$content['new_alarm']['owner'],
 451                      'owner'  => $content['new_alarm']['owner'] ? $content['new_alarm']['owner'] : $this->user,
 452                  );
 453                  if ($alarm['time'] < $this->bo->now_su)
 454                  {
 455                      $msg = lang("Can't add alarms in the past !!!");
 456                  }
 457                  elseif ($event['id'])    // save the alarm immediatly
 458                  {
 459                      if(($alarm_id = $this->bo->save_alarm($event['id'],$alarm)))
 460                      {
 461                          $alarm['id'] = $alarm_id;
 462                          $event['alarm'][$alarm_id] = $alarm;
 463                          
 464                          $msg = lang('Alarm added');
 465                      }
 466                      else
 467                      {
 468                          $msg = lang('Error adding the alarm');
 469                      }
 470                  }
 471                  else
 472                  {
 473                      for($alarm['id']=1; isset($event['alarm'][$alarm['id']]); $alarm['id']++);    // get a temporary non-conflicting, numeric id
 474                      $event['alarm'][$alarm['id']] = $alarm;
 475                  }
 476              }
 477              else
 478              {
 479                  $msg = lang('Permission denied');
 480              }
 481              break;
 482          }
 483          if (in_array($button,array('cancel','save','delete','delete_series')))
 484          {
 485              if ($content['no_popup'])
 486              {
 487                  $GLOBALS['egw']->redirect_link('/index.php',array(
 488                      'menuaction' => $content['referer'],
 489                      'msg'        => $msg,
 490                  ));
 491              }
 492              $js .= 'window.close();';
 493              echo "<html><body onload=\"$js\"></body></html>\n";
 494              $GLOBALS['egw']->common->egw_exit();
 495          }
 496          return $this->edit($event,$preserv,$msg,$js,$event['id'] ? $event['id'] : $content['link_to']['to_id']);
 497      }
 498  
 499      /**
 500       * return javascript to open felamimail compose window with preset content to mail all participants
 501       *
 502       * @param array $event
 503       * @param boolean $added
 504       * @return string javascript window.open command
 505       */
 506  	function custom_mail($event,$added)
 507      {
 508          $to = array();
 509          foreach($event['participants'] as $uid => $status)
 510          {
 511              if (is_numeric($uid) && $uid != $this->user && $status != 'R' && $GLOBALS['egw']->accounts->get_type($uid) == 'u')
 512              {
 513                  $GLOBALS['egw']->accounts->get_account_name($uid,$lid,$firstname,$lastname);
 514                   
 515                  $to[] = $firstname.' '.$lastname.
 516                      ' <'.$GLOBALS['egw']->accounts->id2name($uid,'account_email').'>';
 517              }
 518          }
 519          list($subject,$body) = $this->bo->get_update_message($event,$added ? MSG_ADDED : MSG_MODIFIED);    // update-message is in TZ of the user
 520  
 521          $boical =& CreateObject('calendar.boical');
 522          $ics = $boical->exportVCal(array($event),'2.0','request');
 523  
 524          $ics_file = tempnam($GLOBALS['egw_info']['server']['temp_dir'],'ics');
 525          if(($f = fopen($ics_file,'w')))
 526          {
 527              fwrite($f,$ics);
 528              fclose($f);
 529          }
 530          $vars = array(
 531              'menuaction'      => 'felamimail.uicompose.compose',
 532              'preset[to]'      => implode(', ',$to),
 533              'preset[subject]' => $subject,
 534              'preset[body]'    => $body,
 535              'preset[name]'    => 'event.ics',
 536              'preset[file]'    => $ics_file,
 537              'preset[type]'    => 'text/calendar; method=request',
 538              'preset[size]'    => filesize($ics_file),
 539          );
 540          return "window.open('".$GLOBALS['egw']->link('/index.php',$vars)."','_blank','width=700,height=700,scrollbars=yes,status=no');";
 541      }
 542  
 543      /**
 544       * Edit a calendar event
 545       *
 546       * @param array $event=null Event to edit, if not $_GET['cal_id'] contains the event-id
 547       * @param array $perserv=null following keys:
 548       *    view boolean view-mode, if no edit-access we automatic fallback to view-mode
 549       *    referer string menuaction of the referer
 550       *    no_popup boolean use a popup or not
 551       *    edit_single int timestamp of single event edited, unset/null otherwise
 552       * @param string $msg='' msg to display
 553       * @param string $js='window.focus();' javascript to include in the page
 554       * @param mixed $link_to_id='' $content from or for the link-widget
 555       */
 556  	function edit($event=null,$preserv=null,$msg='',$js = 'window.focus();',$link_to_id='')
 557      {
 558          $etpl =& CreateObject('etemplate.etemplate','calendar.edit');
 559          
 560          $sel_options = array(
 561              'recur_type'      => &$this->bo->recur_types,
 562              'accounts_status' => $this->bo->verbose_status,
 563              'owner'           => array(),
 564              'duration'        => $this->durations,
 565          );
 566          if (!is_array($event))
 567          {
 568              $preserv = array(
 569                  'no_popup' => isset($_GET['no_popup']),
 570                  'referer'  => preg_match('/menuaction=([^&]+)/',$_SERVER['HTTP_REFERER'],$matches) ? $matches[1] : $this->view_menuaction,
 571                  'view'     => $preserv['view'],
 572              );
 573              $cal_id = (int) $_GET['cal_id'];
 574              
 575              if (!$cal_id || $cal_id && !($event = $this->bo->read($cal_id,$_GET['date'])) || !$this->bo->check_perms(EGW_ACL_READ,$event))
 576              {
 577                  if ($cal_id) 
 578                  {
 579                      if (!$preserv['no_popup'])
 580                      {
 581                          $js = "alert('".lang('Permission denied')."'); window.close();";
 582                      }
 583                      else
 584                      {
 585                          $GLOBALS['egw']->common->egw_header();
 586                          parse_navbar();
 587                          echo '<p class="redItalic" align="center">'.lang('Permission denied')."</p>\n";
 588                          $GLOBALS['egw']->common->egw_exit();
 589                      }
 590                  }
 591                  $event =& $this->default_add_event();
 592              }
 593              // check if the event is the whole day
 594              $start = $this->bo->date2array($event['start']);
 595              $end = $this->bo->date2array($event['end']);
 596              $event['whole_day'] = !$start['hour'] && !$start['minute'] && $end['hour'] == 23 && $end['minute'] == 59;
 597  
 598              $link_to_id = $event['id'];
 599              if (!$add_link && !$event['id'] && isset($_GET['link_app']) && isset($_GET['link_id']) &&
 600                  preg_match('/^[a-z_0-9-]+:[:a-z_0-9-]+$/i',$_GET['link_app'].':'.$_GET['link_id']))    // gard against XSS
 601              {
 602                  $this->link->link('calendar',$link_to_id,$_GET['link_app'],$_GET['link_id']);
 603              }
 604          }
 605          $view = $preserv['view'] = $preserv['view'] || $event['id'] && !$this->bo->check_perms(EGW_ACL_EDIT,$event);
 606          //echo "view=$view, event="; _debug_array($event);
 607          $content = array_merge($event,array(
 608              'link_to' => array(
 609                  'to_id'  => $link_to_id,
 610                  'to_app' => 'calendar',
 611              ),
 612              'edit_single' => $preserv['edit_single'],    // need to be in content too, as it is used in the template
 613              'view' => $view,
 614          ));
 615          $content['participants'] = array();
 616  
 617          $content['duration'] = $content['end'] - $content['start'];
 618          if (isset($this->durations[$content['duration']])) $content['end'] = '';
 619  
 620          foreach($event['participant_types'] as $type => $participants)
 621          {
 622              $name = 'accounts';
 623              if (isset($this->bo->resources[$type]))
 624              {
 625                  $name = $this->bo->resources[$type]['app'];
 626              }
 627              foreach($participants as $id => $status)
 628              {
 629                  $content['participants'][$name][] = $id . (substr($status,1) > 1 ? (':'.substr($status,1)) : '');
 630              }
 631  
 632              if ($view)
 633              {
 634                  $stati =& $content['participants'][$name][$name.'_status'];
 635                  $stati = $participants;
 636                  // enumerate group-invitations, so people can accept/reject them
 637                  if ($name == 'accounts')
 638                  {
 639                      foreach($participants as $id => $status)
 640                      {
 641                          if ($GLOBALS['egw']->accounts->get_type($id) == 'g' &&
 642                              ($members = $GLOBALS['egw']->accounts->member($id)))
 643                          {
 644                              $sel_options['accounts_status']['G'] = lang('Select one');
 645                              foreach($members as $member)
 646                              {
 647                                  if (!isset($stati[$member['account_id']]) && $this->bo->check_perms(EGW_ACL_EDIT,0,$member['account_id']))
 648                                  {
 649                                      $stati[$member['account_id']] = 'G';    // status for invitation via membership in group
 650                                      $content['participants'][$name][] = $member['account_id'];
 651                                  }
 652                              }
 653                          }
 654                      }
 655                  }
 656                  foreach($stati as $id => $status)
 657                  {
 658                      $readonlys[$name.'_status['.$id.']'] = !$this->bo->check_perms(EGW_ACL_EDIT,0,($type != 'u' ? $type : '').$id);
 659                  }
 660              }
 661          }
 662  //         echo '$content[participants]'; _debug_array($content['participants']);
 663  //         echo '$content[participant_types]'; _debug_array($content['participant_types']);
 664  //         _debug_array($sel_options);
 665          $preserv = array_merge($preserv,$view ? $event : $content);
 666  
 667          if ($event['alarm'])
 668          {
 669              // makes keys of the alarm-array starting with 1
 670              $content['alarm'] = array(false);
 671              foreach(array_values($event['alarm']) as $id => $alarm)
 672              {
 673                  if (!$alarm['all'] && !$this->bo->check_perms(EGW_ACL_READALARM,0,$alarm['owner']))
 674                  {
 675                      continue;    // no read rights to the calendar of the alarm-owner, dont show the alarm
 676                  }
 677                  $alarm['all'] = (int) $alarm['all'];
 678                  $days = (int) ($alarm['offset'] / DAY_s);
 679                  $hours = (int) (($alarm['offset'] % DAY_s) / HOUR_s);
 680                  $minutes = (int) (($alarm['offset'] % HOUR_s) / 60);
 681                  $label = array();
 682                  if ($days) $label[] = $days.' '.lang('days');
 683                  if ($hours) $label[] = $hours.' '.lang('hours');
 684                  if ($minutes) $label[] = $minutes.' '.lang('Minutes');
 685                  $alarm['offset'] = implode(', ',$label);
 686                  $content['alarm'][] = $alarm;
 687                  
 688                  $readonlys['delete_alarm['.$id.']'] = !$this->bo->check_perms(EGW_ACL_EDIT,$alarm['all'] ? $event : 0,$alarm['owner']);
 689              }
 690          }
 691          else
 692          {
 693              $content['alarm'] = false;
 694          }
 695          $content['msg'] = $msg;
 696  
 697          if ($view)
 698          {
 699              foreach($event as $key => $val)
 700              {
 701                  if ($key != 'alarm') $readonlys[$key] = true;
 702              }
 703              // we need to unset the tab itself, as this would make all content (incl. the change-status selects) readonly
 704              unset($readonlys['general|description|participants|recurrence|custom|links|alarms']);
 705  
 706              $readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['freetime'] = true;
 707              $readonlys['link_to'] = $readonlys['customfields'] = true;
 708              $readonlys['duration'] = true;
 709              
 710              if ($event['recur_type'] != MCAL_RECUR_NONE)
 711              {
 712                  $etpl->set_cell_attribute('button[edit]','help','Edit this series of recuring events');    
 713                  $etpl->set_cell_attribute('button[delete]','help','Delete this series of recuring events');
 714                  $onclick =& $etpl->get_cell_attribute('button[delete]','onclick');
 715                  $onclick = str_replace('Delete this event','Delete this series of recuring events',$onclick);
 716              }
 717          }
 718          else
 719          {
 720              if (!is_object($GLOBALS['egw']->js))
 721              {
 722                  $GLOBALS['egw']->js = CreateObject('phpgwapi.javascript');
 723              }
 724              // We hide the enddate if one of our predefined durations fits
 725              // the call to set_style_by_class has to be in onload, to make sure the function and the element is already created
 726              $GLOBALS['egw']->js->set_onload("set_style_by_class('table','end_hide','visibility','".($content['duration'] && isset($sel_options['duration'][$content['duration']]) ? 'hidden' : 'visible')."');");
 727  
 728              $readonlys['button[copy]'] = $readonlys['button[vcal]'] = true;
 729              unset($preserv['participants']);    // otherwise deleted participants are still reported
 730              $readonlys['recur_exception'] = !count($content['recur_exception']);    // otherwise we get a delete button
 731          }
 732          // disabling the custom fields tab, if there are none
 733          $readonlys['general|description|participants|recurrence|custom|links|alarms'] = array(
 734              'custom' => !count($this->bo->config['customfields'])
 735          );
 736          if ($view || !isset($GLOBALS['egw_info']['user']['apps']['felamimail']))
 737          {
 738              $etpl->disable_cells('custom_mail');
 739          }
 740          if (!($readonlys['button[exception]'] = $readonlys['button[edit]'] = !$view || !$this->bo->check_perms(EGW_ACL_EDIT,$event)))
 741          {
 742              $readonlys['button[exception]'] = $event['recur_type'] == MCAL_RECUR_NONE;
 743          }
 744          $readonlys['button[delete]'] = !$event['id'] || !$this->bo->check_perms(EGW_ACL_DELETE,$event);
 745  
 746          if ($event['id'] || $this->bo->check_perms(EGW_ACL_EDIT,$event))    // new event or edit rights to the event ==> allow to add alarm for all users
 747          {
 748              $sel_options['owner'][0] = lang('All participants');
 749          }
 750          foreach((array) $event['participant_types']['u'] as $uid => $status)
 751          {
 752              if ($status != 'R' && $this->bo->check_perms(EGW_ACL_EDIT,0,$uid))
 753              {
 754                  $sel_options['owner'][$uid] = $this->bo->participant_name($uid);
 755              }
 756          }
 757          $content['no_add_alarm'] = !count($sel_options['owner']);    // no rights to set any alarm
 758          if (!$event['id'])
 759          {
 760              $etpl->set_cell_attribute('button[new_alarm]','type','checkbox');    
 761          }
 762          foreach($this->bo->resources as $res_data)
 763          {
 764              $sel_options[$res_data['app'].'_status'] =& $this->bo->verbose_status;
 765          }
 766          if ($preserv['no_popup'])
 767          {
 768              $etpl->set_cell_attribute('button[cancel]','onclick','');
 769          }
 770          //echo "content="; _debug_array($content);
 771          //echo "preserv="; _debug_array($preserv);
 772           //echo "readonlys="; _debug_array($readonlys);
 773           //echo "sel_options="; _debug_array($sel_options);
 774          $GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . ($event['id'] ? ($view ? lang('View') : 
 775              ($content['edit_single'] ? lang('Edit exception') : lang('Edit'))) : lang('Add'));
 776          $GLOBALS['egw_info']['flags']['java_script'] .= "<script>\n$js\n</script>\n";
 777          $etpl->exec('calendar.uiforms.process_edit',$content,$sel_options,$readonlys,$preserv,$preserv['no_popup'] ? 0 : 2);
 778      }
 779  
 780      /**
 781       * displays a sheduling conflict
 782       *
 783       * @param array $event 
 784       * @param array $conflicts array with conflicting events, the events are not garantied to be readable by the user!
 785       * @param array $preserv data to preserv
 786       */
 787  	function conflicts($event,$conflicts,$preserv)
 788      {
 789          $etpl =& CreateObject('etemplate.etemplate','calendar.conflicts');
 790          
 791          foreach($conflicts as $k => $conflict)
 792          {
 793              $is_readable = $this->bo->check_perms(EGW_ACL_READ,$conflict);
 794              
 795              $conflicts[$k] += array(
 796                  'icon_participants' => $is_readable ? (count($conflict['participants']) > 1 ? 'users' : 'single') : 'private',
 797                  'tooltip_participants' => $is_readable ? implode(', ',$this->bo->participants($conflict)) : '',
 798                  'time' => $this->bo->long_date($conflict['start'],$conflict['end'],true),
 799                  'conflicting_participants' => implode(",\n",$this->bo->participants(array(
 800                      'participants' => array_intersect_key($conflict['participants'],$event['participants']),
 801                  ),true,true)),    // show group invitations too
 802                  'icon_recur' => $conflict['recur_type'] != MCAL_RECUR_NONE ? 'recur' : '',
 803                  'text_recur' => $conflict['recur_type'] != MCAL_RECUR_NONE ? lang('Recurring event') : ' ',
 804              );        
 805          }
 806          $content = $event + array(
 807              'conflicts' => array_values($conflicts),    // conflicts have id-start as key
 808          );
 809          $GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . lang('Scheduling conflict');
 810  
 811          $etpl->exec('calendar.uiforms.process_edit',$content,false,false,array_merge($event,$preserv),$preserv['no_popup'] ? 0 : 2);
 812      }
 813  
 814      /**
 815       * Freetime search
 816       *
 817       * As the function is called in a popup via javascript, parametes get initialy transfered via the url
 818       * @param array $content=null array with parameters or false (default) to use the get-params
 819       * @param string start[str] start-date
 820       * @param string start[hour] start-hour
 821       * @param string start[min] start-minutes
 822       * @param string end[str] end-date
 823       * @param string end[hour] end-hour
 824       * @param string end[min] end-minutes
 825       * @param string participants ':' delimited string of user-id's
 826       */
 827  	function freetimesearch($content = null)
 828      {
 829          $etpl =& CreateObject('etemplate.etemplate','calendar.freetimesearch');
 830  
 831          $sel_options['search_window'] = array(
 832              7*DAY_s        => lang('one week'),
 833              14*DAY_s    => lang('two weeks'),
 834              31*DAY_s    => lang('one month'),
 835              92*DAY_s    => lang('three month'),
 836              365*DAY_s    => lang('one year'),
 837          );
 838          if (!is_array($content))
 839          {
 840              $edit_content = $etpl->process_values2url();
 841  
 842              if ($edit_content['duration'])
 843              {
 844                  $edit_content['end'] = $edit_content['start'] + $edit_content['duration'];
 845              }
 846              if ($edit_content['whole_day'])
 847              {
 848                  $arr = $this->bo->date2array($edit_content['start']);
 849                  $arr['hour'] = $arr['minute'] = $arr['second'] = 0; unset($arr['raw']);
 850                  $edit_content['start'] = $this->bo->date2ts($arr);
 851                  $arr = $this->bo->date2array($edit_content['end']);
 852                  $arr['hour'] = 23; $arr['minute'] = $arr['second'] = 59; unset($arr['raw']);
 853                  $edit_content['end'] = $this->bo->date2ts($arr);
 854              }
 855              $content = array(
 856                  'start'    => $edit_content['start'],
 857                  'duration' => $edit_content['end'] - $edit_content['start'],
 858                  'end'      => $edit_content['end'],
 859                  'cal_id'   => $edit_content['id'],
 860                  'recur_type'   => $edit_content['recur_type'],
 861                  'participants' => array(),
 862              );
 863              foreach($edit_content['participants'] as $app => $ids)
 864              {
 865                  if ($app == 'accounts')
 866                  {
 867                      $content['participants'] += (array)$ids;
 868                  }
 869                  elseif ($ids)
 870                  {
 871                      foreach($this->bo->resources as $type => $data)
 872                      {
 873                          if ($data['app'] == $app) break;
 874                      }
 875                      foreach((array)$ids as $id)
 876                      {
 877                          $content['participants'][] = $type . $id;
 878                      }
 879                  }
 880              }
 881              // default search parameters
 882              $content['start_time'] = $edit_content['whole_day'] ? 0 : $this->cal_prefs['workdaystarts'];
 883              $content['end_time'] = $this->cal_prefs['workdayends'];
 884              if ($this->cal_prefs['workdayends']*HOUR_s < $this->cal_prefs['workdaystarts']*HOUR_s+$content['duration'])
 885              {
 886                  $content['end_time'] = 0;    // no end-time limit, as duration would never fit
 887              }
 888              $content['weekdays'] = MCAL_M_WEEKDAYS;
 889              
 890              $content['search_window'] = 7 * DAY_s;
 891              // pick a searchwindow fitting the duration (search for a 10 day slot in a one week window never succeeds)
 892              foreach($sel_options['search_window'] as $window => $label)
 893              {
 894                  if ($window > $content['duration']) 
 895                  {
 896                      $content['search_window'] = $window;
 897                      break;
 898                  }
 899              }
 900          }
 901          else
 902          {
 903              if (!$content['duration']) $content['duration'] = $content['end'] - $content['start']; 
 904              
 905              if (is_array($content['freetime']['select']))
 906              {
 907                  list($selected) = each($content['freetime']['select']);
 908                  //echo "$selected = ".date('D d.m.Y H:i',$content['freetime'][$selected]['start']);
 909                  $start = (int) $content['freetime'][$selected]['start'];
 910                  $end = $start + $content['duration'];
 911                  /**
 912                   * ToDo: make this an eTemplate function to transmit content back to the opener
 913                   */
 914                  $fields_to_set = array(
 915                      'exec[start][str]'    => date($this->common_prefs['dateformat'],$start),
 916                      'exec[start][i]'    => (int) date('i',$start),
 917                      'exec[end][str]'    => date($this->common_prefs['dateformat'],$end),
 918                      'exec[end][i]'        => (int) date('i',$end),
 919                      'exec[duration]'    => $content['duration'],
 920                  );
 921                  if ($this->common_prefs['timeformat'] == 12)
 922                  {
 923                      $fields_to_set += array(
 924                          'exec[start][H]'    => date('h',$start),
 925                          'exec[start][a]'    => date('a',$start),
 926                          'exec[end][H]'        => date('h',$end),
 927                          'exec[end][a]'        => date('a',$end),
 928                      );
 929                  }
 930                  else    
 931                  {
 932                      $fields_to_set += array(
 933                          'exec[start][H]'    => (int) date('H',$start),
 934                          'exec[end][H]'        => (int) date('H',$end),
 935                      );
 936                  }
 937                  echo "<html>
 938  <script>
 939      var fields = Array('".implode("','",array_keys($fields_to_set))."');
 940      var values = Array('".implode("','",$fields_to_set)."');
 941      for (i=0; i < fields.length; ++i) {
 942          elements = opener.document.getElementsByName(fields[i]);
 943          if (elements) {
 944              if (elements.length == 1)
 945                  elements[0].value = values[i];
 946              else
 947                  for (n=0; n < elements.length; ++n) {
 948                      if (elements[n].value == values[i]) elements[n].checked = true;
 949                  }
 950          }
 951      }
 952      window.close();    
 953  </script>
 954  </html>\n";
 955                  exit;
 956              }
 957          }
 958          if ($content['recur_type'])
 959          {
 960              $content['msg'] .= lang('Only the initial date of that recuring event is checked!');
 961          }
 962          $content['freetime'] = $this->freetime($content['participants'],$content['start'],$content['start']+$content['search_window'],$content['duration'],$content['cal_id']);
 963          $content['freetime'] = $this->split_freetime_daywise($content['freetime'],$content['duration'],$content['weekdays'],$content['start_time'],$content['end_time'],$sel_options);
 964  
 965          //echo "<pre>".print_r($content,true)."</pre>\n";
 966          $GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . lang('freetime search');
 967          // let the window popup, if its already there
 968          $GLOBALS['egw_info']['flags']['java_script'] .= "<script>\nwindow.focus();\n</script>\n";
 969          
 970          if (!is_object($GLOBALS['egw']->js))
 971          {
 972              $GLOBALS['egw']->js = CreateObject('phpgwapi.javascript');
 973          }
 974          $sel_options['duration'] = $this->durations;
 975          if ($content['duration'] && isset($sel_options['duration'][$content['duration']])) $content['end'] = '';
 976          // We hide the enddate if one of our predefined durations fits
 977          // the call to set_style_by_class has to be in onload, to make sure the function and the element is already created
 978          $GLOBALS['egw']->js->set_onload("set_style_by_class('table','end_hide','visibility','".($content['duration'] && isset($sel_options['duration'][$content['duration']]) ? 'hidden' : 'visible')."');");
 979  
 980          $etpl->exec('calendar.uiforms.freetimesearch',$content,$sel_options,'',array(
 981                  'participants'    => $content['participants'],
 982                  'cal_id'        => $content['cal_id'],
 983                  'recur_type'    => $content['recur_type'],
 984              ),2);        
 985      }
 986      
 987      /**
 988       * calculate the freetime of given $participants in a certain time-span
 989       *
 990       * @param array $participants user-id's
 991       * @param int $start start-time timestamp in user-time
 992       * @param int $end end-time timestamp in user-time
 993       * @param int $duration min. duration in sec, default 1
 994       * @param int $cal_id own id for existing events, to exclude them from being busy-time, default 0
 995       * @return array of free time-slots: array with start and end values
 996       */
 997  	function freetime($participants,$start,$end,$duration=1,$cal_id=0)
 998      {
 999          if ($this->debug > 2) $this->bo->debug_message('uiforms::freetime(participants=%1, start=%2, end=%3, duration=%4, cal_id=%5)',true,$participants,$start,$end,$duration,$cal_id);
1000  
1001          $busy = $this->bo->search(array(
1002              'start' => $start,
1003              'end'    => $end,
1004              'users'    => $participants,
1005              'ignore_acl' => true,    // otherwise we get only events readable by the user
1006          ));
1007          $busy[] = array(    // add end-of-search-date as event, to cope with empty search and get freetime til that date
1008              'start'    => $end,
1009              'end'    => $end,
1010          );    
1011          $ft_start = $start;
1012          $freetime = array();
1013          $n = 0;
1014          foreach($busy as $event)
1015          {
1016              if ((int)$cal_id && $event['id'] == (int)$cal_id) continue;    // ignore our own event
1017  
1018               if ($event['non_blocking']) continue; // ignore non_blocking events
1019  
1020              if ($this->debug)
1021              {
1022                  echo "<p>ft_start=".date('D d.m.Y H:i',$ft_start)."<br>\n";
1023                  echo "event[title]=$event[title]<br>\n";
1024                  echo "event[start]=".date('D d.m.Y H:i',$event['start']['raw'])."<br>\n";
1025                  echo "event[end]=".date('D d.m.Y H:i',$event['end']['raw'])."<br>\n";
1026              }
1027              // $events ends before our actual position ==> ignore it
1028              if ($event['end'] < $ft_start)
1029              {
1030                  //echo "==> event ends before ft_start ==> continue<br>\n";
1031                  continue;
1032              }
1033              // $events starts before our actual position ==> set start to it's end and go to next event
1034              if ($event['start'] < $ft_start)
1035              {
1036                  //echo "==> event starts before ft_start ==> set ft_start to it's end & continue<br>\n";
1037                  $ft_start = $event['end'];
1038                  continue;
1039              }
1040              $ft_end = $event['start'];
1041  
1042              // only show slots equal or bigger to min_length
1043              if ($ft_end - $ft_start >= $duration)
1044              {
1045                  $freetime[++$n] = array(
1046                      'start'    => $ft_start,
1047                      'end'    => $ft_end,
1048                  );
1049                  if ($this->debug > 1) echo "<p>freetime: ".date('D d.m.Y H:i',$ft_start)." - ".date('D d.m.Y H:i',$ft_end)."</p>\n";
1050              }    
1051              $ft_start = $event['end'];
1052          }
1053          if ($this->debug > 0) $this->bo->debug_message('uiforms::freetime(participants=%1, start=%2, end=%3, duration=%4, cal_id=%5) freetime=%6',true,$participants,$start,$end,$duration,$cal_id,$freetime);
1054          
1055          return $freetime;
1056      }
1057      
1058      /**
1059       * split the freetime in daywise slot, taking into account weekdays, start- and stop-times
1060       *
1061       * If the duration is bigger then the difference of start- and end_time, the end_time is ignored
1062       *
1063       * @param array $freetime free time-slots: array with start and end values
1064       * @param int $duration min. duration in sec
1065       * @param int $weekdays allowed weekdays, bitfield of MCAL_M_...
1066       * @param int $start_time minimum start-hour 0-23
1067       * @param int $end_time maximum end-hour 0-23, or 0 for none
1068       * @param array $sel_options on return options for start-time selectbox
1069       * @return array of free time-slots: array with start and end values
1070       */
1071  	function split_freetime_daywise($freetime,$duration,$weekdays,$start_time,$end_time,&$sel_options)
1072      {
1073          if ($this->debug > 1) $this->bo->debug_message('uiforms::split_freetime_daywise(freetime=%1, duration=%2, start_time=%3, end_time=%4)',true,$freetime,$duration,$start_time,$end_time);
1074          
1075          $freetime_daywise = array();
1076          if (!is_array($sel_options)) $sel_options = array();
1077          $time_format = $this->common_prefs['timeformat'] == 12 ? 'h:i a' : 'H:i';
1078          
1079          $start_time = (int) $start_time;    // ignore leading zeros
1080          $end_time   = (int) $end_time;
1081  
1082          // ignore the end_time, if duration would never fit
1083          if (($end_time - $start_time)*HOUR_s < $duration) 
1084          {
1085              $end_time = 0; 
1086              if ($this->debug > 1) $this->bo->debug_message('uiforms::split_freetime_daywise(, duration=%2, start_time=%3,..) end_time set to 0, it never fits durationn otherwise',true,$duration,$start_time);
1087          }
1088          $n = 0;
1089          foreach($freetime as $ft)
1090          {
1091              $daybegin = $this->bo->date2array($ft['start']);
1092              $daybegin['hour'] = $daybegin['minute'] = $daybegin['second'] = 0;
1093              unset($daybegin['raw']);
1094              $daybegin = $this->bo->date2ts($daybegin);
1095              
1096              for($t = $daybegin; $t < $ft['end']; $t += DAY_s,$daybegin += DAY_s)
1097              {
1098                  $dow = date('w',$daybegin+DAY_s/2);    // 0=Sun, .., 6=Sat
1099                  $mcal_dow = pow(2,$dow);
1100                  if (!($weekdays & $mcal_dow))
1101                  {
1102                      //echo "wrong day of week $dow<br>\n";
1103                      continue;    // wrong day of week
1104                  }
1105                  $start = $t < $ft['start'] ? $ft['start'] : $t;
1106                  
1107                  if ($start-$daybegin < $start_time*HOUR_s)    // start earlier then start_time
1108                  {
1109                      $start = $daybegin + $start_time*HOUR_s;
1110                  }
1111                  // if end_time given use it, else the original slot's end
1112                  $end = $end_time ? $daybegin + $end_time*HOUR_s : $ft['end'];
1113                  if ($end > $ft['end']) $end = $ft['end'];
1114  
1115                  // slot to small for duration
1116                  if ($end - $start < $duration)
1117                  {
1118                      //echo "slot to small for duration=$duration<br>\n";
1119                      continue;
1120                  }
1121                  $freetime_daywise[++$n] = array(
1122                      'start'    => $start,
1123                      'end'    => $end,
1124                  );
1125                  $times = array();
1126                  for ($s = $start; $s+$duration <= $end && $s < $daybegin+DAY_s; $s += 60*$this->cal_prefs['interval'])
1127                  {
1128                      $e = $s + $duration;
1129                      $end_date = $e-$daybegin > DAY_s ? lang(date('l',$e)).' '.date($this->common_prefs['dateformat'],$e).' ' : '';
1130                      $times[$s] = date($time_format,$s).' - '.$end_date.date($time_format,$e);
1131                  }
1132                  $sel_options[$n.'[start]'] = $times;
1133              }
1134          }
1135          return $freetime_daywise;
1136      }
1137      
1138      /**
1139       * Export events as vCalendar version 2.0 files (iCal)
1140       *
1141       * @param int/array $content=0 numeric cal_id or submitted content from etempalte::exec
1142       * @param boolean $return_error=false should an error-msg be returned or a regular page with it generated (default)
1143       * @return string error-msg if $return_error
1144       */
1145  	function export($content=0,$return_error=false)
1146      {
1147          if (is_numeric($cal_id = $content ? $content : $_REQUEST['cal_id']))
1148          {
1149              if (!($ical =& ExecMethod2('calendar.boical.exportVCal',$cal_id,'2.0')))
1150              {
1151                  $msg = lang('Permission denied');
1152                  
1153                  if ($return_error) return $msg;
1154              }
1155              else
1156              {
1157                  $GLOBALS['egw']->browser =& CreateObject('phpgwapi.browser');
1158                  $GLOBALS['egw']->browser->content_header('event.ics','text/calendar',strlen($ical));
1159                  echo $ical;
1160                  $GLOBALS['egw']->common->egw_exit();
1161              }
1162          }
1163          if (is_array($content))
1164          {
1165              $events =& $this->bo->search(array(
1166                  'start' => $content['start'],
1167                  'end'   => $content['end'],
1168                  'enum_recuring' => false,
1169                  'daywise'       => false,
1170                  'owner'         => $this->owner,
1171                  'date_format'   => 'server',    // timestamp in server time for boical class
1172              ));
1173              if (!$events)
1174              {
1175                  $msg = lang('No events found');
1176              }
1177              else
1178              {
1179                  $ical =& ExecMethod2('calendar.boical.exportVCal',$events,'2.0'/*$content['version']*/);
1180                  $GLOBALS['egw']->browser =& CreateObject('phpgwapi.browser');
1181                  $GLOBALS['egw']->browser->content_header($content['file'] ? $content['file'] : 'event.ics','text/calendar',strlen($ical));
1182                  echo $ical;
1183                  $GLOBALS['egw']->common->egw_exit();
1184              }
1185          }
1186          if (!is_array($content))
1187          {
1188              $view = $GLOBALS['egw']->session->appsession('view','calendar');
1189  
1190              $content = array(
1191                  'start' => $this->bo->date2ts($_REQUEST['start'] ? $_REQUEST['start'] : $this->date),
1192                  'end'   => $this->bo->date2ts($_REQUEST['end'] ? $_REQUEST['end'] : $this->date),
1193                  'file'  => 'event.ics',
1194                  'version' => '2.0',
1195              );
1196          }
1197          $content['msg'] = $msg;
1198          
1199          $GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . lang('iCal Export');
1200          $etpl =& CreateObject('etemplate.etemplate','calendar.export');
1201          
1202          $etpl->exec('calendar.uiforms.export',$content);
1203      }
1204      
1205      /**
1206       * Import events as vCalendar version 2.0 files (iCal)
1207       *
1208       * @param array $content=null submitted content from etempalte::exec
1209       */
1210  	function import($content=null)
1211      {
1212          if (is_array($content))
1213          {
1214              if (is_array($content['ical_file']) && is_uploaded_file($content['ical_file']['tmp_name']))
1215              {
1216                  if (!ExecMethod('calendar.boical.importVCal',file_get_contents($content['ical_file']['tmp_name'])))
1217                  {
1218                      $msg = lang('Error: importing the iCal');
1219                  }
1220                  else
1221                  {
1222                      $msg = lang('iCal successful imported');
1223                  }
1224              }
1225              else
1226              {
1227                  $msg = lang('You need to select an iCal file first');
1228              }
1229          }
1230          $content = array(
1231              'msg' => $msg,
1232          );
1233          $GLOBALS['egw_info']['flags']['app_header'] = lang('calendar') . ' - ' . lang('iCal Import');
1234          $etpl =& CreateObject('etemplate.etemplate','calendar.import');
1235          
1236          $etpl->exec('calendar.uiforms.import',$content);
1237      }
1238  }


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7