835c6c2001-06-17Martin Nilsson // This file is part of Roxen WebServer. // Copyright © 2001, Roxen IS.
a896932001-01-03Per Hedbor #include <stat.h> #include <config.h>
f7ea0c2002-02-06Martin Stjernholm #include <module.h>
3e3bab2001-01-19Per Hedbor #include <module_constants.h>
9689f12002-09-03Martin Stjernholm constant cvs_version="$Id: prototypes.pike,v 1.52 2002/09/03 15:51:24 mast Exp $";
a896932001-01-03Per Hedbor  class Variable { constant is_variable = 1; constant type = "Basic"; string get_warnings(); int get_flags(); void set_flags( int flags ); int check_visibility( RequestID id, int more_mode, int expert_mode, int devel_mode, int initial, int|void variable_in_cfif ); void set_invisibility_check_callback( function(RequestID,Variable:int) cb ); function(Variable:void) get_changed_callback( ); void set_changed_callback( function(Variable:void) cb ); void add_changed_callback( function(Variable:void) cb ); function(RequestID,Variable:int) get_invisibility_check_callback() ; string doc( ); string name( ); string type_hint( ); mixed default_value(); void set_warning( string to ); int set( mixed to ); int low_set( mixed to ); mixed query(); int is_defaulted(); array(string|mixed) verify_set( mixed new_value ); mapping(string:string) get_form_vars( RequestID id ); mixed transform_from_form( string what ); void set_from_form( RequestID id ); string path(); void set_path( string to ); string render_form( RequestID id, void|mapping additional_args ); string render_view( RequestID id ); } class BasicDefvar { mapping(string:Variable) variables=([]); Variable getvar( string name ); int deflocaledoc( string locale, string variable, string name, string doc, mapping|void translate ); void set(string var, mixed value); int killvar(string var); void setvars( mapping (string:mixed) vars ); Variable defvar(string var, mixed value, mapping|string|void|object name, int|void type, mapping|string|void|object doc_str, mixed|void misc, int|function|void not_in_config, mapping|void option_translations); mixed query(string|void var, int|void ok); void definvisvar(string name, mixed value, int type, array|void misc); } class StringFile( string data, mixed|void _st ) { int offset; string _sprintf() { return "StringFile("+strlen(data)+","+offset+")"; } string read(int nbytes) { if(!nbytes) { offset = strlen(data); return data; } string d = data[offset..offset+nbytes-1]; offset += strlen(d); return d; } array stat() { if( _st ) return (array)_st; return ({ 0, strlen(data), time(), time(), time(), 0, 0, 0 }); } void write(mixed ... args) { throw( ({ "File not open for write\n", backtrace() }) ); } void seek(int to) { offset = to; } } class ModuleInfo { string sname; string filename; int last_checked; int type, multiple_copies;
ea262c2002-04-17Marcus Wellhardh  int|string locked; mapping(Configuration:int) config_locked;
a896932001-01-03Per Hedbor  string get_name(); string get_description(); RoxenModule instance( object conf, void|int silent ); void save(); void update_with( RoxenModule mod, string what ); int init_module( string what ); int rec_find_module( string what, string dir ); int find_module( string sn ); int check (void|int force); } class ModuleCopies { mapping copies = ([]); mixed `[](mixed q ) { return copies[q]; } mixed `[]=(mixed q,mixed w ) { return copies[q]=w; } array _indices() { return indices(copies); } array _values() { return values(copies); }
4d7e512001-01-16Martin Nilsson  string _sprintf( ) { return "ModuleCopies("+sizeof(copies)+")"; }
a896932001-01-03Per Hedbor }
7f66d82001-08-24Martin Nilsson class Configuration
a896932001-01-03Per Hedbor { inherit BasicDefvar; constant is_configuration = 1; mapping enabled_modules = ([]); mapping(string:array(int)) error_log=([]); #ifdef PROFILE mapping profile_map = ([]); #endif class Priority { string _sprintf() { return "Priority()"; } array (RoxenModule) url_modules = ({ }); array (RoxenModule) logger_modules = ({ }); array (RoxenModule) location_modules = ({ }); array (RoxenModule) filter_modules = ({ }); array (RoxenModule) last_modules = ({ }); array (RoxenModule) first_modules = ({ }); mapping (string:array(RoxenModule)) file_extension_modules = ([ ]); mapping (RoxenModule:multiset(string)) provider_modules = ([ ]); } class DataCache { int current_size, max_size, max_file_size; int hits, misses; void flush(); void expire_entry( string url ); void set( string url, string data, mapping meta, int expire ); array(string|mapping(string:mixed)) get( string url ); void init_from_variables( ); }; array(Priority) allocate_pris(); object throttler; RoxenModule types_module; RoxenModule dir_module; function types_fun; string name; int inited; // Protocol specific statistics. int requests, sent, hsent, received; function(string:int) log_function; DataCache datacache; int get_config_id(); string get_doc_for( string region, string variable ); string query_internal_location(RoxenModule|void mod); string query_name(); string comment();
0e15572001-02-23Martin Stjernholm  void unregister_urls(); void stop(void|int asynch);
a896932001-01-03Per Hedbor  string type_from_filename( string file, int|void to, string|void myext );
c109fc2001-07-21Martin Stjernholm  string get_url();
a896932001-01-03Per Hedbor  array (RoxenModule) get_providers(string provides); RoxenModule get_provider(string provides); array(mixed) map_providers(string provides, string fun, mixed ... args); mixed call_provider(string provides, string fun, mixed ... args); array(function) file_extension_modules(string ext); array(function) url_modules(); mapping api_functions(void|RequestID id); array(function) logger_modules(); array(function) last_modules(); array(function) first_modules(); array location_modules(); array(function) filter_modules(); void init_log_file(); int|mapping check_security(function|object a, RequestID id, void|int slevel); void invalidate_cache(); void clear_memory_caches(); string examine_return_mapping(mapping m); mapping|int(-1..0) low_get_file(RequestID id, int|void no_magic); mapping get_file(RequestID id, int|void no_magic, int|void internal_get); array(string) find_dir(string file, RequestID id, void|int(0..1) verbose);
ce64272001-01-14Martin Nilsson  array(int)|object(Stdio.Stat) stat_file(string file, RequestID id);
a896932001-01-03Per Hedbor  array open_file(string fname, string mode, RequestID id, void|int ig); mapping(string:array(mixed)) find_dir_stat(string file, RequestID id); array access(string file, RequestID id); string real_file(string file, RequestID id); int|string try_get_file(string s, RequestID id, int|void status, int|void nocache,
6a613a2002-06-17Anders Johansson  int|void not_internal, mapping|void result_mapping);
2fbed12001-09-13Martin Nilsson  int(0..1) is_file(string virt_path, RequestID id, int(0..1)|void internal);
a896932001-01-03Per Hedbor  void start(int num); void save_me(); int save_one( RoxenModule o ); RoxenModule reload_module( string modname ); RoxenModule enable_module( string modname, RoxenModule|void me, ModuleInfo|void moduleinfo,
7902be2002-04-09Marcus Wellhardh  int|void nostart, int|void nosave );
a896932001-01-03Per Hedbor  void call_start_callbacks( RoxenModule me, ModuleInfo moduleinfo, ModuleCopies module ); void call_low_start_callbacks( RoxenModule me, ModuleInfo moduleinfo, ModuleCopies module ); int disable_module( string modname, int|void nodest ); int add_modules( array(string) mods, int|void now ); RoxenModule find_module(string name);
850c282001-01-10Per Hedbor #if ROXEN_COMPAT < 2.2 Sql.Sql sql_cache_get(string what); Sql.Sql sql_connect(string db); #endif
a896932001-01-03Per Hedbor  void enable_all_modules(); void low_init(void|int modules_already_enabled); string parse_rxml(string what, RequestID id, void|Stdio.File file, void|mapping defines ); void add_parse_module (RoxenModule mod); void remove_parse_module (RoxenModule mod); string real_file(string a, RequestID b);
6495292001-01-19Per Hedbor  mapping authenticate_throw( RequestID id, string realm, UserDB|void database, AuthModule|void method); User authenticate( RequestID id, UserDB|void database, AuthModule|void method ); array(AuthModule) auth_modules(); array(UserDB) user_databases();
e3f4662001-01-19Per Hedbor  AuthModule find_auth_module( string name ); UserDB find_user_database( string name );
a896932001-01-03Per Hedbor  static string _sprintf( ) { return "Configuration("+name+")"; } }
7f66d82001-08-24Martin Nilsson //! @appears Protocol
a896932001-01-03Per Hedbor class Protocol { inherit BasicDefvar;
a9fa0d2001-07-21Martin Stjernholm 
a896932001-01-03Per Hedbor  constant name = "unknown";
a9fa0d2001-07-21Martin Stjernholm  //! Name used for internal identification. constant prot_name = "unknown"; //! Name of the protocol as seen in the protocol part of a url.
a896932001-01-03Per Hedbor  constant supports_ipless = 0; constant requesthandlerfile = ""; constant default_port = 4711; int bound; int refs; program requesthandler; string path; int port; string ip; array(string) sorted_urls = ({}); mapping(string:mapping) urls = ([]);
ea65f72001-07-21Martin Stjernholm  mapping(Configuration:mapping) conf_data = ([]);
a896932001-01-03Per Hedbor  void ref(string url, mapping data); void unref(string url); Configuration find_configuration_for_url( string url, RequestID id, int|void no_default ); string get_key(); void save(); void restore(); };
e0ffe32001-02-05Per Hedbor class FakedVariables( mapping real_variables ) { static array _indices() { return indices( real_variables ); } static array _values() { return map( _indices(), `[] ); } static mixed fix_value( mixed what ) { if( !what ) return what; if( !arrayp(what) ) return what; // huh if( sizeof( what ) == 1 ) return what[0]; return what*"\0"; } static mixed `[]( string ind ) { return fix_value( real_variables[ ind ] ); } static mixed `->(string ind ) { return `[]( ind ); } static mixed `[]=( string ind, mixed what ) { real_variables[ ind ] = ({ what }); return what; } static mixed `->=(string ind, mixed what ) { return `[]=( ind,what ); } static mixed _m_delete( mixed what ) {
91d3c32001-03-12Martin Nilsson // report_debug(" _m_delete( %O )\n", what );
e0ffe32001-02-05Per Hedbor  return fix_value( m_delete( real_variables, what ) ); } static int _equal( mixed what ) { return `==(what); } static int `==( mixed what ) { if( mappingp( what ) && (real_variables == what) ) return 1; } static string _sprintf( int f ) { switch( f ) { case 'O': return sprintf( "FakedVariables(%O)", real_variables ); default: return sprintf( sprintf("%%%c", f ), real_variables ); } } static this_program `|( mapping what ) { foreach( indices(what), string q )`[]=( q,what[q] ); return this_object(); } static this_program `+=( mapping what ) { foreach( indices(what), string q )`[]=( q,what[q] ); return this_object(); } static this_program `+( mapping what ) { foreach( indices(what), string q )`[]=( q,what[q] ); return this_object(); }
e734d52001-02-18Mirar (Pontus Hagland)  static mapping cast(string to) { if (to[..6]=="mapping")
3ce5922001-02-18Mirar (Pontus Hagland)  { array v=indices(real_variables); return mkmapping(v,map(v,`[])); }
e734d52001-02-18Mirar (Pontus Hagland)  error("can't cast to %O\n",to); }
e0ffe32001-02-05Per Hedbor }
a896932001-01-03Per Hedbor class RequestID
7f66d82001-08-24Martin Nilsson //! @appears RequestID
a896932001-01-03Per Hedbor //! The request information object contains all request-local information and //! server as the vessel for most forms of intercommunication between modules, //! scripts, RXML and so on. It gets passed round to almost all API callbacks //! worth mentioning. A RequestID object is born when an incoming request is //! encountered, and its life expectancy is short, as it dies again when the //! request has passed through all levels of the <ref>module type calling //! sequence</ref>. { Configuration conf; Protocol port_obj; //! The port object this request came from. int time; //! Time of the request, standard unix time (seconds since the epoch; 1970). string raw_url; //! The nonparsed, nontouched, non-* URL requested by the client. //! Hence, this path is unlike <ref>not_query</ref> and //! <ref>virtfile</ref> not relative to the server URL and must be //! used in conjunction with the former to generate absolute paths //! within the server. Be aware that this string will contain any //! URL variables present in the request as well as the file path. int do_not_disconnect; //! Typically 0, meaning the channel to the client will be disconnected upon //! finishing the request and the RequestID object destroyed with it.
e0ffe32001-02-05Per Hedbor  mapping (string:array) real_variables;
a896932001-01-03Per Hedbor  //! Form variables submitted by the client browser, as found in the //! <tt>form</tt> scope in RXML. Both query (as found in the query part of //! the URL) and POST (submitted in the request body) variables share this //! scope, with query variables having priority over POST ones. In other //! words, the query part of the URL overrides whatever variables are sent //! in the request body. //! //! The indices and values of this mapping map to the names and values of //! the variable names. All data (names and values) are decoded from their //! possible transport encoding.
e0ffe32001-02-05Per Hedbor  //! //! The value is always an array
a896932001-01-03Per Hedbor 
5aca9b2001-09-28Martin Stjernholm  mapping(string:mixed)|FakedVariables variables;
e0ffe32001-02-05Per Hedbor  //! @decl mapping(string:mixed) variables; //! //! The variables mapping is more or less identical to the //! real_variables maping, but each variable can only have one //! value, if the form variable was sent multiple times from the //! client (this happens, as an example, if you have checkbox //! variables with the same name but different values), the values //! will be separated with \0 (the null character) in this mapping.
9644732001-11-27Martin Stjernholm  mapping (string:mixed) misc;
a896932001-01-03Per Hedbor  //! This mapping contains miscellaneous non-standardized information, and //! is the typical location to store away your own request-local data for //! passing between modules et cetera. Be sure to use a key unique to your //! own application. mapping (string:string) cookies; //! The indices and values map to the names and values of the cookies sent //! by the client for the requested page. All data (names and values) are //! decoded from their possible transport encoding.
5588692001-04-22Per Hedbor  mapping (string:array(string)|string) request_headers;
a896932001-01-03Per Hedbor  //! Indices and values map to the names and values of all HTTP headers sent //! with the request; all data has been transport decoded, and the header //! names are canonized (lowercased) on top of that. Here is where you look //! for the "user-agent" header, the "referer" [sic!] header and similar //! interesting data provided by the client. mapping (string:mixed) throttle; // ? mapping (string:mixed) client_var; //! The client scope; a mapping of various client-related variables, indices //! being the entity names and the values being their values respectively. multiset(string) prestate; //! A multiset of all prestates harvested from the URL. Prestates are boolean //! flags, who are introduced in an extra leading path segment of the URL //! path put within parentheses, as in <a //! href="http://docs.roxen.com/(tables)/">docs://www.roxen.com/(tables)/</a>, //! this rendering a prestate multiset <pi>(&lt; "tables" &gt;)</pi>. //! //! Prestates are mostly useful for debugging purposes, since prestates //! generally lead to multiple URLs for identical documents resulting in //! poor usage of browser/proxy caches and the like. See <ref>config</ref>. multiset(string) config; //! Much like prestates, the id->config multiset is typically used for //! boolean information of state supplied by the client. The config state, //! however, is hidden in a client-side cookie treated specially by roxen, //! namely the <tt>RoxenConfig</tt> cookie. multiset(string) supports; //! All flags set by the supports system. multiset(string) pragma; //! All pragmas (lower-cased for canonization) sent with the request. For //! real-world applications typically only <pi>pragma["no-cache"]</pi> is of //! any particular interest, this being sent when the user does a forced //! reload of the page. array(string) client; array(string) referer; Stdio.File my_fd; // Don't touch; use the returned file descriptor from connection() instead. string prot; //! The protocol used for the request, e g "FTP", "HTTP/1.0", "HTTP/1.1". //! (Se also <ref>clientprot</ref>.) string clientprot; //! The protocol the client wanted to use in the request. This may //! not be the same as <ref>prot</ref>, if the client wanted to talk //! a higher protocol version than the server supports to date. string method; //! The method used by the client in this request, e g "GET", "POST". string realfile; //! When the the requested resource is an actual file in the real //! filesystem, this is its path. string virtfile; //! The mountpoint of the location module that provided the requested file. //! Note that this is not accessable from location modules; you need to keep //! track of your mountpoint on your own using <ref>defvar()</ref> and //! <ref>query()</ref>. This mountpoint is relative to the server URL. string rest_query; //! The scraps and leftovers of the requested URL's query part after //! removing all variables (that is, all key=value pairs) from it. string raw; //! The raw, untouched request in its entirety. string query; //! The entire raw query part (all characters after the first question mark, //! '?') of the requested URL. string not_query; //! The part of the path segment of the requested URL that is below //! the virtual server's mountpoint. For a typical server //! registering a URL with no ending path component, not_query will //! contain all characters from the leading '/' to, but not //! including, the first question mark ('?') of the URL. string extra_extension; string data; //! The raw request body, containing non-decoded post variables et cetera. string leftovers;
9689f12002-09-03Martin Stjernholm  string rawauth, realauth; // Used by many modules, so let's keep this.
a896932001-01-03Per Hedbor  string since; string remoteaddr; //! The client's IP address. string host; //! The client's hostname, if resolved.
46d4cb2001-08-22Martin Stjernholm  multiset(string) cache_status = (<>); //! Contains the caches that was hit when the request was served. //! See the docstring for @tt{$cache-status@} in the @tt{LogFormat@} //! global variable for known values, but note that the multiset //! actually never contains the value "nocache"; it's only written //! when the multiset is empty.
7fafb82001-07-25Johan Sundström  object root_id; //! @decl RequestID root_id; //! The root id object directly associated with the request - remains //! the same for all id objects generated by <insert href> tags and //! similar conditions that invoke @[clone_me()].
a896932001-01-03Per Hedbor  static void create(Stdio.File fd, Protocol port, Configuration conf){} void send(string|object what, int|void len){}
5430602001-07-21Martin Stjernholm  static string cached_url_base; string url_base() //! Returns the base part of the URL, i.e. what should be added in //! front of a path in the virtual filesystem to get the absolute
3c49612001-07-21Martin Stjernholm  //! URL to the page. The returned string ends with a "/", or is "" //! if no server base could be found.
5430602001-07-21Martin Stjernholm  //! //! This function gets the correct host for protocols that handles //! IP-less hosts. { // Note: Code duplication in protocols/http.pike. if (!cached_url_base) { string tmp;
3c49612001-07-21Martin Stjernholm  // First consult the port object. if (port_obj) { string host = port_obj->conf_data[conf]->hostname; if (host == "*" && conf && sizeof (host = conf->get_url())) if (sscanf (host, "%*s://%[^:/]", host) < 2) host = port_obj->ip; cached_url_base = port_obj->prot_name + "://" + host;
5430602001-07-21Martin Stjernholm  if (port_obj->port != port_obj->default_port) cached_url_base += ":" + port_obj->port; }
3c49612001-07-21Martin Stjernholm  // Then try the configuration url. else if (conf && sizeof (tmp = conf->get_url())) cached_url_base = tmp[..sizeof (tmp) - 2]; // Remove trailing '/'.
5430602001-07-21Martin Stjernholm 
3c49612001-07-21Martin Stjernholm  // Lastly use a pathetic fallback. With this the produced urls // will still be relative, which has some chance of working. else return cached_url_base = "";
5430602001-07-21Martin Stjernholm  if (string p = misc->site_prefix_path) cached_url_base += p; cached_url_base += "/"; } return cached_url_base; }
f7ea0c2002-02-06Martin Stjernholm  void add_response_header (string name, string value)
b421932002-01-29Martin Stjernholm  //! Adds a header @[name] with the value @[value] to be sent in the //! http response. An existing header with the same name will not be //! overridden, instead another (duplicate) header line will be sent //! in the response. //! //! @note //! If used from within an RXML parse session, this function will //! ensure that the new header is registered properly in the RXML //! p-code cache. That's the primary reason to used it instead of //! adding the header directly to @tt{misc->moreheads@} or //! @tt{misc->defines[" _extra_heads"]@}.
f7ea0c2002-02-06Martin Stjernholm  { mapping hdrs = misc->defines && misc->defines[" _extra_heads"] || misc->moreheads; if (!hdrs) hdrs = misc->moreheads = ([]); // Essentially Roxen.add_http_header inlined. Can't refer to it // from here due to the recursive resolver problems in Pike. array|string cur_val = hdrs[name]; if(cur_val) { if(arrayp(cur_val)) { if (!has_value(cur_val, value)) cur_val += ({ value }); } else { if (cur_val != value) cur_val = ({ cur_val, value }); } } else cur_val = value; if (hdrs == misc->moreheads) hdrs[name] = cur_val; else if (object/*(RXML.Context)*/ ctx = RXML_CONTEXT) ctx->set_var (name, cur_val, "header"); else hdrs[name] = cur_val; }
b421932002-01-29Martin Stjernholm 
f7ea0c2002-02-06Martin Stjernholm  void set_response_header (string name, string value)
b421932002-01-29Martin Stjernholm  //! Sets the header @[name] to the value @[value] to be sent in the //! http response. If an existing header with the same name exists, //! its value(s) will be overridden. This is useful for headers like //! "Expire-Time", otherwise @[add_response_header] is typically a //! better choice. //! //! @note //! If used from within an RXML parse session, this function will //! ensure that the new header is registered properly in the RXML //! p-code cache. That's the primary reason to used it instead of //! adding the header directly to @tt{misc->moreheads@} or //! @tt{misc->defines[" _extra_heads"]@}.
f7ea0c2002-02-06Martin Stjernholm  { if (misc->defines && misc->defines[" _extra_heads"]) { misc->defines[" _extra_heads"][name] = value; if (object/*(RXML.Context)*/ ctx = RXML_CONTEXT) ctx->signal_var_change (name, "header"); } else { if (!misc->moreheads) misc->moreheads = ([]); misc->moreheads[name] = value; } }
b421932002-01-29Martin Stjernholm 
9689f12002-09-03Martin Stjernholm  array(string) output_charset = ({}); string input_charset; void set_output_charset( string|function to, int|void mode ) { if( search( output_charset, to ) != -1 ) // Already done. return; switch( mode ) { case 0: // Really set. output_charset = ({ to }); break; case 1: // Only set if not already set. if( !sizeof( output_charset ) ) output_charset = ({ to }); break; case 2: // Join. output_charset |= ({ to }); break; } }
a896932001-01-03Per Hedbor  string scan_for_query( string f ) { if(sscanf(f,"%s?%s", f, query) == 2) { string v, a, b; foreach(query / "&", v)
ccf8312001-08-15Per Hedbor  if(sscanf(v, "%s=%s", a, b) == 2) { a = _Roxen.http_decode_string(replace(a, "+", " ")); b = _Roxen.http_decode_string(replace(b, "+", " ")); real_variables[ a ] += ({ b }); } else if(strlen( rest_query )) rest_query += "&" + _Roxen.http_decode_string( v ); else rest_query = _Roxen.http_decode_string( v );
a896932001-01-03Per Hedbor  rest_query=replace(rest_query, "+", "\000"); } return f; }
9689f12002-09-03Martin Stjernholm  void adjust_for_config_path( string p ) { if( not_query ) not_query = not_query[ strlen(p).. ]; raw_url = raw_url[ strlen(p).. ]; misc->site_prefix_path = p; }
a896932001-01-03Per Hedbor  void end(string|void s, int|void keepit){} void ready_to_receive(){} void send_result(mapping|void result){} RequestID clone_me() { object c,t; c=object_program(t=this_object())(0, port_obj, conf); c->port_obj = port_obj; c->conf = conf;
7fafb82001-07-25Johan Sundström  c->root_id = root_id;
a896932001-01-03Per Hedbor  c->time = time; c->raw_url = raw_url;
ccf8312001-08-15Per Hedbor  c->real_variables = copy_value( real_variables ); c->variables = FakedVariables( c->real_variables );
a896932001-01-03Per Hedbor  c->misc = copy_value( misc ); c->misc->orig = t; c->prestate = prestate; c->supports = supports; c->config = config; c->client_var = client_var; c->remoteaddr = remoteaddr; c->host = host; c->client = client; c->referer = referer; c->pragma = pragma; c->cookies = cookies; c->my_fd = 0; c->prot = prot; c->clientprot = clientprot; c->method = method; c->rest_query = rest_query; c->raw = raw; c->query = query; c->not_query = not_query; c->data = data; c->extra_extension = extra_extension; c->realauth = realauth; c->rawauth = rawauth; c->since = since; return c; } Stdio.File connection( ) //! Returns the file descriptor used for the connection to the client. { return my_fd; } Configuration configuration() //! Returns the <ref>Configuration</ref> object of the virtual server that //! is handling the request. { return conf; } } class RoxenModule { inherit BasicDefvar; constant is_module = 1; constant module_type = 0; constant module_unique = 1;
7787ac2001-07-31Per Hedbor  LocaleString module_name; LocaleString module_doc;
a896932001-01-03Per Hedbor 
0aa37d2001-08-23Martin Stjernholm  string module_identifier(); string module_local_id();
a896932001-01-03Per Hedbor  array(int|string|mapping) register_module(); string file_name_and_stuff(); void start(void|int num, void|object conf); string query_internal_location(); string query_location(); string query_provides(); array query_seclevels();
ce64272001-01-14Martin Nilsson  array(int)|object(Stdio.Stat) stat_file(string f, RequestID id);
a896932001-01-03Per Hedbor  array(String) find_dir(string f, RequestID id); mapping(string:array(mixed)) find_dir_stat(string f, RequestID id); string real_file(string f, RequestID id); void save(); mapping api_functions(); mapping query_tag_callers(); mapping query_container_callers(); string info(object conf); string comment(); } class _roxen { mapping(string:object) variables; string real_version; object locale; int start_time; array(Configuration) configurations; mixed query(string a); void store(string a, mapping b, int c, object d); mapping(string:mixed) retrieve(string a, object b); void remove(string a, object b); string version(); void dump(string a); void nwrite(string a, int|void b, int|void c, void|mixed ... d); int main(int a, array(string) b); }
3e3bab2001-01-19Per Hedbor  class AuthModule
7f66d82001-08-24Martin Nilsson //! @appears AuthModule
3e3bab2001-01-19Per Hedbor //! The interface an authentication module must implement { inherit RoxenModule; constant module_type = MODULE_AUTH; constant thread_safe=1; constant name = "method name";
3342dd2001-01-19Per Hedbor  User authenticate( RequestID id, UserDB db );
3e3bab2001-01-19Per Hedbor  //! Try to authenticate the request with users from the specified user //! database. If no @[db] is specified, all datbases in the current //! configuration are searched in order, then the configuration user //! database.
3342dd2001-01-19Per Hedbor  mapping authenticate_throw( RequestID id, string realm, UserDB db );
3e3bab2001-01-19Per Hedbor  //! Returns a reply mapping, similar to @[Roxen.http_rxml_reply] with //! friends. If no @[db] is specified, all datbases in the current //! configuration are searched in order, then the configuration user //! database. }
e082212001-08-28Per Hedbor static mapping(string:function(void:void)) user_sql_inited = ([]);
a665382001-01-29Per Hedbor static Sql.Sql user_mysql;
69fa3e2001-01-30Per Hedbor static void init_user_sql(string table)
3342dd2001-01-19Per Hedbor {
e082212001-08-28Per Hedbor  string db = all_constants()->REPLICATE?"replicate":"local";
69fa3e2001-01-30Per Hedbor  if( !user_mysql )
e082212001-08-28Per Hedbor  user_mysql = master()->resolv("DBManager.get")( db );
c580392001-08-13Per Hedbor  if(catch(user_mysql->query( "SELECT module FROM "+ table+" WHERE module=''"))) {
69fa3e2001-01-30Per Hedbor  user_mysql->query( "CREATE TABLE "+table+" " " (module varchar(30) NOT NULL, "
3342dd2001-01-19Per Hedbor  " name varchar(30) NOT NULL, "
69fa3e2001-01-30Per Hedbor  " user varchar(30) NOT NULL, " " value blob, " " raw int not null, " " INDEX foo (module,name,user))" );
e082212001-08-28Per Hedbor  master()->resolv("DBManager.is_module_table")( 0, db, table, "Contains metadata about users. "
c580392001-08-13Per Hedbor  "Userdatabases can store information here " "at the request of other modules, or they " "can keep their own state in this table" ); }
e082212001-08-28Per Hedbor  user_sql_inited[ table ]= lambda(){user_mysql = master()->resolv("DBManager.get")( db );};
3342dd2001-01-19Per Hedbor }
7f66d82001-08-24Martin Nilsson //! @appears Group
3342dd2001-01-19Per Hedbor class Group( UserDB database )
3e3bab2001-01-19Per Hedbor { string name();
3342dd2001-01-19Per Hedbor  //! The group name
6533f22001-08-23Martin Nilsson 
9b94322001-01-29Per Hedbor  array(string) members()
3342dd2001-01-19Per Hedbor  //! All users that are members of this group. The default //! implementation loops over all users handled by the user database
3181852001-10-09Per Hedbor  //! and looks for users with the same gid as this group, or who is a //! member of it when the groups() method are called.
3342dd2001-01-19Per Hedbor  { array res = ({}); User uid; int id = gid(); foreach( database->list_users(), string u )
3181852001-10-09Per Hedbor  if( (uid = database->find_user( u )) && ((uid->gid() == id) || has_value(uid->groups(), name())))
9b94322001-01-29Per Hedbor  res += ({ u });
3342dd2001-01-19Per Hedbor  return res; } int gid(); //! A numerical GID, or -1 if not applicable
3181852001-10-09Per Hedbor  int set_name( string new_name ) { return 0; } int set_gid( int new_gid ) { return 0; } int set_members( array(string) members ) { return 0; } //! Returns 1 if it was possible to set the variable.
3342dd2001-01-19Per Hedbor }
e082212001-08-28Per Hedbor #ifdef THREADS
61e1cd2001-09-05Martin Nilsson static Thread.Mutex mutex = Thread.Mutex();
e082212001-08-28Per Hedbor #endif
7f66d82001-08-24Martin Nilsson //! @appears User
3342dd2001-01-19Per Hedbor class User( UserDB database ) {
69fa3e2001-01-30Per Hedbor  static string table;
3342dd2001-01-19Per Hedbor  string name(); //! The user (short) name
6533f22001-08-23Martin Nilsson 
3e3bab2001-01-19Per Hedbor  string real_name();
3342dd2001-01-19Per Hedbor  //! The real name of the user
0d1bcb2001-08-30Henrik Grubbström (Grubba)  int password_authenticate(string password)
3342dd2001-01-19Per Hedbor  //! Return 1 if the password is correct, 0 otherwise. The default //! implementation uses the crypted_password() method. {
0d1bcb2001-08-30Henrik Grubbström (Grubba)  string c = crypted_password(); return !sizeof(c) || crypt(password, c);
3342dd2001-01-19Per Hedbor  } int uid(); //! A numerical UID, or -1 if not applicable
6533f22001-08-23Martin Nilsson 
3342dd2001-01-19Per Hedbor  int gid(); //! A numerical GID, or -1 if not applicable
6533f22001-08-23Martin Nilsson 
3342dd2001-01-19Per Hedbor  string shell(); //! The shell, or 0 if not applicable string gecos() //! The gecos field, defaults to return the real name { return real_name(); } string homedir(); string crypted_password() { return "x"; } //! Used by compat_userinfo(). The default implementation returns "x"
9b94322001-01-29Per Hedbor  array(string) groups()
e3f4662001-01-19Per Hedbor  //! Return all groups this user is a member in. The default //! implementation returns ({}) { return ({}); }
3342dd2001-01-19Per Hedbor 
1d5c892001-01-19Per Hedbor  int set_name(string name) {} int set_real_name(string rname) {} int set_uid(int uid) {} int set_gid(int gid) {} int set_shell(string shell) {} int set_gecos(string gecos) {} int set_homedir(string hodir) {} int set_crypted_password(string passwd) {} int set_password(string passwd) {} //! Returns 1 if it was possible to set the variable.
3342dd2001-01-19Per Hedbor  array compat_userinfo( ) //! Return a unix passwd compatible array with user information. The //! defualt implementation uses the other methods to assemble this //! information. //! //! Basically: //! return ({ name(), crypted_password(), //! uid(), gid(), gecos(), homedir(), //! shell() }); { return ({name(),crypted_password(),uid(),gid(),gecos(),homedir(),shell()}); }
3e3bab2001-01-19Per Hedbor 
69fa3e2001-01-30Per Hedbor  #define INIT_SQL() do{ \ if(!table) table = replace(database->my_configuration()->name," ","_")+"_user_variables"; \
e082212001-08-28Per Hedbor  if(!user_sql_inited[ table ] )init_user_sql( table );else user_sql_inited[ table ](); \
69fa3e2001-01-30Per Hedbor  } while( 0 )
e082212001-08-28Per Hedbor #ifdef THREADS #define LOCK() mixed ___key = mutex->lock() #else #define LOCK() #endif
69fa3e2001-01-30Per Hedbor  static string module_name( RoxenModule module ) { if( !module ) // NULL does not work together with indexes, but this is // not a valid modulename, so it's not a problem. return "'0'"; else return replace("'"+user_mysql->quote(module->sname())+"'","%","%%"); }
3342dd2001-01-19Per Hedbor 
1d5c892001-01-19Per Hedbor  mixed set_var( RoxenModule module, string index, mixed value )
3342dd2001-01-19Per Hedbor  //! Set a specified variable in the user. If @[value] is a string, //! it's stored as is in the database, otherwise it's encoded using
e3f4662001-01-19Per Hedbor  //! encode_value before it's stored. Returns the value.
3342dd2001-01-19Per Hedbor  //! //! You can use 0 for the @[module] argument. //! //! The default implementation stores the value in a mysql table
69fa3e2001-01-30Per Hedbor  //! '*_user_data' in the 'shared' database.
3342dd2001-01-19Per Hedbor  //! //! Use @[get_var] to retrieve the value, and @[delete_var] to //! delete it. { delete_var( module, index );
69fa3e2001-01-30Per Hedbor  mixed oval = value;
e082212001-08-28Per Hedbor  LOCK();
69fa3e2001-01-30Per Hedbor  INIT_SQL();
3342dd2001-01-19Per Hedbor  int encoded;
69fa3e2001-01-30Per Hedbor 
3342dd2001-01-19Per Hedbor  if( stringp( value ) ) value = string_to_utf8( value ); else { value = encode_value( value ); encoded = 1; }
e082212001-08-28Per Hedbor 
3342dd2001-01-19Per Hedbor  user_mysql->query(
69fa3e2001-01-30Per Hedbor  "INSERT INTO "+table+" (module,name,user,value,raw) " "VALUES ("+module_name( module )+", %s, %s, %s, %d)", index, name(), value, encoded
3342dd2001-01-19Per Hedbor  );
69fa3e2001-01-30Per Hedbor  return oval;
3342dd2001-01-19Per Hedbor  } mixed get_var( RoxenModule module, string index ) //! Return the value of a variable previously set with @[set_var] { array rows;
e082212001-08-28Per Hedbor  LOCK();
69fa3e2001-01-30Per Hedbor  INIT_SQL(); rows = user_mysql->query( "SELECT * FROM "+table+
e082212001-08-28Per Hedbor  " WHERE module="+module_name( module ) +" AND name=%s AND user=%s",
3342dd2001-01-19Per Hedbor  index, name() ); if( !sizeof( rows ) ) return 0; mapping m = rows[0];
69fa3e2001-01-30Per Hedbor 
3342dd2001-01-19Per Hedbor  if( (int)m->raw ) return decode_value( m->value ); return utf8_to_string( m->value ); } void delete_var( RoxenModule module, string index ) //! Delete a variable previously created with @[set_var] {
e082212001-08-28Per Hedbor  LOCK();
69fa3e2001-01-30Per Hedbor  INIT_SQL(); user_mysql->query( "DELETE FROM "+table+" WHERE (module="+ module_name( module )+ " AND name=%s AND user=%s)", index, name() );
3342dd2001-01-19Per Hedbor  }
69fa3e2001-01-30Per Hedbor #undef INIT_SQL
e082212001-08-28Per Hedbor #undef LOCK
3e3bab2001-01-19Per Hedbor } class UserDB
7f66d82001-08-24Martin Nilsson //! @appears UserDB
3e3bab2001-01-19Per Hedbor //! The interface a UserDB module must implement. { inherit RoxenModule; constant module_type = MODULE_USERDB;
8ea2012001-01-29Per Hedbor  constant thread_safe=1;
3e3bab2001-01-19Per Hedbor 
e3f4662001-01-19Per Hedbor  constant name = "db name";
99a70c2001-08-30Henrik Grubbström (Grubba)  User find_user( string s, RequestID|void id );
3e3bab2001-01-19Per Hedbor  //! Find a user
3342dd2001-01-19Per Hedbor  User find_user_from_uid( int id ) //! Find a user given a UID. The default implementation loops over //! list_users() and checks the uid() of each one. { User uid; foreach( list_users(), string u ) if( (uid = find_user( u )) && (uid->uid() == id) ) return uid; } Group find_group( string group ) //! Find a group object given a group name. //! The default implementation returns 0. { }
3181852001-10-09Per Hedbor  Group find_group_from_gid( int id )
3342dd2001-01-19Per Hedbor  //! Find a group given a GID. The default implementation loops over //! list_groups() and checks the gid() of each one. { Group uid; foreach( list_groups(), string u ) if( (uid = find_group( u )) && (uid->gid() == id) ) return uid; } array(string) list_groups( ) //! Return a list of all groups handled by this database module. //! The default implementation returns the empty array. { return ({}); }
3e3bab2001-01-19Per Hedbor  array(string) list_users( ); //! Return a list of all users handled by this database module.
3342dd2001-01-19Per Hedbor  User create_user( string s )
788f082001-10-09Henrik Grubbström (Grubba)  //! Not necessarily implemented, as an example, it's not possible to
3e3bab2001-01-19Per Hedbor  //! create users in the system user database from Roxen WebServer.
3342dd2001-01-19Per Hedbor  //! The default implementation returns 0.
69fa3e2001-01-30Per Hedbor  { return 0; }
3181852001-10-09Per Hedbor  Group create_group( string s )
788f082001-10-09Henrik Grubbström (Grubba)  //! Not necessarily implemented, as an example, it's not possible to
3181852001-10-09Per Hedbor  //! create groups in the system user database from Roxen WebServer. //! The default implementation returns 0. { return 0; }
3e3bab2001-01-19Per Hedbor }