1<?php
2/**
3 * DokuWiki Plugin DAVCard (Book Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Böhler <dev@aboehler.at>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
13require_once(DOKU_PLUGIN.'syntax.php');
14
15class syntax_plugin_davcard_book extends DokuWiki_Syntax_Plugin {
16
17    protected $hlp = null;
18
19    // Load the helper plugin
20    public function syntax_plugin_davcard_book() {
21        $this->hlp =& plugin_load('helper', 'davcard');
22    }
23
24
25    /**
26     * What kind of syntax are we?
27     */
28    function getType(){
29        return 'substition';
30    }
31
32    /**
33     * What about paragraphs?
34     */
35    function getPType(){
36        return 'normal';
37    }
38
39    /**
40     * Where to sort in?
41     */
42    function getSort(){
43        return 165;
44    }
45
46    /**
47     * Connect pattern to lexer
48     */
49    function connectTo($mode) {
50        $this->Lexer->addSpecialPattern('\{\{davcardbook>[^}]*\}\}',$mode,'plugin_davcard_book');
51    }
52
53    /**
54     * Handle the match
55     */
56    function handle($match, $state, $pos, Doku_Handler $handler){
57        global $ID;
58        $options = trim(substr($match,14,-2));
59        $options = explode(',', $options);
60        $data = array('name' => $ID,
61                      'description' => $this->getLang('created_by_davcard'),
62                      'id' => array(),
63                      'filter' => array(),
64                      );
65        foreach($options as $option)
66        {
67            list($key, $val) = explode('=', $option);
68            $key = strtolower(trim($key));
69            $val = trim($val);
70            switch($key)
71            {
72                case 'filter':
73                    list($k, $v) = explode(':', strtolower($val), 2);
74                    $data['filter'][$k] = $v;
75                break;
76                case 'id':
77                    if(!in_array($val, $data['id']))
78                        $data['id'][] = $val;
79                break;
80                default:
81                    $data[$key] = $val;
82            }
83        }
84        // Handle the default case when the user didn't enter a different ID
85        if(empty($data['id']))
86        {
87            $data['id'] = array($ID);
88        }
89        // Only update the addressbook name/description if the ID matches the page ID.
90        // Otherwise, the addressbook is included in another page and we don't want
91        // to interfere with its data.
92        if(in_array($ID, $data['id']))
93        {
94            if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER']))
95                $username = $_SERVER['REMOTE_USER'];
96            else
97                $username = uniqid('davcard-');
98            $this->hlp->setAddressbookNameForPage($data['name'], $data['description'], $ID, $username);
99        }
100
101        $meta = p_get_metadata($ID, 'plugin_davcard');
102        if(is_null($meta))
103            $meta = array();
104        $meta['addressbooks'] = $data;
105        // Add webdavclient information so that we can disable caching if need be
106        foreach($data['id'] as $addrbkid)
107        {
108            if(strpos($addrbkid, 'webdav://') === 0)
109            {
110                $connectionId = str_replace('webdav://', '', $addrbkid);
111                if(!is_array($meta['webdavclient']))
112                    $meta['webdavclient'] = array();
113                if(!in_array($addrbkid, $meta['webdavclient']))
114                    $meta['webdavclient'][] = $connectionId;
115            }
116        }
117        p_set_metadata($ID, array('plugin_davcard' => $meta));
118        return $data;
119    }
120
121    /**
122     * Create output
123     */
124    function render($format, Doku_Renderer $R, $data)
125    {
126        global $ID;
127        if($format !== 'xhtml')
128            return false;
129
130        $addressbooklist = array();
131
132        $R->doc .= '<div class="davcardAddressbookAddNew"><a href="#" class="davcardAddressbookAddNew">'.$this->getLang('add_new').'</a></div>';
133
134        $R->doc .= '<div id="davcardAddressbookList" data-addressbookpage="'.$ID.'">';
135        $R->doc .= '<table class="davcardAddressbookTable">';
136        $R->doc .= '<tr><th>'.$this->getLang('name').'</th><th>'.$this->getLang('address').'</th><th>'.$this->getLang('phone').'</th><th>'.$this->getLang('email').'</th></tr>';
137        foreach($data['id'] as $id)
138        {
139            $write = false;
140            if(strpos($id, 'webdav://') === 0)
141            {
142                $wdc =& plugin_load('helper', 'webdavclient');
143                if(is_null($wdc))
144                {
145                    echo $this->getLang('no_wdc');
146                    continue;
147                }
148                $connectionId = str_replace('webdav://', '', $id);
149                $settings = $wdc->getConnection($connectionId);
150                if($settings === false)
151                {
152                    echo $this->getLang('settings_not_found');
153                    continue;
154                }
155                if($settings['type'] !== 'contacts')
156                {
157                    echo $this->getLang('wrong_type');
158                    continue;
159                }
160                $name = $settings['displayname'];
161                $entries = $wdc->getAddressbookEntries($connectionId);
162                $write = $settings['write'];
163            }
164            else
165            {
166                $acl = auth_quickaclcheck($id);
167                if($acl > AUTH_READ)
168                {
169                    $write = true;
170                }
171                elseif($acl < AUTH_READ)
172                {
173                    continue;
174                }
175                else
176                {
177                    $write = false;
178                }
179                $addressbookid = $this->hlp->getAddressbookIdForPage($id);
180                $name = $this->hlp->getAddressBookSettings($addressbookid);
181                $name = $name['displayname'];
182                $entries = $this->hlp->getAddressbookEntries($addressbookid);
183            }
184
185            $addressbooklist[] = array('id' => $id, 'name' => $name, 'write' => $write);
186
187            foreach($entries as $entry)
188            {
189                $contactdata = $this->hlp->parseVcard($entry['contactdata'], $entry['uri'], $write);
190                if(!$this->contactFilterMatch($data['filter'], $contactdata))
191                    continue;
192                $R->doc .= '<tr><td><a href="#" class="plugin_davcard_edit_vcard" data-davcardid="'.$id.'" data-davcarduri="'.hsc($entry['uri']).'" data-write="'.($write ? 'true' : 'false').'">'.hsc($entry['formattedname']).'</a></td><td>';
193                if(count($contactdata['addr']) > 0)
194                {
195                    $R->doc .= '<span class="adr">';
196                    foreach($contactdata['addr'] as $dat)
197                    {
198                        if(isset($dat['type']))
199                            $type = $dat['type'];
200                        else
201                            $type = 'other';
202                        $R->doc .= '<span class="type">'.hsc($this->getLang('adr'.strtolower($type))).'</span>';
203                        if($dat['address'][2] != '')
204                        {
205                            $R->doc .= '<span class="street-address">'.hsc($dat['address'][2]).'</span><br>';
206                        }
207                        if($dat['address'][5] != '')
208                        {
209                            $R->doc .= '<span class="postal-code">'.hsc($dat['address'][5]).' </span>';
210                        }
211                        if($dat['address'][3] != '')
212                        {
213                            $R->doc .= '<span class="locality">'.hsc($dat['address'][3]).'</span><br>';
214                        }
215
216                        if($dat['address'][6] != '')
217                        {
218                            $R->doc .= '<span class="country-name">'.hsc($dat['address'][6]).'</span>';
219                        }
220                    }
221                    $R->doc .= '</span>';
222                }
223                $R->doc .= '</td><td>';
224                if(count($contactdata['tel']) > 0)
225                {
226                    $R->doc .= '<span class="tel">';
227                    foreach($contactdata['tel'] as $dat)
228                    {
229                        if(isset($dat['type']))
230                            $type = $dat['type'];
231                        else
232                            $type = 'other';
233                        $R->doc .= '<span class="type">'.hsc($this->getLang('tel'.strtolower($type))).' </span>';
234                        $R->doc .= hsc($dat['number']).'<br>';
235                    }
236                    $R->doc .= '</span>';
237                }
238                $R->doc .= '</td><td>';
239                if(count($contactdata['mail']) > 0)
240                {
241                    foreach($contactdata['mail'] as $dat)
242                    {
243                        $R->doc .= '<span class="email">'.hsc($dat['mail']).'</span><br>';
244                    }
245                }
246                $R->doc .= '</td></tr>';
247            }
248        }
249        $R->doc .= '</table>';
250        $R->doc .= '<div id="davcardAddressbookList" class="davcardAddressbookList" style="display:none">';
251        $R->doc .= '<select id="davcardAddressbookDropdown">';
252        foreach($addressbooklist as $addrbk)
253        {
254            $R->doc .= '<option value="'.hsc($addrbk['id']).'" data-write="'.hsc($addrbk['write']).'">'.hsc($addrbk['name']).'</option>';
255        }
256        $R->doc .= '</select></div>';
257        $R->doc .= '</div>';
258
259    }
260
261/**
262 * Check if a contact matches a given filter pattern
263 *
264 * @param array $filter The filter array
265 * @param array $contactdata The contact's data to match
266 *
267 * @return true on success, otherwise false
268 */
269    private function contactFilterMatch($filter, $contactdata)
270    {
271        if(empty($filter))
272            return true;
273
274        foreach($filter as $type => $params)
275        {
276            $params = '/'.$params.'/i';
277            switch($type)
278            {
279                case 'name':
280                    if(preg_match($params, $contactdata['formattedname']) !== 1)
281                        return false;
282                break;
283                case 'mail':
284                    $found = false;
285                    foreach($contactdata['mail'] as $dat)
286                    {
287                        if(preg_match($params, $dat['mail']) === 1)
288                            $found = true;
289                    }
290                    if(!$found)
291                        return false;
292                break;
293                case 'address':
294                    $found = false;
295                    foreach($contactdata['addr'] as $dat)
296                    {
297                        foreach($dat['address'] as $da)
298                        {
299                            if(preg_match($params, $da) === 1)
300                                $found = true;
301                        }
302                    }
303                    if(!$found)
304                        return false;
305                break;
306                case 'tel':
307                    $found = false;
308                    foreach($contactdata['tel'] as $dat)
309                    {
310                        if(preg_match($params, $dat['number']) === 1)
311                            $found = true;
312                    }
313                    if(!$found)
314                        return false;
315                break;
316            }
317        }
318        return true;
319    }
320
321}
322
323// vim:ts=4:sw=4:et:enc=utf-8:
324