source: trunk/calendar/inc/class.bocalendar.inc.php @ 166

Revision 166, 109.0 KB checked in by niltonneto, 16 years ago (diff)

Correção de bug, conforme ticket 144 do SVN.
Correção na atualização pelo setup.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2  /**************************************************************************\
3  * eGroupWare - Calendar                                                    *
4  * http://www.eGroupWare.org                                                *
5  * Maintained and further developed by RalfBecker@outdoor-training.de       *
6  * Based on Webcalendar by Craig Knudsen <cknudsen@radix.net>               *
7  *          http://www.radix.net/~cknudsen                                  *
8  * Originaly modified by Mark Peters <skeeter@phpgroupware.org>             *
9  * --------------------------------------------                             *
10  *  This program is free software; you can redistribute it and/or modify it *
11  *  under the terms of the GNU General Public License as published by the   *
12  *  Free Software Foundation; either version 2 of the License, or (at your  *
13  *  option) any later version.                                              *
14  \**************************************************************************/
15
16
17        class bocalendar
18        {
19                var $public_functions = Array(
20                        'read_entry'      => True,
21                        'delete_entry'    => True,
22                        'delete_calendar' => True,
23                        'change_owner'    => True,
24                        'update'          => True,
25                        'check_set_default_prefs' => True,
26                        'store_to_cache'  => True,
27                        'export_event'    => True,
28                        'send_alarm'      => True,
29                        'reinstate'       => True
30                );
31
32                var $soap_functions = Array(
33                        'read_entry' => Array(
34                                'in' => Array(
35                                        'int'
36                                ),
37                                'out' => Array(
38                                        'SOAPStruct'
39                                )
40                        ),
41                        'delete_entry' => Array(
42                                'in' => Array(
43                                        'int'
44                                ),
45                                'out' => Array(
46                                        'int'
47                                )
48                        ),
49                        'delete_calendar' => Array(
50                                'in' => Array(
51                                        'int'
52                                ),
53                                'out' => Array(
54                                        'int'
55                                )
56                        ),
57                        'change_owner' => Array(
58                                'in' => Array(
59                                        'array'
60                                ),
61                                'out' => Array(
62                                        'int'
63                                )
64                        ),
65                        'update' => Array(
66                                'in' => Array(
67                                        'array',
68                                        'array',
69                                        'array',
70                                        'array',
71                                        'array'
72                                ),
73                                'out' => Array(
74                                        'array'
75                                )
76                        ),
77                        'store_to_cache'        => Array(
78                                'in' => Array(
79                                        'struct'
80                                ),
81                                'out' => Array(
82                                        'SOAPStruct'
83                                )
84                        ),
85                        'store_to_cache'        => Array(
86                                'in' => Array(
87                                        'array'
88                                ),
89                                'out' => Array(
90                                        'string'
91                                )
92                        ),
93                        'categories' => array(
94                                'in'  => array('bool'),
95                                'out' => array('array')
96                        ),
97                );
98
99                var $debug = False;
100//              var $debug = True;
101
102                var $so;
103                var $so1;
104                var $ex_participants;
105                var $cached_events;
106                var $repeating_events;
107                var $day;
108                var $month;
109                var $year;
110                var $prefs;
111
112                var $owner;
113                var $holiday_color;
114                var $printer_friendly = False;
115
116                var $cached_holidays;
117
118                var $g_owner = 0;
119
120                var $filter;
121                var $cat_id;
122                var $users_timeformat;
123
124                var $modified;
125                var $deleted;
126                var $added;
127
128                var $is_group = False;
129
130                var $soap = False;
131
132                var $use_session = False;
133
134                var $today;
135                var $debug_string;
136
137                var $sortby;
138                var $num_months;
139                var $xmlrpc = False;    // not called via xmlrpc
140
141                function bocalendar($session=0)
142                {
143                        $this->cat = CreateObject('phpgwapi.categories');
144                        $this->grants = $GLOBALS['phpgw']->acl->get_grants('calendar');
145                        @reset($this->grants);
146                        if(DEBUG_APP)
147                        {
148                                if(floor(phpversion()) >= 4)
149                                {
150                                        $this->debug_string = '';
151                                        ob_start();
152                                }
153
154                                foreach($this->grants as $grantor => $rights)
155                                {
156                                        print_debug('Grantor',$grantor);
157                                        print_debug('Rights',$rights);
158                                }
159                        }
160
161                        print_debug('Read use_session',$session);
162
163                        if($session)
164                        {
165                                $this->read_sessiondata();
166                                $this->use_session = True;
167                        }
168                        print_debug('BO Filter',$this->filter);
169                        print_debug('Owner',$this->owner);
170
171                        $this->prefs['calendar']    = $GLOBALS['phpgw_info']['user']['preferences']['calendar'];
172                        $this->check_set_default_prefs();
173
174                        $owner = get_var('owner',array('GET','POST'),$GLOBALS['owner']);
175
176                        ereg('menuaction=([a-zA-Z.]+)',$_SERVER['HTTP_REFERER'],$regs);
177                        $from = $regs[1];
178                        if ((substr($_SERVER['PHP_SELF'],-8) == 'home.php' && substr($this->prefs['calendar']['defaultcalendar'],0,7) == 'planner'
179                                || $_GET['menuaction'] == 'calendar.uicalendar.planner' &&
180                                $from  != 'calendar.uicalendar.planner' && !$this->save_owner)
181                                && (int)$this->prefs['calendar']['planner_start_with_group'] > 0)
182                        {
183                                // entering planner for the first time ==> saving owner in save_owner, setting owner to default
184                                //
185                                $this->save_owner = $this->owner;
186                                $owner = 'g_'.$this->prefs['calendar']['planner_start_with_group'];
187                        }
188                        elseif ($_GET['menuaction'] != 'calendar.uicalendar.planner' &&
189                                $this->save_owner)
190                        {
191                                // leaving planner with an unchanged user/owner ==> setting owner back to save_owner
192                                //
193                                $owner = (int)(isset($_GET['owner']) ? $_GET['owner'] : $this->save_owner);
194                                unset($this->save_owner);
195                        }
196                        elseif (!empty($owner) && $owner != $this->owner && $from == 'calendar.uicalendar.planner')
197                        {
198                                // user/owner changed within planner ==> forgetting save_owner
199                                //
200                                unset($this->save_owner);
201                        }
202
203                        if(isset($owner) && $owner!='' && substr($owner,0,2) == 'g_')
204                        {
205                                $this->set_owner_to_group(substr($owner,2));
206                        }
207                        elseif(isset($owner) && $owner!='')
208                        {
209                                $this->owner = (int)$owner;
210                        }
211                        elseif(!@isset($this->owner) || !@$this->owner)
212                        {
213                                $this->owner = (int)$GLOBALS['phpgw_info']['user']['account_id'];
214                        }
215                        elseif(isset($this->owner) && $GLOBALS['phpgw']->accounts->get_type($this->owner) == 'g')
216                        {
217                                $this->set_owner_to_group((int)$this->owner);
218                        }
219
220                        $this->prefs['common']    = $GLOBALS['phpgw_info']['user']['preferences']['common'];
221
222                        if ($this->prefs['common']['timeformat'] == '12')
223                        {
224                                $this->users_timeformat = 'h:ia';
225                        }
226                        else
227                        {
228                                $this->users_timeformat = 'H:i';
229                        }
230                        $this->holiday_color = (substr($GLOBALS['phpgw_info']['theme']['bg07'],0,1)=='#'?'':'#').$GLOBALS['phpgw_info']['theme']['bg07'];
231
232                        $friendly = (isset($_GET['friendly'])?$_GET['friendly']:'');
233                        $friendly = ($friendly=='' && isset($_POST['friendly'])?$_POST['friendly']:$friendly);
234
235                        $this->printer_friendly = ((int)$friendly == 1?True:False);
236
237                        if(isset($_POST['filter'])) { $this->filter = $_POST['filter']; }
238                        if(isset($_POST['sortby'])) { $this->sortby = $_POST['sortby']; }
239                        if(isset($_POST['cat_id'])) { $this->cat_id = $_POST['cat_id']; }
240
241                        if(!isset($this->filter))
242                        {
243                                $this->filter = ' '.$this->prefs['calendar']['defaultfilter'].' ';
244                        }
245
246                        if(!isset($this->sortby))
247                        {
248                                $this->sortby = $this->prefs['calendar']['defaultcalendar'] == 'planner_user' ? 'user' : 'category';
249                        }
250
251                        if($GLOBALS['phpgw']->accounts->get_type($this->owner)=='g')
252                        {
253                                $this->filter = ' all ';
254                        }
255
256                        $this->so = CreateObject('calendar.socalendar',
257                                Array(
258                                        'owner'         => $this->owner,
259                                        'filter'        => $this->filter,
260                                        'category'      => $this->cat_id,
261                                        'g_owner'       => $this->g_owner
262                                )
263                        );
264                        $this->rpt_day = array( // need to be after creation of socalendar
265                                MCAL_M_SUNDAY    => 'Sunday',
266                                MCAL_M_MONDAY    => 'Monday',
267                                MCAL_M_TUESDAY   => 'Tuesday',
268                                MCAL_M_WEDNESDAY => 'Wednesday',
269                                MCAL_M_THURSDAY  => 'Thursday',
270                                MCAL_M_FRIDAY    => 'Friday',
271                                MCAL_M_SATURDAY  => 'Saturday'
272                        );
273                        if($this->bo->prefs['calendar']['weekdaystarts'] != 'Sunday')
274                        {
275                                $mcals = array_keys($this->rpt_day);
276                                $days  = array_values($this->rpt_day);
277                                $this->rpt_day = array();
278                                list($n) = $found = array_keys($days,$this->prefs['calendar']['weekdaystarts']);
279                                for ($i = 0; $i < 7; ++$i,++$n)
280                                {
281                                        $this->rpt_day[$mcals[$n % 7]] = $days[$n % 7];
282                                }
283                        }
284                        $this->rpt_type = Array(
285                                MCAL_RECUR_NONE         => 'None',
286                                MCAL_RECUR_DAILY        => 'Daily',
287                                MCAL_RECUR_WEEKLY       => 'Weekly',
288                                MCAL_RECUR_MONTHLY_WDAY => 'Monthly (by day)',
289                                MCAL_RECUR_MONTHLY_MDAY => 'Monthly (by date)',
290                                MCAL_RECUR_YEARLY       => 'Yearly'
291                        );
292
293                        $localtime = $GLOBALS['phpgw']->datetime->users_localtime;
294
295                        $date = (isset($GLOBALS['date'])?$GLOBALS['date']:'');
296                        $date = (isset($_GET['date'])?$_GET['date']:$date);
297                        $date = ($date=='' && isset($_POST['date'])?$_POST['date']:$date);
298
299                        $year = (isset($_GET['year'])?$_GET['year']:'');
300                        $year = ($year=='' && isset($_POST['year'])?$_POST['year']:$year);
301
302                        $month = (isset($_GET['month'])?$_GET['month']:'');
303                        $month = ($month=='' && isset($_POST['month'])?$_POST['month']:$month);
304
305                        $day = (isset($_GET['day'])?$_GET['day']:'');
306                        $day = ($day=='' && isset($_POST['day'])?$_POST['day']:'');
307
308                        $num_months = (isset($_GET['num_months'])?$_GET['num_months']:'');
309                        $num_months = ($num_months=='' && isset($_POST['num_months'])?$_POST['num_months']:$num_months);
310
311                        if(isset($date) && $date!='')
312                        {
313                                $this->year  = (int)(substr($date,0,4));
314                                $this->month = (int)(substr($date,4,2));
315                                $this->day   = (int)(substr($date,6,2));
316                        }
317                        else
318                        {
319                                if(isset($year) && $year!='')
320                                {
321                                        $this->year = $year;
322                                }
323                                else
324                                {
325                                        $this->year = date('Y',$localtime);
326                                }
327                                if(isset($month) && $month!='')
328                                {
329                                        $this->month = $month;
330                                }
331                                else
332                                {
333                                        $this->month = date('m',$localtime);
334                                }
335                                if(isset($day) && $day!='')
336                                {
337                                        $this->day = $day;
338                                }
339                                else
340                                {
341                                        $this->day = date('d',$localtime);
342                                }
343                        }
344
345                        if(isset($num_months) && $num_months!='')
346                        {
347                                $this->num_months = $num_months;
348                        }
349                        elseif($this->num_months == 0)
350                        {
351                                $this->num_months = 1;
352                        }
353
354                        $this->today = date('Ymd',$GLOBALS['phpgw']->datetime->users_localtime);
355
356                        if(DEBUG_APP)
357                        {
358                                print_debug('BO Filter','('.$this->filter.')');
359                                print_debug('Owner',$this->owner);
360                                print_debug('Today',$this->today);
361                                if(floor(phpversion()) >= 4)
362                                {
363                                        $this->debug_string .= ob_get_contents();
364                                        ob_end_clean();
365                                }
366                        }
367                        $this->xmlrpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method;
368                }
369
370                function list_methods($_type='xmlrpc')
371                {
372                        /*
373                          This handles introspection or discovery by the logged in client,
374                          in which case the input might be an array.  The server always calls
375                          this function to fill the server dispatch map using a string.
376                        */
377                        if (is_array($_type))
378                        {
379                                $_type = $_type['type'];
380                        }
381                        switch($_type)
382                        {
383                                case 'xmlrpc':
384                                        $xml_functions = array(
385                                                'list_methods' => array(
386                                                        'function'  => 'list_methods',
387                                                        'signature' => array(array(xmlrpcStruct,xmlrpcString)),
388                                                        'docstring' => lang('Read this list of methods.')
389                                                ),
390                                                'read' => array(
391                                                        'function'  => 'read_entry',
392                                                        'signature' => array(array(xmlrpcStruct,xmlrpcInt)),
393                                                        'docstring' => lang('Read a single entry by passing the id and fieldlist.')
394                                                ),
395                                                'read_entry' => array(  // deprecated, use read
396                                                        'function'  => 'read_entry',
397                                                        'signature' => array(array(xmlrpcStruct,xmlrpcInt)),
398                                                        'docstring' => lang('Read a single entry by passing the id and fieldlist.')
399                                                ),
400                                                'write' => array(
401                                                        'function'  => 'update',
402                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
403                                                        'docstring' => lang('Add or update a single entry by passing the fields.')
404                                                ),
405                                                'add_entry' => array(   // deprecated, use write
406                                                        'function'  => 'update',
407                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
408                                                        'docstring' => lang('Add a single entry by passing the fields.')
409                                                ),
410                                                'update_entry' => array(        // deprecated, use write
411                                                        'function'  => 'update',
412                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
413                                                        'docstring' => lang('Update a single entry by passing the fields.')
414                                                ),
415                                                'delete' => array(
416                                                        'function'  => 'delete_entry',
417                                                        'signature' => array(array(xmlrpcInt,xmlrpcInt)),
418                                                        'docstring' => lang('Delete a single entry by passing the id.')
419                                                ),
420                                                'delete_entry' => array(        // deprecated, use delete
421                                                        'function'  => 'delete_entry',
422                                                        'signature' => array(array(xmlrpcInt,xmlrpcInt)),
423                                                        'docstring' => lang('Delete a single entry by passing the id.')
424                                                ),
425                                                'delete_calendar' => array(
426                                                        'function'  => 'delete_calendar',
427                                                        'signature' => array(array(xmlrpcInt,xmlrpcInt)),
428                                                        'docstring' => lang('Delete an entire users calendar.')
429                                                ),
430                                                'change_owner' => array(
431                                                        'function'  => 'change_owner',
432                                                        'signature' => array(array(xmlrpcInt,xmlrpcStruct)),
433                                                        'docstring' => lang('Change all events for $params[\'old_owner\'] to $params[\'new_owner\'].')
434                                                ),
435                                                'search' => array(
436                                                        'function'  => 'store_to_cache',
437                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
438                                                        'docstring' => lang('Read a list of entries.')
439                                                ),
440                                                'store_to_cache' => array(      // deprecated, use search
441                                                        'function'  => 'store_to_cache',
442                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
443                                                        'docstring' => lang('Read a list of entries.')
444                                                ),
445                                                'export_event' => array(
446                                                        'function'  => 'export_event',
447                                                        'signature' => array(array(xmlrpcString,xmlrpcStruct)),
448                                                        'docstring' => lang('Export a list of entries in iCal format.')
449                                                ),
450                                                'categories' => array(
451                                                        'function'  => 'categories',
452                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
453                                                        'docstring' => lang('List all categories.')
454                                                ),
455                                        );
456                                        return $xml_functions;
457                                        break;
458                                case 'soap':
459                                        return $this->soap_functions;
460                                        break;
461                                default:
462                                        return array();
463                                        break;
464                        }
465                }
466
467                function set_owner_to_group($owner)
468                {
469                        print_debug('calendar::bocalendar::set_owner_to_group:owner',$owner);
470                        $this->owner = (int)$owner;
471                        $this->is_group = True;
472                        $this->g_owner = Array();
473                        $members = $GLOBALS['phpgw']->accounts->member($owner);
474                        if (is_array($members))
475                        {
476                                foreach($members as $user)
477                                {
478                                        // use only members which gave the user a read-grant
479                                        if ($this->check_perms(PHPGW_ACL_READ,0,$user['account_id']))
480                                        {
481                                                $this->g_owner[] = $user['account_id'];
482                                        }
483                                }
484                        }
485                        //echo "<p>".function_backtrace().": set_owner_to_group($owner) = ".print_r($this->g_owner,True)."</p>\n";
486                }
487
488                function member_of_group($owner=0)
489                {
490                        $owner = ($owner==0?$GLOBALS['phpgw_info']['user']['account_id']:$owner);
491                        $group_owners = $GLOBALS['phpgw']->accounts->membership();
492                        while($group_owners && list($index,$group_info) = each($group_owners))
493                        {
494                                if($this->owner == $group_info['account_id'])
495                                {
496                                        return True;
497                                }
498                        }
499                        return False;
500                }
501
502                function save_sessiondata($data='')
503                {
504                        if ($this->use_session)
505                        {
506                                if (!is_array($data))
507                                {
508                                        $data = array(
509                                                'filter'     => $this->filter,
510                                                'cat_id'     => $this->cat_id,
511                                                'owner'      => $this->owner,
512                                                'save_owner' => $this->save_owner,
513                                                'year'       => $this->year,
514                                                'month'      => $this->month,
515                                                'day'        => $this->day,
516                                                'date'       => $this->date,
517                                                'sortby'     => $this->sortby,
518                                                'num_months' => $this->num_months,
519                                                'return_to'  => $this->return_to
520                                        );
521                                }
522                                if($this->debug)
523                                {
524                                        if(floor(phpversion()) >= 4)
525                                        {
526                                                ob_start();
527                                        }
528                                        echo '<!-- '."\n".'Save:'."\n"._debug_array($data,False)."\n".' -->'."\n";
529                                        if(floor(phpversion()) >= 4)
530                                        {
531                                                $this->debug_string .= ob_get_contents();
532                                                ob_end_clean();
533                                        }
534                                }
535                                $GLOBALS['phpgw']->session->appsession('session_data','calendar',$data);
536                        }
537                }
538
539                function read_sessiondata()
540                {
541                        $data = $GLOBALS['phpgw']->session->appsession('session_data','calendar');
542                        print_debug('Read',_debug_array($data,False));
543
544                        $this->filter = $data['filter'];
545                        $this->cat_id = $data['cat_id'];
546                        $this->sortby = $data['sortby'];
547                        $this->owner  = (int)$data['owner'];
548                        $this->save_owner = (int)$data['save_owner'];
549                        $this->year   = (int)$data['year'];
550                        $this->month  = (int)$data['month'];
551                        $this->day    = (int)$data['day'];
552                        $this->num_months = (int)$data['num_months'];
553                        $this->return_to = $data['return_to'];
554                }
555
556                function read_entry($id,$ignore_acl=False)
557                {
558                        if (is_array($id) && count($id) == 1)
559                        {
560                                list(,$id) = each($id);
561                        }
562                        if($ignore_acl || $this->check_perms(PHPGW_ACL_READ,$id))
563                        {
564                                $event = $this->so->read_entry($id);
565                                if(!isset($event['participants'][$this->owner]) && $this->user_is_a_member($event,$this->owner))
566                                {
567                                        $this->so->add_attribute('participants','U',(int)$this->owner);
568                                        $this->so->add_entry($event);
569                                        $event = $this->get_cached_event();
570                                }
571                                return $this->xmlrpc ? $this->xmlrpc_prepare($event) : $event;
572                        }
573                        if ($this->xmlrpc)
574                        {
575                                $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']);
576                        }
577                        return False;
578                }
579
580                function delete_single($param)
581                {
582                        if($this->check_perms(PHPGW_ACL_DELETE,(int)$param['id']))
583                        {
584                                $temp_event = $this->get_cached_event();
585                                $event = $this->read_entry((int)$param['id']);
586//                              if($this->owner == $event['owner'])
587//                              {
588                                $exception_time = mktime($event['start']['hour'],$event['start']['min'],0,$param['month'],$param['day'],$param['year']) - $GLOBALS['phpgw']->datetime->tz_offset;
589                                $event['recur_exception'][] = (int)$exception_time;
590                                $this->so->cal->event = $event;
591//                              print_debug('exception time',$event['recur_exception'][count($event['recur_exception']) -1]);
592//                              print_debug('count event exceptions',count($event['recur_exception']));
593                                $this->so->add_entry($event);
594                                $cd = 16;
595
596                                $this->so->cal->event = $temp_event;
597                                unset($temp_event);
598                        }
599                        else
600                        {
601                                $cd = 60;
602                        }
603//                      }
604                        return $cd;
605                }
606
607                function delete_entry($id)
608                {
609                        if (is_array($id) && count($id) == 1)
610                        {
611                                list(,$id) = each($id);
612                        }
613                        if($this->check_perms(PHPGW_ACL_DELETE,$id))
614                        {
615                                $this->so->delete_entry($id);
616
617                                if ($this->xmlrpc)
618                                {
619                                        $this->so->expunge($id);
620                                }
621                                return $this->xmlrpc ? True : 16;
622                        }
623                        if ($this->xmlrpc)
624                        {
625                                $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']);
626                        }
627                        return 60;
628                }
629
630                function reinstate($params='')
631                {
632                        if($this->check_perms(PHPGW_ACL_EDIT,$params['cal_id']) && isset($params['reinstate_index']))
633                        {
634                                $event = $this->so->read_entry($params['cal_id']);
635                                @reset($params['reinstate_index']);
636                                print_debug('Count of reinstate_index',count($params['reinstate_index']));
637                                if(count($params['reinstate_index']) > 1)
638                                {
639                                        while(list($key,$value) = each($params['reinstate_index']))
640                                        {
641                                                print_debug('reinstate_index ['.$key.']',(int)$value);
642                                                print_debug('exception time',$event['recur_exception'][(int)$value]);
643                                                unset($event['recur_exception'][(int)$value]);
644                                                print_debug('count event exceptions',count($event['recur_exception']));
645                                        }
646                                }
647                                else
648                                {
649                                        print_debug('reinstate_index[0]',(int)$params['reinstate_index'][0]);
650                                        print_debug('exception time',$event['recur_exception'][(int)$params['reinstate_index'][0]]);
651                                        unset($event['recur_exception'][(int)$params['reinstate_index'][0]]);
652                                        print_debug('count event exceptions',count($event['recur_exception']));
653                                }
654                                $this->so->cal->event = $event;
655                                $this->so->add_entry($event);
656                                return 42;
657                        }
658                        else
659                        {
660                                return 43;
661                        }
662                }
663
664                function delete_calendar($owner)
665                {
666                        if($GLOBALS['phpgw_info']['user']['apps']['admin'])
667                        {
668                                $this->so->delete_calendar($owner);
669                        }
670                }
671
672                function change_owner($params='')
673                {
674                        if($GLOBALS['phpgw_info']['server']['calendar_type'] == 'sql')
675                        {
676                                if(is_array($params))
677                                {
678                                        $this->so->change_owner($params['old_owner'],$params['new_owner']);
679                                }
680                        }
681                }
682
683                function expunge()
684                {
685                        reset($this->so->cal->deleted_events);
686                        while(list($i,$event_id) = each($this->so->cal->deleted_events))
687                        {
688                                $event = $this->so->read_entry($event_id);
689                                if($this->check_perms(PHPGW_ACL_DELETE,$event))
690                                {
691                                        $this->send_update(MSG_DELETED,$event['participants'],$event);
692                                }
693                                else
694                                {
695                                        unset($this->so->cal->deleted_events[$i]);
696                                }
697                        }
698                        $this->so->expunge();
699                }
700
701                function search_keywords($keywords)
702                {
703                        $type = $GLOBALS['phpgw']->accounts->get_type($this->owner);
704
705                        if($type == 'g')
706                        {
707                                $members = $GLOBALS['phpgw']->acl->get_ids_for_location($this->owner, 1, 'phpgw_group');
708                        }
709                        else
710                        {
711                                $members = array_keys($this->grants);
712
713                                if (!in_array($this->owner,$members))
714                                {
715                                        $members[] = $this->owner;
716                                }
717                        }
718                        foreach($members as $n => $uid)
719                        {
720                                if (!($this->grants[$uid] & PHPGW_ACL_READ))
721                                {
722                                        unset($members[$n]);
723                                }
724                        }
725                        return $this->so->list_events_keyword($keywords,$members);
726                }
727
728                function update($params='')
729                {
730                       
731                        $l_cal = (@isset($params['cal']) && $params['cal']?$params['cal']:$_POST['cal']);
732                        $l_participants = (@$params['participants']?$params['participants']:$_POST['participants']);
733                        $this->ex_participants = (@$params['ex_participants']?$params['ex_participants']:$_POST['ex_participants']);
734                        $l_categories = (@$params['categories']?$params['categories']:$_POST['categories']);
735                        $l_start = (@isset($params['start']) && $params['start']?$params['start']:$_POST['start']);
736                        $l_end = (@isset($params['end']) && $params['end']?$params['end']:$_POST['end']);
737                        $l_recur_enddate = (@isset($params['recur_enddate']) && $params['recur_enddate']?$params['recur_enddate']:$_POST['recur_enddate']);
738                       
739                        $send_to_ui = True;
740                        //if ((!is_array($l_start) || !is_array($l_end)) && !isset($_GET['readsess']))  // xmlrpc call
741                        if ($this->xmlrpc)      // xmlrpc call
742                        {
743                                $send_to_ui = False;
744
745                                $l_cal = $params;       // no extra array
746
747                                foreach(array('start','end','recur_enddate') as $name)
748                                {
749                                        $var = 'l_'.$name;
750                                        $$var = $GLOBALS['server']->iso86012date($params[$name]);
751                                        unset($l_cal[$name]);
752                                }
753                                if (!is_array($l_participants) || !count($l_participants))
754                                {
755                                        $l_participants = array($GLOBALS['phpgw_info']['user']['account_id'].'A');
756                                }
757                                else
758                                {
759                                        $l_participants = array();
760                                        foreach($params['participants'] as $user => $data)
761                                        {
762                                                $l_participants[] = $user.$data['status'];
763                                        }
764                                }
765                                unset($l_cal['participants']);
766
767                                if (!is_object($GLOBALS['phpgw']->categories))
768                                {
769                                        $GLOBALS['phpgw']->categories = CreateObject('phpgwapi.categories');
770                                }
771                                $l_categories = $GLOBALS['server']->xmlrpc2cats($params['category']);
772                                unset($l_cal['category']);
773
774                                // using access={public|private} in all modules via xmlrpc
775                                $l_cal['public'] = $params['access'] != 'private';
776                                unset($l_cal['access']);
777/*
778                                $fp = fopen('/tmp/xmlrpc.log','a+');
779                                ob_start();
780                                echo "\nbocalendar::update("; print_r($params); echo ")\n";
781                                //echo "\nl_start="; print_r($l_start);
782                                //echo "\nl_end="; print_r($l_end);
783                                fwrite($fp,ob_get_contents());
784                                ob_end_clean();
785                                fclose($fp);
786*/
787                        }
788                        print_debug('ID',$l_cal['id']);
789
790                        // don't wrap to the next day for no time
791                        if ($l_end['hour'] == 24 && $l_end['min'] == 0)
792                        {
793                                $l_end['hour'] = 23;
794                                $l_end['min'] = 59;
795                        }
796
797                        if(isset($_GET['readsess']))
798                        {
799                                $event = $this->restore_from_appsession();
800                                $event['title'] = stripslashes($event['title']);
801                                $event['description'] = stripslashes($event['description']);
802                                $event['ex_participants'] = stripslashes($event['ex_participants']);
803                                $datetime_check = $this->validate_update($event);
804                                if($datetime_check)
805                                {
806                                        ExecMethod('calendar.uicalendar.edit',
807                                                Array(
808                                                        'cd'            => $datetime_check,
809                                                        'readsess'      => 1
810                                                )
811                                        );
812                                        $GLOBALS['phpgw']->common->phpgw_exit(True);
813                                }
814                                $overlapping_events = False;
815                        }
816                        else
817                        {
818                                if((!$l_cal['id'] && !$this->check_perms(PHPGW_ACL_ADD)) ||
819                                   ($l_cal['id'] && !$this->check_perms(PHPGW_ACL_EDIT,$l_cal['id'])))
820                                {
821                                        if ($this->xmlrpc)
822                                        {
823                                                $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['no_access'],$GLOBALS['xmlrpcstr']['no_access']);
824                                        }
825                                        if (!$send_to_ui)
826                                        {
827                                                return array(($l_cal['id']?1:2) => 'permission denied');
828                                        }
829                                        ExecMethod('calendar.uicalendar.index');
830                                        $GLOBALS['phpgw']->common->phpgw_exit();
831                                }
832
833                                print_debug('Prior to fix_update_time()');
834                                $this->fix_update_time($l_start);
835                                $this->fix_update_time($l_end);
836
837                                if(!isset($l_cal['private']))
838                                {
839                                        $l_cal['private'] = 'public';
840                                }
841                                if(!isset($l_cal['ex_participants']))
842                                {
843                                        $l_cal['ex_participants'] = $this->ex_participants;
844                                }
845
846                                if(!isset($l_categories))
847                                {
848                                        $l_categories = 0;
849                                }
850
851                                $is_public = (int)(isset($l_cal['public']) ? $l_cal['public'] : $l_cal['private'] == 'public');
852                                $this->so->event_init();
853                                $this->add_attribute('uid',$l_cal['uid']);
854                                if($l_cal['ex_participants']) {
855                                        $this->add_attribute('ex_participants',$l_cal['ex_participants']);
856                                }
857                                if(count($l_categories) >= 2)
858                                {
859                                        $this->so->set_category(implode(',',$l_categories));
860                                }
861                                else
862                                {
863                                        $this->so->set_category(strval($l_categories[0]));
864                                }
865                                $this->so->set_title($l_cal['title']);
866                                $this->so->set_description($l_cal['description']);
867                                $this->so->set_ex_participants($l_cal['ex_participants']);
868                                $this->so->set_start($l_start['year'],$l_start['month'],$l_start['mday'],$l_start['hour'],$l_start['min'],0);
869                                $this->so->set_end($l_end['year'],$l_end['month'],$l_end['mday'],$l_end['hour'],$l_end['min'],0);
870                                $this->so->set_class($is_public);
871                                $this->so->add_attribute('reference',(@isset($l_cal['reference']) && $l_cal['reference']?$l_cal['reference']:0));
872                                $this->so->add_attribute('location',(@isset($l_cal['location']) && $l_cal['location']?$l_cal['location']:''));
873                                if($l_cal['id'])
874                                {
875                                        $this->so->add_attribute('id',$l_cal['id']);
876                                }
877
878                                if($l_cal['rpt_use_end'] != 'y')
879                                {
880                                        $l_recur_enddate['year'] = 0;
881                                        $l_recur_enddate['month'] = 0;
882                                        $l_recur_enddate['mday'] = 0;
883                                }
884                                elseif (isset($l_recur_enddate['str']))
885                                {
886                                        $l_recur_enddate = $this->jscal->input2date($l_recur_enddate['str'],False,'mday');
887                                }
888
889                                switch((int)$l_cal['recur_type'])
890                                {
891                                        case MCAL_RECUR_NONE:
892                                                $this->so->set_recur_none();
893                                                break;
894                                        case MCAL_RECUR_DAILY:
895                                                $this->so->set_recur_daily((int)$l_recur_enddate['year'],(int)$l_recur_enddate['month'],(int)$l_recur_enddate['mday'],(int)$l_cal['recur_interval']);
896                                                break;
897                                        case MCAL_RECUR_WEEKLY:
898                                                foreach(array('rpt_sun','rpt_mon','rpt_tue','rpt_wed','rpt_thu','rpt_fri','rpt_sat') as $rpt_day)
899                                                {
900                                                        $l_cal['recur_data'] += (int)$l_cal[$rpt_day];
901                                                }
902                                                if (is_array($l_cal['rpt_day']))
903                                                {
904                                                        foreach ($l_cal['rpt_day'] as $mask)
905                                                        {
906                                                                $l_cal['recur_data'] |= (int)$mask;
907                                                        }
908                                                }
909                                                $this->so->set_recur_weekly((int)$l_recur_enddate['year'],(int)$l_recur_enddate['month'],(int)$l_recur_enddate['mday'],(int)$l_cal['recur_interval'],$l_cal['recur_data']);
910                                                break;
911                                        case MCAL_RECUR_MONTHLY_MDAY:
912                                                $this->so->set_recur_monthly_mday((int)$l_recur_enddate['year'],(int)$l_recur_enddate['month'],(int)$l_recur_enddate['mday'],(int)$l_cal['recur_interval']);
913                                                break;
914                                        case MCAL_RECUR_MONTHLY_WDAY:
915                                                $this->so->set_recur_monthly_wday((int)$l_recur_enddate['year'],(int)$l_recur_enddate['month'],(int)$l_recur_enddate['mday'],(int)$l_cal['recur_interval']);
916                                                break;
917                                        case MCAL_RECUR_YEARLY:
918                                                $this->so->set_recur_yearly((int)$l_recur_enddate['year'],(int)$l_recur_enddate['month'],(int)$l_recur_enddate['mday'],(int)$l_cal['recur_interval']);
919                                                break;
920                                }
921
922                                if($l_participants)
923                                {
924                                        $parts = $l_participants;
925                                        $minparts = min($l_participants);
926                                        $part = Array();
927                                        for($i=0;$i<count($parts);$i++)
928                                        {
929                                                if (($accept_type = substr($parts[$i],-1,1)) == '0' || (int)$accept_type > 0)
930                                                {
931                                                        $accept_type = 'U';
932                                                }
933                                                $acct_type = $GLOBALS['phpgw']->accounts->get_type((int)$parts[$i]);
934                                                if($acct_type == 'u')
935                                                {
936                                                        $part[(int)$parts[$i]] = $accept_type;
937                                                }
938                                                elseif($acct_type == 'g')
939                                                {
940                                                        $part[(int)$parts[$i]] = $accept_type;
941                                                        $groups[] = $parts[$i];
942                                                        /* This pulls ALL users of a group and makes them as participants to the event */
943                                                        /* I would like to turn this back into a group thing. */
944                                                        $acct = CreateObject('phpgwapi.accounts',(int)$parts[$i]);
945                                                        $members = $acct->member((int)$parts[$i]);
946                                                        unset($acct);
947                                                        if($members == False)
948                                                        {
949                                                                continue;
950                                                        }
951                                                        while($member = each($members))
952                                                        {
953                                                                $part[$member[1]['account_id']] = $accept_type;
954                                                        }
955                                                }
956                                        }
957                                }
958                                else
959                                {
960                                        $part = False;
961                                }
962
963                                if($part)
964                                {
965                                        @reset($part);
966                                        while(list($key,$accept_type) = each($part))
967                                        {
968                                                $this->so->add_attribute('participants',$accept_type,(int)$key);
969                                        }
970                                }
971
972                                if($groups)
973                                {
974                                        @reset($groups);
975                                        $this->so->add_attribute('groups',(int)$group_id);
976                                }
977
978                                $event = $this->get_cached_event();
979                                if(!is_int($minparts))
980                                {
981                                        $minparts = $this->owner;
982                                }
983                                if(!@isset($event['participants'][$l_cal['owner']]))
984                                {
985                                        $this->so->add_attribute('owner',$minparts);
986                                }
987                                else
988                                {
989                                        $this->so->add_attribute('owner',$l_cal['owner']);
990                                }
991                                $this->so->add_attribute('priority',$l_cal['priority']);
992
993                                foreach($l_cal as $name => $value)
994                                {
995                                        if ($name[0] == '#')    // Custom field
996                                        {
997                                                $this->so->add_attribute($name,stripslashes($value));
998                                        }
999                                }
1000                                if (isset($_POST['preserved']) && is_array($preserved = unserialize(stripslashes($_POST['preserved']))))
1001                                {
1002                                        foreach($preserved as $name => $value)
1003                                        {
1004                                                switch($name)
1005                                                {
1006                                                        case 'owner':
1007                                                                $this->so->add_attribute('participants',$value,$l_cal['owner']);
1008                                                                break;
1009                                                        default:
1010                                                                $this->so->add_attribute($name,str_replace(array('&amp;','&quot;','&lt;','&gt;'),array('&','"','<','>'),$value));
1011                                                }
1012                                        }
1013                                }
1014                                $event = $this->get_cached_event();
1015
1016                                if ($l_cal['alarmdays'] > 0 || $l_cal['alarmhours'] > 0 ||
1017                                                $l_cal['alarmminutes'] > 0)
1018                                {
1019                                        $offset = ($l_cal['alarmdays'] * 24 * 3600) +
1020                                                ($l_cal['alarmhours'] * 3600) + ($l_cal['alarmminutes'] * 60);
1021
1022                                        $time = $this->maketime($event['start']) - $offset;
1023
1024                                        $event['alarm'][] = Array(
1025                                                'time'    => $time,
1026                                                'offset'  => $offset,
1027                                                'owner'   => $this->owner,
1028                                                'enabled' => 1
1029                                        );
1030                                }
1031
1032                                $this->store_to_appsession($event);
1033                                $datetime_check = $this->validate_update($event);
1034                                print_debug('bo->validated_update() returnval',$datetime_check);
1035                                if($datetime_check)
1036                                {
1037                                        if (!$send_to_ui)
1038                                        {
1039                                                return array($datetime_check => 'invalid input data');
1040                                        }
1041                                        ExecMethod('calendar.uicalendar.edit',
1042                                                Array(
1043                                                        'cd'            => $datetime_check,
1044                                                        'readsess'      => 1
1045                                                )
1046                                        );
1047                                        $GLOBALS['phpgw']->common->phpgw_exit(True);
1048                                }
1049
1050                                if($event['id'])
1051                                {
1052                                        $event_ids[] = $event['id'];
1053                                }
1054                                if($event['reference'])
1055                                {
1056                                        $event_ids[] = $event['reference'];
1057                                }
1058
1059                                $overlapping_events = $this->overlap(
1060                                        $this->maketime($event['start']),
1061                                        $this->maketime($event['end']),
1062                                        $event['participants'],
1063                                        $event['owner'],
1064                                        $event_ids
1065                                );
1066                        }
1067                        if($overlapping_events)
1068                        {
1069                                if($send_to_ui)
1070                                {
1071                                        $event['ex_participants'] = $this->ex_participants;
1072                                        unset($GLOBALS['phpgw_info']['flags']['noheader']);
1073                                        unset($GLOBALS['phpgw_info']['flags']['nonavbar']);
1074                                        ExecMethod('calendar.uicalendar.overlap',
1075                                                Array(
1076                                                        'o_events'      => $overlapping_events,
1077                                                        'this_event'    => $event
1078                                                )
1079                                        );
1080                                        $GLOBALS['phpgw']->common->phpgw_exit(True);
1081                                }
1082                                else
1083                                {
1084                                        return $overlapping_events;
1085                                }
1086                        }
1087                        else
1088                        {
1089                                if(!$event['id'])
1090                                {
1091                                        if(!$this->ex_participants)
1092                                                $this->ex_participants = $event['ex_participants'];
1093                                        $this->so->add_entry($event);
1094                                        $this->send_update(MSG_ADDED,$event['participants'],'',$this->get_cached_event());
1095                                        print_debug('New Event ID',$event['id']);
1096                                }
1097                                else
1098                                {
1099                                        print_debug('Updating Event ID',$event['id']);
1100                                        $new_event = $event;
1101                                        $old_event = $this->read_entry($event['id']);
1102                                        // if old event has alarm and the start-time changed => update them
1103                                        //echo "<p>checking ".count($old_event['alarm'])." alarms of event #$event[id] start moved from ".print_r($old_event['start'],True)." to ".print_r($event['start'],True)."</p>\n";
1104                                        if ($old_event['alarm'] &&
1105                                                $this->maketime($old_event['start']) != $this->maketime($event['start']))
1106                                        {
1107                                                $this->so->delete_alarms($old_event['id']);
1108                                                foreach($old_event['alarm'] as $id => $alarm)
1109                                                {
1110                                                        $alarm['time'] = $this->maketime($event['start']) - $alarm['offset'];
1111                                                        $event['alarm'][] = $alarm;
1112                                                }
1113                                                //echo "updated alarms<pre>".print_r($event['alarm'],True)."</pre>\n";
1114                                        }
1115                                        $this->so->cal->event = $event;
1116                                        $this->so->add_entry($event);
1117                                        $this->prepare_recipients($new_event,$old_event);
1118                                }
1119
1120                                $date = sprintf("%04d%02d%02d",$event['start']['year'],$event['start']['month'],$event['start']['mday']);
1121                                if($send_to_ui)
1122                                {
1123                                        $this->read_sessiondata();
1124                                        if ($this->return_to)
1125                                        {
1126                                                $GLOBALS['phpgw']->redirect_link('/index.php','menuaction='.$this->return_to);
1127                                                $GLOBALS['phpgw']->common->phpgw_exit();
1128                                        }
1129                                        Execmethod('calendar.uicalendar.index');
1130                                }
1131                                else
1132                                {
1133                                        return (int)$event['id'];
1134                                }
1135                        }
1136                        return True;
1137                }
1138
1139                /* Private functions */
1140                function read_holidays($year=0)
1141                {
1142                        if(!$year)
1143                        {
1144                                $year = $this->year;
1145                        }
1146                        $holiday = CreateObject('calendar.boholiday');
1147                        $holiday->prepare_read_holidays($year,$this->owner);
1148                        $this->cached_holidays = $holiday->read_holiday();
1149                        unset($holiday);
1150                }
1151
1152                function user_is_a_member($event,$user)
1153                {
1154                        @reset($event['participants']);
1155                        $uim = False;
1156                        $security_equals = $GLOBALS['phpgw']->accounts->membership($user);
1157                        while(!$uim && $event['participants'] && $security_equals && list($participant,$status) = each($event['participants']))
1158                        {
1159                                if($GLOBALS['phpgw']->accounts->get_type($participant) == 'g')
1160                                {
1161                                        @reset($security_equals);
1162                                        while(list($key,$group_info) = each($security_equals))
1163                                        {
1164                                                if($group_info['account_id'] == $participant)
1165                                                {
1166                                                        return True;
1167                                                        $uim = True;
1168                                                }
1169                                        }
1170                                }
1171                        }
1172                        return $uim;
1173                }
1174
1175                function maketime($time)
1176                {
1177                        return mktime(intval($time['hour']),intval($time['min']),intval($time['sec']),intval($time['month']),intval($time['mday']),intval($time['year']));
1178                }
1179
1180                /*!
1181                @function time2array
1182                @abstract returns a date-array suitable for the start- or endtime of an event from a timestamp
1183                @syntax time2array($time,$alarm=0)
1184                @param $time the timestamp for the values of the array
1185                @param $alarm (optional) alarm field of the array, defaults to 0
1186                @author ralfbecker
1187                */
1188                function time2array($time,$alarm = 0)
1189                {
1190                        return array(
1191                                'year'  => (int)(date('Y',$time)),
1192                                'month' => (int)(date('m',$time)),
1193                                'mday'  => (int)(date('d',$time)),
1194                                'hour'  => (int)(date('H',$time)),
1195                                'min'   => (int)(date('i',$time)),
1196                                'sec'   => (int)(date('s',$time)),
1197                                'alarm' => (int)($alarm)
1198                        );
1199                }
1200
1201                /*!
1202                @function set_recur_date
1203                @abstract set the start- and enddates of a recuring event for a recur-date
1204                @syntax set_recur_date(&$event,$date)
1205                @param $event the event which fields to set (has to be the original event for start-/end-times)
1206                @param $date  the recuring date in form 'Ymd', eg. 20030226
1207                @author ralfbecker
1208                */
1209                function set_recur_date(&$event,$date)
1210                {
1211                        $org_start = $this->maketime($event['start']);
1212                        $org_end   = $this->maketime($event['end']);
1213                        $start = mktime($event['start']['hour'],$event['start']['min'],0,substr($date,4,2),substr($date,6,2),substr($date,0,4));
1214                        $end   = $org_end + $start - $org_start;
1215                        $event['start'] = $this->time2array($start);
1216                        $event['end']   = $this->time2array($end);
1217                }
1218
1219                function fix_update_time(&$time_param)
1220                {
1221                        if (isset($time_param['str']))
1222                        {
1223                                if (!is_object($this->jscal))
1224                                {
1225                                        $this->jscal = CreateObject('phpgwapi.jscalendar');
1226                                }
1227                                $time_param += $this->jscal->input2date($time_param['str'],False,'mday');
1228                                unset($time_param['str']);
1229                        }
1230                        if ($this->prefs['common']['timeformat'] == '12')
1231                        {
1232                                if ($time_param['ampm'] == 'pm')
1233                                {
1234                                        if ($time_param['hour'] <> 12)
1235                                        {
1236                                                $time_param['hour'] += 12;
1237                                        }
1238                                }
1239                                elseif ($time_param['ampm'] == 'am')
1240                                {
1241                                        if ($time_param['hour'] == 12)
1242                                        {
1243                                                $time_param['hour'] -= 12;
1244                                        }
1245                                }
1246
1247                                if($time_param['hour'] > 24)
1248                                {
1249                                        $time_param['hour'] -= 12;
1250                                }
1251                        }
1252                }
1253
1254                function validate_update($event)
1255                {
1256                        $error = 0;
1257                        // do a little form verifying
1258                        if (!count($event['participants']))
1259                        {
1260                                $error = 43;
1261                        }
1262                        elseif ($event['title'] == '')
1263                        {
1264                                $error = 40;
1265                        }
1266                        elseif (($GLOBALS['phpgw']->datetime->time_valid($event['start']['hour'],$event['start']['min'],0) == False) || ($GLOBALS['phpgw']->datetime->time_valid($event['end']['hour'],$event['end']['min'],0) == False))
1267                        {
1268                                $error = 41;
1269                        }
1270                        elseif (($GLOBALS['phpgw']->datetime->date_valid($event['start']['year'],$event['start']['month'],$event['start']['mday']) == False) || ($GLOBALS['phpgw']->datetime->date_valid($event['end']['year'],$event['end']['month'],$event['end']['mday']) == False) || ($GLOBALS['phpgw']->datetime->date_compare($event['start']['year'],$event['start']['month'],$event['start']['mday'],$event['end']['year'],$event['end']['month'],$event['end']['mday']) == 1))
1271                        {
1272                                $error = 42;
1273                        }
1274                        elseif ($GLOBALS['phpgw']->datetime->date_compare($event['start']['year'],$event['start']['month'],$event['start']['mday'],$event['end']['year'],$event['end']['month'],$event['end']['mday']) == 0)
1275                        {
1276                                if ($GLOBALS['phpgw']->datetime->time_compare($event['start']['hour'],$event['start']['min'],0,$event['end']['hour'],$event['end']['min'],0) == 1)
1277                                {
1278                                        $error = 42;
1279                                }
1280                        }
1281                        return $error;
1282                }
1283
1284                /*!
1285                @function participants_not_rejected($participants,$event)
1286                @abstract checks if any of the $particpants participates in $event and has not rejected it
1287                */
1288                function participants_not_rejected($participants,$event)
1289                {
1290                        //echo "participants_not_rejected()<br>participants =<pre>"; print_r($participants); echo "</pre><br>event[participants]=<pre>"; print_r($event['participants']); echo "</pre>\n";
1291                        foreach($participants as $uid => $status)
1292                        {
1293                                //echo "testing event[participants][uid=$uid] = '".$event['participants'][$uid]."'<br>\n";
1294                                if (isset($event['participants'][$uid]) && $event['participants'][$uid] != 'R' &&
1295                                        $status != 'R')
1296                                {
1297                                        return True;    // found not rejected participant in event
1298                                }
1299                        }
1300                        return False;
1301                }
1302
1303                function overlap($starttime,$endtime,$participants,$owner=0,$id=0,$restore_cache=False)
1304                {
1305//                      $retval = Array();
1306//                      $ok = False;
1307
1308/* This needs some attention.. by commenting this chunk of code it will fix bug #444265 */
1309
1310                        if($restore_cache)
1311                        {
1312                                $temp_cache_events = $this->cached_events;
1313                        }
1314
1315//                      $temp_start = (int)$GLOBALS['phpgw']->common->show_date($starttime,'Ymd');
1316//                      $temp_start_time = (int)($GLOBALS['phpgw']->common->show_date($starttime,'Hi');
1317//                      $temp_end = (int)$GLOBALS['phpgw']->common->show_date($endtime,'Ymd');
1318//                      $temp_end_time = (int)$GLOBALS['phpgw']->common->show_date($endtime,'Hi');
1319                        $temp_start = (int)(date('Ymd',$starttime));
1320                        $temp_start_time = (int)(date('Hi',$starttime));
1321                        $temp_end = (int)(date('Ymd',$endtime));
1322                        $temp_end_time = (int)(date('Hi',$endtime));
1323                        if($this->debug)
1324                        {
1325                                echo '<!-- Temp_Start: '.$temp_start.' -->'."\n";
1326                                echo '<!-- Temp_End: '.$temp_end.' -->'."\n";
1327                        }
1328
1329                        $users = Array();
1330                        if(count($participants))
1331                        {
1332                                while(list($user,$status) = each($participants))
1333                                {
1334                                        $users[] = $user;
1335                                }
1336                        }
1337                        else
1338                        {
1339                                $users[] = $this->owner;
1340                        }
1341
1342                        $possible_conflicts = $this->store_to_cache(
1343                                Array(
1344                                        'smonth'        => substr(strval($temp_start),4,2),
1345                                        'sday'  => substr(strval($temp_start),6,2),
1346                                        'syear' => substr(strval($temp_start),0,4),
1347                                        'emonth'        => substr(strval($temp_end),4,2),
1348                                        'eday'  => substr(strval($temp_end),6,2),
1349                                        'eyear' => substr(strval($temp_end),0,4),
1350                                        'owner' => $users
1351                                )
1352                        );
1353
1354                        if($this->debug)
1355                        {
1356                                echo '<!-- Possible Conflicts ('.($temp_start - 1).'): '.count($possible_conflicts[$temp_start - 1]).' -->'."\n";
1357                                echo '<!-- Possible Conflicts ('.$temp_start.'): '.count($possible_conflicts[$temp_start]).' '.count($id).' -->'."\n";
1358                        }
1359
1360                        if($possible_conflicts[$temp_start] || $possible_conflicts[$temp_end])
1361                        {
1362                                if($temp_start == $temp_end)
1363                                {
1364                                        if($this->debug)
1365                                        {
1366                                                echo '<!-- Temp_Start == Temp_End -->'."\n";
1367                                        }
1368                                        @reset($possible_conflicts[$temp_start]);
1369                                        while(list($key,$event) = each($possible_conflicts[$temp_start]))
1370                                        {
1371                                                $found = False;
1372                                                if($id)
1373                                                {
1374                                                        @reset($id);
1375                                                        while(list($key,$event_id) = each($id))
1376                                                        {
1377                                                                if($this->debug)
1378                                                                {
1379                                                                        echo '<!-- $id['.$key.'] = '.$id[$key].' = '.$event_id.' -->'."\n";
1380                                                                        echo '<!-- '.$event['id'].' == '.$event_id.' -->'."\n";
1381                                                                }
1382                                                                if($event['id'] == $event_id)
1383                                                                {
1384                                                                        $found = True;
1385                                                                }
1386                                                        }
1387                                                }
1388                                                if($this->debug)
1389                                                {
1390                                                        echo '<!-- Item found: '.$found.' -->'."<br>\n";
1391                                                }
1392                                                if(!$found)
1393                                                {
1394                                                        if($this->debug)
1395                                                        {
1396                                                                echo '<!-- Checking event id #'.$event['id'];
1397                                                        }
1398                                                        $temp_event_start = sprintf("%d%02d",$event['start']['hour'],$event['start']['min']);
1399                                                        $temp_event_end = sprintf("%d%02d",$event['end']['hour'],$event['end']['min']);
1400//                                                      if((($temp_start_time <= $temp_event_start) && ($temp_end_time >= $temp_event_start) && ($temp_end_time <= $temp_event_end)) ||
1401                                                        if(($temp_start_time <= $temp_event_start &&
1402                                                                $temp_end_time > $temp_event_start &&
1403                                                                $temp_end_time <= $temp_event_end ||
1404                                                                $temp_start_time >= $temp_event_start &&
1405                                                                $temp_start_time < $temp_event_end &&
1406                                                                $temp_end_time >= $temp_event_end ||
1407                                                                $temp_start_time <= $temp_event_start &&
1408                                                                $temp_end_time >= $temp_event_end ||
1409                                                                $temp_start_time >= $temp_event_start &&
1410                                                                $temp_end_time <= $temp_event_end) &&
1411                                                                $this->participants_not_rejected($participants,$event))
1412                                                        {
1413                                                                if($this->debug)
1414                                                                {
1415                                                                        echo ' Conflicts';
1416                                                                }
1417                                                                $retval[] = $event['id'];
1418                                                        }
1419                                                        if($this->debug)
1420                                                        {
1421                                                                echo ' -->'."\n";
1422                                                        }
1423                                                }
1424                                        }
1425                                }
1426                        }
1427                        else
1428                        {
1429                                $retval = False;
1430                        }
1431
1432                        if($restore_cache)
1433                        {
1434                                $this->cached_events = $temp_cache_events;
1435                        }
1436
1437                        return $retval;
1438                }
1439
1440                /*!
1441                @function check_perms( )
1442                @syntax check_perms($needed,$event=0,$other=0)
1443                @abstract Checks if the current user has the necessary ACL rights
1444                @author ralfbecker
1445                @discussion The check is performed on an event or general on the cal of an other user
1446                @param $needed necessary ACL right: PHPGW_ACL_{READ|EDIT|DELETE}
1447                @param $event event as array or the event-id or 0 for general check
1448                @param $other uid to check (if event==0) or 0 to check against $this->owner
1449                @note Participating in an event is considered as haveing read-access on that event, \
1450                        even if you have no general read-grant from that user.
1451                */
1452                function check_perms($needed,$event=0,$other=0)
1453                {
1454                        $event_in = $event;
1455                        if (is_int($event) && $event == 0)
1456                        {
1457                                $owner = $other > 0 ? $other : $this->owner;
1458                        }
1459                        else
1460                        {
1461                                if (!is_array($event))
1462                                {
1463                                        $event = $this->so->read_entry((int) $event);
1464                                }
1465                                if (!is_array($event))
1466                                {
1467                                        if ($this->xmlrpc)
1468                                        {
1469                                                $GLOBALS['server']->xmlrpc_error($GLOBALS['xmlrpcerr']['not_exist'],$GLOBALS['xmlrpcstr']['not_exist']);
1470                                        }
1471                                        return False;
1472                                }
1473                                $owner = $event['owner'];
1474                                $private = $event['public'] == False || $event['public'] == 0;
1475                        }
1476                        $user = $GLOBALS['phpgw_info']['user']['account_id'];
1477                        $grants = $this->grants[$owner];
1478
1479                        if (is_array($event) && $needed == PHPGW_ACL_READ)
1480                        {
1481                                // Check if the $user is one of the participants or has a read-grant from one of them
1482                                //
1483                                foreach($event['participants'] as $uid => $accept)
1484                                {
1485                                        if ($this->grants[$uid] & PHPGW_ACL_READ || $uid == $user)
1486                                        {
1487                                                $grants |= PHPGW_ACL_READ;
1488                                                break;
1489                                        }
1490                                }
1491                        }
1492
1493                        if ($GLOBALS['phpgw']->accounts->get_type($owner) == 'g' && $needed == PHPGW_ACL_ADD)
1494                        {
1495                                $access = False;        // a group can't be the owner of an event
1496                        }
1497                        else
1498                        {
1499                                $access = $user == $owner || $grants & $needed && (!$private || $grants & PHPGW_ACL_PRIVATE);
1500                        }
1501                        //echo "<p>".function_backtrace()." check_perms($needed,$event_id,$other) for user $user and needed_acl $needed: event='$event[title]': owner=$owner, private=$private, grants=$grants ==> access=$access</p>\n";
1502
1503                        return $access;
1504                }
1505
1506
1507                function display_status($user_status)
1508                {
1509                        if(@$this->prefs['calendar']['display_status'] && $user_status)
1510                        {
1511                                $user_status = substr($this->get_long_status($user_status),0,1);
1512
1513                                return ' ('.$user_status.')';
1514                        }
1515                        else
1516                        {
1517                                return '';
1518                        }
1519                }
1520
1521                function get_long_status($status_short)
1522                {
1523                        switch ($status_short)
1524                        {
1525                                case 'A':
1526                                        $status = lang('Accepted');
1527                                        break;
1528                                case 'R':
1529                                        $status = lang('Rejected');
1530                                        break;
1531                                case 'T':
1532                                        $status = lang('Tentative');
1533                                        break;
1534                                case 'U':
1535                                        $status = lang('No Response');
1536                                        break;
1537                        }
1538                        return $status;
1539                }
1540
1541                function is_private($event,$owner)
1542                {
1543                        if($owner == 0)
1544                        {
1545                                $owner = $this->owner;
1546                        }
1547                        if ($owner == $GLOBALS['phpgw_info']['user']['account_id'] || ($event['public']==1) || ($this->check_perms(PHPGW_ACL_PRIVATE,$event) && $event['public']==0) || $event['owner'] == $GLOBALS['phpgw_info']['user']['account_id'])
1548                        {
1549                                return False;
1550                        }
1551                        elseif($event['public'] == 0)
1552                        {
1553                                return True;
1554                        }
1555                        elseif($event['public'] == 2)
1556                        {
1557                                $is_private = True;
1558                                $groups = $GLOBALS['phpgw']->accounts->membership($owner);
1559                                while (list($key,$group) = each($groups))
1560                                {
1561                                        if (strpos(' '.implode(',',$event['groups']).' ',$group['account_id']))
1562                                        {
1563                                                return False;
1564                                        }
1565                                }
1566                        }
1567                        else
1568                        {
1569                                return False;
1570                        }
1571
1572                        return $is_private;
1573                }
1574
1575                function get_short_field($event,$is_private=True,$field='')
1576                {
1577                        if($is_private)
1578                        {
1579                                return 'private';
1580                        }
1581
1582// cut off too long titles
1583                        elseif(strlen($event[$field]) > 19 && !$this->printer_friendly && $field=="title")
1584//                      elseif(strlen($event[$field]) > 19 && $this->printer_friendly)
1585                        {
1586// we dont use currently 160304
1587//                              return substr($event[$field], 0 , 19) . '&nbsp;...';
1588                                return $event[$field];
1589                        }
1590                        else
1591                        {
1592                                return $event[$field];
1593                        }
1594                }
1595
1596                function long_date($first,$last=0)
1597                {
1598                        if (!is_array($first))
1599                        {
1600                                $first = $this->time2array($raw = $first);
1601                                $first['raw'] = $raw;
1602                                $first['day'] = $first['mday'];
1603                        }
1604                        if ($last && !is_array($last))
1605                        {
1606                                $last = $this->time2array($raw = $last);
1607                                $last['raw'] = $raw;
1608                                $last['day'] = $last['mday'];
1609                        }
1610                        $datefmt = $this->prefs['common']['dateformat'];
1611
1612                        $month_before_day = strtolower($datefmt[0]) == 'm' ||
1613                                strtolower($datefmt[2]) == 'm' && $datefmt[4] == 'd';
1614
1615                        for ($i = 0; $i < 5; $i += 2)
1616                        {
1617                                switch($datefmt[$i])
1618                                {
1619                                        case 'd':
1620                                                $range .= $first['day'] . ($datefmt[1] == '.' ? '.' : '');
1621                                                if ($first['month'] != $last['month'] || $first['year'] != $last['year'])
1622                                                {
1623                                                        if (!$month_before_day)
1624                                                        {
1625                                                                $range .= ' '.lang(strftime('%B',$first['raw']));
1626                                                        }
1627                                                        if ($first['year'] != $last['year'] && $datefmt[0] != 'Y')
1628                                                        {
1629                                                                $range .= ($datefmt[0] != 'd' ? ', ' : ' ') . $first['year'];
1630                                                        }
1631                                                        if (!$last)
1632                                                        {
1633                                                                return $range;
1634                                                        }
1635                                                        $range .= ' - ';
1636
1637                                                        if ($first['year'] != $last['year'] && $datefmt[0] == 'Y')
1638                                                        {
1639                                                                $range .= $last['year'] . ', ';
1640                                                        }
1641
1642                                                        if ($month_before_day)
1643                                                        {
1644                                                                $range .= lang(strftime('%B',$last['raw']));
1645                                                        }
1646                                                }
1647                                                else
1648                                                {
1649                                                        $range .= ' - ';
1650                                                }
1651                                                $range .= ' ' . $last['day'] . ($datefmt[1] == '.' ? '.' : '');
1652                                                break;
1653                                        case 'm':
1654                                        case 'M':
1655                                                $range .= ' '.lang(strftime('%B',$month_before_day ? $first['raw'] : $last['raw'])) . ' ';
1656                                                break;
1657                                        case 'Y':
1658                                                $range .= ($datefmt[0] == 'm' ? ', ' : ' ') . ($datefmt[0] == 'Y' ? $first['year'].($datefmt[2] == 'd' ? ', ' : ' ') : $last['year'].' ');
1659                                                break;
1660                                }
1661                        }
1662                        return $range;
1663                }
1664
1665                function get_week_label()
1666                {
1667                        $first = $GLOBALS['phpgw']->datetime->gmtdate($GLOBALS['phpgw']->datetime->get_weekday_start($this->year, $this->month, $this->day));
1668                        $last = $GLOBALS['phpgw']->datetime->gmtdate($first['raw'] + 518400);
1669
1670                        return ($this->long_date($first,$last));
1671                }
1672
1673                function normalizeminutes(&$minutes)
1674                {
1675                        $hour = 0;
1676                        $min = (int)$minutes;
1677                        if($min >= 60)
1678                        {
1679                                $hour += $min / 60;
1680                                $min %= 60;
1681                        }
1682                        settype($minutes,'integer');
1683                        $minutes = $min;
1684                        return $hour;
1685                }
1686
1687                function splittime($time,$follow_24_rule=True)
1688                {
1689                        $temp = array('hour','minute','second','ampm');
1690                        $time = strrev($time);
1691                        $second = (int)(strrev(substr($time,0,2)));
1692                        $minute = (int)(strrev(substr($time,2,2)));
1693                        $hour   = (int)(strrev(substr($time,4)));
1694                        $hour += $this->normalizeminutes($minute);
1695                        $temp['second'] = $second;
1696                        $temp['minute'] = $minute;
1697                        $temp['hour']   = $hour;
1698                        $temp['ampm']   = '  ';
1699                        if($follow_24_rule == True)
1700                        {
1701                                if ($this->prefs['common']['timeformat'] == '24')
1702                                {
1703                                        return $temp;
1704                                }
1705
1706                                $temp['ampm'] = 'am';
1707
1708                                if ((int)$temp['hour'] > 12)
1709                                {
1710                                        $temp['hour'] = (int)((int)$temp['hour'] - 12);
1711                                        $temp['ampm'] = 'pm';
1712                                }
1713                                elseif ((int)$temp['hour'] == 12)
1714                                {
1715                                        $temp['ampm'] = 'pm';
1716                                }
1717                        }
1718                        return $temp;
1719                }
1720
1721                function get_exception_array($exception_str='')
1722                {
1723                        $exception = Array();
1724                        if(strpos(' '.$exception_str,','))
1725                        {
1726                                $exceptions = explode(',',$exception_str);
1727                                for($exception_count=0;$exception_count<count($exceptions);$exception_count++)
1728                                {
1729                                        $exception[] = (int)$exceptions[$exception_count];
1730                                }
1731                        }
1732                        elseif($exception_str != '')
1733                        {
1734                                $exception[] = (int)$exception_str;
1735                        }
1736                        return $exception;
1737                }
1738
1739                function build_time_for_display($fixed_time)
1740                {
1741                        $time = $this->splittime($fixed_time);
1742                        $str = $time['hour'].':'.((int)$time['minute']<=9?'0':'').$time['minute'];
1743
1744                        if ($this->prefs['common']['timeformat'] == '12')
1745                        {
1746                                $str .= ' ' . $time['ampm'];
1747                        }
1748
1749                        return $str;
1750                }
1751
1752                function sort_event($event,$date)
1753                {
1754                        $inserted = False;
1755                        if(isset($event['recur_exception']))
1756                        {
1757                                $event_time = mktime($event['start']['hour'],$event['start']['min'],0,(int)(substr($date,4,2)),(int)(substr($date,6,2)),(int)(substr($date,0,4))) - $GLOBALS['phpgw']->datetime->tz_offset;
1758                                while($inserted == False && list($key,$exception_time) = each($event['recur_exception']))
1759                                {
1760                                        if($this->debug)
1761                                        {
1762                                                echo '<!-- checking exception datetime '.$exception_time.' to event datetime '.$event_time.' -->'."\n";
1763                                        }
1764                                        if($exception_time == $event_time)
1765                                        {
1766                                                $inserted = True;
1767                                        }
1768                                }
1769                        }
1770                        if($this->cached_events[$date] && $inserted == False)
1771                        {
1772
1773                                if($this->debug)
1774                                {
1775                                        echo '<!-- Cached Events found for '.$date.' -->'."\n";
1776                                }
1777                                $year = substr($date,0,4);
1778                                $month = substr($date,4,2);
1779                                $day = substr($date,6,2);
1780
1781                                if($this->debug)
1782                                {
1783                                        echo '<!-- Date : '.$date.' Count : '.count($this->cached_events[$date]).' -->'."\n";
1784                                }
1785
1786                                for($i=0;$i<count($this->cached_events[$date]);$i++)
1787                                {
1788                                        if($this->cached_events[$date][$i]['id'] == $event['id'] || $this->cached_events[$date][$i]['reference'] == $event['id'])
1789                                        {
1790                                                if($this->debug)
1791                                                {
1792                                                        echo '<!-- Item already inserted! -->'."\n";
1793                                                }
1794                                                $inserted = True;
1795                                                break;
1796                                        }
1797                                        /* This puts all spanning events across multiple days up at the top. */
1798                                        if($this->cached_events[$date][$i]['recur_type'] == MCAL_RECUR_NONE)
1799                                        {
1800                                                if($this->cached_events[$date][$i]['start']['mday'] != $day && $this->cached_events[$date][$i]['end']['mday'] >= $day)
1801                                                {
1802                                                        continue;
1803                                                }
1804                                        }
1805                                        if(date('Hi',mktime($event['start']['hour'],$event['start']['min'],$event['start']['sec'],$month,$day,$year)) < date('Hi',mktime($this->cached_events[$date][$i]['start']['hour'],$this->cached_events[$date][$i]['start']['min'],$this->cached_events[$date][$i]['start']['sec'],$month,$day,$year)))
1806                                        {
1807                                                for($j=count($this->cached_events[$date]);$j>=$i;$j--)
1808                                                {
1809                                                        $this->cached_events[$date][$j] = $this->cached_events[$date][$j-1];
1810                                                }
1811                                                if($this->debug)
1812                                                {
1813                                                        echo '<!-- Adding event ID: '.$event['id'].' to cached_events -->'."\n";
1814                                                }
1815                                                $inserted = True;
1816                                                $this->cached_events[$date][$i] = $event;
1817                                                break;
1818                                        }
1819                                }
1820                        }
1821                        if(!$inserted)
1822                        {
1823                                if($this->debug)
1824                                {
1825                                        echo '<!-- Adding event ID: '.$event['id'].' to cached_events -->'."\n";
1826                                }
1827                                $this->cached_events[$date][] = $event;
1828                        }
1829                }
1830
1831                function check_repeating_events($datetime)
1832                {
1833                        @reset($this->repeating_events);
1834                        $search_date_full = date('Ymd',$datetime);
1835                        $search_date_year = date('Y',$datetime);
1836                        $search_date_month = date('m',$datetime);
1837                        $search_date_day = date('d',$datetime);
1838                        $search_date_dow = date('w',$datetime);
1839                        $search_beg_day = mktime(0,0,0,$search_date_month,$search_date_day,$search_date_year);
1840                        if($this->debug)
1841                        {
1842                                echo '<!-- Search Date Full = '.$search_date_full.' -->'."\n";
1843                        }
1844                        $repeated = $this->repeating_events;
1845                        $r_events = count($repeated);
1846                        for ($i=0;$i<$r_events;$i++)
1847                        {
1848                                $rep_events = $this->repeating_events[$i];
1849                                $id = $rep_events['id'];
1850                                $event_beg_day = mktime(0,0,0,$rep_events['start']['month'],$rep_events['start']['mday'],$rep_events['start']['year']);
1851                                if($rep_events['recur_enddate']['month'] != 0 && $rep_events['recur_enddate']['mday'] != 0 && $rep_events['recur_enddate']['year'] != 0)
1852                                {
1853                                        $event_recur_time = $this->maketime($rep_events['recur_enddate']);
1854                                }
1855                                else
1856                                {
1857                                        $event_recur_time = mktime(0,0,0,1,1,2030);
1858                                }
1859                                $end_recur_date = date('Ymd',$event_recur_time);
1860                                $full_event_date = date('Ymd',$event_beg_day);
1861
1862                                if($this->debug)
1863                                {
1864                                        echo '<!-- check_repeating_events - Processing ID - '.$id.' -->'."\n";
1865                                        echo '<!-- check_repeating_events - Recurring End Date - '.$end_recur_date.' -->'."\n";
1866                                }
1867
1868                                // only repeat after the beginning, and if there is an rpt_end before the end date
1869                                if (($search_date_full > $end_recur_date) || ($search_date_full < $full_event_date))
1870                                {
1871                                        continue;
1872                                }
1873
1874                                if ($search_date_full == $full_event_date)
1875                                {
1876                                        $this->sort_event($rep_events,$search_date_full);
1877                                        continue;
1878                                }
1879                                else
1880                                {
1881                                        $freq = $rep_events['recur_interval'];
1882                                        $type = $rep_events['recur_type'];
1883                                        switch($type)
1884                                        {
1885                                                case MCAL_RECUR_DAILY:
1886                                                        if($this->debug)
1887                                                        {
1888                                                                echo '<!-- check_repeating_events - MCAL_RECUR_DAILY - '.$id.' -->'."\n";
1889                                                        }
1890                                                       
1891                                                        if ($freq == 1 && $rep_events['recur_enddate']['month'] != 0 && $rep_events['recur_enddate']['mday'] != 0 && $rep_events['recur_enddate']['year'] != 0 && $search_date_full <= $end_recur_date)
1892                                                        {
1893                                                                $this->sort_event($rep_events,$search_date_full);
1894                                                        }
1895                                                        elseif (floor(($search_beg_day - $event_beg_day)/86400) % ($freq ? $freq : 1))
1896                                                        {
1897                                                                continue;
1898                                                        }
1899                                                        else
1900                                                        {
1901                                                                $this->sort_event($rep_events,$search_date_full);
1902                                                        }
1903                                                        break;
1904                                                case MCAL_RECUR_WEEKLY:
1905                                                        if (floor(($search_beg_day - $event_beg_day)/604800)  % ($freq ? $freq : 1))
1906                                                        {
1907                                                                continue;
1908                                                        }
1909                                                        $check = 0;
1910                                                        switch($search_date_dow)
1911                                                        {
1912                                                                case 0:
1913                                                                        $check = MCAL_M_SUNDAY;
1914                                                                        break;
1915                                                                case 1:
1916                                                                        $check = MCAL_M_MONDAY;
1917                                                                        break;
1918                                                                case 2:
1919                                                                        $check = MCAL_M_TUESDAY;
1920                                                                        break;
1921                                                                case 3:
1922                                                                        $check = MCAL_M_WEDNESDAY;
1923                                                                        break;
1924                                                                case 4:
1925                                                                        $check = MCAL_M_THURSDAY;
1926                                                                        break;
1927                                                                case 5:
1928                                                                        $check = MCAL_M_FRIDAY;
1929                                                                        break;
1930                                                                case 6:
1931                                                                        $check = MCAL_M_SATURDAY;
1932                                                                        break;
1933                                                        }
1934                                                        if ($rep_events['recur_data'] & $check)
1935                                                        {
1936                                                                $this->sort_event($rep_events,$search_date_full);
1937                                                        }
1938                                                        break;
1939                                                case MCAL_RECUR_MONTHLY_WDAY:
1940                                                        if ((($search_date_year - $rep_events['start']['year']) * 12 + $search_date_month - $rep_events['start']['month']) % $freq)
1941                                                        {
1942                                                                continue;
1943                                                        }
1944
1945                                                        if (($GLOBALS['phpgw']->datetime->day_of_week($rep_events['start']['year'],$rep_events['start']['month'],$rep_events['start']['mday']) == $GLOBALS['phpgw']->datetime->day_of_week($search_date_year,$search_date_month,$search_date_day)) &&
1946                                                                (ceil($rep_events['start']['mday']/7) == ceil($search_date_day/7)))
1947                                                        {
1948                                                                $this->sort_event($rep_events,$search_date_full);
1949                                                        }
1950                                                        break;
1951                                                case MCAL_RECUR_MONTHLY_MDAY:
1952                                                        if ((($search_date_year - $rep_events['start']['year']) * 12 + $search_date_month - $rep_events['start']['month'])  % ($freq ? $freq : 1))
1953                                                        {
1954                                                                continue;
1955                                                        }
1956                                                        if ($search_date_day == $rep_events['start']['mday'])
1957                                                        {
1958                                                                $this->sort_event($rep_events,$search_date_full);
1959                                                        }
1960                                                        break;
1961                                                case MCAL_RECUR_YEARLY:
1962                                                        if (($search_date_year - $rep_events['start']['year']) % ($freq ? $freq : 1))
1963                                                        {
1964                                                                continue;
1965                                                        }
1966                                                        if (date('dm',$datetime) == date('dm',$event_beg_day))
1967                                                        {
1968                                                                $this->sort_event($rep_events,$search_date_full);
1969                                                        }
1970                                                        break;
1971                                        }
1972                                }
1973                        }       // end for loop
1974                }       // end function
1975
1976                function store_to_cache($params)
1977                {
1978                        if(!is_array($params))
1979                        {
1980                                return False;
1981                        }
1982                        if (isset($params['start']) && ($datearr = $GLOBALS['server']->iso86012date($params['start'])))
1983                        {
1984                                $syear = $datearr['year'];
1985                                $smonth = $datearr['month'];
1986                                $sday = $datearr['mday'];
1987                                $this->xmlrpc = True;
1988                        }
1989                        else
1990                        {
1991                                $syear = $params['syear'];
1992                                $smonth = $params['smonth'];
1993                                $sday = $params['sday'];
1994                        }
1995                        if (isset($params['end']) && ($datearr = $GLOBALS['server']->iso86012date($params['end'])))
1996                        {
1997                                $eyear = $datearr['year'];
1998                                $emonth = $datearr['month'];
1999                                $eday = $datearr['mday'];
2000                                $this->xmlrpc = True;
2001                        }
2002                        else
2003                        {
2004                                $eyear = (isset($params['eyear'])?$params['eyear']:0);
2005                                $emonth = (isset($params['emonth'])?$params['emonth']:0);
2006                                $eday = (isset($params['eday'])?$params['eday']:0);
2007                        }
2008                        if (!isset($params['owner']) && @$this->xmlrpc)
2009                        {
2010                                $owner_id = $GLOBALS['phpgw_info']['user']['user_id'];
2011                        }
2012                        else
2013                        {
2014                                $owner_id = (isset($params['owner'])?$params['owner']:0);
2015                                if($owner_id==0 && $this->is_group)
2016                                {
2017                                        unset($owner_id);
2018                                        $owner_id = $this->g_owner;
2019                                        if($this->debug)
2020                                        {
2021                                                echo '<!-- owner_id in ('.implode(',',$owner_id).') -->'."\n";
2022                                        }
2023                                }
2024                        }
2025                        if(!$eyear && !$emonth && !$eday)
2026                        {
2027                                $edate = mktime(23,59,59,$smonth + 1,$sday + 1,$syear);
2028                                $eyear = date('Y',$edate);
2029                                $emonth = date('m',$edate);
2030                                $eday = date('d',$edate);
2031                        }
2032                        else
2033                        {
2034                                if(!$eyear)
2035                                {
2036                                        $eyear = $syear;
2037                                }
2038                                if(!$emonth)
2039                                {
2040                                        $emonth = $smonth + 1;
2041                                        if($emonth > 12)
2042                                        {
2043                                                $emonth = 1;
2044                                                $eyear++;
2045                                        }
2046                                }
2047                                if(!$eday)
2048                                {
2049                                        $eday = $sday + 1;
2050                                }
2051                                $edate = mktime(23,59,59,$emonth,$eday,$eyear);
2052                        }
2053                        //echo "<p>bocalendar::store_to_cache(".print_r($params,True).") syear=$syear, smonth=$smonth, sday=$sday, eyear=$eyear, emonth=$emonth, eday=$eday, xmlrpc='$param[xmlrpc]'</p>\n";
2054                        if($this->debug)
2055                        {
2056                                echo '<!-- Start Date : '.sprintf("%04d%02d%02d",$syear,$smonth,$sday).' -->'."\n";
2057                                echo '<!-- End   Date : '.sprintf("%04d%02d%02d",$eyear,$emonth,$eday).' -->'."\n";
2058                        }
2059
2060                        if($owner_id)
2061                        {
2062                                $cached_event_ids = $this->so->list_events($syear,$smonth,$sday,$eyear,$emonth,$eday,$owner_id);
2063                                $cached_event_ids_repeating = $this->so->list_repeated_events($syear,$smonth,$sday,$eyear,$emonth,$eday,$owner_id);
2064                        }
2065                        else
2066                        {
2067                                $cached_event_ids = $this->so->list_events($syear,$smonth,$sday,$eyear,$emonth,$eday);
2068                                $cached_event_ids_repeating = $this->so->list_repeated_events($syear,$smonth,$sday,$eyear,$emonth,$eday);
2069                        }
2070
2071                        $c_cached_ids = count($cached_event_ids);
2072                        $c_cached_ids_repeating = count($cached_event_ids_repeating);
2073
2074                        if($this->debug)
2075                        {
2076                                echo '<!-- events cached : '.$c_cached_ids.' : for : '.sprintf("%04d%02d%02d",$syear,$smonth,$sday).' -->'."\n";
2077                                echo '<!-- repeating events cached : '.$c_cached_ids_repeating.' : for : '.sprintf("%04d%02d%02d",$syear,$smonth,$sday).' -->'."\n";
2078                        }
2079
2080                        $this->cached_events = Array();
2081
2082                        if($c_cached_ids == 0 && $c_cached_ids_repeating == 0)
2083                        {
2084                                return;
2085                        }
2086
2087                        $cache_start = (int)(sprintf("%04d%02d%02d",$syear,$smonth,$sday));
2088                        $cached_event=$this->get_cached_event();
2089                        if($c_cached_ids)
2090                        {
2091                                for($i=0;$i<$c_cached_ids;$i++)
2092                                {
2093                                        $event = $this->so->read_entry($cached_event_ids[$i]);
2094                                        if ($event['recur_type'])
2095                                        {
2096                                                continue;       // fetch recuring events only in 2. loop
2097                                        }
2098                                        $startdate = (int)(date('Ymd',$this->maketime($event['start'])));
2099                                        $enddate = (int)(date('Ymd',$this->maketime($event['end'])));
2100                                        $this->cached_events[$startdate][] = $event;
2101                                        if($startdate != $enddate)
2102                                        {
2103                                                $start['year'] = (int)(substr($startdate,0,4));
2104                                                $start['month'] = (int)(substr($startdate,4,2));
2105                                                $start['mday'] = (int)(substr($startdate,6,2));
2106                                                for($j=$startdate,$k=0;$j<=$enddate;$k++,$j=(int)(date('Ymd',mktime(0,0,0,$start['month'],$start['mday'] + $k,$start['year']))))
2107                                                {
2108                                                        $c_evt_day = count($this->cached_events[$j]) - 1;
2109                                                        if($c_evt_day < 0)
2110                                                        {
2111                                                                $c_evt_day = 0;
2112                                                        }
2113                                                        if($this->debug)
2114                                                        {
2115                                                                echo '<!-- Date: '.$j.' Count : '.$c_evt_day.' -->'."\n";
2116                                                        }
2117                                                        if($this->cached_events[$j][$c_evt_day]['id'] != $event['id'])
2118                                                        {
2119                                                                if($this->debug)
2120                                                                {
2121                                                                        echo '<!-- Adding Event for Date: '.$j.' -->'."\n";
2122                                                                }
2123                                                                $this->cached_events[$j][] = $event;
2124                                                        }
2125                                                        if ($j >= $cache_start && (@$params['no_doubles'] || @$this->xmlrpc))
2126                                                        {
2127                                                                break;  // add event only once on it's startdate
2128                                                        }
2129                                                }
2130                                        }
2131                                }
2132                        }
2133
2134                        $this->repeating_events = Array();
2135                        if($c_cached_ids_repeating)
2136                        {
2137                                for($i=0;$i<$c_cached_ids_repeating;$i++)
2138                                {
2139                                        $this->repeating_events[$i] = $this->so->read_entry($cached_event_ids_repeating[$i]);
2140                                        if($this->debug)
2141                                        {
2142                                                echo '<!-- Cached Events ID: '.$cached_event_ids_repeating[$i].' ('.sprintf("%04d%02d%02d",$this->repeating_events[$i]['start']['year'],$this->repeating_events[$i]['start']['month'],$this->repeating_events[$i]['start']['mday']).') -->'."\n";
2143                                        }
2144                                }
2145                                for($date=mktime(0,0,0,$smonth,$sday,$syear);$date<=$edate;$date += 86400)
2146                                {
2147                                        if($this->debug)
2148                                        {
2149                                                $search_date = date('Ymd',$date);
2150                                                echo '<!-- Calling check_repeating_events('.$search_date.') -->'."\n";
2151                                        }
2152                                        $this->check_repeating_events($date);
2153                                        if($this->debug)
2154                                        {
2155                                                echo '<!-- Total events found matching '.$search_date.' = '.count($this->cached_events[$search_date]).' -->'."\n";
2156                                                for($i=0;$i<count($this->cached_events[$search_date]);$i++)
2157                                                {
2158                                                        echo '<!-- Date: '.$search_date.' ['.$i.'] = '.$this->cached_events[$search_date][$i]['id'].' -->'."\n";
2159                                                }
2160                                        }
2161                                }
2162                        }
2163                        $retval = Array();
2164                        for($j=date('Ymd',mktime(0,0,0,$smonth,$sday,$syear)),$k=0;$j<=date('Ymd',mktime(0,0,0,$emonth,$eday,$eyear));$k++,$j=date('Ymd',mktime(0,0,0,$smonth,$sday + $k,$syear)))
2165                        {
2166                                if(is_array($this->cached_events[$j]))
2167                                {
2168                                        if ($this->xmlrpc)
2169                                        {
2170                                                foreach($this->cached_events[$j] as $event)
2171                                                {
2172                                                        $retval[] = $this->xmlrpc_prepare($event);
2173                                                }
2174                                        }
2175                                        else
2176                                        {
2177                                                $retval[$j] = $this->cached_events[$j];
2178                                        }
2179                                }
2180                        }
2181                        //echo "store_to_cache(".print_r($params,True).")=<pre>".print_r($retval,True)."</pre>\n";
2182                        $this->so->cal->event = $cached_event;
2183                        return $retval;
2184                }
2185
2186                function xmlrpc_prepare(&$event)
2187                {
2188                        $event['rights'] = $this->grants[$event['owner']];
2189
2190                        foreach(array('start','end','modtime','recur_enddate') as $name)
2191                        {
2192                                if (isset($event[$name]))
2193                                {
2194                                        $event[$name] = $GLOBALS['server']->date2iso8601($event[$name]);
2195                                }
2196                        }
2197                        if (is_array($event['recur_exception']))
2198                        {
2199                                foreach($event['recur_exception'] as $key => $timestamp)
2200                                {
2201                                        $event['recur_exception'][$key] = $GLOBALS['server']->date2iso8601($timestamp);
2202                                }
2203                        }
2204                        static $user_cache = array();
2205
2206                        if (!is_object($GLOBALS['phpgw']->perferences))
2207                        {
2208                                $GLOBALS['phpgw']->perferences = CreateObject('phpgwapi.preferences');
2209                        }
2210                        foreach($event['participants'] as $user_id => $status)
2211                        {
2212                                if (!isset($user_cache[$user_id]))
2213                                {
2214                                        $user_cache[$user_id] = array(
2215                                                'name'   => $GLOBALS['phpgw']->common->grab_owner_name($user_id),
2216                                                'email'  => $GLOBALS['phpgw']->perferences->email_address($user_id)
2217                                        );
2218                                }
2219                                $event['participants'][$user_id] = $user_cache[$user_id] + array(
2220                                        'status' => $status,
2221                                );
2222                        }
2223                        if (is_array($event['alarm']))
2224                        {
2225                                foreach($event['alarm'] as $id => $alarm)
2226                                {
2227                                        $event['alarm'][$id]['time'] = $GLOBALS['server']->date2iso8601($alarm['time']);
2228                                        if ($alarm['owner'] != $GLOBALS['phpgw_info']['user']['account_id'])
2229                                        {
2230                                                unset($event['alarm'][$id]);
2231                                        }
2232                                }
2233                        }
2234                        $event['category'] = $GLOBALS['server']->cats2xmlrpc(explode(',',$event['category']));
2235
2236                        // using access={public|privat} in all modules via xmlrpc
2237                        $event['access'] = $event['public'] ? 'public' : 'privat';
2238                        unset($event['public']);
2239
2240                        return $event;
2241                }
2242
2243                /* Begin Appsession Data */
2244                function store_to_appsession($event)
2245                {
2246                        $GLOBALS['phpgw']->session->appsession('entry','calendar',$event);
2247                }
2248
2249                function restore_from_appsession()
2250                {
2251                        $this->event_init();
2252                        $event = $GLOBALS['phpgw']->session->appsession('entry','calendar');
2253                        $this->so->cal->event = $event;
2254                        return $event;
2255                }
2256                /* End Appsession Data */
2257
2258                /* Begin of SO functions */
2259                function get_cached_event()
2260                {
2261                        return $this->so->get_cached_event();
2262                }
2263
2264                function add_attribute($var,$value,$index='**(**')
2265                {
2266                        $this->so->add_attribute($var,$value,$index);
2267                }
2268
2269                function event_init()
2270                {
2271                        $this->so->event_init();
2272                }
2273
2274                function set_start($year,$month,$day=0,$hour=0,$min=0,$sec=0)
2275                {
2276                        $this->so->set_start($year,$month,$day,$hour,$min,$sec);
2277                }
2278
2279                function set_end($year,$month,$day=0,$hour=0,$min=0,$sec=0)
2280                {
2281                        $this->so->set_end($year,$month,$day,$hour,$min,$sec);
2282                }
2283
2284                function set_title($title='')
2285                {
2286                        $this->so->set_title($title);
2287                }
2288
2289                function set_description($description='')
2290                {
2291                        $this->so->set_description($description);
2292                }
2293                function set_ex_participants($ex_participants='')
2294                {
2295                        $this->so->set_ex_participants($ex_participants);
2296                }
2297
2298                function set_class($class)
2299                {
2300                        $this->so->set_class($class);
2301                }
2302
2303                function set_category($category='')
2304                {
2305                        $this->so->set_category($category);
2306                }
2307
2308                function set_alarm($alarm)
2309                {
2310                        $this->so->set_alarm($alarm);
2311                }
2312
2313                function set_recur_none()
2314                {
2315                        $this->so->set_recur_none();
2316                }
2317
2318                function set_recur_daily($year,$month,$day,$interval)
2319                {
2320                        $this->so->set_recur_daily($year,$month,$day,$interval);
2321                }
2322
2323                function set_recur_weekly($year,$month,$day,$interval,$weekdays)
2324                {
2325                        $this->so->set_recur_weekly($year,$month,$day,$interval,$weekdays);
2326                }
2327
2328                function set_recur_monthly_mday($year,$month,$day,$interval)
2329                {
2330                        $this->so->set_recur_monthly_mday($year,$month,$day,$interval);
2331                }
2332
2333                function set_recur_monthly_wday($year,$month,$day,$interval)
2334                {
2335                        $this->so->set_recur_monthly_wday($year,$month,$day,$interval);
2336                }
2337
2338                function set_recur_yearly($year,$month,$day,$interval)
2339                {
2340                        $this->so->set_recur_yearly($year,$month,$day,$interval);
2341                }
2342                /* End of SO functions */
2343
2344                function prepare_matrix($interval,$increment,$part,$fulldate)
2345                {
2346                        for($h=0;$h<24;$h++)
2347                        {
2348                                for($m=0;$m<$interval;$m++)
2349                                {
2350                                        $index = (($h * 10000) + (($m * $increment) * 100));
2351                                        $time_slice[$index]['marker'] = '&nbsp';
2352                                        $time_slice[$index]['description'] = '';
2353                                }
2354                        }
2355                        foreach($this->cached_events[$fulldate] as $event)
2356                        {
2357                                if ($event['participants'][$part] == 'R')
2358                                {
2359                                        continue;       // dont show rejected invitations, as they are free time
2360                                }
2361                                $eventstart = $GLOBALS['phpgw']->datetime->localdates($this->maketime($event['start']) - $GLOBALS['phpgw']->datetime->tz_offset);
2362                                $eventend = $GLOBALS['phpgw']->datetime->localdates($this->maketime($event['end']) - $GLOBALS['phpgw']->datetime->tz_offset);
2363                                $start = ($eventstart['hour'] * 10000) + ($eventstart['minute'] * 100);
2364                                $starttemp = $this->splittime("$start",False);
2365                                $subminute = 0;
2366                                for($m=0;$m<$interval;$m++)
2367                                {
2368                                        $minutes = $increment * $m;
2369                                        if((int)$starttemp['minute'] > $minutes && (int)$starttemp['minute'] < ($minutes + $increment))
2370                                        {
2371                                                $subminute = ($starttemp['minute'] - $minutes) * 100;
2372                                        }
2373                                }
2374                                $start -= $subminute;
2375                                $end =  ($eventend['hour'] * 10000) + ($eventend['minute'] * 100);
2376                                $endtemp = $this->splittime("$end",False);
2377                                $addminute = 0;
2378                                for($m=0;$m<$interval;$m++)
2379                                {
2380                                        $minutes = ($increment * $m);
2381                                        if($endtemp['minute'] < ($minutes + $increment) && $endtemp['minute'] > $minutes)
2382                                        {
2383                                                $addminute = ($minutes + $increment - $endtemp['minute']) * 100;
2384                                        }
2385                                }
2386                                $end += $addminute;
2387                                $starttemp = $this->splittime("$start",False);
2388                                $endtemp = $this->splittime("$end",False);
2389
2390                                for($h=$starttemp['hour'];$h<=$endtemp['hour'];$h++)
2391                                {
2392                                        $startminute = 0;
2393                                        $endminute = $interval;
2394                                        $hour = $h * 10000;
2395                                        if($h == (int)$starttemp['hour'])
2396                                        {
2397                                                $startminute = ($starttemp['minute'] / $increment);
2398                                        }
2399                                        if($h == (int)$endtemp['hour'])
2400                                        {
2401                                                $endminute = ($endtemp['minute'] / $increment);
2402                                        }
2403                                        $private = $this->is_private($event,$part);
2404                                        $time_display = $GLOBALS['phpgw']->common->show_date($eventstart['raw'],$this->users_timeformat).'-'.$GLOBALS['phpgw']->common->show_date($eventend['raw'],$this->users_timeformat);
2405                                        $time_description = '('.$time_display.') '.$this->get_short_field($event,$private,'title').$this->display_status($event['participants'][$part]);
2406                                        for($m=$startminute;$m<$endminute;$m++)
2407                                        {
2408                                                $index = ($hour + (($m * $increment) * 100));
2409                                                $time_slice[$index]['marker'] = '-';
2410                                                $time_slice[$index]['description'] = $time_description;
2411                                                $time_slice[$index]['id'] = $event['id'];
2412                                        }
2413                                }
2414                        }
2415                        return $time_slice;
2416                }
2417
2418                /*!
2419                @function set_status
2420                @abstract set the participant response $status for event $cal_id and notifies the owner of the event
2421                */
2422                function set_status($cal_id,$status)
2423                {
2424                        $status2msg = array(
2425                                REJECTED  => MSG_REJECTED,
2426                                TENTATIVE => MSG_TENTATIVE,
2427                                ACCEPTED  => MSG_ACCEPTED
2428                        );
2429                        if (!isset($status2msg[$status]))
2430                        {
2431                                return False;
2432                        }
2433                        $this->so->set_status($cal_id,$status);
2434                        $event = $this->so->read_entry($cal_id);
2435                        $this->send_update($status2msg[$status],$event['participants'],$event);
2436
2437                        return True;
2438                }
2439
2440                /*!
2441                @function update_requested
2442                @abstract checks if $userid has requested (in $part_prefs) updates for $msg_type
2443                @syntax update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event)
2444                @param $userid numerical user-id
2445                @param $part_prefs preferces of the user $userid
2446                @param $msg_type type of the notification: MSG_ADDED, MSG_MODIFIED, MSG_ACCEPTED, ...
2447                @param $old_event Event before the change
2448                @param $new_event Event after the change
2449                @returns 0 = no update requested, > 0 update requested
2450                */
2451                function update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event)
2452                {
2453                        if ($msg_type == MSG_ALARM)
2454                        {
2455                                return True;    // always True for now
2456                        }
2457                        $want_update = 0;
2458
2459                        // the following switch fall-through all cases, as each included the following too
2460                        //
2461                        $msg_is_response = $msg_type == MSG_REJECTED || $msg_type == MSG_ACCEPTED || $msg_type == MSG_TENTATIVE;
2462
2463                        switch($ru = $part_prefs['calendar']['receive_updates'])
2464                        {
2465                                case 'responses':
2466                                        if ($msg_is_response)
2467                                        {
2468                                                ++$want_update;
2469                                        }
2470                                case 'modifications':
2471                                        if ($msg_type == MSG_MODIFIED)
2472                                        {
2473                                                ++$want_update;
2474                                        }
2475                                case 'time_change_4h':
2476                                case 'time_change':
2477                                        $diff = max(abs($this->maketime($old_event['start'])-$this->maketime($new_event['start'])),
2478                                                abs($this->maketime($old_event['end'])-$this->maketime($new_event['end'])));
2479                                        $check = $ru == 'time_change_4h' ? 4 * 60 * 60 - 1 : 0;
2480                                        if ($msg_type == MSG_MODIFIED && $diff > $check)
2481                                        {
2482                                                ++$want_update;
2483                                        }
2484                                case 'add_cancel':
2485                                        if ($old_event['owner'] == $userid && $msg_is_response ||
2486                                                $msg_type == MSG_DELETED || $msg_type == MSG_ADDED)
2487                                        {
2488                                                ++$want_update;
2489                                        }
2490                                        break;
2491                                case 'no':
2492                                        break;
2493                        }
2494                        //echo "<p>bocalendar::update_requested(user=$userid,pref=".$part_prefs['calendar']['receive_updates'] .",msg_type=$msg_type,".($old_event?$old_event['title']:'False').",".($old_event?$old_event['title']:'False').") = $want_update</p>\n";
2495                        return $want_update > 0;
2496                }
2497
2498        function create_vcard($event_array)
2499        {
2500        $tmpattach="BEGIN:VCALENDAR\n"
2501        ."PRODID:-//Expresso Livre//Calendar//EN\n"
2502        ."VERSION:1.0\n";
2503                foreach ($event_array as $event)
2504                {
2505                        // It translates int to string
2506                        if ( $event[end][month] < 10 )
2507                                $end_event_month="0".$event[end][month];
2508                        else
2509                                $end_event_month=$event[end][month];
2510                        if ( $event[start][month] < 10 )
2511                                $start_event_month="0".$event[start][month];
2512                        else
2513                                $start_event_month=$event[start][month];
2514                        if ( $event[end][mday] < 10 )
2515                                $end_event_day="0".$event[end][mday];
2516                        else
2517                                $end_event_day=$event[end][mday];
2518                        if ( $event[start][mday] < 10 )
2519                                $start_event_day="0".$event[start][mday];
2520                        else
2521                                $start_event_day=$event[start][mday];
2522                        if ( $event[start][hour] < 10)
2523                                $start_event_hour="0".$event[start][hour];
2524                        else
2525                                $start_event_hour=$event[start][hour];
2526                        if ( $event[end][hour] < 10)
2527                                $end_event_hour="0".$event[end][hour];
2528                        else
2529                                $end_event_hour=$event[end][hour];
2530                               
2531                        if ( $event[start][min] < 10)
2532                                $start_event_min="0".$event[start][min];
2533                        else
2534                                $start_event_min=$event[start][min];
2535                        if ( $event[end][min] < 10)
2536                                $end_event_min="0".$event[end][min];
2537                        else
2538                                $end_event_min=$event[end][min];       
2539               
2540
2541                        $tmpattach.="BEGIN:VEVENT\n"
2542                        ."DTSTART:".$event[start][year].$start_event_month.$start_event_day."T".$start_event_hour.$start_event_min."00Z\n"
2543                        ."DTEND:".$event[end][year].$end_event_month.$end_event_day."T".$end_event_hour.$end_event_min."00Z\n"
2544                        ."UID:Expresso-".$event[id].$event[uid]."\n"
2545                        ."LAST-MODIFIED:".time()."\n"
2546                        ."DESCRIPTION:".$event[description]."\n"
2547                        ."SUMMARY:".$event[title]."\n"
2548                        ."LOCATION:".$event[location]."\n"
2549                        ."END:VEVENT"."\n";
2550                }
2551                        $tmpattach.="END:VCALENDAR\n";
2552                        return $tmpattach;
2553}
2554
2555                /*!
2556                @function send_update
2557                @abstract sends update-messages to certain participants of an event
2558                @syntax send_update($msg_type,$to_notify,$old_event,$new_event=False)
2559                @param $msg_type type of the notification: MSG_ADDED, MSG_MODIFIED, MSG_ACCEPTED, ...
2560                @param $to_notify array with numerical user-ids as keys (!) (value is not used)
2561                @param $old_event Event before the change
2562                @param $new_event Event after the change
2563                */
2564                function send_update($msg_type,$to_notify,$old_event,$new_event=False,$user=False)
2565                {
2566                       
2567                        //echo "<p>bocalendar::send_update(type=$msg_type,to_notify="; print_r($to_notify); echo ", old_event="; print_r($old_event); echo ", new_event="; print_r($new_event); echo ", user=$user)</p>\n";
2568                        if (!is_array($to_notify))
2569                        {
2570                                $to_notify = array();
2571                        }
2572                        $owner = $old_event ? $old_event['owner'] : $new_event['owner'];
2573                        if ($owner && !isset($to_notify[$owner]) && $msg_type != MSG_ALARM)
2574                        {
2575                                $to_notify[$owner] = 'owner';   // always include the event-owner
2576                        }
2577                        $version = $GLOBALS['phpgw_info']['apps']['calendar']['version'];
2578
2579                        $GLOBALS['phpgw_info']['user']['preferences'] = $GLOBALS['phpgw']->preferences->create_email_preferences();
2580                        $sender = $GLOBALS['phpgw_info']['user']['email'];
2581
2582                        $temp_tz_offset = $this->prefs['common']['tz_offset'];
2583                        $temp_timeformat = $this->prefs['common']['timeformat'];
2584                        $temp_dateformat = $this->prefs['common']['dateformat'];
2585
2586                        $tz_offset = ((60 * 60) * (int)$temp_tz_offset);
2587
2588                        if($old_event != False)
2589                        {
2590                                $t_old_start_time = $this->maketime($old_event['start']);
2591                                if($t_old_start_time < (time() - 86400))
2592                                {
2593                                        return False;
2594                                }
2595                        }
2596
2597                        $temp_user = $GLOBALS['phpgw_info']['user'];
2598
2599                        if (!$user)
2600                        {
2601                                $user = $this->owner;
2602                        }
2603                        $GLOBALS['phpgw_info']['user']['preferences'] = $GLOBALS['phpgw']->preferences->create_email_preferences($user);
2604
2605                        $event = $msg_type == MSG_ADDED || $msg_type == MSG_MODIFIED ? $new_event : $old_event;
2606                        if($old_event != False)
2607                        {
2608                                $old_starttime = $t_old_start_time - $GLOBALS['phpgw']->datetime->tz_offset;
2609                        }
2610                        $starttime = $this->maketime($event['start']) - $GLOBALS['phpgw']->datetime->tz_offset;
2611                        $endtime   = $this->maketime($event['end']) - $GLOBALS['phpgw']->datetime->tz_offset;
2612
2613                        switch($msg_type)
2614                        {
2615                                case MSG_DELETED:
2616                                        $action = lang('Canceled');
2617                                        $msg = 'Canceled';
2618                                        $msgtype = '"calendar";';
2619                                        $method = 'cancel';
2620                                        $typesend = 1;
2621                                        break;
2622                                case MSG_MODIFIED:
2623                                        $action = lang('Modified');
2624                                        $msg = 'Modified';
2625                                        $msgtype = '"calendar"; Version="'.$version.'"; Id="'.$new_event['id'].'"';
2626                                        $method = 'request';
2627                                        $typesend = 2;
2628                                        break;
2629                                case MSG_ADDED:
2630                                        $action = lang('Added');
2631                                        $msg = 'Added';
2632                                        $msgtype = '"calendar"; Version="'.$version.'"; Id="'.$new_event['id'].'"';
2633                                        $method = 'request';
2634                                        $typesend = 3;
2635                                        break;
2636                                case MSG_REJECTED:
2637                                        $action = lang('Rejected');
2638                                        $msg = 'Response';
2639                                        $msgtype = '"calendar";';
2640                                        $method = 'reply';
2641                                        $typesend = 4;
2642                                        break;
2643                                case MSG_TENTATIVE:
2644                                        $action = lang('Tentative');
2645                                        $msg = 'Response';
2646                                        $msgtype = '"calendar";';
2647                                        $method = 'reply';
2648                                        $typesend = 5;
2649                                        break;
2650                                case MSG_ACCEPTED:
2651                                        $action = lang('Accepted');
2652                                        $msg = 'Response';
2653                                        $msgtype = '"calendar";';
2654                                        $method = 'reply';
2655                                        $typesend = 6;
2656                                        break;
2657                                case MSG_ALARM:
2658                                        $action = lang('Alarm');
2659                                        $msg = 'Alarm';
2660                                        $msgtype = '"calendar";';
2661                                        $method = 'publish';    // duno if thats right
2662                                        $typesend = 7;
2663                                        break;
2664                                default:
2665                                        $method = 'publish';
2666                                        $typesend = 8;
2667                        }
2668                        $notify_msg = $this->prefs['calendar']['notify'.$msg];
2669                        if (empty($notify_msg))
2670                        {
2671                                $notify_msg = $this->prefs['calendar']['notifyAdded'];  // use a default
2672                        }
2673                        $details = array(                       // event-details for the notify-msg
2674                                'id'          => $msg_type == MSG_ADDED ? $new_event['id'] : $old_event['id'],
2675                                'action'      => $action,
2676                        );
2677                        $event_arr = $this->event2array($event);
2678                        foreach($event_arr as $key => $val)
2679                        {
2680                                $details[$key] = $val['data'];
2681                        }
2682                       
2683                        $details['participants'] = implode("\n",$details['participants']);
2684
2685                        $details['link'] = $GLOBALS['phpgw_info']['server']['webserver_url'].'/index.php?menuaction=calendar.uicalendar.view&cal_id='.$event['id'];
2686                        // if url is only a path, try guessing the rest ;-)
2687                        if ($GLOBALS['phpgw_info']['server']['webserver_url'][0] == '/')
2688                        {
2689                                $details['link'] = ($GLOBALS['phpgw_info']['server']['enforce_ssl'] ? 'https://' : 'http://').
2690                                        ($GLOBALS['phpgw_info']['server']['hostname'] ? $GLOBALS['phpgw_info']['server']['hostname'] : 'localhost').
2691                                        $details['link'];
2692                        }
2693
2694                        /*if(!is_object($GLOBALS['phpgw']->send))
2695                        {
2696                                $GLOBALS['phpgw']->send = CreateObject('phpgwapi.send');
2697                        }*/
2698                //      $send = &$GLOBALS['phpgw']->send;
2699                       
2700                        //Seta o email usando phpmailer
2701                        define('PHPGW_INCLUDE_ROOT','../');     
2702                        define('PHPGW_API_INC','../phpgwapi/inc');     
2703                        include_once(PHPGW_API_INC.'/class.phpmailer.inc.php');
2704                        $mail = new PHPMailer();
2705                        $mail->IsSMTP();
2706                        /*
2707                        $mail->Host = $_SESSION['phpgw_info']['expressomail']['email_server']['smtpServer'];
2708                        $mail->Port = $_SESSION['phpgw_info']['expressomail']['email_server']['smtpPort'];
2709                        $mail->From = $_SESSION['phpgw_info']['expressomail']['user']['email'];
2710                        $mail->FromName = $_SESSION['phpgw_info']['expressomail']['user']['fullname'];
2711                        $mail->IsHTML(true);
2712                        */
2713                        $boemailadmin = CreateObject('emailadmin.bo');
2714                        $emailadmin_profile = $boemailadmin->getProfileList();
2715                        $emailadmin = $boemailadmin->getProfile($emailadmin_profile[0]['profileID']);
2716                        $mail->Host = $emailadmin['smtpServer'];
2717                        $mail->Port = $emailadmin['smtpPort'];
2718                        $mail->From = $GLOBALS['phpgw']->preferences->values['email'];
2719                        $mail->FromName = $GLOBALS['phpgw_info']['user'];
2720                        $mail->IsHTML(true);
2721
2722                        // Aqui é enviado o email
2723                        foreach($to_notify as $userid => $statusid)
2724                        {
2725                                $mail->ClearAllRecipients();
2726                                $mail->ClearAttachments();
2727                               
2728                                $userid = (int)$userid;
2729
2730                                if ($statusid == 'R' || $GLOBALS['phpgw']->accounts->get_type($userid) == 'g')
2731                                {
2732                                        continue;       // dont notify rejected participants
2733                                }
2734                                if($userid != $GLOBALS['phpgw_info']['user']['account_id'] ||  $msg_type == MSG_ALARM)
2735                                {
2736                                        print_debug('Msg Type',$msg_type);
2737                                        print_debug('UserID',$userid);
2738
2739                                        $preferences = CreateObject('phpgwapi.preferences',$userid);
2740                                        $part_prefs = $preferences->read_repository();
2741
2742                                        if (!$this->update_requested($userid,$part_prefs,$msg_type,$old_event,$new_event))
2743                                        {
2744                                                continue;
2745                                        }
2746                                        $GLOBALS['phpgw']->accounts->get_account_name($userid,$lid,$details['to-firstname'],$details['to-lastname']);
2747                                        $details['to-fullname'] = $GLOBALS['phpgw']->common->display_fullname('',$details['to-firstname'],$details['to-lastname']);
2748
2749                                        $to = $preferences->email_address($userid);
2750                                       
2751                                        if (empty($to) || $to[0] == '@' || $to[0] == '$')       // we have no valid email-address
2752                                        {
2753                                                //echo "<p>bocalendar::send_update: Empty email adress for user '".$details['to-fullname']."' ==> ignored !!!</p>\n";
2754                                                continue;
2755                                        }
2756                                        print_debug('Email being sent to',$to);
2757
2758                                        $GLOBALS['phpgw_info']['user']['preferences']['common']['tz_offset'] = $part_prefs['common']['tz_offset'];
2759                                        $GLOBALS['phpgw_info']['user']['preferences']['common']['timeformat'] = $part_prefs['common']['timeformat'];
2760                                        $GLOBALS['phpgw_info']['user']['preferences']['common']['dateformat'] = $part_prefs['common']['dateformat'];
2761
2762                                        $GLOBALS['phpgw']->datetime->tz_offset = ((60 * 60) * (int)$GLOBALS['phpgw_info']['user']['preferences']['common']['tz_offset']);
2763
2764                                        if($old_starttime)
2765                                        {
2766                                                $details['olddate'] = $GLOBALS['phpgw']->common->show_date($old_starttime);
2767                                        }
2768                                        $details['startdate'] = $GLOBALS['phpgw']->common->show_date($starttime);
2769                                        $details['enddate']   = $GLOBALS['phpgw']->common->show_date($endtime);
2770                                       
2771                                       
2772                                        list($subject,$body1) = split("\n",$GLOBALS['phpgw']->preferences->parse_notify($notify_msg,$details),2);
2773                                       
2774                                        switch($part_prefs['calendar']['update_format'])
2775                                        {
2776                                                case  'extended':
2777                                                        //$body .= "\n\n".lang('Event Details follow').":\n";
2778                                                        $body = '';
2779                                                        $body .= "<br>".lang('Event Details follow')." :: ";
2780                                                        foreach($event_arr as $key => $val)
2781                                                        {
2782                                                                // titulo
2783                                                                if($key =='title')
2784                                                                {
2785                                                                        $var1 = $val['field'];
2786                                                                        $vardata1 = $details[$key];
2787                                                                }
2788                                                                //descricao
2789                                                                if($key =='description')
2790                                                                {
2791                                                                        $var2 = $val['field'];
2792                                                                        $vardata2 = $details[$key];
2793                                                                }
2794                                                                //dt inicio
2795                                                                if($key =='startdate')
2796                                                                {
2797                                                                        switch(trim($part_prefs['common']['dateformat']))
2798                                                                        {
2799                                                                               
2800                                                                                case ($part_prefs['common']['dateformat'] === "m/d/Y" || $part_prefs['common']['dateformat'] === "m-d-Y" || $part_prefs['common']['dateformat'] === "m.d.Y"):
2801                                                                                        $var3 = $val['field'];
2802                                                                                        $vardata3 = $details[$key];
2803                                                                                        $newmounth3 = substr($vardata3,0,2);
2804                                                                                        $newday3 = substr($vardata3,3,2);
2805                                                                                        $newyear3 = substr($vardata3,6,4);
2806                                                                                        $newall3 =$newyear3.$newmounth3.$newday3;
2807                                                                                        break;
2808                                                                                       
2809                                                                                case    ($part_prefs['common']['dateformat'] === "Y/d/m" || $part_prefs['common']['dateformat'] === "Y-d-m" || $part_prefs['common']['dateformat'] === "Y.d.m"):
2810
2811                                                                                        $var3 = $val['field'];
2812                                                                                        $vardata3 = $details[$key];
2813                                                                                        $newyear3 = substr($vardata3,0,4);
2814                                                                                        $newday3 = substr($vardata3,5,2);
2815                                                                                        $newmounth3 = substr($vardata3,8,2);
2816                                                                                        $newall3 =$newyear3.$newmounth3.$newday3;
2817                                                                                        break;
2818
2819                                                                                case ($part_prefs['common']['dateformat'] === "Y/m/d" || $part_prefs['common']['dateformat'] === "Y-m-d" || $part_prefs['common']['dateformat'] === "Y.m.d"):
2820
2821                                                                                        $var3 = $val['field'];
2822                                                                                        $vardata3 = $details[$key];
2823                                                                                        $newyear3 = substr($vardata3,0,4);
2824                                                                                        $newmounth3 = substr($vardata3,5,2);
2825                                                                                        $newday3 = substr($vardata3,8,2);
2826                                                                                        $newall3 =$newyear3.$newmounth3.$newday3;
2827                                                                                        break;
2828
2829                                                                                case ($part_prefs['common']['dateformat'] === "d/m/Y" || $part_prefs['common']['dateformat'] === "d-m-Y" || $part_prefs['common']['dateformat'] === "d.m.Y" || $part_prefs['common']['dateformat'] === "d-M-Y"):
2830                                                                               
2831                                                                                        $var3 = $val['field'];
2832                                                                                        $vardata3 = $details[$key];
2833                                                                                        $newday3 = substr($vardata3,0,2);
2834                                                                                        $newmounth3 = substr($vardata3,3,2);
2835                                                                                        $newyear3 = substr($vardata3,6,4);
2836                                                                                        $newall3 =$newyear3.$newmounth3.$newday3;
2837                                                                                        break;
2838                                                                       
2839                                                                        }
2840                                                                       
2841                                                                }
2842                                                                //dt final
2843                                                                if($key =='enddate')
2844                                                                {
2845                                                                        $var4 = $val['field'];
2846                                                                        $vardata4 = $details[$key];
2847                                                                }
2848                                                                //localizacao
2849                                                                if($key =='location')
2850                                                                {
2851                                                                        $var8 = $val['field'];
2852                                                                        $vardata8 = $details[$key];
2853                                                                }
2854                                                                //participantes
2855                                                                if($key =='participants')
2856                                                                {
2857                                                                        $var5 = $val['field'];
2858                                                                        foreach($val['data'] as $NewKey => $NewVal)
2859                                                                        {
2860                                                                                //Research inside of ldap ( Pesquisa dentro do ldap )
2861                                                                                $newvalue = $this->so->search_uidNumber($to);
2862                                                                                foreach($newvalue as $tmp)
2863                                                                                {
2864                                                                                        $tmpmail = $tmp['mail'][0];
2865                                                                                        $tmpuid = $tmp['uidnumber'][0];
2866                                                                                        if( trim($tmpmail) == trim($to) & trim($tmpuid) == trim($NewKey))
2867                                                                                        {
2868                                                                                                        if($typesend == 3)
2869                                                                                                        {
2870
2871                                                                                                                $lang1 = lang("To See Commitment");
2872                                                                                                                $varbuttom = "<form action=".$GLOBALS['phpgw_info']['server']['webserver_url']."/index.php?menuaction=calendar.uicalendar.view&cal_id=$event[id]&date=$newall3' method='POST'>
2873                                                                                                                                                                  <input type='submit' value='$lang1'>
2874                                                                                                                                                                   </form>";
2875                                                                                                                $lang2 = lang("To accept");
2876                                                                                                                $varbuttom1 ="<input type='submit' value='$lang2' onClick='javascript:window.open(\"".$GLOBALS['phpgw_info']['server']['webserver_url']."/index.php?menuaction=calendar.uicalendar.set_action&cal_id=$event[id]&action=3&response=1\",\"frontpage\",\"height=100,width=400,statusbar=no,toolbar=no,scrollbars=no,menubar=no,left=300,top=200\")'>";
2877
2878                                                                                                                $lang3 = lang("To reject");
2879                                                                                                                $varbuttom2 ="<input type='submit' value='$lang3' onClick='javascript:window.open(\"".$GLOBALS['phpgw_info']['server']['webserver_url']."/index.php?menuaction=calendar.uicalendar.set_action&cal_id=$event[id]&action=0&response=0\",\"frontpage\",\"height=100,width=400,statusbar=no,toolbar=no,scrollbars=no,menubar=no,left=300,top=200\")'>";
2880                                                                                                               
2881                                                                                                                $lang4 = lang("Alarm");
2882                                                                                                                $varbuttom3 = "<form action=".$GLOBALS['phpgw_info']['server']['webserver_url']."/index.php?menuaction=calendar.uialarm.manager method='POST'>
2883                                                                                                                                                                  <input type='submit' value='$lang4'>
2884                                                                                                                                                                  <input type='hidden' name='cal_id' value=$event[id]>
2885                                                                                                                                                                   </form>";
2886                                                                                                        }
2887                                                                                                        else
2888                                                                                                        {
2889                                                                                                                        $varbuttom  = "";
2890                                                                                                                        $varbuttom1 = "";
2891                                                                                                                        $varbuttom2 = "";
2892                                                                                                                        $varbuttom3 = "";
2893                                                                                                        }
2894                                                                                        }
2895                                                                                        // It only mounts variavel with the name of the participants of the list ( Monta a variavel somente com o nome dos participantes da lista)
2896                                                                                        if($typesend == 3)
2897                                                                                        {
2898                                                                                                list($tmpvardata5,$tmp2vardata5) = explode("(",$NewVal);
2899                                                                                                $vardata5 = $tmpvardata5."<br>";
2900                                                                                        }
2901                                                                                        else
2902                                                                                        {
2903                                                                                                $vardata5 = $NewVal."<br>";
2904                                                                                        }
2905                                                                               
2906                                                                                }
2907                                                                                $vardata6 .= $vardata5;
2908                                                                                unset($vardata5);
2909                                                                        }
2910                                                                }               
2911                                                        }
2912                                                        //To mount the message as text/html (Para montar a mensagem como text/html - /phpgwapi/inc/class.send.inc.php )
2913                                                        $content_type = "text/html";
2914                                                        //It mounts the body of the message (Monta o corpo da mensagem)
2915                                                       
2916                                                        // A constante PHPGW_APP_TPL nao existe para envio de alarmes (cront, asyncservice).
2917                                                        define ("PHPGW_APP_TPL",PHPGW_API_INC . "/../../calendar/templates/celepar");
2918                                                       
2919                                                        $body = CreateObject('phpgwapi.Template',PHPGW_APP_TPL);
2920                                                        $body->set_file(Array('calendar' => 'body_email.tpl'));
2921                                                        $body->set_block('calendar','list');
2922                                                        $var = Array(
2923                                                                'script'                        => $script,
2924                                                                'subject'                       => $body1,
2925                                                                'var1'                          => $var1,
2926                                                                'vardata1'                      => $vardata1,
2927                                                                'var2'                          => $var2,
2928                                                                'vardata2'                      => $vardata2,
2929                                                                'var3'                          => $var3,
2930                                                                'vardata3'                      => $vardata3,
2931                                                                'var4'                          => $var4,
2932                                                                'vardata4'                      => $vardata4,
2933                                                                'var5'                          => $var5,
2934                                                                'vardata6'                      => $vardata6,
2935                                                                'var8'                          => $var8,
2936                                                                'vardata8'                      => $vardata8,                                                   
2937                                                                'varbuttom'                     => $varbuttom,
2938                                                                'varbuttom1'            => $varbuttom1,
2939                                                                'varbuttom2'            => $varbuttom2,
2940                                                                'varbuttom3'            => $varbuttom3
2941                                                               
2942                                                        );
2943                                                        $body->set_var($var);
2944                                                        $tmpbody = $body->fp('out','list');
2945                                                                                                               
2946                                                        break;
2947
2948                                                case 'ical':
2949                                                        $content_type = "calendar; method=$method; name=calendar.ics";
2950/*                                                      if ($body != '')
2951                                                        {
2952                                                                $boundary = '----Message-Boundary';
2953                                                                $body .= "\n\n\n$boundary\nContent-type: text/$content_type\n".
2954                                                                        "Content-Disposition: inline\nContent-transfer-encoding: 7BIT\n\n";
2955                                                                $content_type = '';
2956                                                        }
2957*/
2958                                                        $body = ExecMethod('calendar.boicalendar.export',array(
2959                                                                'l_event_id'  => $event['id'],
2960                                                                'method'      => $method,
2961                                                                'chunk_split' => False
2962                                                        ));
2963                                                        break;
2964                                        }
2965                                        $mail->AddAddress($to);
2966                                        $mail->Body = $tmpbody;
2967                                        $mail->From = $sender;
2968                                        $mail->FromName = $GLOBALS['phpgw_info']['user']['fullname'];
2969                                        $mail->Sender = $mail->From;
2970                                        $mail->SenderName = $mail->FromName;
2971                                        $mail->Subject = $subject;
2972                                       
2973                                       
2974                                        //It sends email for the participants ( Envia email para os participantes)
2975                                        if(!$mail->Send())
2976                                        {
2977                                               
2978                                                $returncode=false;
2979                                        }
2980                                        else
2981                                        {
2982                                                $returncode=true;
2983                                        }
2984                                                               
2985                                        //$returncode = $send->msg('email',$to,$subject,$tmpbody,''/*$msgtype*/,'','','',$sender, $content_type/*,$boundary*/);
2986
2987                               
2988                                        unset($vardata5);
2989                                        unset($vardata6);
2990                                        if (!$returncode)       // not nice, but better than failing silently
2991                                        {
2992                                                echo '<p><b>bocalendar::send_update</b>: '.lang("Failed sending message to '%1' #%2 subject='%3', sender='%4' !!!",$to,$userid,htmlspecialchars($subject), $sender)."<br>\n";
2993                                                echo '<i>'.$mail->ErrorInfo."</i><br>\n";
2994                                                echo lang('This is mostly caused by a not or wrongly configured SMTP server. Notify your administrator.')."</p>\n";
2995                                                echo '<p>'.lang('Click %1here%2 to return to the calendar.','<a href="'.$GLOBALS['phpgw']->link('/calendar/').'">','</a>')."</p>\n";
2996                                        }
2997                                }
2998                        }
2999                        if(count($to_notify) && $this->ex_participants){
3000                                $var = explode(",",trim($this->ex_participants));
3001                                $to = array();
3002                                if(!$subject) {
3003                                        $details['startdate'] = $GLOBALS['phpgw']->common->show_date($starttime);
3004                                        $details['enddate']   = $GLOBALS['phpgw']->common->show_date($endtime);
3005                                        list($subject,$body1) = split("\n",$GLOBALS['phpgw']->preferences->parse_notify($notify_msg,$details),2);
3006                                }
3007                                foreach($var as $index => $ex_participant){
3008                                        $ex_participant = trim($ex_participant);
3009                                        $ex_participant = preg_replace('#"(.*)" <(.*)\@(.*)\.(.*)>#','\\2@\\3.\\4',$ex_participant);
3010                                                if($ex_participant)
3011                                                        $to[] = $ex_participant;
3012                                }               
3013                                foreach($to as $i => $to_array)
3014                                        $mail->AddAddress($to_array);
3015                                $_body = explode("<hr size='1' width='100%'>",$tmpbody);
3016                                $tmpbody = $_body[0];
3017                                $tmpbody.= "<b>".lang("external participants").":: </b> ".htmlentities($this->ex_participants);
3018                                $tmpbody.= "<br>".lang("Summary").": ".$this->so->cal->event[title]."<br>";
3019                                $tmpbody.= "<br>".lang("Start time").": ".$GLOBALS['phpgw']->common->show_date($starttime)."<br>".lang("End date").": ".$GLOBALS['phpgw']->common->show_date($endtime)."<br>";
3020                                $tmpbody.= "<br><br><hr size='1' width='100%'><font color='red'>"
3021                                .lang("This message was sent by server. You must send a message to sender to confirm this event")."<br>"
3022                                .lang("This is an external event. Even if it added to your expresso its can be changed any time at all")."</font><br>";
3023                               
3024                                if ($GLOBALS['bocalendar']->so->cal->event[start][month] > 10)
3025                                        $event_month=$GLOBALS['bocalendar']->so->cal->event[start][month];
3026                                else
3027                                        $event_month="0".$GLOBALS['bocalendar']->so->cal->event[start][month];
3028                                $tmpbody .="<a href='../index.php?menuaction=calendar.uicalendar.add&date="
3029                                .$GLOBALS['bocalendar']->so->cal->event[start][year]
3030                                .$event_month
3031                                .$GLOBALS['bocalendar']->so->cal->event[start][mday]
3032                                ."&hour=".$GLOBALS['bocalendar']->so->cal->event[start][hour]
3033                                ."&minute=".$GLOBALS['bocalendar']->so->cal->event[start][min]
3034                                ."&title=".$GLOBALS['bocalendar']->so->cal->event['title']
3035                                ."&description=".$GLOBALS['bocalendar']->so->cal->event['description']
3036                                ."&location=".$GLOBALS['bocalendar']->so->cal->event['location']."'>"
3037                                ."<h2>".lang("Add to my expresso")."</h2>";
3038                               
3039                                //attach extern vcard                   
3040                                // define('context','$GLOBALS.bocalendar.so.cal.event');
3041                                $tmpattach = $this->create_vcard($GLOBALS['bocalendar']->so->cal->event);
3042                                $tempdir = $GLOBALS['phpgw_info']['server']['temp_dir'] . SEP;
3043                                srand((double)microtime()*1000000);
3044                                $random_number = rand(100000000,999999999);
3045                                $newfilename = md5(time() . getenv("REMOTE_ADDR") . $random_number );
3046                                $filename = $tempdir . $newfilename;
3047                                $attach_fd = fopen($filename,"w+");
3048                                fwrite($attach_fd,$tmpattach);
3049                                $mail->AddAttachment($filename, "extern.vcard", "base64", "text/plain"); // "application/octet-stream"
3050                                fclose($attach_fd);
3051                                $mail->From = $sender;
3052                                $mail->FromName = $GLOBALS['phpgw_info']['user']['fullname'];
3053                                $mail->Sender = $mail->From;
3054                                $mail->SenderName = $mail->FromName;
3055                                $mail->Subject = lang("External event from Expresso");
3056                                $mail->Body = $tmpbody;
3057                               
3058                                if(!$mail->Send())
3059                                {
3060                                        $returncode=false;
3061                                }
3062                                else
3063                                {
3064                                        $returncode=true;
3065                                }
3066                        }
3067
3068
3069                        if((is_int($this->user) && $this->user != $temp_user['account_id']) ||
3070                                (is_string($this->user) && $this->user != $temp_user['account_lid']))
3071                        {
3072                                $GLOBALS['phpgw_info']['user'] = $temp_user;
3073                        }
3074
3075                        $GLOBALS['phpgw_info']['user']['preferences']['common']['tz_offset'] = $temp_tz_offset;
3076                        $GLBOALS['phpgw']->datetime->tz_offset = ((60 * 60) * $temp_tz_offset);
3077                        $GLOBALS['phpgw_info']['user']['preferences']['common']['timeformat'] = $temp_timeformat;
3078                        $GLOBALS['phpgw_info']['user']['preferences']['common']['dateformat'] = $temp_dateformat;
3079
3080                        return $returncode;
3081                }
3082
3083                function send_alarm($alarm)
3084                {
3085                        //echo "<p>bocalendar::send_alarm("; print_r($alarm); echo ")</p>\n";
3086                        $GLOBALS['phpgw_info']['user']['account_id'] = $this->owner = $alarm['owner'];
3087
3088                        if (!$alarm['enabled'] || !$alarm['owner'] || !$alarm['cal_id'] || !($event = $this->so->read_entry($alarm['cal_id'])))
3089                        {
3090                                return False;   // event not found
3091                        }
3092                        if ($alarm['all'])
3093                        {
3094                                $to_notify = $event['participants'];
3095                        }
3096                        elseif ($this->check_perms(PHPGW_ACL_READ,$event))      // checks agains $this->owner set to $alarm[owner]
3097                        {
3098                                $to_notify[$alarm['owner']] = 'A';
3099                        }
3100                        else
3101                        {
3102                                return False;   // no rights
3103                        }
3104                        return $this->send_update(MSG_ALARM,$to_notify,$event,False,$alarm['owner']);
3105                }
3106
3107                function get_alarms($event_id)
3108                {
3109                        return $this->so->get_alarm($event_id);
3110                }
3111
3112                function alarm_today($event,$today,$starttime)
3113                {
3114                        $found = False;
3115                        @reset($event['alarm']);
3116                        $starttime_hi = $GLOBALS['phpgw']->common->show_date($starttime,'Hi');
3117                        $t_appt['month'] =$GLOBALS['phpgw']->common->show_date($today,'m');
3118                        $t_appt['mday'] = $GLOBALS['phpgw']->common->show_date($today,'d');
3119                        $t_appt['year'] = $GLOBALS['phpgw']->common->show_date($today,'Y');
3120                        $t_appt['hour'] = $GLOBALS['phpgw']->common->show_date($starttime,'H');
3121                        $t_appt['min']  = $GLOBALS['phpgw']->common->show_date($starttime,'i');
3122                        $t_appt['sec']  = 0;
3123                        $t_time = $this->maketime($t_appt) - $GLOBALS['phpgw']->datetime->tz_offset;
3124                        $y_time = $t_time - 86400;
3125                        $tt_time = $t_time + 86399;
3126                        print_debug('T_TIME',$t_time.' : '.$GLOBALS['phpgw']->common->show_date($t_time));
3127                        print_debug('Y_TIME',$y_time.' : '.$GLOBALS['phpgw']->common->show_date($y_time));
3128                        print_debug('TT_TIME',$tt_time.' : '.$GLOBALS['phpgw']->common->show_date($tt_time));
3129                        while(list($key,$alarm) = each($event['alarm']))
3130                        {
3131                                if($alarm['enabled'])
3132                                {
3133                                        print_debug('TIME',$alarm['time'].' : '.$GLOBALS['phpgw']->common->show_date($alarm['time']).' ('.$event['id'].')');
3134                                        if($event['recur_type'] != MCAL_RECUR_NONE)   /* Recurring Event */
3135                                        {
3136                                                print_debug('Recurring Event');
3137                                                if($alarm['time'] > $y_time && $GLOBALS['phpgw']->common->show_date($alarm['time'],'Hi') < $starttime_hi && $alarm['time'] < $t_time)
3138                                                {
3139                                                        $found = True;
3140                                                }
3141                                        }
3142                                        elseif($alarm['time'] > $y_time && $alarm['time'] < $t_time)
3143                                        {
3144                                                $found = True;
3145                                        }
3146                                }
3147                        }
3148                        print_debug('Found',$found);
3149                        return $found;
3150                }
3151
3152                function prepare_recipients(&$new_event,$old_event)
3153                {
3154                        // Find modified and deleted users.....
3155                        while(list($old_userid,$old_status) = each($old_event['participants']))
3156                        {
3157                                if(isset($new_event['participants'][$old_userid]))
3158                                {
3159                                        print_debug('Modifying event for user',$old_userid);
3160                                        $this->modified[(int)$old_userid] = $new_status;
3161                                }
3162                                else
3163                                {
3164                                        print_debug('Deleting user from the event',$old_userid);
3165                                        $this->deleted[(int)$old_userid] = $old_status;
3166                                }
3167                        }
3168                        // Find new users.....
3169                        while(list($new_userid,$new_status) = each($new_event['participants']))
3170                        {
3171                                if(!isset($old_event['participants'][$new_userid]))
3172                                {
3173                                        print_debug('Adding event for user',$new_userid);
3174                                        $this->added[$new_userid] = 'U';
3175                                        $new_event['participants'][$new_userid] = 'U';
3176                                }
3177                        }
3178
3179                        if(count($this->added) > 0 || count($this->modified) > 0 || count($this->deleted) > 0)
3180                        {
3181                                if(count($this->added) > 0)
3182                                {
3183                                        $this->send_update(MSG_ADDED,$this->added,'',$new_event);
3184                                }
3185                                if(count($this->modified) > 0)
3186                                {
3187                                        $this->send_update(MSG_MODIFIED,$this->modified,$old_event,$new_event);
3188                                }
3189                                if(count($this->deleted) > 0)
3190                                {
3191                                        $this->send_update(MSG_DELETED,$this->deleted,$old_event);
3192                                }
3193                        }
3194                }
3195
3196                function remove_doubles_in_cache($firstday,$lastday)
3197                {
3198                        $already_moved = Array();
3199                        for($v=$firstday;$v<=$lastday;$v++)
3200                        {
3201                                if (!$this->cached_events[$v])
3202                                {
3203                                        continue;
3204                                }
3205                                $cached = $this->cached_events[$v];
3206                                $this->cached_events[$v] = array();
3207                                while (list($g,$event) = each($cached))
3208                                {
3209                                        $end = date('Ymd',$this->maketime($event['end']));
3210                                        print_debug('EVENT',_debug_array($event,False));
3211                                        print_debug('start',$start);
3212                                        print_debug('v',$v);
3213
3214                                        if (!isset($already_moved[$event['id']]) || $event['recur_type'] && $v > $end)
3215                                        {
3216                                                $this->cached_events[$v][] = $event;
3217                                                $already_moved[$event['id']] = 1;
3218                                                print_debug('Event moved');
3219                                        }
3220                                }
3221                        }
3222                }
3223
3224                function get_dirty_entries($lastmod=-1)
3225                {
3226                        $events = false;
3227                        $event_ids = $this->so->cal->list_dirty_events($lastmod);
3228                        if(is_array($event_ids))
3229                        {
3230                                foreach($event_ids as $key => $id)
3231                                {
3232                                        $events[$id] = $this->so->cal->fetch_event($id);
3233                                }
3234                        }
3235                        unset($event_ids);
3236
3237                        $rep_event_ids = $this->so->cal->list_dirty_events($lastmod,$true);
3238                        if(is_array($rep_event_ids))
3239                        {
3240                                foreach($rep_event_ids as $key => $id)
3241                                {
3242                                        $events[$id] = $this->so->cal->fetch_event($id);
3243                                }
3244                        }
3245                        unset($rep_event_ids);
3246
3247                        return $events;
3248                }
3249
3250                function _debug_array($data)
3251                {
3252                        echo '<br>UI:';
3253                        _debug_array($data);
3254                }
3255
3256                /*!
3257                @function rejected_no_show
3258                @abstract checks if event is rejected from user and he's not the owner and dont want rejected
3259                @param $event to check
3260                @returns True if event should not be shown
3261                */
3262                function rejected_no_show($event)
3263                {
3264                        $ret = !$this->prefs['calendar']['show_rejected'] &&
3265                                $event['owner'] != $this->owner &&
3266                                $event['participants'][$this->owner] == 'R';
3267                        //echo "<p>rejected_no_show($event[title])='$ret': user=$this->owner, event-owner=$event[owner], status='".$event['participants'][$this->owner]."', show_rejected='".$this->prefs['calendar']['show_rejected']."'</p>\n";
3268                        return $ret;
3269                }
3270
3271                /* This is called only by list_cals().  It was moved here to remove fatal error in php5 beta4 */
3272                function list_cals_add($id,&$users,&$groups)
3273                {
3274                        $name = $GLOBALS['phpgw']->common->grab_owner_name($id);
3275                        if (($type = $GLOBALS['phpgw']->accounts->get_type($id)) == 'g')
3276                        {
3277                                $arr = &$groups;
3278                        }
3279                        else
3280                        {
3281                                $arr = &$users;
3282                        }
3283                        $arr[$name] = Array(
3284                                'grantor' => $id,
3285                                'value'   => ($type == 'g' ? 'g_' : '') . $id,
3286                                'name'    => $name
3287                        );
3288                }
3289
3290                /*!
3291                @function list_cals
3292                @abstract generate list of user- / group-calendars for the selectbox in the header
3293                @returns alphabeticaly sorted array with groups first and then users
3294                */
3295                function list_cals()
3296                {
3297                        $users = $groups = array();
3298                        foreach($this->grants as $id => $rights)
3299                        {
3300                                $this->list_cals_add($id,$users,$groups);
3301                        }
3302                       
3303                        //by JakJr, melhora de performance na abertura da agenda
3304                        /*if ($memberships = $GLOBALS['phpgw']->accounts->membership($GLOBALS['phpgw_info']['user']['account_id']))
3305                        {
3306                                foreach($memberships as $group_info)
3307                                {
3308                                        $this->list_cals_add($group_info['account_id'],$users,$groups);
3309
3310                                        if ($account_perms = $GLOBALS['phpgw']->acl->get_ids_for_location($group_info['account_id'],PHPGW_ACL_READ,'calendar'))
3311                                        {
3312                                                foreach($account_perms as $id)
3313                                                {
3314                                                        $this->list_cals_add($id,$users,$groups);
3315                                                }
3316                                        }
3317                                }
3318                        }*/
3319                        uksort($users,'strnatcasecmp');
3320                        uksort($groups,'strnatcasecmp');
3321
3322                        return $users + $groups;        // users first and then groups, both alphabeticaly
3323                }
3324
3325                /*!
3326                @function event2array
3327                @abstract create array with name, translated name and readable content of each attributes of an event
3328                @syntax event2array($event,$sep='<br>')
3329                @param $event event to use
3330                @returns array of attributes with fieldname as key and array with the 'field'=translated name \
3331                        'data' = readable content (for participants this is an array !)
3332                */
3333                function event2array($event)
3334                {
3335                        $var['title'] = Array(
3336                                'field'         => lang('Title'),
3337                                'data'          => $event['title']
3338                        );
3339
3340                        // Some browser add a \n when its entered in the database. Not a big deal
3341                        // this will be printed even though its not needed.
3342                        $var['description'] = Array(
3343                                'field' => lang('Description'),
3344                                'data'  => $event['description']
3345                        );
3346
3347                        $var['ex_participants'] = Array(
3348                                'field' => lang('External Participants'),
3349                                'data'  => $event['ex_participants']
3350                        );
3351
3352                        $cats = Array();
3353                        $this->cat->categories($this->bo->owner,'calendar');
3354                        if(strpos($event['category'],','))
3355                        {
3356                                $cats = explode(',',$event['category']);
3357                        }
3358                        else
3359                        {
3360                                $cats[] = $event['category'];
3361                        }
3362                        foreach($cats as $cat_id)
3363                        {
3364                                list($cat) = $this->cat->return_single($cat_id);
3365                                $cat_string[] = $cat['name'];
3366                        }
3367                        $var['category'] = Array(
3368                                'field' => lang('Category'),
3369                                'data'  => implode(', ',$cat_string)
3370                        );
3371
3372                        $var['location'] = Array(
3373                                'field' => lang('Location'),
3374                                'data'  => $event['location']
3375                        );
3376
3377                        $var['startdate'] = Array(
3378                                'field' => lang('Start Date/Time'),
3379                                'data'  => $GLOBALS['phpgw']->common->show_date($this->maketime($event['start']) - $GLOBALS['phpgw']->datetime->tz_offset),
3380                        );
3381
3382                        $var['enddate'] = Array(
3383                                'field' => lang('End Date/Time'),
3384                                'data'  => $GLOBALS['phpgw']->common->show_date($this->maketime($event['end']) - $GLOBALS['phpgw']->datetime->tz_offset)
3385                        );
3386
3387                        $pri = Array(
3388                                1       => lang('Low'),
3389                                2       => lang('Normal'),
3390                                3       => lang('High')
3391                        );
3392                        $var['priority'] = Array(
3393                                'field' => lang('Priority'),
3394                                'data'  => $pri[$event['priority']]
3395                        );
3396
3397                        $var['owner'] = Array(
3398                                'field' => lang('Created By'),
3399                                'data'  => $GLOBALS['phpgw']->common->grab_owner_name($event['owner'])
3400                        );
3401
3402                        $var['updated'] = Array(
3403                                'field' => lang('Updated'),
3404                                'data'  => $GLOBALS['phpgw']->common->show_date($this->maketime($event['modtime']) - $GLOBALS['phpgw']->datetime->tz_offset)
3405                        );
3406
3407                        $var['access'] = Array(
3408                                'field' => lang('Access'),
3409                                'data'  => $event['public'] ? lang('Public') : lang('Private')
3410                        );
3411
3412                        if(@isset($event['groups'][0]))
3413                        {
3414                                $cal_grps = '';
3415                                for($i=0;$i<count($event['groups']);$i++)
3416                                {
3417                                        if($GLOBALS['phpgw']->accounts->exists($event['groups'][$i]))
3418                                        {
3419                                                $cal_grps .= ($i>0?'<br>':'').$GLOBALS['phpgw']->accounts->id2name($event['groups'][$i]);
3420                                        }
3421                                }
3422
3423                                $var['groups'] = Array(
3424                                        'field' => lang('Groups'),
3425                                        'data'  => $cal_grps
3426                                );
3427                        }
3428
3429                        $participants = array();
3430                        foreach($event['participants'] as $user => $short_status)
3431                        {
3432                                if($GLOBALS['phpgw']->accounts->exists($user))
3433                                {
3434                                        $participants[$user] = $GLOBALS['phpgw']->common->grab_owner_name($user).' ('.$this->get_long_status($short_status).')';
3435                                }
3436                        }
3437                        $var['participants'] = Array(
3438                                'field' => lang('Participants'),
3439                                'data'  => $participants
3440                        );
3441
3442                        // Repeated Events
3443                        if($event['recur_type'] != MCAL_RECUR_NONE)
3444                        {
3445                                $str = lang($this->rpt_type[$event['recur_type']]);
3446
3447                                $str_extra = array();
3448                                if ($event['recur_enddate']['mday'] != 0 && $event['recur_enddate']['month'] != 0 && $event['recur_enddate']['year'] != 0)
3449                                {
3450                                        $recur_end = $this->maketime($event['recur_enddate']);
3451                                        if($recur_end != 0)
3452                                        {
3453                                                $recur_end -= $GLOBALS['phpgw']->datetime->tz_offset;
3454                                                $str_extra[] = lang('ends').': '.lang($GLOBALS['phpgw']->common->show_date($recur_end,'l')).', '.$this->long_date($recur_end).' ';
3455                                        }
3456                                }
3457                                // only weekly uses the recur-data (days) !!!
3458                                if($event['recur_type'] == MCAL_RECUR_WEEKLY)
3459                                {
3460                                        $repeat_days = array();
3461                                        foreach ($this->rpt_day as $mcal_mask => $dayname)
3462                                        {
3463                                                if ($event['recur_data'] & $mcal_mask)
3464                                                {
3465                                                        $repeat_days[] = lang($dayname);
3466                                                }
3467                                        }
3468                                        if(count($repeat_days))
3469                                        {
3470                                                $str_extra[] = lang('days repeated').': '.implode(', ',$repeat_days);
3471                                        }
3472                                }
3473                                if($event['recur_interval'] != 0)
3474                                {
3475                                        $str_extra[] = lang('Interval').': '.$event['recur_interval'];
3476                                }
3477
3478                                if(count($str_extra))
3479                                {
3480                                        $str .= ' ('.implode(', ',$str_extra).')';
3481                                }
3482
3483                                $var['recure_type'] = Array(
3484                                        'field' => lang('Repetition'),
3485                                        'data'  => $str,
3486                                );
3487                        }
3488
3489                        if (!isset($this->fields))
3490                        {
3491                                $this->custom_fields = CreateObject('calendar.bocustom_fields');
3492                                $this->fields = &$this->custom_fields->fields;
3493                                $this->stock_fields = &$this->custom_fields->stock_fields;
3494                        }
3495                        foreach($this->fields as $field => $data)
3496                        {
3497                                if (!$data['disabled'])
3498                                {
3499                                        if (isset($var[$field]))
3500                                        {
3501                                                $sorted[$field] = $var[$field];
3502                                        }
3503                                        elseif (!isset($this->stock_fields[$field]) && strlen($event[$field]))  // Custom field
3504                                        {
3505                                                $lang = lang($name = substr($field,1));
3506                                                $sorted[$field] = array(
3507                                                        'field' => $lang == $name.'*' ? $name : $lang,
3508                                                        'data'  => $event[$field]
3509                                                );
3510                                        }
3511                                }
3512                                unset($var[$field]);
3513                        }
3514                        foreach($var as $name => $v)
3515                        {
3516                                $sorted[$name] = $v;
3517
3518                        }
3519                        return $sorted;
3520                }
3521
3522                /*!
3523                @function check_set_default_prefs
3524                @abstract sets the default prefs, if they are not already set (on a per pref. basis)
3525                @note It sets a flag in the app-session-data to be called only once per session
3526                */
3527                function check_set_default_prefs()
3528                {
3529                        if (($set = $GLOBALS['phpgw']->session->appsession('default_prefs_set','calendar')))
3530                        {
3531                                return;
3532                        }
3533                        $GLOBALS['phpgw']->session->appsession('default_prefs_set','calendar','set');
3534
3535                        //$default_prefs = $GLOBALS['phpgw']->preferences->default['calendar']; jakjr
3536
3537                        $subject = lang('Calendar Event') . ' - $$action$$: $$startdate$$ $$title$$'."\n";
3538                        $defaults = array(
3539                                'defaultcalendar' => 'week',
3540                                'mainscreen_showevents' => '0',
3541                                'summary'         => 'no',
3542                                'receive_updates' => 'no',
3543                                'update_format'   => 'extended',        // leave it to extended for now, as iCal kills the message-body
3544                                'notifyAdded'     => $subject . lang ('You have a meeting scheduled for %1','$$startdate$$'),
3545                                'notifyCanceled'  => $subject . lang ('Your meeting scheduled for %1 has been canceled','$$startdate$$'),
3546                                'notifyModified'  => $subject . lang ('Your meeting that had been scheduled for %1 has been rescheduled to %2','$$olddate$$','$$startdate$$'),
3547                                'notifyResponse'  => $subject . lang ('On %1 %2 %3 your meeting request for %4','$$date$$','$$fullname$$','$$action$$','$$startdate$$'),
3548                                'notifyAlarm'     => lang('Alarm for %1 at %2 in %3','$$title$$','$$startdate$$','$$location$$')."\n".lang ('Here is your requested alarm.'),
3549                                'show_rejected'   => '0',
3550                                'display_status'  => '1',
3551                                'weekdaystarts'   => 'Monday',
3552                                'workdaystarts'   => '9',
3553                                'workdayends'     => '17',
3554                                'interval'        => '30',
3555                                'defaultlength'   => '60',
3556                                'planner_start_with_group' => $GLOBALS['phpgw']->accounts->name2id('Default'),
3557                                'planner_intervals_per_day'=> '4',
3558                                'defaultfilter'   => 'all',
3559                                'default_private' => '0',
3560                                'display_minicals'=> '1',
3561                                'print_black_white'=>'0'
3562                        );
3563                        foreach($defaults as $var => $default)
3564                        {
3565                                if (!isset($default_prefs[$var]) || $default_prefs[$var] == '')
3566                                {
3567                                        $GLOBALS['phpgw']->preferences->add('calendar',$var,$default,'default');
3568                                        $need_save = True;
3569                                }
3570                        }
3571                        if ($need_save)
3572                        {
3573                                $prefs = $GLOBALS['phpgw']->preferences->save_repository(False,'default');
3574                                $this->prefs['calendar'] = $prefs['calendar'];
3575                        }
3576                        if ($this->prefs['calendar']['send_updates'] && !isset($this->prefs['calendar']['receive_updates']))
3577                        {
3578                                $this->prefs['calendar']['receive_updates'] = $this->prefs['calendar']['send_updates'];
3579                                $GLOBALS['phpgw']->preferences->add('calendar','receive_updates',$this->prefs['calendar']['send_updates']);
3580                                $GLOBALS['phpgw']->preferences->delete('calendar','send_updates');
3581                                $prefs = $GLOBALS['phpgw']->preferences->save_repository();
3582                        }
3583                }
3584
3585                // return array with all infolog categories (for xmlrpc)
3586                function categories($complete = False)
3587                {
3588                        return $GLOBALS['server']->categories($complete);
3589                }
3590        }
3591?>
Note: See TracBrowser for help on using the repository browser.