835c6c2001-06-17Martin Nilsson // This file is part of Roxen WebServer.
f41b982009-05-07Martin Stjernholm // Copyright © 1999 - 2009, Roxen IS.
835c6c2001-06-17Martin Nilsson //
c2d3012000-01-20Martin Nilsson // Handles supports
0917d32013-03-04Anders Johansson // $Id$
c2d3012000-01-20Martin Nilsson 
044ba92000-02-16Per Hedbor #include <module_constants.h>
2d81ff1999-09-02Per Hedbor #include <module.h> inherit "socket"; // The db for the nice '<if supports=..>' tag.
c2d3012000-01-20Martin Nilsson private mapping (string:array (array (object|multiset))) supports;
aa5a892000-03-07Martin Nilsson private multiset(string) default_supports; private mapping (string:string) default_client_var;
1679422000-03-11Martin Nilsson private array(string) supports_ind;
2d81ff1999-09-02Per Hedbor 
c2d3012000-01-20Martin Nilsson //------------------ Code to decode the supports file ----------------------
aa5a892000-03-07Martin Nilsson private array(multiset(string)|mapping(string:string)) split_supports(array(string) from) { mapping(string:string) m=([]); multiset(string) pos=(<>),neg=(<>);
c2d3012000-01-20Martin Nilsson  string i,v; foreach(from, string s) { if(s[0]=='*') { if(sscanf(s,"*%s=%s", i, v)==2) m[i]=v; else report_debug("Error in supports database (%s)\n", s); }
2d81ff1999-09-02Per Hedbor  else
c2d3012000-01-20Martin Nilsson  if(s[0]=='-')
a0673a2000-03-14Marcus Wellhardh  neg[s[1..]]=1;
c2d3012000-01-20Martin Nilsson  else pos[s]=1; } return ({pos, neg, m});
2d81ff1999-09-02Per Hedbor }
aa5a892000-03-07Martin Nilsson private void parse_supports_string(string what, string current_section, mapping(string:array(string)) defines)
2d81ff1999-09-02Per Hedbor {
6fdbbd2000-05-08Martin Nilsson  what-="\r";
c2d3012000-01-20Martin Nilsson  foreach(replace(what, "\\\n", " ")/"\n"-({""}), string line)
2d81ff1999-09-02Per Hedbor  {
c2d3012000-01-20Martin Nilsson  if(line[0] == '#')
2d81ff1999-09-02Per Hedbor  { string file; string name, to;
c2d3012000-01-20Martin Nilsson  if(sscanf(line, "#include <%s>", file))
2d81ff1999-09-02Per Hedbor  {
35cf042000-03-13Per Hedbor  if(catch(line=lopen(file,"r")->read()))
7aa9732000-08-01Martin Nilsson  report_error("Supports: Cannot include file "+file+"\n");
35cf042000-03-13Per Hedbor  else parse_supports_string(line, current_section, defines);
c2d3012000-01-20Martin Nilsson  }
696ed72000-01-21Martin Nilsson  else if(sscanf(line, "#define %[^ \t]%*[ \t]%s", name, to)) {
2d81ff1999-09-02Per Hedbor  name -= "\t";
696ed72000-01-21Martin Nilsson  defines[name] = replace(to, ({"\t",","}), ({" "," "}) )/" "-({""}); array add=({}); foreach(defines[name], string sup) if(defines[sup]) { defines[name]-=({sup}); add+=defines[sup]; } defines[name]+=add;
91d3c32001-03-12Martin Nilsson // report_debug("#defining '"+name+"' to "+to+"\n");
c2d3012000-01-20Martin Nilsson  } else if(sscanf(line, "#section %[^ ] {", name)) {
91d3c32001-03-12Martin Nilsson // report_debug("Entering section "+name+"\n");
2d81ff1999-09-02Per Hedbor  current_section = name; if(!supports[name]) supports[name] = ({});
c2d3012000-01-20Martin Nilsson  } else if((line-" ") == "#}") {
91d3c32001-03-12Martin Nilsson // report_debug("Leaving section "+current_section+"\n");
2d81ff1999-09-02Per Hedbor  current_section = 0; }
7c67f31999-12-16Martin Nilsson 
c2d3012000-01-20Martin Nilsson  } else {
91d3c32001-03-12Martin Nilsson // report_debug("Parsing supports line '"+line+"'\n");
aa5a892000-03-07Martin Nilsson  array(string) sups = replace(line, ({"\t",","}), ({" "," "}))/" " -({ "" });
696ed72000-01-21Martin Nilsson  array add=({}); foreach(sups, string sup) if(defines[sup]) { sups-=({sup}); add+=defines[sup]; } sups+=add;
7c67f31999-12-16Martin Nilsson 
696ed72000-01-21Martin Nilsson  if(sizeof(sups) < 2)
2d81ff1999-09-02Per Hedbor  continue;
7c67f31999-12-16Martin Nilsson 
696ed72000-01-21Martin Nilsson  if(sups[0] == "default") {
aa5a892000-03-07Martin Nilsson  array(multiset(string)|mapping(string:string)) tmp=split_supports(sups[1..]); default_supports = [multiset(string)]tmp[0] - [multiset(string)]tmp[1]; default_client_var = [mapping(string:string)]tmp[2];
c2d3012000-01-20Martin Nilsson  } else {
2d81ff1999-09-02Per Hedbor  mixed err; if (err = catch { supports[current_section]
696ed72000-01-21Martin Nilsson  += ({ ({ Regexp(sups[0])->match }) + split_supports(sups[1..]) });
c2d3012000-01-20Martin Nilsson  })
7aa9732000-08-01Martin Nilsson  report_error("Failed to parse supports regexp:\n%s\n", describe_backtrace(err));
2d81ff1999-09-02Per Hedbor  } } }
1679422000-03-11Martin Nilsson  supports_ind=({0})+(indices(supports)-({0}));
2d81ff1999-09-02Per Hedbor } public void initiate_supports() { supports = ([ 0:({ }) ]);
c2d3012000-01-20Martin Nilsson  default_supports = (< >); default_client_var = ([ ]);
4c77c82000-03-07Martin Nilsson  parse_supports_string([string]roxenp()->query("Supports"), 0, ([]) );
c2d3012000-01-20Martin Nilsson }
aa5a892000-03-07Martin Nilsson private array(multiset(string)|mapping(string:string)) lookup_supports(string from)
c2d3012000-01-20Martin Nilsson {
aa5a892000-03-07Martin Nilsson  if(array(multiset(string)|mapping(string:string)) q = [array(multiset(string)|mapping(string:string))] cache_lookup("supports", from))
1497c62002-01-02Jonas Wallden  return q + ({ });
c2d3012000-01-20Martin Nilsson 
2708962000-01-25Per Hedbor  multiset (string) sup = (<>); mapping (string:string) m = ([]); multiset (string) nsup = (< >);
1679422000-03-11Martin Nilsson  foreach(supports_ind, string v)
2708962000-01-25Per Hedbor  {
1679422000-03-11Martin Nilsson  if(!v || (sizeof(v)<=sizeof(from) && from[..sizeof(v)-1]==v))
c2d3012000-01-20Martin Nilsson  {
91d3c32001-03-12Martin Nilsson  // report_debug("Section "+v+" match "+from+"\n");
2708962000-01-25Per Hedbor  foreach(supports[v], array(function|multiset) s)
aa5a892000-03-07Martin Nilsson  if(([function(string:void|mixed)]s[0])(from))
2708962000-01-25Per Hedbor  { sup |= s[1]; nsup |= s[2]; m |= s[3]; }
1679422000-03-11Martin Nilsson  if(v) break;
c2d3012000-01-20Martin Nilsson  }
2708962000-01-25Per Hedbor  } if(!sizeof(sup)) { sup = default_supports;
c2d3012000-01-20Martin Nilsson #ifdef DEBUG
91d3c32001-03-12Martin Nilsson  report_debug("Unknown client: \""+from+"\"\n");
c2d3012000-01-20Martin Nilsson #endif }
2708962000-01-25Per Hedbor  sup -= nsup;
2b3e762009-11-17Martin Stjernholm  array res = ({sup, m}); sup = m = 0; // Discard refs for memory counting in cache_set. cache_set("supports", from, res); return res + ({});
c2d3012000-01-20Martin Nilsson }
696ed72000-01-21Martin Nilsson  //---------------------- Returns the supports flags ------------------------ // Return a list of 'supports' flags for the current connection.
aa5a892000-03-07Martin Nilsson multiset(string) find_supports(string from, void|multiset(string) existing_sup)
c2d3012000-01-20Martin Nilsson {
2708962000-01-25Per Hedbor  if(!multisetp(existing_sup)) existing_sup=(<>);
c2d3012000-01-20Martin Nilsson  if(!strlen(from) || from == "unknown") return default_supports|existing_sup;
aa5a892000-03-07Martin Nilsson  return ([multiset(string)]lookup_supports(from)[0])|existing_sup;
c2d3012000-01-20Martin Nilsson }
696ed72000-01-21Martin Nilsson // Return a list of 'supports' variables for the current connection.
aa5a892000-03-07Martin Nilsson mapping(string:string) find_client_var(string from, void|mapping(string:string) existing_cv)
c2d3012000-01-20Martin Nilsson {
2708962000-01-25Per Hedbor  if(!mappingp(existing_cv)) existing_cv=([]);
c2d3012000-01-20Martin Nilsson  if(!strlen(from) || from == "unknown")
2708962000-01-25Per Hedbor  return default_client_var|existing_cv;
c2d3012000-01-20Martin Nilsson 
aa5a892000-03-07Martin Nilsson  return ([mapping(string:string)]lookup_supports(from)[1])|existing_cv;
2d81ff1999-09-02Per Hedbor }
aa5a892000-03-07Martin Nilsson array(multiset(string)| mapping(string:string)) find_supports_and_vars(string from, void|multiset(string) existing_sup, void|mapping(string:string) existing_cv)
0431052000-02-15Martin Nilsson { if(!multisetp(existing_sup)) existing_sup=(<>); if(!mappingp(existing_cv)) existing_cv=([]); if(!strlen(from) || from == "unknown") return ({ default_supports|existing_sup, default_client_var|existing_cv });
aa5a892000-03-07Martin Nilsson  array(multiset(string)|mapping(string:string)) ret = lookup_supports(from);
0431052000-02-15Martin Nilsson  ret[0]|=existing_sup; ret[1]|=existing_cv; return ret; }