|
|
|
|
#include <module_constants.h> |
#include <module.h> |
#include <request_trace.h> |
|
constant __pragma_save_parent__ = 1; |
|
inherit "basic_defvar"; |
mapping(string:array(int)) error_log=([]); |
|
constant is_module = 1; |
|
|
|
constant module_unique = 1; |
|
|
private Configuration _my_configuration; |
private string _module_local_identifier; |
private string _module_identifier = |
lambda() { |
mixed init_info = roxen->bootstrap_info->get(); |
if (arrayp (init_info)) { |
[_my_configuration, _module_local_identifier] = init_info; |
return _my_configuration->name + "/" + _module_local_identifier; |
} |
}(); |
static mapping _api_functions = ([]); |
|
string|array(string) module_creator; |
string module_url; |
RXML.TagSet module_tag_set; |
|
|
|
|
|
|
|
|
void report_fatal( mixed ... args ) { predef::report_fatal( @args ); } |
void report_error( mixed ... args ) { predef::report_error( @args ); } |
void report_notice( mixed ... args ) { predef::report_notice( @args ); } |
void report_debug( mixed ... args ) { predef::report_debug( @args ); } |
|
|
string module_identifier() |
|
|
|
{ |
#if 1 |
return _module_identifier; |
#else |
if (!_module_identifier) { |
string|mapping name = this_object()->register_module()[1]; |
if (mappingp (name)) name = name->standard; |
string cname = sprintf ("%O", my_configuration()); |
if (sscanf (cname, "Configuration(%s", cname) == 1 && |
sizeof (cname) && cname[-1] == ')') |
cname = cname[..sizeof (cname) - 2]; |
_module_identifier = sprintf ("%s,%s", |
name||this_object()->module_name, cname); |
} |
return _module_identifier; |
#endif |
} |
|
string module_local_id() |
|
|
|
|
{ |
return _module_local_identifier; |
} |
|
RoxenModule this_module() |
{ |
return this_object(); |
} |
|
string _sprintf() |
{ |
return sprintf ("RoxenModule(%s)", _module_identifier || "?"); |
} |
|
array register_module() |
{ |
return ({ |
this_object()->module_type, |
this_object()->module_name, |
this_object()->module_doc, |
0, |
module_unique, |
this_object()->module_locked, |
}); |
} |
|
string fix_cvs(string from) |
{ |
from = replace(from, ({ "$", "Id: "," Exp $" }), ({"","",""})); |
sscanf(from, "%*s,v %s", from); |
return replace(from,"/","-"); |
} |
|
int module_dependencies(Configuration configuration, |
array (string) modules, |
int|void now) |
|
|
|
|
|
|
{ |
modules = map (modules, |
lambda (string modname) { |
sscanf ((modname / "/")[-1], "%[^#]", modname); |
return modname; |
}); |
Configuration conf = configuration || my_configuration(); |
if (!conf) |
report_warning ("Configuration not resolved; module(s) %s that %s " |
"depend on weren't added.", String.implode_nicely (modules), |
module_identifier()); |
else |
conf->add_modules( modules, now ); |
return 1; |
} |
|
string file_name_and_stuff() |
{ |
return ("<b>Loaded from:</b> "+(roxen->filename(this_object()))+"<br>"+ |
(this_object()->cvs_version? |
"<b>CVS Version:</b> "+ |
fix_cvs(this_object()->cvs_version)+"\n":"")); |
} |
|
|
Configuration my_configuration() |
|
|
{ |
return _my_configuration; |
} |
|
nomask void set_configuration(Configuration c) |
{ |
if(_my_configuration && _my_configuration != c) |
error("set_configuration() called twice.\n"); |
_my_configuration = c; |
} |
|
void set_module_creator(string|array(string) c) |
|
|
|
|
|
{ |
module_creator = c; |
} |
|
void set_module_url(string to) |
|
|
|
|
{ |
module_url = to; |
} |
|
void free_some_sockets_please(){} |
|
void start(void|int num, void|Configuration conf) {} |
|
string status() {} |
|
string info(Configuration conf) |
{ |
return (this_object()->register_module()[2]); |
} |
|
string sname( ) |
{ |
return my_configuration()->otomod[ this_object() ]; |
} |
|
ModuleInfo my_moduleinfo( ) |
|
{ |
string f = sname(); |
if( f ) return roxen.find_module( (f/"#")[0] ); |
} |
|
void save_me() |
{ |
my_configuration()->save_one( this_object() ); |
my_configuration()->module_changed( my_moduleinfo(), this_object() ); |
} |
|
void save() { save_me(); } |
string comment() { return ""; } |
|
string query_internal_location() |
|
|
{ |
if(!_my_configuration) |
error("Please do not call this function from create()!\n"); |
return _my_configuration->query_internal_location(this_object()); |
} |
|
string query_absolute_internal_location(RequestID id) |
|
{ |
return (id->misc->site_prefix_path || "") + query_internal_location(); |
} |
|
string query_location() |
|
|
|
{ |
string s; |
catch{s = query("location");}; |
return s; |
} |
|
array(string) location_urls() |
|
{ |
string loc = query_location(); |
if (!loc) return ({}); |
if(!_my_configuration) |
error("Please do not call this function from create()!\n"); |
array(string) urls = copy_value(_my_configuration->query("URLs")); |
string hostname; |
if (string world_url = _my_configuration->query ("MyWorldLocation")) |
sscanf (world_url, "%*s://%s%*[:/]", hostname); |
if (!hostname) hostname = gethostname(); |
for (int i = 0; i < sizeof (urls); i++) |
{ |
urls[i] = (urls[i]/"#")[0]; |
if (sizeof (urls[i]/"*") == 2) |
urls[i] = replace(urls[i], "*", hostname); |
} |
return map (urls, `+, loc[1..]); |
} |
|
|
string query_provides() { return 0; } |
|
|
function(RequestID:int|mapping) query_seclevels() |
{ |
if(catch(query("_seclevels")) || (query("_seclevels") == 0)) |
return 0; |
return roxen.compile_security_pattern(query("_seclevels"),this_object()); |
} |
|
Stat stat_file(string f, RequestID id){} |
array(string) find_dir(string f, RequestID id){} |
mapping(string:Stat) find_dir_stat(string f, RequestID id) |
{ |
SIMPLE_TRACE_ENTER(this, "find_dir_stat(): %O", f); |
|
array(string) files = find_dir(f, id); |
mapping(string:Stat) res = ([]); |
|
foreach(files || ({}), string fname) { |
SIMPLE_TRACE_ENTER(this, "stat()'ing %O", f + "/" + fname); |
Stat st = stat_file(replace(f + "/" + fname, "//", "/"), id); |
if (st) { |
res[fname] = st; |
TRACE_LEAVE("OK"); |
} else { |
TRACE_LEAVE("No stat info"); |
} |
} |
|
TRACE_LEAVE(""); |
return(res); |
} |
|
class DefaultPropertySet |
{ |
inherit PropertySet; |
|
static Stat stat; |
|
static void create (string path, RequestID id, Stat stat) |
{ |
::create (path, id); |
this_program::stat = stat; |
} |
|
Stat get_stat() {return stat;} |
|
static mapping(string:string) response_headers; |
|
mapping(string:string) get_response_headers() |
{ |
if (!response_headers) { |
|
if (!id->misc->common) |
id->misc->common = ([]); |
|
RequestID sub_id = id->clone_me(); |
sub_id->misc->common = id->misc->common; |
|
sub_id->not_query = query_location() + path; |
sub_id->raw_url = replace (id->raw_url, id->not_query, sub_id->not_query); |
sub_id->method = "HEAD"; |
|
mapping(string:mixed)|int(-1..0)|object res = find_file (path, sub_id); |
if (res == -1) res = ([]); |
else if (objectp (res)) { |
string ext; |
if(stringp(sub_id->extension)) { |
sub_id->not_query += sub_id->extension; |
ext = lower_case(Roxen.extension(sub_id->not_query, sub_id)); |
} |
array(string) tmp=sub_id->conf->type_from_filename(sub_id->not_query, 1, ext); |
if(tmp) |
res = ([ "file":res, "type":tmp[0], "encoding":tmp[1] ]); |
else |
res = (["file": res]); |
} |
response_headers = sub_id->make_response_headers (res); |
destruct (sub_id); |
} |
|
return response_headers; |
} |
} |
|
|
|
|
|
|
|
|
|
|
PropertySet|mapping(string:mixed) query_properties(string path, RequestID id) |
{ |
SIMPLE_TRACE_ENTER (this, "Querying properties on %O", path); |
Stat st = stat_file(path, id); |
|
if (!st) { |
SIMPLE_TRACE_LEAVE ("No such file or dir"); |
return 0; |
} |
|
PropertySet res = DefaultPropertySet(path, id, st); |
SIMPLE_TRACE_LEAVE (""); |
return res; |
} |
|
|
|
|
|
|
|
string|array(Parser.XML.Tree.Node)|mapping(string:mixed) |
query_property(string path, string prop_name, RequestID id) |
{ |
mapping(string:mixed)|PropertySet properties = query_properties(path, id); |
if (!properties) { |
return Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND, |
"No such file or directory."); |
} |
if (mappingp (properties)) |
return properties; |
return properties->query_property(prop_name) || |
Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND, "No such property."); |
} |
|
|
|
void recurse_find_properties(string path, string mode, |
int depth, MultiStatus result, |
RequestID id, |
multiset(string)|void filt) |
{ |
SIMPLE_TRACE_ENTER (this, "%s for %O, depth %d", |
mode == "DAV:propname" ? "Listing property names" : |
mode == "DAV:allprop" ? "Retrieving all properties" : |
mode == "DAV:prop" ? "Retrieving specific properties" : |
"Finding properties with mode " + mode, |
path, depth); |
mapping(string:mixed)|PropertySet properties = query_properties(path, id); |
|
if (!properties) { |
SIMPLE_TRACE_LEAVE ("No such file or dir"); |
return; |
} |
|
{ |
mapping(string:mixed) ret = mappingp (properties) ? |
properties : properties->find_properties(mode, result, filt); |
|
if (ret) { |
result->add_response(path, XMLStatusNode(ret->error, ret->rettext)); |
if (ret->rettext) { |
Parser.XML.Tree.ElementNode descr = |
Parser.XML.Tree.ElementNode ("DAV:responsedescription", ([])); |
descr->add_child (Parser.XML.Tree.TextNode (ret->rettext)); |
result->add_response (path, descr); |
} |
SIMPLE_TRACE_LEAVE ("Got status %d: %O", ret->error, ret->rettext); |
return; |
} |
} |
|
if (properties->get_stat()->isdir) { |
if (depth <= 0) { |
SIMPLE_TRACE_LEAVE ("Not recursing due to depth limit"); |
return; |
} |
depth--; |
foreach(find_dir(path, id) || ({}), string filename) { |
recurse_find_properties(combine_path(path, filename), mode, depth, |
result, id, filt); |
} |
} |
|
SIMPLE_TRACE_LEAVE (""); |
return; |
} |
|
mapping(string:mixed) patch_properties(string path, |
array(PatchPropertyCommand) instructions, |
MultiStatus result, RequestID id) |
{ |
SIMPLE_TRACE_ENTER (this, "Patching properties for %O", path); |
mapping(string:mixed)|PropertySet properties = query_properties(path, id); |
|
if (!properties) { |
SIMPLE_TRACE_LEAVE ("No such file or dir"); |
return 0; |
} |
if (mappingp (properties)) { |
SIMPLE_TRACE_LEAVE ("Got error %d from query_properties: %O", |
properties->error, properties->rettext); |
return properties; |
} |
|
mapping(string:mixed) errcode = properties->start(); |
|
if (errcode) { |
SIMPLE_TRACE_LEAVE ("Got error %d from PropertySet.start: %O", |
errcode->error, errcode->rettext); |
return errcode; |
} |
|
array(mapping(string:mixed)) results; |
|
mixed err = catch { |
results = instructions->execute(properties); |
}; |
if (err) { |
properties->unroll(); |
throw (err); |
} else { |
int any_failed; |
foreach(results, mapping(string:mixed) answer) { |
if (any_failed = (answer && (answer->error >= 300))) { |
break; |
} |
} |
if (any_failed) { |
|
int i; |
mapping(string:mixed) answer = |
Roxen.http_status (Protocols.HTTP.DAV_FAILED_DEP, "Failed dependency."); |
for(i = 0; i < sizeof(results); i++) { |
if (!results[i] || results[i]->error < 300) { |
result->add_property(path, instructions[i]->property_name, |
answer); |
} else { |
result->add_property(path, instructions[i]->property_name, |
results[i]); |
} |
} |
properties->unroll(); |
} else { |
int i; |
for(i = 0; i < sizeof(results); i++) { |
result->add_property(path, instructions[i]->property_name, |
results[i]); |
} |
properties->commit(); |
} |
} |
|
SIMPLE_TRACE_LEAVE (""); |
return 0; |
} |
|
|
|
|
|
|
mapping(string:mixed) set_property (string path, string prop_name, |
string|array(Parser.XML.Tree.Node) value, |
RequestID id) |
{ |
mapping(string:mixed)|PropertySet properties = query_properties(path, id); |
if (!properties) return Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND, |
"File not found."); |
if (mappingp (properties)) return properties; |
|
mapping(string:mixed) result = properties->start(); |
if (result) return result; |
|
result = properties->set_property(prop_name, value); |
if (result && result->error >= 300) { |
properties->unroll(); |
return result; |
} |
|
properties->commit(); |
return 0; |
} |
|
|
|
|
|
|
mapping(string:mixed) remove_property (string path, string prop_name, |
RequestID id) |
{ |
mapping(string:mixed)|PropertySet properties = query_properties(path, id); |
if (!properties) return Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND, |
"File not found."); |
if (mappingp (properties)) return properties; |
|
mapping(string:mixed) result = properties->start(); |
if (result) return result; |
|
result = properties->remove_property(prop_name); |
if (result && result->error >= 300) { |
properties->unroll(); |
return result; |
} |
|
properties->commit(); |
return 0; |
} |
|
string resource_id (string path, RequestID id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
return has_suffix (path, "/") ? path : path + "/"; |
} |
|
string|int authenticated_user_id (string path, RequestID id) |
|
|
|
|
|
|
|
|
|
{ |
|
User uid = my_configuration()->authenticate (id); |
return uid && uid->name(); |
} |
|
|
|
|
|
static mapping(string:mapping(mixed:DAVLock)) file_locks = ([]); |
|
|
|
|
|
|
static mapping(string:mapping(mixed:DAVLock)) prefix_locks = ([]); |
|
#define LOOP_OVER_BOTH(PATH, LOCKS, CODE) \ |
do { \ |
foreach (file_locks; PATH; LOCKS) {CODE;} \ |
foreach (prefix_locks; PATH; LOCKS) {CODE;} \ |
} while (0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
multiset(DAVLock) find_locks(string path, |
int(0..1) recursive, |
int(0..1) exclude_shared, |
RequestID id) |
{ |
|
if (!sizeof(file_locks) && !sizeof(prefix_locks)) return 0; |
|
TRACE_ENTER(sprintf("find_locks(%O, %O, %O, X)", |
path, recursive, exclude_shared), this); |
|
path = resource_id (path, id); |
|
multiset(DAVLock) locks = (<>); |
function(mapping(mixed:DAVLock):void) add_locks; |
|
if (exclude_shared) { |
mixed auth_user = authenticated_user_id (path, id); |
add_locks = lambda (mapping(mixed:DAVLock) sub_locks) { |
foreach (sub_locks; string user; DAVLock lock) |
if (user == auth_user || |
lock->lockscope == "DAV:exclusive") |
locks[lock] = 1; |
}; |
} |
else |
add_locks = lambda (mapping(mixed:DAVLock) sub_locks) { |
locks |= mkmultiset (values (sub_locks)); |
}; |
|
if (file_locks[path]) { |
add_locks (file_locks[path]); |
} |
|
foreach(prefix_locks; |
string prefix; mapping(mixed:DAVLock) sub_locks) { |
if (has_prefix(path, prefix)) { |
add_locks (sub_locks); |
break; |
} |
} |
|
if (recursive) { |
LOOP_OVER_BOTH (string prefix, mapping(mixed:DAVLock) sub_locks, { |
if (has_prefix(prefix, path)) { |
add_locks (sub_locks); |
} |
}); |
} |
|
add_locks = 0; |
|
TRACE_LEAVE(sprintf("Done, found %d locks.", sizeof(locks))); |
|
return sizeof(locks) && locks; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DAVLock|int(0..3) check_locks(string path, |
int(0..1) recursive, |
RequestID id) |
{ |
|
if (!sizeof(file_locks) && !sizeof(prefix_locks)) return 0; |
|
TRACE_ENTER(sprintf("check_locks(%O, %d, X)", path, recursive), this); |
|
path = resource_id (path, id); |
|
mixed auth_user = authenticated_user_id (path, id); |
|
if (DAVLock lock = |
file_locks[path] && file_locks[path][auth_user] || |
prefix_locks[path] && prefix_locks[path][auth_user]) { |
TRACE_LEAVE(sprintf("Found lock %O.", lock->locktoken)); |
return lock; |
} |
int(0..1) shared; |
|
if (mapping(mixed:DAVLock) locks = file_locks[path]) { |
foreach(locks;; DAVLock lock) { |
if (lock->lockscope == "DAV:exclusive") { |
TRACE_LEAVE(sprintf("Found other user's exclusive lock %O.", |
lock->locktoken)); |
return 3; |
} |
shared = 1; |
break; |
} |
} |
|
foreach(prefix_locks; |
string prefix; mapping(mixed:DAVLock) locks) { |
if (has_prefix(path, prefix)) { |
if (DAVLock lock = locks[auth_user]) return lock; |
if (!shared) |
|
|
foreach(locks;; DAVLock lock) { |
if (lock->lockscope == "DAV:exclusive") { |
TRACE_LEAVE(sprintf("Found other user's exclusive lock %O.", |
lock->locktoken)); |
return 3; |
} |
shared = 1; |
break; |
} |
} |
} |
|
if (!recursive) { |
TRACE_LEAVE(sprintf("Returning %O.", shared)); |
return shared; |
} |
|
int(0..1) locked_by_auth_user; |
|
|
|
LOOP_OVER_BOTH (string prefix, mapping(mixed:DAVLock) locks, { |
if (has_prefix(prefix, path)) { |
if (locks[auth_user]) |
locked_by_auth_user = 1; |
else |
foreach(locks;; DAVLock lock) { |
if (lock->lockscope == "DAV:exclusive") { |
TRACE_LEAVE(sprintf("Found other user's exclusive lock %O.", |
lock->locktoken)); |
return 3; |
} |
shared = 1; |
break; |
} |
} |
}); |
|
TRACE_LEAVE(sprintf("Returning %O.", locked_by_auth_user ? 2 : shared)); |
return locked_by_auth_user ? 2 : shared; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void register_lock(string path, DAVLock lock, RequestID id) |
{ |
TRACE_ENTER(sprintf("register_lock(%O, lock(%O), X).", path, lock->locktoken), |
this); |
ASSERT_IF_DEBUG (lock->locktype == "DAV:write"); |
path = resource_id (path, id); |
mixed auth_user = authenticated_user_id (path, id); |
if (lock->recursive) { |
if (prefix_locks[path]) { |
prefix_locks[path][auth_user] = lock; |
} else { |
prefix_locks[path] = ([ auth_user:lock ]); |
} |
} else { |
if (file_locks[path]) { |
file_locks[path][auth_user] = lock; |
} else { |
file_locks[path] = ([ auth_user:lock ]); |
} |
} |
TRACE_LEAVE("Ok."); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) lock_file(string path, |
DAVLock lock, |
RequestID id) |
{ |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) unlock_file (string path, |
DAVLock lock, |
RequestID id) |
{ |
TRACE_ENTER(sprintf("unlock_file(%O, lock(%O), X).", path, lock->locktoken), |
this); |
mixed auth_user = authenticated_user_id (path, id); |
path = resource_id (path, id); |
DAVLock removed_lock; |
if (lock->recursive) { |
removed_lock = m_delete (prefix_locks[path], auth_user); |
if (!sizeof (prefix_locks[path])) m_delete (prefix_locks, path); |
} |
else { |
removed_lock = m_delete (file_locks[path], auth_user); |
if (!sizeof (file_locks[path])) m_delete (file_locks, path); |
} |
ASSERT_IF_DEBUG (!removed_lock || lock == removed_lock , |
lock, removed_lock); |
TRACE_LEAVE("Ok."); |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) write_access(string path, int(0..1) recursive, RequestID id) |
{ |
|
|
if (!sizeof(path) || (path[-1] != '/')) path += "/"; |
|
int(0..3)|DAVLock lock = check_locks(path, 0, id); |
|
if (lock && intp(lock)) |
return Roxen.http_status(Protocols.HTTP.DAV_LOCKED); |
|
path = query_location() + path; |
|
mapping(string:array(array(array(string)))) if_data = id->get_if_data(); |
array(array(array(string))) condition; |
if (!if_data || !sizeof(condition = if_data[path] || if_data[0])) { |
if (lock) return Roxen.http_status(Protocols.HTTP.DAV_LOCKED); |
return 0; |
} |
mapping(string:mixed) res; |
next_condition: |
foreach(condition, array(array(string)) sub_cond) { |
int negate; |
foreach(sub_cond, array(string) token) { |
switch(token[0]) { |
case "not": |
negate = !negate; |
break; |
case "etag": |
|
|
res = Roxen.http_status (Protocols.HTTP.HTTP_NOT_IMPL, |
"Etag conditions not supported."); |
continue next_condition; |
case "lock": |
if ((lock && lock->locktoken == token[1]) != negate) { |
|
continue next_condition; |
} |
negate = 0; |
break; |
} |
} |
return 0; |
} |
return res || Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED); |
} |
|
mapping(string:mixed)|int(-1..0)|Stdio.File find_file(string path, |
RequestID id); |
|
|
|
|
|
|
|
|
mapping(string:mixed) delete_file(string path, RequestID id) |
{ |
|
RequestID tmp_id = id->close_me(); |
tmp_id->not_query = query_location() + path; |
tmp_id->method = "DELELE"; |
|
return find_file(path, id) || Roxen.http_status(404); |
} |
|
int(0..1) recurse_delete_files(string path, MultiStatus stat, RequestID id) |
{ |
Stat st = stat_file(path, id); |
if (!st) return 0; |
if (st->isdir) { |
|
|
|
int(0..1) fail; |
foreach(find_dir(path, id) || ({}), string fname) { |
fail |= recurse_delete_files(path+"/"+fname, stat, id); |
} |
|
|
|
if (fail) return fail; |
} |
mapping ret = delete_file(path, id); |
if (ret->code != 204) { |
|
|
|
|
stat->add_response(path, XMLStatusNode(ret->code)); |
} |
return ret->code >= 300; |
} |
|
mapping copy_file(string path, string dest, int(-1..1) behavior, RequestID id) |
{ |
werror("copy_file(%O, %O, %O, %O)\n", |
path, dest, behavior, id); |
return Roxen.http_status (Protocols.HTTP.HTTP_NOT_IMPL); |
} |
|
void recurse_copy_files(string path, int depth, string dest_prefix, |
string dest_suffix, |
mapping(string:int(-1..1)) behavior, |
MultiStatus result, RequestID id) |
{ |
Stat st = stat_file(path, id); |
if (!st) return; |
if (!dest_prefix) { |
Standards.URI dest_uri = Standards.URI(result->href_prefix); |
Configuration c = roxen->find_configuration_for_url(dest_uri, id->conf); |
|
if (!c || |
!has_prefix(dest_uri->path||"/", query_location())) { |
|
|
result->add_response(dest_suffix, XMLStatusNode(502)); |
return; |
} |
dest_prefix = (dest_uri->path||"/")[sizeof(query_location())..]; |
Stat dest_st; |
if (!(dest_st = stat_file(combine_path(dest_prefix, ".."), id)) || |
!(dest_st->isdir)) { |
result->add_response("", XMLStatusNode(409)); |
return; |
} |
if (combine_path(dest_prefix, dest_suffix, ".") == |
combine_path(path, ".")) { |
result->add_response(dest_suffix, XMLStatusNode(403, "Source and destination are the same.")); |
return; |
} |
} |
werror("recurse_copy_files(%O, %O, %O, %O, %O, %O, %O)\n", |
path, depth, dest_prefix, dest_suffix, behavior, result, id); |
mapping res = copy_file(path, dest_prefix + dest_suffix, |
behavior[dest_prefix + dest_suffix]||behavior[0], |
id); |
result->add_response(dest_suffix, XMLStatusNode(res->error, res->data)); |
if (res->error >= 300) { |
|
return; |
} |
if ((depth <= 0) || !st->isdir) return; |
depth--; |
foreach(find_dir(path, id), string filename) { |
recurse_copy_files(combine_path(path, filename), depth, |
dest_prefix, combine_path(dest_suffix, filename), |
behavior, result, id); |
} |
} |
|
string real_file(string f, RequestID id){} |
|
void add_api_function( string name, function f, void|array(string) types) |
{ |
_api_functions[name] = ({ f, types }); |
} |
|
mapping api_functions() |
{ |
return _api_functions; |
} |
|
#if ROXEN_COMPAT <= 1.4 |
mapping(string:function) query_tag_callers() |
|
{ |
mapping(string:function) m = ([]); |
foreach(glob("tag_*", indices( this_object())), string q) |
if(functionp( this_object()[q] )) |
m[replace(q[4..], "_", "-")] = this_object()[q]; |
return m; |
} |
|
mapping(string:function) query_container_callers() |
|
{ |
mapping(string:function) m = ([]); |
foreach(glob("container_*", indices( this_object())), string q) |
if(functionp( this_object()[q] )) |
m[replace(q[10..], "_", "-")] = this_object()[q]; |
return m; |
} |
#endif |
|
mapping(string:array(int|function)) query_simpletag_callers() |
{ |
mapping(string:array(int|function)) m = ([]); |
foreach(glob("simpletag_*", indices(this_object())), string q) |
if(functionp(this_object()[q])) |
m[replace(q[10..],"_","-")] = |
({ intp (this_object()[q + "_flags"]) && this_object()[q + "_flags"], |
this_object()[q] }); |
return m; |
} |
|
mapping(string:array(int|function)) query_simple_pi_tag_callers() |
{ |
mapping(string:array(int|function)) m = ([]); |
foreach (glob ("simple_pi_tag_*", indices (this_object())), string q) |
if (functionp (this_object()[q])) |
m[replace (q[sizeof ("simple_pi_tag_")..], "_", "-")] = |
({(intp (this_object()[q + "_flags"]) && this_object()[q + "_flags"]) | |
RXML.FLAG_PROC_INSTR, this_object()[q]}); |
return m; |
} |
|
RXML.TagSet query_tag_set() |
{ |
if (!module_tag_set) { |
array(function|program|object) tags = |
filter (rows (this_object(), |
glob ("Tag*", indices (this_object()))), |
lambda(mixed x) { return functionp(x)||programp(x); }); |
for (int i = 0; i < sizeof (tags); i++) |
if (programp (tags[i])) |
if (!tags[i]->is_RXML_Tag) tags[i] = 0; |
else tags[i] = tags[i](); |
else { |
tags[i] = tags[i](); |
|
if (!tags[i]->is_RXML_Tag) tags[i] = 0; |
} |
tags -= ({0}); |
module_tag_set = |
(this_object()->ModuleTagSet || RXML.TagSet) (this_object(), "", tags); |
} |
return module_tag_set; |
} |
|
mixed get_value_from_file(string path, string index, void|string pre) |
{ |
Stdio.File file=Stdio.File(); |
if(!file->open(path,"r")) return 0; |
if(has_suffix(index, "()")) |
index = index[..sizeof(index) - 3]; |
|
|
|
return compile_string((pre || "") + file->read(), path)[index]; |
} |
|
static private mapping __my_tables = ([]); |
|
array(mapping(string:mixed)) sql_query( string query, mixed ... args ) |
|
|
|
|
|
|
|
|
{ |
return get_my_sql()->query( replace( query, __my_tables ), @args ); |
} |
|
object sql_big_query( string query, mixed ... args ) |
|
|
{ |
return get_my_sql()->big_query( replace( query, __my_tables ), @args ); |
} |
|
array(mapping(string:mixed)) sql_query_ro( string query, mixed ... args ) |
|
|
|
|
|
|
|
|
{ |
return get_my_sql(1)->query( replace( query, __my_tables ), @args ); |
} |
|
object sql_big_query_ro( string query, mixed ... args ) |
|
|
{ |
return get_my_sql(1)->big_query( replace( query, __my_tables ), @args ); |
} |
|
static int create_sql_tables( mapping(string:array(string)) definitions, |
string|void comment, |
int|void no_unique_names ) |
|
|
{ |
int ddc; |
if( !no_unique_names ) |
foreach( indices( definitions ), string t ) |
ddc+=get_my_table( t, definitions[t], comment, 1 ); |
else |
{ |
Sql.Sql sql = get_my_sql(); |
foreach( indices( definitions ), string t ) |
{ |
if( !catch { |
sql->query("CREATE TABLE "+t+" ("+definitions[t]*","+")" ); |
} ) |
ddc++; |
DBManager.is_module_table( this_object(), my_db, t, comment ); |
} |
} |
return ddc; |
} |
|
static string sql_table_exists( string name ) |
|
{ |
if(strlen(name)) |
name = "_"+name; |
|
string res = hash(_my_configuration->name)->digits(36) |
+ "_" + replace(sname(),"#","_") + name; |
|
return catch(get_my_sql()->query( "SELECT * FROM "+res+" LIMIT 1" ))?0:res; |
} |
|
|
static string|int get_my_table( string|array(string) name, |
void|array(string)|string definition, |
string|void comment, |
int|void flag ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
string oname; |
int ddc; |
if( !definition ) |
{ |
definition = name; |
oname = name = ""; |
} |
else if(strlen(name)) |
name = "_"+(oname = name); |
|
Sql.Sql sql = get_my_sql(); |
|
string res = hash(_my_configuration->name)->digits(36) |
+ "_" + replace(sname(),"#","_") + name; |
|
if( !sql ) |
{ |
report_error("Failed to get SQL handle, permission denied for "+my_db+"\n"); |
return 0; |
} |
if( arrayp( definition ) ) |
definition *= ", "; |
|
if( catch(sql->query( "SELECT * FROM "+res+" LIMIT 1" )) ) |
{ |
ddc++; |
mixed error = |
catch |
{ |
get_my_sql()->query( "CREATE TABLE "+res+" ("+definition+")" ); |
DBManager.is_module_table( this_object(), my_db, res, |
oname+"\0"+comment ); |
}; |
if( error ) |
{ |
if( strlen( name ) ) |
name = " "+name; |
report_error( "Failed to create table"+name+": "+ |
describe_error( error ) ); |
return 0; |
} |
if( flag ) |
{ |
__my_tables[ "&"+oname+";" ] = res; |
return ddc; |
} |
return __my_tables[ "&"+oname+";" ] = res; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
if( flag ) |
{ |
__my_tables[ "&"+oname+";" ] = res; |
return ddc; |
} |
return __my_tables[ "&"+oname+";" ] = res; |
} |
|
static string my_db = "local"; |
|
static void set_my_db( string to ) |
|
|
|
{ |
my_db = to; |
} |
|
Sql.Sql get_my_sql( int|void read_only ) |
|
|
|
|
|
{ |
return DBManager.cached_get( my_db, _my_configuration, read_only ); |
} |
|
|