[Phpbbkb-checkins] SF.net SVN: phpbbkb: [46] main/trunk
Status: Alpha
Brought to you by:
markthedaemon
|
From: <mar...@us...> - 2007-02-14 02:30:30
|
Revision: 46
http://svn.sourceforge.net/phpbbkb/?rev=46&view=rev
Author: markthedaemon
Date: 2007-02-13 18:30:25 -0800 (Tue, 13 Feb 2007)
Log Message:
-----------
I have no idea why these files aren't in here. They should be...
Added Paths:
-----------
main/trunk/kb/
main/trunk/kb/auth.php
main/trunk/kb/constants.php
main/trunk/kb/functions.php
Added: main/trunk/kb/auth.php
===================================================================
--- main/trunk/kb/auth.php (rev 0)
+++ main/trunk/kb/auth.php 2007-02-14 02:30:25 UTC (rev 46)
@@ -0,0 +1,188 @@
+<?php
+/***************************************************************************
+ * auth.php
+ * -------------------
+ *
+ * copyright: phpBB KB Group
+ * site: http://www.phpbbknowledgebase.com
+ * SF Project Page: http://www.sourceforge.net/projects/phpbbkb
+ *
+ ***************************************************************************/
+
+/***************************************************************************
+ *
+ * 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 file holds the kb auth functions, very similar to the phpBB auth functions, but differs certain places :)
+// As of now, the articles auth is handles out from which category it is selected through, therefore an article
+// can have different kinds of auth, all depending on through which category it is viewed. This solution might seem
+// stupid, but it is the best I can come up with, and I think admins will just take that into consideration when creating
+// category permissions.
+
+//
+// This function returns info on whether the user is allowed to do the supplied argument(s) all dependant on the given category id
+//
+function kb_auth($type, $cat_id, $userdata)
+{
+ switch($type)
+ {
+ case "view":
+ $sql = "a.auth_view";
+ $auth_fields = array('auth_view');
+ break;
+
+ case "add":
+ $sql = "a.auth_add";
+ $auth_fields = array('auth_add');
+ break;
+
+ case "edit":
+ $sql = "a.auth_edit";
+ $auth_fields = array('auth_edit');
+ break;
+
+ case "delete":
+ $sql = "a.auth_delete";
+ $auth_fields = array('auth_delete');
+ break;
+
+ case "mod":
+ $sql = "a.auth_mod";
+ $auth_fields = array('auth_mod');
+ break;
+
+ case "comment":
+ $sql = "a.auth_comment";
+ $auth_fields = array('auth_comment');
+ break;
+
+ case "rate":
+ $sql = "a.auth_rate";
+ $auth_fields = array('auth_rate');
+ break;
+
+ case "attach":
+ $sql = "a.auth_attach";
+ $auth_fields = array('auth_attach');
+ break;
+
+ // Returns array containing everything above
+ case "all":
+ $sql = "a.auth_view, a.auth_add, a.auth_edit, a.auth_delete, a.auth_mod, a.auth_comment, a.auth_rate, a.auth_attach";
+ $auth_fields = array('auth_view', 'auth_add', 'auth_edit', 'auth_delete', 'auth_mod', 'auth_comment', 'auth_rate', 'auth_attach');
+ break;
+
+ // Returns array containing article related auth
+ case "article":
+ $sql = "a.auth_view, a.auth_edit, a.auth_delete, a.auth_mod, a.auth_comment, a.auth_rate";
+ $auth_fields = array('auth_view', 'auth_edit', 'auth_delete', 'auth_mod', 'auth_comment', 'auth_rate');
+ break;
+
+ // Returns array containing category related auth
+ case "cat":
+ $sql = "a.auth_view, a.auth_add, a.auth_attach";
+ $auth_fields = array('auth_view', 'auth_add', 'auth_attach');
+ break;
+ }
+
+ $sql = "SELECT a.cat_id, $sql
+ FROM " . KB_CATEGORIES_TABLE . " a
+ WHERE a.cat_id = '" . $cat_id . "'";
+
+ if(!$result = $db->sql_query($sql))
+ {
+ message_die(GENERAL_MESSAGE, 'Could not retrieve categorys auth info.', '', __LINE__, __FILE__, $sql);
+ }
+
+ $f_access = $db->sql_fetchrow($result);
+
+ //
+ // If user is logged in we need to see if he is in any usergroups that changes his auth info, else just return it
+ //
+ if($userdata['session_logged_in'])
+ {
+ // Check if the user is present in a group that changes his permissions
+ $sql = "SELECT a.cat_id, $sql, a.auth_mod
+ FROM " . KB_AUTH_ACCESS_TABLE . " a, " . USER_GROUP_TABLE . " ug
+ WHERE ug.user_id = ".$userdata['user_id']. "
+ AND ug.user_pending = 0
+ AND a.group_id = ug.group_id
+ AND a.cat_id = '" . $cat_id . "'";
+ if ( !($result = $db->sql_query($sql)) )
+ {
+ message_die(GENERAL_ERROR, 'Failed obtaining category access control lists', '', __LINE__, __FILE__, $sql);
+ }
+
+ if ( $row = $db->sql_fetchrow($result) )
+ {
+ do
+ {
+ $u_access[] = $row;
+ }
+ while( $row = $db->sql_fetchrow($result) );
+ }
+ $db->sql_freeresult($result);
+ }
+
+ $is_admin = ( $userdata['user_level'] == ADMIN && $userdata['session_logged_in'] ) ? TRUE : 0;
+
+ $auth = array();
+ for($i = 0; $i < count($auth_fields); $i++)
+ {
+ $key = $auth_fields[$i];
+
+ //
+ // If the user is logged on and the forum type is either ALL or REG then the user has access
+ //
+ // If the type if ACL, MOD or ADMIN then we need to see if the user has specific permissions
+ // to do whatever it is they want to do ... to do this we pull relevant information for the
+ // user (and any groups they belong to)
+ //
+ // Now we compare the users access level against the forums. We assume here that a moderator
+ // and admin automatically have access to an ACL forum, similarly we assume admins meet an
+ // auth requirement of MOD
+ //
+ $value = $f_access[$key];
+
+ switch( $value )
+ {
+ case AUTH_ALL:
+ $auth[$key] = TRUE;
+ $auth[$key . '_type'] = $lang['Auth_Anonymous_Users'];
+ break;
+
+ case AUTH_REG:
+ $auth_user[$key] = ( $userdata['session_logged_in'] ) ? TRUE : 0;
+ $auth_user[$key . '_type'] = $lang['Auth_Registered_Users'];
+ break;
+
+ case AUTH_ACL:
+ $auth[$key] = ( $userdata['session_logged_in'] ) ? auth_check_user(AUTH_ACL, $key, $u_access, $is_admin) : 0;
+ $auth[$key . '_type'] = $lang['Auth_Users_granted_access'];
+ break;
+
+ case AUTH_MOD:
+ $auth[$key] = ( $userdata['session_logged_in'] ) ? auth_check_user(AUTH_MOD, 'auth_mod', $u_access, $is_admin) : 0;
+ $auth[$key . '_type'] = $lang['Auth_Moderators'];
+ break;
+
+ case AUTH_ADMIN:
+ $auth[$key] = $is_admin;
+ $auth[$key . '_type'] = $lang['Auth_Administrators'];
+ break;
+
+ default:
+ $auth[$key] = 0;
+ break;
+ }
+ }
+
+ return $auth;
+}
+
+?>
Added: main/trunk/kb/constants.php
===================================================================
--- main/trunk/kb/constants.php (rev 0)
+++ main/trunk/kb/constants.php 2007-02-14 02:30:25 UTC (rev 46)
@@ -0,0 +1,40 @@
+<?php
+/***************************************************************************
+ * constants.php
+ * -------------------
+ *
+ * copyright: phpBB KB Group
+ * site: http://www.phpbbknowledgebase.com
+ * SF Project Page: http://www.sourceforge.net/projects/phpbbkb
+ *
+ ***************************************************************************/
+
+/***************************************************************************
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+if (!defined('IN_PHPBB'))
+{
+ die('Hacking attempt');
+}
+
+// All constants here
+// DB Tables
+define('KB_CATEGORIES_TABLE', $table_prefix . "kb_categories");
+define('KB_ARTICLES_TABLE', $table_prefix . "kb_articles");
+define('KB_ARTICLECATS_TABLE', $table_prefix . "kb_articlecats"); // For Multiple cats
+define('KB_AUTH_ACCESS', $table_prefix . "kb_auth_access");
+
+// Article Status
+define('KB_STATUS_NOT_ASSIGNED', 0);
+define('KB_STATUS_ASSIGNED', 1);
+define('KB_STATUS_REVIEW_IN_PROGRESS', 3);
+define('KB_STATUS_ACCEPTED', 4);
+define('KB_STATUS_REJECTED', 5);
+
+?>
\ No newline at end of file
Added: main/trunk/kb/functions.php
===================================================================
--- main/trunk/kb/functions.php (rev 0)
+++ main/trunk/kb/functions.php 2007-02-14 02:30:25 UTC (rev 46)
@@ -0,0 +1,966 @@
+<?php
+/***************************************************************************
+ * functions.php
+ * -------------------
+ *
+ * copyright: phpBB KB Group
+ * site: http://www.phpbbknowledgebase.com
+ * SF Project Page: http://www.sourceforge.net/projects/phpbbkb
+ *
+ ***************************************************************************/
+
+/***************************************************************************
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+if (!defined('IN_PHPBB'))
+{
+ die('Hacking attempt');
+}
+
+// This function creates the navigation line based on a few parameters
+function create_navigation($type = "main", $id_ary = array())
+{
+ global $db, $template, $lang, $board_config, $phpEx;
+
+ switch($type)
+ {
+ case "ucp":
+ // Different kind of subcategories
+ switch($id_ary)
+ {
+ case "post_article":
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx . '?pid=ucp&action=post_article') . '">' . $lang['kb_ucp_articlepost'] .'</a></span>';
+ break;
+
+ case "edit_article":
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx . '?pid=ucp&action=edit_article') . '">' . $lang['kb_ucp_articleedit'] .'</a></span>';
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case "viewcat":
+ // View category
+ // id = $cat_id::$cat_name
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_cat&id='. $id_ary[0]) . '">' . $id_ary[1] .'</a></span>';
+ break;
+
+ case "viewsubcat":
+ // View subcategory
+ // id = $cat_id::$cat_name::$maincat_id
+ $sql = "SELECT cat_title
+ FROM " . KB_CATEGORIES_TABLE . "
+ WHERE cat_id = '" . $id_ary[2] . "'";
+ if( !($result = $db->sql_query($sql)) )
+ {
+ message_die(GENERAL_ERROR, 'Could not query cat name.', '', __LINE__, __FILE__, $sql);
+ }
+ $maincat = $db->sql_fetchrow($result);
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_cat&id=' . $id_ary[2]) . '">' . $maincat['cat_title'] .'</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_cat&id=' . $id_ary[0]) . '">' . $id_ary[1] .'</a></span>';
+ break;
+
+ case "viewarticle":
+ // Viewing an article
+ if($id_ary[2] == 0)
+ {
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_cat&id=' . $id_ary[0]) . '">' . $id_ary[1] .'</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_article&id=' . $id_ary[3]) . '&cid=' . $id_ary[0] . '">' . $id_ary[4] .'</a></span>';
+ }
+ else
+ {
+ $sql = "SELECT cat_title
+ FROM " . KB_CATEGORIES_TABLE . "
+ WHERE cat_id = '" . $id_ary[2] . "'";
+ if( !($result = $db->sql_query($sql)) )
+ {
+ message_die(GENERAL_ERROR, 'Could not query cat name.', '', __LINE__, __FILE__, $sql);
+ }
+ $maincat = $db->sql_fetchrow($result);
+
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_cat&id=' . $id_ary[2]) . '">' . $maincat['cat_title'] .'</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_cat&id=' . $id_ary[0]) . '">' . $id_ary[1] .'</a> -> <a class="nav" href="' . append_sid('kb.' . $phpEx.'?pid=view_article&id=' . $id_ary[3]) . '&cid=' . $id_ary[0] . '">' . $id_ary[4] .'</a></span>';
+ }
+ break;
+
+ case "search":
+ // viewing search results or page
+ break;
+
+ case "main":
+ default:
+ $navigation = '<span class="nav"> <a href="' . append_sid('kb.' . $phpEx) . '" class="nav">' . $lang['kb_main'] . '</a></span>';
+ break;
+ }
+
+ $template->assign_vars(array(
+ 'NAVIGATION' => $navigation)
+ );
+
+ return;
+}
+
+function get_cats_structure()
+{
+ global $db;
+
+ $cats = array();
+ $sql = "SELECT *
+ FROM " . KB_CATEGORIES_TABLE . "
+ WHERE cat_main = '0'
+ ORDER BY cat_order ASC";
+ if( !($result = $db->sql_query($sql)) )
+ {
+ message_die(GENERAL_ERROR, 'Could not query cats.', '', __LINE__, __FILE__, $sql);
+ }
+
+ $i = 0;
+ while($row = $db->sql_fetchrow($result))
+ {
+ $cats[$i] = $row;
+
+ $sql = "SELECT *
+ FROM " . KB_CATEGORIES_TABLE . "
+ WHERE cat_main = '" . $row['cat_id'] . "'
+ ORDER BY cat_order ASC";
+ if( !($subcat_result = $db->sql_query($sql)) )
+ {
+ message_die(GENERAL_ERROR, 'Could not query subcats.', '', __LINE__, __FILE__, $sql);
+ }
+
+ $cats[$i]['subcats'] = array();
+ while($row2 = $db->sql_fetchrow($subcat_result))
+ {
+ $cats[$i]['subcats'][] = $row2;
+ }
+ $i++;
+ }
+
+ return $cats;
+}
+
+function get_kb_config()
+{
+ // Using normal db table with kb_prefix
+ global $db;
+
+ $sql = "SELECT *
+ FROM " . CONFIG_TABLE;
+ if(!$result = $db->sql_query($sql))
+ {
+ message_die(CRITICAL_ERROR, "Could not query config information in admin_board", "", __LINE__, __FILE__, $sql);
+ }
+
+ $config = array();
+ while($row = $db->fetchrow($result))
+ {
+ // Detect if it has a kb_ in it and strip it
+ if(strstr('kb_', $row['config_name']))
+ {
+ $name = str_replace("kb_", "", $row['config_name']);
+ $config[$name] = $row['config_value'];
+ }
+ }
+
+ return $config;
+}
+
+////////////////////////////////////////
+/// UCP FUNCTIONS ///
+////////////////////////////////////////
+function ucp_generate_page_title($action)
+{
+ global $lang;
+
+ $title = $lang['kb_ucp'];
+ switch($action)
+ {
+ case "articles":
+ break;
+
+ case "comments":
+ break;
+
+ case "post_article":
+ $title .= ": " . $lang['kb_ucp_articlepost'];
+ break;
+
+ case "edit_article":
+ $title .= ": " . $lang['kb_ucp_articleedit'];
+ break;
+
+ case "delete_article":
+ $title .= ": " . $lang['kb_ucp_articledelete'];
+ break;
+
+ case "post_comment": // Only input
+ break;
+
+ case "edit_comment":
+ break;
+
+ case "delete_comment":
+ break;
+
+ default:
+ break;
+ }
+
+ return $title;
+}
+
+// This is for posting articles, mostly cut out of the posting.php :)
+function ucp_article_form($mode, $id, $preview)
+{
+ global $template, $board_config, $db, $userdata, $lang, $phpbb_root_path, $phpEx, $HTTP_POST_VARS;
+
+ $error_msg = '';
+ $user_sig = $userdata['user_sig'];
+
+ // Simple auth for Alpha 1
+ if(!$userdata['session_logged_in'])
+ {
+ message_die(GENERAL_MESSAGE, 'Not authenticated!');
+ }
+
+ if(!empty($HTTP_POST_VARS['post']))
+ {
+ if($mode == 'edit')
+ {
+ // Let's get the old article data
+ $article_id = isset($HTTP_POST_VARS['id']) ? $HTTP_POST_VARS['id'] : false;
+ if(!$article_id)
+ {
+ message_die(MESSAGE_DIE, 'No article id defined.');
+ }
+
+ $sql = "SELECT *
+ FROM " . KB_ARTICLES_TABLE . "
+ WHERE article_id = '$article_id'";
+ if (!$result = $db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Error while retrieving old article data.', '', __LINE__, __FILE__, $sql);
+ }
+
+ $article = $db->sql_fetchrow($result);
+
+ // if user editing set status = 0, else set status = old status :)
+ if($userdata['user_id'] == $article['article_author'])
+ {
+ $article_status = "0";
+ }
+ else
+ {
+ $article_status = $article['article_status'];
+ }
+
+ // Simple Auth for alpha 1
+ if(($userdata['user_level'] != ADMIN) && ($userdata['user_id'] != $article['article_author']))
+ {
+ message_die(GENERAL_MESSAGE, $lang['kb_edit_noauth']);
+ }
+ }
+
+ // Add the new article
+ // Make all the variables :)
+ if ( !$board_config['allow_html'] )
+ {
+ $html_on = 0;
+ }
+ else
+ {
+ $html_on = ( !empty($HTTP_POST_VARS['disable_html']) ) ? 0 : 1;
+ }
+
+ if ( !$board_config['allow_bbcode'] )
+ {
+ $bbcode_on = 0;
+ }
+ else
+ {
+ $bbcode_on = ( !empty($HTTP_POST_VARS['disable_bbcode']) ) ? 0 : 1;
+ }
+
+ if ( !$board_config['allow_smilies'] )
+ {
+ $smilies_on = 0;
+ }
+ else
+ {
+ $smilies_on = ( !empty($HTTP_POST_VARS['disable_smilies']) ) ? 0 : 1;
+ }
+
+ $article_desc = ( !empty($HTTP_POST_VARS['desc']) ) ? trim($HTTP_POST_VARS['desc']) : '';
+ $article_title = ( !empty($HTTP_POST_VARS['title']) ) ? trim($HTTP_POST_VARS['title']) : '';
+ $message = ( !empty($HTTP_POST_VARS['message']) ) ? $HTTP_POST_VARS['message'] : '';
+ $article_author = ($mode == 'edit') ? $article['article_author'] : $userdata['user_id'];
+ $article_authorname = ( $mode == 'edit' ) ? ( ( empty($HTTP_POST_VARS['authorname']) ) ? $article['article_authorname'] : $HTTP_POST_VARS['authorname'] ) : ( ( empty($HTTP_POST_VARS['authorname']) ) ? $userdata['username'] : $HTTP_POST_VARS['authorname'] );
+ $bbcode_uid = '';
+ $cat_id = $HTTP_POST_VARS['cats'];
+ $attach_sig = ( !empty($HTTP_POST_VARS['attach_sig']) ) ? 1 : 0;
+
+ prepare_article($bbcode_on, $html_on, $smilies_on, $error_msg, $bbcode_uid, $article_title, $article_desc, $message, $cat_id);
+
+ if ( $error_msg == '' )
+ {
+ $current_time = time();
+
+ if($mode == 'post')
+ {
+ $sql = "INSERT INTO " . KB_ARTICLES_TABLE . " (article_id, article_title, article_desc, article_author, article_authorname, article_time, article_edittime, article_hits, article_editby, article_status, bbcode_uid, enable_sig, enable_html, enable_bbcode, enable_smilies, article_text) VALUES
+ ('', '$article_title', '$article_desc', '$article_author', '$article_authorname', '$current_time', '$current_time', '0', '" . $userdata['user_id'] . "', '0', '$bbcode_uid', '$attach_sig', '$html_on', '$bbcode_on', '$smilies_on', '$message');";
+ if (!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Error in adding article', '', __LINE__, __FILE__, $sql);
+ }
+
+ $article_id = $db->sql_nextid();
+ // Now make the categories
+ foreach($cat_id as $i => $cat)
+ {
+ $sql = "INSERT INTO " . KB_ARTICLECATS_TABLE . " VALUES ('$article_id', '$cat');\n";
+ $sql2 = "UPDATE " . KB_CATEGORIES_TABLE . " SET cat_articles = cat_articles + 1 WHERE cat_id = '$cat';\n";
+
+ if (!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Error in adding articles categories.', '', __LINE__, __FILE__, $sql);
+ }
+
+ if (!$db->sql_query($sql2))
+ {
+ message_die(GENERAL_ERROR, 'Error in adding updating categories articles count.', '', __LINE__, __FILE__, $sql);
+ }
+ }
+
+ $meta = '<meta http-equiv="refresh" content="3;url=' . append_sid('kb.' . $phpEx . '?pid=view_article&id=' . $article_id) . '>"';
+ $return_message = $lang['kb_added'] . '<br /><br />' . sprintf($lang['kb_click_view_article'], '<a href="' . append_sid('kb.' . $phpEx . '?pid=view_article&id=' . $article_id) . '">', '</a>') . '<br /><br />' . sprintf($lang['kb_click_return_ucp'], '<a href="' . append_sid('kb.' . $phpEx . '?pid=ucp') . '">', '</a>');
+ }
+ else
+ {
+ $article_id = isset($HTTP_POST_VARS['id']) ? $HTTP_POST_VARS['id'] : false;
+ if(!$article_id)
+ {
+ message_die(GENERAL_ERROR, 'No article to edit.');
+ }
+
+ // First update the article table
+ $sql = "UPDATE " . KB_ARTICLES_TABLE . "
+ SET article_title = '$article_title',
+ article_desc = '$article_desc',
+ article_author = '$article_author',
+ article_authorname = '$article_authorname',
+ article_edittime = '$current_time',
+ article_editby = '" . $userdata['user_id'] . "',
+ article_status = '$article_status',
+ enable_sig = '$attach_sig',
+ enable_html = '$html_on',
+ enable_bbcode = '$bbcode_on',
+ enable_smilies = '$smilies_on',
+ article_text = '$message'
+ WHERE article_id = '$article_id'";
+
+ if (!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Error in editing article', '', __LINE__, __FILE__, $sql);
+ }
+
+ // Now delete all articlecats
+ $sql = "DELETE FROM " . KB_ARTICLECATS_TABLE . " WHERE article_id = '$article_id'";
+
+ if (!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Error in deleting articlecat entries.', '', __LINE__, __FILE__, $sql);
+ }
+
+ // Last add them again doing the loop
+ foreach($cat_id as $i => $cat)
+ {
+ $sql = "INSERT INTO " . KB_ARTICLECATS_TABLE . " VALUES ('$article_id', '$cat');\n";
+ $sql2 = "UPDATE " . KB_CATEGORIES_TABLE . " SET cat_articles = cat_articles + 1 WHERE cat_id = '$cat';\n";
+
+ if (!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Error in adding articles categories.', '', __LINE__, __FILE__, $sql);
+ }
+
+ if (!$db->sql_query($sql2))
+ {
+ message_die(GENERAL_ERROR, 'Error in adding updating categories articles count.', '', __LINE__, __FILE__, $sql);
+ }
+ }
+
+ // Message here somewhere
+ $meta = '<meta http-equiv="refresh" content="3;url=' . append_sid('kb.' . $phpEx . '?pid=view_article&id=' . $article_id) . '>"';
+ $return_message = $lang['kb_edited'] . '<br /><br />' . sprintf($lang['kb_click_view_article'], '<a href="' . append_sid('kb.' . $phpEx . '?pid=view_article&id=' . $article_id) . '">', '</a>') . '<br /><br />' . sprintf($lang['kb_click_return_ucp'], '<a href="' . append_sid('kb.' . $phpEx . '?pid=ucp') . '">', '</a>');
+ }
+
+ $template->assign_vars(array(
+ 'META' => $meta)
+ );
+
+ message_die(GENERAL_MESSAGE, $return_message);
+ }
+ }
+
+ if($mode == "post" && !$preview && $error_msg == '')
+ {
+ $article_title = '';
+ $article_text = '';
+ $article_desc = '';
+ $authorname = $userdata['username'];
+ $form_action = append_sid('kb.' . $phpEx . '?pid=ucp&action=post_article');
+ $hidden_form_fields = "";
+ $attach_sig = ( $userdata['user_id'] == ANONYMOUS ) ? 0 : $userdata['user_attachsig'];
+
+ if ( !$board_config['allow_html'] )
+ {
+ $html_on = 0;
+ }
+ else
+ {
+ $html_on = ( ( $userdata['user_id'] == ANONYMOUS ) ? $board_config['allow_html'] : $userdata['user_allowhtml'] );
+ }
+
+ if ( !$board_config['allow_bbcode'] )
+ {
+ $bbcode_on = 0;
+ }
+ else
+ {
+ $bbcode_on = ( ( $userdata['user_id'] == ANONYMOUS ) ? $board_config['allow_bbcode'] : $userdata['user_allowbbcode'] );
+ }
+
+ if ( !$board_config['allow_smilies'] )
+ {
+ $smilies_on = 0;
+ }
+ else
+ {
+ $smilies_on = ( ( $userdata['user_id'] == ANONYMOUS ) ? $board_config['allow_smilies'] : $userdata['user_allowsmile'] );
+ }
+ }
+ elseif($preview || $error_msg != '')
+ {
+ $article_id = $HTTP_POST_VARS['id'];
+ $article_title = $HTTP_POST_VARS['title'];
+ $article_text = $HTTP_POST_VARS['message'];
+ $article_desc = $HTTP_POST_VARS['desc'];
+ $article_cats = $HTTP_POST_VARS['cats'];
+ $authorname = $HTTP_POST_VARS['authorname'];
+
+ $attach_sig = ( $HTTP_POST_VARS['enable_sig'] ) ? TRUE : 0;
+
+ $html_on = ( $HTTP_POST_VARS['disable_html'] ) ? false : true;
+ $bbcode_on = ( $HTTP_POST_VARS['disable_bbcode'] ) ? false : true;
+ $smilies_on = ( $HTTP_POST_VARS['disable_smilies'] ) ? false : true;
+
+ if($mode == 'edit')
+ {
+ $form_action = append_sid("kb.php?pid=ucp&action=edit_article");
+ $hidden_form_fields = '<input type="hidden" name="id" value="' . $article_id . '" />';
+ }
+ else
+ {
+ $hidden_form_fields = "";
+ $form_action = append_sid("kb.php?pid=ucp&action=post_article");
+ }
+
+ if($error_msg != "")
+ {
+ $template->set_filenames(array(
+ 'reg_header' => 'error_body.tpl')
+ );
+ $template->assign_vars(array(
+ 'ERROR_MESSAGE' => $error_msg)
+ );
+ $template->assign_var_from_handle('ERROR_BOX', 'reg_header');
+ }
+
+ if($preview)
+ {
+ // Create the preview box
+ $preview_article_desc = ( !empty($HTTP_POST_VARS['desc']) ) ? trim($HTTP_POST_VARS['desc']) : '';
+ $preview_article_title = ( !empty($HTTP_POST_VARS['title']) ) ? trim($HTTP_POST_VARS['title']) : '';
+ $preview_message = ( !empty($HTTP_POST_VARS['message']) ) ? $HTTP_POST_VARS['message'] : '';
+ $bbcode_uid = ( $bbcode_on ) ? make_bbcode_uid() : '';
+
+ $preview_message = stripslashes(prepare_article_text(addslashes(unprepare_article_text(trim($preview_message))), $html_on, $bbcode_on, $smilies_on, $bbcode_uid));
+
+ // A lot of copy/paste from viewtopic.php, then shaped for this file ofc :)
+ //
+ // If the board has HTML off but the post has HTML
+ // on then we process it, else leave it alone
+ //
+ if ( !$html_on )
+ {
+ $preview_message = preg_replace('#(<)([\/]?.*?)(>)#is', "<\\2>", $preview_message);
+ }
+
+ //
+ // Parse message and/or sig for BBCode if reqd
+ //
+ if ($bbcode_uid != '')
+ {
+ $preview_message = ($bbcode_on) ? bbencode_second_pass($preview_message, $bbcode_uid) : preg_replace("/\:$bbcode_uid/si", '', $preview_message);
+ }
+
+ $preview_message = make_clickable($preview_message);
+
+ //
+ // Parse smilies
+ //
+ if ( $smilies_on )
+ {
+ $preview_message = smilies_pass($preview_message);
+ }
+
+ //
+ // Replace naughty words
+ //
+ $orig_word = array();
+ $replacement_word = array();
+ obtain_word_list($orig_word, $replacement_word);
+ if (count($orig_word))
+ {
+ $preview_article_title = preg_replace($orig_word, $replacement_word, $preview_article_title);
+ $preview_article_desc = preg_replace($orig_word, $replacement_word, $preview_article_desc);
+ $preview_message = str_replace('\"', '"', substr(@preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "@preg_replace(\$orig_word, \$replacement_word, '\\0')", '>' . $preview_message . '<'), 1, -1));
+ }
+
+ $preview_message = str_replace("\n", "\n<br />\n", $preview_message);
+
+
+ $template->set_filenames(array(
+ 'preview_box' => 'kb_previewarticle.tpl')
+ );
+
+ $template->assign_vars(array(
+ 'L_ARTICLE_NAME' => $lang['kb_articlename'],
+ 'L_ARTICLE_DESC' => $lang['kb_articledesc'],
+ 'L_PREVIEW' => $lang['kb_articlepreview'],
+ 'PREVIEW_ARTICLE_TITLE' => $preview_article_title,
+ 'PREVIEW_ARTICLE_DESC' => $preview_article_desc,
+ 'MESSAGE' => $preview_message)
+ );
+
+ $template->assign_var_from_handle('ARTICLE_PREVIEW_BOX', 'preview_box');
+ }
+ }
+ else
+ {
+ if(empty($id))
+ {
+ message_die(GENERAL_ERROR, "No article defined.");
+ }
+
+ $sql = "SELECT *
+ FROM " . KB_ARTICLES_TABLE . "
+ WHERE article_id = '$id'";
+ if(!$result = $db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Could not query article data.', '', __LINE__, __FILE__, $sql);
+ }
+
+ if($db->sql_numrows($result) == 1)
+ {
+ $article = $db->sql_fetchrow($result);
+ }
+ else
+ {
+ message_die(GENERAL_ERROR, "Article does not exist.");
+ }
+
+ // Now make an array over the cats
+ $sql = "SELECT cat_id
+ FROM " . KB_ARTICLECATS_TABLE . "
+ WHERE article_id = '$id'";
+ if(!$result = $db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, 'Could not query articlecats data.', '', __LINE__, __FILE__, $sql);
+ }
+
+ $article_cats = array();
+ while($row = $db->sql_fetchrow($result))
+ {
+ $article_cats[] = $row;
+ }
+
+ $article_title = $article['article_title'];
+ $article_text = $article['article_text'];
+ $article_desc = $article['article_desc'];
+ $authorname = $article['article_authorname'];
+
+ $attach_sig = ( $article['enable_sig'] ) ? TRUE : 0;
+
+ $html_on = ( $article['enable_html'] ) ? true : false;
+ $bbcode_on = ( $article['enable_bbcode'] ) ? true : false;
+ $smilies_on = ( $article['enable_smilies'] ) ? true : false;
+
+ $form_action = append_sid("kb.php?pid=ucp&action=edit_article");
+ $hidden_form_fields = '<input type="hidden" name="id" value="' . $id . '" />';
+ }
+
+ if ( $article['bbcode_uid'] != '' )
+ {
+ $article_text = preg_replace('/\:(([a-z0-9]:)?)' . $article['bbcode_uid'] . '/s', '', $article_text);
+ }
+
+ $article_text = str_replace('<', '<', $article_text);
+ $article_text = str_replace('>', '>', $article_text);
+ $article_text = str_replace('<br />', "\n", $article_text);
+
+ //
+ // Signature toggle selection
+ //
+ if( $user_sig != '' )
+ {
+ $template->assign_block_vars('switch_signature_checkbox', array());
+ }
+
+ //
+ // HTML toggle selection
+ //
+ if ( $board_config['allow_html'] )
+ {
+ $html_status = $lang['HTML_is_ON'];
+ $template->assign_block_vars('switch_html_checkbox', array());
+ }
+ else
+ {
+ $html_status = $lang['HTML_is_OFF'];
+ }
+
+ //
+ // BBCode toggle selection
+ //
+ if ( $board_config['allow_bbcode'] )
+ {
+ $bbcode_status = $lang['BBCode_is_ON'];
+ $template->assign_block_vars('switch_bbcode_checkbox', array());
+ }
+ else
+ {
+ $bbcode_status = $lang['BBCode_is_OFF'];
+ }
+
+ // Obtain categories structure
+ $cats = get_cats_structure();
+
+ // First lets sort main cats, yes i know there is a lot of loops, but i can't find a better way :S
+ $s_cats = '<option value="0">-' . $lang['kb_main'] . '</option>';
+ if($mode == "edit" || $preview)
+ {
+ for($i = 0; $i < count($cats); $i++)
+ {
+ $selected = '';
+ for($k = 0; $k < count($article_cats); $k++)
+ {
+ if($article_cats[$k]['cat_id'] == $cats[$i]['cat_id'])
+ {
+ $selected = ' selected="selected"';
+ }
+ }
+ $s_cats .= '<option' . $selected . ' value="' . $cats[$i]['cat_id'] . '"> --' . $cats[$i]['cat_title'] . '</option>';
+
+ // Sort subcats
+ for($j = 0; $j < count($cats[$i]['subcats']); $j++)
+ {
+ $selected = '';
+ for($k = 0; $k < count($article_cats); $k++)
+ {
+ if($article_cats[$k]['cat_id'] == $cats[$i]['subcats'][$j]['cat_id'])
+ {
+ $selected = ' selected="selected"';
+ }
+ }
+ $s_cats .= '<option' . $selected . ' value="' . $cats[$i]['subcats'][$j]['cat_id'] . '"> --' . $cats[$i]['subcats'][$j]['cat_title'] . '</option>';
+ }
+ }
+ }
+ else
+ {
+ for($i = 0; $i < count($cats); $i++)
+ {
+ $s_cats .= '<option value="' . $cats[$i]['cat_id'] . '">--' . $cats[$i]['cat_title'] . '</option>';
+
+ // Sort subcats
+ for($j = 0; $j < count($cats[$i]['subcats']); $j++)
+ {
+ $s_cats .= '<option value="' . $cats[$i]['subcats'][$j]['cat_id'] . '">--' . $cats[$i]['subcats'][$j]['cat_title'] . '</option>';
+ }
+ }
+ }
+
+ //
+ // Smilies toggle selection
+ //
+ if ( $board_config['allow_smilies'] )
+ {
+ $smilies_status = $lang['Smilies_are_ON'];
+ $template->assign_block_vars('switch_smilies_checkbox', array());
+ }
+ else
+ {
+ $smilies_status = $lang['Smilies_are_OFF'];
+ }
+
+ $template->set_filenames(array(
+ 'body' => 'kb_article_posting.tpl')
+ );
+
+ create_navigation("ucp", $action);
+ $post_article = ($mode == 'edit') ? $lang['kb_edit_article'] : $lang['kb_post_article'];
+
+ // This is the template stuff we need no matter what
+ $template->assign_vars(array(
+ 'AUTHORNAME' => $authorname,
+ 'ARTICLE_TITLE' => $article_title,
+ 'ARTICLE' => $article_text,
+ 'DESC' => $article_desc,
+ 'HTML_STATUS' => $html_status,
+ 'BBCODE_STATUS' => sprintf($bbcode_status, '<a href="' . append_sid("faq." . $phpEx . "?mode=bbcode") . '" target="_phpbbcode">', '</a>'),
+ 'SMILIES_STATUS' => $smilies_status,
+
+ 'L_POST_ARTICLE' => $post_article,
+ 'L_AUTHORNAME' => $lang['kb_authorname'],
+ 'L_ARTICLE_NAME' => $lang['kb_articlename'],
+ 'L_ARTICLE_DESC' => $lang['kb_articledesc'],
+ 'L_ARTICLE_CATS' => $lang['kb_articlecats'],
+ 'L_ARTICLE_BODY' => $lang['kb_articletext'],
+ 'L_AUTHORNAME_DESC' => $lang['kb_authorname_desc'],
+ 'L_ARTICLEDESC_DESC' => $lang['kb_articledesc_desc'], // Funny one eh?
+ 'L_ARTICLECATS_DESC' => $lang['kb_articlecats_desc'],
+
+ 'L_OPTIONS' => $lang['Options'],
+ 'L_PREVIEW' => $lang['Preview'],
+ 'L_SUBMIT' => $lang['Submit'],
+ 'L_DISABLE_HTML' => $lang['Disable_HTML_post'],
+ 'L_DISABLE_BBCODE' => $lang['Disable_BBCode_post'],
+ 'L_DISABLE_SMILIES' => $lang['Disable_Smilies_post'],
+ 'L_ATTACH_SIGNATURE' => $lang['Attach_signature'],
+
+ 'L_BBCODE_B_HELP' => $lang['bbcode_b_help'],
+ 'L_BBCODE_I_HELP' => $lang['bbcode_i_help'],
+ 'L_BBCODE_U_HELP' => $lang['bbcode_u_help'],
+ 'L_BBCODE_Q_HELP' => $lang['bbcode_q_help'],
+ 'L_BBCODE_C_HELP' => $lang['bbcode_c_help'],
+ 'L_BBCODE_L_HELP' => $lang['bbcode_l_help'],
+ 'L_BBCODE_O_HELP' => $lang['bbcode_o_help'],
+ 'L_BBCODE_P_HELP' => $lang['bbcode_p_help'],
+ 'L_BBCODE_W_HELP' => $lang['bbcode_w_help'],
+ 'L_BBCODE_A_HELP' => $lang['bbcode_a_help'],
+ 'L_BBCODE_S_HELP' => $lang['bbcode_s_help'],
+ 'L_BBCODE_F_HELP' => $lang['bbcode_f_help'],
+ 'L_EMPTY_MESSAGE' => $lang['Empty_message'],
+
+ 'L_FONT_COLOR' => $lang['Font_color'],
+ 'L_COLOR_DEFAULT' => $lang['color_default'],
+ 'L_COLOR_DARK_RED' => $lang['color_dark_red'],
+ 'L_COLOR_RED' => $lang['color_red'],
+ 'L_COLOR_ORANGE' => $lang['color_orange'],
+ 'L_COLOR_BROWN' => $lang['color_brown'],
+ 'L_COLOR_YELLOW' => $lang['color_yellow'],
+ 'L_COLOR_GREEN' => $lang['color_green'],
+ 'L_COLOR_OLIVE' => $lang['color_olive'],
+ 'L_COLOR_CYAN' => $lang['color_cyan'],
+ 'L_COLOR_BLUE' => $lang['color_blue'],
+ 'L_COLOR_DARK_BLUE' => $lang['color_dark_blue'],
+ 'L_COLOR_INDIGO' => $lang['color_indigo'],
+ 'L_COLOR_VIOLET' => $lang['color_violet'],
+ 'L_COLOR_WHITE' => $lang['color_white'],
+ 'L_COLOR_BLACK' => $lang['color_black'],
+
+ 'L_FONT_SIZE' => $lang['Font_size'],
+ 'L_FONT_TINY' => $lang['font_tiny'],
+ 'L_FONT_SMALL' => $lang['font_small'],
+ 'L_FONT_NORMAL' => $lang['font_normal'],
+ 'L_FONT_LARGE' => $lang['font_large'],
+ 'L_FONT_HUGE' => $lang['font_huge'],
+
+ 'L_BBCODE_CLOSE_TAGS' => $lang['Close_Tags'],
+ 'L_STYLES_TIP' => $lang['Styles_tip'],
+
+ 'S_HTML_CHECKED' => ( !$html_on ) ? 'checked="checked"' : '',
+ 'S_BBCODE_CHECKED' => ( !$bbcode_on ) ? 'checked="checked"' : '',
+ 'S_SMILIES_CHECKED' => ( !$smilies_on ) ? 'checked="checked"' : '',
+ 'S_SIGNATURE_CHECKED' => ( $attach_sig ) ? 'checked="checked"' : '',
+ 'S_POST_ACTION' => $form_action,
+ 'CATS_HTML' => $s_cats,
+ 'S_HIDDEN_FORM_FIELDS' => $hidden_form_fields)
+ );
+}
+
+// Delete an article
+function ucp_article_delete($id, $confirm)
+{
+ global $lang, $db, $phpEx, $template;
+
+ // Simple auth for alpha 1
+ if(($userdata['user_level'] != ADMIN) && ($userdata['user_id'] != $article['article_author']))
+ {
+ message_die(GENERAL_MESSAGE, $lang['kb_delete_noauth']);
+ }
+
+ if(!$confirm)
+ {
+ $s_hidden_fields = '<input type="hidden" name="article_id" value="' . $id . '" />';
+ $l_confirm = $lang['kb_confirm_deletearticle'];
+
+ //
+ // Output confirmation page
+ //
+ $template->set_filenames(array(
+ 'confirm_body' => 'confirm_body.tpl')
+ );
+
+ $template->assign_vars(array(
+ 'MESSAGE_TITLE' => $lang['Information'],
+ 'MESSAGE_TEXT' => $l_confirm,
+
+ 'L_YES' => $lang['Yes'],
+ 'L_NO' => $lang['No'],
+
+ 'S_CONFIRM_ACTION' => append_sid("kb." . $phpEx . "?mode=ucp&action=delete_article"),
+ 'S_HIDDEN_FIELDS' => $s_hidden_fields)
+ );
+
+ $template->pparse('confirm_body');
+ }
+ elseif($confirm) // Double check they actually confirmed
+ {
+ $article_id = $HTTP_POST_VARS['article_id'];
+
+ // Need lang vars for the error messages?
+ $sql = "DELETE FROM " . KB_ARTICLES_TABLE . " WHERE article_id = '" . $article_id . "'";
+ if(!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, "Couldn't delete article from articles table.", "", __LINE__, __FILE__, $sql);
+ }
+
+ $sql = "DELETE FROM " . KB_ARTICLECATS_TABLE . " WHERE article_id = '" . $article_id . "'";
+ if(!$db->sql_query($sql))
+ {
+ message_die(GENERAL_ERROR, "Couldn't delete article from articlecats table.", "", __LINE__, __FILE__, $sql);
+ }
+
+ // Message
+ $meta = '<meta http-equiv="refresh" content="3;url=' . append_sid('kb.' . $phpEx . '?pid=view_article&id=' . $article_id) . '>"';
+ $return_message = $lang['kb_deleted'] . '<br /><br />' . sprintf($lang['kb_click_view_article'], '<a href="' . append_sid('kb.' . $phpEx . '?pid=view_article&id=' . $article_id) . '">', '</a>') . '<br /><br />' . sprintf($lang['kb_click_return_ucp'], '<a href="' . append_sid('kb.' . $phpEx . '?pid=ucp') . '">', '</a>');
+
+ $template->assign_vars(array(
+ 'META' => $meta)
+ );
+
+ message_die(GENERAL_MESSAGE, $return_message);
+ }
+}
+
+//
+// Prepare an article for the database
+//
+function prepare_article(&$bbcode_on, &$html_on, &$smilies_on, &$error_msg, &$bbcode_uid, &$article_title, &$article_desc, &$message, &$cat_id)
+{
+ global $board_config, $userdata, $lang, $phpEx, $phpbb_root_path;
+
+ // Check title
+ if (!empty($article_title))
+ {
+ $article_title = htmlspecialchars(trim($article_title));
+ }
+ else
+ {
+ $error_msg .= (!empty($error_msg)) ? '<br />' . $lang['kb_empty_article_title'] : $lang['kb_empty_article_title'];
+ }
+
+ // Check message
+ if(!empty($message))
+ {
+ $bbcode_uid = ($bbcode_on) ? make_bbcode_uid() : '';
+ $message = prepare_article_text(trim($message), $html_on, $bbcode_on, $smilies_on, $bbcode_uid);
+ }
+ else
+ {
+ $error_msg .= (!empty($error_msg)) ? '<br />' . $lang['kb_empty_article'] : $lang['kb_empty_article'];
+ }
+
+ // Check Desc
+ if (!empty($article_desc))
+ {
+ $article_desc = htmlspecialchars(trim($article_desc));
+ }
+ else
+ {
+ $error_msg .= (!empty($error_msg)) ? '<br />' . $lang['kb_empty_article_desc'] : $lang['kb_empty_article_desc'];
+ }
+
+ // Check categories
+ if(!is_array($cat_id))
+ {
+ $error_msg .= (!empty($error_msg)) ? '<br />' . $lang['kb_empty_cats'] : $lang['kb_empty_cats'];
+ }
+ return;
+}
+
+function prepare_article_text($message, $html_on, $bbcode_on, $smile_on, $bbcode_uid = 0)
+{
+ global $board_config, $phpEx;
+
+ //
+ // Clean up the message
+ //
+ $message = trim($message);
+ $html_entities_match = array('#&(?!(\#[0-9]+;))#', '#<#', '#>#', '#"#');
+ $html_entities_replace = array('&', '<', '>', '"');
+
+ if ($html_on)
+ {
+ // If HTML is on, we try to make it safe
+ // This approach is quite agressive and anything that does not look like a valid tag
+ // is going to get converted to HTML entities
+ $message = stripslashes($message);
+ $html_match = '#<[^\w<]*(\w+)((?:"[^"]*"|\'[^\']*\'|[^<>\'"])+)?>#';
+ $matches = array();
+
+ $message_split = preg_split($html_match, $message);
+ preg_match_all($html_match, $message, $matches);
+
+ $message = '';
+
+ // Include functions_post for clean_html
+ include($phpbb_root_path . "includes/functions_post." . $phpEx);
+
+ foreach ($message_split as $part)
+ {
+ $tag = array(array_shift($matches[0]), array_shift($matches[1]), array_shift($matches[2]));
+ $message .= preg_replace($html_entities_match, $html_entities_replace, $part) . clean_html($tag);
+ }
+
+ $message = addslashes($message);
+ $message = str_replace('"', '\"', $message);
+ }
+ else
+ {
+ $message = preg_replace($html_entities_match, $html_entities_replace, $message);
+ }
+
+ if($bbcode_on && $bbcode_uid != '')
+ {
+ $message = bbencode_first_pass($message, $bbcode_uid);
+ }
+
+ return $message;
+}
+
+function unprepare_article_text($message)
+{
+ $unhtml_specialchars_match = array('#>#', '#<#', '#"#', '#&#');
+ $unhtml_specialchars_replace = array('>', '<', '"', '&');
+
+ return preg_replace($unhtml_specialchars_match, $unhtml_specialchars_replace, $message);
+}
+?>
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|