|
|
|
|
#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) |
{ |
TRACE_ENTER("find_dir_stat(): \""+f+"\"", 0); |
|
array(string) files = find_dir(f, id); |
mapping(string:Stat) res = ([]); |
|
foreach(files || ({}), string fname) { |
TRACE_ENTER("stat()'ing "+ f + "/" + fname, 0); |
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); |
} |
|
|
|
|
static string iso8601_date_time(int ts) |
{ |
mapping(string:int) gmt = gmtime(ts); |
return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", |
1900 + gmt->year, gmt->mon, gmt->mday, |
gmt->hour, gmt->min, gmt->sec); |
} |
|
|
multiset(string) query_all_properties(string path, RequestID id) |
{ |
Stat st = stat_file(path, id); |
if (!st) return (<>); |
multiset(string) res = (< |
"DAV:creationdate", |
"DAV:displayname", |
"DAV:getlastmodified", |
>); |
if (st->isreg) { |
res += (< |
"DAV:getcontentlength", |
"DAV:getcontenttype", |
>); |
} |
return res; |
} |
|
|
|
|
|
|
|
string|array(Parser.XML.Tree.Node)|mapping(string:mixed) |
query_property(string path, string prop_name, RequestID id) |
{ |
Stat st = stat_file(path, id); |
if (!st) return 0; |
switch(prop_name) { |
case "DAV:creationdate": |
return iso8601_date_time(st->ctime); |
case "DAV:displayname": |
return combine_path(query_location(), path); |
case "DAV:getcontentlength": |
if (st->isreg) { |
return (string)st->size; |
} |
break; |
case "DAV:getcontenttype": |
if (st->isreg) { |
return id->conf-> |
type_from_filename(path, 0, |
lower_case(Roxen.extension(path, id))); |
} |
break; |
case "DAV:getlastmodified": |
return iso8601_date_time(st->mtime); |
default: |
break; |
} |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) set_property(string path, string prop_name, |
string|array(Parser.XML.Tree.Node) value, |
RequestID id) |
{ |
switch(prop_name) { |
case "DAV:creationdate": |
case "DAV:displayname": |
case "DAV:getcontentlength": |
case "DAV:getcontenttype": |
case "DAV:getlastmodified": |
return Roxen.http_low_answer(409, |
"Attempt to set read-only property."); |
} |
return set_dead_property(path, prop_name, value, id); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) set_dead_property(string path, string prop_name, |
array(Parser.XML.Tree.Node) value, |
RequestID id) |
{ |
return Roxen.http_low_answer(405, |
"Setting of dead properties is not supported."); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed) remove_property(string path, string prop_name, |
RequestID id) |
{ |
switch(prop_name) { |
case "DAV:creationdate": |
case "DAV:displayname": |
case "DAV:getcontentlength": |
case "DAV:getcontenttype": |
case "DAV:getlastmodified": |
return Roxen.http_low_answer(409, |
"Attempt to remove a read-only property."); |
} |
return Roxen.http_low_answer(404, |
"Attempt to remove an unknown property."); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void find_properties(string path, string mode, MultiStatus result, |
RequestID id, multiset(string)|void filt) |
{ |
Stat st = stat_file(path, id); |
if (!st) return; |
|
switch(mode) { |
case "DAV:propname": |
foreach(indices(query_all_properties(path, id)), string prop_name) { |
result->add_property(path, prop_name, ""); |
} |
return; |
case "DAV:allprop": |
filt = query_all_properties(path, id); |
|
case "DAV:prop": |
foreach(indices(filt), string prop_name) { |
result->add_property(path, prop_name, |
query_property(path, prop_name, id)); |
} |
return; |
} |
|
return; |
} |
|
void recurse_find_properties(string path, string mode, int depth, |
MultiStatus result, |
RequestID id, multiset(string)|void filt) |
{ |
Stat st = stat_file(path, id); |
if (!st) return; |
|
find_properties(path, mode, result, id, filt); |
if ((depth <= 0) || !st->isdir) return; |
depth--; |
foreach(find_dir(path, id), string filename) { |
recurse_find_properties(combine_path(path, filename), mode, depth, |
result, id, filt); |
} |
} |
|
|
|
|
|
|
|
|
void patch_property_start(string path, RequestID id) |
{ |
} |
|
|
|
|
void patch_property_unroll(string path, RequestID id) |
{ |
} |
|
|
void patch_property_commit(string path, RequestID id) |
{ |
} |
|
void patch_properties(string path, array(PatchPropertyCommand) instructions, |
MultiStatus result, RequestID id) |
{ |
patch_property_start(path, id); |
|
array(mapping(string:mixed)) results; |
|
mixed err = catch { |
results = instructions->execute(path, this_object(), id); |
}; |
if (err) { |
report_debug("patch_properties() failed:\n" |
"%s\n", |
describe_backtrace(err)); |
mapping(string:mixed) answer = |
Roxen.http_low_answer(500, "Internal Server Error."); |
foreach(instructions, PatchPropertyCommand instr) { |
result->add_property(path, instr->property_name, answer); |
} |
patch_property_unroll(path, id); |
} 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_low_answer(424, "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]); |
} |
} |
patch_property_unroll(path, id); |
} else { |
int i; |
for(i = 0; i < sizeof(results); i++) { |
result->add_property(path, instructions[i]->property_name, |
results[i]); |
} |
patch_property_commit(path, id); |
} |
} |
} |
|
void recurse_patch_properties(string path, int depth, |
array(PatchPropertyCommand) instructions, |
MultiStatus result, RequestID id) |
{ |
Stat st = stat_file(path, id); |
|
patch_properties(path, instructions, result, id); |
if (!st || (depth <= 0) || !st->isdir) return; |
depth--; |
foreach(find_dir(path, id), string filename) { |
recurse_patch_properties(combine_path(path, filename), depth, |
instructions, 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(index[sizeof(index)-2..sizeof(index)-1]=="()") { |
return compile_string((pre||"")+file->read())[index[..sizeof(index)-3]](); |
} |
return compile_string((pre||"")+file->read())[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 defenition, |
string|void comment, |
int|void flag ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
string oname; |
int ddc; |
if( !defenition ) |
{ |
defenition = 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( defenition ) ) |
defenition *= ", "; |
|
if( catch(sql->query( "SELECT * FROM "+res+" LIMIT 1" )) ) |
{ |
ddc++; |
mixed error = |
catch |
{ |
get_my_sql()->query( "CREATE TABLE "+res+" ("+defenition+")" ); |
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 ); |
} |
|
|