Пример #1
0
function caller_landmark($position = 1, $skipfunction_re = null)
{
    if (is_string($position)) {
        list($position, $skipfunction_re) = array(1, $position);
    }
    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    $fname = null;
    for (++$position; isset($trace[$position]); ++$position) {
        $fname = get_s($trace[$position], "class");
        $fname .= ($fname ? "::" : "") . $trace[$position]["function"];
        if ((!$skipfunction_re || !preg_match($skipfunction_re, $fname)) && ($fname !== "call_user_func" || get($trace[$position - 1], "file"))) {
            break;
        }
    }
    $t = "";
    if ($position > 0 && ($pi = $trace[$position - 1]) && isset($pi["file"])) {
        $t = $pi["file"] . ":" . $pi["line"];
    }
    if ($fname) {
        $t .= ($t ? ":" : "") . $fname;
    }
    return $t ?: "<unknown>";
}
Пример #2
0
 public function document($dtype, $did = 0)
 {
     assert($did || $dtype == DTYPE_SUBMISSION || $dtype == DTYPE_FINAL);
     if ($dtype == DTYPE_SUBMISSION || $dtype == DTYPE_FINAL) {
         if ($this->finalPaperStorageId <= 0) {
             $psi = [DTYPE_SUBMISSION, $this->paperStorageId];
         } else {
             $psi = [DTYPE_FINAL, $this->finalPaperStorageId];
         }
         if ($did == 0 || $did == $psi[1]) {
             return (object) ["paperId" => $this->paperId, "documentType" => $psi[0], "paperStorageId" => $psi[1], "mimetype" => get_s($this, "mimetype"), "size" => get_i($this, "size"), "timestamp" => get_i($this, "timestamp"), "sha1" => get_s($this, "sha1")];
         }
     }
     // load document object from database if pre-loaded version doesn't work
     return Dbl::fetch_first_object("select paperId, documentType, paperStorageId, mimetype, size, timestamp, sha1, filename from PaperStorage where paperStorageId=?", $did);
 }
Пример #3
0
 static function reparse($line, $header)
 {
     $i = 0;
     $a = array();
     foreach ($line as $field) {
         if (get_s($header, $i) !== "") {
             $a[$header[$i]] = $field;
         } else {
             $a[$i] = $field;
         }
         ++$i;
     }
     return $a;
 }
Пример #4
0
 static function send_preparation($prep)
 {
     global $Conf, $Opt;
     if (!isset($Opt["internalMailer"])) {
         $Opt["internalMailer"] = strncasecmp(PHP_OS, "WIN", 3) != 0;
     }
     $headers = $prep->headers;
     // create valid To: header
     $to = $prep->to;
     if (is_array($to)) {
         $to = join(", ", $to);
     }
     $to = MimeText::encode_email_header("To: ", $to);
     $headers["to"] = $to . MAILER_EOL;
     // set sendmail parameters
     $extra = get_s($Opt, "sendmailParam");
     if (isset($Opt["emailSender"])) {
         @ini_set("sendmail_from", $Opt["emailSender"]);
         if (!isset($Opt["sendmailParam"])) {
             $extra = "-f" . escapeshellarg($Opt["emailSender"]);
         }
     }
     if ($prep->sendable && $Opt["internalMailer"] && ($sendmail = ini_get("sendmail_path"))) {
         $htext = join("", $headers);
         $f = popen($extra ? "{$sendmail} {$extra}" : $sendmail, "wb");
         fwrite($f, $htext . MAILER_EOL . $prep->body);
         $status = pclose($f);
         if (pcntl_wifexited($status) && pcntl_wexitstatus($status) == 0) {
             return true;
         } else {
             $Opt["internalMailer"] = false;
             error_log("Mail " . $headers["to"] . " failed to send, falling back (status {$status})");
         }
     }
     if ($prep->sendable) {
         if (strpos($to, MAILER_EOL) === false) {
             unset($headers["to"]);
             $to = substr($to, 4);
             // skip "To: "
         } else {
             $to = "";
         }
         unset($headers["subject"]);
         $htext = substr(join("", $headers), 0, -2);
         return mail($to, $prep->subject, $prep->body, $htext, $extra);
     } else {
         if (!$Opt["sendEmail"] && !preg_match('/\\Aanonymous\\d*\\z/', $to)) {
             unset($headers["mime-version"], $headers["content-type"]);
             $text = join("", $headers) . MAILER_EOL . $prep->body;
             if (PHP_SAPI == "cli" && !get($Opt, "disablePrintEmail")) {
                 fwrite(STDERR, "========================================\n" . str_replace("\r\n", "\n", $text) . "========================================\n");
             } else {
                 $Conf->infoMsg("<pre>" . htmlspecialchars($text) . "</pre>");
             }
             return null;
         }
     }
 }
Пример #5
0
 public function table_html($listname, $options = array())
 {
     global $Conf;
     if (!$this->_prepare()) {
         return null;
     }
     if (isset($options["fold"])) {
         foreach ($options["fold"] as $n => $v) {
             $this->viewmap->{$n} = $v;
         }
     }
     if (isset($options["table_id"])) {
         $this->viewmap->table_id = $options["table_id"];
     }
     // need tags for row coloring
     if ($this->contact->can_view_tags(null)) {
         $this->qopts["tags"] = 1;
     }
     $this->table_type = $listname;
     // get column list, check sort
     $field_list = $this->_list_columns($listname);
     if (!$field_list) {
         Conf::msg_error("There is no paper list query named “" . htmlspecialchars($listname) . "”.");
         return null;
     }
     $field_list = $this->_columns($field_list, true);
     $body_attr = $this->row_attr;
     $rows = $this->_rows($field_list);
     if ($rows === null) {
         return null;
     }
     // return IDs if requested
     if (empty($rows)) {
         if ($altq = $this->search->alternate_query()) {
             $altqh = htmlspecialchars($altq);
             $url = $this->search->url_site_relative_raw($altq);
             if (substr($url, 0, 5) == "search") {
                 $altqh = "<a href=\"" . htmlspecialchars(Navigation::siteurl() . $url) . "\">" . $altqh . "</a>";
             }
             return "No matching papers. Did you mean “{$altqh}”?";
         } else {
             return "No matching papers";
         }
     }
     // get field array
     $fieldDef = array();
     $ncol = $titlecol = 0;
     // folds: au:1, anonau:2, fullrow:3, aufull:4, force:5, rownum:6, [fields]
     $next_fold = 7;
     foreach ($field_list as $fdef) {
         if ($fdef->view != Column::VIEW_NONE) {
             $fieldDef[] = $fdef;
         }
         if ($fdef->view != Column::VIEW_NONE && $fdef->foldable) {
             $fdef->foldable = $next_fold;
             ++$next_fold;
         }
         if ($fdef->name == "title") {
             $titlecol = $ncol;
         }
         if ($fdef->view == Column::VIEW_COLUMN && !$fdef->is_folded) {
             ++$ncol;
         }
     }
     // count non-callout columns
     $skipcallout = 0;
     foreach ($fieldDef as $fdef) {
         if ($fdef->name != "id" && !isset($fdef->is_selector)) {
             break;
         } else {
             ++$skipcallout;
         }
     }
     // create render state
     $rstate = new PaperListRenderState($ncol, $titlecol, $skipcallout);
     // collect row data
     $body = array();
     $lastheading = !empty($this->search->groupmap) ? -1 : -2;
     $need_render = false;
     foreach ($rows as $row) {
         ++$this->count;
         if ($lastheading > -2) {
             $lastheading = $this->_check_heading($this->_row_thenval($row), $rstate, $rows, $lastheading, $body);
         }
         $body[] = $this->_row_text($rstate, $row, $fieldDef);
         if ($this->need_render && !$need_render) {
             $Conf->footerScript('$(plinfo.render_needed)', 'plist_render_needed');
             $need_render = true;
         }
         if ($this->need_render && $this->count % 16 == 15) {
             $body[count($body) - 1] .= "  <script>plinfo.render_needed()</script>\n";
             $this->need_render = false;
         }
     }
     if ($lastheading > -2 && $this->search->is_order_anno) {
         while ($lastheading + 1 < count($this->search->groupmap)) {
             $lastheading = $this->_check_heading($lastheading + 1, $rstate, $rows, $lastheading, $body);
         }
     }
     // header cells
     $colhead = "";
     $url = $this->search->url_site_relative_raw();
     if (!defval($options, "noheader")) {
         $colhead .= " <thead class=\"pltable\">\n  <tr class=\"pl_headrow\">";
         $ord = 0;
         $titleextra = $this->_make_title_header_extra($rstate, $fieldDef, get($options, "header_links"));
         foreach ($fieldDef as $fdef) {
             if ($fdef->view != Column::VIEW_COLUMN || $fdef->is_folded) {
                 continue;
             }
             $colhead .= "<th class=\"pl " . $fdef->className;
             if ($fdef->foldable) {
                 $colhead .= " fx" . $fdef->foldable;
             }
             $colhead .= "\">";
             if ($fdef->has_content) {
                 $colhead .= $this->_field_title($fdef, $ord);
             }
             if ($titleextra && $fdef->className == "pl_title") {
                 $colhead .= $titleextra;
                 $titleextra = false;
             }
             $colhead .= "</th>";
             ++$ord;
         }
         $colhead .= "</tr>\n";
         if ($this->search->is_order_anno) {
             $colhead .= "  <tr class=\"pl_headrow pl_annorow\" data-anno-tag=\"{$this->search->is_order_anno}\">";
             if ($rstate->titlecol) {
                 $colhead .= "<td colspan=\"{$rstate->titlecol}\"></td>";
             }
             $colhead .= "<td colspan=\"" . ($rstate->ncol - $rstate->titlecol) . "\"><a href=\"#\" onclick=\"return plinfo_tags.edit_anno(this)\">Annotate order</a></td></tr>\n";
         }
         $colhead .= " </thead>\n";
     }
     // table skeleton including fold classes
     $foldclasses = array();
     if ($this->foldable) {
         $foldclasses = $this->_analyze_folds($rstate, $fieldDef);
     }
     $enter = "";
     if (self::$include_stash) {
         $enter .= Ht::take_stash();
     }
     $enter .= "<table class=\"pltable plt_" . htmlspecialchars($listname);
     if (defval($options, "class")) {
         $enter .= " " . $options["class"];
     }
     if ($this->listNumber) {
         $enter .= " has_hotcrp_list";
     }
     if (!empty($foldclasses)) {
         $enter .= " " . join(" ", $foldclasses);
     }
     if ($this->viewmap->table_id) {
         $enter .= "\" id=\"" . $this->viewmap->table_id;
     }
     if (defval($options, "attributes")) {
         foreach ($options["attributes"] as $n => $v) {
             $enter .= "\" {$n}=\"" . htmlspecialchars($v);
         }
     }
     if ($this->search->is_order_anno) {
         $enter .= "\" data-order-tag=\"{$this->search->is_order_anno}";
     }
     foreach ($body_attr as $k => $v) {
         $enter .= "\" {$k}=\"" . htmlspecialchars($v);
     }
     if ($this->listNumber) {
         $enter .= '" data-hotcrp-list="' . $this->listNumber;
     }
     $enter .= "\" data-fold=\"true\">\n";
     $exit = "</table>";
     // maybe make columns, maybe not
     $tbody_class = "pltable";
     if ($this->viewmap->columns && !empty($rstate->ids) && $this->_column_split($rstate, $colhead, $body)) {
         $enter = '<div class="plsplit_col_ctr_ctr"><div class="plsplit_col_ctr">' . $enter;
         $exit = $exit . "</div></div>";
         $ncol = $rstate->split_ncol;
         $tbody_class = "pltable_split";
     } else {
         $enter .= $colhead;
         $tbody_class .= $rstate->hascolors ? " pltable_colored" : "";
     }
     // footer
     $foot = "";
     if ($this->viewmap->statistics && !$this->viewmap->columns) {
         $foot .= $this->_statistics_rows($rstate, $fieldDef);
     }
     if ($fieldDef[0] instanceof SelectorPaperColumn && !defval($options, "nofooter")) {
         $foot .= $this->_footer($ncol, get_s($options, "footer_extra"));
     }
     if ($foot) {
         $enter .= ' <tfoot' . ($rstate->hascolors ? ' class="pltable_colored"' : "") . ">\n" . $foot . " </tfoot>\n";
     }
     // body
     $enter .= " <tbody class=\"{$tbody_class}\">\n";
     // header scripts to set up delegations
     if ($this->_header_script) {
         $enter .= '  <script>' . $this->_header_script . "</script>\n";
     }
     // session variable to remember the list
     if ($this->listNumber) {
         $sl = $this->search->create_session_list_object($rstate->ids, self::_listDescription($listname), $this->sortdef());
         if (isset($this->qreq->sort)) {
             $url .= (strpos($url, "?") ? "&" : "?") . "sort=" . urlencode($this->qreq->sort);
         }
         $sl->url = $url;
         if (get($options, "list_properties")) {
             foreach ($options["list_properties"] as $k => $v) {
                 $sl->{$k} = $v;
             }
         }
         SessionList::change($this->listNumber, $sl);
     }
     foreach ($fieldDef as $fdef) {
         if ($fdef->has_content) {
             $this->any[$fdef->name] = true;
         }
     }
     if ($rstate->has_openau) {
         $this->any->openau = true;
     }
     if ($rstate->has_anonau) {
         $this->any->anonau = true;
     }
     $this->ids = $rstate->ids;
     return $enter . join("", $body) . " </tbody>\n" . $exit;
 }
 function infer_user_name($r, $contact)
 {
     // If user hasn't entered a name, try to infer it from author records
     if ($this->row && $this->row->paperId > 0) {
         $e1 = get_s($contact, "email");
         $e2 = get_s($contact, "preferredEmail");
         foreach ($this->row->author_list() as $au) {
             if (($au->firstName || $au->lastName) && $au->email && (strcasecmp($au->email, $e1) == 0 || strcasecmp($au->email, $e2) == 0)) {
                 $r->firstName = $au->firstName;
                 $r->lastName = $au->lastName;
                 $r->name = $au->name();
                 return;
             }
         }
     }
 }
Пример #7
0
 function make_preparation($template, $rest = array())
 {
     global $Conf;
     // look up template
     if (is_string($template) && $template[0] == "@") {
         $template = self::get_template(substr($template, 1));
     }
     // add rest fields to template for expansion
     foreach (self::$email_fields as $lcfield => $field) {
         if (isset($rest[$lcfield])) {
             $template[$lcfield] = $rest[$lcfield];
         }
     }
     // expand the template
     $prep = $this->preparation = $this->create_preparation();
     $m = $this->expand($template);
     $this->preparation = null;
     $subject = MimeText::encode_header("Subject: ", $m["subject"]);
     $prep->subject = substr($subject, 9);
     $prep->body = $m["body"];
     // look up recipient; use preferredEmail if set
     $recipient = $this->recipient;
     if (!$recipient || !$recipient->email) {
         return Conf::msg_error("no email in Mailer::send");
     }
     if (get($recipient, "preferredEmail")) {
         $recipient = (object) array("email" => $recipient->preferredEmail);
         foreach (array("firstName", "lastName", "name", "fullName") as $k) {
             if (get($this->recipient, $k)) {
                 $recipient->{$k} = $this->recipient->{$k};
             }
         }
     }
     $prep->to = array(Text::user_email_to($recipient));
     $m["to"] = $prep->to[0];
     $prep->sendable = self::allow_send($recipient->email);
     // parse headers
     if (!$Conf->opt("emailFromHeader")) {
         $Conf->set_opt("emailFromHeader", MimeText::encode_email_header("From: ", $Conf->opt("emailFrom")));
     }
     $eol = self::eol();
     $prep->headers = array("from" => $Conf->opt("emailFromHeader") . $eol, "subject" => $subject . $eol, "to" => "");
     foreach (self::$email_fields as $lcfield => $field) {
         if (($text = get_s($m, $lcfield)) !== "" && $text !== "<none>") {
             if ($hdr = MimeText::encode_email_header($field . ": ", $text)) {
                 $prep->headers[$lcfield] = $hdr . $eol;
             } else {
                 $prep->errors[$lcfield] = $text;
                 if (!get($rest, "no_error_quit")) {
                     Conf::msg_error("{$field} destination “<samp>" . htmlspecialchars($text) . "</samp>” isn't a valid email list.");
                 }
             }
         }
     }
     $prep->headers["mime-version"] = "MIME-Version: 1.0" . $eol;
     $prep->headers["content-type"] = "Content-Type: text/plain; charset=utf-8" . $eol;
     if ($prep->errors && !get($rest, "no_error_quit")) {
         return false;
     } else {
         return $prep;
     }
 }
 function __construct($args)
 {
     if (is_object($args)) {
         $args = get_object_vars($args);
     }
     $this->id = (int) $args["id"];
     $this->name = $args["name"];
     $this->type = $args["type"];
     $this->abbr = $args["abbr"];
     $this->description = get_s($args, "description");
     $p = get($args, "position");
     if ((is_int($p) || is_float($p)) && $p > 0) {
         $this->position = $p;
     } else {
         $this->position = 99999;
     }
     $this->final = !!get($args, "final");
     $vis = get($args, "visibility") ?: get($args, "view_type");
     if ($vis !== "rev" && $vis !== "nonblind" && $vis !== "admin") {
         $vis = "rev";
     }
     $this->visibility = $vis;
     $disp = get($args, "display");
     if (get($args, "near_submission")) {
         $disp = "submission";
     }
     if (get($args, "highlight")) {
         $disp = "prominent";
     }
     if ($disp === null) {
         $disp = "topics";
     }
     $this->display = get(self::$display_map, $disp, self::DISP_DEFAULT);
     $this->form_priority = get_i($args, "form_priority");
     if ($x = get($args, "display_space")) {
         $this->display_space = (int) $x;
     }
     $this->selector = get($args, "selector");
 }
 public function save($req, $contact)
 {
     global $Conf, $Now;
     if (is_array($req)) {
         $req = (object) $req;
     }
     $Table = $this->prow->comment_table_name();
     $LinkTable = $this->prow->table_name();
     $LinkColumn = $this->prow->id_column();
     $req_visibility = get($req, "visibility");
     $is_response = !!($this->commentType & COMMENTTYPE_RESPONSE);
     if ($is_response && get($req, "submit")) {
         $ctype = COMMENTTYPE_RESPONSE | COMMENTTYPE_AUTHOR;
     } else {
         if ($is_response) {
             $ctype = COMMENTTYPE_RESPONSE | COMMENTTYPE_AUTHOR | COMMENTTYPE_DRAFT;
         } else {
             if ($req_visibility == "a" || $req_visibility == "au") {
                 $ctype = COMMENTTYPE_AUTHOR;
             } else {
                 if ($req_visibility == "p" || $req_visibility == "pc") {
                     $ctype = COMMENTTYPE_PCONLY;
                 } else {
                     if ($req_visibility == "admin") {
                         $ctype = COMMENTTYPE_ADMINONLY;
                     } else {
                         if ($this->commentId && $req_visibility === null) {
                             $ctype = $this->commentType;
                         } else {
                             // $req->visibility == "r" || $req->visibility == "rev"
                             $ctype = COMMENTTYPE_REVIEWER;
                         }
                     }
                 }
             }
         }
     }
     if ($is_response ? $this->prow->blind : $Conf->is_review_blind(!!get($req, "blind"))) {
         $ctype |= COMMENTTYPE_BLIND;
     }
     // tags
     if ($is_response) {
         $ctags = " response ";
         if (($rname = $Conf->resp_round_name($this->commentRound)) != "1") {
             $ctags .= "{$rname}response ";
         }
     } else {
         if (get($req, "tags") && preg_match_all(',\\S+,', $req->tags, $m)) {
             $tagger = new Tagger($contact);
             $ctags = array();
             foreach ($m[0] as $text) {
                 if (($text = $tagger->check($text, Tagger::NOVALUE)) && !stri_ends_with($text, "response")) {
                     $ctags[strtolower($text)] = $text;
                 }
             }
             $tagger->sort($ctags);
             $ctags = count($ctags) ? " " . join(" ", $ctags) . " " : null;
         } else {
             $ctags = null;
         }
     }
     // notifications
     $displayed = !($ctype & COMMENTTYPE_DRAFT);
     // query
     $text = get_s($req, "text");
     $q = "";
     $qv = array();
     if ($text === "" && $this->commentId) {
         $change = true;
         $q = "delete from {$Table} where commentId={$this->commentId}";
     } else {
         if ($text === "") {
             /* do nothing */
         } else {
             if (!$this->commentId) {
                 $change = true;
                 $qa = ["contactId, {$LinkColumn}, commentType, comment, commentOverflow, timeModified, replyTo"];
                 $qb = [$contact->contactId, $this->prow->{$LinkColumn}, $ctype, "?", "?", $Now, 0];
                 if (strlen($text) <= 32000) {
                     array_push($qv, $text, null);
                 } else {
                     array_push($qv, UnicodeHelper::utf8_prefix($text, 200), $text);
                 }
                 if ($ctags !== null) {
                     $qa[] = "commentTags";
                     $qb[] = "?";
                     $qv[] = $ctags;
                 }
                 if ($is_response) {
                     $qa[] = "commentRound";
                     $qb[] = $this->commentRound;
                 }
                 if ($displayed) {
                     $qa[] = "timeDisplayed, timeNotified";
                     $qb[] = "{$Now}, {$Now}";
                 }
                 $q = "insert into {$Table} (" . join(", ", $qa) . ") select " . join(", ", $qb) . "\n";
                 if ($is_response) {
                     // make sure there is exactly one response
                     $q .= " from (select {$LinkTable}.{$LinkColumn}, coalesce(commentId, 0) commentId\n                from {$LinkTable}\n                left join {$Table} on ({$Table}.{$LinkColumn}={$LinkTable}.{$LinkColumn} and (commentType&" . COMMENTTYPE_RESPONSE . ")!=0 and commentRound={$this->commentRound})\n                where {$LinkTable}.{$LinkColumn}={$this->prow->{$LinkColumn}} limit 1) t\n        where t.commentId=0";
                 }
             } else {
                 $change = $this->commentType >= COMMENTTYPE_AUTHOR != $ctype >= COMMENTTYPE_AUTHOR;
                 if ($this->timeModified >= $Now) {
                     $Now = $this->timeModified + 1;
                 }
                 // do not notify on updates within 3 hours
                 $qa = "";
                 if ($this->timeNotified + 10800 < $Now || $ctype & COMMENTTYPE_RESPONSE && !($ctype & COMMENTTYPE_DRAFT) && $this->commentType & COMMENTTYPE_DRAFT) {
                     $qa .= ", timeNotified={$Now}";
                 }
                 // reset timeDisplayed if you change the comment type
                 if ((!$this->timeDisplayed || $this->ordinal_missing($ctype)) && $text !== "" && $displayed) {
                     $qa .= ", timeDisplayed={$Now}";
                 }
                 $q = "update {$Table} set timeModified={$Now}{$qa}, commentType={$ctype}, comment=?, commentOverflow=?, commentTags=? where commentId={$this->commentId}";
                 if (strlen($text) <= 32000) {
                     array_push($qv, $text, null);
                 } else {
                     array_push($qv, UnicodeHelper::utf8_prefix($text, 200), $text);
                 }
                 $qv[] = $ctags;
             }
         }
     }
     $result = Dbl::qe_apply($q, $qv);
     if (!$result) {
         return false;
     }
     $cmtid = $this->commentId ?: $result->insert_id;
     if (!$cmtid) {
         return false;
     }
     // log
     $contact->log_activity("Comment {$cmtid} " . ($text !== "" ? "saved" : "deleted"), $this->prow->{$LinkColumn});
     // ordinal
     if ($text !== "" && $this->ordinal_missing($ctype)) {
         $this->save_ordinal($cmtid, $ctype, $Table, $LinkTable, $LinkColumn);
     }
     // reload
     if ($text !== "") {
         $comments = $this->prow->fetch_comments("commentId={$cmtid}");
         $this->merge($comments[$cmtid], $this->prow);
         if ($this->timeNotified == $this->timeModified) {
             self::$watching = $this;
             $this->prow->notify(WATCHTYPE_COMMENT, "CommentInfo::watch_callback", $contact);
             self::$watching = null;
         }
     } else {
         $this->commentId = 0;
         $this->comment = "";
         $this->commentTags = null;
     }
     return true;
 }
Пример #10
0
 function parse($sv, $si)
 {
     global $Conf;
     if (!$sv->newv("resp_active")) {
         return false;
     }
     $old_roundnames = $Conf->resp_round_list();
     $roundnames = array(1);
     $roundnames_set = array();
     if (isset($sv->req["resp_roundname"])) {
         $rname = trim(get_s($sv->req, "resp_roundname"));
         if ($rname === "" || $rname === "none" || $rname === "1") {
             /* do nothing */
         } else {
             if ($rerror = Conf::resp_round_name_error($rname)) {
                 $sv->set_error("resp_roundname", $rerror);
             } else {
                 $roundnames[0] = $rname;
                 $roundnames_set[strtolower($rname)] = 0;
             }
         }
     }
     for ($i = 1; isset($sv->req["resp_roundname_{$i}"]); ++$i) {
         $rname = trim(get_s($sv->req, "resp_roundname_{$i}"));
         if ($rname === "" && get($old_roundnames, $i)) {
             $rname = $old_roundnames[$i];
         }
         if ($rname === "") {
             continue;
         } else {
             if ($rerror = Conf::resp_round_name_error($rname)) {
                 $sv->set_error("resp_roundname_{$i}", $rerror);
             } else {
                 if (get($roundnames_set, strtolower($rname)) !== null) {
                     $sv->set_error("resp_roundname_{$i}", "Response round name “" . htmlspecialchars($rname) . "” has already been used.");
                 } else {
                     $roundnames[] = $rname;
                     $roundnames_set[strtolower($rname)] = $i;
                 }
             }
         }
     }
     foreach ($roundnames_set as $i) {
         $isuf = $i ? "_{$i}" : "";
         if (($v = parse_value($sv, "resp_open{$isuf}", Si::get("resp_open"))) !== null) {
             $sv->save("resp_open{$isuf}", $v <= 0 ? null : $v);
         }
         if (($v = parse_value($sv, "resp_done{$isuf}", Si::get("resp_done"))) !== null) {
             $sv->save("resp_done{$isuf}", $v <= 0 ? null : $v);
         }
         if (($v = parse_value($sv, "resp_grace{$isuf}", Si::get("resp_grace"))) !== null) {
             $sv->save("resp_grace{$isuf}", $v <= 0 ? null : $v);
         }
         if (($v = parse_value($sv, "resp_words{$isuf}", Si::get("resp_words"))) !== null) {
             $sv->save("resp_words{$isuf}", $v < 0 ? null : $v);
         }
         if (($v = parse_value($sv, "msg.resp_instrux{$isuf}", Si::get("msg.resp_instrux"))) !== null) {
             $sv->save("msg.resp_instrux{$isuf}", $v);
         }
     }
     if (count($roundnames) > 1 || $roundnames[0] !== 1) {
         $sv->save("resp_rounds", join(" ", $roundnames));
     } else {
         $sv->save("resp_rounds", null);
     }
     return false;
 }
Пример #11
0
 function output_ajax($values = null, $div = false)
 {
     if ($values === false || $values === true) {
         $values = array("ok" => $values);
     } else {
         if ($values === null) {
             $values = array();
         } else {
             if (is_object($values)) {
                 $values = get_object_vars($values);
             }
         }
     }
     $t = "";
     if (session_id() !== "" && ($msgs = $this->session("msgs", array()))) {
         $this->save_session("msgs", null);
         foreach ($msgs as $msg) {
             if (($msg[0] === "merror" || $msg[0] === "xmerror") && !isset($values["error"])) {
                 $values["error"] = $msg[1];
             }
             if ($div) {
                 $t .= Ht::xmsg($msg[0], $msg[1]);
             } else {
                 $t .= "<span class=\"{$msg['0']}\">{$msg['1']}</span>";
             }
         }
     }
     if ($t !== "") {
         $values["response"] = $t . get_s($values, "response");
     }
     if (isset($_REQUEST["jsontext"]) && $_REQUEST["jsontext"]) {
         header("Content-Type: text/plain");
     } else {
         header("Content-Type: application/json");
     }
     if (check_post()) {
         header("Access-Control-Allow-Origin: *");
     }
     echo json_encode($values);
 }
Пример #12
0
 function __construct($me, $options, $reviewer = false)
 {
     global $Conf;
     if (is_string($options)) {
         $options = array("q" => $options);
     }
     // contact facts
     $this->contact = $me;
     $this->privChair = $me->privChair;
     $this->amPC = $me->isPC;
     $this->cid = $me->contactId;
     // paper selection
     $ptype = get_s($options, "t");
     if ($ptype === 0) {
         $ptype = "";
     }
     if ($this->privChair && !$ptype && $Conf->timeUpdatePaper()) {
         $this->limitName = "all";
     } else {
         if ($me->privChair && $ptype === "act" || $me->isPC && (!$ptype || $ptype === "act" || $ptype === "all") && $Conf->can_pc_see_all_submissions()) {
             $this->limitName = "act";
         } else {
             if ($me->privChair && $ptype === "unm") {
                 $this->limitName = "unm";
             } else {
                 if ($me->isPC && (!$ptype || $ptype === "s" || $ptype === "unm")) {
                     $this->limitName = "s";
                 } else {
                     if ($me->isPC && ($ptype === "und" || $ptype === "undec")) {
                         $this->limitName = "und";
                     } else {
                         if ($me->isPC && ($ptype === "acc" || $ptype === "revs" || $ptype === "reqrevs" || $ptype === "req" || $ptype === "lead" || $ptype === "rable" || $ptype === "manager")) {
                             $this->limitName = $ptype;
                         } else {
                             if ($this->privChair && ($ptype === "all" || $ptype === "unsub")) {
                                 $this->limitName = $ptype;
                             } else {
                                 if ($ptype === "r" || $ptype === "rout" || $ptype === "a") {
                                     $this->limitName = $ptype;
                                 } else {
                                     if ($ptype === "rable") {
                                         $this->limitName = "r";
                                     } else {
                                         if (!$me->is_reviewer()) {
                                             $this->limitName = "a";
                                         } else {
                                             if (!$me->is_author()) {
                                                 $this->limitName = "r";
                                             } else {
                                                 $this->limitName = "ar";
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     // track other information
     $this->allowAuthor = false;
     if ($me->privChair || $me->is_author() || $this->amPC && $Conf->submission_blindness() != Conf::BLIND_ALWAYS) {
         $this->allowAuthor = true;
     }
     // default query fields
     // NB: If a complex query field, e.g., "re", "tag", or "option", is
     // default, then it must be the only default or query construction
     // will break.
     $this->fields = array();
     $qtype = defval($options, "qt", "n");
     if ($qtype === "n" || $qtype === "ti") {
         $this->fields["ti"] = 1;
     }
     if ($qtype === "n" || $qtype === "ab") {
         $this->fields["ab"] = 1;
     }
     if ($this->allowAuthor && ($qtype === "n" || $qtype === "au" || $qtype === "ac")) {
         $this->fields["au"] = 1;
     }
     if ($this->privChair && $qtype === "ac") {
         $this->fields["co"] = 1;
     }
     if ($this->amPC && $qtype === "re") {
         $this->fields["re"] = 1;
     }
     if ($this->amPC && $qtype === "tag") {
         $this->fields["tag"] = 1;
     }
     $this->qt = $qtype === "n" ? "" : $qtype;
     // the query itself
     $this->q = trim(get_s($options, "q"));
     // URL base
     if (isset($options["urlbase"])) {
         $this->urlbase = $options["urlbase"];
     } else {
         $this->urlbase = hoturl_site_relative_raw("search", "t=" . urlencode($this->limitName));
         if ($qtype !== "n") {
             $this->urlbase .= "&qt=" . urlencode($qtype);
         }
     }
     if (strpos($this->urlbase, "&amp;") !== false) {
         trigger_error(caller_landmark() . " PaperSearch::urlbase should be a raw URL", E_USER_NOTICE);
     }
     $this->_reviewer = $reviewer;
     if ($this->_reviewer === false) {
         $this->_reviewer = get($options, "reviewer", false);
     }
     $this->_reviewer_fixed = !!$this->_reviewer;
     if ($this->_reviewer && $reviewer === false) {
         error_log("PaperSearch::\$reviewer set: " . json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)));
     }
     $this->_allow_deleted = defval($options, "allow_deleted", false);
 }
Пример #13
0
 private static function apply_placeholder(&$value, &$js)
 {
     if ($temp = get($js, "placeholder")) {
         if ($value === null || $value === "" || $value === $temp) {
             $js["class"] = trim(get_s($js, "class") . " temptext");
         }
         self::stash_script("jQuery(hotcrp_load.temptext)", "temptext");
     }
 }
Пример #14
0
 private function merge($user)
 {
     if (is_array($user)) {
         $user = (object) $user;
     }
     if (!isset($user->dsn) || $user->dsn == $this->conf->dsn) {
         if (isset($user->contactId)) {
             $this->contactId = $this->cid = (int) $user->contactId;
         }
         //else if (isset($user->cid))
         //    $this->contactId = $this->cid = (int) $user->cid;
     }
     if (isset($user->contactDbId)) {
         $this->contactDbId = (int) $user->contactDbId;
     }
     if (isset($user->firstName) && isset($user->lastName)) {
         $name = $user;
     } else {
         $name = Text::analyze_name($user);
     }
     $this->firstName = get_s($name, "firstName");
     $this->lastName = get_s($name, "lastName");
     if (isset($user->unaccentedName)) {
         $this->unaccentedName = $user->unaccentedName;
     } else {
         if (isset($name->unaccentedName)) {
             $this->unaccentedName = $name->unaccentedName;
         } else {
             $this->unaccentedName = Text::unaccented_name($name);
         }
     }
     foreach (array("email", "preferredEmail", "affiliation") as $k) {
         if (isset($user->{$k})) {
             $this->{$k} = simplify_whitespace($user->{$k});
         }
     }
     if (isset($user->collaborators)) {
         $this->collaborators = "";
         foreach (preg_split('/[\\r\\n]+/', $user->collaborators) as $c) {
             if (($c = simplify_whitespace($c)) !== "") {
                 $this->collaborators .= "{$c}\n";
             }
         }
     }
     self::set_sorter($this);
     if (isset($user->password)) {
         $this->password = (string) $user->password;
     }
     if (isset($user->disabled)) {
         $this->disabled = !!$user->disabled;
     }
     foreach (["defaultWatch", "passwordTime", "passwordUseTime", "updateTime", "creationTime"] as $k) {
         if (isset($user->{$k})) {
             $this->{$k} = (int) $user->{$k};
         }
     }
     if (property_exists($user, "contactTags")) {
         $this->contactTags = $user->contactTags;
     } else {
         $this->contactTags = false;
     }
     if (isset($user->activity_at)) {
         $this->activity_at = (int) $user->activity_at;
     } else {
         if (isset($user->lastLogin)) {
             $this->activity_at = (int) $user->lastLogin;
         }
     }
     if (isset($user->extension)) {
         $this->extension = !!$user->extension;
     }
     if (isset($user->seascode_username)) {
         $this->seascode_username = $user->seascode_username;
     }
     if (isset($user->github_username)) {
         $this->github_username = $user->github_username;
     }
     if (isset($user->anon_username)) {
         $this->anon_username = $user->anon_username;
     }
     if (isset($user->contactImageId)) {
         $this->contactImageId = (int) $user->contactImageId;
     }
     if (isset($user->roles) || isset($user->isPC) || isset($user->isAssistant) || isset($user->isChair)) {
         $roles = (int) get($user, "roles");
         if (get($user, "isPC")) {
             $roles |= self::ROLE_PC;
         }
         if (get($user, "isAssistant")) {
             $roles |= self::ROLE_ADMIN;
         }
         if (get($user, "isChair")) {
             $roles |= self::ROLE_CHAIR;
         }
         $this->assign_roles($roles);
     }
     if (!$this->isPC && $this->conf->opt("disableNonPC")) {
         $this->disabled = true;
     }
     if (isset($user->is_site_contact)) {
         $this->is_site_contact = $user->is_site_contact;
     }
     $this->username = $this->github_username ?: $this->seascode_username;
 }
Пример #15
0
 private function same_authors($pj, $opj)
 {
     $pj_ct = count(get($pj, "authors"));
     $opj_ct = count(get($opj, "authors"));
     if ($pj_ct != $opj_ct) {
         return false;
     }
     for ($i = 0; $i != $pj_ct; ++$i) {
         if (get($pj->authors[$i], "email") !== get($opj->authors[$i], "email") || get_s($pj->authors[$i], "affiliation") !== get_s($opj->authors[$i], "affiliation") || Text::name_text($pj->authors[$i]) !== Text::name_text($opj->authors[$i])) {
             return false;
         }
     }
     return true;
 }
Пример #16
0
 private function merge($user)
 {
     global $Conf;
     if (is_array($user)) {
         $user = (object) $user;
     }
     if (!isset($user->dsn) || $user->dsn == $Conf->dsn) {
         if (isset($user->contactId)) {
             $this->contactId = $this->cid = (int) $user->contactId;
         }
         //else if (isset($user->cid))
         //    $this->contactId = $this->cid = (int) $user->cid;
     }
     if (isset($user->contactDbId)) {
         $this->contactDbId = (int) $user->contactDbId;
     }
     if (isset($user->firstName) && isset($user->lastName)) {
         $name = $user;
     } else {
         $name = Text::analyze_name($user);
     }
     $this->firstName = get_s($name, "firstName");
     $this->lastName = get_s($name, "lastName");
     if (isset($user->unaccentedName)) {
         $this->unaccentedName = $user->unaccentedName;
     } else {
         if (isset($name->unaccentedName)) {
             $this->unaccentedName = $name->unaccentedName;
         } else {
             $this->unaccentedName = Text::unaccented_name($name);
         }
     }
     foreach (array("email", "preferredEmail", "affiliation", "voicePhoneNumber", "country") as $k) {
         if (isset($user->{$k})) {
             $this->{$k} = simplify_whitespace($user->{$k});
         }
     }
     if (isset($user->collaborators)) {
         $this->collaborators = "";
         foreach (preg_split('/[\\r\\n]+/', $user->collaborators) as $c) {
             if (($c = simplify_whitespace($c)) !== "") {
                 $this->collaborators .= "{$c}\n";
             }
         }
     }
     self::set_sorter($this);
     if (isset($user->password)) {
         $this->password = (string) $user->password;
     }
     if (isset($user->disabled)) {
         $this->disabled = !!$user->disabled;
     }
     foreach (["defaultWatch", "passwordTime", "passwordUseTime", "updateTime", "creationTime"] as $k) {
         if (isset($user->{$k})) {
             $this->{$k} = (int) $user->{$k};
         }
     }
     if (property_exists($user, "contactTags")) {
         $this->contactTags = $user->contactTags;
     } else {
         $this->contactTags = false;
     }
     if (isset($user->activity_at)) {
         $this->activity_at = (int) $user->activity_at;
     } else {
         if (isset($user->lastLogin)) {
             $this->activity_at = (int) $user->lastLogin;
         }
     }
     if (isset($user->data) && $user->data) {
         // this works even if $user->data is a JSON string
         // (array_to_object_recursive($str) === $str)
         $this->data = array_to_object_recursive($user->data);
     }
     if (isset($user->roles) || isset($user->isPC) || isset($user->isAssistant) || isset($user->isChair)) {
         $roles = (int) get($user, "roles");
         if (get($user, "isPC")) {
             $roles |= self::ROLE_PC;
         }
         if (get($user, "isAssistant")) {
             $roles |= self::ROLE_ADMIN;
         }
         if (get($user, "isChair")) {
             $roles |= self::ROLE_CHAIR;
         }
         $this->assign_roles($roles);
     }
     if (isset($user->has_review)) {
         $this->has_review_ = $user->has_review;
     }
     if (isset($user->has_outstanding_review)) {
         $this->has_outstanding_review_ = $user->has_outstanding_review;
     }
     if (isset($user->is_site_contact)) {
         $this->is_site_contact = $user->is_site_contact;
     }
 }
Пример #17
0
 private function collect_papers($req, &$pids, $report_error)
 {
     $pfield = trim(get_s($req, "paper"));
     if ($pfield !== "" && ctype_digit($pfield)) {
         $pids[intval($pfield)] = 2;
     } else {
         if ($pfield !== "") {
             if (!isset($this->searches[$pfield])) {
                 $search = new PaperSearch($this->contact, $pfield);
                 $this->searches[$pfield] = $search->paperList();
                 if ($report_error) {
                     foreach ($search->warnings as $w) {
                         $this->error($w);
                     }
                 }
             }
             foreach ($this->searches[$pfield] as $pid) {
                 $pids[$pid] = 1;
             }
             if (!count($this->searches[$pfield]) && $report_error) {
                 $this->error("No papers match “" . htmlspecialchars($pfield) . "”");
             }
         } else {
             if ($report_error) {
                 $this->error("Bad paper column");
             }
         }
     }
 }
Пример #18
0
 public static function active($listtype = null, $id = null)
 {
     global $Conf, $Me, $Now;
     // check current-list cache
     if (!$listtype && self::$active_list) {
         return self::$active_list;
     } else {
         if (!$listtype) {
             $listtype = "p";
             $id = $Conf->paper ? $Conf->paper->paperId : null;
         }
     }
     if (!$id) {
         return null;
     }
     $listid = "{$id}/{$listtype}";
     if (self::$active_listid === $listid) {
         return self::$active_list;
     }
     // start with requested list
     $list = self::requested();
     if ($list && !str_starts_with(get_s($list, "listid"), $listtype)) {
         $list = null;
     }
     // look up ID in list; try new lists if not found
     $k = false;
     if ($list) {
         $k = array_search($id, $list->ids);
     }
     if ($k === false) {
         $list = self::try_list([], $listtype);
         $k = array_search($id, $list->ids);
     }
     if ($k === false && $Me->privChair) {
         $list = self::try_list(["t" => "all"], $listtype);
         $k = array_search($id, $list->ids);
     }
     if ($k === false) {
         $list = null;
     }
     // save list changes
     if ($list && !get($list, "listno")) {
         $list->listno = self::allocate($list->listid);
     }
     if ($list) {
         $list->timestamp = $Now;
         self::change($list->listno, $list);
         $list->id_position = $k;
     }
     self::$active_listid = $listid;
     self::$active_list = $list;
     return $list;
 }
$arg = getopt_rest($argv, "hn:", array("help", "name:"));
if (isset($arg["h"]) || isset($arg["help"])) {
    fwrite(STDOUT, "Usage: php batch/updateutf8trans.php CODEPOINT STRING...\n");
    exit(0);
}
function quote_key($k)
{
    if (strlen($k) == 2) {
        return sprintf("\\x%02X\\x%02X", ord($k[0]), ord($k[1]));
    } else {
        return sprintf("\\x%02X\\x%02X\\x%02X", ord($k[0]), ord($k[1]), ord($k[2]));
    }
}
for ($i = 0; $i < count($arg["_"]); $i += 2) {
    $sin = $arg["_"][$i];
    $sout = trim(get_s($arg["_"], $i + 1));
    if ($sin !== "" && is_numeric($sin)) {
        $cp = (int) $sin;
        if ($cp < 0x80) {
            $sin = chr($cp);
        } else {
            if ($cp < 0x800) {
                $sin = chr(0xc0 | $cp >> 6) . chr(0x80 | $cp & 0x3f);
            } else {
                if ($cp < 0x10000) {
                    $sin = chr(0xe0 | $cp >> 12) . chr(0x80 | $cp >> 6 & 0x3f) . chr(0x80 | $cp & 0x3f);
                } else {
                    if ($cp < 0x800) {
                        $sin = chr(0xf0 | $cp >> 18) . chr(0x80 | $cp >> 12 & 0x3f) . chr(0x80 | $cp >> 6 & 0x3f) . chr(0x80 | $cp & 0x3f);
                    } else {
                        $sin = "";
Пример #20
0
    error_go(false, "That password reset code has expired, or you didn’t enter it correctly.");
}
if ($iscdb) {
    $Acct = Contact::contactdb_find_by_id($capdata->contactId);
} else {
    $Acct = Contact::find_by_id($capdata->contactId);
}
if (!$Acct) {
    error_go(false, "That password reset code refers to a user who no longer exists. Either create a new account or contact the conference administrator.");
}
// don't show information about the current user, if there is one
$Me = new Contact();
$password_class = "";
if (isset($_POST["go"]) && check_post()) {
    $_POST["password"] = trim(get_s($_POST, "password"));
    $_POST["password2"] = trim(get_s($_POST, "password2"));
    if ($_POST["password"] == "") {
        Conf::msg_error("You must enter a password.");
    } else {
        if ($_POST["password"] !== $_POST["password2"]) {
            Conf::msg_error("The two passwords you entered did not match.");
        } else {
            if (!Contact::valid_password($_POST["password"])) {
                Conf::msg_error("Invalid password.");
            } else {
                $flags = 0;
                if ($_POST["password"] === get($_POST, "autopassword")) {
                    $flags |= Contact::CHANGE_PASSWORD_PLAINTEXT;
                }
                $Acct->change_password(null, $_POST["password"], $flags);
                if (!$iscdb || !($log_acct = $Conf->user_by_email($Acct->email))) {
Пример #21
0
 function parse($sv, $si)
 {
     global $Conf;
     if (!isset($sv->req["rev_roundtag"])) {
         $sv->save("rev_roundtag", null);
         return false;
     }
     // round names
     $roundnames = $roundnames_set = array();
     $roundname0 = $round_deleted = null;
     for ($i = 0; isset($sv->req["roundname_{$i}"]) || isset($sv->req["deleteround_{$i}"]) || !$i; ++$i) {
         $rname = trim(get_s($sv->req, "roundname_{$i}"));
         if ($rname === "(no name)" || $rname === "default" || $rname === "unnamed") {
             $rname = "";
         }
         if ((get($sv->req, "deleteround_{$i}") || $rname === "") && $i) {
             $roundnames[] = ";";
             if (Dbl::fetch_ivalue("select reviewId from PaperReview where reviewRound={$i} limit 1")) {
                 $this->rev_round_changes[] = array($i, 0);
             }
             if ($round_deleted === null && !isset($sv->req["roundname_0"]) && $i < $sv->req["oldroundcount"]) {
                 $round_deleted = $i;
             }
         } else {
             if ($rname === "") {
                 /* ignore */
             } else {
                 if ($rerror = Conf::round_name_error($rname)) {
                     $sv->set_error("roundname_{$i}", $rerror);
                 } else {
                     if ($i == 0) {
                         $roundname0 = $rname;
                     } else {
                         if (get($roundnames_set, strtolower($rname))) {
                             $roundnames[] = ";";
                             $this->rev_round_changes[] = array($i, $roundnames_set[strtolower($rname)]);
                         } else {
                             $roundnames[] = $rname;
                             $roundnames_set[strtolower($rname)] = $i;
                         }
                     }
                 }
             }
         }
     }
     if ($roundname0 && !get($roundnames_set, strtolower($roundname0))) {
         $roundnames[] = $roundname0;
         $roundnames_set[strtolower($roundname0)] = count($roundnames);
     }
     if ($roundname0) {
         array_unshift($this->rev_round_changes, array(0, $roundnames_set[strtolower($roundname0)]));
     }
     // round deadlines
     foreach ($Conf->round_list() as $i => $rname) {
         $suffix = $i ? "_{$i}" : "";
         foreach (Conf::$review_deadlines as $k) {
             $sv->save($k . $suffix, null);
         }
     }
     $rtransform = array();
     if ($roundname0 && ($ri = $roundnames_set[strtolower($roundname0)]) && !isset($sv->req["pcrev_soft_{$ri}"])) {
         $rtransform[0] = "_{$ri}";
         $rtransform[$ri] = false;
     }
     if ($round_deleted) {
         $rtransform[$round_deleted] = "";
         if (!isset($rtransform[0])) {
             $rtransform[0] = false;
         }
     }
     for ($i = 0; $i < count($roundnames) + 1; ++$i) {
         if ((isset($rtransform[$i]) || ($i ? $roundnames[$i - 1] !== ";" : !isset($sv->req["deleteround_0"]))) && get($rtransform, $i) !== false) {
             $isuffix = $i ? "_{$i}" : "";
             if (($osuffix = get($rtransform, $i)) === null) {
                 $osuffix = $isuffix;
             }
             $ndeadlines = 0;
             foreach (Conf::$review_deadlines as $k) {
                 $v = parse_value($sv, $k . $isuffix, Si::get($k));
                 $sv->save($k . $osuffix, $v <= 0 ? null : $v);
                 $ndeadlines += $v > 0;
             }
             if ($ndeadlines == 0 && $osuffix) {
                 $sv->save("pcrev_soft{$osuffix}", 0);
             }
             foreach (array("pcrev_", "extrev_") as $k) {
                 list($soft, $hard) = ["{$k}soft{$osuffix}", "{$k}hard{$osuffix}"];
                 list($softv, $hardv) = [$sv->savedv($soft), $sv->savedv($hard)];
                 if (!$softv && $hardv) {
                     $sv->save($soft, $hardv);
                 } else {
                     if ($hardv && $softv > $hardv) {
                         $desc = $i ? ", round " . htmlspecialchars($roundnames[$i - 1]) : "";
                         $sv->set_error($soft, Si::get("{$k}soft", "short_description") . $desc . ": Must come before " . Si::get("{$k}hard", "short_description") . ".");
                         $sv->set_error($hard);
                     }
                 }
             }
         }
     }
     // round list (save after deadlines processing)
     while (count($roundnames) && $roundnames[count($roundnames) - 1] === ";") {
         array_pop($roundnames);
     }
     $sv->save("tag_rounds", join(" ", $roundnames));
     // default round
     $t = trim($sv->req["rev_roundtag"]);
     $sv->save("rev_roundtag", null);
     if (preg_match('/\\A(?:|\\(none\\)|\\(no name\\)|default|unnamed)\\z/i', $t)) {
         /* do nothing */
     } else {
         if ($t === "#0") {
             if ($roundname0) {
                 $sv->save("rev_roundtag", $roundname0);
             }
         } else {
             if (preg_match('/^#[1-9][0-9]*$/', $t)) {
                 $rname = get($roundnames, substr($t, 1) - 1);
                 if ($rname && $rname !== ";") {
                     $sv->save("rev_roundtag", $rname);
                 }
             } else {
                 if (!($rerror = Conf::round_name_error($t))) {
                     $sv->save("rev_roundtag", $t);
                 } else {
                     $sv->set_error("rev_roundtag", $rerror);
                 }
             }
         }
     }
     if (count($this->rev_round_changes)) {
         $sv->need_lock["PaperReview"] = true;
         return true;
     } else {
         return false;
     }
 }