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.120 2011/12/06 10:51:46 grubba 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))   
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:124:    diff = diff[..sizeof(diff)-2];    foreach(diff, string row)    {    row = Roxen.html_encode_string(row);    row = replace(row, "\t", " ");    row = replace(row, " ", "&nbsp;");    switch(row[0])    {    case '&': r += "<tt>"+row+"</tt><br>\n";    break; -  case '+': r += "<tt><font color='darkgreen'>"+row+"</font></tt><br>\n"; +  case '+': r += "<font color='darkgreen'><tt>"+row+"</tt></font><br>\n";    added++;    break; -  case '-': r += "<tt><font color='darkred'>"+row+"</font></tt><br>\n"; +  case '-': r += "<font color='darkred'><tt>"+row+"</tt></font><br>\n";    deleted++;    break;    case 'L': r += "<i>"+row+"</i><br>\n";    break;    }    }    if (!hide_header)    r =    "<b>" + LOCALE(476, "Change in content") + "</b><br />\n"+    "<i>"+(added==1? LOCALE(477, "1 line added."):
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:316:    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() ) &&    cb( id, this_object() ) )    return 0;    return 1;    }    -  void set_invisibility_check_callback( function(RequestID,Variable:int) cb ) +  this_program set_invisibility_check_callback( function(RequestID,Variable:int) cb )    //! If the function passed as argument returns 1, the variable    //! will not be visible in the configuration interface.    //!    //! Pass 0 to remove the invisibility callback.    {    if( functionp( cb ) )    invisibility_callbacks[ _id ] = cb;    else    m_delete( invisibility_callbacks, _id ); -  +  return this;    }       function(Variable:void) get_changed_callback( )    //! Return the callback set with set_changed_callback    {    return changed_callbacks[ _id ];    }    -  void set_changed_callback( function(Variable:void) cb ) +  this_program set_changed_callback( function(Variable:void) cb )    //! The function passed as an argument will be called    //! when the variable value is changed.    //!    //! Pass 0 to remove the callback.    {    if( functionp( cb ) )    changed_callbacks[ _id ] = cb;    else    m_delete( changed_callbacks, _id ); -  +  return this;    }    -  void add_changed_callback( function(Variable:void) cb ) +  this_program add_changed_callback( function(Variable:void) cb )    //! Add a new callback to be called when the variable is changed.    //! If set_changed_callback is called, callbacks added with this function    //! are overridden.    {    mixed oc = get_changed_callback( );    if( arrayp( oc ) )    oc += ({ cb });    else    oc = ({ oc, cb }) - ({ 0 });    changed_callbacks[ _id ] = oc; -  +  return this;    }       function(RequestID,Variable:int) get_invisibility_check_callback()    //! Return the current invisibility check callback    {    return invisibility_callbacks[_id];    }       LocaleString doc( )    //! Return the documentation for this variable (locale dependant).
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:492:       mixed query()    //! Returns the current value for this variable.    {    mixed v;    if( !zero_type( v = changed_values[ _id ] ) )    return v;    return default_value();    }    +  mixed encode() +  //! Returns the current value for this variable encoded for storage. +  //! +  //! The default implementation just returns the value from @[query()]. +  //! +  //! @seealso +  //! @[query()], @[decode()] +  { +  return query(); +  } +  +  int decode(mixed encoded) +  //! Set the variable from the encoded representation +  //! returned by @[encode()]. +  //! +  //! The default implementation just calls @[set()] with the argument. +  //! +  //! @seealso +  //! @[set()], @[decode()] +  { +  return set(encoded); +  } +     int is_defaulted()    //! Return true if this variable is set to it's default value.    {    return zero_type( changed_values[ _id ] ) ||    equal(changed_values[ _id ], default_value());    }       array(string|mixed) verify_set_from_form( mixed new_value )    //! Like verify_set, but only called when the variables are set    //! from a form.
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:769:    {    return Roxen.html_encode_string( _format(query()) );    }       string render_form( RequestID id, void|mapping additional_args )    {    int size = 15;    if( _max != no_limit && _min != no_limit )    size = max( strlen(_format(_max)), strlen(_format(_min)) )+2;    string value; +  catch {    if (_may_be_empty && (float)query() == (float)0)    value = "";    else    value = query()==""? "" : _format( (float)query() ); -  +  };       additional_args = additional_args || ([]); -  +  if (!additional_args->type)    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;    }
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:876:    }       string render_form( RequestID id, void|mapping additional_args )    {    int size = 10;    if( _min != no_limit && _max != no_limit )    size = max( strlen((string)_max), strlen((string)_min) )+2;    string value = (query() == 0 && _is_empty)? "" : (string)query();       additional_args = additional_args || ([]); +  if (!additional_args->type)    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() {}   }    -  + class Priority + //! @[Int] that gets adjusted to the configured range. + { +  inherit Int; +  constant type = "Priority"; +  protected int|NoLimit _max = 9, _min = 0;    -  +  void set_range(int|NoLimit minimum, int|NoLimit maximum ) +  //! Set the range of the variable. +  //! +  //! @note +  //! Also scales the value of the variable accordingly. +  { +  if (_max != maximum) { +  if (!maximum || !_max) { +  set_default_value(0); +  low_set(0); +  } else { +  // Scale the old value. +  int new_val = (query() * maximum)/_max; +  if (new_val < minimum) new_val = minimum; +  int new_default = (default_value() * maximum)/_max; +  set_default_value(new_default); +  low_set(new_val); +  } +  } +  _max = maximum; +  _min = minimum; +  } +  +  string render_form( RequestID id, void|mapping additional_args ) +  { +  if ((_max != 9) || _min) return ::render_form(id, additional_args); +  +  // Display the traditional 0-9 selector by default. +  string res = "<select name='"+path()+"'>\n"; +  string current = (string)query(); +  int selected = 0; +  foreach( ({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }), int elem ) +  { +  mapping m = ([]); +  m->value = (string)elem; +  if( equal( m->value, current ) ) { +  m->selected="selected"; +  selected = 1; +  } +  res += " "+Roxen.make_container( "option", m, (string)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":current, "selected": "selected"]), +  sprintf(LOCALE(332,"(keep stale value %s)"),current)); +  return res + "</select>"; +  } +  +  string|int encode() +  { +  if (!_max) return 0; +  int ones = _max/9; +  int val = query(); +  if (val % ones) { +  // New-style. +  int digits = sizeof(sprintf("%d", ones)); +  // NB: We pad with zeroes to the field size to encode the +  // field size that was used at encode time. +  return sprintf("%*0d", digits, val); +  } +  // Compat. +  return val / ones; +  } +  +  int decode(string|int encoded) +  { +  if (!_max) { +  return set(0); +  } +  int ones = _max/9; +  if (intp(encoded)) { +  return set(encoded * ones); +  } +  if (encoded == "") { +  // Paranoia check in case someone has modified the config file. +  return set(5 * ones); // Default value. +  } +  // Expand the encoded value to the current field size. +  int digits = sizeof(sprintf("%d", ones)); +  while (sizeof(encoded) < digits) { +  encoded += encoded; +  } +  if (sizeof(encoded) > digits) { +  encoded = encoded[..digits-1]; +  } +  return set(array_sscanf(encoded, "%d")[0]); +  } +  +  LocaleString|string doc() +  { +  return ::doc() + +  sprintf((string)LOCALE(1120, "<p>%d is the highest priority and " +  "0 the lowest.</p>"), +  _max); +  } + } +    // =====================================================================   // String   // =====================================================================   class String   //! String variable   {    inherit Variable;    constant type = "String"; -  int width = 40; +  int width = 60;    //! The width of the input field. Used by overriding classes.       string diff( int render )    {    if(!render)    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 || ([]); -  +  if (!additional_args->type)    additional_args->type="text";    return input(path(), (string)query(), width, additional_args);    }   }      // =====================================================================   // Text   // =====================================================================   class Text   //! Text (multi-line string) variable
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:999:    }      }            // =====================================================================   // Password   // =====================================================================   class Password - //! Password variable (uses crypt) + //! Password variable (uses crypt_password)   {    inherit String; -  int width = 20; +  int width = 40;    constant type = "Password";       int(0..1) set_from_form( RequestID id )    {    mapping val;    if( sizeof( val = get_form_vars(id)) &&    val[""] && strlen(val[""]) ) { -  set( crypt( val[""] ) ); +  set( crypt_password( val[""] ) );    return 1;    }    return 0;    }       string render_view( RequestID id )    {    return "******";    }   
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1034:    additional_args->type="password";    return input(path(), "", 30, additional_args);    }   }      class File   //! A filename   {    inherit String;    constant type = "File"; -  int width = 50; +  int width = 60;       string read( )    //! Read the file as a string.    {    return Stdio.read_bytes( query() );    }       Stat stat()    //! Stat the file    {
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1062:    }   #endif      }      class Location   //! A location in the virtual filesystem   {    inherit String;    constant type = "Location"; -  int width = 50; +  int width = 60;       array verify_set( string value )    {    if( !strlen( value ) || !((<'~','/'>)[value[-1]]) )    return ({    LOCALE(330,"You most likely want an ending '/' on this variable"),    value    });    return ::verify_set( value );    }   }      class URL   //! A URL.   {    inherit String;    constant type = "URL"; -  int width = 50; +  int width = 60;       array verify_set_from_form( string new_value )    {    return verify_port( new_value );    }   }      class Directory   //! A Directory.   {    inherit String;    constant type = "Directory"; -  int width = 50; +  int width = 60;       array verify_set( string value )    {   #ifdef __NT__    value = replace( value, "\\", "/" );   #endif    if( strlen(value) && value[-1] != '/' )    value += "/";    if( !strlen( value ) )    return ::verify_set( value );
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1129:    }   }            // =====================================================================   // MultipleChoice (one of many) baseclass   // =====================================================================      class MultipleChoice - //! Base class for multiple-choice (one of many) variables. + //! Base class for multiple-choice (one or many of many) variables.   {    inherit Variable;    protected array _list = ({});    protected mapping _table = ([]);    -  +  protected int(0..1) multiselect; +  +  //! Identifier to use to detect presence of +  //! support for multiselect mode. +  constant multiselect_supported = 1; +  +  array(string|array(string)) verify_set(mixed to) +  { +  if (multiselect && stringp(to)) { +  return ({ "Compatibility: " +  "Converted to multi-select.\n", +  ({ to }), +  }); +  } else if (!multiselect && arrayp(to)) { +  return ({ "Compatibility: " +  "Converted to single-select.\n", +  sizeof (to) ? to[0] : default_value(), +  }); +  } +  +  +  return ::verify_set(to); +  } +     string diff( int render )    { -  if(!render) +  if(!render) { +  if (multiselect) +  return "(" + map(default_value(), _title) * ", " + ")";    return "("+_title( default_value() )+")";    } -  +  }       void set_choice_list( array to )    //! Set the list of choices.    {    _list = to;    }       array get_choice_list( )    //! Get the list of choices. Used by this class as well.    //! You can overload this function if you want a dynamic list.
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1167:    _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;    }    +  int(0..1) set_from_form(RequestID id, void|int(0..1) force) +  { +  if (!multiselect) return ::set_from_form(id); +  if (!id->real_variables[path()]) return 0; +  set_warning(0); +  mapping(string:string) m = get_form_vars(id); +  array(mixed) values = ({}); +  foreach(id->real_variables[path()] || ({}), string form_val) { +  mixed val = transform_from_form(form_val, m); +  array b = ({ 0, val }); +  mixed err = catch { b = verify_set_from_form(val); }; +  if (err) { +  add_warning(err); +  return 0; +  } else if (sizeof(b) != 2) { +  add_warning("Internal error: Illegal sized array " +  "from verify_set_from_form\n"); +  return 0; +  } +  if (b[0]) { +  add_warning(b[0]); +  } +  values += ({ b[1] }); +  } +  set(values); +  return 1; +  } +     protected string _name( mixed what )    //! Get the name used as value for an element gotten from the    //! get_choice_list() function.    {    return (string)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;    }    -  +  protected string render_element(mixed elem) +  //! Render the title used as description (shown to the user) for an +  //! element gotten from the get_choice_list() function. +  //! +  //! The default implementation just calls @[_title()], +  //! and quotes the result. +  //! +  //! Overload this for more advanced rendering. +  { +  return Roxen.html_encode_string(_title(elem)); +  } +     string render_form( RequestID id, void|mapping additional_args )    {    string autosubmit = "";    if(additional_args && additional_args->autosubmit)    autosubmit = " autosubmit='autosubmit' onChange='javascript:submit();'"; -  string res = "<select name='"+path()+"'"+autosubmit+">\n"; +  if (multiselect) { +  array(string) current = map(query(), _name); +  string res = "<table>\n"; +  foreach( get_choice_list(), mixed elem ) +  { +  mapping m = ([ +  "type": "checkbox", +  "name": path(), +  "value": _name(elem), +  ]); +  if(has_value(current, m->value)) { +  m->checked="checked"; +  current -= ({ m->value }); +  } +  res += sprintf("<tr><td>%s</td><td>%s</td></tr>\n", +  Roxen.make_tag( "input", m), +  render_element(elem)); +  } +  // Make an entry for the current values if they're not in the list, +  // to ensure that the value doesn't change as a side-effect by +  // another change. +  foreach(current, string value) +  { +  mapping m = ([ +  "type": "checkbox", +  "name": path(), +  "value": value, +  "checked": "checked", +  ]); +  string title = sprintf(LOCALE(1121,"(stale value %s)"), value); +  res += sprintf("<tr><td>%s</td><td>%s</td></tr>\n", +  Roxen.make_tag( "input", m), +  Roxen.html_encode_string(title)); +  } +  return res + "</table>"; +  } else {    string current = _name (query());    int selected = 0; -  +  string res = "<select name='"+path()+"'"+autosubmit+">\n";    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":current, "selected": "selected"]),    sprintf(LOCALE(332,"(keep stale value %s)"),current));    return res + "</select>";    } -  +  }       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 ); -  +  multiselect = arrayp(default_value);    if( mappingp( choices ) ) {    set_translation_table( choices );    set_choice_list( sort(indices(choices)) );    } else    set_choice_list( choices );    }   }         // =====================================================================
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1430:    ::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 string|array(string) module_id; +  protected string|array(string) default_id;    protected int automatic_dependency;    -  int low_set(RoxenModule to) +  int low_set(array(RoxenModule)|RoxenModule to)    { -  RoxenModule old = changed_values[_id]; +  array(RoxenModule)|RoxenModule old = changed_values[_id];    if (!old) {    if (module_id) { -  +  if (multiselect) { +  old = map(module_id, transform_from_form); +  } else {    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; +  if (equal (to, old)) return 0;    changed_values[_id] = to; -  +  if (multiselect) { +  array(string) names = map (to, _name); +  if (equal (module_id, names)) return 0; // Reloaded module or similar. +  module_id = names; +  } else {    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) +  int set(string|array(string)|RoxenModule|array(RoxenModule) to)    { -  if (stringp(to)) { +  if (multiselect && arrayp(to) && sizeof(to) && stringp(to[0])) {    module_id = to; -  +  array(RoxenModule) mods = map(to, transform_from_form); +  if (automatic_dependency) { +  foreach(mods; int i; RoxenModule mod) { +  if (!mod && conf->enabled_modules[to[i]]) { +  conf->add_modules(({to[i]}), 1); +  mod = transform_from_form(to[i]); +  } +  if (!mod && conf->enabled_modules[to[i]]) +  // The module exists but isn't started yet. Don't call set() +  // in this case since that will cause a bogus warning. +  return 0; +  mods[i] = mod; +  } +  } +  // FIXME: Modules that have disappeared from the configuration +  // will be silently removed here. To fix that, "to" must be able +  // to hold a mix of RoxenModule and string, and low_set must be +  // updated accordingly. Also, see query(). +  to = mods - ({ 0 }); +  } else 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|array(RoxenModule) query()    { -  RoxenModule res = changed_values[_id]; -  if (!res) { +  array(RoxenModule)|RoxenModule res = changed_values[_id]; +  if (!res || (multiselect && has_value(res, 0))) {    if (module_id) {    // The module might have been reloaded.    // Try locating it again. -  +  if (multiselect) { +  res = map(module_id, transform_from_form) - ({ 0 }); +  } else {    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()
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1523:    return res;    }       protected string _name(RoxenModule val)    {    return val?val->module_local_id():"";    }       protected string _title(RoxenModule val)    { -  return val?val->module_name:""; +  return val?Roxen.get_modfullname(val):"";    }       RoxenModule transform_from_form(string module_id, mapping|void v)    {    return conf->find_module(module_id);    }    -  RoxenModule default_value() +  RoxenModule|array(RoxenModule) default_value()    {    if (default_id) { -  +  if (multiselect) return map(default_id, transform_from_form);    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 )
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1560:       //! @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, +  protected void create(string|array(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); -  +  multiselect = arrayp(default_id);    }   }      //! Select a module that provides the specified interface.   class ProviderChoice   {    inherit ModuleChoice;    constant type = "ProviderChoice";    protected string provides;   
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1607:   }      // =====================================================================   // List baseclass   // =====================================================================   class List   //! Many of one type types   {    inherit Variable;    constant type="List"; -  int width = 40; +  int width = 60;       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-" ")/"," }); +  map(to/",", global.String.trim_all_whites), +  });    }    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;    }
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:1727:    query = "";    else    query += "&";       // 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); +  query += "&_roxen_wizard_id=" + Roxen.get_wizard_id_cookie(id);       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 )
Roxen.git/server/etc/modules/Variable.pmod/module.pmod:2074:   // {   // 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) + #if constant(SSL.File)    // 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;    int default_pno =