#include <module.h> |
#include <roxen.h> |
static inherit "html"; |
|
|
static inline string getloclang() { |
return roxenp()->locale->get(); |
} |
|
|
|
#if constant(Locale.DeferredLocale) |
#define LOCALE(X,Y) \ |
([string](mixed)Locale.DeferredLocale("roxen_config",getloclang,X,Y)) |
#else /* !Locale.DeferredLocale */ |
#define LOCALE(X,Y) \ |
([string](mixed)RoxenLocale.DeferredLocale("roxen_config",getloclang,X,Y)) |
#endif /* Locale.DeferredLocale */ |
|
|
static int unique_vid; |
|
|
|
|
|
static mapping(int:mixed) changed_values = ([]); |
static mapping(int:function(object:void)) changed_callbacks = ([]); |
static mapping(int:int) all_flags = ([]); |
static mapping(int:string) all_warnings = ([]); |
static mapping(int:function(RequestID,object:int)) |
invisibility_callbacks = set_weak_flag( ([]), 1 ); |
|
class Variable |
|
|
{ |
constant is_variable = 1; |
|
constant type = "Basic"; |
|
|
static int _id = unique_vid++; |
|
|
static mixed _initial; |
static string _path; |
static string|object __name, __doc; |
|
void destroy() |
{ |
|
m_delete( all_flags, _id ); |
m_delete( all_warnings, _id ); |
m_delete( invisibility_callbacks, _id ); |
m_delete( changed_values, _id ); |
} |
|
string get_warnings() |
|
{ |
return all_warnings[ _id ]; |
} |
|
int get_flags() |
|
|
|
|
|
|
|
{ |
return all_flags[_id]; |
} |
|
void set_flags( int flags ) |
|
|
|
|
|
|
|
{ |
if(!flags ) |
m_delete( all_flags, _id ); |
else |
all_flags[_id] = flags; |
} |
|
int check_visibility( RequestID id, |
int more_mode, |
int expert_mode, |
int devel_mode, |
int initial ) |
|
|
|
|
{ |
int flags = get_flags(); |
function cb; |
if( initial && !(flags & VAR_INITIAL) ) return 0; |
if( (flags & VAR_EXPERT) && !expert_mode ) return 0; |
if( (flags & VAR_MORE) && !more_mode ) return 0; |
if( (flags & VAR_DEVELOPER) && !devel_mode ) return 0; |
if( (cb = get_invisibility_check_callback() ) && |
cb( id, this_object() ) ) |
return 0; |
return 1; |
} |
|
void set_invisibility_check_callback( function(RequestID,Variable:int) cb ) |
|
|
|
|
{ |
if( functionp( cb ) ) |
invisibility_callbacks[ _id ] = cb; |
else |
m_delete( invisibility_callbacks, _id ); |
} |
|
function(Variable:void) get_changed_callback( ) |
|
{ |
return changed_callbacks[ _id ]; |
} |
|
void set_changed_callback( function(Variable:void) cb ) |
|
|
|
|
{ |
if( functionp( cb ) ) |
changed_callbacks[ _id ] = cb; |
else |
m_delete( changed_callbacks, _id ); |
} |
|
function(RequestID,Variable:int) get_invisibility_check_callback() |
|
{ |
return invisibility_callbacks[_id]; |
} |
|
string doc( ) |
|
|
|
|
{ |
return __doc || ""; |
} |
|
string name( ) |
|
|
|
|
{ |
return __name || "unnamed "+_id; |
} |
|
string type_hint( ) |
|
|
|
{ |
} |
|
mixed default_value() |
|
{ |
return _initial; |
} |
|
void set_warning( string to ) |
|
{ |
if( to && strlen(to) ) |
all_warnings[ _id ] = to; |
else |
m_delete( all_warnings, _id ); |
} |
|
int set( mixed to ) |
|
|
|
|
|
|
|
|
|
|
|
{ |
string err, e2; |
if( e2 = catch( [err,to] = verify_set( to )) ) |
{ |
if( stringp( e2 ) ) |
{ |
set_warning( e2 ); |
return ([])[0]; |
} |
throw( e2 ); |
} |
set_warning( err ); |
return low_set( to ); |
} |
|
int low_set( mixed to ) |
|
|
|
|
{ |
if( equal( to, query() ) ) |
return 0; |
|
if( !equal(to, default_value() ) ) |
{ |
changed_values[ _id ] = to; |
if( get_changed_callback() ) |
catch( get_changed_callback()( this_object() ) ); |
return 1; |
} |
else |
{ |
m_delete( changed_values, _id ); |
if( get_changed_callback() ) |
catch( get_changed_callback()( this_object() ) ); |
return -1; |
} |
} |
|
mixed query() |
|
{ |
mixed v; |
if( !zero_type( v = changed_values[ _id ] ) ) |
return v; |
return default_value(); |
} |
|
int is_defaulted() |
|
{ |
return zero_type( changed_values[ _id ] ) || |
equal(changed_values[ _id ], default_value()); |
} |
|
array(string|mixed) verify_set( mixed new_value ) |
|
|
|
|
|
|
|
|
{ |
return ({ 0, new_value }); |
} |
|
mapping(string:string) get_form_vars( RequestID id ) |
|
{ |
string p = path(); |
array names = glob( p+"*", indices(id->variables) ); |
mapping res = ([ ]); |
foreach( sort(names), string n ) |
res[ n[strlen(p).. ] ] = id->variables[ n ]; |
return res; |
} |
|
mixed transform_from_form( string what ) |
|
|
{ |
return what; |
} |
|
void set_from_form( RequestID id ) |
|
|
|
|
|
|
{ |
mapping val; |
if( sizeof( val = get_form_vars(id)) && val[""] && |
transform_from_form( val[""] ) != query() ) |
set( transform_from_form( val[""] )); |
} |
|
string path() |
|
|
|
|
|
|
|
|
{ |
return _path; |
} |
|
void set_path( string to ) |
|
|
|
|
|
|
{ |
_path = to; |
} |
|
string render_form( RequestID id ); |
|
|
|
|
string render_view( RequestID id ) |
|
{ |
return Roxen.html_encode_string( (string)query() ); |
} |
|
static string _sprintf( int i ) |
{ |
if( i == 'O' ) |
return sprintf( "Variables.%s(%s) [%O]", type, |
(string)name(), |
query() ); |
} |
|
static void create(mixed default_value,int flags, |
string|object std_name,string|object std_doc) |
|
|
|
|
|
|
|
|
|
|
{ |
set_flags( flags ); |
_initial = default_value; |
__name = std_name; |
__doc = std_doc; |
} |
} |
|
|
|
|
|
|
|
|
class Float |
|
{ |
inherit Variable; |
constant type = "Float"; |
static float _max, _min; |
static int _prec = 2, mm_set; |
|
static string _format( float m ) |
{ |
if( !_prec ) |
return sprintf( "%d", (int)m ); |
return sprintf( "%1."+_prec+"f", m ); |
} |
|
void set_range(float minimum, float maximum ) |
|
|
{ |
if( minimum == maximum ) |
mm_set = 0; |
else |
mm_set = 1; |
_max = maximum; |
_min = minimum; |
} |
|
void set_precision( int prec ) |
|
|
|
{ |
_prec = prec; |
} |
|
array(string|float) verify_set( float new_value ) |
{ |
string warn; |
if( mm_set ) |
{ |
if( new_value > _max ) |
{ |
warn = sprintf("Value is bigger than %s, adjusted", _format(_max) ); |
new_value = _max; |
} |
else if( new_value < _min ) |
{ |
warn = sprintf("Value is less than %s, adjusted", _format(_min) ); |
new_value = _min; |
} |
} |
return ({ warn, new_value }); |
} |
|
float transform_from_form( string what ) |
{ |
return (float)what; |
} |
|
string render_view( RequestID id ) |
{ |
return Roxen.html_encode_string( _format(query()) ); |
} |
|
string render_form( RequestID id ) |
{ |
int size = 15; |
if( mm_set ) |
size = max( strlen(_format(_max)), strlen(_format(_min)) )+2; |
return input(path(), _format(query()), size); |
} |
} |
|
|
|
|
|
|
|
|
class Int |
|
{ |
inherit Variable; |
constant type = "Int"; |
static int _max, _min, mm_set; |
|
void set_range(int minimum, int maximum ) |
|
|
{ |
if( minimum == maximum ) |
mm_set = 0; |
else |
mm_set = 1; |
_max = maximum; |
_min = minimum; |
} |
|
array(string|int) verify_set( int new_value ) |
{ |
string warn; |
if( mm_set ) |
{ |
if( new_value > _max ) |
{ |
warn = sprintf("Value is bigger than %d, adjusted", _max ); |
new_value = _max; |
} |
else if( new_value < _min ) |
{ |
warn = sprintf("Value is less than %d, adjusted", _min ); |
new_value = _min; |
} |
} |
return ({ warn, new_value }); |
} |
|
int transform_from_form( string what ) |
{ |
return (int)what; |
} |
|
string render_form( RequestID id ) |
{ |
int size = 10; |
if( mm_set ) |
size = max( strlen((string)_max), strlen((string)_min) )+2; |
return input(path(), (string)query(), size); |
} |
} |
|
|
|
|
|
|
class String |
|
{ |
inherit Variable; |
constant type = "String"; |
constant width = 40; |
|
string render_form( RequestID id ) |
{ |
return input(path(), (string)query(), width); |
} |
} |
|
|
|
|
class Text |
|
{ |
inherit String; |
constant type = "Text"; |
constant cols = 60; |
|
constant rows = 10; |
|
string render_form( RequestID id ) |
{ |
return "<textarea cols='"+cols+"' rows='"+rows+"' name='"+path()+"'>" |
+ Roxen.html_encode_string( query() || "" ) + |
"</textarea>"; |
} |
} |
|
|
|
|
|
|
class Password |
|
{ |
inherit String; |
constant width = 20; |
constant type = "Password"; |
|
void set_from_form( RequestID id ) |
{ |
mapping val; |
if( sizeof( val = get_form_vars(id)) && |
val[""] && strlen(val[""]) ) |
set( crypt( val[""] ) ); |
} |
|
string render_view( RequestID id ) |
{ |
return "******"; |
} |
|
string render_form( RequestID id ) |
{ |
return "<input name=\""+path()+"\" type=\"password\" size=\"30\">"; |
} |
} |
|
class File |
|
{ |
inherit String; |
constant type = "File"; |
constant width = 50; |
|
string read( ) |
|
{ |
return Stdio.read_bytes( query() ); |
} |
|
array stat() |
|
{ |
return file_stat( query() ); |
} |
} |
|
class Location |
|
{ |
inherit String; |
constant type = "Location"; |
constant width = 50; |
} |
|
class URL |
|
{ |
inherit String; |
constant type = "URL"; |
constant width = 50; |
|
array verify_set( string new_value ) |
{ |
return verify_port( new_value, 1 ); |
} |
} |
|
class Directory |
|
{ |
inherit String; |
constant type = "Directory"; |
constant width = 50; |
|
array verify_set( string value ) |
{ |
if( !(r_file_stat( value ) && (r_file_stat( value )[ ST_SIZE ] == -2 ))) |
return ({value+" is not a directory", value }); |
return ::verify_set( value ); |
} |
|
array stat() |
|
{ |
return file_stat( query() ); |
} |
|
array get( ) |
|
{ |
return get_dir( query() ); |
} |
} |
|
|
|
|
|
|
|
class MultipleChoice |
|
{ |
inherit Variable; |
static array _list = ({}); |
static mapping _table = ([]); |
|
void set_choice_list( array to ) |
|
{ |
_list = to; |
} |
|
array get_choice_list( ) |
|
|
{ |
return _list; |
} |
|
void set_translation_table( mapping to ) |
|
{ |
_table = to; |
} |
|
mapping get_translation_table( ) |
|
|
{ |
return _table; |
} |
|
static string _name( mixed what ) |
|
|
{ |
return (string)what; |
} |
|
static string _title( mixed what ) |
|
|
{ |
if( mapping tt = get_translation_table() ) |
return tt[ what ] || (string)what; |
return (string)what; |
} |
|
string render_form( RequestID id ) |
{ |
string res = "<select name='"+path()+"'>\n"; |
foreach( get_choice_list(), mixed elem ) |
{ |
mapping m = ([]); |
m->value = _name( elem ); |
if( m->value == query() ) |
m->selected="selected"; |
res += " "+Roxen.make_container( "option", m, _title( elem ) )+"\n"; |
} |
return res + "</select>"; |
} |
static void create( mixed default_value, array|mapping choices, |
int _flags, string std_name, string std_doc ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
::create( default_value, _flags, std_name, std_doc ); |
if( mappingp( choices ) ) { |
set_translation_table( choices ); |
set_choice_list( indices(choices) ); |
} else |
set_choice_list( choices ); |
} |
} |
|
|
|
|
|
|
class StringChoice |
|
{ |
inherit MultipleChoice; |
constant type = "StringChoice"; |
} |
|
|
class IntChoice |
|
{ |
inherit MultipleChoice; |
constant type = "IntChoice"; |
int transform_from_form( string what ) |
{ |
return (int)what; |
} |
} |
|
class FloatChoice |
|
{ |
inherit MultipleChoice; |
constant type = "FloatChoice"; |
static int _prec = 3; |
|
void set_precision( int prec ) |
|
|
|
{ |
_prec = prec; |
} |
|
static string _title( mixed what ) |
{ |
if( !_prec ) |
return sprintf( "%d", (int)what ); |
return sprintf( "%1."+_prec+"f", what ); |
} |
|
int transform_from_form( string what ) |
{ |
array q = get_choice_list(); |
mapping a = mkmapping( map( q, _name ), q ); |
return a[what] || (float)what; |
} |
} |
|
class FontChoice |
|
{ |
inherit StringChoice; |
constant type = "FontChoice"; |
void set_choice_list() |
{ |
} |
array get_choice_list() |
{ |
return roxenp()->fonts->available_fonts(); |
} |
static void create(mixed default_value,int flags, |
string std_name,string std_doc) |
|
|
|
|
|
|
|
|
|
|
{ |
::create( default_value, 0, flags,std_name, std_doc ); |
} |
} |
|
|
|
|
|
class List |
|
{ |
inherit String; |
constant type="List"; |
constant width = 40; |
|
string transform_to_form( mixed what ) |
|
|
{ |
return (string)what; |
} |
|
mixed transform_from_form( string what ) |
{ |
return what; |
} |
|
static int _current_count = time()*100+(gethrtime()/10000); |
void set_from_form(RequestID id) |
{ |
int rn; |
array l = query(); |
mapping vl = get_form_vars(id); |
|
|
if( (int)vl[".count"] != _current_count ) |
return; |
_current_count++; |
|
foreach( indices( vl ), string vv ) |
if( sscanf( vv, ".set.%d", rn ) ) |
{ |
m_delete( id->variables, path()+vv ); |
l[rn] = transform_from_form( vl[vv] ); |
m_delete( vl, vv ); |
} |
|
foreach( indices(vl), string vv ) |
if( sscanf( vv, ".up.%d.x%*s", rn ) == 2 ) |
{ |
m_delete( id->variables, path()+vv ); |
m_delete( vl, vv ); |
l = l[..rn-2] + l[rn..rn] + l[rn-1..rn-1] + l[rn+1..]; |
} |
else if( sscanf( vv, ".down.%d.x%*s", rn )==2 ) |
{ |
m_delete( id->variables, path()+vv ); |
l = l[..rn-1] + l[rn+1..rn+1] + l[rn..rn] + l[rn+2..]; |
} |
|
if( vl[".new.x"] ) |
{ |
m_delete( id->variables, path()+".new.x" ); |
l += ({ transform_from_form( "" ) }); |
} |
|
|
foreach( indices(vl), string vv ) |
if( sscanf( vv, ".delete.%d.x%*s", rn )==2 ) |
{ |
m_delete( id->variables, path()+vv ); |
l = l[..rn-1] + l[rn+1..]; |
} |
set( l ); |
} |
|
string render_form( RequestID id ) |
{ |
string prefix = path()+"."; |
int i; |
|
_current_count++; |
|
string res = "<table>\n" |
"<input type='hidden' name='"+prefix+"count' value='"+_current_count+"' />"; |
|
foreach( map(query(), transform_to_form), string val ) |
{ |
res += "<tr><td><font size='-1'>"+ input( prefix+"set."+i, val, width) + "</font></td>"; |
|
#define BUTTON(X,Y) ("<submit-gbutton2 name='"+X+"'>"+Y+"</submit-gbutton2>") |
if( i ) |
res += "\n<td>"+ |
BUTTON(prefix+"up."+i, "^")+ |
"</td>"; |
else |
res += "<td></td>"; |
if( i != sizeof( query())- 1 ) |
res += "\n<td>"+ |
BUTTON(prefix+"down."+i, "v") |
+"</td>"; |
else |
res += "<td></td>"; |
res += "\n<td>"+ |
BUTTON(prefix+"delete."+i, LOCALE("", "Delete") ) |
+"</td>"; |
"</tr>"; |
i++; |
} |
res += |
"<tr><td colspan='2'>"+ |
BUTTON(prefix+"new", LOCALE("", "New row") )+ |
"</td></tr></table>\n"; |
|
return res; |
} |
} |
|
|
|
|
|
class DirectoryList |
|
{ |
inherit List; |
constant type="DirectoryList"; |
|
array verify_set( array(string) value ) |
{ |
string warn = ""; |
foreach( value, string value ) |
if( !(r_file_stat( value ) && (r_file_stat( value )[ ST_SIZE ] == -2 ))) |
warn += value+" is not a directory\n"; |
if( strlen( warn ) ) |
return ({ warn, value }); |
return ::verify_set( value ); |
} |
} |
|
class StringList |
|
{ |
inherit List; |
constant type="StringList"; |
} |
|
class IntList |
|
{ |
inherit List; |
constant type="IntList"; |
constant width=20; |
|
string transform_to_form(int what) { return (string)what; } |
int transform_from_form(string what) { return (int)what; } |
} |
|
class FloatList |
|
{ |
inherit List; |
constant type="DirectorYList"; |
constant width=20; |
|
static int _prec = 3; |
|
void set_precision( int prec ) |
|
|
|
{ |
_prec = prec; |
} |
|
string transform_to_form(int what) |
{ |
return sprintf("%1."+_prec+"f", what); |
} |
float transform_from_form(string what) { return (float)what; } |
} |
|
class URLList |
|
{ |
inherit List; |
constant type="UrlList"; |
|
array verify_set( array(string) new_value ) |
{ |
string warn = ""; |
array res = ({}); |
foreach( new_value, string vv ) |
{ |
string tmp1, tmp2; |
[tmp1,tmp2] = verify_port( vv, 1 ); |
if( tmp1 ) |
warn += tmp1; |
res += ({ tmp2 }); |
} |
if( !strlen( warn ) ) |
warn = 0; |
return ({ warn, res }); |
} |
} |
|
class PortList |
|
{ |
inherit List; |
constant type="PortList"; |
|
array verify_set( array(string) new_value ) |
{ |
string warn = ""; |
array res = ({}); |
foreach( new_value, string vv ) |
{ |
string tmp1, tmp2; |
[tmp1,tmp2] = verify_port( vv, 0 ); |
if( tmp1 ) |
warn += tmp1; |
res += ({ tmp2 }); |
} |
if( !strlen( warn ) ) |
warn = ""; |
return ({ warn, res }); |
} |
} |
|
|
class FileList |
|
{ |
inherit List; |
constant type="FileList"; |
} |
|
|
|
|
|
|
class Flag |
|
{ |
inherit Variable; |
constant type = "Flag"; |
|
int transform_from_form( string what ) |
{ |
return (int)what; |
} |
|
string render_form( RequestID id ) |
{ |
string res = "<select name=\""+path()+"\"> "; |
if(query()) |
res += "<option value=\"1\" selected=\"selected\">" + |
LOCALE("yes", "Yes")+ "</option>\n" |
"<option value=\"0\">" +LOCALE("no", "No")+ "</option>\n"; |
else |
res += "<option value=\"1\">" +LOCALE("yes", "Yes")+ "</option>\n" |
"<option value=\"0\" selected>" +LOCALE("no", "No")+ "</option>\n"; |
return res+"</select>"; |
} |
} |
|
|
|
|
|
|
|
|
array(string) verify_port( string port, int nofhttp ) |
{ |
if(!strlen(port)) |
return ({ 0, port }); |
string warning=""; |
if( (int)port ) |
{ |
warning += "Assuming http://*:"+port+"/ for "+port+"\n"; |
port = "http://*:"+port+"/"; |
} |
string protocol, host, path; |
|
if(!strlen( port ) ) |
return ({ "Empty URL field", port }); |
|
if(sscanf( port, "%[^:]://%[^/]%s", protocol, host, path ) != 3) |
return ({""+port+" does not conform to URL syntax\n", port }); |
|
if( path == "" ) |
{ |
warning += "Added / to the end of "+port+"\n"; |
host += "/"; |
} |
int pno; |
if( sscanf( host, "%s:%d", host, pno ) == 2) |
{ |
if( roxenp()->protocols[ lower_case( protocol ) ] |
&& (pno == roxenp()->protocols[ lower_case( protocol ) ]->default_port )) |
warning += "Removed the " |
"default port number ("+pno+") from "+port+"\n"; |
else |
host = host+":"+pno; |
} |
if( nofhttp && protocol == "fhttp" ) |
{ |
warning += "Changed " + protocol + " to http\n"; |
protocol = "http"; |
} |
if( protocol != lower_case( protocol ) ) |
{ |
warning += "Changed "+protocol+" to "+ lower_case( protocol )+"\n"; |
} |
|
port = lower_case( protocol )+"://"+host+path; |
|
if( !roxenp()->protocols[ lower_case( protocol ) ] ) |
warning += "Warning: The protocol "+lower_case(protocol)+" is unknown\n"; |
return ({ (strlen(warning)?warning:0), port }); |
} |
|
|