1 /* Copyright (C) 2000-2007 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: filepath.pike,v 1.3 2010/08/20 20:42:25 astra Exp $
19 inherit "/kernel/module";
20 inherit "/kernel/orb";
27 #include <attributes.h>
28 //! This module represents an ORB which converts a given pathname to
29 //! an sTeam object by using the structure of environment/inventory or
32 //! There are several different trees with the
33 //! roots "/", "~user" or "/home/user".
34 class filepath : public module,orb{
41 //#define FILEPATH_DEBUG
44 #define DEBUG_FILEPATH(s,args...) werror(s+"\n",args)
46 #define DEBUG_FILEPATH(s,args...)
49 #define MODE_ANNOTATE 1
50 #define MODE_VERSION 2
54 mapping mPathCache = ([ ]);
57 * Initialize the module. This time only the description attributes is set.
63 set_attribute(OBJ_DESC,"This is the filepath object for simulating "+
64 "a filepath in steam. It works by traversing through rooms in rooms/"+
65 "containers in containers starting from the Users "+
66 "and Groups workrooms");
71 void post_load_module() {
72 db_handle = _Database->get_db_handle();
76 * Convert a given path to ~ syntax to retrieve a user or a workarea.
78 * @param string path - the path to convert.
79 * @return user or workarea object or 0.
81 object get_tilde(string path)
86 DEBUG_FILEPATH("get_tilde("+path+")");
87 if ( sscanf(path, "~%ss workroom", user) > 0 )
91 uid = MODULE_USERS->lookup(user);
92 if ( !objectp(uid) ) {
93 uid = MODULE_GROUPS->lookup(user);
96 workroom = uid->query_attribute(GROUP_WORKROOM);
99 workroom = uid->query_attribute(USER_WORKROOM);
101 DEBUG_FILEPATH("Returning workroom="+workroom->get_object_id());
104 else if ( sscanf(path, "~%s", user) > 0 )
106 // object is the user
107 uid = MODULE_USERS->lookup(user);
109 uid = MODULE_GROUPS->lookup(user);
115 object get_annotation_on_obj(object obj, string name)
117 return obj->get_annotation_byid(name);
120 object get_version_of_obj(object obj, string name)
127 * @param cont - the container
128 * @param obj_name - path to object name (only one token: container or object)
129 * @return the appropriate object in the container
133 get_object_in_cont(object cont, string obj_name)
137 DEBUG_FILEPATH("get_object_in_cont("+cont->get_identifier()+","+
140 if ( !objectp(cont) )
142 if ( strlen(obj_name) > 0 && obj_name[0] == '~' )
143 return get_tilde(obj_name);
145 obj = cont->get_object_byname(obj_name);
150 * Get an array of objects which represent the environment of the environment
151 * (and so on) of the given object.
153 * @param object obj - the object to retrieve the environment hierarchy for.
154 * @return array of objects which represent the path to environment = null.
156 array object_to_environment_path(object obj)
158 array objects = ({ });
160 object current = obj;
161 object env = obj->get_environment();
162 while ( objectp(env) ) {
163 DEBUG_FILEPATH("object_to_environment_path: " + obj->query_attribute(OBJ_NAME));
164 objects = ({ env }) + objects;
166 env = current->get_environment();
168 // check root object if it is a workroom
169 if ( stringp(check_tilde(current)) )
170 objects = ({ _Server->get_module("home") }) + objects;
176 * resolves a given path, by starting with container uid and
177 * traversing through the tree to find the appropriate object
179 * @param uid - the user logged in (for ~ syntax) or null
180 * @param path - path to an object
182 * @see object_to_path
183 * @see path_to_object
185 object resolve_path(string|object env, string path, void|int rs_links)
190 if (!objectp(env) && !stringp(env)) {
191 env = MODULE_OBJECTS->lookup("rootroom");
192 if ( !objectp(env) ) {
193 FATAL("Root-Room is null on resolve_path()...");
197 else if (objectp(env)) {
198 path = Stdio.append_path(object_to_filename(env), path);
200 else if (stringp(env)) {
201 path = Stdio.append_path(env, path);
204 if ( !stringp(path) || strlen(path) == 0 || path == "/" ) {
208 return path_to_object(env);
211 if ( path[0] != '/' )
213 if ( path[-1] == '/' )
214 path = path[..strlen(path)-2];
216 // FIXME: why is there a db search done here? it matches objects on / that are otherwise expected to be found in env
217 if (objectp(db_handle)) {
219 string query = "select ob_id from ob_data where ob_attr='OBJ_PATH' and ob_data='\""+db_handle->quote(path)+"\"'";
220 Sql.sql_result res = db_handle->big_query(query);
221 if (objectp(res) && res->num_rows() == 1) {
222 mixed row = res->fetch_row();
223 return find_object((int)row[0]);
227 FATAL("Error while resolving path: %O\n%O", err[0], err[1]);
230 path = Stdio.append_path(path, "");
233 env = path_to_object(env);
236 array tokens = path / "/";
237 for ( mode = 0, i = 1; i < sizeof(tokens); i++ ) {
238 string token = tokens[i];
239 if (!objectp(env) ) return 0;
242 env = get_annotation_on_obj(env, token);
245 env = get_version_of_obj(env, token);
248 env = get_object_in_cont(env, token);
250 if ( objectp(env) ) {
251 // if links should be resolved...
253 if ( env->get_object_class() & CLASS_EXIT )
254 env = env->get_exit();
255 else if ( env->get_object_class() & CLASS_LINK )
256 env = env->get_link_object();
260 else if ( token == "annotations" ) {
261 mode = MODE_ANNOTATE;
262 env = obj; // fall back to object in annotate mode!
264 else if ( token == "versions" ) {
272 * Resolve a path. The ~ syntax will be converted to user/path.
273 * additionally the __oid syntax is understood by this function.
275 * @param path - the path to convert to an object
276 * @return the resolved object or 0
279 object path_to_object(string path, void|bool rs_links)
283 if ( !stringp(path) || strlen(path) == 0 )
286 obj = mPathCache[path];
287 if (objectp(obj) && obj->status()>=0 && obj->status() != PSTAT_DELETED) {
288 if (!stringp(obj->query_attribute(OBJ_PATH)) || obj->query_attribute(OBJ_PATH) == path) {
291 if (obj->get_object_class() & CLASS_LINK)
292 obj = obj->get_link_object();
293 else if (obj->get_object_class() & CLASS_EXIT)
294 obj = obj->get_exit();
299 m_delete(mPathCache, obj);
302 DEBUG_FILEPATH("path_to_object("+path+")");
303 if ( strlen(path) > 0 && path[0] != '/' && !IS_SOCKET(CALLER) ) {
304 obj = resolve_path(CALLER->get_environment(), path, rs_links);
307 obj = resolve_path(0, path, rs_links);
309 mPathCache[path] = obj;
314 * Check if a given object is a groups workarea or a user workroom
315 * and return the appropriate path.
317 * @param object obj - the object to check.
318 * @return tilde path or "" or 0.
320 string|int check_tilde(object obj)
322 object creator, workroom;
324 if ( obj->get_object_class() & CLASS_ROOM ) {
325 if ( obj == _ROOTROOM )
327 foreach ( indices(mVirtualPath), object module ) {
328 string vpath = module->contains_virtual(obj);
329 if ( stringp(vpath) )
330 return mVirtualPath[module] + vpath;
333 object owner = obj->query_attribute(OBJ_OWNER);
334 if ( objectp(owner) )
337 creator = obj->get_creator();
339 if ( objectp(creator) ) {
340 if ( creator->get_object_class() & CLASS_USER )
341 workroom = creator->query_attribute(USER_WORKROOM);
343 workroom = creator->query_attribute(GROUP_WORKROOM);
346 if ( creator->get_object_class() & CLASS_USER )
347 return "/home/"+creator->get_user_name();
349 return "/home/"+creator->get_identifier();
352 else if ( obj->get_object_class() & CLASS_USER ) {
353 return "/~"+obj->get_user_name();
359 string annotation_object_to_path(object obj)
363 string name = obj->get_object_id();
365 object ann = obj->get_annotating();
368 ann = ann->get_annotating();
370 while ( objectp(ann) ) {
371 path = "/" + name + path;
372 name = ann->get_object_id();
374 ann = ann->get_annotating();
376 if ( !objectp(annotated) )
377 return "/void/" + obj->get_object_id();
378 return object_to_filename(annotated) + "/annotations" + path;
381 string calendar_object_to_path(object obj)
386 string version_object_to_path(object obj)
388 object version = obj->query_attribute(OBJ_VERSIONOF);
389 if (objectp(version->query_attribute(OBJ_VERSIONOF)))
390 return "/versionmismatch/"+ version->get_object_id() + "/";
391 return object_to_filename(version) + "/versions/";
395 * return the path equivalent to an object
397 * @param obj - the object
398 * @return converts the object to a path description
399 * @see path_to_object
402 object_to_path(object obj)
404 object env, last_env;
413 if (obj == _ROOTROOM)
416 /* traverse through the tree beginning with the object itself
417 * and following the environment structure */
418 env = obj->get_environment();
420 if ( last_env == _ROOTROOM )
422 else if ( objectp(env) )
423 env = env->get_environment();
424 else if ( objectp(obj->get_annotating()) )
425 return annotation_object_to_path(obj);
426 else if ( obj->get_object_class() & CLASS_CALENDAR )
427 return calendar_object_to_path(obj);
428 else if ( objectp(obj->query_attribute(OBJ_VERSIONOF)) )
429 return version_object_to_path(obj);
433 if ( stringp(workroom=check_tilde(last_env)) )
434 return workroom + "/";
438 while ( objectp(env) ) {
439 name = last_env->get_identifier();
441 path = "/" + name + path;
443 if ( stringp(workroom=check_tilde(env)) ) {
444 return workroom + path;
446 env = env->get_environment();
448 string tilde = check_tilde(last_env);
449 if ( !stringp(tilde) ) {
450 if ( last_env == _ROOTROOM )
457 string object_to_identifier(object obj)
459 if (obj->get_object_class() & CLASS_CALENDAR) {
460 object creator = obj->get_creator();
461 if ( objectp(creator) )
462 return creator->get_identifier();
464 if (objectp(obj->get_environment()))
465 return obj->get_identifier();
466 return obj->get_object_id();
470 * Return the whole path, including the filename, for the given object.
472 * @param obj - the object to get the filename
473 * @return the filename
475 string object_to_filename(object obj, void|int force)
478 steam_error("Cannot resolve filename for non-object !");
483 string path = obj->query_attribute(OBJ_PATH);
484 if ( stringp(path) && strlen(path) > 0 )
489 if ( stringp(workroom=check_tilde(obj)) )
491 return object_to_path(obj) + object_to_identifier(obj);
495 * Get the Container or Room a given url-object is located.
497 * @param string url - the url to find the objects environment.
498 * @return the environment.
501 path_to_environment(string url)
506 while ( i > 0 && url[i] != '/' ) i--;
507 if ( i == 0 ) return _ROOTROOM;
508 return path_to_object(url[..i]);
511 string get_identifier() { return "filepath:tree"; }
514 * Check whether the current user is able to read the given file.
516 * @param string file - the file to check.
519 int check_access(string file)
522 obj = path_to_object(file);
523 if ( objectp(obj) ) {
525 _SECURITY->access_read(0, obj, this_user());
527 if ( arrayp(err) ) return 0;
528 DEBUG_FILEPATH("Access ok !");