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 !");