diff --git a/www/forums.php b/www/forums.php new file mode 100644 index 0000000..1f4298f --- /dev/null +++ b/www/forums.php @@ -0,0 +1,1149 @@ +"; + +if ($from == "" || $from == "Anonymous") + $from = "Anonymous "; + + +// +// 'format_date()' - Format a RFC 2822 date string. +// + +function // O - Date/time in human format +format_date($rfc2822) // I - Date/time in RFC 2822 format +{ + if (($time = strtotime($rfc2822)) < 0) + $date = htmlspecialchars($rfc2822, ENT_QUOTES); + else + { + $diff = abs(time() - $time); + + if ($diff < 604800) + $date = date("H:i D", $time); + else if ($diff < 31536000) + $date = date("H:i M d", $time); + else + $date = date("M d, Y", $time); + } + + return ($date); +} + + +// +// 'nntp_header()' - Show the standard header and nav links. +// + +function +nntp_header($title, // I - Title + $links) // I - Links +{ + html_header($title); + html_start_links(TRUE); + html_links($links); + html_end_links(); +} + + +// +// 'nntp_close()' - Close a news server thing... +// + +function +nntp_close($stream) // I - Socket stream +{ + nntp_command($stream, "QUIT", 205); + + fclose($stream); +} + + +// +// 'nntp_command()' - Send a command and get the response... +// + +function // O - NNTP response +nntp_command($stream, // I - Socket stream + $command = "QUIT", // I - NNTP command + $expect = 200) // I - Expected status + +{ +// print("

nntp_command(stream=$stream, command='$command', expect=$expect)

\n"); + + fwrite($stream, "$command\r\n"); + + $status = fgets($stream, 1024); + +// print("

status='$status'

\n"); + +// if ((int)$status != $expect) +// { +// print("

Error: $status

\n"); +// return (NULL); +// } +// else + return ($status); +} + + +// +// 'nntp_connect()' - Connect to the news server. +// + +function // O - Socket stream +nntp_connect() +{ + global $NNTPSERVER, $NNTPPORT; + + + $errno = 0; + $errstr = ""; + $stream = fsockopen($NNTPSERVER, $NNTPPORT, $errno, $errstr); + + if ($stream) + { + if ($line = fgets($stream, 1024)) + { + if ((int)$line != 200) + { + print("

Error: $line

\n"); + fclose($stream); + return (FALSE); + } + } + else + { + print("

Error: No response from NNTP server!

\n"); + fclose($stream); + return (FALSE); + } + } + else + print("

Error: $errstr ($errno)

\n"); + + return ($stream); +} + + +// +// 'nntp_error()' - Show an error message. +// + +function +nntp_error($text, // I - Human-readable message + $status, // I - NNTP status message + $group = "") // I - Current group, if any +{ + $links = array(); + + $links["All Forums"] = "forums.php"; + if ($group != "") + $links["Back to $group"] = "forums.php?g$group"; + + nntp_header("Error", $links); + + print("

$text

\n" + ."
$status
\n"); + + html_footer(); +} + + +// +// 'nntp_search()' - Do a header search... +// + +function // O - Matching message headers... +nntp_search($stream, // I - Socket stream + $group, // I - NNTP group + $search, // I - Search text + $threaded = TRUE) // I - Thread messages? +{ +// print("

nntp_search(stream=$stream, group='$group', search='$search'

\n"); + + // Get the start and end messages in the group... + $status = nntp_command($stream, "GROUP $group", 211); + if ((int)$status != 211) + { + nntp_error("We were unable to open the forum '$group' for the following " + ."reason:", $status, $group); + return (NULL); + } + + // Read the messages in the group... + $fields = explode(" ", $status); + $status = nntp_command($stream, "XOVER $fields[2]-$fields[3]", 224); + if ((int)$status != 224) + { + nntp_error("We were unable to search the forum '$group' for the following " + ."reason:", $status, $group); + return (NULL); + } + + $words = html_search_words($search); + $num_matches = 0; + $matches = NULL; + + while ($line = fgets($stream, 1024)) + { + $line = rtrim($line); + + if ($line == ".") + break; + +// print("
" . htmlspecialchars($line) . "
\n"); + + if ($search == "") + { + // Return all matches... + $matches[$num_matches] = $line; + $num_matches ++; + } + else + { + // Search for words... + reset($words); + + $fields = explode("\t", $line); + + foreach ($words as $word) + { + if (stristr($fields[1], $word) || stristr($fields[2], $word)) + { + $matches[$num_matches] = $line; + $num_matches ++; + break; + } + } + } + } + + if ($threaded) + { + // Thread the articles... + $threads = array(); + $parents = array(); + + for ($i = 0; $i < sizeof($matches); $i ++) + { + $fields = explode("\t", $matches[$i]); + $subject = eregi_replace("(re:|\\[[a-z]+\\.[a-z]+\\]) ", "", $fields[1]); + + if (array_key_exists($subject, $parents)) + $threads[$i] = sprintf("%06d%06d", $parents[$subject], $i); + else + { + $parents["$subject"] = $i; + $threads[$i] = sprintf("%06d%06d", $i, $i); + } + } + + array_multisort($threads, SORT_NUMERIC, $matches); + } + + // Return the matches... + return ($matches); +} + + +// +// 'show_prevnext_page()' - Show the prev/next links for the messages list... +// + +function +show_prevnext_page($group, // I - Group + $group_filter, // I - Group filter + $start, // I - Start message + $end, // I - End message + $count, // I - Number of messages + $threaded) // I - Thread messages? +{ + global $PHP_SELF, $PAGE_MAX, $options; + + + print("

\n" + ."\n" + ."
"); + + if ($start > 1) + { + $i = $start - $PAGE_MAX; + if ($i < 1) + $i = 1; + + $j = $i + $PAGE_MAX - 1; + if ($j > $count) + $j = $count; + + html_start_links(); + html_link("Show Messages $i - $j", "$PHP_SELF?s$i+g$group$options"); + html_end_links(); + } + + print(""); + html_start_links(); + if (!ereg(".*\.announce", $group) && !ereg(".*\.commit", $group)) + html_link("New Message", "$PHP_SELF?s$start+g$group+n$options"); + if ($threaded) + html_link("Sort by Date", + "$PHP_SELF?s$start+g$group+T0" . substr($options, 3)); + else + html_link("Sort by Thread", + "$PHP_SELF?s$start+g$group+T1" . substr($options, 3)); + html_end_links(); + print(""); + + if ($end < $count) + { + $i = $start + $PAGE_MAX; + $j = $i + $PAGE_MAX - 1; + if ($j > $count) + $j = $count; + + html_start_links(); + html_link("Show Messages $i - $j", "$PHP_SELF?s$i+g$group$options"); + html_end_links(); + } + + print("

\n"); +} + + +// +// 'show_messages()' - Show messages in the named group... +// + +function +show_messages($group, // I - Group + $group_filter, // I - Group filter + $start, // I - Start message + $search, // I - Search string + $threaded) // I - Threaded view? +{ + global $PHP_SELF, $PAGE_MAX, $_COOKIE, $options; + + + // Figure out which messages to show... + $error = ""; + + $stream = nntp_connect(); + $matches = nntp_search($stream, $group, $search, $threaded); + + nntp_close($stream); + + if (!$matches) + { + $count = 0; + + if ($search == "") + $error = "No messages in group."; + else + $error = "No matches found for '" . + htmlspecialchars($search, ENT_QUOTES) . "'..."; + } + else + $count = count($matches); + + if ($start == 0) + { + if ($search == "") + { + $cookie = str_replace(".", "_", $group); + + if (array_key_exists($cookie, $_COOKIE)) + { + $msgnum = (int)$_COOKIE[$cookie]; + + for ($i = 0; $i < $count; $i ++) + { + $fields = explode("\t", $matches[$i]); + if ((int)$fields[0] == $msgnum) + break; + } + + $start = $i + 1; + } + else + $start = $count - $PAGE_MAX + 1; + } + else + $start = 1; + } + + if ($start > ($count - $PAGE_MAX + 1)) + $start = $count - $PAGE_MAX + 1; + if ($start < 1) + $start = 1; + + $end = $start + $PAGE_MAX - 1; + if ($end > $count) + $end = $count; + + // Show the standard header... + nntp_header("$group ($start - $end of $count)", + array("All Forums" => "forums.php?g$options")); + + $temp = htmlspecialchars($search, ENT_QUOTES); + print("
\n" + ."

Search Words:

\n" + ."
\n"); + + if ($error != "") + print("

$error

\n"); + else + { + show_prevnext_page($group, $group_filter, $start, $end, $count, $threaded); + + html_start_table(array("Subject", "Author", "Date/Time")); + + for ($i = $start; $i <= $end; $i ++) + { + $fields = explode("\t", $matches[$i - 1]); + $subject = htmlspecialchars(eregi_replace("\\[[a-z]+\\.[a-z]+\\] ", "", + $fields[1]), ENT_QUOTES); + $author = sanitize_email($fields[2]); + $date = format_date($fields[3]); + + if ($subject == "") + $subject = "(No Subject)"; + + html_start_row(); + print("" + ."$subject" + ."  $author  " + ."$date"); + html_end_row(); + } + + html_end_table(); + + show_prevnext_page($group, $group_filter, $start, $end, $count, $threaded); + } + + html_footer(); +} + + +// +// 'show_groups()' - Show groups... +// + +function +show_groups($group_filter, // I - Group filter + $search) // I - Search string +{ + global $PHP_SELF, $_COOKIE, $options; + + + nntp_header("Forums", + array("All Forums" => "forums.php?g$options")); + + // Figure out which messages to show... + $stream = nntp_connect(); + + // Search stuff... + print("
\n" + ."

Search Words:

\n" + ."
\n"); + + // Show the standard header... + html_start_table(array("Forum", "Messages", "")); + + $status = nntp_command($stream, "LIST", 215); + $num_groups = 0; + $groups = array(); + + if ((int)$status == 215) + { + while ($line = fgets($stream, 1024)) + { + $line = rtrim($line); + if ($line == ".") + break; + + $fields = explode(" ", $line); + $groups[$num_groups] = $fields[0]; + $num_groups ++; + } + } + + sort($groups); + + while (list($key, $group) = each($groups)) + { + if (ereg("(linuxprinting|private)\\..*", $group)) + continue; + + if ($group_filter && !ereg("${group_filter}\\.*", $group)) + continue; + + $status = nntp_command($stream, "GROUP $group", 211); + if ((int)$status != 211) + continue; + + $fields = explode(" ", $status); + $total = (int)$fields[1]; + + if ($search != "") + { + $matches = nntp_search($stream, $group, $search); + $mcount = count($matches); + $count = "$total total, $mcount match"; + } + else + { + $cookie = str_replace(".", "_", $group); + + if (array_key_exists($cookie, $_COOKIE)) + { + $newcount = (int)$fields[3] - (int)$_COOKIE[$cookie]; + + $count = "$total total, $newcount unread"; + } + else + $count = "$total total"; + } + + html_start_row(); + print("$group" + ."$count"); + + if ($search != "") + print("/$total"); + + print(""); + html_start_links(); + html_link("View", "$PHP_SELF?g$group$options"); + if (!ereg(".*\.announce", $group) && !ereg(".*\.commit", $group)) + html_link("New Message", "$PHP_SELF?g$group+n$options"); + html_end_links(); + print(""); + html_end_row(); + } + + html_start_row("header"); + print("Forums and Mailing Lists"); + html_end_row(); + html_start_row(); + print("" + ."

Point your news reader at " + ."news.easysw.com to view these forums directly.

\n" + ."

Go to " + ."http://lists.easysw.com/mailman/listinfo " + ."to subscribe to or unsubcribe from the mailing lists that mirror " + ."these forums.

" + .""); + html_end_row(); + html_end_table(); + + nntp_close($stream); + + html_footer(); +} + + +// +// 'show_prevnext_msg()' - Show the prev/next links for the messages list... +// + +function +show_prevnext_msg($group, // I - Group + $group_filter, // I - Group filter + $start, // I - Start message + $count, // I - Number of messages + $msg, // I - Current message + $threaded) // I - Thread messages? +{ + global $PHP_SELF, $options; + + + print("

\n" + ."\n" + ."
"); + + if ($msg > 1) + { + $i = $msg - 1; + + html_start_links(); + html_link("Previous Message", "$PHP_SELF?s$start+g$group+v$i$options"); + html_end_links(); + } + + print(""); + if (!ereg(".*\.announce", $group) && !ereg(".*\.commit", $group)) + { + html_start_links(); + html_link("New Message", "$PHP_SELF?s$start+g$group+n$options"); + html_link("Reply", "$PHP_SELF?s$start+g$group+r$msg$options"); + html_end_links(); + } + + print(""); + + if ($msg < $count) + { + $i = $msg + 1; + html_start_links(); + html_link("Next Message", "$PHP_SELF?s$start+g$group+v$i$options"); + html_end_links(); + } + + print("

\n"); +} + + +// +// 'show_message()' - Show a single message... +// + +function +show_message($group, // I - Group + $group_filter, // I - Group filter + $start, // I - Start message + $msg, // I - Current message + $search, // I - Search string + $threaded) // I - Thread messages? +{ + global $PHP_SELF, $_COOKIE, $options; + + +// print("\n"); + + // Figure out which messages to show... + $stream = nntp_connect(); + $matches = nntp_search($stream, $group, $search, $threaded); + $count = count($matches); + + if ($msg[0] == ':') + { + // Lookup a specific message ID... + $msg = (int)substr($msg, 1); + + for ($i = 0; $i < $count; $i ++) + { + $fields = explode("\t", $matches[$i]); + + if ($msg == $fields[0]) + break; + } + + if ($i >= $count) + { + nntp_error("We were unable to show the requested message for the following " + ."reason:", "The message number ($msg) is out of range.", $group); + nntp_close($stream); + return; + } + + $msg = $i; + } + else + { + // Lookup index into search... + if ($msg < 1 || $msg > $count) + { + nntp_error("We were unable to show the requested message for the following " + ."reason:", "The message number is out of range.", $group); + nntp_close($stream); + return; + } + + $fields = explode("\t", $matches[$msg - 1]); + } + +// print("\n"); + + $msgnum = (int)$fields[0]; + $subject = htmlspecialchars(eregi_replace("\\[[a-z]+\\.[a-z]+\\] ", "", + $fields[1]), ENT_QUOTES); + $author = sanitize_email($fields[2]); + $date = format_date($fields[3]); + + if ($subject == "") + $subject = "(No Subject)"; + + // Save last message read... + $cookie = str_replace(".", "_", $group); + if ($search == "" && + (!array_key_exists($group, $_COOKIE) || (int)$_COOKIE[$cookie] < $msgnum)) + setcookie($cookie, $msgnum, time() + 90 * 86400, "/"); + + $status = nntp_command($stream, "BODY $msgnum", 222); + if ((int)$status != 222) + { + nntp_close($stream); + nntp_error("We were unable to show the requested message for the following " + ."reason:", $status, $group); + return (NULL); + } + + $body = ""; + while ($line = fgets($stream, 1024)) + { + $line = rtrim($line); + + if ($line == ".") + break; + + $body = $body . $line . "\n"; + } + + nntp_close($stream); + + $body = quote_text($body); + + nntp_header("$subject", + array("All Forums" => "forums.php?g$options", + "Back to $group" => "forums.php?g$group+s$start$options")); + + show_prevnext_msg($group, $group_filter, $start, $count, $msg, $threaded); + + html_start_table(array($subject, $author, $date), "", "", TRUE); + html_start_row(); + print("$body
\n" + ."[ Direct Link" + ." to Message ]"); + html_end_row(); + html_end_table(); + + show_prevnext_msg($group, $group_filter, $start, $count, $msg, $threaded); + + html_footer(); +} + + +// +// 'post_message()' - Post a message... +// + +function +post_message($group, // I - Group + $group_filter, // I - Group filter + $start, // I - Start message + $msg, // I - Current message + $search, // I - Search string + $threaded) // I - Thread messages? +{ + global $LOGIN_USER, $PHP_SELF, $PROJECT_URL, $_POST, $options; + + + // Get form data... + if (array_key_exists("FROM", $_POST)) + $from = $_POST["FROM"]; + else + $from = ""; + + if (array_key_exists("SUBJECT", $_POST)) + $subject = $_POST["SUBJECT"]; + else + $subject = ""; + + if (array_key_exists("BODY", $_POST)) + $body = $_POST["BODY"]; + else + $body = ""; + + // Validate form data... + if (!validate_email($from) || $subject == "" || $body == "") + { + new_message($group, $group_filter, $start, $from, $subject, $body); + return; + } + + // Connect to the news server and get the reply-to message ID... + $stream = nntp_connect(); + if (!$stream) + { + return; + } + + $id = ""; + + if ($msg > 0) + { + $matches = nntp_search($stream, $group, $search, $threaded); + $count = count($matches); + + if ($msg <= $count) + { + $fields = explode("\t", $matches[$msg - 1]); + $id = $fields[4]; + } + } + + // Create the message body... + $message = "From: $from\r\n" + ."Subject: $subject\r\n" + ."Newsgroups: $group\r\n"; + + if ($id != "") + $message .= "In-Reply-To: $id\r\n"; + + $message .= "X-Login-Name: $LOGIN_USER\r\n" + ."X-Site-URL: $PROJECT_URL\r\n" + ."\r\n"; + + $lines = explode("\n", $body); + $count = count($lines); + + for ($i = 0; $i < $count; $i ++) + { + $line = rtrim($lines[$i]); + + if ($line == ".") + $message .= ". \r\n"; + else + $message .= "$line\r\n"; + } + + // Run the message by spamc to see if it thinks the message is + // spam... + $p = popen("spamc -c >/dev/null", "w"); + if ($p) + { + fwrite($p, $message); + if (pclose($p)) + { + // Message is spam... + nntp_header("$group Error", + array("All Forums" => "forums.php?g$options", + "Back to $group" => "forums.php?g$group+s$start$options")); + + print("

Your message could not be posted for the following reason:

\n" + ."
The anti-spam filters determined that your message " + ."is most likely an unsolicited commercial message that is not " + ."allowed on this group. If this is not the case, please press your " + ."browser's Back button and check that the message does " + ."not contain common spam phrases like 'an offer for you' and so " + ."forth.
\n"); + + html_footer(); + return; + } + } + + // Post the message... + $status = nntp_command($stream, "POST", 340); + + if ((int)$status != 340) + { + nntp_close($stream); + nntp_error("We were unable to post the requested message for the following " + ."reason:", $status, $group); + return; + } + + fwrite($stream, $message); + + // Get the posting status... + $status = nntp_command($stream, ".", 240); + + if ((int)$status == 240) + { + if ($msg == 0) + header("Location: $PHP_SELF?s$start+g$group$options"); + else + header("Location: $PHP_SELF?s$start+g$group+v$msg$options"); + } + else + nntp_error("We were unable to post the requested message for the following " + ."reason:", $status, $group); + + nntp_close($stream); +} + + +// +// 'reply_message()' - Reply to a message... +// + +function +reply_message($group, // I - Group to reply to + $group_filter, // I - Group filter + $start, // I - First message in the display + $msg, // I - Message to reply to + $search, // I - Search string + $threaded, // I - Thread messages? + $sender) // I - Sender address +{ + // Figure out which messages to show... + $stream = nntp_connect(); + $matches = nntp_search($stream, $group, $search, $threaded); + $count = count($matches); + + if ($msg < 1 || $msg > $count) + { + nntp_close($stream); + return; + } + + $fields = explode("\t", $matches[$msg - 1]); + $msgnum = (int)$fields[0]; + $subject = eregi_replace("\\[[a-z]+\\.[a-z]+\\] ", "", $fields[1]); + $author = sanitize_email($fields[2]); + $date = htmlspecialchars($fields[3], ENT_QUOTES); + + if (strncasecmp($subject, "re:", 3)) + $subject = "Re: " . $subject; + + $status = nntp_command($stream, "BODY $msgnum", 222); + if ((int)$status != 222) + { + nntp_close($stream); + nntp_error("We were unable to reply to the requested message for the following " + ."reason:", $status, $group); + return; + } + + $body = ""; + while ($line = fgets($stream, 1024)) + { + $line = rtrim($line); + + if ($line == ".") + break; + + $body = $body . "> " . $line . "\n"; + } + + nntp_close($stream); + + new_message($group, $group_filter, $start, $subject, $sender, $body); +} + + +// +// 'new_message()' - Post a new message... +// + +function +new_message($group, // I - Group to post to + $group_filter, // I - Group filter + $start, // I - First message + $subject, // I - Subject of message + $sender, // I - Sender address + $body) // I - Message body +{ + global $PHP_SELF, $NNTPSPEC, $options; + + + $subject = htmlspecialchars($subject, ENT_QUOTES); + $sender = htmlspecialchars($sender, ENT_QUOTES); + $body = htmlspecialchars($body, ENT_QUOTES); + + nntp_header("Post Message to $group", + array("All Forums" => "forums.php?g$options", + "Back to $group" => "forums.php?g$group+s$start$options")); + + print("

Post Message to $group

"); + + print("
\n"); + + print("
\n"); + print("" + ."\n"); + + print("" + ."\n"); + + print("" + ."\n"); + + print("" + ."\n"); + print("
Subject:
From:
Body:
\n"); + + print("
\n"); + + html_footer(); +} + + +// Parse command-line options... +$start = 0; +$group = ""; +$op = 'l'; +$msg = ""; +$groups = "minixml"; + +if (array_key_exists("THREADED", $_COOKIE)) + $threaded = $_COOKIE["THREADED"] != 0; +else + $threaded = FALSE; + +if (array_key_exists("SEARCH", $_POST)) + $search = $_POST["SEARCH"]; +else + $search = ""; + +for ($i = 0; $i < $argc; $i ++) +{ + switch ($argv[$i][0]) + { + case 'g' : + $group = substr($argv[$i], 1); + break; + + case 'G' : + $groups = substr($argv[$i], 1); + break; + + case 'n' : + case 'p' : + case 'r' : + $op = $argv[$i][0]; + $msg = (int)substr($argv[$i], 1); + break; + + case 'v' : + $op = $argv[$i][0]; + $msg = substr($argv[$i], 1); + break; + + case 's' : + $start = (int)substr($argv[$i], 1); + break; + + case 'T' : // Set threading + $threaded = (int)substr($argv[$i], 1); + break; + + case 'Q' : // Set search text + $search = urldecode(substr($argv[$i], 1)); + $i ++; + while ($i < $argc) + { + $search .= urldecode(" $argv[$i]"); + $i ++; + } + break; + } +} + +setcookie("THREADED", $threaded, time() + 90 * 86400, "/"); + +if ($search != "") + $options = "+T$threaded+Q" . urlencode($search); +else + $options = "+T$threaded"; + +// Now handle the request... +switch ($op) +{ + case 'l' : // List + if ($group) + show_messages($group, $groups, $start, $search, $threaded); + else + show_groups($groups, $search); + break; + + case 'n' : // New message + if ($LOGIN_USER == "") + { + $options = str_replace("+", "%2B", "+g" . urlencode($group) . $options); + header("Location: login.php?PAGE=$PHP_SELF?n$options"); + return; + } + + new_message($group, $groups, $start, "", $from, ""); + break; + + case 'p' : // Post message + if ($LOGIN_USER == "") + { + $options = str_replace("+", "%2B", "+g" . urlencode($group) . $options); + header("Location: login.php?PAGE=$PHP_SELF?l$options"); + return; + } + + if (ereg(".*\.announce", $group) || ereg(".*\.commit", $group)) + { + nntp_header("Forum Posting Error", + array("All Forums" => "forums.php?g$options", + "Back to $group" => "forums.php?g$group+s$start$options")); + + print("

We are sorry, but we could not post your message for the " + ."following reason:\n" + ."

Forum $group is read-only.
\n"); + + html_footer(); + + } + else + post_message($group, $groups, $start, $msg, $search, $threaded); + break; + + case 'r' : // Reply message + if ($LOGIN_USER == "") + { + $options = str_replace("+", "%2B", "+g" . urlencode($group) . $options); + header("Location: login.php?PAGE=$PHP_SELF?r$msg$options"); + return; + } + + reply_message($group, $groups, $start, $msg, $search, $threaded, + $from); + break; + + case 'v' : // View message + show_message($group, $groups, $start, $msg, $search, $threaded); + break; +} + + +// +// End of "$Id$". +// +?> diff --git a/www/phplib/html.php b/www/phplib/html.php index 7c65474..ae762d9 100644 --- a/www/phplib/html.php +++ b/www/phplib/html.php @@ -142,7 +142,7 @@ html_header($title = "", // I - Additional document title ."title='Search'>"; } - $classes = array("unsel", "unsel", "unsel", "unsel", "unsel"); + $classes = array("unsel", "unsel", "unsel", "unsel", "unsel", "unsel"); if (strpos($PHP_SELF, "/account.php") !== FALSE || strpos($PHP_SELF, "/login.php") !== FALSE) $classes[0] = "sel"; @@ -152,6 +152,8 @@ html_header($title = "", // I - Additional document title $classes[3] = "sel"; else if (strpos($PHP_SELF, "/software.php") !== FALSE) $classes[4] = "sel"; + else if (strpos($PHP_SELF, "/forums.php") !== FALSE) + $classes[5] = "sel"; else $classes[1] = "sel"; @@ -172,11 +174,12 @@ html_header($title = "", // I - Additional document title ."Bugs & Features" ."Documentation" ."Download" + ."Forums" ."" ."
" ."$search
" ."\n" - .""); + .""); } @@ -188,8 +191,8 @@ function html_footer() { print("\n" - ."" - ."Copyright 2003-2007 by Michael Sweet. This library is free " + ."" + ."Copyright 2003-2008 by Michael Sweet. This library is free " ."software; you can redistribute it and/or modify it " ."under the terms of the GNU Library General Public " ."License as published by the Free Software Foundation; "