diff --git a/api/boinc_api.C b/api/boinc_api.C index 5c698c6de9..d8e78f781a 100644 --- a/api/boinc_api.C +++ b/api/boinc_api.C @@ -147,8 +147,10 @@ int boinc_init() { strcpy(aid.user_name, "John Smith"); strcpy(aid.team_name, "The A-Team"); aid.wu_cpu_time = 1000; - aid.total_cobblestones = 1000; - aid.recent_avg_cobblestones = 500; + aid.user_total_credit = 1000; + aid.user_expavg_credit = 500; + aid.host_total_credit = 1000; + aid.host_expavg_credit = 500; aid.checkpoint_period = DEFAULT_CHECKPOINT_PERIOD; aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD; @@ -527,13 +529,17 @@ int write_init_data_file(FILE* f, APP_INIT_DATA& ai) { } fprintf(f, "%f\n" - "%f\n" - "%f\n" + "%f\n" + "%f\n" + "%f\n" + "%f\n" "%f\n" "%f\n", ai.wu_cpu_time, - ai.total_cobblestones, - ai.recent_avg_cobblestones, + ai.user_total_credit, + ai.user_expavg_credit, + ai.host_total_credit, + ai.host_expavg_credit, ai.checkpoint_period, ai.fraction_done_update_period ); @@ -554,8 +560,10 @@ int parse_init_data_file(FILE* f, APP_INIT_DATA& ai) { } else if (parse_str(buf, "", ai.user_name, sizeof(ai.user_name))) continue; else if (parse_str(buf, "", ai.team_name, sizeof(ai.team_name))) continue; - else if (parse_double(buf, "", ai.total_cobblestones)) continue; - else if (parse_double(buf, "", ai.recent_avg_cobblestones)) continue; + else if (parse_double(buf, "", ai.user_total_credit)) continue; + else if (parse_double(buf, "", ai.user_expavg_credit)) continue; + else if (parse_double(buf, "", ai.host_total_credit)) continue; + else if (parse_double(buf, "", ai.host_expavg_credit)) continue; else if (parse_double(buf, "", ai.wu_cpu_time)) continue; else if (parse_double(buf, "", ai.checkpoint_period)) continue; else if (parse_double(buf, "", ai.fraction_done_update_period)) continue; diff --git a/api/boinc_api.h b/api/boinc_api.h index 33aefdabae..04fa0e2dbe 100755 --- a/api/boinc_api.h +++ b/api/boinc_api.h @@ -56,8 +56,10 @@ struct APP_INIT_DATA { char user_name[256]; char team_name[256]; double wu_cpu_time; // cpu time from previous sessions - double total_cobblestones; - double recent_avg_cobblestones; + double user_total_credit; + double user_expavg_credit; + double host_total_credit; + double host_expavg_credit; double checkpoint_period; // recommended checkpoint period double fraction_done_update_period; }; diff --git a/client/app.C b/client/app.C index df951254fe..acaff37eac 100644 --- a/client/app.C +++ b/client/app.C @@ -134,12 +134,19 @@ int ACTIVE_TASK::start(bool first_time) { memset(&aid, 0, sizeof(aid)); - // TODO: fill in the app prefs, team name, etc. - strncpy( aid.user_name, wup->project->user_name, 256 ); - if (wup->project->project_specific_prefs) - strncpy( aid.app_preferences, wup->project->project_specific_prefs, 4096 ); - aid.total_cobblestones = wup->project->user_total_credit; - aid.recent_avg_cobblestones = wup->project->user_expavg_credit; + strncpy(aid.user_name, wup->project->user_name, sizeof(aid.user_name)); + strncpy(aid.team_name, wup->project->team_name, sizeof(aid.team_name)); + if (wup->project->project_specific_prefs) { + strncpy( + aid.app_preferences, + wup->project->project_specific_prefs, + sizeof(aid.app_preferences) + ); + } + aid.user_total_credit = wup->project->user_total_credit; + aid.user_expavg_credit = wup->project->user_expavg_credit; + aid.host_total_credit = wup->project->host_total_credit; + aid.host_expavg_credit = wup->project->host_expavg_credit; aid.checkpoint_period = DEFAULT_CHECKPOINT_PERIOD; aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD; aid.wu_cpu_time = checkpoint_cpu_time; @@ -728,34 +735,28 @@ bool ACTIVE_TASK_SET::poll_time() { return updated; } -// Gets the next available free slot, or returns -1 if all slots are full -// TODO: don't use malloc here +// Get the next available free slot, or returns -1 if all slots are full // int ACTIVE_TASK_SET::get_free_slot(int total_slots) { unsigned int i; - char *slot_status; + int j; + bool found; if (active_tasks.size() >= (unsigned int)total_slots) { return -1; } - slot_status = (char *)calloc( sizeof(char), total_slots ); - if (!slot_status) return -1; - - for (i=0; islot >= 0 && active_tasks[i]->slot < total_slots) { - slot_status[active_tasks[i]->slot] = 1; + for (j=0; jslot == j) { + found = true; + break; + } } + if (!found) return j; } - for (i=0; i<(unsigned int)total_slots; i++) { - if (!slot_status[i]) { - free(slot_status); - return i; - } - } - - free(slot_status); return -1; } diff --git a/client/client_state.C b/client/client_state.C index 17a865ffb1..708429f930 100644 --- a/client/client_state.C +++ b/client/client_state.C @@ -53,7 +53,8 @@ #include "speed_stats.h" #include "client_state.h" -#define SECONDS_PER_MONTH (SECONDS_PER_DAY*30) +#define BENCHMARK_PERIOD (SECONDS_PER_DAY*30) + // rerun CPU benchmarks this often (hardware may have been upgraded) CLIENT_STATE gstate; @@ -183,12 +184,11 @@ int CLIENT_STATE::init() { } // Returns true if time tests should be run -// This is determined by seeing if the user passed the "-no_time_test" // flag or if it's been a month since we last checked time stats // bool CLIENT_STATE::should_run_time_tests() { return ( - difftime(time(0), (time_t)host_info.p_calculated) > SECONDS_PER_MONTH + difftime(time(0), (time_t)host_info.p_calculated) > BENCHMARK_PERIOD ); } @@ -569,7 +569,7 @@ int CLIENT_STATE::parse_state_file() { } else if (match_tag(buf, "")) { active_tasks.parse(f, this); } else if (match_tag(buf, "")) { - // should match out current platform name + // should match our current platform name } else if (match_tag(buf, "")) { // could put logic here to detect incompatible state files // after core client update diff --git a/client/client_types.C b/client/client_types.C index 9a8e5c5ca0..d84a082508 100644 --- a/client/client_types.C +++ b/client/client_types.C @@ -37,6 +37,7 @@ PROJECT::PROJECT() { resource_share = 100; strcpy(project_name,""); strcpy(user_name,""); + strcpy(team_name,""); user_total_credit = 0; user_expavg_credit = 0; user_create_time = 0; @@ -103,6 +104,7 @@ int PROJECT::parse_state(FILE* in) { strcpy(project_name, ""); strcpy(user_name, ""); + strcpy(team_name, ""); resource_share = 100; exp_avg_cpu = 0; exp_avg_mod_time = 0; @@ -119,6 +121,7 @@ int PROJECT::parse_state(FILE* in) { else if (parse_str(buf, "", master_url, sizeof(master_url))) continue; else if (parse_str(buf, "", project_name, sizeof(project_name))) continue; else if (parse_str(buf, "", user_name, sizeof(user_name))) continue; + else if (parse_str(buf, "", user_name, sizeof(team_name))) continue; else if (parse_double(buf, "", user_total_credit)) continue; else if (parse_double(buf, "", user_expavg_credit)) continue; else if (parse_int(buf, "", (int &)user_create_time)) continue; @@ -165,6 +168,7 @@ int PROJECT::write_state(FILE* out) { " %s\n" " %s\n" " %s\n" + " %s\n" " %f\n" " %f\n" " %d\n" @@ -181,6 +185,7 @@ int PROJECT::write_state(FILE* out) { master_url, project_name, user_name, + team_name, user_total_credit, user_expavg_credit, user_create_time, @@ -213,6 +218,7 @@ void PROJECT::copy_state_fields(PROJECT& p) { scheduler_urls = p.scheduler_urls; strcpy(project_name, p.project_name); strcpy(user_name, p.user_name); + strcpy(team_name, p.team_name); user_total_credit = p.user_total_credit; user_expavg_credit = p.user_expavg_credit; user_create_time = p.user_create_time; diff --git a/client/client_types.h b/client/client_types.h index b6c6c034b4..5b90b86321 100644 --- a/client/client_types.h +++ b/client/client_types.h @@ -63,6 +63,7 @@ public: vector scheduler_urls; // where to find scheduling servers char project_name[256]; // descriptive. not unique char user_name[256]; + char team_name[256]; double user_total_credit; // as reported by server double user_expavg_credit; // as reported by server unsigned int user_create_time; // as reported by server diff --git a/client/cs_scheduler.C b/client/cs_scheduler.C index 88b45e4d1a..5358cd2e58 100644 --- a/client/cs_scheduler.C +++ b/client/cs_scheduler.C @@ -17,8 +17,7 @@ // Contributor(s): // -// This file contains high-level logic for communicating with -// scheduling servers, +// High-level logic for communicating with scheduling servers, // and for merging the result of a scheduler RPC into the client state // Note: code for actually doing a scheduler RPC is in scheduler_op.C @@ -33,8 +32,9 @@ #include "file_names.h" #include "filesys.h" #include "parse.h" -#include "log_flags.h" +#include "util.h" +#include "log_flags.h" #include "account.h" #include "message.h" #include "scheduler_op.h" @@ -43,8 +43,7 @@ // quantities like avg CPU time decay by a factor of e every week // -#define SECONDS_IN_DAY (3600*24) -#define EXP_DECAY_RATE (1./(SECONDS_IN_DAY*7)) +#define EXP_DECAY_RATE (1./(SECONDS_PER_DAY*7)) // estimate the days of work remaining // @@ -60,7 +59,7 @@ double CLIENT_STATE::current_water_days() { // TODO: subtract time already finished for WUs in progress seconds_remaining += rp->wup->seconds_to_complete; } - return (seconds_remaining / SECONDS_IN_DAY); + return (seconds_remaining / SECONDS_PER_DAY); } // seconds of work needed to come up to high-water mark @@ -68,7 +67,7 @@ double CLIENT_STATE::current_water_days() { double CLIENT_STATE::work_needed_secs() { double x = current_water_days(); if (x > global_prefs.high_water_days) return 0; - return (global_prefs.high_water_days - x)*SECONDS_IN_DAY; + return (global_prefs.high_water_days - x)*SECONDS_PER_DAY; } // update exponentially-averaged CPU times of all projects diff --git a/client/hostinfo.C b/client/hostinfo.C index 8322a9d7a7..dc25d39c33 100644 --- a/client/hostinfo.C +++ b/client/hostinfo.C @@ -191,15 +191,14 @@ int HOST_INFO::write_time_tests(FILE* out) { } // Returns the domain of the local host -// TODO: Should the 256 be MAXHOSTNAMELEN instead? // -int get_local_domain_name(char* p) { +int get_local_domain_name(char* p, int len) { char buf[256]; gethostname(buf, 256); struct hostent* he = gethostbyname(buf); if (!he) return -1; - strcpy(p, he->h_name); + strncpy(p, he->h_name, len); return 0; } diff --git a/client/hostinfo.h b/client/hostinfo.h index 8904ecad75..3aa49bda47 100644 --- a/client/hostinfo.h +++ b/client/hostinfo.h @@ -65,7 +65,7 @@ extern int get_host_info(HOST_INFO&); extern void clear_host_info(HOST_INFO&); extern void get_host_disk_info( double &total_space, double &free_space ); -extern int get_local_domain_name(char* p); +extern int get_local_domain_name(char* p, int len); extern int get_local_ip_addr_str(char* p); extern int get_local_ip_addr(int& p); diff --git a/client/hostinfo_unix.C b/client/hostinfo_unix.C index 2dd0cf8246..1e419293a8 100644 --- a/client/hostinfo_unix.C +++ b/client/hostinfo_unix.C @@ -300,7 +300,7 @@ int get_host_info(HOST_INFO& host) { parse_meminfo(host); #endif - get_local_domain_name(host.domain_name); + get_local_domain_name(host.domain_name, sizeof(host.domain_name)); get_local_ip_addr_str(host.ip_addr); host.timezone = get_timezone(); #ifdef HAVE_SYS_UTSNAME_H diff --git a/client/time_stats.C b/client/time_stats.C index a2b55a3552..207c57ae9e 100644 --- a/client/time_stats.C +++ b/client/time_stats.C @@ -22,6 +22,7 @@ #include #include "parse.h" +#include "util.h" #include "error_numbers.h" #include "time_stats.h" @@ -30,7 +31,7 @@ // The last 30 days have a weight of 1/e; // everything before that has a weight of (1-1/e) -#define ALPHA (3600.*24*7*30) +#define ALPHA (SECONDS_PER_DAY*30) TIME_STATS::TIME_STATS() { last_update = 0; diff --git a/html/user/account_setup.php b/html/user/account_setup.php index ec370165e8..8c5a20817c 100644 --- a/html/user/account_setup.php +++ b/html/user/account_setup.php @@ -1,7 +1,6 @@ prefs); +$prefs = prefs_parse($user->global_prefs); prefs_global_parse_form($prefs); global_prefs_update($user, $prefs); +$prefs = prefs_parse($user->project_prefs); prefs_email_parse_form($prefs); project_prefs_update($user, $prefs); diff --git a/html/user/download.inc b/html/user/download.inc index d9feaa586e..c7481890b4 100644 --- a/html/user/download.inc +++ b/html/user/download.inc @@ -14,10 +14,9 @@ function platform_downloads($platform, $core_app) { echo "CAN'T FIND FILENAMEn $app_version->xml_doc\n"; } $version = sprintf( - $platform->name, $app_version->version_num/100 ); - echo "$platform->user_friendly_name\n"; + echo "$platform->user_friendly_name $version\n"; //$app_version->md5_cksum"; $found = true; } diff --git a/html/user/htmlfilter.inc b/html/user/htmlfilter.inc new file mode 100644 index 0000000000..0b18fdbcfe --- /dev/null +++ b/html/user/htmlfilter.inc @@ -0,0 +1,984 @@ + + * @Version 1.0.5 (Oct-16-2002) + */ + +/** + * This is a debugging function used throughout the code. To enable + * debugging you have to specify a global variable called "debug" before + * calling sanitize() and set it to true. + * + * Note: Although insignificantly, debugging does slow you down even + * when $debug is set to false. If you wish to get rid of all + * debugging calls, run the following command: + * + * fgrep -v 'spew("' htmlfilter.inc > htmlfilter.inc.new + * + * htmlfilter.inc.new will contain no debugging calls. + * + * @param $message A string with the message to output. + * @return void. + */ +function spew($message){ + global $debug; + if ($debug == true){ + echo "$message"; + } +} + +/** + * This function returns the final tag out of the tag name, an array + * of attributes, and the type of the tag. This function is called by + * sanitize internally. + * + * @param $tagname the name of the tag. + * @param $attary the array of attributes and their values + * @param $tagtype The type of the tag (see in comments). + * @return a string with the final tag representation. + */ +function tagprint($tagname, $attary, $tagtype){ + $me = 'tagprint'; + if ($tagtype == 2){ + $fulltag = ''; + } else { + $fulltag = '<' . $tagname; + if (is_array($attary) && sizeof($attary)){ + $atts = Array(); + while (list($attname, $attvalue) = each($attary)){ + array_push($atts, "$attname=$attvalue"); + } + $fulltag .= ' ' . join(' ', $atts); + } + if ($tagtype == 3){ + $fulltag .= ' /'; + } + $fulltag .= '>'; + } + spew("$me: $fulltag\n"); + return $fulltag; +} + +/** + * A small helper function to use with array_walk. Modifies a by-ref + * value and makes it lowercase. + * + * @param $val a value passed by-ref. + * @return void since it modifies a by-ref value. + */ +function casenormalize(&$val){ + $val = strtolower($val); +} + +/** + * This function skips any whitespace from the current position within + * a string and to the next non-whitespace value. + * + * @param $body the string + * @param $offset the offset within the string where we should start + * looking for the next non-whitespace character. + * @return the location within the $body where the next + * non-whitespace char is located. + */ +function skipspace($body, $offset){ + $me = 'skipspace'; + preg_match('/^(\s*)/s', substr($body, $offset), $matches); + if (sizeof($matches{1})){ + $count = strlen($matches{1}); + spew("$me: skipped $count chars\n"); + $offset += $count; + } + return $offset; +} + +/** + * This function looks for the next character within a string. It's + * really just a glorified "strpos", except it catches the failures + * nicely. + * + * @param $body The string to look for needle in. + * @param $offset Start looking from this position. + * @param $needle The character/string to look for. + * @return location of the next occurance of the needle, or + * strlen($body) if needle wasn't found. + */ +function findnxstr($body, $offset, $needle){ + $me = 'findnxstr'; + $pos = strpos($body, $needle, $offset); + if ($pos === FALSE){ + $pos = strlen($body); + spew("$me: end of body reached\n"); + } + spew("$me: '$needle' found at pos $pos\n"); + return $pos; +} + +/** + * This function takes a PCRE-style regexp and tries to match it + * within the string. + * + * @param $body The string to look for needle in. + * @param $offset Start looking from here. + * @param $reg A PCRE-style regex to match. + * @return Returns a false if no matches found, or an array + * with the following members: + * - integer with the location of the match within $body + * - string with whatever content between offset and the match + * - string with whatever it is we matched + */ +function findnxreg($body, $offset, $reg){ + $me = 'findnxreg'; + $matches = Array(); + $retarr = Array(); + $preg_rule = '%^(.*?)(' . $reg . ')%s'; + preg_match($preg_rule, substr($body, $offset), $matches); + if (!$matches{0}){ + spew("$me: No matches found.\n"); + $retarr = false; + } else { + $retarr{0} = $offset + strlen($matches{1}); + $retarr{1} = $matches{1}; + $retarr{2} = $matches{2}; + spew("$me: '$reg' found at pos $offset matching '".$matches{2}."'\n"); + } + return $retarr; +} + +/** + * This function looks for the next tag. + * + * @param $body String where to look for the next tag. + * @param $offset Start looking from here. + * @return false if no more tags exist in the body, or + * an array with the following members: + * - string with the name of the tag + * - array with attributes and their values + * - integer with tag type (1, 2, or 3) + * - integer where the tag starts (starting "<") + * - integer where the tag ends (ending ">") + * first three members will be false, if the tag is invalid. + */ +function getnxtag($body, $offset){ + $me = 'getnxtag'; + if ($offset > strlen($body)){ + spew("$me: Past the end of body\n"); + return false; + } + $lt = findnxstr($body, $offset, '<'); + if ($lt == strlen($body)){ + spew("$me: No more tags found!\n"); + return false; + } + /** + * We are here: + * blah blah + * \---------^ + */ + spew("$me: Found '<' at pos $lt\n"); + $pos = skipspace($body, $lt + 1); + if ($pos >= strlen($body)){ + spew("$me: End of body reached.\n"); + return Array(false, false, false, $lt, strlen($body)); + } + /** + * There are 3 kinds of tags: + * 1. Opening tag, e.g.: + * + * 2. Closing tag, e.g.: + * + * 3. XHTML-style content-less tag, e.g.: + * + */ + $tagtype = false; + switch (substr($body, $pos, 1)){ + case '/': + spew("$me: This is a closing tag (type 2)\n"); + $tagtype = 2; + $pos++; + break; + case '!': + /** + * A comment or an SGML declaration. + */ + if (substr($body, $pos+1, 2) == '--'){ + spew("$me: A comment found. Stripping.\n"); + $gt = strpos($body, '-->', $pos); + if ($gt === false){ + $gt = strlen($body); + } else { + $gt += 2; + } + return Array(false, false, false, $lt, $gt); + } else { + spew("$me: An SGML declaration found. Stripping.\n"); + $gt = findnxstr($body, $pos, '>'); + return Array(false, false, false, $lt, $gt); + } + break; + default: + /** + * Assume tagtype 1 for now. If it's type 3, we'll switch values + * later. + */ + $tagtype = 1; + break; + } + + $tag_start = $pos; + $tagname = ''; + /** + * Look for next [\W-_], which will indicate the end of the tag name. + */ + $regary = findnxreg($body, $pos, '[^\w\-_]'); + if ($regary == false){ + spew("$me: End of body reached while analyzing tag name\n"); + return Array(false, false, false, $lt, strlen($body)); + } + list($pos, $tagname, $match) = $regary; + $tagname = strtolower($tagname); + + /** + * $match can be either of these: + * '>' indicating the end of the tag entirely. + * '\s' indicating the end of the tag name. + * '/' indicating that this is type-3 xhtml tag. + * + * Whatever else we find there indicates an invalid tag. + */ + switch ($match){ + case '/': + /** + * This is an xhtml-style tag with a closing / at the + * end, like so: . Check if it's followed + * by the closing bracket. If not, then this tag is invalid + */ + if (substr($body, $pos, 2) == '/>'){ + spew("$me: XHTML-style tag found.\n"); + $pos++; + spew("$me: Setting tagtype to 3\n"); + $tagtype = 3; + } else { + spew("$me: Found invalid character '/'.\n"); + $gt = findnxstr($body, $pos, '>'); + spew("$me: Tag is invalid. Returning.\n"); + $retary = Array(false, false, false, $lt, $gt); + return $retary; + } + case '>': + spew("$me: End of tag found at $pos\n"); + spew("$me: Tagname is '$tagname'\n"); + spew("$me: This tag has no attributes\n"); + return Array($tagname, false, $tagtype, $lt, $pos); + break; + default: + /** + * Check if it's whitespace + */ + if (preg_match('/\s/', $match)){ + spew("$me: Tagname is '$tagname'\n"); + } else { + /** + * This is an invalid tag! Look for the next closing ">". + */ + spew("$me: Invalid characters found in tag name: $match\n"); + $gt = findnxstr($body, $offset, '>'); + return Array(false, false, false, $lt, $gt); + } + } + + /** + * At this point we're here: + * + * \-------^ + * + * At this point we loop in order to find all attributes. + */ + $attname = ''; + $atttype = false; + $attary = Array(); + + while ($pos <= strlen($body)){ + $pos = skipspace($body, $pos); + if ($pos == strlen($body)){ + /** + * Non-closed tag. + */ + spew("$me: End of body reached before end of tag. Discarding.\n"); + return Array(false, false, false, $lt, $pos); + } + /** + * See if we arrived at a ">" or "/>", which means that we reached + * the end of the tag. + */ + $matches = Array(); + preg_match('%^(\s*)(>|/>)%s', substr($body, $pos), $matches); + if (isset($matches{0}) && $matches{0}){ + /** + * Yep. So we did. + */ + spew("$me: Arrived at the end of the tag.\n"); + $pos += strlen($matches{1}); + if ($matches{2} == '/>'){ + $tagtype = 3; + $pos++; + } + return Array($tagname, $attary, $tagtype, $lt, $pos); + } + + /** + * There are several types of attributes, with optional + * [:space:] between members. + * Type 1: + * attrname[:space:]=[:space:]'CDATA' + * Type 2: + * attrname[:space:]=[:space:]"CDATA" + * Type 3: + * attr[:space:]=[:space:]CDATA + * Type 4: + * attrname + * + * We leave types 1 and 2 the same, type 3 we check for + * '"' and convert to """ if needed, then wrap in + * double quotes. Type 4 we convert into: + * attrname="yes". + */ + $regary = findnxreg($body, $pos, '[^\w\-_]'); + if ($regary == false){ + /** + * Looks like body ended before the end of tag. + */ + spew("$me: End of body found before end of tag.\n"); + spew("$me: Invalid, returning\n"); + return Array(false, false, false, $lt, strlen($body)); + } + list($pos, $attname, $match) = $regary; + $attname = strtolower($attname); + spew("$me: Attribute '$attname' found\n"); + /** + * We arrived at the end of attribute name. Several things possible + * here: + * '>' means the end of the tag and this is attribute type 4 + * '/' if followed by '>' means the same thing as above + * '\s' means a lot of things -- look what it's followed by. + * anything else means the attribute is invalid. + */ + switch($match){ + case '/': + /** + * This is an xhtml-style tag with a closing / at the + * end, like so: . Check if it's followed + * by the closing bracket. If not, then this tag is invalid + */ + if (substr($body, $pos, 2) == '/>'){ + spew("$me: This is an xhtml-style tag.\n"); + $pos++; + spew("$me: Setting tagtype to 3\n"); + $tagtype = 3; + } else { + spew("$me: Found invalid character '/'.\n"); + $gt = findnxstr($body, $pos, '>'); + spew("$me: Tag is invalid. Returning.\n"); + $retary = Array(false, false, false, $lt, $gt); + return $retary; + } + case '>': + spew("$me: found type 4 attribute.\n"); + spew("$me: Additionally, end of tag found at $pos\n"); + spew("$me: Attname is '$attname'\n"); + spew("$me: Setting attvalue to 'yes'\n"); + $attary{$attname} = '"yes"'; + return Array($tagname, $attary, $tagtype, $lt, $pos); + break; + default: + /** + * Skip whitespace and see what we arrive at. + */ + $pos = skipspace($body, $pos); + $char = substr($body, $pos, 1); + /** + * Two things are valid here: + * '=' means this is attribute type 1 2 or 3. + * \w means this was attribute type 4. + * anything else we ignore and re-loop. End of tag and + * invalid stuff will be caught by our checks at the beginning + * of the loop. + */ + if ($char == '='){ + spew("$me: Attribute type 1, 2, or 3 found.\n"); + $pos++; + $pos = skipspace($body, $pos); + /** + * Here are 3 possibilities: + * "'" attribute type 1 + * '"' attribute type 2 + * everything else is the content of tag type 3 + */ + $quot = substr($body, $pos, 1); + if ($quot == '\''){ + spew("$me: In fact, this is attribute type 1\n"); + spew("$me: looking for closing quote\n"); + $regary = findnxreg($body, $pos+1, '\''); + if ($regary == false){ + spew("$me: end of body reached before end of val\n"); + spew("$me: Returning\n"); + return Array(false, false, false, $lt, strlen($body)); + } + list($pos, $attval, $match) = $regary; + spew("$me: Attvalue is '$attval'\n"); + $pos++; + $attary{$attname} = '\'' . $attval . '\''; + } else if ($quot == '"'){ + spew("$me: In fact, this is attribute type 2\n"); + spew("$me: looking for closing quote\n"); + $regary = findnxreg($body, $pos+1, '\"'); + if ($regary == false){ + spew("$me: end of body reached before end of val\n"); + spew("$me: Returning\n"); + return Array(false, false, false, $lt, strlen($body)); + } + list($pos, $attval, $match) = $regary; + spew("$me: Attvalue is \"$attval\"\n"); + $pos++; + $attary{$attname} = '"' . $attval . '"'; + } else { + spew("$me: This looks like attribute type 3\n"); + /** + * These are hateful. Look for \s, or >. + */ + spew("$me: Looking for end of attval\n"); + $regary = findnxreg($body, $pos, '[\s>]'); + if ($regary == false){ + spew("$me: end of body reached before end of val\n"); + spew("$me: Returning\n"); + return Array(false, false, false, $lt, strlen($body)); + } + list($pos, $attval, $match) = $regary; + /** + * If it's ">" it will be caught at the top. + */ + spew("$me: translating '\"' into "\n"); + $attval = preg_replace('/\"/s', '"', $attval); + spew("$me: wrapping in quotes\n"); + $attary{$attname} = '"' . $attval . '"'; + } + } else if (preg_match('|[\w/>]|', $char)) { + /** + * That was attribute type 4. + */ + spew("$me: attribute type 4 found.\n"); + spew("$me: Setting value to 'yes'\n"); + $attary{$attname} = '"yes"'; + } else { + /** + * An illegal character. Find next '>' and return. + */ + spew("$me: illegal character '$char' found.\n"); + spew("$me: returning\n"); + $gt = findnxstr($body, $pos, '>'); + return Array(false, false, false, $lt, $gt); + } + } + } + /** + * The fact that we got here indicates that the tag end was never + * found. Return invalid tag indication so it gets stripped. + */ + spew("$me: No tag end found\n"); + return Array(false, false, false, $lt, strlen($body)); +} + +/** + * This function checks attribute values for entity-encoded values + * and returns them translated into 8-bit strings so we can run + * checks on them. + * + * @param $attvalue A string to run entity check against. + * @return Translated value. + */ +function deent($attvalue){ + $me = 'deent'; + /** + * See if we have to run the checks first. All entities must start + * with "&". + */ + if (strpos($attvalue, '&') === false){ + return $attvalue; + } + /** + * Check named entities first. + */ + spew("$me: translating named entities\n"); + $trans = get_html_translation_table(HTML_ENTITIES); + /** + * Leave " in, as it can mess us up. + */ + $trans = array_flip($trans); + unset($trans{'"'}); + while (list($ent, $val) = each($trans)){ + $attvalue = preg_replace('/' . $ent . '*/si', $val, $attvalue); + } + /** + * Now translate numbered entities from 1 to 255 if needed. + */ + if (strpos($attvalue, '#') !== false){ + spew("$me: translating numbered entities\n"); + $omit = Array(34, 39); + for ($asc = 256; $asc >= 0; $asc--){ + if (!in_array($asc, $omit)){ + $chr = chr($asc); + $octrule = '/\�*' . $asc . ';*/si'; + $hexrule = '/\�*' . dechex($asc) . ';*/si'; + $attvalue = preg_replace($octrule, $chr, $attvalue); + $attvalue = preg_replace($hexrule, $chr, $attvalue); + } + } + } + spew("$me: translated into: $attvalue\n"); + return $attvalue; +} + +/** + * This function runs various checks against the attributes. + * + * @param $tagname String with the name of the tag. + * @param $attary Array with all tag attributes. + * @param $rm_attnames See description for sanitize + * @param $bad_attvals See description for sanitize + * @param $add_attr_to_tag See description for sanitize + * @return Array with modified attributes. + */ +function fixatts($tagname, + $attary, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag + ){ + $me = 'fixatts'; + spew("$me: Fixing attributes\n"); + while (list($attname, $attvalue) = each($attary)){ + /** + * See if this attribute should be removed. + */ + foreach ($rm_attnames as $matchtag=>$matchattrs){ + if (preg_match($matchtag, $tagname)){ + foreach ($matchattrs as $matchattr){ + if (preg_match($matchattr, $attname)){ + spew("$me: Attribute '$attname' defined as bad.\n"); + spew("$me: Removing.\n"); + unset($attary{$attname}); + continue; + } + } + } + } + /** + * Remove any entities. + */ + $attvalue = deent($attvalue); + + /** + * Now let's run checks on the attvalues. + * I don't expect anyone to comprehend this. If you do, + * get in touch with me so I can drive to where you live and + * shake your hand personally. :) + */ + foreach ($bad_attvals as $matchtag=>$matchattrs){ + if (preg_match($matchtag, $tagname)){ + foreach ($matchattrs as $matchattr=>$valary){ + if (preg_match($matchattr, $attname)){ + /** + * There are two arrays in valary. + * First is matches. + * Second one is replacements + */ + list($valmatch, $valrepl) = $valary; + $newvalue = preg_replace($valmatch, $valrepl, $attvalue); + if ($newvalue != $attvalue){ + spew("$me: attvalue is now $newvalue\n"); + $attary{$attname} = $newvalue; + } + } + } + } + } + } + /** + * See if we need to append any attributes to this tag. + */ + foreach ($add_attr_to_tag as $matchtag=>$addattary){ + if (preg_match($matchtag, $tagname)){ + $attary = array_merge($attary, $addattary); + spew("$me: Added attributes to this tag\n"); + } + } + return $attary; +} + +/** + * This is the main function and the one you should actually be calling. + * There are several variables you should be aware of an which need + * special description. + * + * $tag_list + * ---------- + * This is a simple one-dimentional array of strings, except for the + * very first one. The first member should be einter false or true. + * In case it's FALSE, the following list will be considered a list of + * tags that should be explicitly REMOVED from the body, and all + * others that did not match the list will be allowed. If the first + * member is TRUE, then the list is the list of tags that should be + * explicitly ALLOWED -- any tag not matching this list will be + * discarded. + * + * Examples: + * $tag_list = Array( + * false, + * "blink", + * "link", + * "object", + * "meta", + * "marquee", + * "html" + * ); + * + * This will allow all tags except for blink, link, object, meta, marquee, + * and html. + * + * $tag_list = Array( + * true, + * "b", + * "a", + * "i", + * "img", + * "strong", + * "em", + * "p" + * ); + * + * This will remove all tags from the body except b, a, i, img, strong, em and + * p. + * + * $rm_tags_with_content + * --------------------- + * This is a simple one-dimentional array of strings, which specifies the + * tags to be removed with any and all content between the beginning and + * the end of the tag. + * Example: + * $rm_tags_with_content = Array( + * "script", + * "style", + * "applet", + * "embed" + * ); + * + * This will remove the following structure: + * + * + * $self_closing_tags + * ------------------ + * This is a simple one-dimentional array of strings, which specifies which + * tags contain no content and should not be forcefully closed if this option + * is turned on (see further). + * Example: + * $self_closing_tags = Array( + * "img", + * "br", + * "hr", + * "input" + * ); + * + * $force_tag_closing + * ------------------ + * Set it to true to forcefully close any tags opened within the document. + * This is good if you want to take care of people who like to screw up + * the pages by leaving unclosed tags like , , , etc. + * + * $rm_attnames + * ------------- + * Now we come to parameters that are more obscure. This parameter is + * a nested array which is used to specify which attributes should be + * removed. It goes like so: + * + * $rm_attnames = Array( + * "PCRE regex to match tag name" => + * Array( + * "PCRE regex to match attribute name" + * ) + * ); + * + * Example: + * $rm_attnames = Array( + * "|.*|" => + * Array( + * "|target|i", + * "|^on.*|i" + * ) + * ); + * + * This will match all attributes (.*), and specify that all attributes + * named "target" and starting with "on" should be removed. This will take + * care of the following problem: + * + * The "onmouseover" will be removed. + * + * $bad_attvals + * ------------ + * This is where it gets ugly. This is a nested array with many levels. + * It goes like so: + * + * $bad_attvals = Array( + * "pcre regex to match tag name" => + * Array( + * "pcre regex to match attribute name" => + * Array( + * "pcre regex to match attribute value" + * ) + * Array( + * "pcre regex replace a match from above with" + * ) + * ) + * ); + * + * An extensive example: + * + * $bad_attvals = Array( + * "|.*|" => + * Array( + * "/^src|background|href|action/i" => + * Array( + * Array( + * "/^([\'\"])\s*\S+script\s*:.*([\'\"])/si" + * ), + * Array( + * "\\1http://veryfunny.com/\\2" + * ) + * ), + * "/^style/i" => + * Array( + * Array( + * "/expression/si", + * "/url\(([\'\"])\s*https*:.*([\'\"])\)/si", + * "/url\(([\'\"])\s*\S+script:.*([\'\"])\)/si" + * ), + * Array( + * "idiocy", + * "url(\\1http://veryfunny.com/\\2)", + * "url(\\1http://veryfynny.com/\\2)" + * ) + * ) + * ) + * ); + * + * This will take care of nearly all known cross-site scripting exploits, + * plus some (see my filter sample at + * http://www.mricon.com/html/phpfilter.html for a working version). + * + * $add_attr_to_tag + * ---------------- + * This is a useful little feature which lets you add attributes to + * certain tags. It is a nested array as well, but not at all like + * the previous one. It goes like so: + * + * $add_attr_to_tag = Array( + * "PCRE regex to match tag name" => + * Array( + * "attribute name"=>'"attribute value"' + * ) + * ); + * + * Note: don't forget quotes around attribute value. + * + * Example: + * + * $add_attr_to_tag = Array( + * "/^a$/si" => + * Array( + * 'target'=>'"_new"' + * ) + * ); + * + * This will change all tags and add target="_new" to them so all links + * open in a new window. + * + * + * + * @param $body the string with HTML you wish to filter + * @param $tag_list see description above + * @param $rm_tags_with_content see description above + * @param $self_closing_tags see description above + * @param $force_tag_closing see description above + * @param $rm_attnames see description above + * @param $bad_attvals see description above + * @param $add_attr_to_tag see description above + * @return sanitized html safe to show on your pages. + */ +function sanitize($body, + $tag_list, + $rm_tags_with_content, + $self_closing_tags, + $force_tag_closing, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag + ){ + $me = 'sanitize'; + /** + * Normalize rm_tags and rm_tags_with_content. + */ + @array_walk($rm_tags, 'casenormalize'); + @array_walk($rm_tags_with_content, 'casenormalize'); + @array_walk($self_closing_tags, 'casenormalize'); + /** + * See if tag_list is of tags to remove or tags to allow. + * false means remove these tags + * true means allow these tags + */ + $rm_tags = array_shift($tag_list); + $curpos = 0; + $open_tags = Array(); + $trusted = "\n"; + $skip_content = false; + /** + * Take care of netscape's stupid javascript entities like + * &{alert('boo')}; + */ + $body = preg_replace('/&(\{.*?\};)/si', '&\\1', $body); + spew("$me: invoking the loop\n"); + while (($curtag = getnxtag($body, $curpos)) != FALSE){ + list($tagname, $attary, $tagtype, $lt, $gt) = $curtag; + spew("$me: grabbing free-standing content\n"); + $free_content = substr($body, $curpos, $lt - $curpos); + spew("$me: " . strlen($free_content) . " chars grabbed\n"); + if ($skip_content == false){ + spew("$me: appending free content to trusted.\n"); + $trusted .= $free_content; + } else { + spew("$me: Skipping free content.\n"); + } + if ($tagname != FALSE){ + spew("$me: tagname is '$tagname'\n"); + if ($tagtype == 2){ + spew("$me: This is a closing tag\n"); + if ($skip_content == $tagname){ + /** + * Got to the end of tag we needed to remove. + */ + spew("$me: Finished removing tag with content\n"); + $tagname = false; + $skip_content = false; + } else { + if ($skip_content == false){ + if (isset($open_tags{$tagname}) && + $open_tags{$tagname} > 0){ + spew("$me: popping '$tagname' from open_tags\n"); + $open_tags{$tagname}--; + } else { + spew("$me: '$tagname' was never opened\n"); + spew("$me: removing\n"); + $tagname = false; + } + } else { + spew("$me: Skipping this tag\n"); + } + } + } else { + /** + * $rm_tags_with_content + */ + if ($skip_content == false){ + /** + * See if this is a self-closing type and change + * tagtype appropriately. + */ + if ($tagtype == 1 + && in_array($tagname, $self_closing_tags)){ + spew("$me: Self-closing tag. Changing tagtype.\n"); + $tagtype = 3; + } + /** + * See if we should skip this tag and any content + * inside it. + */ + if ($tagtype == 1 && in_array($tagname, $rm_tags_with_content)){ + spew("$me: removing this tag with content\n"); + $skip_content = $tagname; + } else { + if (($rm_tags == false && in_array($tagname, $tag_list)) || + ($rm_tags == true && !in_array($tagname, $tag_list))){ + spew("$me: Removing this tag.\n"); + $tagname = false; + } else { + if ($tagtype == 1){ + spew("$me: adding '$tagname' to open_tags\n"); + if (isset($open_tags{$tagname})){ + $open_tags{$tagname}++; + } else { + $open_tags{$tagname} = 1; + } + } + /** + * This is where we run other checks. + */ + if (is_array($attary) && sizeof($attary) > 0){ + $attary = fixatts($tagname, + $attary, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag); + } + } + } + } else { + spew("$me: Skipping this tag\n"); + } + } + if ($tagname != false && $skip_content == false){ + spew("$me: Appending tag to trusted.\n"); + $trusted .= tagprint($tagname, $attary, $tagtype); + } + } else { + spew("$me: Removing invalid tag\n"); + } + $curpos = $gt + 1; + } + spew("$me: Appending any leftover content\n"); + $trusted .= substr($body, $curpos, strlen($body) - $curpos); + if ($force_tag_closing == true){ + foreach ($open_tags as $tagname=>$opentimes){ + while ($opentimes > 0){ + spew("$me: '$tagname' left open. Closing by force.\n"); + $trusted .= ''; + $opentimes--; + } + } + $trusted .= "\n"; + } + $trusted .= "\n"; + return $trusted; +} +?> diff --git a/html/user/prefs.inc b/html/user/prefs.inc index dbc2d8a4ac..9ca6f1e2de 100644 --- a/html/user/prefs.inc +++ b/html/user/prefs.inc @@ -76,7 +76,7 @@ function element_end($parser, $name) { $parse_result->run_if_user_active = true; break; case "confirm_before_connecting": - $parse_result->confirm_before_connecting = 1; + $parse_result->confirm_before_connecting = true; break; case "low_water_days": $parse_result->low_water_days = $text; @@ -128,8 +128,8 @@ function char_handler($parser, $x) { function default_prefs() { $p = null; $p->run_on_batteries = false; - $p->run_if_user_active = false; - $p->confirm_before_connecting = 0; + $p->run_if_user_active = true; + $p->confirm_before_connecting = false; $p->low_water_days = 1; $p->high_water_days = 3; $p->disk_max_used_gb = 100; @@ -139,15 +139,18 @@ function default_prefs() { $p->resource_share = 100; $p->show_email = false; $p->send_email = true; + + $p->project_specific = project_specific_prefs_default(); return $p; } // state of prefs before parsing // function initial_prefs() { - $p = default_prefs; + $p = default_prefs(); $p->show_email = false; $p->send_email = false; + return $p; } // parse prefs (either global or project) from XML to a struct @@ -242,8 +245,8 @@ function prefs_form_global($user, $prefs) {
(This matters only if you use a modem) "; - printf("Yes \n", $prefs->confirm_before_connecting?"checked":""); - printf("No \n", $prefs->confirm_before_connecting?"":"checked"); + printf("Yes \n", $prefs->confirm_before_connecting?"checked":""); + printf("No \n", $prefs->confirm_before_connecting?"":"checked"); echo " Keep enough to work on disk to last between @@ -339,11 +342,21 @@ function venue_update($user) { // function prefs_global_parse_form(&$prefs) { parse_str(getenv("QUERY_STRING")); + $prefs->run_on_batteries = ($run_on_batteries == "yes"); $prefs->run_if_user_active = ($run_if_user_active == "yes"); - $prefs->confirm_before_connecting = isset($confirm_before_connecting)?1:0; + $prefs->confirm_before_connecting = ($confirm_before_connecting == "yes"); + + if ($low_water_days<0) $low_water_days = 0; + if ($high_water_days<0) $high_water_days = 0; + if ($low_water_days > $high_water_days) $low_water_days = $high_water_days; $prefs->low_water_days = $low_water_days; $prefs->high_water_days = $high_water_days; + + if ($disk_max_used_gb<0) $disk_max_used_gb = 0; + if ($disk_max_used_pct<0) $disk_max_used_pct = 0; + if ($disk_max_used_pct>100) $disk_max_used_pct = 100; + if ($disk_min_free_gb<0) $disk_min_free_gb = 0; $prefs->disk_max_used_gb = $disk_max_used_gb; $prefs->disk_max_used_pct = $disk_max_used_pct; $prefs->disk_min_free_gb = $disk_min_free_gb; @@ -401,9 +414,14 @@ function project_prefs_make_xml($prefs) { if ($prefs->send_email == 1) { $xml = $xml."\n"; } - $xml = $xml - ."$prefs->resource_share\n" - ."\n$prefs->project_specific\n"; + if ($prefs->resource_share) { + $xml = $xml + ."$prefs->resource_share\n"; + } + if ($prefs->project_specific) { + $xml = $xml + ."\n$prefs->project_specific\n"; + } $xml = $xml."\n"; return $xml; } diff --git a/html/user/project.inc b/html/user/project.inc index 47d8945cea..0494a8e36a 100755 --- a/html/user/project.inc +++ b/html/user/project.inc @@ -1,5 +1,7 @@ $name\n"; } +function project_specific_prefs_default() { + return "Tahiti Sunset\n"; +} + // given struct, show form for editing // function project_specific_prefs_edit($prefs) { diff --git a/html/user/sanitize_html.inc b/html/user/sanitize_html.inc new file mode 100644 index 0000000000..8d4cbd469c --- /dev/null +++ b/html/user/sanitize_html.inc @@ -0,0 +1,105 @@ + + Array( + '/target/i', + '/^on.*/i', + '/^dynsrc/i', + '/^datasrc/i', + '/^data.*/i' + ) + ); + +/** + * Yeah-yeah, so this looks horrible. Check out htmlfilter.inc for + * some idea of what's going on here. :) + */ + +$bad_attvals = Array( + '/.*/' => + Array( + '/.*/' => + Array( + Array( + '/^([\'\"])\s*\S+\s*script\s*:*(.*)([\'\"])/i', + '/^([\'\"])\s*https*\s*:(.*)([\'\"])/i', + '/^([\'\"])\s*mocha\s*:*(.*)([\'\"])/i', + '/^([\'\"])\s*about\s*:(.*)([\'\"])/i' + ), + Array( + '\\1oddjob:\\2\\3', + '\\1uucp:\\2\\3', + '\\1amaretto:\\2\\3', + '\\1round:\\2\\3' + ) + ), + + '/^style/i' => + Array( + Array( + '/expression/i', + '/behaviou*r/i', + '/binding/i', + '/url\(([\'\"]*)\s*https*:.*([\'\"]*)\)/i', + '/url\(([\'\"]*)\s*\S+script:.*([\'\"]*)\)/i' + ), + Array( + 'idiocy', + 'idiocy', + 'idiocy', + 'url(\\1http://securityfocus.com/\\2)', + 'url(\\1http://securityfocus.com/\\2)' + ) + ) + ) + ); + +$add_attr_to_tag = Array( + '/^a$/i' => Array('target' => '"_new"') + ); + +function sanitize_html($body) { + global $tag_list; + global $rm_tags_with_content; + global $self_closing_tags; + global $force_tag_closing; + global $rm_attnames; + global $bad_attvals; + global $add_attr_to_tag; + return sanitize( + $body, + $tag_list, + $rm_tags_with_content, + $self_closing_tags, + $force_tag_closing, + $rm_attnames, + $bad_attvals, + $add_attr_to_tag + ); +} + +?> diff --git a/html/user/team.inc b/html/user/team.inc index e4e7ae300c..ad3187b9b9 100644 --- a/html/user/team.inc +++ b/html/user/team.inc @@ -2,6 +2,7 @@ require_once("util.inc"); require_once("db.inc"); +require_once("sanitize_html.inc"); function show_team($team) { start_table(); @@ -11,7 +12,7 @@ function show_team($team) { row("url", $team->url); row("type", $team->type); row("name_html", $team->name_html); - row("description", $team->description); + row("description", sanitize_html($team->description)); } function display_team_page($team) { @@ -36,7 +37,7 @@ function display_team_page($team) { echo "Team Info:"; echo ""; if (strlen($team->description)) { - row("Description: ", $team->description); + row("Description: ", sanitize_html($team->description)); } if (strlen($team->url)) {; row("Web site: ", "url>http://$team->url"); diff --git a/html/user/team_edit_action.php b/html/user/team_edit_action.php index 8bff27c140..6cff5a2771 100644 --- a/html/user/team_edit_action.php +++ b/html/user/team_edit_action.php @@ -18,39 +18,38 @@ require_founder_login($user, $team); $team_url = ereg_replace("\"", "'", $HTTP_POST_VARS["url"]); - $pos = strpos($team_url, "http://"); - if (!($pos === false)) { // note: three equal signs - $team_url = substr($team_url, 7); + $x = strstr($team_url, "http://"); + if ($x) { + $team_url = substr($team_url, 7); } $team_name = ereg_replace("\"", "'", $HTTP_POST_VARS["name"]); $team_name_html = ereg_replace("\"", "'", $HTTP_POST_VARS["name_html"]); $team_description = ereg_replace("\"", "'", $HTTP_POST_VARS["description"]); - - $query_team_table = sprintf( - "update team set name = '%s', - name_html = '%s', - url = '%s', - description = '%s', - type = %d - where id = %d", - $team_name, - $team_name_html, - $team_url, - $team_description, - $HTTP_POST_VARS["type"], - $team->id - ); - $result_team_table = mysql_query($query_team_table); - if ($result_team_table) { - page_head("Changes accepted"); - $team_name = $team->name; - echo "

Changes Accepted

"; - echo "The changes to id>$team_name were accepted and should now be in effect."; - } else { - page_head("Error"); - echo "Couldn't edit team - please try later.\n"; - } + $query_team_table = sprintf( + "update team set name = '%s', + name_html = '%s', + url = '%s', + description = '%s', + type = %d + where id = %d", + $team_name, + $team_name_html, + $team_url, + $team_description, + $HTTP_POST_VARS["type"], + $team->id + ); + $result_team_table = mysql_query($query_team_table); + if ($result_team_table) { + page_head("Changes accepted"); + $team_name = $team->name; + echo "

Changes Accepted

"; + echo "The changes to id>$team_name were accepted and should now be in effect."; + } else { + page_head("Error"); + echo "Couldn't edit team - please try later.\n"; + } page_tail(); diff --git a/html/user/util.inc b/html/user/util.inc index 3f2b96456b..fc90a47baa 100644 --- a/html/user/util.inc +++ b/html/user/util.inc @@ -206,7 +206,9 @@ function no_cache() { // (Used during account creation and email address changes) // a valid email address is of the form A@B.C -// where A, B, C are nonempty and don't contain @ or . +// where A, B, C are nonempty, +// A and B don't contain @ or ., +// and C doesn't contain @ // function is_valid_email_addr($addr) { $x = strstr($addr, "@"); @@ -218,9 +220,6 @@ function is_valid_email_addr($addr) { if (!$y) return false; if (strlen($y) == strlen($x)) return false; if (strlen($y) == 1) return false; - $y = substr($y, 1); - if (strstr($y, ".")) return false; - if (strlen($y) == 0) return false; return true; } @@ -241,4 +240,8 @@ function split_munged_email_addr($addr, $string, &$email) { return true; } +// remove all HTML tags except vanilla formatting +// +function cleanse_html($text) { +} ?>