1<?php
2
3/**
4 * Driver interface for the Tasklist plugin
5 *
6 * @version @package_version@
7 * @author Thomas Bruederli <bruederli@kolabsys.com>
8 *
9 * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Affero General Public License as
13 * published by the Free Software Foundation, either version 3 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Affero General Public License for more details.
20 *
21 * You should have received a copy of the GNU Affero General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /**
26  * Struct of an internal task object how it is passed from/to the driver classes:
27  *
28  *  $task = array(
29  *            'id' => 'Task ID used for editing',  // must be unique for the current user
30  *     'parent_id' => 'ID of parent task',  // null if top-level task
31  *           'uid' => 'Unique identifier of this task',
32  *          'list' => 'Task list identifier to add the task to or where the task is stored',
33  *       'changed' => <DateTime>,  // Last modification date/time of the record
34  *         'title' => 'Event title/summary',
35  *   'description' => 'Event description',
36  *          'tags' => array(),      // List of tags for this task
37  *          'date' => 'Due date',   // as string of format YYYY-MM-DD or null if no date is set
38  *          'time' => 'Due time',   // as string of format hh::ii or null if no due time is set
39  *     'startdate' => 'Start date'  // Delay start of the task until that date
40  *     'starttime' => 'Start time'  // ...and time
41  *    'categories' => 'Task category',
42  *       'flagged' => 'Boolean value whether this record is flagged',
43  *      'complete' => 'Float value representing the completeness state (range 0..1)',
44  *      'status'   => 'Task status string according to (NEEDS-ACTION, IN-PROCESS, COMPLETED, CANCELLED) RFC 2445',
45  *       'valarms' => array(           // List of reminders (new format), each represented as a hash array:
46  *                array(
47  *                   'trigger' => '-PT90M',     // ISO 8601 period string prefixed with '+' or '-', or DateTime object
48  *                    'action' => 'DISPLAY|EMAIL|AUDIO',
49  *                  'duration' => 'PT15M',      // ISO 8601 period string
50  *                    'repeat' => 0,            // number of repetitions
51  *               'description' => '',           // text to display for DISPLAY actions
52  *                   'summary' => '',           // message text for EMAIL actions
53  *                 'attendees' => array(),      // list of email addresses to receive alarm messages
54  *                ),
55  *    ),
56  *    'recurrence' => array(   // Recurrence definition according to iCalendar (RFC 2445) specification as list of key-value pairs
57  *              'FREQ' => 'DAILY|WEEKLY|MONTHLY|YEARLY',
58  *          'INTERVAL' => 1...n,
59  *             'UNTIL' => DateTime,
60  *             'COUNT' => 1..n,     // number of times
61  *             'RDATE' => array(),  // complete list of DateTime objects denoting individual repeat dates
62  *     ),
63  *     '_fromlist' => 'List identifier where the task was stored before',
64  *  );
65  */
66
67/**
68 * Driver interface for the Tasklist plugin
69 */
70abstract class tasklist_driver
71{
72    // features supported by the backend
73    public $alarms = false;
74    public $attachments = false;
75    public $attendees = false;
76    public $undelete = false; // task undelete action
77    public $sortable = false;
78    public $alarm_types = array('DISPLAY');
79    public $alarm_absolute = true;
80    public $last_error;
81
82    const FILTER_ALL           = 0;
83    const FILTER_WRITEABLE     = 1;
84    const FILTER_INSERTABLE    = 2;
85    const FILTER_ACTIVE        = 4;
86    const FILTER_PERSONAL      = 8;
87    const FILTER_PRIVATE       = 16;
88    const FILTER_CONFIDENTIAL  = 32;
89    const FILTER_SHARED        = 64;
90
91
92    /**
93     * Get a list of available task lists from this source
94     * @param integer Bitmask defining filter criterias.
95     *                See FILTER_* constants for possible values.
96     */
97    abstract function get_lists($filter = 0);
98
99    /**
100     * Create a new list assigned to the current user
101     *
102     * @param array Hash array with list properties
103     *        name: List name
104     *       color: The color of the list
105     *  showalarms: True if alarms are enabled
106     * @return mixed ID of the new list on success, False on error
107     */
108    abstract function create_list(&$prop);
109
110    /**
111     * Update properties of an existing tasklist
112     *
113     * @param array Hash array with list properties
114     *          id: List Identifier
115     *        name: List name
116     *       color: The color of the list
117     *  showalarms: True if alarms are enabled (if supported)
118     * @return boolean True on success, Fales on failure
119     */
120    abstract function edit_list(&$prop);
121
122    /**
123     * Set active/subscribed state of a list
124     *
125     * @param array Hash array with list properties
126     *          id: List Identifier
127     *      active: True if list is active, false if not
128     * @return boolean True on success, Fales on failure
129     */
130    abstract function subscribe_list($prop);
131
132    /**
133     * Delete the given list with all its contents
134     *
135     * @param array Hash array with list properties
136     *      id: list Identifier
137     * @return boolean True on success, Fales on failure
138     */
139    abstract function delete_list($prop);
140
141    /**
142     * Search for shared or otherwise not listed tasklists the user has access
143     *
144     * @param string Search string
145     * @param string Section/source to search
146     * @return array List of tasklists
147     */
148    abstract function search_lists($query, $source);
149
150    /**
151     * Get number of tasks matching the given filter
152     *
153     * @param array List of lists to count tasks of
154     * @return array Hash array with counts grouped by status (all|flagged|completed|today|tomorrow|nodate)
155     */
156    abstract function count_tasks($lists = null);
157
158    /**
159     * Get all task records matching the given filter
160     *
161     * @param array Hash array with filter criterias:
162     *  - mask:  Bitmask representing the filter selection (check against tasklist::FILTER_MASK_* constants)
163     *  - from:  Date range start as string (Y-m-d)
164     *  - to:    Date range end as string (Y-m-d)
165     *  - search: Search query string
166     * @param array List of lists to get tasks from
167     * @return array List of tasks records matchin the criteria
168     */
169    abstract function list_tasks($filter, $lists = null);
170
171    /**
172     * Get a list of tags to assign tasks to
173     *
174     * @return array List of tags
175     */
176    abstract function get_tags();
177
178    /**
179     * Get a list of pending alarms to be displayed to the user
180     *
181     * @param  integer Current time (unix timestamp)
182     * @param  mixed   List of list IDs to show alarms for (either as array or comma-separated string)
183     * @return array   A list of alarms, each encoded as hash array with task properties
184     *         id: Task identifier
185     *        uid: Unique identifier of this task
186     *       date: Task due date
187     *       time: Task due time
188     *      title: Task title/summary
189     */
190    abstract function pending_alarms($time, $lists = null);
191
192    /**
193     * (User) feedback after showing an alarm notification
194     * This should mark the alarm as 'shown' or snooze it for the given amount of time
195     *
196     * @param  string  Task identifier
197     * @param  integer Suspend the alarm for this number of seconds
198     */
199    abstract function dismiss_alarm($id, $snooze = 0);
200
201    /**
202     * Remove alarm dismissal or snooze state
203     *
204     * @param  string  Task identifier
205     */
206    abstract public function clear_alarms($id);
207
208    /**
209     * Return data of a specific task
210     *
211     * @param mixed   Hash array with task properties or task UID
212     * @param integer Bitmask defining filter criterias for folders.
213     *                See FILTER_* constants for possible values.
214     *
215     * @return array Hash array with task properties or false if not found
216     */
217    abstract public function get_task($prop, $filter = 0);
218
219    /**
220     * Get decendents of the given task record
221     *
222     * @param mixed  Hash array with task properties or task UID
223     * @param boolean True if all childrens children should be fetched
224     * @return array List of all child task IDs
225     */
226    abstract public function get_childs($prop, $recursive = false);
227
228    /**
229     * Add a single task to the database
230     *
231     * @param array Hash array with task properties (see header of this file)
232     * @return mixed New event ID on success, False on error
233     */
234    abstract function create_task($prop);
235
236    /**
237     * Update an task entry with the given data
238     *
239     * @param array Hash array with task properties (see header of this file)
240     * @return boolean True on success, False on error
241     */
242    abstract function edit_task($prop);
243
244    /**
245     * Move a single task to another list
246     *
247     * @param array   Hash array with task properties:
248     *      id: Task identifier
249     *      list: New list identifier to move to
250     *      _fromlist: Previous list identifier
251     * @return boolean True on success, False on error
252     */
253    abstract function move_task($prop);
254
255    /**
256     * Remove a single task from the database
257     *
258     * @param array   Hash array with task properties:
259     *      id: Task identifier
260     *    list: Tasklist identifer
261     * @param boolean Remove record irreversible (mark as deleted otherwise, if supported by the backend)
262     * @return boolean True on success, False on error
263     */
264    abstract function delete_task($prop, $force = true);
265
266    /**
267     * Restores a single deleted task (if supported)
268     *
269     * @param array Hash array with task properties:
270     *      id: Task identifier
271     * @return boolean True on success, False on error
272     */
273    public function undelete_task($prop)
274    {
275        return false;
276    }
277
278    /**
279     * Get attachment properties
280     *
281     * @param string $id    Attachment identifier
282     * @param array  $task  Hash array with event properties:
283     *         id: Task identifier
284     *       list: List identifier
285     *        rev: Revision (optional)
286     *
287     * @return array Hash array with attachment properties:
288     *         id: Attachment identifier
289     *       name: Attachment name
290     *   mimetype: MIME content type of the attachment
291     *       size: Attachment size
292     */
293    public function get_attachment($id, $task) { }
294
295    /**
296     * Get attachment body
297     *
298     * @param string $id    Attachment identifier
299     * @param array  $task  Hash array with event properties:
300     *         id: Task identifier
301     *       list: List identifier
302     *        rev: Revision (optional)
303     *
304     * @return string Attachment body
305     */
306    public function get_attachment_body($id, $task) { }
307
308    /**
309     * Build a struct representing the given message reference
310     *
311     * @param object|string $uri_or_headers rcube_message_header instance holding the message headers
312     *                         or an URI from a stored link referencing a mail message.
313     * @param string $folder  IMAP folder the message resides in
314     *
315     * @return array An struct referencing the given IMAP message
316     */
317    public function get_message_reference($uri_or_headers, $folder = null)
318    {
319        // to be implemented by the derived classes
320        return false;
321    }
322
323    /**
324     * Find tasks assigned to a specified message
325     *
326     * @param object $message rcube_message_header instance
327     * @param string $folder  IMAP folder the message resides in
328     *
329     * @param array List of linked task objects
330     */
331    public function get_message_related_tasks($headers, $folder)
332    {
333        // to be implemented by the derived classes
334        return array();
335    }
336
337    /**
338     * Helper method to determine whether the given task is considered "complete"
339     *
340     * @param array  $task  Hash array with event properties
341     * @return boolean True if complete, False otherwiese
342     */
343    public function is_complete($task)
344    {
345        return ($task['complete'] >= 1.0 && empty($task['status'])) || $task['status'] === 'COMPLETED';
346    }
347
348    /**
349     * Provide a list of revisions for the given task
350     *
351     * @param array  $task Hash array with task properties:
352     *         id: Task identifier
353     *       list: List identifier
354     *
355     * @return array List of changes, each as a hash array:
356     *         rev: Revision number
357     *        type: Type of the change (create, update, move, delete)
358     *        date: Change date
359     *        user: The user who executed the change
360     *          ip: Client IP
361     *     mailbox: Destination list for 'move' type
362     */
363    public function get_task_changelog($task)
364    {
365        return false;
366    }
367
368    /**
369     * Get a list of property changes beteen two revisions of a task object
370     *
371     * @param array  $task Hash array with task properties:
372     *         id: Task identifier
373     *       list: List identifier
374     * @param mixed  $rev1   Old Revision
375     * @param mixed  $rev2   New Revision
376     *
377     * @return array List of property changes, each as a hash array:
378     *    property: Revision number
379     *         old: Old property value
380     *         new: Updated property value
381     */
382    public function get_task_diff($task, $rev1, $rev2)
383    {
384        return false;
385    }
386
387    /**
388     * Return full data of a specific revision of an event
389     *
390     * @param mixed  $task UID string or hash array with task properties:
391     *         id: Task identifier
392     *       list: List identifier
393     * @param mixed  $rev Revision number
394     *
395     * @return array Task object as hash array
396     * @see self::get_task()
397     */
398    public function get_task_revison($task, $rev)
399    {
400        return false;
401    }
402
403    /**
404     * Command the backend to restore a certain revision of a task.
405     * This shall replace the current object with an older version.
406     *
407     * @param mixed  $task UID string or hash array with task properties:
408     *         id: Task identifier
409     *       list: List identifier
410     * @param mixed  $rev Revision number
411     *
412     * @return boolean True on success, False on failure
413     */
414    public function restore_task_revision($task, $rev)
415    {
416        return false;
417    }
418
419    /**
420     * Build the edit/create form for lists.
421     * This gives the drivers the opportunity to add more list properties
422     *
423     * @param string  The action called this form
424     * @param array   Tasklist properties
425     * @param array   List with form fields to be rendered
426     *
427     * @return string HTML content of the form
428     */
429    public function tasklist_edit_form($action, $list, $formfields)
430    {
431        $table = new html_table(array('cols' => 2, 'class' => 'propform'));
432
433        foreach ($formfields as $col => $colprop) {
434            $label = !empty($colprop['label']) ? $colprop['label'] : $rcmail->gettext("$domain.$col");
435
436            $table->add('title', html::label($colprop['id'], rcube::Q($label)));
437            $table->add(null, $colprop['value']);
438        }
439
440        return $table->show();
441    }
442
443    /**
444     * Compose an URL for CalDAV access to the given list (if configured)
445     */
446    public function tasklist_caldav_url($list)
447    {
448        $rcmail = rcube::get_instance();
449        if (!empty($list['caldavuid']) && ($template = $rcmail->config->get('calendar_caldav_url', null))) {
450            return strtr($template, array(
451                '%h' => $_SERVER['HTTP_HOST'],
452                '%u' => urlencode($rcmail->get_user_name()),
453                '%i' => urlencode($list['caldavuid']),
454                '%n' => urlencode($list['editname']),
455            ));
456        }
457
458        return null;
459    }
460
461    /**
462     * Handler for user_delete plugin hook
463     *
464     * @param array Hash array with hook arguments
465     * @return array Return arguments for plugin hooks
466     */
467    public function user_delete($args)
468    {
469        // TO BE OVERRIDDEN
470        return $args;
471    }
472}
473