Index: htmlparse.pike
===================================================================
RCS file: /cvs/roxen_src/server/modules/tags/htmlparse.pike,v
retrieving revision 1.105
retrieving revision 1.119
diff -C3 -r1.105 -r1.119
*** htmlparse.pike	1998/05/29 13:19:12	1.105
--- htmlparse.pike	1998/07/17 17:09:32	1.119
***************
*** 12,18 ****
  // the only thing that should be in this file is the main parser.  
  string date_doc=Stdio.read_bytes("modules/tags/doc/date_doc");
  
! constant cvs_version = "$Id: htmlparse.pike,v 1.105 1998/05/29 13:19:12 per Exp $";
  constant thread_safe=1;
  
  #include <config.h>
--- 12,18 ----
  // the only thing that should be in this file is the main parser.  
  string date_doc=Stdio.read_bytes("modules/tags/doc/date_doc");
  
! constant cvs_version = "$Id: htmlparse.pike,v 1.119 1998/07/17 17:09:32 noring Exp $";
  constant thread_safe=1;
  
  #include <config.h>
***************
*** 108,116 ****
    defvar("exec", 0, "SSI support: execute command", 
  	 TYPE_FLAG,
  	 "If set and if server side include support is enabled, Roxen "
! 	 "will accept NCSA / Apache &lt;!--#exec cmd=\"XXX\"--&gt;.",
  	 ssi_is_not_set);
  
    defvar("close_db", 1, "Close the database if it is not used",
  	 TYPE_FLAG|VAR_MORE,
  	 "If set, the accessed database will be closed if it is not used for "
--- 108,136 ----
    defvar("exec", 0, "SSI support: execute command", 
  	 TYPE_FLAG,
  	 "If set and if server side include support is enabled, Roxen "
! 	 "will accept NCSA / Apache &lt;!--#exec cmd=\"XXX\" --&gt;. "
! 	 "Note that this will allow your users to execute arbitrary "
! 	 "commands.",
  	 ssi_is_not_set);
  
+ #if constant(getpwnam)
+   array nobody = getpwnam("nobody") || ({ "nobody", "x", 65534, 65534 });
+ #else /* !constant(getpwnam) */
+   array nobody = ({ "nobody", "x", 65534, 65534 });
+ #endif /* constant(getpwnam) */
+ 
+   defvar("execuid", nobody[2] || 65534, "SSI support: execute command uid",
+ 	 TYPE_INT,
+ 	 "UID to run NCSA / Apache &lt;!--#exec cmd=\"XXX\" --&gt; "
+ 	 "commands with.",
+ 	 ssi_is_not_set);
+ 
+   defvar("execgid", nobody[3] || 65534, "SSI support: execute command gid",
+ 	 TYPE_INT,
+ 	 "GID to run NCSA / Apache &lt;!--#exec cmd=\"XXX\" --&gt; "
+ 	 "commands with.",
+ 	 ssi_is_not_set);
+ 
    defvar("close_db", 1, "Close the database if it is not used",
  	 TYPE_FLAG|VAR_MORE,
  	 "If set, the accessed database will be closed if it is not used for "
***************
*** 387,393 ****
    defines->line = (string)line;
    string|function rf = real_container_callers[tag][i];
    if(args->help && Stdio.file_size("modules/tags/doc/"+tag) > 0)
!     return handle_help("modules/tags/doc/"+tag, tag, args);
    if(stringp(rf)) return rf;
    TRACE_ENTER("container (&lt;"+tag+"&gt on line "+line+")", rf);
  #ifdef MODULE_LEVEL_SECURITY
--- 407,413 ----
    defines->line = (string)line;
    string|function rf = real_container_callers[tag][i];
    if(args->help && Stdio.file_size("modules/tags/doc/"+tag) > 0)
!     return handle_help("modules/tags/doc/"+tag, tag, args)+contents;
    if(stringp(rf)) return rf;
    TRACE_ENTER("container (&lt;"+tag+"&gt on line "+line+")", rf);
  #ifdef MODULE_LEVEL_SECURITY
***************
*** 424,429 ****
--- 444,450 ----
  string call_user_tag(string tag, mapping args, int line, mixed foo, object id)
  {
    id->misc->line = line;
+   args = id->misc->defaults[tag]|args;
    if(!id->misc->up_args) id->misc->up_args = ([]);
    array replace_from = ({"#args#"})+
      Array.map(indices(args)+indices(id->misc->up_args),
***************
*** 442,447 ****
--- 463,469 ----
  			 mixed foo, object id)
  {
    id->misc->line = line;
+   args = id->misc->defaults[tag]|args;
    if(!id->misc->up_args) id->misc->up_args = ([]);
    array replace_from = ({"#args#", "<contents>"})+
      Array.map(indices(args)+indices(id->misc->up_args),
***************
*** 767,775 ****
        // Unset variable.
        m_delete( id->variables, m->variable );
      return("");
!   }
!   else
      return("<!-- set (line "+id->misc->defines->line+"): variable not specified -->");
  }
  
  string tag_append( string tag, mapping m, object id )
--- 789,799 ----
        // Unset variable.
        m_delete( id->variables, m->variable );
      return("");
!   } else if (id->misc->defines) {
      return("<!-- set (line "+id->misc->defines->line+"): variable not specified -->");
+   } else {
+     return("<!-- set: variable not specified -->");
+   }
  }
  
  string tag_append( string tag, mapping m, object id )
***************
*** 831,859 ****
    nid->misc->defines = ([]);
    nid->misc->_tags = 0;
    nid->misc->_containers = 0;
  
- 
    if(m->packageinfo)
    {
      string res ="<dl>";
      foreach(get_dir("../rxml_packages"), string f)
!     {
!       string doc = "";
!       string data = Stdio.read_bytes("../rxml_packages/"+f);
!       sscanf(data, "%*sdoc=\"%s\"", doc);
!       parse_rxml(data, nid);
!       res += "<dt><b>"+f+"</b><dd>"+doc+"<br>";
!       array tags = indices(nid->misc->tags||({}));
!       array containers = indices(nid->misc->containers||({}));
!       if(sizeof(tags))
! 	res += "defines the following tag"+
! 	  (sizeof(tags)!=1?"s":"") +": "+
! 	  String.implode_nicely( sort(tags) )+"<br>";
!       if(sizeof(containers))
! 	res += "defines the following container"+
! 	  (sizeof(tags)!=1?"s":"") +": "+
! 	  String.implode_nicely( sort(containers) )+"<br>";
!     }
      return res+"</dl>";
    }
  
--- 855,884 ----
    nid->misc->defines = ([]);
    nid->misc->_tags = 0;
    nid->misc->_containers = 0;
+   nid->misc->defaults = ([]);
  
    if(m->packageinfo)
    {
      string res ="<dl>";
      foreach(get_dir("../rxml_packages"), string f)
!       catch 
!       {
! 	string doc = "";
! 	string data = Stdio.read_bytes("../rxml_packages/"+f);
! 	sscanf(data, "%*sdoc=\"%s\"", doc);
! 	parse_rxml(data, nid);
! 	res += "<dt><b>"+f+"</b><dd>"+doc+"<br>";
! 	array tags = indices(nid->misc->tags||({}));
! 	array containers = indices(nid->misc->containers||({}));
! 	if(sizeof(tags))
! 	  res += "defines the following tag"+
! 	    (sizeof(tags)!=1?"s":"") +": "+
! 	    String.implode_nicely( sort(tags) )+"<br>";
! 	if(sizeof(containers))
! 	  res += "defines the following container"+
! 	    (sizeof(tags)!=1?"s":"") +": "+
! 	    String.implode_nicely( sort(containers) )+"<br>";
!       };
      return res+"</dl>";
    }
  
***************
*** 862,872 ****
      return "<use help>";
    
    if(id->pragma["no-cache"] || 
!      !(res = cache_lookup("macrofiles", (m->file || m->package))))
    {
      string foo;
      if(m->file)
!       foo = nid->conf->try_get_file( m->file, nid );
      else 
        foo=Stdio.read_bytes("../rxml_packages/"+combine_path("/",m->package));
        
--- 887,899 ----
      return "<use help>";
    
    if(id->pragma["no-cache"] || 
!      !(res = cache_lookup("macrofiles:"+ id->conf->name ,
! 			  (m->file || m->package))))
    {
+     res = ([]);
      string foo;
      if(m->file)
!       foo = nid->conf->try_get_file( fix_relative(m->file,nid), nid );
      else 
        foo=Stdio.read_bytes("../rxml_packages/"+combine_path("/",m->package));
        
***************
*** 885,903 ****
      foreach(indices(res->_containers), string t)
        if(!res->containers[t]) m_delete(res->_containers, t);
      res->defines = nid->misc->defines||([]);
      m_delete(res->defines, "line");
!     cache_set("macrofiles", (m->file || m->package), res);
    }
  
    if(!id->misc->tags)
      id->misc->tags = res->tags;
    else
      id->misc->tags |= res->tags;
    if(!id->misc->containers)
      id->misc->containers = res->containers;
    else
      id->misc->containers |= res->containers;
  
    id->misc->defines |= res->defines;
  
    foreach(indices(res->_tags), string t)
--- 912,937 ----
      foreach(indices(res->_containers), string t)
        if(!res->containers[t]) m_delete(res->_containers, t);
      res->defines = nid->misc->defines||([]);
+     res->defaults = nid->misc->defaults||([]);
      m_delete(res->defines, "line");
!     cache_set("macrofiles:"+ id->conf->name, (m->file || m->package), res);
    }
  
    if(!id->misc->tags)
      id->misc->tags = res->tags;
    else
      id->misc->tags |= res->tags;
+ 
    if(!id->misc->containers)
      id->misc->containers = res->containers;
    else
      id->misc->containers |= res->containers;
  
+   if(!id->misc->defaults)
+     id->misc->defaults = res->defaults;
+   else
+     id->misc->defaults |= res->defaults;
+ 
    id->misc->defines |= res->defines;
  
    foreach(indices(res->_tags), string t)
***************
*** 912,943 ****
      return "";
  }
  
! string tag_define(string tag,mapping m, string str, object got,object file,
  		  mapping defines)
  { 
    if (m->name) 
      defines[m->name]=str;
    else if (m->tag) 
    {
!     if(!got->misc->tags)
!     {
!       got->misc->tags = ([]);
! //       got->misc->_tags = ([]);
!     }
!     got->misc->tags[m->tag] = str;
!     got->misc->_tags[m->tag] = call_user_tag;
    }
    else if (m->container) 
    {
!     if(!got->misc->containers)
!     {
!       got->misc->containers = ([]);
! //       got->misc->_containers = ([]);
!     }
!     got->misc->containers[m->container] = str;
!     got->misc->_containers[m->container] = call_user_container;
    }
!   else return "<!-- No name specified for the define! <define name=...> -->";
    return ""; 
  }
  
--- 946,991 ----
      return "";
  }
  
! string tag_define(string tag, mapping m, string str, object id, object file,
  		  mapping defines)
  { 
    if (m->name) 
      defines[m->name]=str;
    else if (m->tag) 
    {
!     if(!id->misc->tags)
!       id->misc->tags = ([]);
!     if(!id->misc->defaults)
!       id->misc->defaults = ([]);
!     if(!id->misc->defaults[m->tag])
!       id->misc->defaults[m->tag] = ([]);
! 
!     foreach( indices(m), string arg )
!       if( arg[0..7] == "default_" )
! 	id->misc->defaults[m->tag] += ([ arg[8..]:m[arg] ]);
!     
!     id->misc->tags[m->tag] = str;
!     id->misc->_tags[m->tag] = call_user_tag;
    }
    else if (m->container) 
    {
!     if(!id->misc->containers)
!       id->misc->containers = ([]);
! 
!     if(!id->misc->defaults)
!       id->misc->defaults = ([]);
!     if(!id->misc->defaults[m->container])
!       id->misc->defaults[m->container] = ([]);
! 
!     foreach( indices(m), string arg )
!       if( arg[0..7] == "default_" )
! 	id->misc->defaults[m->container] += ([ arg[8..]:m[arg] ]);
!     
!     id->misc->containers[m->container] = str;
!     id->misc->_containers[m->container] = call_user_container;
    }
!   else return "<!-- No name, tag or container specified for the define! "
! 	 "&lt;define help&gt; for instructions. -->";
    return ""; 
  }
  
***************
*** 1156,1165 ****
        return popen(m->cmd,
  		   getenv()
  		   | build_roxen_env_vars(got)
! 		   | build_env_vars(got->not_query, got, 0));
      }
-     else
-       return " <b>execute command support disabled</b> ";
    }
    return "<!-- exec what? -->";
  }
--- 1204,1215 ----
        return popen(m->cmd,
  		   getenv()
  		   | build_roxen_env_vars(got)
! 		   | build_env_vars(got->not_query, got, 0),
! 		   QUERY(execuid) || -2, QUERY(execgid) || -2);
!     } else {
!       return "<b>Execute command support disabled."
! 	"<!-- Check \"Main RXML Parser\"/\"SSI support\". --></b>";
      }
    }
    return "<!-- exec what? -->";
  }
***************
*** 1505,1520 ****
  
  string simple_parse_users_file(string file, string u)
  {
!  string line, user, pass;
!  foreach(file/"\n", line)
   {
     array(string) arr = line/":";
     if (arr[0] == u) {
       if (sizeof(arr) > 1) {
         return(arr[1]);
       }
-      // Malformed!
-      return 0;
     }
   }
   return 0;
--- 1555,1567 ----
  
  string simple_parse_users_file(string file, string u)
  {
!  foreach(file/"\n", string line)
   {
     array(string) arr = line/":";
     if (arr[0] == u) {
       if (sizeof(arr) > 1) {
         return(arr[1]);
       }
     }
   }
   return 0;
***************
*** 1539,1544 ****
--- 1586,1641 ----
    return match_passwd(u[2], pass);
  }
  
+ multiset simple_parse_group_file(string file, string g)
+ {
+  multiset res = (<>);
+ 
+  foreach(file/"\n", string line)
+  {
+    array(string) arr = line/":";
+    if (arr[0] == g) {
+      if (sizeof(arr) > 1) {
+        res += (< @arr[-1]/"," >);
+      }
+    }
+  }
+  // roxen_perror(sprintf("Parse group:%O => %O\n", g, res));
+ 
+  return res;
+ }
+ 
+ int group_member(array auth, string group, string groupfile, object id)
+ {
+   if(!auth)
+     return 0; // No auth sent
+ 
+   string s;
+   catch {
+     s = Stdio.read_bytes(groupfile);
+   };
+ 
+   if (!s) {
+     if (groupfile[0..0] != "/") {
+       if (id->not_query[-1] != '/')
+ 	groupfile = combine_path(id->not_query, "../"+groupfile);
+       else
+ 	groupfile = id->not_query + groupfile;
+     }
+     s = id->conf->try_get_file(groupfile, id);
+   }
+ 
+   if (!s) {
+     return 0;
+   }
+ 
+   s = replace(s, ({ " ", "\t", "\r" }), ({ "", "", "" }));
+ 
+   multiset(string) members = simple_parse_group_file(s, group);
+ 
+   return members && members[replace(auth[1],
+ 				    ({ " ", "\t", "\r" }), ({ "", "", "" }))];
+ }
+ 
  string tag_prestate(string tag, mapping m, string q, object got);
  string tag_client(string tag,mapping m, string s,object got,object file);
  string tag_deny(string a,  mapping b, string c, object d, object e, 
***************
*** 1599,1604 ****
--- 1696,1706 ----
    IS_TEST(cookie, got->cookies);
    IS_TEST(defined, defines);
  
+   if (m->match) {
+     string a, b;
+     if(sscanf(m->match, "%s is %s", a, b)==2)
+       TEST(_match(a, b/","));
+   }
  
    if(m->accept)
      if(!got->misc->accept)
***************
*** 1649,1655 ****
      
      b=(int)sprintf("%02d%02d%02d", c->year, c->mon + 1, c->mday);
      a=(int)m->date;
!     
      if(m->inclusive || !(m->before || m->after) && a==b)
        tok=1;
  
--- 1751,1757 ----
      
      b=(int)sprintf("%02d%02d%02d", c->year, c->mon + 1, c->mday);
      a=(int)m->date;
!     if(a > 999999) a -= 19000000;
      if(m->inclusive || !(m->before || m->after) && a==b)
        tok=1;
  
***************
*** 1738,1743 ****
--- 1840,1853 ----
  	TEST(got->auth && got->auth[0] && search(m->user/",", got->auth[1])
  	     != -1);
  
+   if (m->group) {
+     if (m->groupfile && sizeof(m->groupfile)) {
+       TEST(group_member(got->auth, m->group, m->groupfile, got));
+     } else {
+       return("<!-- groupfile not specified --><false>");
+     }
+   }
+ 
    return ok?(QUERY(compat_if)?"<true>"+s:s+"<true>"):"<false>";
  }
  
***************
*** 2055,2066 ****
    }
    
    if(!(m->value && m->name))
!     return "<!-- Header requires booth a name and a value. -->";
  
    add_header(_extra_heads, m->name, m->value);
    return "";
  }
  
  string tag_expire_time(string tag, mapping m, object got, object file,
  		       mapping defines)
  {
--- 2165,2195 ----
    }
    
    if(!(m->value && m->name))
!     return "<!-- Header requires both a name and a value. -->";
  
    add_header(_extra_heads, m->name, m->value);
    return "";
  }
  
+ string tag_redirect(string tag, mapping m, object id, object file,
+ 		    mapping defines)
+ {
+   if (!m->to) {
+     return("<!-- Redirect requires attribute \"to\". -->");
+   }
+   mapping r = http_redirect(m->to, id);
+   if (r->error) {
+     _error = r->error;
+   }
+   if (r->extra_heads) {
+     _extra_heads += r->extra_heads;
+   }
+   if (m->text) {
+     _rettext = m->text;
+   }
+   return("");
+ }
+ 
  string tag_expire_time(string tag, mapping m, object got, object file,
  		       mapping defines)
  {
***************
*** 2238,2244 ****
     return (["accessed":tag_accessed,
  	    "modified":tag_modified,
  	    "pr":tag_pr,
! 	   "use":tag_use,
  	    "list-tags":tag_list_tags,
  	    "number":tag_number,
  	    "imgs":tag_ximage,
--- 2367,2373 ----
     return (["accessed":tag_accessed,
  	    "modified":tag_modified,
  	    "pr":tag_pr,
! 	    "use":tag_use,
  	    "list-tags":tag_list_tags,
  	    "number":tag_number,
  	    "imgs":tag_ximage,
***************
*** 2264,2269 ****
--- 2393,2399 ----
  	    "realfile":tag_realfile,
  	    "vfs":tag_vfs,
  	    "header":tag_header,
+ 	    "redirect":tag_redirect,
  	    "expire_time":tag_expire_time,
  	    "signature":tag_signature,
  	    "user":tag_user,
***************
*** 2437,2459 ****
  }
  
  // Removes empty lines
! string tag_trimlines( string tag_name, mapping args, string contents,
  		      object id )
  {
!   contents = parse_rxml( contents, id );
!   contents = contents / "\r\n" * "\n";
!   contents = contents / "\r" * "\n";
!   contents = (contents / "\n" - ({ "" })) * "\n";
!   return contents;
  }
  
  // Internal method for the default tag
! private string tag_input( string tag_name, mapping args, string name,
  			  multiset (string) value )
  {
!   werror( sprintf( "%O %O %O\n", args, name, value ) );
!   if (name && args->name != name
!       || args->_parsed)
      return 0;
    if (args->type == "checkbox" || args->type == "radio")
      if (args->value)
--- 2567,2585 ----
  }
  
  // Removes empty lines
! mixed tag_trimlines( string tag_name, mapping args, string contents,
  		      object id )
  {
!   contents = replace(parse_rxml( contents, id ),
! 		     ({ "\r\n","\r" }), ({"\n", "\n"}));
!   return ({ (contents / "\n" - ({ "" })) * "\n" });
  }
  
  // Internal method for the default tag
! private mixed tag_input( string tag_name, mapping args, string name,
  			  multiset (string) value )
  {
!   if (name && args->name != name)
      return 0;
    if (args->type == "checkbox" || args->type == "radio")
      if (args->value)
***************
*** 2480,2487 ****
  	  return 0;
    else
      return 0;
!   args->_parsed = "_parsed";
!   return make_tag( tag_name, args );
  }
  
  private string remove_leading_trailing_ws( string str )
--- 2606,2612 ----
  	  return 0;
    else
      return 0;
!   return ({ make_tag( tag_name, args ) });
  }
  
  private string remove_leading_trailing_ws( string str )
***************
*** 2492,2499 ****
  }
  
  // Internal method for the default tag
! private string tag_option( string tag_name, mapping args, string contents,
! 			   multiset (string) value )
  {
    if (args->value)
      if (value[ args->value ])
--- 2617,2624 ----
  }
  
  // Internal method for the default tag
! private mixed tag_option( string tag_name, mapping args, string contents,
! 				  multiset (string) value )
  {
    if (args->value)
      if (value[ args->value ])
***************
*** 2511,2537 ****
  	args->selected = "selected";
      else
        return 0;
!   return make_container( tag_name, args, contents );
  }
  
  // Internal method for the default tag
! private string tag_select( string tag_name, mapping args, string contents,
  			   string name, multiset (string) value )
  {
    array (string) tmp;
    int c;
    
!   if (name && args->name != name
!       || args->_parsed)
      return 0;
    tmp = contents / "<option";
    for (c=1; c < sizeof( tmp ); c++)
      if (sizeof( tmp[c] / "</option>" ) == 1)
        tmp[c] += "</option>";
    contents = tmp * "<option";
!   contents = parse_html( contents, ([ ]), ([ "option" : tag_option ]), value );
!   args->_parsed = "_parsed";
!   return make_container( tag_name, args, contents );
  }
  
  // The default tag is used to give default values to forms elements,
--- 2636,2661 ----
  	args->selected = "selected";
      else
        return 0;
!   return ({make_container( tag_name, args, contents )});
  }
  
  // Internal method for the default tag
! private mixed tag_select( string tag_name, mapping args, string contents,
  			   string name, multiset (string) value )
  {
    array (string) tmp;
    int c;
    
!   if (name && args->name != name)
      return 0;
    tmp = contents / "<option";
    for (c=1; c < sizeof( tmp ); c++)
      if (sizeof( tmp[c] / "</option>" ) == 1)
        tmp[c] += "</option>";
    contents = tmp * "<option";
!   mapping m = ([ "option" : tag_option ]);
!   contents = parse_html( contents, ([ ]), m, value );
!   return ({ make_container( tag_name, args, contents ) });
  }
  
  // The default tag is used to give default values to forms elements,
***************
*** 2594,2599 ****
--- 2718,2726 ----
  mapping query_container_callers()
  {
    return (["comment":lambda(){ return ""; },
+ 	   "cset":lambda(string t, mapping m, string c, object id)
+ 		  { tag_set("set", m + ([ "value":html_decode_string(c) ]),
+ 			    id); },
  	   "source":tag_source,
  	   "noparse":tag_noparse,
  	   "nooutput":tag_nooutput,
