Roxen.git / server / etc / modules / Variable.pmod / module.pmod

version» Context lines:

Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1: - // $Id: module.pmod,v 1.64 2001/08/24 14:44:26 nilsson Exp $ + // $Id$      #include <module.h>   #include <roxen.h>      // Locale macros   //<locale-token project="roxen_config"> LOCALE </locale-token>      #define LOCALE(X,Y) \    ([string](mixed)Locale.translate("roxen_config",roxenp()->locale->get(),X,Y))    - // Increased for each variable, used to index the mappings below. - static int unique_vid; + // Increased for each variable, used to index the mappings below. The unique + // prefix is needed to avoid clobbering variables after server restart. + protected int unique_vid; + protected string unique_prefix = (string) getpid();      // The theory is that most variables (or at least a sizable percentage - // of all variables) does not have these members. Thus this saves + // of all variables) do not have these members. Thus this saves   // quite a respectable amount of memory, the cost is speed. But   // hopefully not all that great a percentage of speed. - 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)) + protected mapping(string:mixed) changed_values = ([]); + protected mapping(string:function(object:void)) changed_callbacks = ([]); + protected mapping(string:int) all_flags = ([]); + protected mapping(string:string) all_warnings = ([]); + protected mapping(string:function(RequestID,object:int))    invisibility_callbacks = set_weak_flag( ([]), 1 );      mapping(string:Variable) all_variables = set_weak_flag( ([]), 1 );      mapping get_all_variables()   {    return all_variables;   }      Variable get_variables( string v )
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:57:    m = ([ "href":diff_url,"target":"_new", ]);    diff_button =    Roxen.make_container( "a",m,    Roxen.make_container(    button_tag,    ([]),    LOCALE(474,"Show changes")    ) );    }    } -  m = ([ "href":def_url, ]); +  m = ([ "href" : def_url, +  "onclick" : "return confirm('" + LOCALE(1041, "Are you sure you want " +  "to restore the default " +  "value?") + "');" ]);    return diff_button + " " +    Roxen.make_container( "a",m,    Roxen.make_container( button_tag, ([]),    LOCALE(475, "Restore default value" )+    (oneliner||"") ) );      }      class Diff   { -  static private array(string) diff; +  private array(string) diff;    -  static private +  private    array(string) print_row(array(string) diff_old, array(string) diff_new,    int line, int|void start, int|void end)    {    if(!sizeof(diff_old) && sizeof(diff_new))    // New row.    return Array.map(diff_new, lambda(string s) {return "+ " + s;} );       if(sizeof(diff_old) && !sizeof(diff_new))    // Deleted row.    return Array.map(diff_old, lambda(string s) {return "- " + s;} );
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:185:      class Variable   //! The basic variable type in Roxen. All other variable types should   //! inherit this class.   {    constant is_variable = 1;       constant type = "Basic";    //! Mostly used for debug (sprintf( "%O", variable_obj ) uses it)    -  int _id = unique_vid++; +  string _id = unique_prefix + "_" + (string) unique_vid++;    // used for indexing the mappings.    -  static mixed _initial; // default value -  static string _path = sprintf("v%x",_id); // used for forms -  static LocaleString __name, __doc; +  protected mixed _initial; // default value +  protected string _path = sprintf("v%s",_id); // used for forms +  protected LocaleString __name, __doc;       string diff( int render )    //! Generate a html diff of the difference between the current    //! value and the default value.    //!    //! This method is used by the configuration interface.    //!    //! The argument @[render] is used to select the operation mode.    //!    //! render=0 means that you should generate an inline diff. This
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:219:    //! HTML code to render on.    //!    //! If you return 0 for render=1 as well, no difference will be    //! shown. This is the default.    {    return 0;    }       void destroy()    { +  if (global::this) {    // clean up...    m_delete( all_flags, _id );    m_delete( all_warnings, _id );    m_delete( invisibility_callbacks, _id );    m_delete( changed_values, _id );    } -  +  }       string get_warnings()    //! Returns the current warnings, if any.    {    return all_warnings[ _id ];    }       int get_flags()    //! Returns the 'flags' field for this variable.    //! Flags is a bitwise or of one or more of    //! -  //! VAR_EXPERT Only for experts -  //! VAR_MORE Only visible when more-mode is on (default on) -  //! VAR_DEVELOPER Only visible when devel-mode is on (default on) -  //! VAR_INITIAL Should be configured initially. +  //! @int +  //! @value VAR_EXPERT +  //! Only for experts. +  //! @value VAR_MORE +  //! Only visible when more-mode is on (default on). +  //! @value VAR_DEVELOPER +  //! Only visible when devel-mode is on (default on). +  //! @value VAR_INITIAL +  //! Should be configured initially. +  //! @value VAR_INVISIBLE +  //! The variable is permanently hidden from view. +  //! @endint    {    return all_flags[_id];    }       void set_flags( int flags )    //! Set the flags for this variable.    //! Flags is a bitwise or of one or more of    //! -  //! VAR_EXPERT Only for experts -  //! VAR_MORE Only visible when more-mode is on (default on) -  //! VAR_DEVELOPER Only visible when devel-mode is on (default on) -  //! VAR_INITIAL Should be configured initially. +  //! @int +  //! @value VAR_EXPERT +  //! Only for experts. +  //! @value VAR_MORE +  //! Only visible when more-mode is on (default on). +  //! @value VAR_DEVELOPER +  //! Only visible when devel-mode is on (default on). +  //! @value VAR_INITIAL +  //! Should be configured initially. +  //! @value VAR_INVISIBLE +  //! The variable is permanently hidden from view. +  //! @endint    {    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|void variable_in_cfif ) -  +  //! Check if the variable should be visible to the +  //! configuration interface user. +  //! +  //! @param variable_in_cfif +  //! If variable_in_cfif is true, the variable is in a module +  //! that is added to the configuration interface itself. +  //! +  //! @returns    //! Return 1 if this variable should be visible in the    //! configuration interface. The default implementation check the    //! 'flags' field, and the invisibility callback, if any. See    //! get_flags, set_flags and set_invisibibility_check_callback    //! -  //! If variable_in_cfif is true, the variable is in a module -  //! that is added to the configuration interface itself. +     {    int flags = get_flags();    function cb;    if( flags & VAR_INVISIBLE ) return 0;    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( (flags & VAR_NOT_CFIF) && variable_in_cfif ) return 0;    if( (cb = get_invisibility_check_callback() ) &&
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:345:       LocaleString doc( )    //! Return the documentation for this variable (locale dependant).    //!    //! The default implementation queries the locale object in roxen    //! to get the documentation.    {    return __doc || "";    }    +  void set_doc (LocaleString doc) +  //! Set the (locale dependent) documentation for this variable. +  { +  __doc = doc; +  } +     LocaleString name( )    //! Return the name of this variable (locale dependant).    //!    //! The default implementation queries the locale object in roxen    //! to get the documentation.    {    return __name || LOCALE(326,"unnamed")+" "+_id;    }    -  +  void set_name (LocaleString name) +  //! Set the (locale dependent) name for this variable. +  { +  __name = name; +  } +     LocaleString type_hint( )    //! Return the type hint for this variable.    //! Type hints are generic documentation for this variable type,    //! and is the same for all instances of the type.    {    }       mixed default_value()    //! The default (initial) value for this variable.    {    return _initial;    }    -  +  void set_default_value (mixed to) +  //! Change the default value. If the variable was previously set to +  //! the old default value, this will also change its actual value. +  { +  _initial = to; +  } +     void set_warning( string to )    //! Set the warning shown in the configuration interface    {    if( to && strlen(to) )    all_warnings[ _id ] = to;    else    m_delete( all_warnings, _id );    }       void add_warning( string to )
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:395:    //! Otherwise 0 is returned. 0 is also returned if the variable was    //! not changed by the set. 1 is returned if the variable was    //! changed, and -1 is returned if the variable was changed back to    //! its default value.    //!    //! If verify_set() threw a string, ([])[0] is returned, that is,    //! 0 with zero_type set.    //!    //! If verify_set() threw an exception, the exception is thrown.    { -  string err, e2; +  string err; +  mixed e2;    if( e2 = catch( [err,to] = verify_set( to )) )    {    if( stringp( e2 ) )    {    add_warning( e2 );    return ([])[0];    }    throw( e2 );    }    add_warning( err );
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:422:    //! the variable was changed back to it's default value and 0    //! otherwise.    {    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() ) ); +  get_changed_callback()( this_object() );    return 1;    }    else    {    m_delete( changed_values, _id );    if( get_changed_callback() ) -  catch( get_changed_callback()( this_object() ) ); +  get_changed_callback()( this_object() );    return -1;    }    }       mixed query()    //! Returns the current value for this variable.    {    mixed v;    if( !zero_type( v = changed_values[ _id ] ) )    return v;
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:474:    //! If a string is thrown, it will be used as a error message from    //! set, and the variable will not be changed.    {    return ({ 0, new_value });    }       mapping(string:string) get_form_vars( RequestID id )    //! Return all form variables preficed with path().    {    string p = path(); -  array names = glob( p+"*", indices(id->variables) ); +  array names = glob( p+"*", indices(id->real_variables) );    mapping res = ([ ]);    foreach( sort(names), string n ) -  res[ n[strlen(p).. ] ] = id->variables[ n ]; +  res[ n[strlen(p).. ] ] = id->real_variables[ n ][0];    return res;    }       mixed transform_from_form( string what, mapping|void v )    //! Given a form value, return what should be set.    //! Used by the default set_from_form implementation.    {    return what;    }       int(0..1) set_from_form( RequestID id, void|int(0..1) force ) -  //! Set this variable from the form variable in id->Variables, +  //! Set this variable from the form variable in id->variables,    //! if any are available. The default implementation simply sets    //! the variable to the string in the form variables. @[force]    //! forces the variable to be set even if the variable already    //! has the new value, forcing possible warnings to be added.    //! Returns 1 if the variable was changed, otherwise 0.    //!    //! Other side effects: Might create warnings to be shown to the    //! user (see get_warnings)    //!    //! Calls verify_set_from_form and verify_set    {    mixed val;    if( sizeof( val = get_form_vars(id)) && val[""])    { -  +  set_warning(0);    val = transform_from_form( val[""], val );    if( !force && val == query() )    return 0;    array b;    mixed q = catch( b = verify_set_from_form( val ) );    if( q || sizeof( b ) != 2 )    {    if( q )    add_warning( q );    else    add_warning( "Internal error: Illegal sized array "    "from verify_set_from_form\n" );    return 0;    }    if( b )    { -  set_warning( b[0] ); +  add_warning( b[0] );    set( b[1] );    return 1;    }    }    }       string path()    //! A unique identifier for this variable.    //! Should be used to prefix form variable names.    //!
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:566:    //! from the path() function.       string render_view( RequestID id )    //! Return a 'view only' version of this variable.    {    mixed v = query();    if( arrayp(v) ) v = map(v,lambda(mixed v){return(string)v;})*", " ;    return Roxen.html_encode_string( (string)v );    }    -  static string _sprintf( int i ) +  protected string _sprintf( int i )    {    if( i == 'O' )    return sprintf( "Variable.%s(%s)",type,(string)name());    }    -  static void create(mixed default_value, void|int flags, +  protected void create(mixed default_value, void|int flags,    void|LocaleString std_name, void|LocaleString std_doc)    //! Constructor.    //! Flags is a bitwise or of one or more of    //!    //! VAR_EXPERT Only for experts    //! VAR_MORE Only visible when more-mode is on (default on)    //! VAR_DEVELOPER Only visible when devel-mode is on (default on)    //! VAR_INITIAL Should be configured initially.    //!    //! The std_name and std_doc is the name and documentation string    //! for the default locale (always english)    {    set_flags( flags );    _initial = default_value;    __name = std_name;    __doc = std_doc;    all_variables[ path() ] = this_object();    }   }    -  + class NoLimit + { +  string _sprintf (int flag) +  { +  switch (flag) { +  case 's': return "n/a"; +  case 'O': return this == no_limit ? "no_limit" : "<bogus no_limit clone>"; +  default: return 0; +  } +  } + }    -  + NoLimit no_limit = NoLimit(); + //! @[no_limit] is used as value in a limit setting to signify that it + //! isn't applicable, to allow open ended intervals in e.g. @[Float] + //! and @[Int]. + //! + //! @note + //! Always use the @[no_limit] object, never instance another one from + //! the @[NoLimit] class.       -  +    // =====================================================================   // Float   // =====================================================================      class Float   //! Float variable, with optional range checks, and adjustable precision.   {    inherit Variable;    constant type = "Float"; -  static float _max, _min; -  static int _prec = 2; +  protected float|NoLimit _max = no_limit, _min = no_limit; +  protected int _prec = 2; +  protected int _may_be_empty = 0; +  protected int(0..1) _is_empty = 0;    -  static string _format( float m ) +  protected string _format( float|NoLimit m )    { -  +  if (m == no_limit) +  return "n/a";    if( !_prec )    return sprintf( "%d", (int)m );    return sprintf( "%1."+_prec+"f", m );    }       string diff( int render )    {    if(!render)    return "("+_format(default_value())+")";    }    -  void set_range(float minimum, float maximum ) -  //! Set the range of the variable, if minimum and maximum are both -  //! 0.0 (the default), the range check is removed. +  void set_range(float|NoLimit minimum, float|NoLimit maximum ) +  //! Set the range of the variable. +  //! +  //! As a compatibility measure, the range check is removed if +  //! maximum < minimum.    { -  +  if (maximum != no_limit && minimum != no_limit && maximum < minimum) +  _max = _min = no_limit; +  else {    _max = maximum;    _min = minimum;    } -  +  }       void set_precision( int prec )    //! Set the number of _decimals_ shown to the user.    //! If prec is 3, and the float is 1, 1.000 will be shown.    //! Default is 2.    {    _prec = prec;    }       array(string|float) verify_set( float new_value )    { -  +  if (new_value == (float)0 && _is_empty) +  return ({ 0, new_value });    string warn; -  if( new_value > _max && _max > _min) +  if(_max != no_limit && new_value > _max)    {    warn = sprintf(LOCALE(328,"Value is bigger than %s, adjusted"),    _format(_max) );    new_value = _max;    } -  else if( new_value < _min && _min < _max) +  else if(_min != no_limit && new_value < _min)    {    warn = sprintf(LOCALE(329,"Value is less than %s, adjusted"),    _format(_min) );    new_value = _min;    }    return ({ warn, new_value });    }    -  float transform_from_form( string what ) +  float transform_from_form( mixed what )    { -  +  if (!sizeof(what) && _may_be_empty) { +  _is_empty = 1; +  return (float)0; +  } +  string junk; +  if(!sizeof(what)) { +  add_warning(LOCALE(80, "No data entered.\n")); +  return _min; +  } +  sscanf(what, "%f%s", what, junk); +  if(!junk) { +  add_warning(LOCALE(81, "Data is not a float.\n")); +  return _min; +  } +  if(sizeof(junk)) +  add_warning(sprintf(LOCALE(82, "Found the string %O trailing after the float.\n"), junk));    return (float)what;    }       string render_view( RequestID id )    {    return Roxen.html_encode_string( _format(query()) );    }       string render_form( RequestID id, void|mapping additional_args )    {    int size = 15; -  if( _max != _min ) +  if( _max != no_limit && _min != no_limit )    size = max( strlen(_format(_max)), strlen(_format(_min)) )+2; -  return input(path(), (query()==""?"":_format(query())), size, additional_args); +  string value; +  if (_may_be_empty && (float)query() == (float)0) +  value = ""; +  else +  value = query()==""? "" : _format( (float)query() ); +  +  additional_args = additional_args || ([]); +  additional_args->type="text"; +  +  return input(path(), value, size, additional_args);    } -  +  +  void may_be_empty(int(0..1) state) +  //! Decides if an empty variable also is valid. +  { +  _may_be_empty = state;    } -  + }               // =====================================================================   // Int   // =====================================================================      class Int   //! Integer variable, with optional range checks   {    inherit Variable;    constant type = "Int"; -  static int _max, _min; +  protected int|NoLimit _max = no_limit, _min = no_limit;    -  void set_range(int minimum, int maximum ) -  //! Set the range of the variable, if minimum and maximum are both -  //! 0 (the default), the range check is removed. +  protected int(0..1) _may_be_empty = 0; +  protected int(0..1) _is_empty = 0; +  +  void set_range(int|NoLimit minimum, int|NoLimit maximum ) +  //! Set the range of the variable. +  //! +  //! As a compatibility measure, the range check is removed if +  //! maximum < minimum.    { -  +  if (maximum != no_limit && minimum != no_limit && maximum < minimum) +  _max = _min = no_limit; +  else {    _max = maximum;    _min = minimum;    } -  +  }       string diff( int render )    {    if(!render)    return "("+default_value()+")";    }       array(string|int) verify_set( mixed new_value )    { -  +  if (new_value == 0 && _is_empty) +  return ({ 0, new_value });    string warn;    if(!intp( new_value ) )    return ({ sprintf(LOCALE(152,"%O is not an integer"),new_value),    query() }); -  if( new_value > _max && _max > _min ) +  if( _max != no_limit && new_value > _max)    {    warn = sprintf(LOCALE(328,"Value is bigger than %s, adjusted"),    (string)_max );    new_value = _max;    } -  else if( new_value < _min && _min < _max) +  else if( _min != no_limit && new_value < _min)    {    warn = sprintf(LOCALE(329,"Value is less than %s, adjusted"),    (string)_min );    new_value = _min;    }    return ({ warn, new_value });    }       int transform_from_form( mixed what )    { -  sscanf( what, "%d", what ); +  if (!sizeof(what) && _may_be_empty) { +  _is_empty = 1; +  return 0; +  } +  string junk; +  if(!sizeof(what)) { +  add_warning(LOCALE(80, "No data entered.\n")); +  return _min; +  } +  sscanf( what, "%d%s", what, junk ); +  if(!junk) { +  add_warning(LOCALE(83, "Data is not an integer\n")); +  return _min; +  } +  if(sizeof(junk)) +  add_warning(sprintf(LOCALE(84, "Found the string %O trailing after the integer.\n"), junk));    return what;    }       string render_form( RequestID id, void|mapping additional_args )    {    int size = 10; -  if( _min != _max ) +  if( _min != no_limit && _max != no_limit )    size = max( strlen((string)_max), strlen((string)_min) )+2; -  return input(path(), (string)query(), size, additional_args); +  string value = (query() == 0 && _is_empty)? "" : (string)query(); +  +  additional_args = additional_args || ([]); +  additional_args->type="text"; +  +  return input(path(), value, size, additional_args);    } -  +  +  void may_be_empty(int(0..1) state) +  //! Decides if an empty variable also is valid. +  { +  _may_be_empty = state;    } -  + }    -  + class TmpInt + //! @[Int] that doesn't get saved. + { +  inherit Int; +  void save() {} + }    -  +    // =====================================================================   // String   // =====================================================================   class String   //! String variable   {    inherit Variable;    constant type = "String";    int width = 40;    //! The width of the input field. Used by overriding classes.
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:763:    return "("+Roxen.html_encode_string( default_value() )+")";    }       array(string) verify_set_from_form( mixed new )    {    return ({ 0, [string]new-"\r" });    }       string render_form( RequestID id, void|mapping additional_args )    { +  additional_args = additional_args || ([]); +  additional_args->type="text";    return input(path(), (string)query(), width, additional_args);    }   }      // =====================================================================   // Text   // =====================================================================   class Text   //! Text (multi-line string) variable   {    inherit String;    constant type = "Text";    -  int cols = 60; +  int cols = 56;    //! The width of the textarea       int rows = 10;    //! The height of the textarea       string diff( int render )    {    switch( render )    {    case 0: return 0;
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:808:    }    }       array(string) verify_set_from_form( mixed new )    {    return ({ 0, [string]new-"\r" });    }       string render_form( RequestID id, void|mapping additional_args )    { -  return "<textarea cols='"+cols+"' rows='"+rows+"' name='"+path()+"'>" +  return "<textarea cols='"+cols+"' rows='"+rows+"' name='"+path()+"' wrap='off'>"    + Roxen.html_encode_string( query() || "" ) +    "</textarea>";    }    -  static void create(mixed default_value, void|int flags, +  protected void create(mixed default_value, void|int flags,    void|LocaleString std_name, void|LocaleString std_doc)    //! Constructor.    //! Flags is a bitwise or of one or more of    //!    //! VAR_EXPERT Only for experts    //! VAR_MORE Only visible when more-mode is on (default on)    //! VAR_DEVELOPER Only visible when devel-mode is on (default on)    //! VAR_INITIAL Should be configured initially.    //!    //! The std_name and std_doc is the name and documentation string
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:973:         // =====================================================================   // MultipleChoice (one of many) baseclass   // =====================================================================      class MultipleChoice   //! Base class for multiple-choice (one of many) variables.   {    inherit Variable; -  static array _list = ({}); -  static mapping _table = ([]); +  protected array _list = ({}); +  protected mapping _table = ([]);       string diff( int render )    {    if(!render)    return "("+_title( default_value() )+")";    }       void set_choice_list( array to )    //! Set the list of choices.    {
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1008:    _table = to;    }       mapping get_translation_table( )    //! Get the lookup table. Used by this class as well.    //! You can overload this function if you want a dynamic table.    {    return _table;    }    -  static string _name( mixed what ) +  protected string _name( mixed what )    //! Get the name used as value for an element gotten from the    //! get_choice_list() function.    {    return (string)what;    }    -  static string _title( mixed what ) +  protected string _title( mixed what )    //! Get the title used as description (shown to the user) for an    //! element gotten from the get_choice_list() function.    {    if( mapping tt = get_translation_table() )    return tt[ what ] || (string)what;    return (string)what;    }       string render_form( RequestID id, void|mapping additional_args )    { -  string res = "<select name='"+path()+"'>\n"; +  string autosubmit = ""; +  if(additional_args && additional_args->autosubmit) +  autosubmit = " autosubmit='autosubmit' onChange='javascript:submit();'"; +  string res = "<select name='"+path()+"'"+autosubmit+">\n";    string current = _name (query());    int selected = 0;    foreach( get_choice_list(), mixed elem )    {    mapping m = ([]);    m->value = _name( elem );    if( equal( m->value, current ) ) {    m->selected="selected";    selected = 1;    }    res += " "+Roxen.make_container( "option", m, _title( elem ) )+"\n";    }    if (!selected)    // Make an entry for the current value if it's not in the list,    // so no other value appears to be selected, and to ensure that    // the value doesn't change as a side-effect by another change.    res += " " + Roxen.make_container ( -  "option", (["value":_name(current), "selected": "selected"]), -  sprintf(LOCALE(332,"(keep stale value %s)"),_name(current))); +  "option", (["value":current, "selected": "selected"]), +  sprintf(LOCALE(332,"(keep stale value %s)"),current));    return res + "</select>";    }    -  static void create( mixed default_value, array|mapping choices, +  protected void create( mixed default_value, array|mapping choices,    void|int _flags, void|LocaleString std_name,    void|LocaleString std_doc )    //! Constructor.    //!    //! Choices is the list of possible choices, can be set with    //! set_choice_list at any time.    //!    //! Flags is a bitwise or of one or more of    //!    //! VAR_EXPERT Only for experts    //! VAR_MORE Only visible when more-mode is on (default on)    //! VAR_DEVELOPER Only visible when devel-mode is on (default on)    //! VAR_INITIAL Should be configured initially.    //!    //! The std_name and std_doc is the name and documentation string    //! for the default locale (always english)    {    ::create( default_value, _flags, std_name, std_doc );    if( mappingp( choices ) ) {    set_translation_table( choices ); -  set_choice_list( indices(choices) ); +  set_choice_list( sort(indices(choices)) );    } else    set_choice_list( choices );    }   }         // =====================================================================   // MultipleChoice subclasses   // =====================================================================   
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1105:    {    return (int)what;    }   }      class FloatChoice   //! Select one of many floating point (real) numbers.   {    inherit MultipleChoice;    constant type = "FloatChoice"; -  static int _prec = 3; +  protected int _prec = 3;       void set_precision( int prec )    //! Set the number of _decimals_ shown to the user.    //! If prec is 3, and the float is 1, 1.000 will be shown.    //! Default is 2.    {    _prec = prec;    }    -  static string _title( mixed what ) +  protected 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 );
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1143:    inherit StringChoice;    constant type = "FontChoice";    void set_choice_list()    {    }    array get_choice_list()    {    return roxenp()->fonts->available_fonts();    }    -  static void create(mixed default_value, void|int flags, +  protected void create(mixed default_value, void|int flags,    void|LocaleString std_name, void|LocaleString std_doc)    //! Constructor.    //! Flags is a bitwise or of one or more of    //!    //! VAR_EXPERT Only for experts    //! VAR_MORE Only visible when more-mode is on (default on)    //! VAR_DEVELOPER Only visible when devel-mode is on (default on)    //! VAR_INITIAL Should be configured initially.    //!    //! The std_name and std_doc is the name and documentation string    //! for the default locale (always english)    {    ::create( default_value, 0, flags,std_name, std_doc );    }   }    -  + class TableChoice + { +  inherit StringChoice; +  constant type = "TableChoice"; +  Variable db; +  +  array(string) get_choice_list( ) +  { +  return sort(DBManager.db_tables( db->query() )); +  } +  +  void create( string default_value, +  void|int flags, +  void|LocaleString std_name, +  void|LocaleString std_doc, +  Variable _dbchoice ) +  { +  ::create( default_value, ({}), flags, std_name, std_doc ); +  db = _dbchoice; +  } + } +  +    class DatabaseChoice   //! Select a database from all available databases.   {    inherit StringChoice;    constant type = "DatabaseChoice";       function(void:void|object) config = lambda() { return 0; };       DatabaseChoice set_configuration_pointer( function(void:object) configuration )    //! Provide a function that returns a configuration object,    //! that will be used for authentication against the database    //! manager. Typically called as -  //! @code{set_configuration_pointer(my_configuration)@}. +  //! @expr{set_configuration_pointer(my_configuration)@}.    {    config = configuration;    return this_object();    }       array get_choice_list( )    { -  +  if (!functionp(config)) { +  // Some modules apparently send in a configration reference instead of +  // a function pointer when calling set_configuration_pointer(). +  report_warning("Incorrect usage of Variable.DatabaseChoice:\n\n%s", +  describe_backtrace(backtrace())); +  return ({ " none" }); +  }    return ({ " none" }) + sort(DBManager.list( config() ));    }    -  static void create(string default_value, void|int flags, +  protected void create(string default_value, void|int flags,    void|LocaleString std_name, void|LocaleString std_doc)    {    ::create( default_value, ({}), flags, std_name, std_doc );    }   }    -  + class AuthMethodChoice + { +  inherit StringChoice; +  constant type = "AuthMethodChoice";    -  +  protected Configuration config; +  +  array get_choice_list( ) +  { +  return ({ " all" }) + sort( config->auth_modules()->name ); +  } +  +  protected void create( string default_value, int flags, +  string std_name, string std_doc, +  Configuration c ) +  { +  config = c; +  ::create( default_value, ({}), flags, std_name, std_doc ); +  } + } +  + class UserDBChoice + { +  inherit StringChoice; +  constant type = "UserDBChoice"; +  +  protected Configuration config; +  +  array get_choice_list( ) +  { +  return ({ " all" }) + sort( config->user_databases()->name ); +  } +  +  protected void create( string default_value, int flags, +  string std_name, string std_doc, +  Configuration c ) +  { +  config = c; +  ::create( default_value, ({}), flags, std_name, std_doc ); +  } + } +  + //! Select a module in the current configuration. + class ModuleChoice + { +  inherit StringChoice; +  constant type = "ModuleChoice"; +  protected Configuration conf; +  protected string module_id; +  protected string default_id; +  protected int automatic_dependency; +  +  int low_set(RoxenModule to) +  { +  RoxenModule old = changed_values[_id]; +  if (!old) { +  if (module_id) { +  old = transform_from_form(module_id); +  } else { +  old = default_value(); +  if (old) { +  module_id = _name(old); +  } +  } +  if (old) { +  changed_values[_id] = old; +  } +  } +  if (to == old) return 0; +  changed_values[_id] = to; +  if (module_id == _name(to)) return 0; // Reloaded module or similar. +  module_id = _name(to); +  if( get_changed_callback() ) +  get_changed_callback()( this_object() ); +  return 1; +  } +  +  // NOTE: Will be called with a string at module init! +  int set(string|RoxenModule to) +  { +  if (stringp(to)) { +  module_id = to; +  RoxenModule mod = transform_from_form (to); +  if (!mod && automatic_dependency && conf->enabled_modules[to]) { +  conf->add_modules (({to}), 1); +  mod = transform_from_form (to); +  } +  if (!mod && conf->enabled_modules[to]) +  // The module exists but isn't started yet. Don't call set() +  // in this case since that will cause a bogus warning. +  return 0; +  to = mod; +  } +  return ::set(to); +  } +  +  RoxenModule query() +  { +  RoxenModule res = changed_values[_id]; +  if (!res) { +  if (module_id) { +  // The module might have been reloaded. +  // Try locating it again. +  res = transform_from_form(module_id); +  if (res) low_set(res); +  } else { +  res = default_value(); +  if (res) low_set(res); +  } +  } +  return res; +  } +  +  //! Fetch the unsorted list of choices. +  protected array low_get_choice_list() +  { +  return indices(conf->otomod); +  } +  +  array get_choice_list() +  { +  array res = low_get_choice_list(); +  // Sort order: +  // priority: descending, +  // title: ascending, +  // module_id: ascending. +  sort(res->module_local_id(), res); +  sort(map(res, _title), res); +  res = reverse(res); +  sort(res->query("_priority"), res); +  res = reverse(res); +  return res; +  } +  +  protected string _name(RoxenModule val) +  { +  return val?val->module_local_id():""; +  } +  +  protected string _title(RoxenModule val) +  { +  return val?val->module_name:""; +  } +  +  RoxenModule transform_from_form(string module_id, mapping|void v) +  { +  return conf->find_module(module_id); +  } +  +  RoxenModule default_value() +  { +  if (default_id) { +  return transform_from_form(default_id); +  } +  array(RoxenModule) modules = get_choice_list(); +  if (sizeof(modules)) { +  return modules[0]; +  } +  return UNDEFINED; +  } +  +  array(string|mixed) verify_set( mixed new_value ) +  { +  if (!new_value) { +  return ({ "Not configured", 0 }); +  } +  return ({ 0, new_value }); +  } +  +  //! @param default_id +  //! The @[RoxenModule.module_local_id] of the default value. +  //! @param conf +  //! The current configuration. +  //! @param no_automatic_dependency +  //! Do not automatically depend on the chosen module. Normally, if +  //! it already exists in the configuration then it will be loaded +  //! before @expr{start@} in this module is called. Setting this +  //! flag disables that. +  protected void create(string default_id, int flags, +  string std_name, string std_doc, +  Configuration conf, +  void|int no_automatic_dependency) +  { +  this_program::default_id = default_id; +  this_program::conf = conf; +  automatic_dependency = !no_automatic_dependency; +  ::create(0, ({}), flags, std_name, std_doc); +  } + } +  + //! Select a module that provides the specified interface. + class ProviderChoice + { +  inherit ModuleChoice; +  constant type = "ProviderChoice"; +  protected string provides; +  +  protected array low_get_choice_list() +  { +  return conf->get_providers(provides); +  } +  +  //! @param default_id +  //! The @[RoxenModule.module_local_id] of the default value. +  //! @param provides +  //! The provider string to match modules against. +  //! @param conf +  //! The current configuration. +  protected void create(string default_id, int flags, +  string std_name, string std_doc, +  string provides, Configuration conf) +  { +  this_program::provides = provides; +  ::create(default_id, flags, std_name, std_doc, conf); +  } + } +    // =====================================================================   // List baseclass   // =====================================================================   class List   //! Many of one type types   {    inherit Variable;    constant type="List";    int width = 40;    -  +  array(string|array(string)) verify_set(mixed to) +  { +  if (stringp(to)) { +  // Backward compatibility junk... +  return ({ "Compatibility: " +  "Converted from TYPE_STRING to TYPE_STRING_LIST.\n", +  (to-" ")/"," }); +  } +  return ::verify_set(to); +  } +     string transform_to_form( mixed what )    //! Override this function to do the value->form mapping for    //! individual elements in the array.    {    return (string)what;    }       mixed transform_from_form( string what,mapping v )    {    return what;    }    -  static int _current_count = time()*100+(gethrtime()/10000); +  protected int _current_count = time()*100+(gethrtime()/10000);    int(0..1) set_from_form(RequestID id)    {    int rn, do_goto; -  array l = query(); +  array l = copy_value(query());    mapping vl = get_form_vars(id);    // first do the assign...    if( (int)vl[".count"] != _current_count )    return 0;    _current_count++; -  +  set_warning(0);       foreach( indices( vl ), string vv )    if( sscanf( vv, ".set.%d", rn ) && (vv == ".set."+rn) )    { -  m_delete( id->variables, path()+vv ); +  if ((rn >= 0) && (rn < sizeof(l))) { +  m_delete( id->real_variables, path()+vv );    l[rn] = transform_from_form( vl[vv], vl );    m_delete( vl, vv ); -  +  } else { +  report_debug("set_from_form(%O): vv:%O sizeof(l):%d\n", +  id, vv, sizeof(l));    } -  +  }    // then the move...    foreach( indices(vl), string vv )    if( sscanf( vv, ".up.%d.x%*s", rn ) == 2 )    {    do_goto = 1; -  m_delete( id->variables, path()+vv ); +  m_delete( id->real_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 )    {    do_goto = 1; -  m_delete( id->variables, path()+vv ); +  m_delete( id->real_variables, path()+vv );    l = l[..rn-1] + l[rn+1..rn+1] + l[rn..rn] + l[rn+2..];    }    // then the possible add.    if( vl[".new.x"] )    {    do_goto = 1; -  m_delete( id->variables, path()+".new.x" ); +  m_delete( id->real_variables, path()+".new.x" );    l += ({ transform_from_form( "",vl ) });    }       // .. and delete ..    foreach( indices(vl), string vv )    if( sscanf( vv, ".delete.%d.x%*s", rn )==2 )    {    do_goto = 1; -  m_delete( id->variables, path()+vv ); +  m_delete( id->real_variables, path()+vv );    l = l[..rn-1] + l[rn+1..];    }       array b;    mixed q = catch( b = verify_set_from_form( l ) );    if( q || sizeof( b ) != 2 )    {    if( q ) -  set_warning( q ); +  add_warning( q );    else -  set_warning( "Internal error: Illegal sized array " +  add_warning( "Internal error: Illegal sized array "    "from verify_set_from_form\n" );    return 0;    }       int ret;    if( b )    { -  set_warning( b[0] ); +  add_warning( b[0] );    set( b[1] );    ret = 1;    }       if( do_goto && !id->misc->do_not_goto )    {    RequestID nid = id;    while( nid->misc->orig )    nid = id->misc->orig;       string section = RXML.get_var("section", "var");    string query = nid->query;    if( !query )    query = "";    else    query += "&"; -  query += "random="+random(4949494)+(section?"&section="+section:""); +     -  nid->misc->moreheads = -  ([ -  "Location":nid->not_query+(nid->misc->path_info||"")+ -  "?"+query+"#"+path(), -  ]); +  // The URL will get a fragment identifier below and since some +  // broken browsers (MSIE) incorrectly includes the fragment in +  // the last variable value we'll place section before random. +  query += +  (section ? ("section=" + section + "&") : "") + +  "random=" + random(4949494); +  +  string url = +  Roxen.http_encode_invalids (nid->not_query + +  (nid->misc->path_info || "") + +  "?" + query + "#" + path()); +  +  nid->set_response_header ("Location", url);    if( nid->misc->defines )    nid->misc->defines[ " _error" ] = 302;    else if( id->misc->defines )    id->misc->defines[ " _error" ] = 302;    }       return ret;    }      
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1331:       string res = "<a name='"+path()+"'>\n</a><table>\n"    "<input type='hidden' name='"+prefix+"count' value='"+_current_count+"' />\n";       foreach( map(query(), transform_to_form), mixed val )    {    res += "<tr>\n<td><font size='-1'>"+ render_row(prefix+"set."+i, val, width)    + "</font></td>\n";   #define BUTTON(X,Y) ("<submit-gbutton2 name='"+X+"'>"+Y+"</submit-gbutton2>")   #define REORDER(X,Y) ("<submit-gbutton2 name='"+X+"' icon-src='"+Y+"'></submit-gbutton2>") + #define DIMBUTTON(X) ("<disabled-gbutton icon-src='"+X+"'></disabled-gbutton>")    if( i )    res += "\n<td>"+    REORDER(prefix+"up."+i, "/internal-roxen-up")+    "</td>";    else -  res += "\n<td></td>"; +  res += "\n<td>"+DIMBUTTON("/internal-roxen-up")+"</td>";    if( i != sizeof( query())- 1 )    res += "\n<td>"+    REORDER(prefix+"down."+i, "/internal-roxen-down")    +"</td>";    else -  res += "\n<td></td>"; +  res += "\n<td>"+DIMBUTTON("/internal-roxen-down")+"</td>";    res += "\n<td>"+    BUTTON(prefix+"delete."+i, LOCALE(227, "Delete") )    +"</td>";    "</tr>";    i++;    }    res +=    "\n<tr><td colspan='2'>"+    BUTTON(prefix+"new", LOCALE(297, "New row") )+    "</td></tr></table>\n\n";
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1412:    int width=20;       string transform_to_form(int what) { return (string)what; }    int transform_from_form(string what,mapping v) { return (int)what; }   }      class FloatList   //! A list of floating point numbers   {    inherit List; -  constant type="DirectoryList"; +  constant type="FloatList";    int width=20;    -  static int _prec = 3; +  protected int _prec = 3;       void set_precision( int prec )    //! Set the number of _decimals_ shown to the user.    //! If prec is 3, and the float is 1, 1.000 will be shown.    //! Default is 2.    {    _prec = prec;    }       string transform_to_form(int what)
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1469:    inherit List;    constant type="PortList";       string render_row( string prefix, mixed val, int width )    {    string res = "<input type=hidden name='"+prefix+"' value='"+prefix+"' />";       Standards.URI split = Standards.URI( val );       res += "<select name='"+prefix+"prot'>"; +  int default_port;    foreach( sort(indices( roxenp()->protocols )), string p )    { -  if( p == split->scheme ) +  if( p == split->scheme ) {    res += "<option selected='t'>"+p+"</option>"; -  +  default_port = roxenp()->protocols[p]->default_port; +  }    else    res += "<option>"+p+"</option>";    }    res += "</select>";    -  res += "://<input type=string name='"+prefix+"host' value='"+ +  res += "://<input type=text name='"+prefix+"host' value='"+    Roxen.html_encode_string(split->host)+"' />"; -  res += ":<input type=string size=5 name='"+prefix+"port' value='"+ -  split->port+"' />"; +  res += ":<input type=text size=5 name='"+prefix+"port' value='"+ +  (split->port == default_port ? "" : split->port) +"' />";    -  res += "/<input type=string name='"+prefix+"path' value='"+ -  Roxen.html_encode_string(split->path[1..])+"' />"; -  +  res += "/<input type=text name='"+prefix+"path' value='"+ +  Roxen.html_encode_string(split->path[1..])+"' /><br />"; +  mapping opts = ([]); +  string a,b; +  foreach( (split->fragment||"")/";", string x ) +  { +  sscanf( x, "%s=%s", a, b ); +  opts[a]=b; +  } +  res += "IP#: <input size=15 type=text name='"+prefix+"ip' value='"+ +  Roxen.html_encode_string(opts->ip||"")+"' /> "; +  res += LOCALE(510,"Bind this port: "); +  res += "<select name='"+prefix+"nobind'>"; +  if( (int)opts->nobind ) +  { +  res += +  ("<option value='0'>"+LOCALE("yes","Yes")+"</option>" +  "<option selected='t' value='1'>"+LOCALE("no","No")+"</option>"); +  } +  else +  { +  res += +  ("<option selected='t' value='0'>"+LOCALE("yes","Yes")+"</option>" +  "<option value='1'>"+LOCALE("no","No")+"</option>"); +  } +  res += "</select>";    return res;    }       string transform_from_form( string v, mapping va )    {    if( v == "" ) return "http://*/";    v = v[strlen(path())..]; -  return (string)Standards.URI(va[v+"prot"]+"://"+va[v+"host"]+":"+va[v+"port"]+"/"+va[v+"path"]); +  if( strlen( va[v+"path"] ) && va[v+"path"][-1] != '/' ) +  va[v+"path"]+="/"; +  +  // Handle IPv6 addresses +  string host = va[v + "host"]; +  if (has_value(host, ":") && !has_prefix(host, "[")) +  host = "[" + host + "]"; +  +  return (string)Standards.URI(va[v+"prot"]+"://"+ host + +  (va[v+"port"] && sizeof (va[v+"port"]) ? +  ":"+ va[v+"port"] : "") +"/"+va[v+"path"]+"#" +  // all options below this point +  "ip="+va[v+"ip"]+";" +  "nobind="+va[v+"nobind"]+";" +  );    }       array verify_set_from_form( array(string) new_value )    {    string warn = "";    array res = ({});    foreach( new_value, string vv )    {    string tmp1, tmp2;    [tmp1,tmp2] = verify_port( vv );
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1522:   }         class FileList   //! A list of filenames.   {    inherit List;    constant type="FileList";      #ifdef __NT__ -  array verify_set( array(string) value ) +  array(string|array(string)) verify_set(mixed value )    { -  +  // Backward compatibility junk... +  if (stringp(value)) +  return ::verify_set( replace(value, "\\", "/") ); +     return ::verify_set( map( value, replace, "\\", "/" ) );    }   #endif   }         // =====================================================================   // Flag   // =====================================================================   
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1565:    return res+"</select>";    }   }               // =================================================================   // Utility functions used in multiple variable classes above   // ================================================================= - static array(string) verify_port( string port ) + protected array(string) verify_port( string port )   {    if(!strlen(port))    return ({ 0, port });       string warning="";    if( (int)port )    {    warning += sprintf(LOCALE(333,"Assuming http://*:%[0]d/ for %[0]d")+"\n",    (int)port);    port = "http://*:"+port+"/";    }    string protocol, host, path;       if(!strlen( port ) )    return ({ LOCALE(334,"Empty URL field")+"\n", port });       if(sscanf( port, "%[^:]://%[^/]%s", protocol, host, path ) != 3)    return ({ sprintf(LOCALE(335,"%s does not conform to URL syntax")+"\n",port),    port });    -  if( path == "" || path[-1] != '/' ) -  { -  warning += sprintf(LOCALE(336,"Added / to the end of %s")+"\n",port); -  path += "/"; -  } + // if( path == "" || path[-1] != '/' ) + // { + // warning += sprintf(LOCALE(336,"Added / to the end of %s")+"\n",port); + // path += "/"; + // }    if( protocol != lower_case( protocol ) )    {    warning += sprintf(LOCALE(338,"Changed %s to %s"),    protocol, lower_case( protocol ))+"\n";    protocol = lower_case( protocol );    }   #if constant(SSL.sslfile)    // All is A-OK   #else    if( (protocol == "https" || protocol == "ftps") )    warning +=    LOCALE(339,"SSL support not available in this Pike version.")+"\n"+    sprintf(LOCALE(340,"Please use %s instead."),    protocol[..strlen(protocol)-2])+"\n";   #endif    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 += sprintf(LOCALE(341,"Removed the default port number " -  "(%d) from %s"),pno,port)+"\n"; -  else -  host = host+":"+pno; -  -  +  int default_pno = +  (roxenp()->protocols[lower_case(protocol)] || ([ ]) )->default_port; +  if (has_value(host, "[")) { +  // IPv6 address +  Standards.URI uri = Standards.URI(port); +  pno = uri->port; +  port = (string) uri; +  } else { +  if (sscanf(host, "%s:%d", host, pno) == 2) +  if (pno != default_pno) +  host = host + ":" + pno;    port = protocol+"://"+host+path; -  +  } +  if (default_pno && (pno == default_pno)) +  warning += sprintf(LOCALE(341, "Removed the default port number " +  "(%d) from %s"), pno, port) + "\n";       if( !roxenp()->protocols[ protocol ] )    warning += sprintf(LOCALE(342,"Warning: The protocol %s is not known "    "by roxen"),protocol)+"\n";    return ({ (strlen(warning)?warning:0), port });   }      string input(string name, string value, int size,    void|mapping(string:string) args, void|int noxml)   {
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1644:    args->value=value;    if(!args->size && size)    args->size=(string)size;       string render="<input";       foreach(indices(args), string attr) {    render+=" "+attr+"=";    if(!has_value(args[attr], "\"")) render+="\""+args[attr]+"\"";    else if(!has_value(args[attr], "'")) render+="'"+args[attr]+"'"; -  else render+="\""+replace(args[attr], "'", "&#39;")+"\""; +  else render+="'"+replace(args[attr], "'", "&#39;")+"'";    }       if(noxml) return render+">";    return render+" />";   }