1 |
<?php |
2 |
/**************************************************************************\ |
3 |
* phpGroupWare - InfoLog Links * |
4 |
* http://www.phpgroupware.org * |
5 |
* Written by Ralf Becker <RalfBecker@outdoor-training.de> * |
6 |
* -------------------------------------------- * |
7 |
* This program is free software; you can redistribute it and/or modify it * |
8 |
* under the terms of the GNU General Public License as published by the * |
9 |
* Free Software Foundation; either version 2 of the License, or (at your * |
10 |
* option) any later version. * |
11 |
\**************************************************************************/ |
12 |
|
13 |
/* $Id$ */ |
14 |
|
15 |
include_once(PHPGW_INCLUDE_ROOT . '/infolog/inc/class.solink.inc.php'); |
16 |
|
17 |
$GLOBALS['phpgw_info']['flags']['included_classes']['bolink'] = True; |
18 |
|
19 |
/*! |
20 |
@class bolink |
21 |
@author ralfbecker |
22 |
@copyright GPL - GNU General Public License |
23 |
@abstract generalized linking between entries of phpGroupware apps - BO layer |
24 |
@discussion This class is the BO-layer of the links<br> |
25 |
Links have two ends each pointing to an entry, each entry is a double:<br> |
26 |
app app-name or directory-name of an phpgw application, eg. 'infolog'<br> |
27 |
id this is the id, eg. an integer or a tupple like '0:INBOX:1234'<br> |
28 |
The BO-layer implementes 2 extra features on top of the so-layer:<br> |
29 |
1) It handles links to not already existing entries. This is used by the eTemplate link-widget, which allows to |
30 |
setup links even for new / not already existing entries, before they get saved. |
31 |
In that case you have to set the first id to 0 for the link-function and pass the array returned in that id |
32 |
(not the return-value) after saveing your new entry again to the link function.<br> |
33 |
2) Attaching files: they are saved in the vfs and not the link-table (!). |
34 |
*/ |
35 |
class bolink extends solink |
36 |
{ |
37 |
// other apps can participate in the linking by implementing a search_link hook, which |
38 |
// has to return an array in the format of an app_register entry |
39 |
// |
40 |
var $app_register = array( |
41 |
'addressbook' => array( |
42 |
'query' => 'addressbook_query', |
43 |
'title' => 'addressbook_title', |
44 |
'view' => array( |
45 |
'menuaction' => 'addressbook.uiaddressbook.view' |
46 |
), |
47 |
'view_id' => 'ab_id' |
48 |
), |
49 |
'projects' => array( |
50 |
'query' => 'projects_query', |
51 |
'title' => 'projects_title', |
52 |
'view' => array ( |
53 |
'menuaction' => 'projects.uiprojects.view_project' |
54 |
), |
55 |
'view_id' => 'project_id' |
56 |
), |
57 |
'calendar' => array( |
58 |
'query' => 'calendar_query', |
59 |
'title' => 'calendar_title', |
60 |
'view' => array ( |
61 |
'menuaction' => 'calendar.uicalendar.view' |
62 |
), |
63 |
'view_id' => 'cal_id' |
64 |
), |
65 |
'infolog' => array( |
66 |
'query' => 'infolog.boinfolog.link_query', |
67 |
'title' => 'infolog.boinfolog.link_title', |
68 |
'view' => array( |
69 |
'menuaction' => 'infolog.uiinfolog.index', |
70 |
'action' => 'sp' |
71 |
), |
72 |
'view_id' => 'action_id', |
73 |
), |
74 |
/* |
75 |
'email' => array( |
76 |
'view' => array( |
77 |
'menuaction' => 'email.uimessage.message' |
78 |
), |
79 |
'view_id' => 'msgball[acctnum:folder:msgnum]' // id is a tupple/array, fields separated by ':' |
80 |
), |
81 |
*/ |
82 |
); |
83 |
var $vfs; |
84 |
var $vfs_basedir='/infolog'; // might changes to links if class gets imported in the api |
85 |
var $vfs_appname='file'; // pseudo-appname for own file-attachments in vfs, this is NOT the vfs-app |
86 |
var $valid_pathes = array(); |
87 |
var $send_file_ips = array(); |
88 |
|
89 |
/*! |
90 |
@function bolink |
91 |
@syntax bolink( ) |
92 |
@author ralfbecker |
93 |
@abstract constructor |
94 |
*/ |
95 |
function bolink( ) |
96 |
{ |
97 |
$this->solink( ); // call constructor of derived class |
98 |
$this->public_functions += array( // extend the public_functions of solink |
99 |
'query' => True, |
100 |
'title' => True, |
101 |
'view' => True, |
102 |
'get_file' => True |
103 |
); |
104 |
$this->vfs = CreateObject('infolog.vfs'); |
105 |
|
106 |
$config = CreateObject('phpgwapi.config'); |
107 |
$config->read_repository(); |
108 |
if (is_array($config->config_data)) |
109 |
{ |
110 |
$this->link_pathes = $config->config_data['link_pathes']; |
111 |
$this->send_file_ips = $config->config_data['send_file_ips']; |
112 |
} |
113 |
unset($config); |
114 |
|
115 |
// other apps can participate in the linking by implementing a search_link hook, which |
116 |
// has to return an array in the format of an app_register entry |
117 |
// |
118 |
$search_link_hooks = $GLOBALS['phpgw']->hooks->process('search_link'); |
119 |
if (is_array($search_link_hooks)) |
120 |
{ |
121 |
foreach($search_link_hooks as $app => $data) |
122 |
{ |
123 |
if (is_array($data)) |
124 |
{ |
125 |
$this->app_register[$app] = $data; |
126 |
} |
127 |
} |
128 |
} |
129 |
} |
130 |
|
131 |
/*! |
132 |
@function link |
133 |
@syntax link( $app1,&$id1,$app2,$id2='',$remark='',$user=0 ) |
134 |
@author ralfbecker |
135 |
@abstract creats a link between $app1,$id1 and $app2,$id2 - $id1 does NOT need to exist yet |
136 |
@param $app1 app of $id1 |
137 |
@param $id1 id of item to linkto or 0 if item not yet created or array with links |
138 |
of not created item or $file-array if $app1 == $this->vfs_appname (see below). |
139 |
If $id==0 it will be set on return to an array with the links for the new item. |
140 |
@param $app2 app of 2.linkend or array with links ($id2 not used) |
141 |
@param $id2 id of 2. item of $file-array if $app2 == $this->vfs_appname (see below)<br> |
142 |
$file array with informations about the file in format of the etemplate file-type<br> |
143 |
$file['name'] name of the file (no directory)<br> |
144 |
$file['type'] mine-type of the file<br> |
145 |
$file['tmp_name'] name of the uploaded file (incl. directory)<br> |
146 |
$file['path'] path of the file on the client computer<br> |
147 |
$file['ip'] of the client (path and ip in $file are only needed if u want a symlink (if possible)) |
148 |
@param $remark Remark to be saved with the link (defaults to '') |
149 |
@param $owner Owner of the link (defaults to user) |
150 |
@discussion Does NOT check if link already exists.<br> |
151 |
File-attachments return a negative link-id !!! |
152 |
@result False (for db or param-error) or on success link_id (Please not the return-value of $id1) |
153 |
*/ |
154 |
function link( $app1,&$id1,$app2,$id2='',$remark='',$owner=0,$lastmod=0 ) |
155 |
{ |
156 |
if ($this->debug) |
157 |
{ |
158 |
echo "<p>bolink.link('$app1',$id1,'$app2',$id2,'$remark',$owner,$lastmod)</p>\n"; |
159 |
} |
160 |
if (!$app1 || !$app2 || $app1 == $app2 && $id1 == $id2) |
161 |
{ |
162 |
return False; |
163 |
} |
164 |
if (is_array($id1) || !$id1) // create link only in $id1 array |
165 |
{ |
166 |
if (!is_array($id1)) |
167 |
{ |
168 |
$id1 = array( ); |
169 |
} |
170 |
$link_id = $app2 != $this->vfs_appname ? "$app2:$id2" : "$app2:$id2[name]"; |
171 |
$id1[$link_id] = array( |
172 |
'app' => $app2, |
173 |
'id' => $id2, |
174 |
'remark' => $remark, |
175 |
'owner' => $owner, |
176 |
'link_id' => $link_id, |
177 |
'lastmod' => time() |
178 |
); |
179 |
if ($this->debug) |
180 |
{ |
181 |
_debug_array($id1); |
182 |
} |
183 |
return $link_id; |
184 |
} |
185 |
if (is_array($app2) && !$id2) |
186 |
{ |
187 |
reset($app2); |
188 |
$link_id = True; |
189 |
while ($link_id && list(,$link) = each($app2)) |
190 |
{ |
191 |
if (!is_array($link)) // check for unlink-marker |
192 |
{ |
193 |
continue; |
194 |
} |
195 |
if ($link['app'] == $this->vfs_appname) |
196 |
{ |
197 |
$link_id = -intval($this->attach_file($app1,$id1,$link['id'],$link['remark'])); |
198 |
} |
199 |
else |
200 |
{ |
201 |
$link_id = solink::link($app1,$id1,$link['app'],$link['id'], |
202 |
$link['remark'],$link['owner'],$link['lastmod']); |
203 |
} |
204 |
} |
205 |
return $link_id; |
206 |
} |
207 |
if ($app1 == $this->vfs_appname) |
208 |
{ |
209 |
return -intval($this->attach_file($app2,$id2,$id1,$remark)); |
210 |
} |
211 |
elseif ($app2 == $this->vfs_appname) |
212 |
{ |
213 |
return -intval($this->attach_file($app1,$id1,$id2,$remark)); |
214 |
} |
215 |
return solink::link($app1,$id1,$app2,$id2,$remark,$owner); |
216 |
} |
217 |
|
218 |
/*! |
219 |
@function get_links |
220 |
@syntax get_links( $app,$id,$only_app='',$only_name='',$order='link_lastmod DESC' ) |
221 |
@author ralfbecker |
222 |
@abstract returns array of links to $app,$id (reimplemented to deal with not yet created items) |
223 |
@param $id id of entry in $app or array of links if entry not yet created |
224 |
@param $only_app if set return only links from $only_app (eg. only addressbook-entries) or NOT from if $only_app[0]=='!' |
225 |
@param $order defaults to newest links first |
226 |
@result array of links or empty array if no matching links found |
227 |
*/ |
228 |
function get_links( $app,$id,$only_app='',$order='link_lastmod DESC' ) |
229 |
{ |
230 |
if (is_array($id) || !$id) |
231 |
{ |
232 |
$ids = array(); |
233 |
if (is_array($id)) |
234 |
{ |
235 |
if ($not_only = $only_app[0]) |
236 |
{ |
237 |
$only_app = substr(1,$only_app); |
238 |
} |
239 |
end($id); |
240 |
while ($link = current($id)) |
241 |
{ |
242 |
if (!is_array($link) || // check for unlink-marker |
243 |
$only_app && $not_only == ($link['app'] == $only_app)) |
244 |
{ |
245 |
continue; |
246 |
} |
247 |
$ids[$link['link_id']] = $link; |
248 |
prev($id); |
249 |
} |
250 |
} |
251 |
return $ids; |
252 |
} |
253 |
$ids = solink::get_links($app,$id,$only_app,$order); |
254 |
|
255 |
if (empty($only_apps) || $only_apps == $this->vfs_appname || |
256 |
($only_app[0] == '!' && $only_app != '!'.$this->vfs_appname)) |
257 |
{ |
258 |
if ($vfs_ids = $this->list_attached($app,$id)) |
259 |
{ |
260 |
$ids += $vfs_ids; |
261 |
} |
262 |
} |
263 |
return $ids; |
264 |
} |
265 |
|
266 |
/*! |
267 |
@function get_link |
268 |
@syntax get_link( $app_link_id,$id='',$app2='',$id2='' ) |
269 |
@author ralfbecker |
270 |
@abstract returns data of a link |
271 |
@param $app_link_id > 0 link_id of link or app-name of link |
272 |
@param $id,$app2,$id2 other param of the link if not link_id given |
273 |
@result array with link-data or False |
274 |
@discussion If $id is an array (links not yet created) only link_ids are allowed. |
275 |
*/ |
276 |
function get_link($app_link_id,$id='',$app2='',$id2='') |
277 |
{ |
278 |
if (is_array($id)) |
279 |
{ |
280 |
if (isset($id[$app_link_id]) && is_array($id[$app_link_id])) // check for unlinked-marker |
281 |
{ |
282 |
return $id[$app_link_id]; |
283 |
} |
284 |
return False; |
285 |
} |
286 |
if (intval($app_link_id) < 0 || $app_link_id == $this->vfs_appname || $app2 == $this->vfs_appname) |
287 |
{ |
288 |
if (intval($app_link_id) < 0) // vfs link_id ? |
289 |
{ |
290 |
return $this->fileinfo2link(-$app_link_id); |
291 |
} |
292 |
if ($app_link_id == $this->vfs_appname) |
293 |
{ |
294 |
return $this->info_attached($app2,$id2,$id); |
295 |
} |
296 |
return $this->info_attached($app_link_id,$id,$id2); |
297 |
} |
298 |
return solink::get_link($app_link_id,$id,$app2,$id2); |
299 |
} |
300 |
|
301 |
/*! |
302 |
@function unlink |
303 |
@syntax unlink( $link_id,$app='',$id='',$owner='',$app2='',$id2='' ) |
304 |
@author ralfbecker |
305 |
@abstract Remove link with $link_id or all links matching given $app,$id |
306 |
@param $link_id link-id to remove if > 0 |
307 |
@param $app,$id,$owner,$app2,$id2 if $link_id <= 0: removes all links matching the non-empty params |
308 |
@discussion Note: if $link_id != '' and $id is an array: unlink removes links from that array only |
309 |
unlink has to be called with &$id so see the result !!! |
310 |
@result the number of links deleted |
311 |
*/ |
312 |
function unlink($link_id,$app='',$id='',$owner='',$app2='',$id2='') |
313 |
{ |
314 |
if ($link_id < 0) // vfs-link? |
315 |
{ |
316 |
return $this->delete_attached(-$link_id); |
317 |
} |
318 |
elseif ($app == $this->vfs_appname) |
319 |
{ |
320 |
return $this->delete_attached($app2,$id2,$id); |
321 |
} |
322 |
elseif ($app2 == $this->vfs_appname) |
323 |
{ |
324 |
return $this->delete_attached($app,$id,$id2); |
325 |
} |
326 |
if ($link_id > 0 || !is_array($id)) |
327 |
{ |
328 |
return solink::unlink($link_id,$app,$id,$owner,$app2,$id2); |
329 |
} |
330 |
if (isset($id[$link_id])) |
331 |
{ |
332 |
$id[$link_id] = False; // set the unlink marker |
333 |
|
334 |
return True; |
335 |
} |
336 |
return False; |
337 |
} |
338 |
|
339 |
/*! |
340 |
@function app_list |
341 |
@syntax app_list( ) |
342 |
@author ralfbecker |
343 |
@abstract get list/array of link-aware apps the user has rights to use |
344 |
@result array( $app => lang($app), ... ) |
345 |
*/ |
346 |
function app_list( ) |
347 |
{ |
348 |
reset ($this->app_register); |
349 |
$apps = array(); |
350 |
while (list($app,$reg) = each($this->app_register)) |
351 |
{ |
352 |
if ($GLOBALS['phpgw_info']['user']['apps'][$app]) |
353 |
{ |
354 |
$apps[$app] = $GLOBALS['phpgw_info']['apps'][$app]['title']; |
355 |
} |
356 |
} |
357 |
return $apps; |
358 |
} |
359 |
|
360 |
/*! |
361 |
@function query |
362 |
@syntax query( $app,$pattern ) |
363 |
@author ralfbecker |
364 |
@abstract Searches for a $pattern in the entries of $app |
365 |
@result an array of $id => $title pairs |
366 |
*/ |
367 |
function query($app,$pattern) |
368 |
{ |
369 |
if ($app == '' || !is_array($reg = $this->app_register[$app]) || !isset($reg['query'])) |
370 |
{ |
371 |
return array(); |
372 |
} |
373 |
$method = $reg['query']; |
374 |
|
375 |
if ($this->debug) |
376 |
{ |
377 |
echo "<p>bolink.query('$app','$pattern') => '$method'</p>\n"; |
378 |
} |
379 |
return strchr($method,'.') ? ExecMethod($method,$pattern) : $this->$method($pattern); |
380 |
} |
381 |
|
382 |
/*! |
383 |
@function title |
384 |
@syntax title( $app,$id ) |
385 |
@author ralfbecker |
386 |
@abstract returns the title (short description) of entry $id and $app |
387 |
@result the title |
388 |
*/ |
389 |
function title($app,$id,$link='') |
390 |
{ |
391 |
if ($this->debug) |
392 |
{ |
393 |
echo "<p>bolink::title('$app','$id')</p>\n"; |
394 |
} |
395 |
if ($app == $this->vfs_appname) |
396 |
{ |
397 |
if (is_array($id) && $link) |
398 |
{ |
399 |
$link = $id; |
400 |
$id = $link['name']; |
401 |
} |
402 |
if (is_array($link)) |
403 |
{ |
404 |
$size = $link['size']; |
405 |
if ($size_k = intval($size / 1024)) |
406 |
{ |
407 |
if (intval($size_k / 1024)) |
408 |
{ |
409 |
$size = sprintf('%3.1dM',doubleval($size_k)/1024.0); |
410 |
} |
411 |
else |
412 |
{ |
413 |
$size = $size_k.'k'; |
414 |
} |
415 |
} |
416 |
$extra = ': '.$link['type'] . ' '.$size; |
417 |
} |
418 |
return $id.$extra; |
419 |
} |
420 |
if ($app == '' || !is_array($reg = $this->app_register[$app]) || !isset($reg['title'])) |
421 |
{ |
422 |
return array(); |
423 |
} |
424 |
$method = $reg['title']; |
425 |
|
426 |
return strchr($method,'.') ? ExecMethod($method,$id) : $this->$method($id); |
427 |
} |
428 |
|
429 |
/*! |
430 |
@function view |
431 |
@syntax view( $app,$id ) |
432 |
@author ralfbecker |
433 |
@abstract view entry $id of $app |
434 |
@result array with name-value pairs for link to view-methode of $app to view $id |
435 |
*/ |
436 |
function view($app,$id,$link='') |
437 |
{ |
438 |
if ($app == $this->vfs_appname && !empty($id) && is_array($link)) |
439 |
{ |
440 |
return $this->get_file($link); |
441 |
} |
442 |
if ($app == '' || !is_array($reg = $this->app_register[$app]) || !isset($reg['view']) || !isset($reg['view_id'])) |
443 |
{ |
444 |
return array(); |
445 |
} |
446 |
$view = $reg['view']; |
447 |
|
448 |
$names = explode(':',$reg['view_id']); |
449 |
if (count($names) > 1) |
450 |
{ |
451 |
$id = explode(':',$id); |
452 |
while (list($n,$name) = each($names)) |
453 |
{ |
454 |
$view[$name] = $id[$n]; |
455 |
} |
456 |
} |
457 |
else |
458 |
{ |
459 |
$view[$reg['view_id']] = $id; |
460 |
} |
461 |
return $view; |
462 |
} |
463 |
|
464 |
function get_file($link='') |
465 |
{ |
466 |
if (is_array($link)) |
467 |
{ |
468 |
return array( |
469 |
'menuaction' => 'infolog.bolink.get_file', |
470 |
'app' => $link['app2'], |
471 |
'id' => $link['id2'], |
472 |
'filename' => $link['id'] |
473 |
); |
474 |
} |
475 |
$app = get_var('app','GET'); |
476 |
$id = get_var('id','GET'); |
477 |
$filename = get_var('filename','GET'); |
478 |
|
479 |
if (empty($app) || empty($id) || empty($filename) /* || !$this->bo->check_access($info_id,PHPGW_ACL_READ)*/) |
480 |
{ |
481 |
$GLOBALS['phpgw']->redirect_link('/'); |
482 |
} |
483 |
$browser = CreateObject('phpgwapi.browser'); |
484 |
|
485 |
$local = $this->attached_local($app,$id,$filename, |
486 |
get_var('REMOTE_ADDR',Array('SERVER')),$browser->is_windows()); |
487 |
|
488 |
if ($local) |
489 |
{ |
490 |
Header('Location: ' . $local); |
491 |
} |
492 |
else |
493 |
{ |
494 |
$info = $this->info_attached($app,$id,$filename); |
495 |
$browser->content_header($filename,$info['type']); |
496 |
echo $this->read_attached($app,$id,$filename); |
497 |
} |
498 |
$GLOBALS['phpgw']->common->phpgw_exit(); |
499 |
} |
500 |
|
501 |
/*! |
502 |
@function vfs_path |
503 |
@syntax vfs_path ( $app,$id,$file='' ) |
504 |
@abstract path to the attached files of $app/$ip |
505 |
@discussion All link-files are based in the vfs-subdir 'infolog'. For other apps |
506 |
@discussion separate subdirs with name app are created. |
507 |
*/ |
508 |
function vfs_path($app,$id='',$file='') |
509 |
{ |
510 |
$path = $this->vfs_basedir . ($app == '' || $app == 'infolog' ? '' : '/'.$app) . |
511 |
($id != '' ? '/' . $id : '') . ($file != '' ? '/' . $file : ''); |
512 |
|
513 |
if ($this->debug) |
514 |
{ |
515 |
echo "<p>bolink::vfs_path('$app','$id','$file') = '$path'</p>\n"; |
516 |
} |
517 |
return $path; |
518 |
} |
519 |
|
520 |
/*! |
521 |
@function attach_file |
522 |
@syntax attach_file ( $app,$id,$file,$comment='' ) |
523 |
@abstract Put a file to the corrosponding place in the VFS and set the attributes |
524 |
@param $app/$id entry which should the file should be linked with |
525 |
@param $file array with informations about the file in format of the etemplate file-type |
526 |
$file['name'] name of the file (no directory) |
527 |
$file['type'] mine-type of the file |
528 |
$file['tmp_name'] name of the uploaded file (incl. directory) |
529 |
$file['path'] path of the file on the client computer |
530 |
$file['ip'] of the client (path and ip are only needed if u want a symlink (if possible)) |
531 |
@param $comment |
532 |
*/ |
533 |
function attach_file($app,$id,$file,$comment='') |
534 |
{ |
535 |
if ($this->debug) |
536 |
{ |
537 |
echo "<p>attach_file: app='$app', id='$id', tmp_name='$file[tmp_name]', name='$file[name]', size='$file[size]', type='$file[type]', path='$file[path]', ip='$file[ip]', comment='$comment'</p>\n"; |
538 |
} |
539 |
// create the root for attached files in infolog, if it does not exists |
540 |
if (!($this->vfs->file_exists($this->vfs_basedir,array(RELATIVE_ROOT)))) |
541 |
{ |
542 |
$this->vfs->override_acl = 1; |
543 |
$this->vfs->mkdir($this->vfs_basedir,array(RELATIVE_ROOT)); |
544 |
$this->vfs->override_acl = 0; |
545 |
} |
546 |
|
547 |
$dir=$this->vfs_path($app); |
548 |
if (!($this->vfs->file_exists($dir,array(RELATIVE_ROOT)))) |
549 |
{ |
550 |
$this->vfs->override_acl = 1; |
551 |
$this->vfs->mkdir($dir,array(RELATIVE_ROOT)); |
552 |
$this->vfs->override_acl = 0; |
553 |
} |
554 |
$dir=$this->vfs_path($app,$id); |
555 |
if (!($this->vfs->file_exists($dir,array(RELATIVE_ROOT)))) |
556 |
{ |
557 |
$this->vfs->override_acl = 1; |
558 |
$this->vfs->mkdir($dir,array(RELATIVE_ROOT)); |
559 |
$this->vfs->override_acl = 0; |
560 |
} |
561 |
$fname = $this->vfs_path($app,$id,$file['name']); |
562 |
$tfname = ''; |
563 |
if (!empty($file['path'])) |
564 |
{ |
565 |
$file['path'] = str_replace('\\\\','/',$file['path']); // vfs uses only '/' |
566 |
@reset($this->link_pathes); |
567 |
while ((list($valid,$trans) = @each($this->link_pathes)) && !$tfname) |
568 |
{ // check case-insensitive for WIN etc. |
569 |
$check = $valid[0] == '\\' || strstr(':',$valid) ? 'eregi' : 'ereg'; |
570 |
$valid2 = str_replace('\\','/',$valid); |
571 |
//echo "<p>attach_file: ereg('".$this->send_file_ips[$valid]."', '$file[ip]')=".ereg($this->send_file_ips[$valid],$file['ip'])."</p>\n"; |
572 |
if ($check('^('.$valid2.')(.*)$',$file['path'],$parts) && |
573 |
ereg($this->send_file_ips[$valid],$file['ip']) && // right IP |
574 |
$this->vfs->file_exists($trans.$parts[2],array(RELATIVE_NONE|VFS_REAL))) |
575 |
{ |
576 |
$tfname = $trans.$parts[2]; |
577 |
} |
578 |
//echo "<p>attach_file: full_fname='$file[path]', valid2='$valid2', trans='$trans', check=$check, tfname='$tfname', parts=(x,'${parts[1]}','${parts[2]}')</p>\n"; |
579 |
} |
580 |
if ($tfname && !$this->vfs->securitycheck($tfname)) |
581 |
{ |
582 |
return False; //lang('Invalid filename').': '.$tfname; |
583 |
} |
584 |
} |
585 |
$this->vfs->override_acl = 1; |
586 |
if ($tfname) // file is local |
587 |
{ |
588 |
$this->vfs->symlink($tfname,$fname,array(RELATIVE_NONE|VFS_REAL,RELATIVE_ROOT)); |
589 |
} |
590 |
else |
591 |
{ |
592 |
$this->vfs->cp($file['tmp_name'],$fname,array(RELATIVE_NONE|VFS_REAL,RELATIVE_ROOT)); |
593 |
} |
594 |
$this->vfs->set_attributes ($fname, array (RELATIVE_ROOT), |
595 |
array ('mime_type' => $file['type'], |
596 |
'comment' => stripslashes ($comment), |
597 |
'app' => $app)); |
598 |
$this->vfs->override_acl = 0; |
599 |
|
600 |
$link = $this->info_attached($app,$id,$file['name']); |
601 |
return is_array($link) ? $link['file_id'] : False; |
602 |
} |
603 |
|
604 |
/*! |
605 |
@function delete_attached |
606 |
@syntax delete_attached( $app,$id,$filename ) |
607 |
@author ralfbecker |
608 |
@abstract deletes an attached file |
609 |
@param $app > 0: file_id of an attchemnt or $app/$id entry which linked to |
610 |
@param $filename |
611 |
*/ |
612 |
function delete_attached($app,$id='',$fname = '') |
613 |
{ |
614 |
if (intval($app) > 0) // is file_id |
615 |
{ |
616 |
$link = $this->fileinfo2link($file_id=$app); |
617 |
$app = $link['app2']; |
618 |
$id = $link['id2']; |
619 |
$fname = $link['id']; |
620 |
} |
621 |
if ($this->debug) |
622 |
{ |
623 |
echo "<p>bolink::delete_attached('$app','$id','$fname') file_id=$file_id</p>\n"; |
624 |
} |
625 |
if (empty($app) || empty($id)) |
626 |
{ |
627 |
return False; // dont delete more than all attachments of an entry |
628 |
} |
629 |
$file = $this->vfs_path($app,$id,$fname); |
630 |
|
631 |
if ($this->vfs->file_exists($file,array(RELATIVE_ROOT))) |
632 |
{ |
633 |
$this->vfs->override_acl = 1; |
634 |
$Ok = $this->vfs->delete($file,array(RELATIVE_ROOT)); |
635 |
$this->vfs->override_acl = 0; |
636 |
return $Ok; |
637 |
} |
638 |
return False; |
639 |
} |
640 |
|
641 |
/*! |
642 |
@function info_attached |
643 |
@syntax info_attached( $app,$id,$filename ) |
644 |
@author ralfbecker |
645 |
@abstract converts the infos vfs has about a file into a link |
646 |
@param $app/$id entry which linked to |
647 |
@param $filename |
648 |
@returns a 'kind' of link-array |
649 |
*/ |
650 |
function info_attached($app,$id,$filename) |
651 |
{ |
652 |
$this->vfs->override_acl = 1; |
653 |
$attachments = $this->vfs->ls($this->vfs_path($app,$id,$filename),array(REALTIVE_NONE)); |
654 |
$this->vfs->override_acl = 0; |
655 |
|
656 |
if (!count($attachments) || !$attachments[0]['name']) |
657 |
{ |
658 |
return False; |
659 |
} |
660 |
return $this->fileinfo2link($attachments[0]); |
661 |
} |
662 |
|
663 |
/*! |
664 |
@function fileinfo2link |
665 |
@syntax fileinfo2link( $fileinfo ) |
666 |
@author ralfbecker |
667 |
@abstract converts a fileinfo (row in the vfs-db-table) in a link |
668 |
@param $fileinfo a row from the vfs-db-table (eg. returned by the vfs ls function) |
669 |
or a file_id of that table |
670 |
@returns a 'kind' of link-array |
671 |
*/ |
672 |
function fileinfo2link($fileinfo) |
673 |
{ |
674 |
if (!is_array($fileinfo)) |
675 |
{ |
676 |
$fileinfo = $this->vfs->fileinfo($fileinfo); |
677 |
list(,$fileinfo) = each($fileinfo); |
678 |
|
679 |
if (!is_array($fileinfo)) |
680 |
{ |
681 |
return False; |
682 |
} |
683 |
} |
684 |
$lastmod = $fileinfo[!empty($fileinfo['modified']) ? 'modified' : 'created']; |
685 |
list($y,$m,$d) = explode('-',$lastmod); |
686 |
$lastmod = mktime(0,0,0,$m,$d,$y); |
687 |
|
688 |
$dir_parts = array_reverse(explode('/',$fileinfo['directory'])); |
689 |
|
690 |
return array( |
691 |
'app' => $this->vfs_appname, |
692 |
'id' => $fileinfo['name'], |
693 |
'app2' => $dir_parts[1], |
694 |
'id2' => $dir_parts[0], |
695 |
'remark' => $fileinfo['comment'], |
696 |
'owner' => $fileinfo['owner_id'], |
697 |
'link_id' => -$fileinfo['file_id'], |
698 |
'lastmod' => $lastmod, |
699 |
'size' => $fileinfo['size'], |
700 |
'type' => $fileinfo['mime_type'] |
701 |
); |
702 |
} |
703 |
|
704 |
/*! |
705 |
@function list_attached |
706 |
@syntax list_attached( $app,$id ) |
707 |
@author ralfbecker |
708 |
@abstract lists all attachments to $app/$id |
709 |
@returns a 'kind' of link-array |
710 |
*/ |
711 |
function list_attached($app,$id) |
712 |
{ |
713 |
$this->vfs->override_acl = 1; |
714 |
$attachments = $this->vfs->ls($this->vfs_path($app,$id),array(REALTIVE_NONE)); |
715 |
$this->vfs->override_acl = 0; |
716 |
|
717 |
if (!count($attachments) || !$attachments[0]['name']) |
718 |
{ |
719 |
return False; |
720 |
} |
721 |
while (list(,$fileinfo) = each($attachments)) |
722 |
{ |
723 |
$link = $this->fileinfo2link($fileinfo); |
724 |
$attached[$link['link_id']] = $link; |
725 |
} |
726 |
return $attached; |
727 |
} |
728 |
|
729 |
/*! |
730 |
@function is_win_path |
731 |
@syntax is_win_path( $path ) |
732 |
@author ralfbecker |
733 |
@abstract checks if path starts with a '\\' or has a ':' in it |
734 |
*/ |
735 |
function is_win_path($path) |
736 |
{ |
737 |
return $path[0] == '\\' || strstr($path,':'); |
738 |
} |
739 |
|
740 |
/*! |
741 |
@function read_attached |
742 |
@syntax read_attached($app,$id,$filename) |
743 |
@author ralfbecker |
744 |
@abstract reads the attached file and returns the content |
745 |
*/ |
746 |
function read_attached($app,$id,$filename) |
747 |
{ |
748 |
if (empty($app) || !$id || empty($filename) /*|| !$this->check_access($info_id,PHPGW_ACL_READ)*/) |
749 |
{ |
750 |
return False; |
751 |
} |
752 |
$this->vfs->override_acl = 1; |
753 |
return $this->vfs->read($this->vfs_path($app,$id,$filename),array(RELATIVE_ROOT)); |
754 |
} |
755 |
|
756 |
/*! |
757 |
@function attached_local |
758 |
@syntax attached_local($app,$id,$filename,$ip,$win_user) |
759 |
@author ralfbecker |
760 |
@abstract Checks if filename should be local availible and if so returns |
761 |
@abstract 'file:/path' for HTTP-redirect else return False |
762 |
*/ |
763 |
function attached_local($app,$id,$filename,$ip,$win_user) |
764 |
{ |
765 |
//echo "<p>attached_local(app=$app, id='$id', filename='$filename', ip='$ip', win_user='$win_user', count(send_file_ips)=".count($this->send_file_ips).")</p>\n"; |
766 |
|
767 |
if (!$id || !$filename || /* !$this->check_access($info_id,PHPGW_ACL_READ) || */ |
768 |
!count($this->send_file_ips)) |
769 |
{ |
770 |
return False; |
771 |
} |
772 |
$link = $this->vfs->readlink ($this->vfs_path($app,$id,$filename), array (RELATIVE_ROOT)); |
773 |
|
774 |
if ($link && is_array($this->link_pathes)) |
775 |
{ |
776 |
reset($this->link_pathes); $fname = ''; |
777 |
while ((list($valid,$trans) = each($this->link_pathes)) && !$fname) |
778 |
{ |
779 |
if (!$this->is_win_path($valid) == !$win_user && // valid for this OS |
780 |
eregi('^'.$trans.'(.*)$',$link,$parts) && // right path |
781 |
ereg($this->send_file_ips[$valid],$ip)) // right IP |
782 |
{ |
783 |
$fname = $valid . $parts[1]; |
784 |
$fname = !$win_user ? str_replace('\\','/',$fname) : str_replace('/','\\',$fname); |
785 |
return 'file:'.($win_user ? '//' : '' ).$fname; |
786 |
} |
787 |
// echo "<p>attached_local: link=$link, valid=$valid, trans='$trans', fname='$fname', parts=(x,'${parts[1]}','${parts[2]}')</p>\n"; |
788 |
} |
789 |
} |
790 |
return False; |
791 |
} |
792 |
|
793 |
/*! |
794 |
@function calendar_title |
795 |
@syntax calendar_title( $id ) |
796 |
@author ralfbecker |
797 |
@abstract get title for an event, should be moved to bocalendar.link_title |
798 |
*/ |
799 |
function calendar_title( $event ) |
800 |
{ |
801 |
if (!is_object($this->bocal)) |
802 |
{ |
803 |
$this->bocal = createobject('calendar.bocalendar'); |
804 |
} |
805 |
if (!is_array($event) && (int) $event > 0) |
806 |
{ |
807 |
$event = $this->bocal->read_entry($event); |
808 |
} |
809 |
if (!is_array($event)) |
810 |
{ |
811 |
return 'not an event !!!'; |
812 |
} |
813 |
$name = $GLOBALS['phpgw']->common->show_date($this->bocal->maketime($event['start']) - $this->bocal->datetime->tz_offset); |
814 |
$name .= ' -- ' . $GLOBALS['phpgw']->common->show_date($this->bocal->maketime($event['end']) - $this->bocal->datetime->tz_offset); |
815 |
$name .= ': ' . $event['title']; |
816 |
|
817 |
return $GLOBALS['phpgw']->strip_html($name); |
818 |
} |
819 |
|
820 |
/*! |
821 |
@function calendar_query |
822 |
@syntax calendar_query( $pattern ) |
823 |
@author ralfbecker |
824 |
@abstract query calendar for an event $matching pattern, should be moved to bocalendar.link_query |
825 |
*/ |
826 |
function calendar_query($pattern) |
827 |
{ |
828 |
if (!is_object($this->bocal)) |
829 |
{ |
830 |
$this->bocal = createobject('calendar.bocalendar'); |
831 |
} |
832 |
$event_ids = $this->bocal->search_keywords($pattern); |
833 |
|
834 |
$content = array( ); |
835 |
while (is_array($event_ids) && list( $key,$id ) = each( $event_ids )) |
836 |
{ |
837 |
$content[$id] = $this->calendar_title( $id ); |
838 |
} |
839 |
return $content; |
840 |
} |
841 |
|
842 |
/*! |
843 |
@function addressbook_title |
844 |
@syntax addressbook_title( $id ) |
845 |
@author ralfbecker |
846 |
@abstract get title for an address, should be moved to boaddressbook.link_title |
847 |
*/ |
848 |
function addressbook_title( $addr ) |
849 |
{ |
850 |
if (!is_object($this->contacts)) |
851 |
{ |
852 |
$this->contacts = createobject('phpgwapi.contacts'); |
853 |
} |
854 |
if (!is_array($addr)) |
855 |
{ |
856 |
list( $addr ) = $this->contacts->read_single_entry( $addr ); |
857 |
} |
858 |
$name = $addr['n_family']; |
859 |
if ($addr['n_given']) |
860 |
{ |
861 |
$name .= ', '.$addr['n_given']; |
862 |
} |
863 |
else |
864 |
{ |
865 |
if ($addr['n_prefix']) |
866 |
{ |
867 |
$name .= ', '.$addr['n_prefix']; |
868 |
} |
869 |
} |
870 |
if ($addr['org_name']) |
871 |
{ |
872 |
$name = $addr['org_name'].': '.$name; |
873 |
} |
874 |
return $GLOBALS['phpgw']->strip_html($name); |
875 |
} |
876 |
|
877 |
/*! |
878 |
@function addressbook_query |
879 |
@syntax addressbook_query( $pattern ) |
880 |
@author ralfbecker |
881 |
@abstract query addressbook for $pattern, should be moved to boaddressbook.link_query |
882 |
*/ |
883 |
function addressbook_query( $pattern ) |
884 |
{ |
885 |
if (!is_object($this->contacts)) |
886 |
{ |
887 |
$this->contacts = createobject('phpgwapi.contacts'); |
888 |
} |
889 |
$addrs = $this->contacts->read( 0,0,'',$pattern,'','DESC','org_name,n_family,n_given' ); |
890 |
$content = array( ); |
891 |
while ($addrs && list( $key,$addr ) = each( $addrs )) |
892 |
{ |
893 |
$content[$addr['id']] = $this->addressbook_title( $addr ); |
894 |
} |
895 |
return $content; |
896 |
} |
897 |
|
898 |
/*! |
899 |
@function projects_title |
900 |
@syntax projects_title( $id ) |
901 |
@author ralfbecker |
902 |
@abstract get title for a project, should be moved to boprojects.link_title |
903 |
*/ |
904 |
function projects_title( $proj ) |
905 |
{ |
906 |
if (!is_object($this->boprojects)) |
907 |
{ |
908 |
if (!file_exists(PHPGW_SERVER_ROOT.'/projects')) // check if projects installed |
909 |
return ''; |
910 |
$this->boprojects = createobject('projects.boprojects'); |
911 |
} |
912 |
if (!is_array($proj)) |
913 |
{ |
914 |
$proj = $this->boprojects->read_single_project( $proj ); |
915 |
} |
916 |
return $proj['title']; |
917 |
} |
918 |
|
919 |
/*! |
920 |
@function projects_query |
921 |
@syntax projects_query( $pattern ) |
922 |
@author ralfbecker |
923 |
@abstract query for projects matching $pattern, should be moved to boprojects.link_query |
924 |
*/ |
925 |
function projects_query( $pattern ) |
926 |
{ |
927 |
if (!is_object($this->boprojects)) |
928 |
{ |
929 |
if (!file_exists(PHPGW_SERVER_ROOT.'/projects')) // check if projects installed |
930 |
return array(); |
931 |
$this->boprojects = createobject('projects.boprojects'); |
932 |
} |
933 |
$projs = $this->boprojects->list_projects( 0,0,$pattern,'','','','',0,'mains','' ); |
934 |
$content = array(); |
935 |
while ($projs && list( $key,$proj ) = each( $projs )) |
936 |
{ |
937 |
$content[$proj['project_id']] = $this->projects_title($proj); |
938 |
} |
939 |
return $content; |
940 |
} |
941 |
} |
942 |
|
943 |
|
944 |
|
945 |
|