calendar_hooks::notifications_actions()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 18
nc 2
nop 1
dl 0
loc 23
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * eGroupWare - Calendar hooks
4
 *
5
 * @link http://www.egroupware.org
6
 * @package calendar
7
 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
8
 * @copyright (c) 2004-16 by RalfBecker-At-outdoor-training.de
9
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10
 * @version $Id$
11
 */
12
13
use EGroupware\Api;
14
use EGroupware\Api\Link;
15
use EGroupware\Api\Egw;
16
use EGroupware\Api\Acl;
17
18
/**
19
 * diverse static calendar hooks
20
 */
21
class calendar_hooks
22
{
23
	/**
24
	 * Hook called by link-class to include calendar in the appregistry of the linkage
25
	 *
26
	 * @param array|string $location location and other parameters (not used)
27
	 * @return array with method-names
28
	 */
29
	static function search_link($location)
30
	{
31
		unset($location);	// not used, but in function signature for hooks
32
		return array(
33
			'query' => 'calendar.calendar_bo.link_query',
34
			'title' => 'calendar.calendar_bo.link_title',
35
			'view'  => array(
36
				'menuaction' => 'calendar.calendar_uiforms.edit',
37
			),
38
			'view_id'    => 'cal_id',
39
			'view_popup' => '850x590',
40
			'edit_popup' => '850x590',
41
			'list'  => array(
42
				'menuaction' => 'calendar.calendar_uiviews.index',
43
				'view' => 'listview',
44
				'ajax'=>'true'
45
			),
46
			// If calendar is not loaded, load it first, then add
47
			'add'        => 'javascript:var promise = framework.setActiveApp(framework.getApplicationByName(\'calendar\')); if(promise) {promise.then(function() {et2_call(\'app.calendar.add\',params);});} else { app.calendar.add(params);}',
48
			'add_app'    => 'link_app',
49
			'add_id'     => 'link_id',
50
			'file_access' => 'calendar.calendar_bo.file_access',
51
			'file_access_user' => true,	// file_access supports 4th parameter $user
52
			'mime' => array(
53
				'text/calendar' => array(
54
					'menuaction' => 'calendar.calendar_uiforms.edit',
55
					'mime_data' => 'ical_data',
56
					'mime_url' => 'ical_url',
57
					'mime_popup' => '850x590',
58
					'mime_target' => '_blank'
59
				),
60
				'application/ics' => array(
61
					'menuaction' => 'calendar.calendar_uiforms.edit',
62
					'mime_data' => 'ical_data',
63
					'mime_url' => 'ical_url',
64
					'mime_popup' => '850x590',
65
					'mime_target' => '_blank'
66
				),
67
			),
68
			'merge' => true,
69
			'entry' => 'Event',
70
			'entries' => 'Events',
71
		);
72
	}
73
74
	/**
75
	 * Hook called to retrieve a app specific exportLimit
76
	 *
77
	 * @param array|string $location location and other parameters (not used)
78
	 * @return the export_limit to be applied for the app, may be empty, int or string
79
	 */
80
	static function getAppExportLimit($location)
81
	{
82
		unset($location);	// not used, but in function signature for hooks
83
		return $GLOBALS['egw_info']['server']['calendar_export_limit'];
84
	}
85
86
	/**
87
	 * Entries for calendar's admin menu
88
	 */
89
	static function admin()
90
	{
91
		$file = Array(
92
			'Site Configuration' => Egw::link('/index.php','menuaction=admin.admin_config.index&appname=calendar&ajax=true'),
93
			'Custom fields' => Egw::link('/index.php','menuaction=admin.admin_customfields.index&appname=calendar&ajax=true'),
94
			'Global Categories' => Egw::link('/index.php','menuaction=admin.admin_categories.index&appname=calendar&ajax=true'),
95
			'Category ACL' => Egw::link('/index.php','menuaction=calendar.calendar_uiforms.cat_acl'),
96
			'Update timezones' => Egw::link('/index.php','menuaction=calendar.calendar_timezones.update'),
97
		);
98
		display_section('calendar','calendar',$file);
99
	}
100
101
	/**
102
	 * Calendar preferences
103
	 *
104
	 * @param array $hook_data
105
	 */
106
	static function settings($hook_data)
107
	{
108
		if (!$hook_data['setup'])	// does not work on setup time
109
		{
110
			$bo = new calendar_bo();
111
			$bo->check_set_default_prefs();
112
		}
113
		$yesno = array(
114
			'1' => lang('Yes'),
115
			'0' => lang('No'),
116
		);
117
		$list_views = array(
118
			0 => lang('None'),
119
			'month' => lang('Monthview'),
120
			'weekN' => lang('Multiple week view'),
121
			'week' => lang('Weekview'),
122
			'day4' => lang('Four days view'),
123
			'day' => lang('Dayview'),
124
		);
125
		$updates = array(
126
			'no'             => lang('Never'),
127
			'add_cancel'     => lang('on invitation / cancellation only'),
128
			'time_change_4h' => lang('on time change of more than 4 hours too'),
129
			'time_change'    => lang('on any time change too'),
130
			'modifications'  => lang('on all modification, but responses'),
131
			'responses'      => lang('on participant responses too')
132
		);
133
		$update_formats = array(
134
			'none'     => lang('None'),
135
			'extended' => lang('Extended'),
136
			'ical'     => lang('iCal / rfc2445'),
137
		);
138
		$event_details = array(
139
			'to-fullname' => lang('Fullname of person to notify'),
140
			'to-firstname'=> lang('Firstname of person to notify'),
141
			'to-lastname' => lang('Lastname of person to notify'),
142
			'title'       => lang('Title of the event'),
143
			'description' => lang('Description'),
144
			'startdate'   => lang('Start Date/Time'),
145
			'enddate'     => lang('End Date/Time'),
146
			'olddate'     => lang('Old Startdate'),
147
			'category'    => lang('Category'),
148
			'location'    => lang('Location'),
149
			'priority'    => lang('Priority'),
150
			'participants'=> lang('Participants'),
151
			'owner'       => lang('Owner'),
152
			'repetition'  => lang('Repetitiondetails (or empty)'),
153
			'action'      => lang('Action that caused the notify: Added, Canceled, Accepted, Rejected, ...'),
154
			'link'        => lang('Link to view the event'),
155
			'disinvited'  => lang('Participants uninvited from an event'),
156
		);
157
		$weekdaystarts = array(
158
			'Monday'   => lang('Monday'),
159
			'Sunday'   => lang('Sunday'),
160
			'Saturday' => lang('Saturday')
161
		);
162
		$birthdays_as_events = array(
163
			'none'     => lang('None'),
164
			'birthday' => lang('Birthdays'),
165
			'holiday'  => lang('Holidays')
166
		);
167
168
		if (!isset($hook_data['setup']))
169
		{
170
			$times = Api\Etemplate\Widget\Select::typeOptions('select-hour', '');
171
			$default_cat_seloptions = Api\Etemplate\Widget\Select::typeOptions('select-cat', ',,,calendar');
172
		}
173
		for ($i = 2; $i <= 9; ++$i)
174
		{
175
			$muliple_weeks[$i] = lang('%1 weeks',$i);
0 ignored issues
show
Unused Code introduced by
The call to lang() has too many arguments starting with $i. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

175
			$muliple_weeks[$i] = /** @scrutinizer ignore-call */ lang('%1 weeks',$i);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
176
		}
177
178
		for ($i = 2; $i <= 20; $i++)
179
		{
180
			$consolidated[$i] = $i;
181
		}
182
		$intervals = array(
183
			5	=> '5',
184
			10	=> '10',
185
			15	=> '15',
186
			20	=> '20',
187
			30	=> '30',
188
			45	=> '45',
189
			60	=> '60'
190
		);
191
		$default_participants = array(
192
			0 => lang('Just me'),
193
			'selected' => lang('Selected users/groups')
194
		);
195
		$defaultresource_sel = array(
196
			'resources_conflict'    => lang('resources with conflict detection'),
197
			'resources_without_conflict'    => lang('resources except conflicting ones')
198
		);
199
		$reset_stati_on_shifts = array(
200
			'no'		=> lang('Never'),
201
			'all'		=> lang('Always'),
202
			'startday'	=> lang('If start day differs'),
203
		);
204
		$freebusy_values = array(
205
			0		=> lang('No'),
206
			1		=> lang('Yes'),
207
			2		=> lang('With credentials included'),
208
		);
209
		if (!$hook_data['setup'])	// does not work at setup time
210
		{
211
			$options = array('0' => lang('none'));
212
			foreach($GLOBALS['egw']->accounts->search(array('type' => 'owngroups','app' => 'calendar')) as $group)
213
			{
214
				$options[$group['account_id']] = Api\Accounts::username($group['account_id']);
215
			}
216
			$freebusy_url = calendar_bo::freebusy_url($GLOBALS['egw_info']['user']['account_lid'],$GLOBALS['egw_info']['user']['preferences']['calendar']['freebusy_pw']);
217
			$freebusy_url = '<a href="'.$freebusy_url.'" target="_blank">'.$freebusy_url.'</a>';
218
			$freebusy_help = lang('Should not loged in persons be able to see your freebusy information? You can set an extra password, different from your normal password, to protect this informations. The freebusy information is in iCal format and only include the times when you are busy. It does not include the event-name, description or locations. The URL to your freebusy information is');
219
			$freebusy_help .= ' ' . $freebusy_url;
220
221
			// Timezone for file exports
222
			$export_tzs = array('0' => lang('Use Event TZ'));
223
			$export_tzs += Api\DateTime::getTimezones();
224
		}
225
		$link_title_options = calendar_bo::get_link_options();
226
		$settings = array(
227
			'1.section' => array(
228
				'type'  => 'section',
229
				'title' => lang('General settings'),
230
				'no_lang'=> true,
231
				'xmlrpc' => False,
232
				'admin'  => False
233
			),
234
			/* disabled until we have a home app again
235
			'mainscreen_showevents' => array(
236
				'type'   => 'select',
237
				'label'  => 'Which view to show on home page',
238
				'name'   => 'mainscreen_showevents',
239
				'values' => $mainscreen,
240
				'help'   => 'Displays this calendar view on the home page (page you get when you enter EGroupware or click on the home page icon)?',
241
				'xmlrpc' => True,
242
				'admin'  => False,
243
				'default'=> '1',	// 1 = week
244
			),*/
245
			'multiple_weeks' => array(
246
				'type'   => 'select',
247
				'label'  => 'Weeks in multiple week view',
248
				'name'   => 'multiple_weeks',
249
				'values' => $muliple_weeks,
250
				'help'   => 'How many weeks should the multiple week view show?',
251
				'xmlrpc' => True,
252
				'admin'  => False,
253
				'default'=> 2,
254
			),
255
			'weekdaystarts' => array(
256
				'type'   => 'select',
257
				'label'  => 'weekday starts on',
258
				'name'   => 'weekdaystarts',
259
				'values' => $weekdaystarts,
260
				'help'   => 'This day is shown as first day in the week or month view.',
261
				'xmlrpc' => True,
262
				'admin'  => False,
263
				'forced' => 'Monday',
264
			),
265
			'workdaystarts' => array(
266
				'type'   => 'select',
267
				'label'  => 'work day starts on',
268
				'name'   => 'workdaystarts',
269
				'values' => $times,
270
				'help'   => 'This defines the start of your dayview. Events before this time, are shown above the dayview.<br>This time is also used as a default starttime for new events.',
271
				'xmlrpc' => True,
272
				'admin'  => False,
273
				'default'=> 9,
274
			),
275
			'workdayends' => array(
276
				'type'   => 'select',
277
				'label'  => 'work day ends on',
278
				'name'   => 'workdayends',
279
				'values' => $times,
280
				'help'   => 'This defines the end of your dayview. Events after this time, are shown below the dayview.',
281
				'xmlrpc' => True,
282
				'admin'  => False,
283
				'default'=> 18,
284
			),
285
			'interval' => array(
286
				'type'   => 'select',
287
				'label'  => 'Length of the time interval',
288
				'name'   => 'interval',
289
				'values' => $intervals,
290
				'help'   => 'How many minutes should each interval last?',
291
				'xmlrpc' => True,
292
				'admin'  => False,
293
				'default'=> 30,
294
			),
295
			'day_consolidate' => array(
296
				'type'  => 'select',
297
				'label' => 'Minimum number of users for showing day view as consolidated.',
298
				'name'  => 'day_consolidate',
299
				'values'=> $consolidated,
300
				'help'  => 'How many separate calendars to show before merging them together',
301
				'default'=> 6
302
			),
303
			'week_consolidate' => array(
304
				'type'  => 'select',
305
				'label' => 'Minimum number of users for showing week view as consolidated.',
306
				'name'  => 'week_consolidate',
307
				'values'=> $consolidated,
308
				'help'  => 'How many separate calendars to show before merging them together',
309
				'default'=> 4
310
			),
311
			'use_time_grid' => array(
312
				'type'   => 'multiselect',
313
				'label'  => 'Views showing a list of events',
314
				'name'   => 'use_time_grid',
315
				'values' => $list_views,
316
				'help'   => 'For which views should calendar just a list of events instead of distinct lines with a fixed time interval.',
317
				'xmlrpc' => True,
318
				'admin'  => False,
319
				'default' => ['weekN', 'month'],
320
			),
321
			'auto_update_on_sidebox_change' => array(
322
				'type'	 => 'check',
323
				'label'  => 'Update calendar view immediately when navigation calendar in sidebox is changed',
324
				'name'   => 'auto_update_on_sidebox_change',
325
				'help'   => 'When changing the month',
326
				'default'=> false
327
			),
328
			'2.section' => array(
329
				'type'  => 'section',
330
				'title' => lang('appointment settings'),
331
				'no_lang'=> true,
332
				'xmlrpc' => False,
333
				'admin'  => False
334
			),
335
			'defaultlength' => array(
336
				'type'    => 'input',
337
				'label'   => 'default appointment length (in minutes)',
338
				'name'    => 'defaultlength',
339
				'help'    => 'Default length of newly created events. The length is in minutes, eg. 60 for 1 hour.',
340
				'default' => '',
341
				'size'    => 3,
342
				'xmlrpc' => True,
343
				'admin'  => False,
344
				'default'=> 60,
345
			),
346
			'default_participant' => array(
347
				'type'	=> 'select',
348
				'label'	=> 'New event participants',
349
				'name'	=> 'default_participant',
350
				'values'=>	$default_participants,
351
				'help'	=> 'Participants automatically added to new events',
352
				'default'	=> 'selected',
353
				'xmlrpc' => False,
354
				'admin'  => False
355
			),
356
			'default_category' => array(
357
				'type'	=> 'multiselect',
358
				'label'	=> 'New event category',
359
				'name'	=> 'default_category',
360
				'help'	=> 'Category automatically added to new events',
361
				'values' => $default_cat_seloptions,
362
				'default'	=> '',
363
				'xmlrpc' => False,
364
				'admin'  => False
365
			),
366
			'default-alarm' => array(
367
				'type'   => 'date-duration',//'select',
368
				'label'  => lang('Default alarm for regular events').' ('.lang('empty = no alarm').')',
369
				'name'   => 'default-alarm',
370
				'help'   => 'Alarm added automatic to new events before event start-time',
371
				'xmlrpc' => True,
372
				'admin'  => False,
373
				'default' => '',
374
			),
375
			'default-alarm-wholeday' => array(
376
				'type'   => 'date-duration',//'select',
377
				'label'  => lang('Default alarm for whole-day events').' ('.lang('empty = no alarm').')',
378
				'name'   => 'default-alarm-wholeday',
379
				'help'   => lang('Alarm added automatic to new events before event start-time').' ('.lang('Midnight').')',
380
				'xmlrpc' => True,
381
				'admin'  => False,
382
				'default' => '',
383
			),
384
		);
385
		if (isset($bo))	// add custom time-spans set by CalDAV clients, not in our prefs
386
		{
387
			$prefs = $GLOBALS['egw_info']['user']['preferences']['calendar'];
388
			$data = array(
389
				'prefs' => &$prefs,	// use reference to get preference value back
390
				'preprocess' => true,
391
				'type' => 'user',
392
			);
393
			self::verify_settings_reference($data);
394
		}
395
		$settings += array(
396
			'defaultresource_sel' => array(
397
				'type'		=> 'select',
398
				'label'		=> 'default type of resources selection',
399
				'name'		=> 'defaultresource_sel',
400
				'values'	=> $defaultresource_sel,
401
				'help'		=> 'Default type of resources application selected in the calendar participants research form.',
402
				'xmlrpc'	=> True,
403
				'admin'		=> False,
404
				'default'	=> 'resources'
405
			),
406
			'default_private' => array(
407
				'type'  => 'check',
408
				'label' => 'Set new events to private',
409
				'name'  => 'default_private',
410
				'help'  => 'Should new events created as private by default ?',
411
				'xmlrpc' => True,
412
				'admin'  => False,
413
				'forced' => '0',
414
			),
415
			'reset_stati'	=> array(
416
				'type'   => 'select',
417
				'label'  => 'Reset participant stati on event shifts',
418
				'name'   => 'reset_stati',
419
				'help'   => 'Select whether you want the participant stati reset to unknown, if an event is shifted later on.',
420
				'values' => $reset_stati_on_shifts,
421
				'default' => 'all',
422
				'xmlrpc' => True,
423
				'admin'  => False,
424
			),
425
			'no_category_custom_color' => array(
426
				'type' => 'color',
427
				'label' => 'Custom event color',
428
				'no_lang' => true,
429
				'name' => 'no_category_custom_color',
430
				'help' => lang('Custom color for events without category color'),
431
				'xmlrpc' => True,
432
				'admin'  => False,
433
			),
434
			'2.5.section' => array(
435
				'type'  => 'section',
436
				'title' => lang('Configuration settings'),
437
				'no_lang'=> true,
438
				'xmlrpc' => False,
439
				'admin'  => False
440
			),
441
			'new_event_dialog' => array(
442
				'type'	=> 'select',
443
				'label'	=> 'Add appointments via shortened dialog or complete edit window',
444
				'name'	=> 'new_event_dialog',
445
				'values'=>	array('add' => lang('Quick add'), 'edit' => lang('Regular edit')),
446
				'help'	=> 'Use quick add or full edit dialog when creating a new event',
447
				'default'	=> 'add',
448
			),
449
			'limit_des_lines' => array(
450
				'type'   => 'input',
451
				'size'   => 5,
452
				'label'  => 'Limit number of description lines in list view (default 5, 0 for no limit)',
453
				'name'   => 'limit_des_lines',
454
				'help'   => 'How many description lines should be directly visible. Further lines are available via a scrollbar.',
455
				'xmlrpc' => True,
456
				'admin'  => False
457
			),
458
			'limit_all_day_lines' => array(
459
				'type'   => 'input',
460
				'size'   => 5,
461
				'label'  => 'Limit number of lines for all day events',
462
				'name'   => 'limit_all_day_lines',
463
				'help'   => 'How many lines of all day events should be directly visible. Further lines are available via a mouseover.',
464
				'xmlrpc' => True,
465
				'default'=> 3,
466
				'admin'  => False
467
			),
468
			'planner_show_empty_rows' => array(
469
				'type'   => 'select',
470
				'label'  => 'Show empty rows in Planner',
471
				'name'   => 'planner_show_empty_rows',
472
				'values' => array(
473
					0 => lang('no'),
474
					'user' => lang('Planner by user'),
475
					'cat'  => lang('Planner by category'),
476
					'both' => lang('All'),
477
				),
478
				'help'   => 'Should the planner display an empty row for users or categories without any appointment.',
479
				'xmlrpc' => True,
480
				'admin'  => False,
481
				'forced' => 'user',
482
			),
483
			'birthdays_as_events' => array(
484
				'type'   => 'multiselect',
485
				'values' => $birthdays_as_events,
486
				'label'  => 'Show birthdays as events',
487
				'name'   => 'birthdays_as_events',
488
				'help'   => 'Show birthdays as all day non-blocking events as well as via mouseover of the date.',
489
				'default'=> 'none'
490
			),
491
			'link_title' => array(
492
				'type'   => 'multiselect',
493
				'label'  => 'Link title for events to show',
494
				'name'   => 'link_title',
495
				'values' => $link_title_options,
496
				'help'   => 'What should links to the calendar events display in other applications.',
497
				'xmlrpc' => True,
498
				'admin'  => false,
499
				'default'=> '',
500
			),
501
502
			'3.section' => array(
503
				'type'  => 'section',
504
				'title' => lang('notification settings'),
505
				'no_lang'=> true,
506
				'xmlrpc' => False,
507
				'admin'  => False
508
			),
509
			'receive_updates' => array(
510
				'type'   => 'select',
511
				'label'  => 'Receive email updates',
512
				'name'   => 'receive_updates',
513
				'values' => $updates,
514
				'help'   => "Do you want to be notified about new or changed appointments? You be notified about changes you make yourself.<br>You can limit the notifications to certain changes only. Each item includes all the notification listed above it. All modifications include changes of title, description, participants, but no participant responses. If the owner of an event requested any notifcations, he will always get the participant responses like acceptions and rejections too.",
515
				'xmlrpc' => True,
516
				'admin'  => False,
517
				'default'=> 'time_change',
518
			),
519
			'receive_own_updates' => array(
520
				'type'   => 'select',
521
				'label'  => 'Receive notifications about events you created/modified/deleted',
522
				'name'   => 'receive_own_updates',
523
				'values' => $yesno,
524
				'help'   => "Do you want to be notified about changes of appointments you modified?",
525
				'xmlrpc' => True,
526
				'admin'  => False,
527
				'default'=> 'false',
528
			),
529
			'receive_not_participating' => array(
530
				'type'   => 'select',
531
				'label'  => 'Do you want responses from events you created, but are not participating in?',
532
				'name'   => 'receive_not_participating',
533
				'values' => $yesno,
534
				'help'   => 'Do you want to be notified about participant responses from events you created, but are not participating in?',
535
				'default'=> '1'
536
			),
537
			'notify_externals' => array(
538
				'type'   => 'select',
539
				'label'  => 'Notify non-EGroupware users about event updates',
540
				'name'   => 'notify_externals',
541
				'values' => $updates,
542
				'help'   => 'Do you want non-EGroupware participants of events you created to be automatically notified about new or changed appointments?',
543
				'xmlrpc' => True,
544
				'admin'  => False,
545
				'default'=> 'no',
546
			),
547
			'update_format' => array(
548
				'type'   => 'select',
549
				'label'  => 'Format of event updates',
550
				'name'   => 'update_format',
551
				'values' => $update_formats,
552
				'help'   => 'Extended updates always include the complete event-details. iCal\'s can be imported by certain other calendar-applications.',
553
				'xmlrpc' => True,
554
				'admin'  => False,
555
				'forced' => 'ical',
556
			),
557
			'notifyAdded' => array(
558
				'type'   => 'notify',
559
				'label'  => 'Notification messages for added events',
560
				'name'   => 'notifyAdded',
561
				'rows'   => 5,
562
				'cols'   => 50,
563
				'help'   => 'This message is sent to every participant of events you own, who has requested notifcations about new events.<br>You can use certain variables which get substituted with the data of the event. The first line is the subject of the email.',
564
				'default' => '',
565
				'values' => $event_details,
566
				'xmlrpc' => True,
567
				'admin'  => False,
568
			),
569
			'notifyCanceled' => array(
570
				'type'   => 'notify',
571
				'label'  => 'Notification messages for canceled events',
572
				'name'   => 'notifyCanceled',
573
				'rows'   => 5,
574
				'cols'   => 50,
575
				'help'   => 'This message is sent for canceled or deleted events.',
576
				'default' => '',
577
				'values' => $event_details,
578
				'subst_help' => False,
579
				'xmlrpc' => True,
580
				'admin'  => False,
581
			),
582
			'notifyModified' => array(
583
				'type'   => 'notify',
584
				'label'  => 'Notification messages for modified events',
585
				'name'   => 'notifyModified',
586
				'rows'   => 5,
587
				'cols'   => 50,
588
				'help'   => 'This message is sent for modified or moved events.',
589
				'default' => '',
590
				'values' => $event_details,
591
				'subst_help' => False,
592
				'xmlrpc' => True,
593
				'admin'  => False,
594
			),
595
			'notifyDisinvited' => array(
596
				'type'   => 'notify',
597
				'label'  => 'Notification messages for uninvited participants',
598
				'name'   => 'notifyDisinvited',
599
				'rows'   => 5,
600
				'cols'   => 50,
601
				'help'   => 'This message is sent to uninvited participants.',
602
				'values' => $event_details,
603
				'subst_help' => False,
604
				'xmlrpc' => True,
605
				'admin'  => False,
606
			),
607
			'notifyResponse' => array(
608
				'type'   => 'notify',
609
				'label'  => 'Notification messages for your responses',
610
				'name'   => 'notifyResponse',
611
				'rows'   => 5,
612
				'cols'   => 50,
613
				'help'   => 'This message is sent when you accept, tentative accept or reject an event.',
614
				'values' => $event_details,
615
				'subst_help' => False,
616
				'xmlrpc' => True,
617
				'admin'  => False,
618
			),
619
			'notifyAlarm' => array(
620
				'type'   => 'notify',
621
				'label'  => 'Notification messages for your alarms',
622
				'name'   => 'notifyAlarm',
623
				'rows'   => 5,
624
				'cols'   => 50,
625
				'help'   => 'This message is sent when you set an Alarm for a certain event. Include all information you might need.',
626
				'values' => $event_details,
627
				'subst_help' => False,
628
				'xmlrpc' => True,
629
				'admin'  => False,
630
			),
631
			'4.section' => array(
632
				'type'  => 'section',
633
				'title' => lang('Data exchange settings'),
634
				'no_lang'=> true,
635
				'xmlrpc' => False,
636
				'admin'  => False
637
			),
638
		);
639
		// Merge print
640
		if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
641
		{
642
			$settings['default_document'] = array(
643
				'type'   => 'vfs_file',
644
				'size'   => 60,
645
				'label'  => 'Default document to insert entries',
646
				'name'   => 'default_document',
647
				'help'   => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.',lang('calendar')).' '.
648
					lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','calendar_title').' '.
649
					lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
650
				'run_lang' => false,
651
				'xmlrpc' => True,
652
				'admin'  => False,
653
			);
654
			$settings['document_dir'] = array(
655
				'type'   => 'vfs_dirs',
656
				'size'   => 60,
657
				'label'  => 'Directory with documents to insert entries',
658
				'name'   => 'document_dir',
659
				'help'   => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the data inserted.',lang('calendar')).' '.
660
					lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','calendar_title').' '.
661
					lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
662
				'run_lang' => false,
663
				'xmlrpc' => True,
664
				'admin'  => False,
665
				'default' => '/templates/calendar',
666
			);
667
		}
668
669
		$settings += array(
670
			'export_timezone' => array(
671
				'type'   => 'select',
672
				'label'  => 'Timezone of event iCal file import/export',
673
				'name'   => 'export_timezone',
674
				'values' => $export_tzs,
675
				'help'   => 'Use this timezone to import/export calendar data.',
676
				'xmlrpc' => True,
677
				'admin'  => False,
678
				'default' => '0', // Use event's TZ
679
			),
680
			'freebusy' => array(
681
				'type'  => 'select',
682
				'label' => 'Make freebusy information available to not logged in persons?',
683
				'name'  => 'freebusy',
684
				'help'  => $freebusy_help,
685
				'values'	=> $freebusy_values,
686
				'run_lang' => false,
687
				'subst_help' => False,
688
				'xmlrpc' => True,
689
				'admin'  => False,
690
				'forced' => 0,
691
			),
692
			'freebusy_pw' => array(
693
				'type'  => 'input',
694
				'label' => 'Password for not loged in users to your freebusy information?',
695
				'name'  => 'freebusy_pw',
696
				'help'  => 'If you dont set a password here, the information is available to everyone, who knows the URL!!!',
697
				'xmlrpc' => True,
698
				'admin'  => False,
699
				'forced' => ''
700
			),
701
		);
702
703
		return $settings;
704
	}
705
706
	/**
707
	 * Verify settings hook called to generate errors about settings used here to store default alarms in CalDAV prefs
708
	 *
709
	 * @param array $data
710
	 *  array $data['prefs']
711
	 *  string $data['type'] 'user', 'default' or 'forced'
712
	 *  boolean $data['preprocess'] true data just shown to user, false: data stored by user
713
	 */
714
	public static function verify_settings(array $data)
715
	{
716
		self::verify_settings_reference($data);
717
	}
718
719
	/**
720
	 * Verify settings hook called to generate errors about settings used here to store default alarms in CalDAV prefs
721
	 *
722
	 * @param array& $data
723
	 *  array $data['prefs']
724
	 *  string $data['type'] 'user', 'default' or 'forced'
725
	 *  boolean $data['preprocess'] true data just shown to user, false: data stored by user
726
	 */
727
	public static function verify_settings_reference(array &$data)
728
	{
729
		//error_log(__METHOD__."(".array2string($data).")");
730
		// caldav perfs are always user specific and cant by switched off
731
		if ($data['type'] != 'user') return;
732
733
		$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
734
		foreach(array(
735
			'default-alarm' => 'default-alarm-vevent-datetime:/'.$account_lid.'/:urn:ietf:params:xml:ns:caldav',
736
			'default-alarm-wholeday' => 'default-alarm-vevent-date:/'.$account_lid.'/:urn:ietf:params:xml:ns:caldav',
737
		) as $name => $dav)
738
		{
739
			$pref =& $GLOBALS['egw_info']['user']['preferences']['groupdav'][$dav];
740
			if (true) $pref = str_replace("\r", '', $pref);	// remove CR messing up multiline preg_match
741
			$val =& $data['prefs'][$name];
742
743
			//error_log(__METHOD__."() groupdav[$dav]=$pref, calendar[$name]=$val");
744
745
			if ($data['preprocess'])	// showing preferences
746
			{
747
				if (!isset($val))	// no calendar pref --> read value from caldav
748
				{
749
					$matches = null;
750
					if (preg_match('/^ACTION:NONE$/mi', $pref))
751
					{
752
						$val = '';
753
					}
754
					elseif (preg_match('/^TRIGGER:-PT(\d+(M|H|D))$/mi', $pref, $matches))
755
					{
756
						static $factors = array(
757
							'M' => 1,
758
							'H' => 60,
759
							'D' => 1440,
760
						);
761
						$factor = $factors[strtoupper($matches[2])];
762
						$val = $factor*(int)$matches[1];
763
					}
764
					else
765
					{
766
						$val = '';
767
					}
768
					$GLOBALS['egw']->preferences->add('calendar', $name, $val, 'user');
769
					//error_log(__METHOD__."() setting $name={$val} from $dav='$pref'");
770
				}
771
			}
772
			else	// storing preferences
773
			{
774
				if (empty($pref) || !preg_match('/^TRIGGER:/m', $pref))
775
				{
776
					$pref = 'BEGIN:VALARM
777
TRIGGER:-PT1H
778
ATTACH;VALUE=URI:Basso
779
ACTION:AUDIO
780
END:VALARM';
781
				}
782
				$trigger = $val < 0 ? 'TRIGGER:PT' : 'TRIGGER:-PT';
783
				if ((string)$val === '')
784
				{
785
					$pref = preg_replace('/^ACTION:.*$/m', 'ACTION:NONE', $pref);
786
				}
787
				elseif (abs($val) < 60)
788
				{
789
					$pref = preg_replace('/^TRIGGER:.*$/m', $trigger.number_format(abs($val), 0).'M', $pref);
790
				}
791
				else
792
				{
793
					$pref = preg_replace('/^TRIGGER:.*$/m', $trigger.number_format(abs($val)/60, 0).'H', $pref);
794
				}
795
				$GLOBALS['egw']->preferences->add('groupdav', $dav, $pref, 'user');
796
				//error_log(__METHOD__."() storing $name=$val --> $dav='$pref'");
797
			}
798
		}
799
	}
800
801
	/**
802
	 * Sync default alarms from CalDAV to Calendar
803
	 *
804
	 * Gets called by Api\CalDAV::PROPPATCH() for 'default-alarm-vevent-date(time)' changes
805
	 */
806
	public static function sync_default_alarms()
807
	{
808
		self::verify_settings(array(
809
			'prefs' => array(),
810
			'preprocess' => true,
811
			'type' => 'user',
812
		));
813
	}
814
815
	public static function config_validate()
816
	{
817
		$GLOBALS['egw_info']['server']['found_validation_hook'] = array('calendar_purge_old');
818
	}
819
820
	/**
821
	 * ACL rights and labels used
822
	 *
823
	 * @param string|array string with location or array with parameters incl. "location", specially "owner" for selected Acl owner
824
	 * @return array Acl::(READ|ADD|EDIT|DELETE|PRIVAT|CUSTOM(1|2|3)) => $label pairs
825
	 */
826
	public static function acl_rights($params)
827
	{
828
		$rights = array(
829
			Acl::CUSTOM2 => 'freebusy',
830
			Acl::CUSTOM3 => 'invite',
831
			Acl::READ    => 'read',
832
			Acl::ADD     => 'add',
833
			Acl::EDIT    => 'edit',
834
			Acl::DELETE  => 'delete',
835
			Acl::PRIVAT  => 'private',
836
		);
837
		$require_acl_invite = $GLOBALS['egw_info']['server']['require_acl_invite'];
838
839
		if (!$require_acl_invite || $require_acl_invite == 'groups' && !($params['owner'] < 0))
840
		{
841
			unset($rights[Acl::CUSTOM3]);
842
		}
843
		return $rights;
844
	}
845
846
	/**
847
	 * Hook to tell framework we use standard categories method
848
	 *
849
	 * @param string|array $data hook-data or location
850
	 * @return boolean
851
	 */
852
	public static function categories($data)
853
	{
854
		unset($data);	// not used, but in function signature for hooks
855
		return true;
856
	}
857
858
	/**
859
	 * Mail integration hook to import mail message contents into a calendar entry
860
	 *
861
	 * @return string method to be executed for calendar mail integration
862
	 */
863
	public static function mail_import($args)
864
	{
865
		unset($args);	// not used, but required by function signature
866
867
		return array (
868
			'menuaction' => 'calendar.calendar_uiforms.mail_import',
869
			'popup' => Link::get_registry('calendar', 'edit_popup')
870
		);
871
	}
872
873
	/**
874
	 * Method to construct notifications actions
875
	 *
876
	 * @param type $params
877
	 * @return type
878
	 */
879
	public static function notifications_actions ($params)
880
	{
881
		Api\Translation::add_app('calendar');
882
		// do not set actions for alarm type
883
		if ($params['data']['type'] == 6) return array();
884
		return array(
885
			array(
886
				'id' => 'A',
887
				'caption' => lang('Accept'),
888
				'icon' => 'accepted',
889
				'onExecute' => 'egw().json("calendar.calendar_uiforms.ajax_status",['.$params['data']['event_id'].','.$params['data']['user_id'].','.'"A"'.']).sendRequest(true);this.button_delete(arguments[0], arguments[1]);'
890
			),
891
			array(
892
				'id' => 'R',
893
				'caption' => lang('Reject'),
894
				'icon' => 'rejected',
895
				'onExecute' => 'egw().json("calendar.calendar_uiforms.ajax_status",['.$params['data']['event_id'].','.$params['data']['user_id'].','.'"R"'.']).sendRequest(true);this.button_delete(arguments[0], arguments[1]);'
896
			),
897
			array(
898
				'id' => 'T',
899
				'caption' => lang('Tentative'),
900
				'icon' => 'tentative',
901
				'onExecute' => 'egw().json("calendar.calendar_uiforms.ajax_status",['.$params['data']['event_id'].','.$params['data']['user_id'].','.'"T"'.']).sendRequest(true);this.button_delete(arguments[0], arguments[1]);'
902
			)
903
		);
904
	}
905
}
906
907
// Not part of the class, since config hooks are still using the old style
908
function calendar_purge_old($config)
909
{
910
	$id = 'calendar_purge';
911
912
	// Cancel old purge
913
	$async = new Api\Asyncservice();
914
	$async->cancel_timer($id);
915
916
	if((float)$config > 0)
917
	{
918
		$result = $async->set_timer(
919
			array('month' => '*', 'day' => 1),
920
			$id,
921
			'calendar.calendar_boupdate.purge',
922
			(float)$config
923
		);
924
		if(!$result)
925
		{
926
			$GLOBALS['config_error'] = 'Unable to schedule purge';
927
		}
928
	}
929
}
930