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: orb_url.pike,v 1.4 2010/08/20 20:42:25 astra Exp $
19 inherit "/kernel/secure_mapping";
20 inherit "/kernel/orb";
22 #include <attributes.h>
23 #include <exception.h>
28 class orb_url : public secure_mapping,orb{
36 #define DEBUG_URL(s, args...) werror("[orb:url] "+s+"\n", args)
38 #define DEBUG_URL(s, args...)
41 mapping mPathCache = ([ ]);
42 mapping newPathCache = ([ ]);
45 * overwrites secure_mapping.list to provide additional information
48 mixed result= ::list();
49 object filepath = _Server->get_module("filepath:tree");
52 string newresult = "";
54 foreach(result, string url) {
56 obj = path_to_object(url);
58 url = httplib.replace_uml(url);
59 newresult += "<site><url><![CDATA["+url+"]]><\/url>";
60 newresult += "<id>"+obj->get_object_id()+"<\/id>";
61 if (objectp(filepath)) {
62 string path = filepath->object_to_filename(obj);
63 path = httplib.replace_uml(path);
64 newresult += "<path><![CDATA["+path+"]]><\/path>";
66 newresult += "<\/site>";
77 mapping result = ([]);
78 foreach (::list();; mixed key)
80 result[key] = get_value(key);
87 foreach (::list();; mixed key)
89 if (!get_value(key) && (string)(int)key != key)
95 * Conversion function.
97 * @param object obj - the object to convert.
99 void convert_url(object obj)
102 mixed old_value = obj->query_attribute(OBJ_URL);
103 if ( stringp(old_value) )
104 obj->set_attribute(OBJ_URL, old_value);
108 * Callback function when the module is installed. Registers
109 * the 'url' attribute in the object factory.
114 set_value("/", get_object_id());
118 private void low_set_url(object obj, string val)
127 string url = get_value(obj->get_object_id());
133 werror("obj_url.pike: deleting %O -> %O\n", url, obj);
139 set_value(val, obj->get_object_id());
140 set_value(obj->get_object_id(), val);
141 if (stringp(url) && strlen(url)>0) {
142 m_delete(mPathCache, url);
144 m_delete(mPathCache, url+"/");
146 m_delete(mPathCache, dirname(url));
148 if (stringp(val) && strlen(val)>0) {
149 m_delete(mPathCache, val);
151 m_delete(mPathCache, val+"/");
153 m_delete(mPathCache, dirname(val));
159 void update_url(object obj)
161 string url = obj->query_attribute(OBJ_URL);
162 low_set_url(obj, url);
166 * The 'url' attribute is acquired from this module and all url change
167 * calls on objects will end up here.
169 * @param string|int key - attribute to change, should be 'url'.
170 * @param mixed val - new value of 'url' attribute.
171 * @return true or new value.
172 * @see query_attribute
174 mixed set_attribute(string|int key, mixed val)
179 FATAL("Old URL syntax detected - skipping !");
180 if ( stringp(val) ) {
181 int id = get_value(val);
183 object urlObject = find_object(id);
184 if ( objectp(urlObject) &&
186 urlObject->status() >= 0 &&
187 urlObject->status() != PSTAT_DELETED)
189 steam_error("Trying to set URL to conflicting value(%s) for %O,"+
193 urlObject->get_object(),
194 _FILEPATH->object_to_filename(urlObject));
198 if ( val == "none" || val == "" )
200 low_set_url(obj, val);
204 return ::set_attribute(key, val);
209 * Query an attribute, but should be 'url' in general for
210 * other objects whose acquiring end up here.
212 * @param string|int key - attribute to query.
213 * @return value for url in database or this modules attribute value.
216 mixed query_attribute(string|int key)
218 if ( key == OBJ_URL ) {
219 return get_value(obj->get_object_id());
221 return ::query_attribute(key);
225 * Get the acquired attribute. No URL to get no loops.
227 * @param string|int key - the key of the attribute.
228 * @return the acquire object or function.
230 mixed get_acquire_attribute(string|int key)
232 if ( key == OBJ_URL )
234 return ::get_acquire_attribute(key);
237 void set_acquire_attribute(string|int key, mixed val)
239 if ( key == OBJ_URL )
241 ::set_acquire_attribute(key, val);
245 * Resolve a path with the url module by getting the saved value for
246 * 'path' and returning the appropriate object.
248 * @param object uid - the uid for compatibility with orb:filepath
249 * @param string path - the path to resolve.
250 * @return the saved object value for 'path'.
253 resolve_path(object|string uid, string path)
255 if ( !objectp(uid) && !stringp(uid))
256 return path_to_object(path);
259 prefix = object_to_filename(uid);
264 array tokens = path / "/";
267 foreach(tokens, string t) {
268 obj = obj->get_object_byname(t);
275 object add_vhost(string host, string user_group)
277 object usergroup = GROUP(user_group) || USER(user_group);
278 if (host == "" || !objectp(usergroup))
281 mapping hosts = GROUP("Admin")->query_attribute("virtual_hosts");
282 if (!mappingp(hosts)) hosts = ([]);
283 hosts[host] = usergroup;
284 GROUP("Admin")->set_attribute("virtual_hosts", hosts);
288 void remove_vhost(string host)
290 mapping hosts = GROUP("Admin")->query_attribute("virtual_hosts");
291 m_delete(hosts, host);
292 GROUP("Admin")->set_attribute("virtual_hosts", hosts);
295 object resolve_vhost(string host)
298 object usergroup = GROUP("Admin")->query_attribute("virtual_hosts")[host];
299 if (objectp(usergroup))
300 destination = usergroup->query_attribute("GROUP_PUBLICROOM") ||
301 usergroup->query_attribute("USER_PUBLICROOM") ||
302 usergroup->query_attribute("GROUP_WORKROOM") ||
303 usergroup->query_attribute("USER_WORKROOM");
307 object lookup_vhost(string host)
309 object usergroup = (GROUP("Admin")->query_attribute("virtual_hosts")||([]))[host];
310 if (objectp(usergroup))
314 mapping list_vhosts()
316 mapping hosts = GROUP("Admin")->query_attribute("virtual_hosts");
317 foreach (hosts; string host; mixed usergroup)
319 if (objectp(usergroup))
320 hosts[host] = usergroup->describe();
327 object path_to_object(string path)
330 return url_to_object(path);
332 return old_path_to_object(path);
337 * Returns an object for the given path if some object is registered
340 * @param string path - the path to process.
341 * @return looks up an object in the database.
344 object old_path_to_object(string path)
348 if ( !stringp(path) )
351 if (objectp(obj=mPathCache[path])) {
352 if (!stringp(obj->query_attribute(OBJ_URL)) ||
353 obj->query_attribute(OBJ_URL)==path)
356 m_delete(mPathCache, path);
359 int l = strlen(path);
365 if ( path[0] != '/' ) {
374 LOG("url:path_to_object("+path+")");
378 // if the path is the path to a directory, try to find the index files
379 if ( oid == 0 && l >= 1 && path[l-1] == '/' ) {
380 p = path + "index.xml";
383 p = path + "index.html";
387 p = path+"index.htm";
392 // if we find no registered object we should try to get any registered
393 // prefix container of this and use normal filepath handling from there.
395 array prefixes = path / "/";
396 if ( sizeof(prefixes) >= 2 ) {
397 for ( int i = sizeof(prefixes) - 1; i >= 0; i-- ) {
398 p = prefixes[..i]*"/";
401 oid = get_value(p+"/"); // try also containers with / at the end
404 obj = find_object(oid);
405 object module = _Server->get_module("filepath:tree");
406 if ( objectp(module) ) {
407 obj = module->resolve_path(obj, (prefixes[i+1..]*"/"));
408 mPathCache[path] = obj;
416 LOG("Found object: " + oid);
417 obj = find_object(oid);
418 mPathCache[path] = obj;
422 return find_object(oid);
426 object url_to_object(string path, void|string _host)
430 host = _Server->get_server_name();
432 //if (!host && objectp(CALLER) && CALLER->get_vhost)
433 // host = CALLER->get_vhost();
435 object usergroup = lookup_vhost(host);
438 // fail if we can't find a requested host,
439 // but don't fail if it's the default host
440 if (!objectp(usergroup) && _host)
442 else if (!objectp(usergroup))
443 return new_path_to_object(path);
445 hostdest = resolve_vhost(host);
449 if (sizeof(path) > 1 && path[-1] == '/')
450 path = path[..sizeof(path)-2];
452 DEBUG_URL("path: %O:%O", host, path);
457 array path_tokens = path / "/";
459 object filepath = _Server->get_module("filepath:tree");
460 object pathdest = filepath->path_to_object("/"+path_tokens[1]);
461 if (!objectp(pathdest))
462 pathdest = hostdest->get_object_byname(path_tokens[1]);
464 if (!objectp(pathdest))
466 object group = GROUP(usergroup->get_identifier()+"."+path_tokens[1]);
468 group = GROUP(path_tokens[1]);
469 if (objectp(group) && (host == _Server->get_server_name() ||
470 usergroup->is_member(group)))
471 pathdest = group->query_attribute("GROUP_PUBLICROOM") ||
472 group->query_attribute("GROUP_WORKROOM");
473 else if (objectp(USER(path_tokens[1])) &&
474 (host == _Server->get_server_name() ||
475 usergroup->is_virtual_member(USER(path_tokens[1]))))
476 pathdest = USER(path_tokens[1])->query_attribute("USER_PUBLICROOM") ||
477 USER(path_tokens[1])->query_attribute("USER_WORKROOM");
480 if (objectp(pathdest))
481 if (sizeof(path_tokens) > 2)
482 return resolve_path(pathdest, path_tokens[2..]*"/");
489 object new_path_to_object(string path)
493 if ( !stringp(path) )
503 LOG("url:new_path_to_object("+path+")");
505 if (objectp(obj=newPathCache[path]))
507 if (!stringp(obj->query_attribute(OBJ_URL)) ||
508 obj->query_attribute(OBJ_URL)==path)
511 m_delete(newPathCache, path);
514 array path_tokens = path / "/";
515 object filepath = _Server->get_module("filepath:tree");
516 if (sizeof(path_tokens) > 1)
518 obj = filepath->path_to_object("/"+path_tokens[1]);
520 if (GROUP(path_tokens[1]))
521 obj = GROUP(path_tokens[1])->query_attribute("GROUP_PUBLICROOM") ||
522 GROUP(path_tokens[1])->query_attribute("GROUP_WORKROOM");
523 else if (USER(path_tokens[1]))
524 obj = USER(path_tokens[1])->query_attribute("USER_PUBLICROOM") ||
525 USER(path_tokens[1])->query_attribute("USER_WORKROOM");
528 if (obj && sizeof(path_tokens) > 2)
529 obj = filepath->resolve_path(obj, path_tokens[2..]*"/");
531 LOG("Found object: " + obj);
532 newPathCache[path] = obj;
540 * Gets the path for an object by looking up the objects id in the
541 * database and returns a path or 0.
543 * @param object obj - the object to get a path for.
544 * @return the path for object 'obj'.
546 string old_object_to_filename(object obj)
548 string path = get_value(obj->get_object_id());
549 if ( !stringp(path) ) {
551 foreach ( indices(mVirtualPath), object module ) {
552 string vpath = module->contains_virtual(obj);
553 if ( stringp(vpath) )
554 return mVirtualPath[module] + vpath;
558 object env = obj->get_environment();
559 // check if environment is registered
562 if ( objectp(env) ) {
563 path = object_to_filename(env);
565 if ( !stringp(path) )
566 steam_error("Unable to resolve path for "+obj->describe());
567 if ( strlen(path) == 0 )
570 if ( path[-1] != '/' )
573 path += obj->get_identifier();
578 string object_to_filename(object obj, void|string server_name)
580 DEBUG_URL("new_object_to_filename(%O, %O)", obj, server_name);
582 // path = get_value(obj->get_object_id());
583 if ( !stringp(path) )
585 foreach ( indices(mVirtualPath), object module )
587 string vpath = module->contains_virtual(obj);
588 if ( stringp(vpath) )
590 DEBUG_URL("new_object_to_filename(%O): %O-%O-%O", obj, module, vpath, mVirtualPath[module]);
591 return mVirtualPath[module] + vpath;
596 object owner = obj->query_attribute("OBJ_OWNER") || obj->get_root_environment()->query_attribute("OBJ_OWNER");
597 // if (objectp(CALLER) && CALLER->get_vhost)
598 // DEBUG_URL("new_object_to_filename(%O) caller w vhost:%O", obj, CALLER->get_vhost());
600 // DEBUG_URL("new_object_to_filename(%O) caller:%O", obj, CALLER);
601 // object socket = Caller.get_socket(this, backtrace());
602 // if (socket && socket->get_vhost)
603 // DEBUG_URL("new_object_to_filename(%O) socket w vhost: %O", obj, socket->get_vhost());
605 // DEBUG_URL("new_object_to_filename(%O) socket: %O", obj, socket);
607 if (owner && obj->get_object_id() == (owner->query_attribute("GROUP_PUBLICROOM") ||
608 owner->query_attribute("USER_PUBLICROOM") ||
609 owner->query_attribute("GROUP_WORKROOM") ||
610 owner->query_attribute("USER_WORKROOM"))->get_object_id())
613 object socket = Caller.get_socket(this, backtrace());
614 if (!server_name && objectp(socket) && socket->get_vhost)
615 server_name = socket->get_vhost();
616 object vhost_owner = lookup_vhost(server_name);
618 DEBUG_URL("new_object_to_filename(%O) %O - %O - socket: %O", obj, server_name, vhost_owner, socket);
622 // if the current host is a virtual host for the owner, path is /
623 if (owner == vhost_owner)
626 // if owner is a subgroup or user check if it is a member of the vhost group,
627 // path is the subgroup or user name.
628 else if (server_name == _Server->get_server_name() ||
629 vhost_owner->is_virtual_member(owner))
630 if (has_prefix(owner->get_identifier(), vhost_owner->get_identifier()+"."))
631 path = "/"+owner->get_identifier()[sizeof(vhost_owner->get_identifier())+1..];
633 path = "/"+owner->get_identifier();
636 // if this is a publicroom then path is groupname.
637 path = "/"+owner->get_identifier();
640 DEBUG_URL("new_object_to_filename(%O) env: %O owner: %O root: %O owner: %O socket: %O room: %O", obj, obj->get_environment(), obj->query_attribute("OBJ_OWNER"), obj->get_root_environment(), owner, Caller.get_socket(this, backtrace()),
641 (owner && (owner->query_attribute("GROUP_PUBLICROOM") ||
642 owner->query_attribute("USER_PUBLICROOM") ||
643 owner->query_attribute("GROUP_WORKROOM") ||
644 owner->query_attribute("USER_WORKROOM"))));
646 if (!owner && obj->query_attribute("OBJ_NAME") == "root-room")
651 object env = obj->get_environment();
655 string parentpath = object_to_filename(env, server_name);
656 if (parentpath[-1] != '/')
658 path = parentpath+obj->get_identifier();
663 steam_error("Unable to resolve path for "+obj->describe());
664 DEBUG_URL("new_object_to_filename(%O) result: %O", obj, path);
668 mapping object_to_url(object obj)
671 // check if owner has a virtual host
672 // get list of groups owner belongs to
673 // get virtual hosts for each group
674 mapping vhosts = GROUP("Admin")->query_attribute("virtual_hosts");
675 mapping host_groups = ([]);
676 foreach (vhosts; string host; object group)
678 if (!host_groups[group])
679 host_groups[group] = ({ host });
681 host_groups[group] += ({ host });
683 object owner = obj->query_attribute("OBJ_OWNER") || obj->get_root_environment()->query_attribute("OBJ_OWNER");
684 array groups = ({ owner });
685 array subgroups = owner->get_groups();
686 while(sizeof(subgroups))
689 subgroups = Array.flatten(subgroups->get_groups());
691 mapping matches = host_groups & groups;
692 array hosts = Array.flatten(values(matches));
694 hosts += ({ _Server->get_server_name() });
697 foreach (hosts;; string host)
699 string path = object_to_filename(obj, host);
700 if (path && sizeof(path))
701 urls[host] = sprintf("http://%s%s", host, path);
706 string object_to_path(object obj)
708 string fullpath = object_to_filename(obj);
709 return dirname(fullpath);
713 * Get environment from a given path. This checks if the directory
714 * prefix of 'url' is also registered in the database.
716 * @param string url - path to get the environment object for.
717 * @return the environment object or 0.
719 object path_to_environment(string url)
721 sscanf(url, "/%s/%*s", url);
722 return path_to_object(url);
725 string execute(mapping vars)
727 return "<html><body><h2>Welcome to sTeam</h2><br/>"+
728 "Congratulations, you successfully installed a sTeam server!"+
729 "<br/>To be able to get anything working on this "+
730 "Web Port, <br/>you need to install the web Package.</body></html>";
733 string get_identifier() { return "filepath:url"; }
734 string get_table_name() { return "orb_url"; }
735 int get_object_class() { return ::get_object_class() | CLASS_SCRIPT; }