HTTP Gateway * Download: https://news.novabbs.com/getrslight * * Based on Newsportal by Florian Amrhein * * E-Mail: retroguy@novabbs.com * Web: https://news.novabbs.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @session_start(); /* * Encode lines with 8bit-characters to quote-printable * * $line: the to be encoded line * * the function returns a sting containing the quoted-printable encoded * $line */ function encode_subject($line) { $newstring = mb_encode_mimeheader(quoted_printable_decode($line)); return $newstring; } if (! function_exists('quoted_printable_encode')) { function quoted_printable_encode($line) { global $www_charset; $qp_table = array( '=00', '=01', '=02', '=03', '=04', '=05', '=06', '=07', '=08', '=09', '=0A', '=0B', '=0C', '=0D', '=0E', '=0F', '=10', '=11', '=12', '=13', '=14', '=15', '=16', '=17', '=18', '=19', '=1A', '=1B', '=1C', '=1D', '=1E', '=1F', '_', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=3D', '>', '=3F', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '=5F', '', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '=7F', '=80', '=81', '=82', '=83', '=84', '=85', '=86', '=87', '=88', '=89', '=8A', '=8B', '=8C', '=8D', '=8E', '=8F', '=90', '=91', '=92', '=93', '=94', '=95', '=96', '=97', '=98', '=99', '=9A', '=9B', '=9C', '=9D', '=9E', '=9F', '=A0', '=A1', '=A2', '=A3', '=A4', '=A5', '=A6', '=A7', '=A8', '=A9', '=AA', '=AB', '=AC', '=AD', '=AE', '=AF', '=B0', '=B1', '=B2', '=B3', '=B4', '=B5', '=B6', '=B7', '=B8', '=B9', '=BA', '=BB', '=BC', '=BD', '=BE', '=BF', '=C0', '=C1', '=C2', '=C3', '=C4', '=C5', '=C6', '=C7', '=C8', '=C9', '=CA', '=CB', '=CC', '=CD', '=CE', '=CF', '=D0', '=D1', '=D2', '=D3', '=D4', '=D5', '=D6', '=D7', '=D8', '=D9', '=DA', '=DB', '=DC', '=DD', '=DE', '=DF', '=E0', '=E1', '=E2', '=E3', '=E4', '=E5', '=E6', '=E7', '=E8', '=E9', '=EA', '=EB', '=EC', '=ED', '=EE', '=EF', '=F0', '=F1', '=F2', '=F3', '=F4', '=F5', '=F6', '=F7', '=F8', '=F9', '=FA', '=FB', '=FC', '=FD', '=FE', '=FF' ); // are there "forbidden" characters in the string? for ($i = 0; $i < strlen($line) && ord($line[$i]) <= 127; $i ++); if ($i < strlen($line)) { // yes, there are. So lets encode them! $from = $i; for ($to = strlen($line) - 1; ord($line[$to]) <= 127; $to --); // lets scan for the start and the end of the to be encoded _words_ for (; $from > 0 && $line[$from] != ' '; $from --); if ($from > 0) $from ++; for (; $to < strlen($line) && $line[$to] != ' '; $to ++); // split the string into the to be encoded middle and the rest $begin = substr($line, 0, $from); $middle = substr($line, $from, $to - $from); $end = substr($line, $to); // ok, now lets encode $middle... $newmiddle = ""; for ($i = 0; $i < strlen($middle); $i ++) $newmiddle .= $qp_table[ord($middle[$i])]; // now we glue the parts together... $line = $begin . '=?' . $www_charset . '?Q?' . $newmiddle . '?=' . $end; } return $line; } } /* * generate a message-id for posting. * $identity: a string containing informations about the article, to * make a md5-hash out of it. * * returns: a complete message-id */ function generate_msgid($identity) { global $CONFIG, $msgid_generate, $msgid_fqdn; switch ($msgid_generate) { case "no": // no, we don't want to generate a message-id. return false; break; case "md5": if ($CONFIG['email_tail'][0] !== '@') { $mymsgid = '@' . $CONFIG['email_tail']; } else { $mymsgid = $CONFIG['email_tail']; } return '<' . md5($identity) . $mymsgid . '>'; break; default: return false; break; } } function check_rate_limit($name, $set = 0, $gettime = 0) { global $CONFIG, $spooldir; if (strcasecmp($name, $CONFIG['anonusername']) == 0) { $name = session_id(); } $ratefile = $spooldir . '/' . strtolower($name) . '-rate.dat'; $postqty = 0; $first = 0; $newrate = array(); if (is_file($ratefile)) { $ratedata = ''; $ratefp = fopen($ratefile, 'r'); while (! feof($ratefp)) { $ratedata .= fgets($ratefp, 1000); } fclose($ratefp); $rate = unserialize($ratedata); sort($rate); foreach ($rate as $ratepost) { if ($ratepost > (time() - 3600)) { $postqty = $postqty + 1; $newrate[] = $ratepost; if ($first == 0) { $oldest = $ratepost; $first = 1; } } } } $newrate[] = time(); if ($set) { $ratefp = fopen($ratefile, 'w'); fputs($ratefp, serialize($newrate)); fclose($ratefp); $postqty = $postqty + 1; } $rate_limit = get_user_config($name, 'rate_limit'); if (($rate_limit !== FALSE) && ($rate_limit > 0)) { $CONFIG['rate_limit'] = $rate_limit; } $postsremaining = $CONFIG['rate_limit'] - $postqty; if ($gettime) { $wait = (3600 - (time() - $oldest)) / 60; return ($wait); } else { return ($postsremaining); } } /* * Post an article to a newsgroup * * $subject: The Subject of the article * $from: The authors name and email of the article * $newsgroups: The groups to post to * $ref: The references of the article * $body: The article itself */ function message_post($subject, $from, $newsgroups, $ref, $body, $encryptthis = null, $encryptto = null, $authname = null, $fromname, $followupto = null, $do_attach = null) { global $server, $port, $send_poster_host, $text_error, $CONFIG; global $www_charset, $config_dir, $spooldir; global $msgid_generate, $msgid_fqdn, $rslight_version; flush(); $attachment_temp_dir = $spooldir . "/tmp/"; if (! is_dir($attachment_temp_dir)) { mkdir($attachment_temp_dir); } $myconfig = false; if (file_exists($config_dir . '/userconfig/' . $authname . '.config')) { $userconfig = unserialize(file_get_contents($config_dir . '/userconfig/' . $authname . '.config')); $myconfig = true; } if (isset($encryptthis)) { $workpath = $config_dir . "users/"; $username = trim(strtolower($encryptto)); $userFilename = $workpath . $username; if ((! is_file($userFilename)) || $encryptto == $CONFIG['anonusername']) { $response = "Cannot encrypt to $encryptto. No such user"; return $response; } } $msgid = generate_msgid($subject . "," . $from . "," . $newsgroups . "," . $ref . "," . $body); /* * SPAM CHECK */ if (isset($CONFIG['spamassassin']) && ($CONFIG['spamassassin'] == true) && ($CONFIG['enable_nntp'] != true)) { $spam_result_array = check_spam($subject, $from, $newsgroups, $ref, $body, $msgid, true); $res = $spam_result_array['res']; $spamresult = $spam_result_array['spamresult']; $spamcheckerversion = $spam_result_array['spamcheckerversion']; $spamlevel = $spam_result_array['spamlevel']; } if ($do_attach) { move_uploaded_file($_FILES["photo"]["tmp_name"], $attachment_temp_dir . $_FILES["photo"]["name"]); if ($authname != null) { $uploadname = $authname; } else { $uploadname = $CONFIG['anonusername']; } if (! is_dir($spooldir . '/upload/' . $uploadname)) { mkdir($spooldir . '/upload/' . $uploadname); } // Copy attachment to user's upload directory copy($attachment_temp_dir . $_FILES["photo"]["name"], $spooldir . '/upload/' . $uploadname . '/' . $_FILES["photo"]["name"]); } $ns = nntp_open($server, $port); if ($ns != false) { fputs($ns, "POST\r\n"); $weg = line_read($ns); $t = explode(' ', $weg); if ($t[0] != "340") { nntp_close($ns); return $weg; } fputs($ns, 'Subject: ' . encode_subject($subject) . "\r\n"); // For Synchronet use if (isset($CONFIG['synchronet']) && ($CONFIG['synchronet'] == true)) { if(!isset($fromname) || trim($fromname) == '') { $fromname = 'ALL'; } fputs($ns, 'To: ' . $fromname . "\r\n"); fputs($ns, 'X-Comment-To: ' . $fromname . "\r\n"); } // X-Rslight headers if ((isset($CONFIG['spamassassin']) && ($CONFIG['spamassassin'] == true))) { if ($res === 1) { fputs($ns, $spamcheckerversion . "\r\n"); if (strpos($spamlevel, '*') !== false) fputs($ns, $spamlevel . "\r\n"); if ($res === 1) { fputs($ns, "X-Rslight-Original-Group: " . $newsgroups . "\r\n"); $newsgroups = $CONFIG['spamgroup']; } } } fputs($ns, 'From: ' . $from . "\r\n"); if ($followupto !== null) { fputs($ns, 'Followup-To: ' . $followupto . "\r\n"); } fputs($ns, 'Newsgroups: ' . $newsgroups . "\r\n"); $sitekey = password_hash($CONFIG['thissitekey'] . $msgid, PASSWORD_DEFAULT); $posting_user = hash('sha1', $from . $CONFIG['thissitekey'] . $_SERVER['HTTP_HOST']); fputs($ns, 'X-Rslight-Site: ' . $sitekey . "\r\n"); fputs($ns, 'X-Rslight-Posting-User: ' . $posting_user . "\r\n"); if (isset($encryptthis)) { fputs($ns, 'X-Rslight-To: ' . $encryptto . "\r\n"); $CONFIG['postfooter'] = ""; } fputs($ns, "Mime-Version: 1.0\r\n"); if ($do_attach == null) { fputs($ns, "Content-Type: text/plain; charset=" . $www_charset . "; format=flowed\r\n"); fputs($ns, "Content-Transfer-Encoding: 8bit\r\n"); } fputs($ns, "User-Agent: Rocksolid Light\r\n"); if ($send_poster_host) @fputs($ns, 'X-HTTP-Posting-Host: ' . gethostbyaddr(getenv("REMOTE_ADDR")) . "\r\n"); if (($ref != false) && (count($ref) > 0)) { // strip references if (strlen(implode(" ", $ref)) > 900) { $ref_first = array_shift($ref); do { $ref = array_slice($ref, 1); } while (strlen(implode(" ", $ref)) > 800); array_unshift($ref, $ref_first); } fputs($ns, 'References: ' . implode(" ", $ref) . "\r\n"); } if (isset($CONFIG['organization'])) fputs($ns, 'Organization: ' . quoted_printable_encode($CONFIG['organization']) . "\r\n"); $body = trim($body); if ($userconfig['signature'] !== '' && $myconfig) { $body .= "\n\n-- \n" . $userconfig['signature']; } else { if ((isset($CONFIG['postfooter'])) && ($CONFIG['postfooter'] != "")) { $postfooter = preg_replace('/\{DOMAIN\}/', "\n" . $_SERVER['HTTP_HOST'], $CONFIG['postfooter']); $body .= "\n\n-- \n" . $postfooter; } } if ($do_attach) { $boundary = uniqid('', true); $body .= "\r\n--------------" . $boundary . "\r\n"; } fputs($ns, 'Message-ID: ' . $msgid . "\r\n"); if ($userconfig['xface'] !== '' && $myconfig) { fputs($ns, 'X-Face: ' . $userconfig['xface'] . "\r\n"); } if ($do_attach) { fputs($ns, 'Content-Type: multipart/mixed;boundary="------------' . $boundary . '"'); fputs($ns, "\r\n"); $contenttype = shell_exec('file -b --mime-type ' . $attachment_temp_dir . $_FILES['photo']['name']); $contenttype = rtrim($contenttype); $b64file = shell_exec('uuencode -m ' . $attachment_temp_dir . $_FILES['photo']['name'] . ' ' . $_FILES['photo']['name'] . ' | grep -v \'begin-base64\|====\''); $body .= 'Content-Type: ' . $contenttype . ';'; $body .= "\r\n name=" . $_FILES['photo']['name']; $body .= "\r\nContent-Transfer-Encoding: base64"; $body .= "\r\nContent-Disposition: attachment;"; $body .= "\r\n filename=" . $_FILES['photo']['name']; $body .= "\r\n"; $body .= "\r\n" . $b64file; $body .= "\r\n--------------" . $boundary . "--\r\n"; } // Headers end here $body = str_replace("\n.\r", "\n..\r", $body); $body = str_replace("\r", '', $body); $body = stripSlashes($body); if ($do_attach) { fputs($ns, "\r\nThis is a multi-part message in MIME format.\r\n"); fputs($ns, "--------------" . $boundary . "\r\n"); fputs($ns, "Content-Type: text/plain; charset=utf-8\r\n"); fputs($ns, "Content-Transfer-Encoding: 7bit\r\n"); } // Encrypt? if (isset($encryptthis)) { $encryptkey = get_user_config($encryptto, "encryptionkey"); $body = chunk_split(rslight_encrypt($body, $encryptkey)); $body = "-- RSLIGHT DAT START\n" . $body . "-- RSLIGHT DAT END\n"; } $body = rtrim($body); fputs($ns, "\r\n" . $body . "\r\n.\r\n"); $message = line_read($ns); nntp_close($ns); if ($do_attach) { // clean up attachment file unlink($attachment_temp_dir . $_FILES["photo"]["name"]); } } else { $message = $text_error["post_failed"]; } // let thread.php ignore the cache for this group, so this new // article will be visible instantly $groupsarr = explode(",", $newsgroups); foreach ($groupsarr as $newsgroup) { $cachefile = $spooldir . '/' . $newsgroup . '-cache.txt'; @unlink($cachefile); } return $message; } ?>