commit e54349c2cebf5bdf4f1e4724ed3af11ca3c63f5a Author: glix08 Date: Mon Jun 27 21:23:51 2011 +0000 Корректное перебазирование. git-svn-id: https://torrentpier2.googlecode.com/svn/trunk@22 a8ac35ab-4ca4-ca47-4c2d-a49a94f06293 diff --git a/install/sphinx/sphinx.conf b/install/sphinx/sphinx.conf new file mode 100644 index 000000000..0f23247f9 --- /dev/null +++ b/install/sphinx/sphinx.conf @@ -0,0 +1,58 @@ +source torrentpier +{ + type = mysql + sql_host = localhost + sql_user = user + sql_pass = user + sql_db = forum + sql_query_pre = SET NAMES utf8 + sql_query_pre = SET CHARACTER_SET_RESULTS=utf8 + sql_query_pre = SET CHARACTER_SET_CLIENT=utf8 + sql_query_pre = SET CHARACTER_SET_RESULTS=utf8 +} + +source topics: torrentpier +{ + sql_query = \ + SELECT topic_id, forum_id, topic_title \ + FROM bb_topics \ + WHERE topic_id BETWEEN $start AND $end + + sql_query_range = SELECT MIN(topic_id), MAX(topic_id) FROM bb_topics + sql_range_step = 100000 + + sql_attr_uint = forum_id + sql_ranged_throttle = 50 + sql_query_info = SELECT * FROM bb_topics WHERE topic_id = $id +} + +index topics +{ + docinfo = extern + morphology = stem_enru + charset_type = utf-8 + charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42C->U+430..U+44C, U+42E..U+42F->U+44E..U+44F, U+430..U+44C, U+44E..U+44F, U+0401->U+0435, U+0451->U+0435, U+042D->U+0435, U+044D->U+0435 + min_prefix_len = 2 + min_infix_len = 0 + min_word_len = 1 + enable_star = 1 + html_strip = 1 + path = ./sphinx/data/topics + source = topics +} + +indexer +{ + mem_limit = 256M +} + +searchd +{ + listen = 127.0.0.1:3312 + log = ./sphinx/log/searchd.log + query_log = ./sphinx/log/query.log + read_timeout = 5 + max_children = 15 + max_matches = 5000 + pid_file = ./sphinx/searchd.pid +} \ No newline at end of file diff --git a/install/sql/mysql.sql b/install/sql/mysql.sql new file mode 100644 index 000000000..a93de11bb --- /dev/null +++ b/install/sql/mysql.sql @@ -0,0 +1,1763 @@ +-- phpMyAdmin SQL Dump +-- version 2.10.3 +-- http://www.phpmyadmin.net +-- +-- Хост: localhost +-- Время создания: Июн 17 2008 г., 13:37 +-- Версия сервера: 5.0.51 +-- Версия PHP: 5.2.6 + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; + +-- +-- Удаление старых таблиц +-- + +DROP TABLE IF EXISTS `bb_ads`; +DROP TABLE IF EXISTS `bb_attach_quota`; +DROP TABLE IF EXISTS `bb_attachments`; +DROP TABLE IF EXISTS `bb_attachments_config`; +DROP TABLE IF EXISTS `bb_attachments_desc`; +DROP TABLE IF EXISTS `bb_auth_access`; +DROP TABLE IF EXISTS `bb_auth_access_snap`; +DROP TABLE IF EXISTS `bb_banlist`; +DROP TABLE IF EXISTS `bb_bt_dlstatus_main`; +DROP TABLE IF EXISTS `bb_bt_dlstatus_mrg`; +DROP TABLE IF EXISTS `bb_bt_dlstatus_new`; +DROP TABLE IF EXISTS `bb_bt_dlstatus_snap`; +DROP TABLE IF EXISTS `bb_bt_last_torstat`; +DROP TABLE IF EXISTS `bb_bt_last_userstat`; +DROP TABLE IF EXISTS `bb_bt_torhelp`; +DROP TABLE IF EXISTS `bb_bt_torrents`; +DROP TABLE IF EXISTS `bb_bt_torstat`; +DROP TABLE IF EXISTS `bb_bt_tracker`; +DROP TABLE IF EXISTS `bb_bt_tracker_snap`; +DROP TABLE IF EXISTS `bb_bt_user_settings`; +DROP TABLE IF EXISTS `bb_bt_users`; +DROP TABLE IF EXISTS `bb_captcha`; +DROP TABLE IF EXISTS `bb_categories`; +DROP TABLE IF EXISTS `bb_config`; +DROP TABLE IF EXISTS `bb_countries`; +DROP TABLE IF EXISTS `bb_cron`; +DROP TABLE IF EXISTS `bb_datastore`; +DROP TABLE IF EXISTS `bb_disallow`; +DROP TABLE IF EXISTS `bb_extension_groups`; +DROP TABLE IF EXISTS `bb_extensions`; +DROP TABLE IF EXISTS `bb_forums`; +DROP TABLE IF EXISTS `bb_groups`; +DROP TABLE IF EXISTS `bb_log`; +DROP TABLE IF EXISTS `bb_posts`; +DROP TABLE IF EXISTS `bb_posts_html`; +DROP TABLE IF EXISTS `bb_posts_search`; +DROP TABLE IF EXISTS `bb_posts_text`; +DROP TABLE IF EXISTS `bb_privmsgs`; +DROP TABLE IF EXISTS `bb_privmsgs_text`; +DROP TABLE IF EXISTS `bb_quota_limits`; +DROP TABLE IF EXISTS `bb_ranks`; +DROP TABLE IF EXISTS `bb_reports`; +DROP TABLE IF EXISTS `bb_reports_changes`; +DROP TABLE IF EXISTS `bb_reports_modules`; +DROP TABLE IF EXISTS `bb_reports_reasons`; +DROP TABLE IF EXISTS `bb_search_rebuild`; +DROP TABLE IF EXISTS `bb_search_results`; +DROP TABLE IF EXISTS `bb_sessions`; +DROP TABLE IF EXISTS `bb_smilies`; +DROP TABLE IF EXISTS `bb_topic_templates`; +DROP TABLE IF EXISTS `bb_topics`; +DROP TABLE IF EXISTS `bb_topics_watch`; +DROP TABLE IF EXISTS `bb_user_group`; +DROP TABLE IF EXISTS `bb_users`; +DROP TABLE IF EXISTS `bb_vote_desc`; +DROP TABLE IF EXISTS `bb_vote_results`; +DROP TABLE IF EXISTS `bb_vote_voters`; +DROP TABLE IF EXISTS `bb_words`; +DROP TABLE IF EXISTS `buf_last_seeder`; +DROP TABLE IF EXISTS `buf_topic_view`; +-- +-- Структура таблицы `bb_ads` +-- + +CREATE TABLE `bb_ads` ( + `ad_id` mediumint(8) unsigned NOT NULL auto_increment, + `ad_block_ids` varchar(255) NOT NULL default '', + `ad_start_time` datetime NOT NULL default '0000-00-00 00:00:00', + `ad_active_days` smallint(6) NOT NULL default '0', + `ad_status` tinyint(4) NOT NULL default '1', + `ad_desc` varchar(255) NOT NULL default '', + `ad_html` text NOT NULL, + PRIMARY KEY (`ad_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_attachments` +-- + +CREATE TABLE `bb_attachments` ( + `attach_id` mediumint(8) unsigned NOT NULL default '0', + `post_id` mediumint(8) unsigned NOT NULL default '0', + `user_id_1` mediumint(8) NOT NULL default '0', + PRIMARY KEY (`attach_id`, `post_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_attachments_config` +-- + +CREATE TABLE `bb_attachments_config` ( + `config_name` varchar(255) NOT NULL default '', + `config_value` varchar(255) NOT NULL default '', + PRIMARY KEY (`config_name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Дамп данных таблицы `bb_attachments_config` +-- + +INSERT INTO `bb_attachments_config` VALUES ('upload_dir', 'files'); +INSERT INTO `bb_attachments_config` VALUES ('upload_img', 'images/icon_clip.gif'); +INSERT INTO `bb_attachments_config` VALUES ('topic_icon', 'images/icon_clip.gif'); +INSERT INTO `bb_attachments_config` VALUES ('display_order', '0'); +INSERT INTO `bb_attachments_config` VALUES ('max_filesize', '262144'); +INSERT INTO `bb_attachments_config` VALUES ('attachment_quota', '52428800'); +INSERT INTO `bb_attachments_config` VALUES ('max_filesize_pm', '262144'); +INSERT INTO `bb_attachments_config` VALUES ('max_attachments', '1'); +INSERT INTO `bb_attachments_config` VALUES ('max_attachments_pm', '1'); +INSERT INTO `bb_attachments_config` VALUES ('disable_mod', '0'); +INSERT INTO `bb_attachments_config` VALUES ('allow_pm_attach', '1'); +INSERT INTO `bb_attachments_config` VALUES ('allow_ftp_upload', '0'); +INSERT INTO `bb_attachments_config` VALUES ('attach_version', '2.3.14'); +INSERT INTO `bb_attachments_config` VALUES ('default_upload_quota', '0'); +INSERT INTO `bb_attachments_config` VALUES ('default_pm_quota', '0'); +INSERT INTO `bb_attachments_config` VALUES ('ftp_server', ''); +INSERT INTO `bb_attachments_config` VALUES ('ftp_path', ''); +INSERT INTO `bb_attachments_config` VALUES ('download_path', ''); +INSERT INTO `bb_attachments_config` VALUES ('ftp_user', ''); +INSERT INTO `bb_attachments_config` VALUES ('ftp_pass', ''); +INSERT INTO `bb_attachments_config` VALUES ('ftp_pasv_mode', '1'); +INSERT INTO `bb_attachments_config` VALUES ('img_display_inlined', '1'); +INSERT INTO `bb_attachments_config` VALUES ('img_max_width', '200'); +INSERT INTO `bb_attachments_config` VALUES ('img_max_height', '200'); +INSERT INTO `bb_attachments_config` VALUES ('img_link_width', '0'); +INSERT INTO `bb_attachments_config` VALUES ('img_link_height', '0'); +INSERT INTO `bb_attachments_config` VALUES ('img_create_thumbnail', '0'); +INSERT INTO `bb_attachments_config` VALUES ('img_min_thumb_filesize', '12000'); +INSERT INTO `bb_attachments_config` VALUES ('img_imagick', '/usr/bin/convert'); +INSERT INTO `bb_attachments_config` VALUES ('use_gd2', '1'); +INSERT INTO `bb_attachments_config` VALUES ('wma_autoplay', '0'); +INSERT INTO `bb_attachments_config` VALUES ('flash_autoplay', '0'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_attachments_desc` +-- + +CREATE TABLE `bb_attachments_desc` ( + `attach_id` mediumint(8) unsigned NOT NULL auto_increment, + `physical_filename` varchar(255) NOT NULL default '', + `real_filename` varchar(255) NOT NULL default '', + `download_count` mediumint(8) unsigned NOT NULL default '0', + `comment` varchar(255) NOT NULL default '', + `extension` varchar(100) NOT NULL default '', + `mimetype` varchar(100) NOT NULL default '', + `filesize` int(20) NOT NULL default '0', + `filetime` int(11) NOT NULL default '0', + `thumbnail` tinyint(1) NOT NULL default '0', + `tracker_status` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`attach_id`), + KEY `filetime` (`filetime`), + KEY `filesize` (`filesize`), + KEY `physical_filename` (`physical_filename`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_attach_quota` +-- + +CREATE TABLE `bb_attach_quota` ( + `user_id` mediumint(8) unsigned NOT NULL default '0', + `group_id` mediumint(8) unsigned NOT NULL default '0', + `quota_type` smallint(2) NOT NULL default '0', + `quota_limit_id` mediumint(8) unsigned NOT NULL default '0', + KEY `quota_type` (`quota_type`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_auth_access` +-- + +CREATE TABLE `bb_auth_access` ( + `group_id` mediumint(8) NOT NULL default '0', + `forum_id` smallint(5) unsigned NOT NULL default '0', + `forum_perm` int(11) NOT NULL default '0', + PRIMARY KEY (`group_id`,`forum_id`), + KEY `forum_id` (`forum_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_auth_access_snap` +-- + +CREATE TABLE `bb_auth_access_snap` ( + `user_id` mediumint(9) NOT NULL default '0', + `forum_id` smallint(6) NOT NULL default '0', + `forum_perm` int(11) NOT NULL default '0', + PRIMARY KEY (`user_id`,`forum_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_banlist` +-- + +CREATE TABLE `bb_banlist` ( + `ban_id` mediumint(8) unsigned NOT NULL auto_increment, + `ban_userid` mediumint(8) NOT NULL default '0', + `ban_ip` varchar(32) NOT NULL default '', + `ban_email` varchar(255) NOT NULL default '', + PRIMARY KEY (`ban_id`), + KEY `ban_ip_user_id` (`ban_ip`,`ban_userid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_dlstatus_main` +-- + +CREATE TABLE `bb_bt_dlstatus_main` ( + `user_id` mediumint(9) NOT NULL default '0', + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_status` tinyint(1) NOT NULL default '0', + `last_modified_dlstatus` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`,`topic_id`), + KEY `topic_id` (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_dlstatus_new` +-- + +CREATE TABLE `bb_bt_dlstatus_new` ( + `user_id` mediumint(9) NOT NULL default '0', + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_status` tinyint(1) NOT NULL default '0', + `last_modified_dlstatus` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`,`topic_id`), + KEY `topic_id` (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_dlstatus_mrg` +-- + +CREATE TABLE `bb_bt_dlstatus_mrg` ( + `user_id` mediumint(9) NOT NULL default '0', + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_status` tinyint(1) NOT NULL default '0', + `last_modified_dlstatus` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + KEY `user_topic` (`user_id`,`topic_id`), + KEY `topic_id` (`topic_id`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 UNION=(`bb_bt_dlstatus_main`,`bb_bt_dlstatus_new`); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_dlstatus_snap` +-- + +CREATE TABLE `bb_bt_dlstatus_snap` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `dl_status` tinyint(4) NOT NULL default '0', + `users_count` smallint(5) unsigned NOT NULL default '0', + KEY `topic_id` (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_last_torstat` +-- + +CREATE TABLE `bb_bt_last_torstat` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_id` mediumint(9) NOT NULL default '0', + `dl_status` tinyint(1) NOT NULL default '0', + `up_add` bigint(20) unsigned NOT NULL default '0', + `down_add` bigint(20) unsigned NOT NULL default '0', + `release_add` bigint(20) unsigned NOT NULL default '0', + `bonus_add` bigint(20) unsigned NOT NULL default '0', + `speed_up` bigint(20) unsigned NOT NULL default '0', + `speed_down` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY USING BTREE (`topic_id`,`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_last_userstat` +-- + +CREATE TABLE `bb_bt_last_userstat` ( + `user_id` mediumint(9) NOT NULL default '0', + `up_add` bigint(20) unsigned NOT NULL default '0', + `down_add` bigint(20) unsigned NOT NULL default '0', + `release_add` bigint(20) unsigned NOT NULL default '0', + `bonus_add` bigint(20) unsigned NOT NULL default '0', + `speed_up` bigint(20) unsigned NOT NULL default '0', + `speed_down` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_torhelp` +-- + +CREATE TABLE `bb_bt_torhelp` ( + `user_id` mediumint(9) NOT NULL default '0', + `topic_id_csv` text NOT NULL, + PRIMARY KEY (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_torrents` +-- + +CREATE TABLE `bb_bt_torrents` ( + `info_hash` varbinary(20) NOT NULL, + `post_id` mediumint(8) unsigned NOT NULL default '0', + `poster_id` mediumint(9) NOT NULL default '0', + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `forum_id` smallint(5) unsigned NOT NULL default '0', + `attach_id` mediumint(8) unsigned NOT NULL default '0', + `size` bigint(20) unsigned NOT NULL default '0', + `reg_time` int(11) NOT NULL default '0', + `call_seed_time` int(11) NOT NULL default '0', + `complete_count` mediumint(8) unsigned NOT NULL default '0', + `seeder_last_seen` int(11) NOT NULL default '0', + `tor_status` tinyint(4) NOT NULL default '0', + `checked_user_id` mediumint(8) NOT NULL default '0', + `checked_time` int(11) NOT NULL default '0', + `tor_type` TINYINT(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`info_hash`), + UNIQUE KEY `post_id` (`post_id`), + UNIQUE KEY `topic_id` (`topic_id`), + UNIQUE KEY `attach_id` (`attach_id`), + KEY `reg_time` (`reg_time`), + KEY `forum_id` (`forum_id`), + KEY `poster_id` (`poster_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_torstat` +-- + +CREATE TABLE `bb_bt_torstat` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_id` mediumint(9) NOT NULL default '0', + `last_modified_torstat` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + `completed` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`topic_id`,`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_tracker` +-- + +CREATE TABLE `bb_bt_tracker` ( + `peer_hash` varchar(32) character set utf8 collate utf8_bin NOT NULL default '', + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_id` mediumint(9) NOT NULL default '0', + `ip` char(8) character set utf8 collate utf8_bin NOT NULL default '0', + `ipv6` varchar(32) DEFAULT NULL, + `port` smallint(5) unsigned NOT NULL default '0', + `seeder` tinyint(1) NOT NULL default '0', + `releaser` tinyint(1) NOT NULL default '0', + `tor_type` TINYINT(1) NOT NULL DEFAULT '0', + `uploaded` bigint(20) unsigned NOT NULL default '0', + `downloaded` bigint(20) unsigned NOT NULL default '0', + `remain` bigint(20) unsigned NOT NULL default '0', + `speed_up` mediumint(8) unsigned NOT NULL default '0', + `speed_down` mediumint(8) unsigned NOT NULL default '0', + `up_add` bigint(20) unsigned NOT NULL default '0', + `down_add` bigint(20) unsigned NOT NULL default '0', + `update_time` int(11) NOT NULL default '0', + `xbt_error` varchar(200) DEFAULT NULL, + `ul_gdc` bigint(20) unsigned NOT NULL DEFAULT '0', + `ul_gdc_c` mediumint(9) unsigned NOT NULL DEFAULT '0', + `ul_16k_c` mediumint(9) unsigned NOT NULL DEFAULT '0', + `ul_eq_dl` mediumint(9) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`peer_hash`), + KEY `topic_id` (`topic_id`), + KEY `user_id` (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_tracker_snap` +-- + +CREATE TABLE `bb_bt_tracker_snap` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `seeders` mediumint(8) unsigned NOT NULL default '0', + `leechers` mediumint(8) unsigned NOT NULL default '0', + `speed_up` int(10) unsigned NOT NULL default '0', + `speed_down` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_users` +-- + +CREATE TABLE `bb_bt_users` ( + `user_id` mediumint(9) NOT NULL default '0', + `auth_key` char(10) character set utf8 collate utf8_bin NOT NULL default '', + `u_up_total` bigint(20) unsigned NOT NULL default '0', + `u_down_total` bigint(20) unsigned NOT NULL default '0', + `u_up_release` bigint(20) unsigned NOT NULL default '0', + `u_up_bonus` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY (`user_id`), + UNIQUE KEY `auth_key` (`auth_key`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_bt_user_settings` +-- + +CREATE TABLE `bb_bt_user_settings` ( + `user_id` mediumint(9) NOT NULL default '0', + `tor_search_set` text NOT NULL, + `last_modified` int(11) NOT NULL default '0', + PRIMARY KEY (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_captcha` +-- + +CREATE TABLE `bb_captcha` ( + `cap_id` int(10) NOT NULL, + `cap_code` char(6) NOT NULL, + `cap_expire` int(11) NOT NULL default '0', + PRIMARY KEY (`cap_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_categories` +-- + +CREATE TABLE `bb_categories` ( + `cat_id` smallint(5) unsigned NOT NULL auto_increment, + `cat_title` varchar(100) NOT NULL default '', + `cat_order` smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (`cat_id`), + KEY `cat_order` (`cat_order`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; + +-- +-- Дамп данных таблицы `bb_categories` +-- + +INSERT INTO `bb_categories` VALUES (1, 'Test category 1', 10); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_config` +-- + +CREATE TABLE `bb_config` ( + `config_name` varchar(255) NOT NULL default '', + `config_value` text NOT NULL, + PRIMARY KEY (`config_name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Дамп данных таблицы `bb_config` +-- + +INSERT INTO `bb_config` VALUES ('allow_autologin', '1'); +INSERT INTO `bb_config` VALUES ('allow_avatar_local', '0'); +INSERT INTO `bb_config` VALUES ('allow_avatar_remote', '0'); +INSERT INTO `bb_config` VALUES ('allow_avatar_upload', '1'); +INSERT INTO `bb_config` VALUES ('allow_bbcode', '1'); +INSERT INTO `bb_config` VALUES ('allow_namechange', '0'); +INSERT INTO `bb_config` VALUES ('allow_sig', '1'); +INSERT INTO `bb_config` VALUES ('allow_smilies', '1'); +INSERT INTO `bb_config` VALUES ('avatar_filesize', '10000'); +INSERT INTO `bb_config` VALUES ('avatar_gallery_path', 'images/avatars/gallery'); +INSERT INTO `bb_config` VALUES ('avatar_max_height', '100'); +INSERT INTO `bb_config` VALUES ('avatar_max_width', '100'); +INSERT INTO `bb_config` VALUES ('avatar_path', 'images/avatars'); +INSERT INTO `bb_config` VALUES ('board_disable', '0'); +INSERT INTO `bb_config` VALUES ('board_email', 'board_email@yourdomain.com'); +INSERT INTO `bb_config` VALUES ('board_email_form', '0'); +INSERT INTO `bb_config` VALUES ('board_email_sig', 'Thanks, The Management'); +INSERT INTO `bb_config` VALUES ('board_startdate', '1211477514'); +INSERT INTO `bb_config` VALUES ('board_timezone', '0'); +INSERT INTO `bb_config` VALUES ('bt_add_auth_key', '1'); +INSERT INTO `bb_config` VALUES ('bt_add_comment', ''); +INSERT INTO `bb_config` VALUES ('bt_add_publisher', 'YourSiteName'); +INSERT INTO `bb_config` VALUES ('bt_allow_spmode_change', '1'); +INSERT INTO `bb_config` VALUES ('bt_announce_url', 'http://yourdomain.com/bt/announce.php'); +INSERT INTO `bb_config` VALUES ('bt_disable_dht', '1'); +INSERT INTO `bb_config` VALUES ('bt_check_announce_url', '0'); +INSERT INTO `bb_config` VALUES ('bt_del_addit_ann_urls', '1'); +INSERT INTO `bb_config` VALUES ('bt_dl_list_only_1st_page', '1'); +INSERT INTO `bb_config` VALUES ('bt_dl_list_only_count', '1'); +INSERT INTO `bb_config` VALUES ('bt_gen_passkey_on_reg', '1'); +INSERT INTO `bb_config` VALUES ('bt_newtopic_auto_reg', '1'); +INSERT INTO `bb_config` VALUES ('bt_replace_ann_url', '1'); +INSERT INTO `bb_config` VALUES ('bt_search_bool_mode', '1'); +INSERT INTO `bb_config` VALUES ('bt_set_dltype_on_tor_reg', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_but_cancel', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_but_compl', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_but_down', '0'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_but_will', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_list', '0'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_list_buttons', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_dl_stat_on_index', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_ip_only_moder', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_peers', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_peers_mode', '1'); +INSERT INTO `bb_config` VALUES ('bt_show_port_only_moder', '1'); +INSERT INTO `bb_config` VALUES ('bt_tor_browse_only_reg', '0'); +INSERT INTO `bb_config` VALUES ('bt_unset_dltype_on_tor_unreg', '0'); +INSERT INTO `bb_config` VALUES ('config_id', '1'); +INSERT INTO `bb_config` VALUES ('cron_last_check', '1211477514'); +INSERT INTO `bb_config` VALUES ('default_dateformat', 'Y-m-d H:i'); +INSERT INTO `bb_config` VALUES ('default_lang', 'russian'); +INSERT INTO `bb_config` VALUES ('enable_confirm', '1'); +INSERT INTO `bb_config` VALUES ('flood_interval', '15'); +INSERT INTO `bb_config` VALUES ('hot_threshold', '300'); +INSERT INTO `bb_config` VALUES ('login_reset_time', '30'); +INSERT INTO `bb_config` VALUES ('max_autologin_time', '10'); +INSERT INTO `bb_config` VALUES ('max_inbox_privmsgs', '200'); +INSERT INTO `bb_config` VALUES ('max_login_attempts', '5'); +INSERT INTO `bb_config` VALUES ('max_poll_options', '6'); +INSERT INTO `bb_config` VALUES ('max_savebox_privmsgs', '50'); +INSERT INTO `bb_config` VALUES ('max_sentbox_privmsgs', '25'); +INSERT INTO `bb_config` VALUES ('max_sig_chars', '255'); +INSERT INTO `bb_config` VALUES ('posts_per_page', '15'); +INSERT INTO `bb_config` VALUES ('privmsg_disable', '0'); +INSERT INTO `bb_config` VALUES ('prune_enable', '1'); +INSERT INTO `bb_config` VALUES ('record_online_date', '1211477508'); +INSERT INTO `bb_config` VALUES ('record_online_users', '2'); +INSERT INTO `bb_config` VALUES ('require_activation', '0'); +INSERT INTO `bb_config` VALUES ('sendmail_fix', '0'); +INSERT INTO `bb_config` VALUES ('site_desc', 'A _little_ text to describe your forum'); +INSERT INTO `bb_config` VALUES ('sitename', 'yourdomain.com'); +INSERT INTO `bb_config` VALUES ('smilies_path', 'images/smiles'); +INSERT INTO `bb_config` VALUES ('smtp_delivery', '0'); +INSERT INTO `bb_config` VALUES ('smtp_host', ''); +INSERT INTO `bb_config` VALUES ('smtp_password', ''); +INSERT INTO `bb_config` VALUES ('smtp_username', ''); +INSERT INTO `bb_config` VALUES ('topics_per_page', '50'); +INSERT INTO `bb_config` VALUES ('version', '.0.22'); +INSERT INTO `bb_config` VALUES ('xs_add_comments', '0'); +INSERT INTO `bb_config` VALUES ('xs_auto_compile', '1'); +INSERT INTO `bb_config` VALUES ('xs_auto_recompile', '1'); +INSERT INTO `bb_config` VALUES ('xs_php', 'php'); +INSERT INTO `bb_config` VALUES ('xs_shownav', '17'); +INSERT INTO `bb_config` VALUES ('xs_template_time', '0'); +INSERT INTO `bb_config` VALUES ('xs_use_cache', '1'); +INSERT INTO `bb_config` VALUES ('xs_version', '8'); +INSERT INTO `bb_config` VALUES ('active_ads', 'a:0:{}'); +INSERT INTO `bb_config` VALUES ('report_subject_auth', '1'); +INSERT INTO `bb_config` VALUES ('report_modules_cache', '1'); +INSERT INTO `bb_config` VALUES ('report_hack_count', '0'); +INSERT INTO `bb_config` VALUES ('report_notify', '0'); +INSERT INTO `bb_config` VALUES ('report_list_admin', '0'); +INSERT INTO `bb_config` VALUES ('report_new_window', '0'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_countries` +-- + +CREATE TABLE `bb_countries` ( + `country_id` mediumint(3) NOT NULL auto_increment, + `country_code` varchar(3) NOT NULL default '0', + `country_code2` varchar(2) NOT NULL, + `country_code3` varchar(3) NOT NULL, + PRIMARY KEY (`country_id`), + KEY `country_code2` (`country_code2`), + KEY `country_code3` (`country_code3`), + KEY `country_code` (`country_code`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=245 ; + +-- +-- Дамп данных таблицы `bb_countries` +-- + +INSERT INTO `bb_countries` (`country_id`, `country_code`, `country_code2`, `country_code3`) VALUES +(1, '036', 'AU', 'AUS'), +(2, '040', 'AT', 'AUT'), +(3, '031', 'AZ', 'AZE'), +(4, '248', 'AX', 'ALA'), +(5, '008', 'AL', 'ALB'), +(6, '012', 'DZ', 'DZA'), +(7, '581', 'UM', 'UMI'), +(8, '850', 'VI', 'VIR'), +(9, '016', 'AS', 'ASM'), +(10, '660', 'AI', 'AIA'), +(11, '024', 'AO', 'AGO'), +(12, '020', 'AD', 'AND'), +(13, '010', 'AQ', 'ATA'), +(14, '028', 'AG', 'ATG'), +(15, '032', 'AR', 'ARG'), +(16, '051', 'AM', 'ARM'), +(17, '533', 'AW', 'ABW'), +(18, '004', 'AF', 'AFG'), +(19, '044', 'BS', 'BHS'), +(20, '050', 'BD', 'BGD'), +(21, '052', 'BB', 'BRB'), +(22, '048', 'BH', 'BHR'), +(23, '084', 'BZ', 'BLZ'), +(24, '112', 'BY', 'BLR'), +(25, '056', 'BE', 'BEL'), +(26, '204', 'BJ', 'BEN'), +(27, '060', 'BM', 'BMU'), +(28, '100', 'BG', 'BGR'), +(29, '068', 'BO', 'BOL'), +(30, '070', 'BA', 'BIH'), +(31, '072', 'BW', 'BWA'), +(32, '076', 'BR', 'BRA'), +(33, '086', 'IO', 'IOT'), +(34, '092', 'VG', 'VGB'), +(35, '096', 'BN', 'BRN'), +(36, '854', 'BF', 'BFA'), +(37, '108', 'BI', 'BDI'), +(38, '064', 'BT', 'BTN'), +(39, '548', 'VU', 'VUT'), +(40, '336', 'VA', 'VAT'), +(41, '826', 'GB', 'GBR'), +(42, '348', 'HU', 'HUN'), +(43, '862', 'VE', 'VEN'), +(44, '626', 'TL', 'TLS'), +(45, '704', 'VN', 'VNM'), +(46, '266', 'GA', 'GAB'), +(47, '332', 'HT', 'HTI'), +(48, '328', 'GY', 'GUY'), +(49, '270', 'GM', 'GMB'), +(50, '288', 'GH', 'GHA'), +(51, '312', 'GP', 'GLP'), +(52, '320', 'GT', 'GTM'), +(53, '324', 'GN', 'GIN'), +(54, '624', 'GW', 'GNB'), +(55, '276', 'DE', 'DEU'), +(56, '292', 'GI', 'GIB'), +(57, '340', 'HN', 'HND'), +(58, '344', 'HK', 'HKG'), +(59, '308', 'GD', 'GRD'), +(60, '304', 'GL', 'GRL'), +(61, '300', 'GR', 'GRC'), +(62, '268', 'GE', 'GEO'), +(63, '316', 'GU', 'GUM'), +(64, '208', 'DK', 'DNK'), +(65, '180', 'CD', 'COD'), +(66, '262', 'DJ', 'DJI'), +(67, '212', 'DM', 'DMA'), +(68, '214', 'DO', 'DOM'), +(69, 'EU', 'EU', ''), +(70, '818', 'EG', 'EGY'), +(71, '894', 'ZM', 'ZMB'), +(72, '732', 'EH', 'ESH'), +(73, '716', 'ZW', 'ZWE'), +(74, '376', 'IL', 'ISR'), +(75, '356', 'IN', 'IND'), +(76, '360', 'ID', 'IDN'), +(77, '400', 'JO', 'JOR'), +(78, '368', 'IQ', 'IRQ'), +(79, '364', 'IR', 'IRN'), +(80, '372', 'IE', 'IRL'), +(81, '352', 'IS', 'ISL'), +(82, '724', 'ES', 'ESP'), +(83, '380', 'IT', 'ITA'), +(84, '887', 'YE', 'YEM'), +(85, '408', 'KP', 'PRK'), +(86, '132', 'CV', 'CPV'), +(87, '398', 'KZ', 'KAZ'), +(88, '136', 'KY', 'CYM'), +(89, '116', 'KH', 'KHM'), +(90, '120', 'CM', 'CMR'), +(91, '124', 'CA', 'CAN'), +(92, '634', 'QA', 'QAT'), +(93, '404', 'KE', 'KEN'), +(94, '196', 'CY', 'CYP'), +(95, '417', 'KG', 'KGZ'), +(96, '296', 'KI', 'KIR'), +(97, '156', 'CN', 'CHN'), +(98, '166', 'CC', 'CCK'), +(99, '170', 'CO', 'COL'), +(100, '174', 'KM', 'COM'), +(101, '188', 'CR', 'CRI'), +(102, '384', 'CI', 'CIV'), +(103, '192', 'CU', 'CUB'), +(104, '414', 'KW', 'KWT'), +(105, '418', 'LA', 'LAO'), +(106, '428', 'LV', 'LVA'), +(107, '426', 'LS', 'LSO'), +(108, '430', 'LR', 'LBR'), +(109, '422', 'LB', 'LBN'), +(110, '434', 'LY', 'LBY'), +(111, '440', 'LT', 'LTU'), +(112, '438', 'LI', 'LIE'), +(113, '442', 'LU', 'LUX'), +(114, '480', 'MU', 'MUS'), +(115, '478', 'MR', 'MRT'), +(116, '450', 'MG', 'MDG'), +(117, '175', 'YT', 'MYT'), +(118, '446', 'MO', 'MAC'), +(119, '807', 'MK', 'MKD'), +(120, '454', 'MW', 'MWI'), +(121, '458', 'MY', 'MYS'), +(122, '466', 'ML', 'MLI'), +(123, '462', 'MV', 'MDV'), +(124, '470', 'MT', 'MLT'), +(125, '504', 'MA', 'MAR'), +(126, '474', 'MQ', 'MTQ'), +(127, '584', 'MH', 'MHL'), +(128, '484', 'MX', 'MEX'), +(129, '508', 'MZ', 'MOZ'), +(130, '498', 'MD', 'MDA'), +(131, '492', 'MC', 'MCO'), +(132, '496', 'MN', 'MNG'), +(133, '500', 'MS', 'MSR'), +(134, '104', 'MM', 'MMR'), +(135, '516', 'NA', 'NAM'), +(136, '520', 'NR', 'NRU'), +(137, '524', 'NP', 'NPL'), +(138, '562', 'NE', 'NER'), +(139, '566', 'NG', 'NGA'), +(140, '530', 'AN', 'ANT'), +(141, '528', 'NL', 'NLD'), +(142, '558', 'NI', 'NIC'), +(143, '570', 'NU', 'NIU'), +(144, '540', 'NC', 'NCL'), +(145, '554', 'NZ', 'NZL'), +(146, '578', 'NO', 'NOR'), +(147, '784', 'AE', 'ARE'), +(148, '512', 'OM', 'OMN'), +(149, '162', 'CX', 'CXR'), +(150, '184', 'CK', 'COK'), +(151, '334', 'HM', 'HMD'), +(152, '586', 'PK', 'PAK'), +(153, '585', 'PW', 'PLW'), +(154, '275', 'PS', 'PSE'), +(155, '591', 'PA', 'PAN'), +(156, '598', 'PG', 'PNG'), +(157, '600', 'PY', 'PRY'), +(158, '604', 'PE', 'PER'), +(159, '612', 'PN', 'PCN'), +(160, '616', 'PL', 'POL'), +(161, '620', 'PT', 'PRT'), +(162, '630', 'PR', 'PRI'), +(163, '178', 'CG', 'COG'), +(164, '638', 'RE', 'REU'), +(165, '643', 'RU', 'RUS'), +(166, '646', 'RW', 'RWA'), +(167, '642', 'RO', 'ROU'), +(168, '840', 'US', 'USA'), +(169, '222', 'SV', 'SLV'), +(170, '882', 'WS', 'WSM'), +(171, '674', 'SM', 'SMR'), +(172, '678', 'ST', 'STP'), +(173, '682', 'SA', 'SAU'), +(174, '748', 'SZ', 'SWZ'), +(175, '744', 'SJ', 'SJM'), +(176, '580', 'MP', 'MNP'), +(177, '690', 'SC', 'SYC'), +(178, '686', 'SN', 'SEN'), +(179, '670', 'VC', 'VCT'), +(180, '659', 'KN', 'KNA'), +(181, '662', 'LC', 'LCA'), +(182, '666', 'PM', 'SPM'), +(183, '688', 'RS', 'SRB'), +(184, '891', 'CS', 'SCG'), +(185, '702', 'SG', 'SGP'), +(186, '760', 'SY', 'SYR'), +(187, '703', 'SK', 'SVK'), +(188, '705', 'SI', 'SVN'), +(189, '090', 'SB', 'SLB'), +(190, '706', 'SO', 'SOM'), +(191, '736', 'SD', 'SDN'), +(192, '740', 'SR', 'SUR'), +(193, '694', 'SL', 'SLE'), +(194, '810', 'SU', 'SUN'), +(195, '762', 'TJ', 'TJK'), +(196, '764', 'TH', 'THA'), +(197, '158', 'TW', 'TWN'), +(198, '834', 'TZ', 'TZA'), +(199, '768', 'TG', 'TGO'), +(200, '772', 'TK', 'TKL'), +(201, '776', 'TO', 'TON'), +(202, '780', 'TT', 'TTO'), +(203, '798', 'TV', 'TUV'), +(204, '788', 'TN', 'TUN'), +(205, '795', 'TM', 'TKM'), +(206, '792', 'TR', 'TUR'), +(207, '800', 'UG', 'UGA'), +(208, '860', 'UZ', 'UZB'), +(209, '804', 'UA', 'UKR'), +(210, '858', 'UY', 'URY'), +(211, '234', 'FO', 'FRO'), +(212, '583', 'FM', 'FSM'), +(213, '242', 'FJ', 'FJI'), +(214, '608', 'PH', 'PHL'), +(215, '246', 'FI', 'FIN'), +(216, '238', 'FK', 'FLK'), +(217, '250', 'FR', 'FRA'), +(218, '254', 'GF', 'GUF'), +(219, '258', 'PF', 'PYF'), +(220, '260', 'TF', 'ATF'), +(221, '191', 'HR', 'HRV'), +(222, '140', 'CF', 'CAF'), +(223, '148', 'TD', 'TCD'), +(224, '499', 'ME', 'MNE'), +(225, '203', 'CZ', 'CZE'), +(226, '152', 'CL', 'CHL'), +(227, '756', 'CH', 'CHE'), +(228, '752', 'SE', 'SWE'), +(229, '144', 'LK', 'LKA'), +(230, '218', 'EC', 'ECU'), +(231, '226', 'GQ', 'GNQ'), +(232, '232', 'ER', 'ERI'), +(233, '233', 'EE', 'EST'), +(234, '231', 'ET', 'ETH'), +(235, '710', 'ZA', 'ZAF'), +(236, '410', 'KR', 'KOR'), +(237, '239', 'GS', 'SGS'), +(238, '388', 'JM', 'JAM'), +(239, '392', 'JP', 'JPN'), +(240, '074', 'BV', 'BVT'), +(241, '574', 'NF', 'NFK'), +(242, '654', 'SH', 'SHN'), +(243, '796', 'TC', 'TCA'), +(244, '876', 'WF', 'WLF'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_cron` +-- + +CREATE TABLE `bb_cron` ( + `cron_id` smallint(5) unsigned NOT NULL auto_increment, + `cron_active` tinyint(4) NOT NULL default '1', + `cron_title` char(120) NOT NULL default '', + `cron_script` char(120) NOT NULL default '', + `schedule` enum('hourly','daily','weekly','monthly','interval') NOT NULL default 'daily', + `run_day` enum('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28') default NULL, + `run_time` time default '04:00:00', + `run_order` tinyint(4) unsigned NOT NULL, + `last_run` datetime NOT NULL default '0000-00-00 00:00:00', + `next_run` datetime NOT NULL default '0000-00-00 00:00:00', + `run_interval` time default NULL, + `log_enabled` tinyint(1) NOT NULL default '0', + `log_file` char(120) NOT NULL default '', + `log_sql_queries` tinyint(4) NOT NULL default '0', + `disable_board` tinyint(1) NOT NULL default '0', + `run_counter` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY (`cron_id`), + UNIQUE KEY `title` (`cron_title`), + UNIQUE KEY `script` (`cron_script`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=22 ; + +-- +-- Дамп данных таблицы `bb_cron` +-- + +INSERT INTO `bb_cron` VALUES (1, 0, 'Site backup', 'site_backup.php', 'daily', '1', '05:00:00', 10, '0000-00-00 00:00:00', '0000-00-00 00:00:00', NULL, 1, '', 0, 1, 0); +INSERT INTO `bb_cron` VALUES (2, 0, 'DB backup', 'db_backup.php', 'daily', '1', '05:00:00', 20, '0000-00-00 00:00:00', '0000-00-00 00:00:00', NULL, 1, '', 0, 1, 0); +INSERT INTO `bb_cron` VALUES (3, 1, 'Avatars cleanup', 'avatars_cleanup.php', 'weekly', '1', '05:00:00', 30, '2008-05-22 19:11:10', '2008-05-26 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (4, 1, 'Board maintenance', 'bb_maintenance.php', 'daily', NULL, '05:00:00', 40, '2008-05-22 19:11:14', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (5, 1, 'Prune forums', 'prune_forums.php', 'daily', NULL, '05:00:00', 50, '2008-05-22 19:11:17', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (6, 1, 'Prune topic moved stubs', 'prune_topic_moved.php', 'daily', NULL, '05:00:00', 60, '2008-05-22 19:11:20', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (7, 1, 'Logs cleanup', 'clean_log.php', 'daily', NULL, '05:00:00', 70, '2008-05-22 19:11:23', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (8, 1, 'Tracker maintenance', 'tr_maintenance.php', 'daily', NULL, '05:00:00', 90, '2008-05-22 19:11:26', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (9, 1, 'Clean dlstat', 'clean_dlstat.php', 'daily', NULL, '05:00:00', 100, '2008-05-22 19:11:29', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (10, 1, 'Prune inactive users', 'prune_inactive_users.php', 'daily', NULL, '05:00:00', 110, '2008-05-22 19:11:32', '2008-05-23 05:00:00', NULL, 1, '', 0, 1, 2); +INSERT INTO `bb_cron` VALUES (11, 1, 'Sessions cleanup', 'sessions_cleanup.php', 'interval', NULL, NULL, 255, '2008-05-22 19:18:07', '2008-05-22 19:21:07', '00:03:00', 0, '', 0, 0, 31); +INSERT INTO `bb_cron` VALUES (12, 1, 'DS update ''cat_forums''', 'ds_update_cat_forums.php', 'interval', NULL, NULL, 255, '2008-05-22 19:18:10', '2008-05-22 19:23:10', '00:05:00', 0, '', 0, 0, 24); +INSERT INTO `bb_cron` VALUES (13, 1, 'DS update ''stats''', 'ds_update_stats.php', 'interval', NULL, NULL, 255, '2008-05-22 19:11:46', '2008-05-22 19:21:46', '00:10:00', 0, '', 0, 0, 15); +INSERT INTO `bb_cron` VALUES (14, 1, 'Flash topic view', 'flash_topic_view.php', 'interval', NULL, NULL, 255, '2008-05-22 19:11:49', '2008-05-22 19:21:49', '00:10:00', 0, '', 0, 0, 15); +INSERT INTO `bb_cron` VALUES (15, 1, 'Clean search results', 'clean_search_results.php', 'interval', NULL, NULL, 255, '2008-05-22 19:11:52', '2008-05-22 19:21:52', '00:10:00', 0, '', 0, 0, 15); +INSERT INTO `bb_cron` VALUES (16, 1, 'Tracker cleanup and dlstat', 'tr_cleanup_and_dlstat.php', 'interval', NULL, NULL, 20, '2008-05-22 20:31:41', '2008-05-22 20:46:41', '00:15:00', 0, '', 0, 0, 14); +INSERT INTO `bb_cron` VALUES (17, 1, 'Make tracker snapshot', 'tr_make_snapshot.php', 'interval', NULL, NULL, 10, '2008-05-22 20:31:38', '2008-05-22 20:41:38', '00:10:00', 0, '', 0, 0, 16); +INSERT INTO `bb_cron` VALUES (18, 1, 'Seeder last seen', 'tr_update_seeder_last_seen.php', 'interval', NULL, NULL, 255, '2008-05-22 19:11:55', '2008-05-22 20:11:55', '01:00:00', 0, '', 0, 0, 5); +INSERT INTO `bb_cron` VALUES (19, 1, 'Clean torrents search options', 'clean_tor_search_options.php', 'interval', NULL, NULL, 255, '2008-05-22 19:11:58', '2008-05-23 01:11:58', '06:00:00', 0, '', 0, 0, 3); +INSERT INTO `bb_cron` VALUES (20, 1, 'Tracker dl-complete count', 'tr_complete_count.php', 'interval', NULL, NULL, 255, '2008-05-22 19:12:01', '2008-05-23 01:12:01', '06:00:00', 0, '', 0, 0, 3); +INSERT INTO `bb_cron` VALUES (21, 1, 'Cache garbage collector', 'cache_gc.php', 'interval', NULL, NULL, 255, '2008-05-22 19:18:13', '2008-05-22 19:23:13', '00:05:00', 0, '', 0, 0, 24); +INSERT INTO `bb_cron` VALUES (22, 1, 'Manage Antibroot', 'bb_manage_untrusted.php', 'interval', NULL, NULL, 255, '2008-05-22 19:18:13', '2008-05-22 19:23:13', '00:10:00', 0, '', 0, 0, 24); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_datastore` +-- + +CREATE TABLE `bb_datastore` ( + `ds_title` varchar(255) NOT NULL default '', + `ds_data` longtext NOT NULL, + PRIMARY KEY (`ds_title`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Дамп данных таблицы `bb_datastore` +-- + +INSERT INTO `bb_datastore` VALUES ('cat_forums', 'a:6:{s:15:"not_auth_forums";a:4:{s:10:"guest_view";s:0:"";s:10:"guest_read";s:0:"";s:9:"user_view";s:0:"";s:9:"user_read";s:0:"";}s:14:"tracker_forums";s:0:"";s:14:"cat_title_html";a:1:{i:1;s:15:"Test category 1";}s:15:"forum_name_html";a:1:{i:1;s:12:"Test Forum 1";}s:1:"c";a:1:{i:1;a:4:{s:6:"cat_id";s:1:"1";s:9:"cat_title";s:15:"Test category 1";s:9:"cat_order";s:2:"10";s:6:"forums";a:1:{i:0;s:1:"1";}}}s:1:"f";a:1:{i:1;a:20:{s:8:"forum_id";s:1:"1";s:6:"cat_id";s:1:"1";s:10:"forum_name";s:12:"Test Forum 1";s:10:"forum_desc";s:26:"This is just a test forum.";s:12:"forum_status";s:1:"0";s:11:"forum_posts";s:1:"1";s:12:"forum_topics";s:1:"1";s:9:"auth_view";s:1:"0";s:9:"auth_read";s:1:"0";s:9:"auth_post";s:1:"1";s:10:"auth_reply";s:1:"1";s:9:"auth_edit";s:1:"1";s:11:"auth_delete";s:1:"1";s:11:"auth_sticky";s:1:"3";s:13:"auth_announce";s:1:"3";s:9:"auth_vote";s:1:"1";s:15:"auth_pollcreate";s:1:"1";s:16:"auth_attachments";s:1:"1";s:13:"auth_download";s:1:"1";s:12:"forum_parent";s:1:"0";}}}'); +INSERT INTO `bb_datastore` VALUES ('jumpbox', 'a:2:{s:5:"guest";s:241:"\n\n";s:4:"user";s:241:"\n\n";}'); +INSERT INTO `bb_datastore` VALUES ('viewtopic_forum_select', 'a:1:{s:22:"viewtopic_forum_select";s:187:"\n\n";}'); +INSERT INTO `bb_datastore` VALUES ('latest_news', 'a:1:{i:0;a:3:{s:8:"topic_id";s:1:"1";s:10:"topic_time";s:9:"972086460";s:11:"topic_title";s:18:"Welcome to TorrentPier";}}'); +INSERT INTO `bb_datastore` VALUES ('ads', 'a:0:{}'); +INSERT INTO `bb_datastore` VALUES ('stats', 'a:4:{s:9:"usercount";s:1:"3";s:10:"newestuser";a:2:{s:7:"user_id";s:1:"2";s:8:"username";s:5:"admin";}s:9:"postcount";s:1:"1";s:10:"topiccount";s:1:"1";}'); +INSERT INTO `bb_datastore` VALUES ('moderators', 'a:6:{s:10:"name_users";a:0:{}s:11:"name_groups";a:0:{}s:9:"mod_users";a:0:{}s:10:"mod_groups";a:0:{}s:10:"moderators";a:0:{}s:6:"admins";a:1:{i:2;s:5:"admin";}}'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_disallow` +-- + +CREATE TABLE `bb_disallow` ( + `disallow_id` mediumint(8) unsigned NOT NULL auto_increment, + `disallow_username` varchar(25) NOT NULL default '', + PRIMARY KEY (`disallow_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_extensions` +-- + +CREATE TABLE `bb_extensions` ( + `ext_id` mediumint(8) unsigned NOT NULL auto_increment, + `group_id` mediumint(8) unsigned NOT NULL default '0', + `extension` varchar(100) NOT NULL default '', + `comment` varchar(100) NOT NULL default '', + PRIMARY KEY (`ext_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=30 ; + +-- +-- Дамп данных таблицы `bb_extensions` +-- + +INSERT INTO `bb_extensions` VALUES (1, 1, 'gif', ''); +INSERT INTO `bb_extensions` VALUES (2, 1, 'png', ''); +INSERT INTO `bb_extensions` VALUES (3, 1, 'jpeg', ''); +INSERT INTO `bb_extensions` VALUES (4, 1, 'jpg', ''); +INSERT INTO `bb_extensions` VALUES (5, 1, 'tif', ''); +INSERT INTO `bb_extensions` VALUES (6, 1, 'tga', ''); +INSERT INTO `bb_extensions` VALUES (7, 2, 'gtar', ''); +INSERT INTO `bb_extensions` VALUES (8, 2, 'gz', ''); +INSERT INTO `bb_extensions` VALUES (9, 2, 'tar', ''); +INSERT INTO `bb_extensions` VALUES (10, 2, 'zip', ''); +INSERT INTO `bb_extensions` VALUES (11, 2, 'rar', ''); +INSERT INTO `bb_extensions` VALUES (12, 2, 'ace', ''); +INSERT INTO `bb_extensions` VALUES (13, 3, 'txt', ''); +INSERT INTO `bb_extensions` VALUES (14, 3, 'c', ''); +INSERT INTO `bb_extensions` VALUES (15, 3, 'h', ''); +INSERT INTO `bb_extensions` VALUES (16, 3, 'cpp', ''); +INSERT INTO `bb_extensions` VALUES (17, 3, 'hpp', ''); +INSERT INTO `bb_extensions` VALUES (18, 3, 'diz', ''); +INSERT INTO `bb_extensions` VALUES (19, 4, 'xls', ''); +INSERT INTO `bb_extensions` VALUES (20, 4, 'doc', ''); +INSERT INTO `bb_extensions` VALUES (21, 4, 'dot', ''); +INSERT INTO `bb_extensions` VALUES (22, 4, 'pdf', ''); +INSERT INTO `bb_extensions` VALUES (23, 4, 'ai', ''); +INSERT INTO `bb_extensions` VALUES (24, 4, 'ps', ''); +INSERT INTO `bb_extensions` VALUES (25, 4, 'ppt', ''); +INSERT INTO `bb_extensions` VALUES (26, 5, 'rm', ''); +INSERT INTO `bb_extensions` VALUES (27, 6, 'wma', ''); +INSERT INTO `bb_extensions` VALUES (28, 7, 'swf', ''); +INSERT INTO `bb_extensions` VALUES (29, 8, 'torrent', ''); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_extension_groups` +-- + +CREATE TABLE `bb_extension_groups` ( + `group_id` mediumint(8) NOT NULL auto_increment, + `group_name` varchar(20) NOT NULL default '', + `cat_id` tinyint(2) NOT NULL default '0', + `allow_group` tinyint(1) NOT NULL default '0', + `download_mode` tinyint(1) unsigned NOT NULL default '1', + `upload_icon` varchar(100) NOT NULL default '', + `max_filesize` int(20) NOT NULL default '0', + `forum_permissions` text NOT NULL, + PRIMARY KEY (`group_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ; + +-- +-- Дамп данных таблицы `bb_extension_groups` +-- + +INSERT INTO `bb_extension_groups` VALUES (1, 'Images', 1, 1, 1, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (2, 'Archives', 0, 1, 1, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (3, 'Plain Text', 0, 0, 1, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (4, 'Documents', 0, 0, 1, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (5, 'Real Media', 0, 0, 2, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (6, 'Streams', 2, 0, 1, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (7, 'Flash Files', 3, 0, 1, '', 262144, ''); +INSERT INTO `bb_extension_groups` VALUES (8, 'Torrent', 0, 1, 1, '', 122880, ''); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_forums` +-- + +CREATE TABLE `bb_forums` ( + `forum_id` smallint(5) unsigned NOT NULL auto_increment, + `cat_id` smallint(5) unsigned NOT NULL default '0', + `forum_name` varchar(150) NOT NULL default '', + `forum_desc` text NOT NULL, + `forum_status` tinyint(4) NOT NULL default '0', + `forum_order` smallint(5) unsigned NOT NULL default '1', + `forum_posts` mediumint(8) unsigned NOT NULL default '0', + `forum_topics` mediumint(8) unsigned NOT NULL default '0', + `forum_last_post_id` mediumint(8) unsigned NOT NULL default '0', + `prune_days` smallint(5) unsigned NOT NULL default '0', + `auth_view` tinyint(2) NOT NULL default '0', + `auth_read` tinyint(2) NOT NULL default '0', + `auth_post` tinyint(2) NOT NULL default '0', + `auth_reply` tinyint(2) NOT NULL default '0', + `auth_edit` tinyint(2) NOT NULL default '0', + `auth_delete` tinyint(2) NOT NULL default '0', + `auth_sticky` tinyint(2) NOT NULL default '0', + `auth_announce` tinyint(2) NOT NULL default '0', + `auth_vote` tinyint(2) NOT NULL default '0', + `auth_pollcreate` tinyint(2) NOT NULL default '0', + `auth_attachments` tinyint(2) NOT NULL default '0', + `auth_download` tinyint(2) NOT NULL default '0', + `allow_reg_tracker` tinyint(1) NOT NULL default '0', + `allow_dl_topic` tinyint(1) NOT NULL default '0', + `self_moderated` tinyint(1) NOT NULL default '0', + `forum_parent` smallint(5) unsigned NOT NULL default '0', + `show_on_index` tinyint(1) NOT NULL default '1', + `forum_display_sort` tinyint(1) NOT NULL default '0', + `forum_display_order` tinyint(1) NOT NULL default '0', + `topic_tpl_id` smallint(6) NOT NULL default '0', + PRIMARY KEY (`forum_id`), + KEY `forums_order` (`forum_order`), + KEY `cat_id` (`cat_id`), + KEY `forum_last_post_id` (`forum_last_post_id`), + KEY `forum_parent` (`forum_parent`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; + +-- +-- Дамп данных таблицы `bb_forums` +-- + +INSERT INTO `bb_forums` VALUES (1, 1, 'Test Forum 1', 'This is just a test forum.', 0, 10, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_groups` +-- + +CREATE TABLE `bb_groups` ( + `group_id` mediumint(8) NOT NULL auto_increment, + `group_type` tinyint(4) NOT NULL default '1', + `group_name` varchar(40) NOT NULL default '', + `group_description` varchar(255) NOT NULL default '', + `group_moderator` mediumint(8) NOT NULL default '0', + `group_single_user` tinyint(1) NOT NULL default '1', + PRIMARY KEY (`group_id`), + KEY `group_single_user` (`group_single_user`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_log` +-- + +CREATE TABLE `bb_log` ( + `log_type_id` mediumint(8) unsigned NOT NULL default '0', + `log_user_id` mediumint(9) NOT NULL default '0', + `log_username` varchar(25) NOT NULL default '', + `log_user_ip` varchar(32) character set utf8 collate utf8_bin NOT NULL default '', + `log_forum_id` smallint(5) unsigned NOT NULL default '0', + `log_forum_id_new` smallint(5) unsigned NOT NULL default '0', + `log_topic_id` mediumint(8) unsigned NOT NULL default '0', + `log_topic_id_new` mediumint(8) unsigned NOT NULL default '0', + `log_topic_title` varchar(250) NOT NULL default '', + `log_topic_title_new` varchar(250) NOT NULL default '', + `log_time` int(11) NOT NULL default '0', + `log_msg` text NOT NULL, + KEY `log_time` (`log_time`), + FULLTEXT KEY `log_topic_title` (`log_topic_title`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_posts` +-- + +CREATE TABLE `bb_posts` ( + `post_id` mediumint(8) unsigned NOT NULL auto_increment, + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `forum_id` smallint(5) unsigned NOT NULL default '0', + `poster_id` mediumint(8) NOT NULL default '0', + `post_time` int(11) NOT NULL default '0', + `poster_ip` char(32) character set utf8 collate utf8_bin NOT NULL default '', + `post_username` varchar(25) NOT NULL default '', + `enable_bbcode` tinyint(1) NOT NULL default '1', + `enable_smilies` tinyint(1) NOT NULL default '1', + `enable_sig` tinyint(1) NOT NULL default '1', + `post_edit_time` int(11) NOT NULL default '0', + `post_edit_count` smallint(5) unsigned NOT NULL default '0', + `post_attachment` tinyint(1) NOT NULL default '0', + `post_reported` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`post_id`), + KEY `topic_id` (`topic_id`), + KEY `poster_id` (`poster_id`), + KEY `post_time` (`post_time`), + KEY `forum_id_post_time` (`forum_id`,`post_time`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; + +-- +-- Дамп данных таблицы `bb_posts` +-- + +INSERT INTO `bb_posts` VALUES (1, 1, 1, 2, 972086460, '', '', 1, 1, 1, 0, 0, 0, 0); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_posts_html` +-- + +CREATE TABLE `bb_posts_html` ( + `post_id` mediumint(9) NOT NULL default '0', + `post_html_time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + `post_html` mediumtext NOT NULL, + PRIMARY KEY (`post_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_posts_search` +-- + +CREATE TABLE `bb_posts_search` ( + `post_id` mediumint(8) unsigned NOT NULL default '0', + `search_words` text NOT NULL, + PRIMARY KEY (`post_id`), + FULLTEXT KEY `search_words` (`search_words`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_posts_text` +-- + +CREATE TABLE `bb_posts_text` ( + `post_id` mediumint(8) unsigned NOT NULL default '0', + `bbcode_uid` varchar(10) NOT NULL default '', + `post_subject` enum('','kFpILr5') NOT NULL default '', + `post_text` text NOT NULL, + PRIMARY KEY (`post_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Дамп данных таблицы `bb_posts_text` +-- + +INSERT INTO `bb_posts_text` VALUES (1, '', '', 'This is an example post in your TorrentPier installation. You may delete this post, this topic and even this forum if you like since everything seems to be working!'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_privmsgs` +-- + +CREATE TABLE `bb_privmsgs` ( + `privmsgs_id` mediumint(8) unsigned NOT NULL auto_increment, + `privmsgs_type` tinyint(4) NOT NULL default '0', + `privmsgs_subject` varchar(255) NOT NULL default '0', + `privmsgs_from_userid` mediumint(8) NOT NULL default '0', + `privmsgs_to_userid` mediumint(8) NOT NULL default '0', + `privmsgs_date` int(11) NOT NULL default '0', + `privmsgs_ip` varchar(32) character set utf8 collate utf8_bin NOT NULL default '', + `privmsgs_enable_bbcode` tinyint(1) NOT NULL default '1', + `privmsgs_enable_smilies` tinyint(1) NOT NULL default '1', + `privmsgs_reported` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`privmsgs_id`), + KEY `privmsgs_from_userid` (`privmsgs_from_userid`), + KEY `privmsgs_to_userid` (`privmsgs_to_userid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_privmsgs_text` +-- + +CREATE TABLE `bb_privmsgs_text` ( + `privmsgs_text_id` mediumint(8) unsigned NOT NULL default '0', + `privmsgs_bbcode_uid` varchar(10) NOT NULL default '0', + `privmsgs_text` text NOT NULL, + PRIMARY KEY (`privmsgs_text_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_quota_limits` +-- + +CREATE TABLE `bb_quota_limits` ( + `quota_limit_id` mediumint(8) unsigned NOT NULL auto_increment, + `quota_desc` varchar(20) NOT NULL default '', + `quota_limit` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY (`quota_limit_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; + +-- +-- Дамп данных таблицы `bb_quota_limits` +-- + +INSERT INTO `bb_quota_limits` VALUES (1, 'Low', 262144); +INSERT INTO `bb_quota_limits` VALUES (2, 'Medium', 10485760); +INSERT INTO `bb_quota_limits` VALUES (3, 'High', 15728640); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_ranks` +-- + +CREATE TABLE `bb_ranks` ( + `rank_id` smallint(5) unsigned NOT NULL auto_increment, + `rank_title` varchar(50) NOT NULL default '', + `rank_min` mediumint(8) NOT NULL default '0', + `rank_special` tinyint(1) NOT NULL default '1', + `rank_image` varchar(255) NOT NULL default '', + PRIMARY KEY (`rank_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; + +-- +-- Дамп данных таблицы `bb_ranks` +-- + +INSERT INTO `bb_ranks` VALUES (1, 'Site Admin', -1, 1, ''); + +-- -------------------------------------------------------- +-- +-- Структура таблицы `bb_reports` +-- + +CREATE TABLE `bb_reports` ( + `report_id` mediumint(8) unsigned NOT NULL auto_increment, + `user_id` mediumint(8) NOT NULL, + `report_time` int(11) NOT NULL, + `report_last_change` mediumint(8) unsigned default NULL, + `report_module_id` mediumint(8) unsigned NOT NULL, + `report_status` tinyint(1) NOT NULL, + `report_reason_id` mediumint(8) unsigned NOT NULL, + `report_subject` int(11) NOT NULL, + `report_subject_data` mediumtext, + `report_title` varchar(255) NOT NULL, + `report_desc` text NOT NULL, + PRIMARY KEY (`report_id`), + KEY `user_id` (`user_id`), + KEY `report_time` (`report_time`), + KEY `report_type_id` (`report_module_id`), + KEY `report_status` (`report_status`), + KEY `report_reason_id` (`report_reason_id`), + KEY `report_subject` (`report_subject`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_reports_changes` +-- + +CREATE TABLE `bb_reports_changes` ( + `report_change_id` mediumint(8) unsigned NOT NULL auto_increment, + `report_id` mediumint(8) unsigned NOT NULL, + `user_id` mediumint(8) NOT NULL, + `report_change_time` int(11) NOT NULL, + `report_status` tinyint(1) NOT NULL, + `report_change_comment` text NOT NULL, + PRIMARY KEY (`report_change_id`), + KEY `report_id` (`report_id`), + KEY `user_id` (`user_id`), + KEY `report_change_time` (`report_change_time`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_reports_modules` +-- + +CREATE TABLE `bb_reports_modules` ( + `report_module_id` mediumint(8) unsigned NOT NULL auto_increment, + `report_module_order` mediumint(8) unsigned NOT NULL, + `report_module_notify` tinyint(1) NOT NULL, + `report_module_prune` smallint(6) NOT NULL, + `report_module_last_prune` int(11) default NULL, + `report_module_name` varchar(50) NOT NULL, + `auth_write` tinyint(1) NOT NULL, + `auth_view` tinyint(1) NOT NULL, + `auth_notify` tinyint(1) NOT NULL, + `auth_delete` tinyint(1) NOT NULL, + PRIMARY KEY (`report_module_id`), + KEY `report_module_order` (`report_module_order`), + KEY `auth_view` (`auth_view`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ; + +-- +-- Дамп данных таблицы `bb_reports_modules` +-- + +INSERT INTO `bb_reports_modules` (`report_module_id`, `report_module_order`, `report_module_notify`, `report_module_prune`, `report_module_last_prune`, `report_module_name`, `auth_write`, `auth_view`, `auth_notify`, `auth_delete`) VALUES +(1, 1, 0, 0, NULL, 'report_general', 0, 1, 1, 1), +(2, 2, 0, 0, NULL, 'report_post', 0, 1, 1, 1), +(3, 3, 0, 0, NULL, 'report_topic', 0, 1, 1, 1), +(4, 4, 0, 0, NULL, 'report_user', 0, 1, 1, 1), +(5, 5, 0, 0, NULL, 'report_privmsg', 0, 1, 1, 1); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_reports_reasons` +-- + +CREATE TABLE `bb_reports_reasons` ( + `report_reason_id` mediumint(8) unsigned NOT NULL auto_increment, + `report_module_id` mediumint(8) unsigned NOT NULL, + `report_reason_order` mediumint(8) unsigned NOT NULL, + `report_reason_desc` varchar(255) NOT NULL, + PRIMARY KEY (`report_reason_id`), + KEY `report_type_id` (`report_module_id`), + KEY `report_reason_order` (`report_reason_order`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Структура таблицы `bb_search_rebuild` +-- + +CREATE TABLE `bb_search_rebuild` ( + `rebuild_session_id` mediumint(8) unsigned NOT NULL auto_increment, + `start_post_id` mediumint(8) unsigned NOT NULL default '0', + `end_post_id` mediumint(8) unsigned NOT NULL default '0', + `start_time` int(11) NOT NULL default '0', + `end_time` int(11) NOT NULL default '0', + `last_cycle_time` int(11) NOT NULL default '0', + `session_time` int(11) NOT NULL default '0', + `session_posts` mediumint(8) unsigned NOT NULL default '0', + `session_cycles` mediumint(8) unsigned NOT NULL default '0', + `search_size` int(10) unsigned NOT NULL default '0', + `rebuild_session_status` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`rebuild_session_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_search_results` +-- + +CREATE TABLE `bb_search_results` ( + `session_id` char(20) character set utf8 collate utf8_bin NOT NULL default '', + `search_type` tinyint(4) NOT NULL default '0', + `search_id` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', + `search_time` int(11) NOT NULL default '0', + `search_settings` text NOT NULL, + `search_array` text NOT NULL, + PRIMARY KEY (`session_id`,`search_type`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_sessions` +-- + +CREATE TABLE `bb_sessions` ( + `session_id` char(20) character set utf8 collate utf8_bin NOT NULL default '', + `session_user_id` mediumint(8) NOT NULL default '0', + `session_start` int(11) NOT NULL default '0', + `session_time` int(11) NOT NULL default '0', + `session_ip` char(32) character set utf8 collate utf8_bin NOT NULL default '', + `session_logged_in` tinyint(1) NOT NULL default '0', + `session_admin` tinyint(2) NOT NULL default '0', + PRIMARY KEY (`session_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_smilies` +-- + +CREATE TABLE `bb_smilies` ( + `smilies_id` smallint(5) unsigned NOT NULL auto_increment, + `code` varchar(50) NOT NULL default '', + `smile_url` varchar(100) NOT NULL default '', + `emoticon` varchar(75) NOT NULL default '', + PRIMARY KEY (`smilies_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=50 ; + +-- +-- Дамп данных таблицы `bb_smilies` +-- + +INSERT INTO `bb_smilies` VALUES (1, ':aa:', 'aa.gif', 'aa'); +INSERT INTO `bb_smilies` VALUES (2, ':ab:', 'ab.gif', 'ab'); +INSERT INTO `bb_smilies` VALUES (3, ':ac:', 'ac.gif', 'ac'); +INSERT INTO `bb_smilies` VALUES (4, ':ad:', 'ad.gif', 'ad'); +INSERT INTO `bb_smilies` VALUES (5, ':ae:', 'ae.gif', 'ae'); +INSERT INTO `bb_smilies` VALUES (6, ':af:', 'af.gif', 'af'); +INSERT INTO `bb_smilies` VALUES (7, ':ag:', 'ag.gif', 'ag'); +INSERT INTO `bb_smilies` VALUES (8, ':ah:', 'ah.gif', 'ah'); +INSERT INTO `bb_smilies` VALUES (9, ':ai:', 'ai.gif', 'ai'); +INSERT INTO `bb_smilies` VALUES (10, ':aj:', 'aj.gif', 'aj'); +INSERT INTO `bb_smilies` VALUES (11, ':ak:', 'ak.gif', 'ak'); +INSERT INTO `bb_smilies` VALUES (12, ':al:', 'al.gif', 'al'); +INSERT INTO `bb_smilies` VALUES (13, ':am:', 'am.gif', 'am'); +INSERT INTO `bb_smilies` VALUES (14, ':an:', 'an.gif', 'an'); +INSERT INTO `bb_smilies` VALUES (15, ':ao:', 'ao.gif', 'ao'); +INSERT INTO `bb_smilies` VALUES (16, ':ap:', 'ap.gif', 'ap'); +INSERT INTO `bb_smilies` VALUES (17, ':aq:', 'aq.gif', 'aq'); +INSERT INTO `bb_smilies` VALUES (18, ':ar:', 'ar.gif', 'ar'); +INSERT INTO `bb_smilies` VALUES (19, ':as:', 'as.gif', 'as'); +INSERT INTO `bb_smilies` VALUES (20, ':at:', 'at.gif', 'at'); +INSERT INTO `bb_smilies` VALUES (21, ':au:', 'au.gif', 'au'); +INSERT INTO `bb_smilies` VALUES (22, ':av:', 'av.gif', 'av'); +INSERT INTO `bb_smilies` VALUES (23, ':aw:', 'aw.gif', 'aw'); +INSERT INTO `bb_smilies` VALUES (24, ':ax:', 'ax.gif', 'ax'); +INSERT INTO `bb_smilies` VALUES (25, ':ay:', 'ay.gif', 'ay'); +INSERT INTO `bb_smilies` VALUES (26, ':az:', 'az.gif', 'az'); +INSERT INTO `bb_smilies` VALUES (27, ':ba:', 'ba.gif', 'ba'); +INSERT INTO `bb_smilies` VALUES (28, ':bb:', 'bb.gif', 'bb'); +INSERT INTO `bb_smilies` VALUES (29, ':bc:', 'bc.gif', 'bc'); +INSERT INTO `bb_smilies` VALUES (30, ':bd:', 'bd.gif', 'bd'); +INSERT INTO `bb_smilies` VALUES (31, ':be:', 'be.gif', 'be'); +INSERT INTO `bb_smilies` VALUES (32, ':bf:', 'bf.gif', 'bf'); +INSERT INTO `bb_smilies` VALUES (33, ':bg:', 'bg.gif', 'bg'); +INSERT INTO `bb_smilies` VALUES (34, ':bh:', 'bh.gif', 'bh'); +INSERT INTO `bb_smilies` VALUES (35, ':bi:', 'bi.gif', 'bi'); +INSERT INTO `bb_smilies` VALUES (36, ':bj:', 'bj.gif', 'bj'); +INSERT INTO `bb_smilies` VALUES (37, ':bk:', 'bk.gif', 'bk'); +INSERT INTO `bb_smilies` VALUES (38, ':bl:', 'bl.gif', 'bl'); +INSERT INTO `bb_smilies` VALUES (39, ':bm:', 'bm.gif', 'bm'); +INSERT INTO `bb_smilies` VALUES (40, ':bn:', 'bn.gif', 'bn'); +INSERT INTO `bb_smilies` VALUES (41, ':bo:', 'bo.gif', 'bo'); +INSERT INTO `bb_smilies` VALUES (42, ':bp:', 'bp.gif', 'bp'); +INSERT INTO `bb_smilies` VALUES (43, ':bq:', 'bq.gif', 'bq'); +INSERT INTO `bb_smilies` VALUES (44, ':br:', 'br.gif', 'br'); +INSERT INTO `bb_smilies` VALUES (45, ':bs:', 'bs.gif', 'bs'); +INSERT INTO `bb_smilies` VALUES (46, ':bt:', 'bt.gif', 'bt'); +INSERT INTO `bb_smilies` VALUES (47, ':bu:', 'bu.gif', 'bu'); +INSERT INTO `bb_smilies` VALUES (48, ':bv:', 'bv.gif', 'bv'); +INSERT INTO `bb_smilies` VALUES (49, ':bw:', 'bw.gif', 'bw'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_topics` +-- + +CREATE TABLE `bb_topics` ( + `topic_id` mediumint(8) unsigned NOT NULL auto_increment, + `forum_id` smallint(8) unsigned NOT NULL default '0', + `topic_title` varchar(250) NOT NULL default '', + `topic_poster` mediumint(8) NOT NULL default '0', + `topic_time` int(11) NOT NULL default '0', + `topic_views` mediumint(8) unsigned NOT NULL default '0', + `topic_replies` mediumint(8) unsigned NOT NULL default '0', + `topic_status` tinyint(3) NOT NULL default '0', + `topic_vote` tinyint(1) NOT NULL default '0', + `topic_type` tinyint(3) NOT NULL default '0', + `topic_first_post_id` mediumint(8) unsigned NOT NULL default '0', + `topic_last_post_id` mediumint(8) unsigned NOT NULL default '0', + `topic_moved_id` mediumint(8) unsigned NOT NULL default '0', + `topic_attachment` tinyint(1) NOT NULL default '0', + `topic_reported` tinyint(1) NOT NULL default '0', + `topic_dl_type` tinyint(1) NOT NULL default '0', + `topic_last_post_time` int(11) NOT NULL default '0', + PRIMARY KEY (`topic_id`), + KEY `forum_id` (`forum_id`), + KEY `topic_last_post_id` (`topic_last_post_id`), + KEY `topic_last_post_time` (`topic_last_post_time`), + FULLTEXT KEY `topic_title` (`topic_title`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; + +-- +-- Дамп данных таблицы `bb_topics` +-- + +INSERT INTO `bb_topics` VALUES (1, 1, 'Welcome to TorrentPier', 2, 972086460, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 972086460); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_topics_watch` +-- + +CREATE TABLE `bb_topics_watch` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_id` mediumint(8) NOT NULL default '0', + `notify_status` tinyint(1) NOT NULL default '0', + KEY `topic_id` (`topic_id`), + KEY `user_id` (`user_id`), + KEY `notify_status` (`notify_status`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_topic_templates` +-- + +CREATE TABLE `bb_topic_templates` ( + `tpl_id` smallint(6) NOT NULL auto_increment, + `tpl_name` varchar(20) NOT NULL default '', + `tpl_script` varchar(30) NOT NULL default '', + `tpl_template` varchar(30) NOT NULL default '', + `tpl_desc` varchar(255) NOT NULL default '', + PRIMARY KEY (`tpl_id`), + UNIQUE KEY `tpl_name` (`tpl_name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=15 ; + +-- +-- Дамп данных таблицы `bb_topic_templates` +-- + +INSERT INTO `bb_topic_templates` VALUES (1, 'video', 'video', 'video', 'Video (basic)'); +INSERT INTO `bb_topic_templates` VALUES (2, 'video_home', 'video', 'video_home', 'Video (home)'); +INSERT INTO `bb_topic_templates` VALUES (3, 'video_simple', 'video', 'video_simple', 'Video (simple)'); +INSERT INTO `bb_topic_templates` VALUES (4, 'video_lesson', 'video', 'video_lesson', 'Video (lesson)'); +INSERT INTO `bb_topic_templates` VALUES (5, 'games', 'games', 'games', 'Games'); +INSERT INTO `bb_topic_templates` VALUES (6, 'games_ps', 'games', 'games_ps', 'Games PS/PS2'); +INSERT INTO `bb_topic_templates` VALUES (7, 'games_psp', 'games', 'games_psp', 'Games PSP'); +INSERT INTO `bb_topic_templates` VALUES (8, 'games_xbox', 'games', 'games_xbox', 'Games XBOX'); +INSERT INTO `bb_topic_templates` VALUES (9, 'progs', 'progs', 'progs', 'Programs'); +INSERT INTO `bb_topic_templates` VALUES (10, 'progs_mac', 'progs', 'progs_mac', 'Programs Mac OS'); +INSERT INTO `bb_topic_templates` VALUES (11, 'music', 'music', 'music', 'Music'); +INSERT INTO `bb_topic_templates` VALUES (12, 'books', 'books', 'books', 'Books'); +INSERT INTO `bb_topic_templates` VALUES (13, 'audiobooks', 'audiobooks', 'audiobooks', 'Audiobooks'); +INSERT INTO `bb_topic_templates` VALUES (14, 'sport', 'sport', 'sport', 'Sport'); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_users` +-- + +CREATE TABLE `bb_users` ( + `user_id` mediumint(8) NOT NULL auto_increment, + `user_active` tinyint(1) NOT NULL default '1', + `username` varchar(25) NOT NULL default '', + `user_password` varchar(32) character set utf8 collate utf8_bin NOT NULL default '', + `user_session_time` int(11) NOT NULL default '0', + `user_lastvisit` int(11) NOT NULL default '0', + `user_last_ip` CHAR(32) NOT NULL default '', + `user_regdate` int(11) NOT NULL default '0', + `user_reg_ip` CHAR(32) NOT NULL default '', + `user_level` tinyint(4) NOT NULL default '0', + `user_posts` mediumint(8) unsigned NOT NULL default '0', + `user_timezone` decimal(5,2) NOT NULL default '0.00', + `user_lang` varchar(255) NOT NULL default '', + `user_dateformat` varchar(14) NOT NULL default '', + `user_new_privmsg` smallint(5) unsigned NOT NULL default '0', + `user_unread_privmsg` smallint(5) unsigned NOT NULL default '0', + `user_last_privmsg` int(11) NOT NULL default '0', + `user_opt` int(11) NOT NULL default '0', + `user_allowavatar` tinyint(1) NOT NULL default '1', + `user_allow_pm` tinyint(1) NOT NULL default '1', + `user_allow_viewonline` tinyint(1) NOT NULL default '1', + `user_notify` tinyint(1) NOT NULL default '1', + `user_notify_pm` tinyint(1) NOT NULL default '0', + `user_rank` int(11) NOT NULL default '0', + `user_avatar` varchar(100) NOT NULL default '', + `user_avatar_type` tinyint(4) NOT NULL default '0', + `user_email` varchar(255) NOT NULL default '', + `user_icq` varchar(15) NOT NULL default '', + `user_website` varchar(100) NOT NULL default '', + `user_from` varchar(100) NOT NULL default '', + `user_sig` text NOT NULL, + `user_sig_bbcode_uid` varchar(10) NOT NULL default '', + `user_occ` varchar(100) NOT NULL default '', + `user_interests` varchar(255) NOT NULL default '', + `user_actkey` varchar(32) NOT NULL default '', + `user_newpasswd` varchar(32) NOT NULL default '', + `user_allow_passkey` tinyint(1) NOT NULL default '1', + `user_from_flag` varchar(3) NOT NULL default '', + `ignore_srv_load` tinyint(1) NOT NULL default '0', + `autologin_id` varchar(12) character set utf8 collate utf8_bin NOT NULL default '', + `user_newest_pm_id` mediumint(8) NOT NULL default '0', + PRIMARY KEY (`user_id`), + KEY `username` (`username`(10)), + KEY `user_email` (`user_email`(10)), + KEY `user_level` (`user_level`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; + +-- +-- Дамп данных таблицы `bb_users` +-- + +INSERT INTO `bb_users` VALUES (-1, 0, 'Anonymous', '', 0, 0, 0, 1117103663, 0, 0, 0, 0.00, '', '', 0, 0, 0, 220, 1, 0, 1, 0, 1, 0, '', 0, '', '', '', '', '', '', '', '', '', '', 1, '', 0, '', 0); +INSERT INTO `bb_users` VALUES (2, 1, 'admin', 0x3231323332663239376135376135613734333839346130653461383031666333, 1211472784, 1210263184, 0, 1117103663, 0, 1, 1, 0.00, '', '', 0, 0, 1211472803, 159, 1, 1, 1, 0, 1, 1, '', 0, 'admin@admin.com', '', '', '', '', '', '', '', '', '', 1, '', 0, 0x4f5750316d724533314b7335, 0); +INSERT INTO `bb_users` VALUES (-746, 0, 'bot', '', 1117115716, 1117115634, 0, 1117114766, 0, 0, 0, 0.00, '', '', 0, 0, 0, 148, 1, 1, 1, 0, 0, 0, 'bot.gif', 1, 'bot@bot.bot', '', '', '', '', '', '', '', '', '', 1, '', 0, '', 0); + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_user_group` +-- + +CREATE TABLE `bb_user_group` ( + `group_id` mediumint(8) NOT NULL default '0', + `user_id` mediumint(8) NOT NULL default '0', + `user_pending` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`group_id`,`user_id`), + KEY `user_id` (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_vote_desc` +-- + +CREATE TABLE `bb_vote_desc` ( + `vote_id` mediumint(8) unsigned NOT NULL auto_increment, + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `vote_text` text NOT NULL, + `vote_start` int(11) NOT NULL default '0', + `vote_length` int(11) NOT NULL default '0', + PRIMARY KEY (`vote_id`), + KEY `topic_id` (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_vote_results` +-- + +CREATE TABLE `bb_vote_results` ( + `vote_id` mediumint(8) unsigned NOT NULL default '0', + `vote_option_id` tinyint(4) unsigned NOT NULL default '0', + `vote_option_text` varchar(255) NOT NULL default '', + `vote_result` int(11) NOT NULL default '0', + KEY `vote_option_id` (`vote_option_id`), + KEY `vote_id` (`vote_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_vote_voters` +-- + +CREATE TABLE `bb_vote_voters` ( + `vote_id` mediumint(8) unsigned NOT NULL default '0', + `vote_user_id` mediumint(8) NOT NULL default '0', + `vote_user_ip` char(32) NOT NULL default '', + KEY `vote_id` (`vote_id`), + KEY `vote_user_id` (`vote_user_id`), + KEY `vote_user_ip` (`vote_user_ip`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `bb_words` +-- + +CREATE TABLE `bb_words` ( + `word_id` mediumint(8) unsigned NOT NULL auto_increment, + `word` char(100) NOT NULL default '', + `replacement` char(100) NOT NULL default '', + PRIMARY KEY (`word_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `buf_last_seeder` +-- + +CREATE TABLE `buf_last_seeder` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `seeder_last_seen` int(11) NOT NULL default '0', + PRIMARY KEY (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `buf_topic_view` +-- + +CREATE TABLE `buf_topic_view` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `topic_views` mediumint(8) unsigned NOT NULL default '0', + PRIMARY KEY (`topic_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Структура таблицы `sph_counter` +-- + +CREATE TABLE IF NOT EXISTS `sph_counter` ( + `counter_id` int(11) NOT NULL, + `max_doc_id` int(11) NOT NULL, + PRIMARY KEY (`counter_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- diff --git a/install/xbt/linux/Tracker/CMakeLists.txt b/install/xbt/linux/Tracker/CMakeLists.txt new file mode 100644 index 000000000..93d1f9eec --- /dev/null +++ b/install/xbt/linux/Tracker/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) +set(CMAKE_BUILD_TYPE release) +include_directories(. ../misc) +include(CheckIncludeFileCXX) +check_include_file_cxx(sys/epoll.h HAVE_SYS_EPOLL) +if(HAVE_SYS_EPOLL) + add_definitions(-DEPOLL) +endif() +add_executable( + xbt_tracker + ../misc/sql/database.cpp + ../misc/sql/sql_query.cpp + ../misc/sql/sql_result.cpp + ../misc/bt_misc.cpp + ../misc/bvalue.cpp + ../misc/sha1.cpp + ../misc/socket.cpp + ../misc/virtual_binary.cpp + ../misc/xcc_z.cpp + config.cpp + connection.cpp + epoll.cpp + server.cpp + tcp_listen_socket.cpp + tracker_input.cpp + transaction.cpp + udp_listen_socket.cpp + "XBT Tracker.cpp" +) +target_link_libraries(xbt_tracker mysqlclient) diff --git a/install/xbt/linux/Tracker/XBT Tracker.cpp b/install/xbt/linux/Tracker/XBT Tracker.cpp new file mode 100644 index 000000000..9c4587ffe --- /dev/null +++ b/install/xbt/linux/Tracker/XBT Tracker.cpp @@ -0,0 +1,135 @@ +#include "stdafx.h" +#include +#include +#include "config.h" +#include "server.h" + +std::string g_conf_file = "xbt_tracker.conf"; +const char* g_service_name = "XBT Tracker"; + +int main1() +{ + srand(static_cast(time(NULL))); + Cconfig config; + if (config.load(g_conf_file)) +#ifdef WIN32 + { + char b[MAX_PATH]; + *b = 0; + GetModuleFileName(NULL, b, MAX_PATH); + if (*b) + strrchr(b, '\\')[1] = 0; + strcat(b, "xbt_tracker.conf"); + if (config.load(b)) + std::cerr << "Unable to read " << g_conf_file << std::endl; + else + g_conf_file = b; + } +#else + std::cerr << "Unable to read " << g_conf_file << std::endl; +#endif + Cdatabase database; + try + { + if (config.m_mysql_host != "-") + database.open(config.m_mysql_host, config.m_mysql_user, config.m_mysql_password, config.m_mysql_database, true); + } + catch (Cdatabase::exception& e) + { + std::cerr << e.what() << std::endl; + return 1; + } + database.set_query_log(config.m_query_log); + return Cserver(database, config.m_mysql_table_prefix, config.m_mysql_host != "-", g_conf_file).run(); +} + +#ifdef WIN32 +static SERVICE_STATUS g_service_status; +static SERVICE_STATUS_HANDLE gh_service_status; + +void WINAPI nt_service_handler(DWORD op) +{ + switch (op) + { + case SERVICE_CONTROL_STOP: + g_service_status.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(gh_service_status, &g_service_status); + Cserver::term(); + break; + } + SetServiceStatus(gh_service_status, &g_service_status); +} + +void WINAPI nt_service_main(DWORD argc, LPTSTR* argv) +{ + g_service_status.dwCheckPoint = 0; + g_service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + g_service_status.dwCurrentState = SERVICE_START_PENDING; + g_service_status.dwServiceSpecificExitCode = 0; + g_service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_service_status.dwWaitHint = 0; + g_service_status.dwWin32ExitCode = NO_ERROR; + if (!(gh_service_status = RegisterServiceCtrlHandler(g_service_name, nt_service_handler))) + return; + SetServiceStatus(gh_service_status, &g_service_status); + g_service_status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(gh_service_status, &g_service_status); + main1(); + g_service_status.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(gh_service_status, &g_service_status); +} +#endif + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + if (argc >= 2) + { + if (!strcmp(argv[1], "--install")) + { + if (nt_service_install(g_service_name)) + { + std::cerr << "Failed to install service " << g_service_name << "." << std::endl; + return 1; + } + std::cout << "Service " << g_service_name << " has been installed." << std::endl; + return 0; + } + else if (!strcmp(argv[1], "--uninstall")) + { + if (nt_service_uninstall(g_service_name)) + { + std::cerr << "Failed to uninstall service " << g_service_name << "." << std::endl; + return 1; + } + std::cout << "Service " << g_service_name << " has been uninstalled." << std::endl; + return 0; + } + else if (!strcmp(argv[1], "--conf_file") && argc >= 3) + g_conf_file = argv[2]; + else + return 1; + } +#ifdef NDEBUG + SERVICE_TABLE_ENTRY st[] = + { + { "", nt_service_main }, + { NULL, NULL } + }; + if (StartServiceCtrlDispatcher(st)) + return 0; + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED + && GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) + return 1; +#endif +#else + if (argc >= 2) + { + if (!strcmp(argv[1], "--conf_file") && argc >= 3) + g_conf_file = argv[2]; + else + return 1; + } +#endif + return main1(); +} diff --git a/install/xbt/linux/Tracker/XBT Tracker.nsi b/install/xbt/linux/Tracker/XBT Tracker.nsi new file mode 100644 index 000000000..19b998665 --- /dev/null +++ b/install/xbt/linux/Tracker/XBT Tracker.nsi @@ -0,0 +1,46 @@ +!define VERSION "0.3.0" + +Name "XBT Tracker ${VERSION}" +Outfile "XBT_Tracker-${VERSION}.exe" +InstallDir "$PROGRAMFILES\XBT\Tracker" +InstallDirRegKey HKLM "Software\XBT\Tracker" "InstallDir" +XPStyle on +Page directory +Page instfiles +UninstPage uninstConfirm +UninstPage instfiles + +Section "Install" + SetShellVarContext all + SetOutPath "$INSTDIR" + + Delete "$INSTDIR\XBT Tracker.exe" + Delete "$INSTDIR\XBT Tracker Old.exe" + Rename "$INSTDIR\XBT Tracker.exe" "$INSTDIR\XBT Tracker Old.exe" + File "release\XBT Tracker.exe" + File xbt_tracker.conf.default + File xbt_tracker.sql + SetOverwrite off + File /oname=xbt_tracker.conf xbt_tracker.conf.default + SetOutPath "$INSTDIR\htdocs" + File htdocs\* + Exec "$INSTDIR\XBT Tracker.exe --install" + WriteUninstaller "$INSTDIR\Uninstall.exe" + CreateShortCut "$SMPROGRAMS\XBT Tracker.lnk" "$INSTDIR\XBT Tracker.exe" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\XBT Tracker" "DisplayName" "XBT Tracker ${VERSION}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\XBT Tracker" "UninstallString" '"$INSTDIR\Uninstall.exe"' + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\XBT Tracker" "NoModify" 1 + WriteRegStr HKLM "Software\XBT\Tracker" "InstallDir" "$INSTDIR" +SectionEnd + +Section "Uninstall" + SetShellVarContext all + ExecWait 'net stop "XBT Tracker"' + ExecWait "$INSTDIR\XBT Tracker.exe --uninstall" + Delete "$SMPROGRAMS\XBT Tracker.lnk" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\XBT Tracker" + DeleteRegKey HKLM "Software\XBT\Tracker" + DeleteRegKey /ifempty HKLM "Software\XBT" + RMDir /r "$PROGRAMFILES\XBT\Tracker" + RMDir "$PROGRAMFILES\XBT" +SectionEnd diff --git a/install/xbt/linux/Tracker/XBT Tracker.rc b/install/xbt/linux/Tracker/XBT Tracker.rc new file mode 100644 index 000000000..c7dafe654 --- /dev/null +++ b/install/xbt/linux/Tracker/XBT Tracker.rc @@ -0,0 +1,3 @@ +#include "resource.h" + +IDR_MAINFRAME ICON "res\\XBT Tracker.ico" diff --git a/install/xbt/linux/Tracker/XBT Tracker.sln b/install/xbt/linux/Tracker/XBT Tracker.sln new file mode 100644 index 000000000..59cf16a96 --- /dev/null +++ b/install/xbt/linux/Tracker/XBT Tracker.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XBT Tracker", "XBT Tracker.vcproj", "{73C570AC-E7C3-451D-A5C6-7A2532F0121B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {73C570AC-E7C3-451D-A5C6-7A2532F0121B}.Debug|Win32.ActiveCfg = Debug|Win32 + {73C570AC-E7C3-451D-A5C6-7A2532F0121B}.Debug|Win32.Build.0 = Debug|Win32 + {73C570AC-E7C3-451D-A5C6-7A2532F0121B}.Release|Win32.ActiveCfg = Release|Win32 + {73C570AC-E7C3-451D-A5C6-7A2532F0121B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/install/xbt/linux/Tracker/XBT Tracker.vcproj b/install/xbt/linux/Tracker/XBT Tracker.vcproj new file mode 100644 index 000000000..9e4b290e2 --- /dev/null +++ b/install/xbt/linux/Tracker/XBT Tracker.vcproj @@ -0,0 +1,709 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/install/xbt/linux/Tracker/XBT Tracker.vcxproj b/install/xbt/linux/Tracker/XBT Tracker.vcxproj new file mode 100644 index 000000000..5e56f4abd --- /dev/null +++ b/install/xbt/linux/Tracker/XBT Tracker.vcxproj @@ -0,0 +1,265 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {73C570AC-E7C3-451D-A5C6-7A2532F0121B} + XBT Tracker + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + + + + + + MaxSpeed + OnlyExplicitInline + true + ..\misc;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + Use + stdafx.h + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0413 + + + zlib.lib;%(AdditionalDependencies) + Console + UseLinkTimeCodeGeneration + false + + + MachineX86 + + + + + + + + + Disabled + ..\misc;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + stdafx.h + Level1 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0413 + + + zlib.lib;%(AdditionalDependencies) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + Console + false + + + MachineX86 + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + Create + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + Create + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/install/xbt/linux/Tracker/client.h b/install/xbt/linux/Tracker/client.h new file mode 100644 index 000000000..3f6f9eadf --- /dev/null +++ b/install/xbt/linux/Tracker/client.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +class Cserver; + +class Cclient +{ +public: + virtual void process_events(int) = 0; + virtual ~Cclient() + { + } +protected: + const Csocket& s() const + { + return m_s; + } + + void s(const Csocket& s) + { + m_s = s; + } + + Csocket m_s; + Cserver* m_server; +}; diff --git a/install/xbt/linux/Tracker/config.cpp b/install/xbt/linux/Tracker/config.cpp new file mode 100644 index 000000000..0f19cf731 --- /dev/null +++ b/install/xbt/linux/Tracker/config.cpp @@ -0,0 +1,146 @@ +#include "stdafx.h" +#include "config.h" + +#include +#include + +Cconfig::Cconfig() +{ + fill_maps(NULL); +} + +Cconfig::Cconfig(const Cconfig& v) +{ + fill_maps(&v); +} + +const Cconfig& Cconfig::operator=(const Cconfig& v) +{ + fill_maps(&v); + return *this; +} + +void Cconfig::fill_maps(const Cconfig* v) +{ + { + t_attribute attributes[] = + { + "auto_register", &m_auto_register, false, + "anonymous_connect", &m_anonymous_connect, true, + "anonymous_announce", &m_anonymous_announce, true, + "anonymous_scrape", &m_anonymous_scrape, true, + "daemon", &m_daemon, true, + "debug", &m_debug, false, + "full_scrape", &m_full_scrape, false, + "gzip_debug", &m_gzip_debug, true, + "gzip_scrape", &m_gzip_scrape, true, + "log_access", &m_log_access, false, + "log_announce", &m_log_announce, false, + "log_scrape", &m_log_scrape, false, + + // TorrentPier begin + "gdc", &m_gdc, true, + "free_leech", &m_free_leech, false, + "trust_ipv6", &m_trust_ipv6, false, + // TorrentPier end + + NULL + }; + fill_map(attributes, v ? &v->m_attributes_bool : NULL, m_attributes_bool); + } + { + t_attribute attributes[] = + { + "announce_interval", &m_announce_interval, 1800, + "clean_up_interval", &m_clean_up_interval, 60, + "read_config_interval", &m_read_config_interval, 60, + "read_db_interval", &m_read_db_interval, 60, + "scrape_interval", &m_scrape_interval, 0, + "write_db_interval", &m_write_db_interval, 15, + + // TorrentPier begin + "cheat_upload", &m_cheat_upload, 18, + "read_files_interval", &m_read_files_interval, 60, + // TorrentPier end + + NULL + }; + fill_map(attributes, v ? &v->m_attributes_int : NULL, m_attributes_int); + } + { + t_attribute attributes[] = + { + "column_files_completed", &m_column_files_completed, "completed", + "column_files_fid", &m_column_files_fid, "fid", + "column_files_leechers", &m_column_files_leechers, "leechers", + "column_files_seeders", &m_column_files_seeders, "seeders", + "column_users_uid", &m_column_users_uid, "uid", + "mysql_database", &m_mysql_database, "xbt", + "mysql_host", &m_mysql_host, "localhost", + "mysql_password", &m_mysql_password, "", + "mysql_table_prefix", &m_mysql_table_prefix, "xbt_", + "mysql_user", &m_mysql_user, "", + "offline_message", &m_offline_message, "", + "pid_file", &m_pid_file, "", + "query_log", &m_query_log, "", + "redirect_url", &m_redirect_url, "", + "table_announce_log", &m_table_announce_log, "", + "table_deny_from_hosts", &m_table_deny_from_hosts, "", + "table_files", &m_table_files, "", + "table_files_users", &m_table_files_users, "", + "table_scrape_log", &m_table_scrape_log, "", + "table_users", &m_table_users, "", + "torrent_pass_private_key", &m_torrent_pass_private_key, "", + + // TorrentPier begin + "column_files_dl_percent", &m_column_files_dl_percent, "", + "column_users_can_leech", &m_column_users_can_leech, "", + "column_users_torrents_limit", &m_column_users_torrents_limit, "", + // TorrentPier end + + NULL, NULL, "" + }; + fill_map(attributes, v ? &v->m_attributes_string : NULL, m_attributes_string); + } + if (v) + { + m_listen_ipas = v->m_listen_ipas; + m_listen_ports = v->m_listen_ports; + } +} + +int Cconfig::set(const std::string& name, const std::string& value) +{ + if (t_attribute* i = find_ptr(m_attributes_string, name)) + *i->value = value; + else if (name == "listen_ipa") + + // TorrentPier begin + m_listen_ipas.insert(value); + else if (name == "listen_port") + m_listen_ports.insert(value); + // TorrentPier end + + else + return set(name, atoi(value.c_str())); + return 0; +} + +int Cconfig::set(const std::string& name, int value) +{ + if (t_attribute* i = find_ptr(m_attributes_int, name)) + *i->value = value; + // TorrentPier // listen_port + else + return set(name, static_cast(value)); + return 0; +} + +int Cconfig::set(const std::string& name, bool value) +{ + if (t_attribute* i = find_ptr(m_attributes_bool, name)) + *i->value = value; + else + return 1; + return 0; +} diff --git a/install/xbt/linux/Tracker/config.h b/install/xbt/linux/Tracker/config.h new file mode 100644 index 000000000..0a309c305 --- /dev/null +++ b/install/xbt/linux/Tracker/config.h @@ -0,0 +1,75 @@ +#pragma once + +#include + +class Cconfig: public Cconfig_base +{ +public: + // TorrentPier begin + typedef std::set t_listen_ipas; + typedef std::set t_listen_ports; + // TorrentPier end + + int set(const std::string& name, const std::string& value); + int set(const std::string& name, int value); + int set(const std::string& name, bool value); + Cconfig(); + Cconfig(const Cconfig&); + const Cconfig& operator=(const Cconfig&); + + bool m_anonymous_announce; + bool m_anonymous_connect; + bool m_anonymous_scrape; + bool m_auto_register; + bool m_daemon; + bool m_debug; + bool m_full_scrape; + bool m_gzip_debug; + bool m_gzip_scrape; + bool m_log_access; + bool m_log_announce; + bool m_log_scrape; + int m_announce_interval; + int m_clean_up_interval; + int m_read_config_interval; + int m_read_db_interval; + int m_scrape_interval; + int m_write_db_interval; + std::string m_column_files_completed; + std::string m_column_files_fid; + std::string m_column_files_leechers; + std::string m_column_files_seeders; + std::string m_column_users_uid; + std::string m_mysql_database; + std::string m_mysql_host; + std::string m_mysql_password; + std::string m_mysql_table_prefix; + std::string m_mysql_user; + std::string m_offline_message; + std::string m_query_log; + std::string m_pid_file; + std::string m_redirect_url; + std::string m_table_announce_log; + std::string m_table_deny_from_hosts; + std::string m_table_files; + std::string m_table_files_users; + std::string m_table_scrape_log; + std::string m_table_users; + std::string m_torrent_pass_private_key; + t_listen_ipas m_listen_ipas; + t_listen_ports m_listen_ports; + + // TorrentPier begin + bool m_gdc; + bool m_free_leech; + std::string m_column_files_dl_percent; + std::string m_column_users_can_leech; + std::string m_column_users_torrents_limit; + int m_read_files_interval; + bool m_trust_ipv6; + int m_cheat_upload; + // TorrentPier end + +private: + void fill_maps(const Cconfig*); +}; diff --git a/install/xbt/linux/Tracker/connection.cpp b/install/xbt/linux/Tracker/connection.cpp new file mode 100644 index 000000000..ced4adf70 --- /dev/null +++ b/install/xbt/linux/Tracker/connection.cpp @@ -0,0 +1,339 @@ +#include "stdafx.h" +#include "connection.h" + +#include +#include +#include +#include +#include +#include "server.h" + +// TorrentPier begin + +#ifdef WIN32 +#include +#endif + +#define PASS_SIZE1 10 +#define PASS_SIZE2 32 + +Cconnection::Cconnection(Cserver* server, const Csocket& s, const sockaddr_storage& a) +// TorrentPier end +{ + m_server = server; + m_s = s; + m_a = a; + m_ctime = server->time(); + + m_state = 0; + m_r.clear(); + m_w = m_read_b; +} + +int Cconnection::pre_select(fd_set* fd_read_set, fd_set* fd_write_set) +{ + FD_SET(m_s, fd_read_set); + if (!m_r.empty()) + FD_SET(m_s, fd_write_set); + return m_s; +} + +int Cconnection::post_select(fd_set* fd_read_set, fd_set* fd_write_set) +{ + return FD_ISSET(m_s, fd_read_set) && recv() + || FD_ISSET(m_s, fd_write_set) && send() + || m_server->time() - m_ctime > 10 + || m_state == 5 && m_r.empty(); +} + +int Cconnection::recv() +{ + int r = m_s.recv(m_w); + if (!r) + { + m_state = 5; + return 0; + } + if (r == SOCKET_ERROR) + { + int e = WSAGetLastError(); + switch (e) + { + case WSAECONNABORTED: + case WSAECONNRESET: + return 1; + case WSAEWOULDBLOCK: + return 0; + } + std::cerr << "recv failed: " << Csocket::error2a(e) << std::endl; + return 1; + } + if (m_state == 5) + return 0; + const unsigned char* a = m_w; + m_w += r; + int state; + do + { + state = m_state; + while (a < m_w && *a != '\n' && *a != '\r') + { + a++; + if (m_state) + m_state = 1; + } + if (a < m_w) + { + switch (m_state) + { + case 0: + read(std::string(&m_read_b.front(), reinterpret_cast(a) - &m_read_b.front())); + m_state = 1; + case 1: + case 3: + m_state += *a == '\n' ? 2 : 1; + break; + case 2: + case 4: + m_state++; + break; + } + a++; + } + } + while (state != m_state); + return 0; +} + +int Cconnection::send() +{ + if (m_r.empty()) + return 0; + int r = m_s.send(m_r); + if (r == SOCKET_ERROR) + { + int e = WSAGetLastError(); + switch (e) + { + case WSAECONNABORTED: + case WSAECONNRESET: + return 1; + case WSAEWOULDBLOCK: + return 0; + } + std::cerr << "send failed: " << Csocket::error2a(e) << std::endl; + return 1; + } + m_r += r; + if (m_r.empty()) + m_write_b.clear(); + return 0; +} + +void Cconnection::read(const std::string& v) +{ +#ifndef NDEBUG + std::cout << v << std::endl; +#endif + if (m_server->config().m_log_access) + { + // TorrentPier begin + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + if (!getnameinfo(reinterpret_cast(&m_a), sizeof(m_a), hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { + static std::ofstream f("xbt_tracker_raw.log"); + f << m_server->time() << '\t' << hbuf << '\t' << sbuf << '\t' << v << std::endl; + } + } + Ctracker_input ti(m_a.ss_family); + // TorrentPier end + + size_t e = v.find('?'); + if (e == std::string::npos) + e = v.size(); + else + { + size_t a = e + 1; + size_t b = v.find(' ', a); + if (b == std::string::npos) + return; + while (a < b) + { + // TorrentPier begin + if( v[a] == '&' || v[a] == '?' ) { a++; continue; } // "&&?" hack + // TorrentPier end + + size_t c = v.find('=', a); + if (c++ == std::string::npos) + break; + size_t d = v.find_first_of(" &", c); + if (d == std::string::npos) + break; + ti.set(v.substr(a, c - a - 1), uri_decode(v.substr(c, d - c))); + a = d + 1; + } + } + + // TorrentPier begin + if (m_a.ss_family == AF_INET) { + sockaddr_in *b = reinterpret_cast(&m_a); + if (!ti.m_ipa || !is_private_ipa(b->sin_addr.s_addr)) + ti.m_ipa = b->sin_addr.s_addr; + } else if (m_a.ss_family == AF_INET6) { + sockaddr_in6 *b = reinterpret_cast(&m_a); + ti.m_ipv6set = true; + memcpy(ti.m_ipv6bin, &(b->sin6_addr), 16); + } + + std::string torrent_pass0 = ti.m_passkey; + // TorrentPier end + + size_t a = 4; + if (a < e && v[a] == '/') + { + do { a++; + } while (a < e && v[a] == '/'); + if (a + 1 < e && v[a + 1] == '/') + a += 2; + + // TorrentPier begin + if (a + 2 < e && v[a + 2] == '/') // Skip "/bt/" + a += 3; + + if (a + PASS_SIZE1 < e && v[a + PASS_SIZE1] == '/') + { + torrent_pass0 = v.substr(a, PASS_SIZE1); + a += PASS_SIZE1+1; + } + + if (a + PASS_SIZE2 < e && v[a + PASS_SIZE2] == '/') + { + torrent_pass0 = v.substr(a, PASS_SIZE2); + a += PASS_SIZE2+1; + } + // TorrentPier end + } + std::string h = "HTTP/1.0 200 OK\r\n"; + Cvirtual_binary s; + bool gzip = true; + switch (a < v.size() ? v[a] : 0) + { + case 'a': + if (!ti.valid()) + break; + gzip = false; + if (ti.banned()) + s = Cbvalue().d(bts_failure_reason, bts_banned_client).read(); + else if (0) + s = Cbvalue().d(bts_failure_reason, bts_banned_client).read(); + else + { + std::string error = m_server->insert_peer(ti, false, m_server->find_user_by_torrent_pass(torrent_pass0, ti.m_info_hash)); + s = error.empty() ? m_server->select_peers(ti) : Cbvalue().d(bts_failure_reason, error).read(); + } + break; + case 'd': + if (m_server->config().m_debug) + { + gzip = m_server->config().m_gzip_debug; + h += "Content-Type: text/html; charset=us-ascii\r\n"; + s = Cvirtual_binary(m_server->debug(ti)); + } + break; + case 's': + if (v.size() >= 7 && v[6] == 't') + { + gzip = m_server->config().m_gzip_debug; + h += "Content-Type: text/html; charset=us-ascii\r\n"; + s = Cvirtual_binary(m_server->statistics()); + } + else if (m_server->config().m_full_scrape || ti.m_compact || !ti.m_info_hash.empty()) + { + gzip = m_server->config().m_gzip_scrape && !ti.m_compact && ti.m_info_hash.empty(); + s = m_server->scrape(ti); + } + break; + } + if (s.empty()) + { + if (!ti.m_peer_id.empty() || m_server->config().m_redirect_url.empty()) + h = "HTTP/1.0 404 Not Found\r\n"; + else + { + h = "HTTP/1.0 302 Found\r\n" + "Location: " + m_server->config().m_redirect_url + (ti.m_info_hash.empty() ? "" : "?info_hash=" + uri_encode(ti.m_info_hash)) + "\r\n"; + } + } + else if (gzip) + { + Cvirtual_binary s2 = xcc_z::gzip(s); +#ifndef NDEBUG + static std::ofstream f("xbt_tracker_gzip.log"); + f << m_server->time() << '\t' << v[5] << '\t' << s.size() << '\t' << s2.size() << std::endl; +#endif + if (s2.size() + 24 < s.size()) + { + h += "Content-Encoding: gzip\r\n"; + s = s2; + } + } + h += "\r\n"; +#ifdef WIN32 + m_write_b.resize(h.size() + s.size()); + memcpy(m_write_b.data_edit(), h.data(), h.size()); + s.read(m_write_b.data_edit() + h.size()); + int r = m_s.send(m_write_b); +#else + boost::array d; + d[0].iov_base = const_cast(h.data()); + d[0].iov_len = h.size(); + d[1].iov_base = const_cast(s.data()); + d[1].iov_len = s.size(); + msghdr m; + m.msg_name = NULL; + m.msg_namelen = 0; + m.msg_iov = const_cast(d.data()); + m.msg_iovlen = d.size(); + m.msg_control = NULL; + m.msg_controllen = 0; + m.msg_flags = 0; + int r = sendmsg(m_s, &m, MSG_NOSIGNAL); +#endif + if (r == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAECONNRESET) + std::cerr << "send failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + } + else if (r != h.size() + s.size()) + { +#ifndef WIN32 + if (r < h.size()) + { + m_write_b.resize(h.size() + s.size()); + memcpy(m_write_b.data_edit(), h.data(), h.size()); + s.read(m_write_b.data_edit() + h.size()); + } + else + { + m_write_b = s; + r -= h.size(); + } +#endif + m_r = m_write_b; + m_r += r; + } + if (m_r.empty()) + m_write_b.clear(); +} + +void Cconnection::process_events(int events) +{ + if (events & (EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP) && recv() + || events & EPOLLOUT && send() + || m_state == 5 && m_write_b.empty()) + m_s.close(); +} + +int Cconnection::run() +{ + return s() == INVALID_SOCKET || m_server->time() - m_ctime > 10; +} diff --git a/install/xbt/linux/Tracker/connection.h b/install/xbt/linux/Tracker/connection.h new file mode 100644 index 000000000..9bdba027a --- /dev/null +++ b/install/xbt/linux/Tracker/connection.h @@ -0,0 +1,33 @@ +#pragma once + +#include "client.h" +#include +#include + +class Cserver; + +class Cconnection: public Cclient, boost::noncopyable +{ +public: + Cclient::s; + int run(); + void read(const std::string&); + int recv(); + int send(); + virtual void process_events(int); + int pre_select(fd_set* fd_read_set, fd_set* fd_write_set); + int post_select(fd_set* fd_read_set, fd_set* fd_write_set); + + // TorrentPier begin + Cconnection(Cserver*, const Csocket&, const sockaddr_storage&); +private: + sockaddr_storage m_a; + // TorrentPier end + + time_t m_ctime; + int m_state; + boost::array m_read_b; + Cvirtual_binary m_write_b; + const_memory_range m_r; + memory_range m_w; +}; diff --git a/install/xbt/linux/Tracker/epoll.cpp b/install/xbt/linux/Tracker/epoll.cpp new file mode 100644 index 000000000..cce7bed39 --- /dev/null +++ b/install/xbt/linux/Tracker/epoll.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "epoll.h" + +Cepoll::Cepoll() +{ + m_fd = -1; +} + +Cepoll::~Cepoll() +{ +#ifdef EPOLL + if (m_fd != -1) + close(m_fd); +#endif +} + +int Cepoll::create(int size) +{ +#ifdef EPOLL + return m_fd = epoll_create(size); +#else + return 0; +#endif +} + +int Cepoll::ctl(int op, int fd, int events, void* p) +{ +#ifdef EPOLL + epoll_event e; + e.data.ptr = p; + e.events = events; + return epoll_ctl(m_fd, op, fd, &e); +#else + return 0; +#endif +} + +int Cepoll::wait(epoll_event* events, int maxevents, int timeout) +{ +#ifdef EPOLL + return epoll_wait(m_fd, events, maxevents, timeout); +#else + return 0; +#endif +} diff --git a/install/xbt/linux/Tracker/epoll.h b/install/xbt/linux/Tracker/epoll.h new file mode 100644 index 000000000..6aa9b7198 --- /dev/null +++ b/install/xbt/linux/Tracker/epoll.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#ifdef EPOLL +#include +#else +enum +{ + EPOLLIN = 1, + EPOLLOUT = 2, + EPOLLPRI = 4, + EPOLLERR = 8, + EPOLLHUP = 0x10, + EPOLLET = 0x20, + EPOLLONESHOT = 0x40, +}; + +enum +{ + EPOLL_CTL_ADD = 1, + EPOLL_CTL_MOD = 2, + EPOLL_CTL_DEL = 4, +}; + +typedef void epoll_event; +#endif + +class Cepoll: boost::noncopyable +{ +public: + int create(int size); + int ctl(int op, int fd, int events, void* p); + int wait(epoll_event* events, int maxevents, int timeout); + Cepoll(); + ~Cepoll(); +private: + int m_fd; +}; diff --git a/install/xbt/linux/Tracker/make.bsd.google_perftools.sh b/install/xbt/linux/Tracker/make.bsd.google_perftools.sh new file mode 100644 index 000000000..f69d1bdce --- /dev/null +++ b/install/xbt/linux/Tracker/make.bsd.google_perftools.sh @@ -0,0 +1 @@ +g++ $@ -DNDEBUG -DPEERS_KEY -ltcmalloc -I /usr/local/include -I ../misc -I . -O3 -o xbt_tracker *.cpp ../misc/*.cpp ../misc/sql/*.cpp `mysql_config --libs` && strip xbt_tracker diff --git a/install/xbt/linux/Tracker/make.bsd.sh b/install/xbt/linux/Tracker/make.bsd.sh new file mode 100644 index 000000000..581aa1b9c --- /dev/null +++ b/install/xbt/linux/Tracker/make.bsd.sh @@ -0,0 +1 @@ +g++ $@ -DNDEBUG -DPEERS_KEY -I /usr/local/include -I ../misc -I . -O3 -o xbt_tracker *.cpp ../misc/*.cpp ../misc/sql/*.cpp `mysql_config --libs` && strip xbt_tracker diff --git a/install/xbt/linux/Tracker/make.sh b/install/xbt/linux/Tracker/make.sh new file mode 100644 index 000000000..f536e4552 --- /dev/null +++ b/install/xbt/linux/Tracker/make.sh @@ -0,0 +1,20 @@ +g++ $@ -DNDEBUG -I ../misc -I . -O3 -o xbt_tracker \ + ../misc/sql/database.cpp \ + ../misc/sql/sql_query.cpp \ + ../misc/sql/sql_result.cpp \ + ../misc/bt_misc.cpp \ + ../misc/bvalue.cpp \ + ../misc/sha1.cpp \ + ../misc/socket.cpp \ + ../misc/virtual_binary.cpp \ + ../misc/xcc_z.cpp \ + config.cpp \ + connection.cpp \ + epoll.cpp \ + server.cpp \ + tcp_listen_socket.cpp \ + tracker_input.cpp \ + transaction.cpp \ + udp_listen_socket.cpp \ + "XBT Tracker.cpp" \ + `mysql_config --libs` && strip xbt_tracker diff --git a/install/xbt/linux/Tracker/md5.cpp b/install/xbt/linux/Tracker/md5.cpp new file mode 100644 index 000000000..7c215789c --- /dev/null +++ b/install/xbt/linux/Tracker/md5.cpp @@ -0,0 +1,362 @@ +/* MD5 + converted to C++ class by Frank Thilo (thilo@unix-ag.org) + for bzflag (http://www.bzflag.org) + + based on: + + md5.h and md5.c + reference implemantion of RFC 1321 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ + +/* interface header */ +#include "md5.h" + +/* system implementation headers */ +#include +#include + +// Constants for MD5Transform routine. +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +/////////////////////////////////////////////// + +// F, G, H and I are basic MD5 functions. +inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { + return x&y | ~x&z; +} + +inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { + return x&z | y&~z; +} + +inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { + return x^y^z; +} + +inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { + return y ^ (x | ~z); +} + +// rotate_left rotates x left n bits. +inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { + return (x << n) | (x >> (32-n)); +} + +// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +// Rotation is separate from addition to prevent recomputation. +inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a+ F(b,c,d) + x + ac, s) + b; +} + +inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + G(b,c,d) + x + ac, s) + b; +} + +inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + H(b,c,d) + x + ac, s) + b; +} + +inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { + a = rotate_left(a + I(b,c,d) + x + ac, s) + b; +} + +////////////////////////////////////////////// + +// default ctor, just initailize +MD5::MD5() +{ + init(); +} + +////////////////////////////////////////////// + +// nifty shortcut ctor, compute MD5 for string and finalize it right away +MD5::MD5(const std::string &text) +{ + init(); + update(text.c_str(), text.length()); + finalize(); +} + +////////////////////////////// + +void MD5::init() +{ + finalized=false; + + count[0] = 0; + count[1] = 0; + + // load magic initialization constants. + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; +} + +////////////////////////////// + +// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4. +void MD5::decode(uint4 output[], const uint1 input[], size_type len) +{ + for (unsigned int i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | + (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); +} + +////////////////////////////// + +// encodes input (uint4) into output (unsigned char). Assumes len is +// a multiple of 4. +void MD5::encode(uint1 output[], const uint4 input[], size_type len) +{ + for (size_type i = 0, j = 0; j < len; i++, j += 4) { + output[j] = input[i] & 0xff; + output[j+1] = (input[i] >> 8) & 0xff; + output[j+2] = (input[i] >> 16) & 0xff; + output[j+3] = (input[i] >> 24) & 0xff; + } +} + +////////////////////////////// + +// apply MD5 algo on a block +void MD5::transform(const uint1 block[blocksize]) +{ + uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + decode (x, block, blocksize); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + // Zeroize sensitive information. + memset(x, 0, sizeof x); +} + +////////////////////////////// + +// MD5 block update operation. Continues an MD5 message-digest +// operation, processing another message block +void MD5::update(const unsigned char input[], size_type length) +{ + // compute number of bytes mod 64 + size_type index = count[0] / 8 % blocksize; + + // Update number of bits + if ((count[0] += (length << 3)) < (length << 3)) + count[1]++; + count[1] += (length >> 29); + + // number of bytes we need to fill in buffer + size_type firstpart = 64 - index; + + size_type i; + + // transform as many times as possible. + if (length >= firstpart) + { + // fill buffer first, transform + memcpy(&buffer[index], input, firstpart); + transform(buffer); + + // transform chunks of blocksize (64 bytes) + for (i = firstpart; i + blocksize <= length; i += blocksize) + transform(&input[i]); + + index = 0; + } + else + i = 0; + + // buffer remaining input + memcpy(&buffer[index], &input[i], length-i); +} + +////////////////////////////// + +// for convenience provide a verson with signed char +void MD5::update(const char input[], size_type length) +{ + update((const unsigned char*)input, length); +} + +////////////////////////////// + +// MD5 finalization. Ends an MD5 message-digest operation, writing the +// the message digest and zeroizing the context. +MD5& MD5::finalize() +{ + static unsigned char padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (!finalized) { + // Save number of bits + unsigned char bits[8]; + encode(bits, count, 8); + + // pad out to 56 mod 64. + size_type index = count[0] / 8 % 64; + size_type padLen = (index < 56) ? (56 - index) : (120 - index); + update(padding, padLen); + + // Append length (before padding) + update(bits, 8); + + // Store state in digest + encode(digest, state, 16); + + // Zeroize sensitive information. + memset(buffer, 0, sizeof buffer); + memset(count, 0, sizeof count); + + finalized=true; + } + + return *this; +} + +////////////////////////////// + +// return hex representation of digest as string +std::string MD5::hexdigest() const +{ + if (!finalized) + return ""; + + char buf[33]; + for (int i=0; i<16; i++) + sprintf(buf+i*2, "%02x", digest[i]); + buf[32]=0; + + return std::string(buf); +} + +////////////////////////////// + +std::ostream& operator<<(std::ostream& out, MD5 md5) +{ + return out << md5.hexdigest(); +} + +////////////////////////////// + +std::string md5(const std::string str) +{ + MD5 md5 = MD5(str); + + return md5.hexdigest(); +} diff --git a/install/xbt/linux/Tracker/md5.h b/install/xbt/linux/Tracker/md5.h new file mode 100644 index 000000000..4f6a8cebd --- /dev/null +++ b/install/xbt/linux/Tracker/md5.h @@ -0,0 +1,93 @@ +/* MD5 + converted to C++ class by Frank Thilo (thilo@unix-ag.org) + for bzflag (http://www.bzflag.org) + + based on: + + md5.h and md5.c + reference implementation of RFC 1321 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ + +#ifndef BZF_MD5_H +#define BZF_MD5_H + +#include +#include + + +// a small class for calculating MD5 hashes of strings or byte arrays +// it is not meant to be fast or secure +// +// usage: 1) feed it blocks of uchars with update() +// 2) finalize() +// 3) get hexdigest() string +// or +// MD5(std::string).hexdigest() +// +// assumes that char is 8 bit and int is 32 bit +class MD5 +{ +public: + typedef unsigned int size_type; // must be 32bit + + MD5(); + MD5(const std::string& text); + void update(const unsigned char *buf, size_type length); + void update(const char *buf, size_type length); + MD5& finalize(); + std::string hexdigest() const; + friend std::ostream& operator<<(std::ostream&, MD5 md5); + +private: + void init(); + typedef unsigned char uint1; // 8bit + typedef unsigned int uint4; // 32bit + enum {blocksize = 64}; // VC6 won't eat a const static int here + + void transform(const uint1 block[blocksize]); + static void decode(uint4 output[], const uint1 input[], size_type len); + static void encode(uint1 output[], const uint4 input[], size_type len); + + bool finalized; + uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk + uint4 count[2]; // 64bit counter for number of bits (lo, hi) + uint4 state[4]; // digest so far + uint1 digest[16]; // the result + + // low level logic operations + static inline uint4 F(uint4 x, uint4 y, uint4 z); + static inline uint4 G(uint4 x, uint4 y, uint4 z); + static inline uint4 H(uint4 x, uint4 y, uint4 z); + static inline uint4 I(uint4 x, uint4 y, uint4 z); + static inline uint4 rotate_left(uint4 x, int n); + static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); + static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); +}; + +std::string md5(const std::string str); + +#endif diff --git a/install/xbt/linux/Tracker/res/Thumbs.db b/install/xbt/linux/Tracker/res/Thumbs.db new file mode 100644 index 000000000..1b7e063e7 Binary files /dev/null and b/install/xbt/linux/Tracker/res/Thumbs.db differ diff --git a/install/xbt/linux/Tracker/res/XBT Tracker.ico b/install/xbt/linux/Tracker/res/XBT Tracker.ico new file mode 100644 index 000000000..0e2f5d148 Binary files /dev/null and b/install/xbt/linux/Tracker/res/XBT Tracker.ico differ diff --git a/install/xbt/linux/Tracker/resource.h b/install/xbt/linux/Tracker/resource.h new file mode 100644 index 000000000..a810dc456 --- /dev/null +++ b/install/xbt/linux/Tracker/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by XBT Client.rc +// +#define IDR_MAINFRAME 128 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 149 +#define _APS_NEXT_COMMAND_VALUE 32849 +#define _APS_NEXT_CONTROL_VALUE 1091 +#define _APS_NEXT_SYMED_VALUE 105 +#endif +#endif diff --git a/install/xbt/linux/Tracker/server.cpp b/install/xbt/linux/Tracker/server.cpp new file mode 100644 index 000000000..3341e4256 --- /dev/null +++ b/install/xbt/linux/Tracker/server.cpp @@ -0,0 +1,1539 @@ +#include "stdafx.h" +#include "server.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "transaction.h" + +// TorrentPier begin +#include "md5.cpp" +#ifdef WIN32 +#include +#endif + +long long gcd(long long a, long long b) { + long long c = 0; + while (b) { + c = a % b; + a = b; + b = c; + } + return a; +} +// TorrentPier end + +static volatile bool g_sig_term = false; + +Cserver::Cserver(Cdatabase& database, const std::string& table_prefix, bool use_sql, const std::string& conf_file): + m_database(database) +{ + m_fid_end = 0; + + for (int i = 0; i < 8; i++) + m_secret = m_secret << 8 ^ rand(); + m_conf_file = conf_file; + m_table_prefix = table_prefix; + m_time = ::time(NULL); + m_use_sql = use_sql; +} + +int Cserver::run() +{ + read_config(); + if (test_sql()) + return 1; + if (m_epoll.create(1 << 10) == -1) + { + std::cerr << "epoll_create failed" << std::endl; + return 1; + } + t_tcp_sockets lt; + t_udp_sockets lu; + + // TorrentPier begin + struct addrinfo hints, *res, *res0; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + Csocket::start_up(); + + BOOST_FOREACH(Cconfig::t_listen_ipas::const_reference j, m_config.m_listen_ipas) + { + BOOST_FOREACH(Cconfig::t_listen_ports::const_reference i, m_config.m_listen_ports) + { + if (getaddrinfo(j == "*" ? NULL : j.c_str(), i.c_str(), &hints, &res0)) { + std::cerr << "getaddrinfo failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + return 1; + } + for (res = res0; res; res = res->ai_next) { + int s = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (s < 0) { + std::cerr << "socket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + return 1; + } + Csocket l(s); +#ifdef IPV6_V6ONLY + if (res->ai_family == AF_INET6 && + l.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, true)) { + std::cerr << "IPV6_V6ONLY failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + } +#endif + if (l.blocking(false)) + std::cerr << "blocking failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else if (l.setsockopt(SOL_SOCKET, SO_REUSEADDR, true), + ::bind(s, res->ai_addr, res->ai_addrlen)) + std::cerr << "bind failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else if (::listen(s, INT_MAX)) + std::cerr << "listen failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else + { + if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) + std::cerr << "getnameinfo failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else + std::cerr << "Listen to " << hbuf << " " << sbuf << std::endl; +#ifdef SO_ACCEPTFILTER + accept_filter_arg afa; + bzero(&afa, sizeof(afa)); + strcpy(afa.af_name, "httpready"); + if (l.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa))) + std::cerr << "setsockopt failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; +#elif TCP_DEFER_ACCEPT + if (l.setsockopt(IPPROTO_TCP, TCP_DEFER_ACCEPT, true)) + std::cerr << "setsockopt failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; +#endif + lt.push_back(Ctcp_listen_socket(this, l)); + if (!m_epoll.ctl(EPOLL_CTL_ADD, l, EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP, <.back())) + continue; + } + return 1; + } + } + + /* + BOOST_FOREACH(Cconfig::t_listen_ports::const_reference i, m_config.m_listen_ports) + { + Csocket l; + if (l.open(SOCK_DGRAM) == INVALID_SOCKET) + std::cerr << "socket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else if (l.setsockopt(SOL_SOCKET, SO_REUSEADDR, true), + l.bind(j, htons(i))) + std::cerr << "bind failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else + { + lu.push_back(Cudp_listen_socket(this, l)); + if (!m_epoll.ctl(EPOLL_CTL_ADD, l, EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP, &lu.back())) + continue; + } + return 1; + } + */ + } + // TorrentPier end + + clean_up(); + read_db_deny_from_hosts(); + read_db_files(); + read_db_users(); + write_db_files(); + write_db_users(); +#ifndef WIN32 + if (m_config.m_daemon) + { + if (daemon(true, false)) + std::cerr << "daemon failed" << std::endl; + std::ofstream(m_config.m_pid_file.c_str()) << getpid() << std::endl; + struct sigaction act; + act.sa_handler = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGTERM, &act, NULL)) + std::cerr << "sigaction failed" << std::endl; + act.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &act, NULL)) + std::cerr << "sigaction failed" << std::endl; + } +#endif +#ifdef EPOLL + boost::array events; +#else + fd_set fd_read_set; + fd_set fd_write_set; + fd_set fd_except_set; +#endif + while (!g_sig_term) + { +#ifdef EPOLL + int r = m_epoll.wait(events.data(), events.size(), 5000); + if (r == -1) + std::cerr << "epoll_wait failed: " << errno << std::endl; + else + { + int prev_time = m_time; + m_time = ::time(NULL); + for (int i = 0; i < r; i++) + reinterpret_cast(events[i].data.ptr)->process_events(events[i].events); + if (m_time == prev_time) + continue; + for (t_connections::iterator i = m_connections.begin(); i != m_connections.end(); ) + { + if (i->run()) + i = m_connections.erase(i); + else + i++; + } + } +#else + FD_ZERO(&fd_read_set); + FD_ZERO(&fd_write_set); + FD_ZERO(&fd_except_set); + int n = 0; + BOOST_FOREACH(t_connections::reference i, m_connections) + { + int z = i.pre_select(&fd_read_set, &fd_write_set); + n = std::max(n, z); + } + BOOST_FOREACH(t_tcp_sockets::reference i, lt) + { + FD_SET(i.s(), &fd_read_set); + n = std::max(n, i.s()); + } + BOOST_FOREACH(t_udp_sockets::reference i, lu) + { + FD_SET(i.s(), &fd_read_set); + n = std::max(n, i.s()); + } + timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + if (select(n + 1, &fd_read_set, &fd_write_set, &fd_except_set, &tv) == SOCKET_ERROR) + std::cerr << "select failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + else + { + m_time = ::time(NULL); + BOOST_FOREACH(t_tcp_sockets::reference i, lt) + { + if (FD_ISSET(i.s(), &fd_read_set)) + accept(i.s()); + } + BOOST_FOREACH(t_udp_sockets::reference i, lu) + { + if (FD_ISSET(i.s(), &fd_read_set)) + Ctransaction(*this, i.s()).recv(); + } + for (t_connections::iterator i = m_connections.begin(); i != m_connections.end(); ) + { + if (i->post_select(&fd_read_set, &fd_write_set)) + i = m_connections.erase(i); + else + i++; + } + } +#endif + if (time() - m_read_config_time > m_config.m_read_config_interval) + read_config(); + else if (time() - m_clean_up_time > m_config.m_clean_up_interval) + clean_up(); + else if (time() - m_read_db_deny_from_hosts_time > m_config.m_read_db_interval) + read_db_deny_from_hosts(); + + // TorrentPier begin + else if (time() - m_read_db_files_time > m_config.m_read_files_interval) + // TorrentPier end + + read_db_files(); + else if (time() - m_read_db_users_time > m_config.m_read_db_interval) + read_db_users(); + else if (m_config.m_write_db_interval && time() - m_write_db_files_time > m_config.m_write_db_interval) + write_db_files(); + else if (m_config.m_write_db_interval && time() - m_write_db_users_time > m_config.m_write_db_interval) + write_db_users(); + } + write_db_files(); + write_db_users(); + unlink(m_config.m_pid_file.c_str()); + return 0; +} + +void Cserver::accept(const Csocket& l) +{ + // TorrentPier begin + sockaddr_storage a; + while (1) + { + socklen_t cb_a = sizeof(sockaddr_storage); + // TorrentPier end + + Csocket s = ::accept(l, reinterpret_cast(&a), &cb_a); + if (s == SOCKET_ERROR) + { + if (WSAGetLastError() == WSAECONNABORTED) + continue; + if (WSAGetLastError() != WSAEWOULDBLOCK) + std::cerr << "accept failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + break; + } + + // TorrentPier begin + if (a.ss_family == AF_INET) { + sockaddr_in *b = reinterpret_cast(&a); + + t_deny_from_hosts::const_iterator i = m_deny_from_hosts.lower_bound(ntohl(b->sin_addr.s_addr)); + if (i != m_deny_from_hosts.end() && ntohl(b->sin_addr.s_addr) >= i->second.begin) + { + m_stats.rejected_tcp++; + continue; + } + m_stats.accepted_tcp4++; + } else if (a.ss_family == AF_INET6) m_stats.accepted_tcp6++; + // TorrentPier end + + m_stats.accepted_tcp++; + if (s.blocking(false)) + std::cerr << "ioctlsocket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + std::auto_ptr connection(new Cconnection(this, s, a)); + connection->process_events(EPOLLIN); + if (connection->s() != INVALID_SOCKET) + { + m_connections.push_back(connection.release()); + m_epoll.ctl(EPOLL_CTL_ADD, m_connections.back().s(), EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLET, &m_connections.back()); + } + } +} + +std::string Cserver::insert_peer(const Ctracker_input& v, bool udp, t_user* user) +{ + if (m_use_sql && m_config.m_log_announce) + { + m_announce_log_buffer += Csql_query(m_database, "(?,?,?,?,?,?,?,?,?,?),") + .p(ntohl(v.m_ipa)).p(ntohs(v.m_port)).p(v.m_event).p(v.m_info_hash).p(v.m_peer_id).p(v.m_downloaded).p(v.m_left).p(v.m_uploaded).p(user ? user->uid : 0).p(time()).read(); + } + if (!m_config.m_offline_message.empty()) + return m_config.m_offline_message; + + // TorrentPier begin + if (!m_config.m_auto_register && !file(v.m_info_hash)) + return bts_unregistered_torrent; + + t_file& file = m_files[v.m_info_hash]; + + if (!m_config.m_anonymous_announce && !user && file.dl_percent >= 0) + return bts_unregistered_torrent_pass; + + std::string xbt_error = ""; + if (v.m_left && v.m_event != Ctracker_input::e_paused && user && !user->can_leech && !m_config.m_free_leech) + /*if (xbt_error.empty())*/ xbt_error = bts_can_not_leech; + if (v.m_left && user && user->user_park) //park + xbt_error = bts_park; + if (user && user->user_active == 0) //unactive + xbt_error = bts_disabled; + if (!file.ctime) + file.ctime = time(); + if (v.m_left && v.m_event != Ctracker_input::e_paused && + user && user->wait_time && file.ctime + user->wait_time > time() && !m_config.m_free_leech) + /*return*/ if (xbt_error.empty()) xbt_error = bts_wait_time; + + t_peers::key_type peer_key = v.m_peer_id; + t_peer* i = find_ptr(file.peers, peer_key); + if (i) + { + if (i->xbt_error_empty) + { + (i->left != e_seeder ? file.leechers : file.seeders)--; + if (t_user* old_user = find_user_by_uid(i->uid)) + (i->left == e_downloader ? old_user->incompletes : old_user->completes)--; + } + + file.speed_ul -= i->speed_ul, file.speed_dl -= i->speed_dl; + } + + if (i && i->xbt_error_empty) { } + else if (v.m_left && v.m_event != Ctracker_input::e_paused && + user && user->torrents_limit && user->incompletes >= user->torrents_limit && !m_config.m_free_leech) + { + /*return*/ if (xbt_error.empty()) xbt_error = bts_torrents_limit_reached; + } + else if (v.m_left && v.m_event != Ctracker_input::e_paused && + user && user->peers_limit && !m_config.m_free_leech) + { + int c = 0, a = 0; + BOOST_FOREACH(t_peers::reference j, file.peers) { + c += j.second.left == e_downloader && j.second.uid == user->uid && j.second.xbt_error_empty; + a += j.second.uid == user->uid && j.second.xbt_error_empty; + } + if (c >= user->peers_limit || a >= user->peers_limit * 3) + /*return*/ if (xbt_error.empty()) xbt_error = bts_peers_limit_reached; + } + + long long downloaded = 0, downloaded_db = 0, downspeed = 0; + long long uploaded = 0, upspeed = 0; + long long bonus = 0; + long long rel = 0; + long long ul_gdc = 0, ul_gdc_16k = 0; + int ul_gdc_count = 0, ul_16k_count = 0, ul_eq_dl_count = 0; + int end_vip = 0; + + bool ipv6set = v.m_ipv6set && (v.m_family == AF_INET6 || m_config.m_trust_ipv6); + + if (m_use_sql && user && file.fid) + { + + long long timespent = 0; + if (i + // && boost::equals(i->peer_id, v.m_peer_id) + && v.m_downloaded >= i->downloaded + && v.m_uploaded >= i->uploaded) + { + downloaded = v.m_downloaded - i->downloaded; + uploaded = v.m_uploaded - i->uploaded; + + if( downloaded > 100000000000ll || uploaded > 100000000000ll ) { + downloaded = uploaded = 0; // anti-hack + if (xbt_error.empty()) xbt_error = bts_banned_client; + } + timespent = time() - i->mtime; + if ((timespent << 1) > m_config.m_announce_interval) + { + upspeed = uploaded / timespent; + downspeed = downloaded / timespent; + } + ul_gdc_count = i->ul_gdc_count; + ul_16k_count = i->ul_16k_count; + ul_gdc_16k = i->ul_gdc_16k; + ul_eq_dl_count = i->ul_eq_dl_count; + if( uploaded && m_config.m_gdc ) + { + ul_gdc_count++; + if (uploaded == downloaded) ul_eq_dl_count++; + long long block = 16384; + if( (uploaded % block) == 0ll ) + { + ul_16k_count++; + if( ul_16k_count > 1 ) + ul_gdc_16k = gcd(uploaded, ul_gdc_16k); + else + ul_gdc_16k = uploaded; + } + if( ul_gdc_count == ul_16k_count ) + ul_gdc = ul_gdc_16k; + else + { + if( ul_gdc_count > 1 ) + ul_gdc = gcd(uploaded, i->ul_gdc); + else + ul_gdc = uploaded; + } + } + else + { + ul_gdc = i->ul_gdc; + } + + downloaded_db = (m_config.m_free_leech || file.dl_percent<0) ? 0 : (downloaded * file.dl_percent /100); + if (user->user_vip == 2 && user->user_vip_exp < time()) end_vip = 1; //vip + if (user->user_vip > 0 && end_vip == 0) downloaded_db = 0; //vip + + if (user->uid == file.tor_poster_id) rel = uploaded; + else if (!v.m_left && file.seeders == 1) bonus = 1; + + // TorrentPier: bb_bt_users_dl_status + int new_status = v.m_left ? 0 : 1; + if (user->uid == file.tor_poster_id) new_status = -1; + if (new_status != i->dl_status && file.tor_topic_id) { + Csql_query q(m_database, "(?,?,?),"); // topic_id,user_id,user_status,update_time + q.p(file.tor_topic_id); // topic_id + q.p(user->uid); // user_id + q.p(new_status); + m_users_dl_status_buffer += q.read(); + i->dl_status = new_status; + } + + // TorrentPier: bb_bt_torrent_activity + int user_status = new_status; + if (new_status == -1) new_status = 2; + Csql_query q(m_database, "(?,?,?,?,?,?,?,?,?,?,?,?),"); + q.p(user->uid); // user_id + q.p(file.tor_topic_id); // torrent_id + q.p(uploaded); + q.p(downloaded_db); + q.p(upspeed); // speed_up mediumint(8) unsigned NOT NULL default '0', + q.p(downspeed); // speed_down mediumint(8) unsigned NOT NULL default '0', + q.p(new_status); + q.p(bonus ? uploaded/bonus : 0); + q.p(user_status); + q.p(downloaded); + q.p(time()); + q.p(m_config.m_announce_interval); //torrent_time + m_tor_dl_stat_buffer += q.read(); + + // TorrentPier: bb_cheat_log + long long cheat = (long long) m_config.m_cheat_upload * 1024 * 1024 * 1024; + if (uploaded > cheat) { + Csql_query q(m_database, "(?,?,?,?),"); // torrent_id,user_id,attach_id,t_up_total,t_down_total + q.p(user->uid); // user_id + q.p(uploaded); + q.p(hex_encode(8, ntohl(v.m_ipa))); + q.p(time()); + m_cheat_buffer += q.read(); + } + + //vip + if (end_vip) { + Csql_query q(m_database, "(?),"); // user_id + q.p(user->uid); // user_id + m_vip_buffer += q.read(); + } + } + Csql_query q(m_database, "(?,?,?,?,?,?,?,?,?,?, ?,?,?,?, ?,?,?,?,?,?),"); + + int cleanup_interval = static_cast(2.5 * m_config.m_announce_interval); + int min_cleanup = 3900; // 65 min + if( cleanup_interval < min_cleanup ) cleanup_interval = min_cleanup; + + // TorrentPier + std::string port_st, ip_st, peer_hash; + port_st = ntohs(v.m_port); + ip_st = hex_encode(8, ntohl(v.m_ipa)); + peer_hash = md5(v.m_info_hash+v.m_passkey+port_st+ip_st); + + q.p(file.fid); // torrent_id mediumint(8) unsigned NOT NULL default '0', + q.p(v.m_peer_id); + q.p(peer_hash); + q.p(user->uid); // user_id mediumint(9) NOT NULL default '0', + q.p(hex_encode(8, ntohl(v.m_ipa))); // ip char(8) binary NOT NULL default '0', + q.p(const_memory_range(v.m_ipv6bin, ipv6set ? 16 : 0)); // ipv6 varchar(32) + q.p(ntohs(v.m_port)); // port smallint(5) unsigned NOT NULL default '0', + q.p(uploaded); // uploaded bigint(20) unsigned NOT NULL default '0', + q.p(downloaded_db); // downloaded bigint(20) unsigned NOT NULL default '0', + q.p(v.m_left && v.m_event != Ctracker_input::e_paused ? 0 : 1); // seeder tinyint(1) NOT NULL default '0', + q.p(user->uid==file.tor_poster_id),// releaser + q.p(v.m_left ? (v.m_left>=file.tor_size ? 0 : ((file.tor_size-v.m_left)*100/file.tor_size)) : v.m_uploaded); // complete_percent bigint(20) unsigned NOT NULL default '0', + q.p(upspeed); // speed_up mediumint(8) unsigned NOT NULL default '0', + q.p(downspeed); // speed_down mediumint(8) unsigned NOT NULL default '0', + q.p(time()); // update_time int(11) NOT NULL default '0', + q.p(xbt_error); + q.p( ul_16k_count*3 > ul_gdc_count*2 ? ul_gdc_16k : ul_gdc ); + q.p(ul_gdc_count); + q.p(ul_16k_count); + q.p(ul_eq_dl_count); + + m_files_users_updates_buffer += q.read(); + + if (downloaded || uploaded) + { + Csql_query q(m_database, "(?,?,?,?,?,?,?),"); + q.p(downloaded_db); + q.p(uploaded); + q.p(user->uid); + q.p(rel); + q.p(bonus ? uploaded/bonus : 0); + q.p(upspeed); + q.p(downspeed); + m_users_updates_buffer += q.read(); + } + + // Double tracker fix + if (v.m_event == Ctracker_input::e_completed && downloaded) + file.completed++, file.completed_inc++; + } + else + { + if (v.m_event == Ctracker_input::e_completed) + file.completed++, file.completed_inc++; + } + + if (v.m_event == Ctracker_input::e_stopped) + file.peers.erase(peer_key); + else + { + t_peer& peer = file.peers[peer_key]; + peer.downloaded = i && v.m_downloaded < i->downloaded ? i->downloaded : v.m_downloaded; + peer.left = v.m_left == 0 ? e_seeder : v.m_event == Ctracker_input::e_paused ? e_incomplete : e_downloader; + // std::copy(v.m_peer_id.begin(), v.m_peer_id.end(), peer.peer_id.begin()); + peer.port = v.m_port; + peer.uid = user ? user->uid : 0; + peer.uploaded = i && v.m_uploaded < i->uploaded ? i->uploaded : v.m_uploaded; + + file.speed_ul += ( peer.speed_ul = upspeed ); + file.speed_dl += ( peer.speed_dl = downspeed ); + + if (xbt_error.empty()) + { + (peer.left != e_seeder ? file.leechers : file.seeders)++; + if (user) + (peer.left == e_downloader ? user->incompletes : user->completes)++; + } + + peer.xbt_error_empty = xbt_error.empty(); + peer.ul_gdc = ul_gdc; + peer.ul_gdc_16k = ul_gdc_16k; + peer.ul_gdc_count = ul_gdc_count; + peer.ul_16k_count = ul_16k_count; + peer.ul_eq_dl_count = ul_eq_dl_count; + + if (ipv6set && v.m_protocol != 4) { + peer.ipv6set = true; + memcpy(peer.ipv6, v.m_ipv6bin, 16); + m_stats.announced_with_ipv6++; + } + + if ((v.m_family == AF_INET || (m_config.m_trust_ipv6 && v.m_ipa != 0)) && v.m_protocol != 6) peer.host_ = v.m_ipa; + + peer.mtime = time(); + } + + // TorrentPier: Fill seeder_last_seen & last_seeder_uid fields + if (user && !v.m_left) + { + file.tor_last_seeder_uid = user->uid; + file.tor_seeder_last_seen = time(); + } + + (udp ? m_stats.announced_udp : m_stats.announced_http)++; + file.dirty = true; + return xbt_error; + // TorrentPier end +} + +std::string Cserver::t_file::select_peers(const Ctracker_input& ti) const +{ + if (ti.m_event == Ctracker_input::e_stopped) + return ""; + + typedef std::vector > t_candidates; + + t_candidates candidates; + BOOST_FOREACH(t_peers::const_reference i, peers) + { + // TorrentPier begin + if (((!ti.m_left || ti.m_event == Ctracker_input::e_paused) && i.second.left != e_downloader) + || !i.second.xbt_error_empty || !i.second.host_ + || boost::equals(i.first, ti.m_peer_id)) + continue; + boost::array v; + memcpy(&v.front(), &i.second.host_, 4); + // TorrentPier end + + memcpy(&v.front() + 4, &i.second.port, 2); + candidates.push_back(v); + } + size_t c = ti.m_num_want < 0 ? 50 : std::min(ti.m_num_want, 50); + std::string d; + d.reserve(300); + if (candidates.size() > c) + { + while (c--) + { + int i = rand() % candidates.size(); + d.append(candidates[i].begin(), candidates[i].end()); + candidates[i] = candidates.back(); + candidates.pop_back(); + } + } + else + { + BOOST_FOREACH(t_candidates::reference i, candidates) + d.append(i.begin(), i.end()); + } + return d; +} + +// TorrentPier begin +std::string Cserver::t_file::select_peers6(const Ctracker_input& ti) const +{ + if (ti.m_event == Ctracker_input::e_stopped) + return ""; + + typedef std::vector > t_candidates; + + t_candidates candidates; + BOOST_FOREACH(t_peers::const_reference i, peers) + { + if (((!ti.m_left || ti.m_event == Ctracker_input::e_paused) && i.second.left != e_downloader) + || !i.second.xbt_error_empty ||!i.second.ipv6set + || boost::equals(i.first, ti.m_peer_id)) + continue; + + boost::array v; + memcpy(&v.front(), i.second.ipv6, 16); + memcpy(&v.front() + 16, &i.second.port, 2); + candidates.push_back(v); + } + size_t c = ti.m_num_want < 0 ? 50 : std::min(ti.m_num_want, 50); + std::string d; + d.reserve(900); + if (candidates.size() > c) + { + while (c--) + { + int i = rand() % candidates.size(); + d.append(candidates[i].begin(), candidates[i].end()); + candidates[i] = candidates.back(); + candidates.pop_back(); + } + } + else + { + BOOST_FOREACH(t_candidates::reference i, candidates) + d.append(i.begin(), i.end()); + } + return d; +} +// TorrentPier end + +Cvirtual_binary Cserver::select_peers(const Ctracker_input& ti) const +{ + const t_file* f = file(ti.m_info_hash); + if (!f) + return Cvirtual_binary(); + // TorrentPier begin + static int rnd = 0; + + long interval = config().m_announce_interval; + if (ti.m_left) { + interval >>= 1; + } else { + int peers = f->seeders + f->leechers + 1; + interval = interval * (peers + f->seeders) / (peers + peers); + } + interval += (++rnd & 63) + (f->fid & 63) - 64; + + if (ti.m_protocol == 6) { // ti.m_family == AF_INET6 && !m_config.m_trust_ipv6) { + std::string peers6 = f->select_peers6(ti); + return Cvirtual_binary((boost::format("d8:completei%de10:incompletei%de8:intervali%de6:peers6%d:%se") + % f->seeders % f->leechers % interval % peers6.size() % peers6).str()); + } else if (ti.m_protocol == 4) { // ti.m_family == AF_INET && !m_config.m_trust_ipv6) { + std::string peers = f->select_peers(ti); + return Cvirtual_binary((boost::format("d8:completei%de10:incompletei%de8:intervali%de5:peers%d:%se") + % f->seeders % f->leechers % interval % peers.size() % peers).str()); + } else { + std::string peers = f->select_peers(ti); + std::string peers6 = f->select_peers6(ti); + return Cvirtual_binary((boost::format("d8:completei%de10:incompletei%de8:intervali%de5:peers%d:%s6:peers6%d:%se") + % f->seeders % f->leechers % interval % peers.size() % peers % peers6.size() % peers6).str()); + } + // TorrentPier end +} + +void Cserver::t_file::clean_up(time_t t, Cserver& server) +{ + for (t_peers::iterator i = peers.begin(); i != peers.end(); ) + { + if (i->second.mtime < t) + { + // TorrentPier begin + if (i->second.xbt_error_empty) + { + (i->second.left != e_seeder ? leechers : seeders)--; + if (t_user* user = server.find_user_by_uid(i->second.uid)) + (i->second.left == e_downloader ? user->incompletes : user->completes)--; + } + /* + if (i->second.uid) + server.m_files_users_updates_buffer += Csql_query(server.m_database, "(0,0,0,0,-1,0,-1,?,?),").p(fid).p(i->second.uid).read(); + */ + speed_ul -= i->second.speed_ul, speed_dl -= i->second.speed_dl; + // TorrentPier end + + peers.erase(i++); + dirty = true; + } + else + i++; + } +} + +void Cserver::clean_up() +{ + // TorrentPier begin + int cleanup_interval = static_cast(2.5 * m_config.m_announce_interval); + if( cleanup_interval < 1800 ) cleanup_interval = 1800; + BOOST_FOREACH(t_files::reference i, m_files) + i.second.clean_up(time() - cleanup_interval, *this); + // TorrentPier end + + m_clean_up_time = time(); +} + +static byte* write_compact_int(byte* w, unsigned int v) +{ + if (v >= 0x200000) + { + *w++ = 0xe0 | (v >> 24); + *w++ = v >> 16; + *w++ = v >> 8; + } + else if (v >= 0x4000) + { + *w++ = 0xc0 | (v >> 16); + *w++ = v >> 8; + } + else if (v >= 0x80) + *w++ = 0x80 | (v >> 8); + *w++ = v; + return w; +} + +Cvirtual_binary Cserver::scrape(const Ctracker_input& ti) +{ + if (m_use_sql && m_config.m_log_scrape) + { + Csql_query q(m_database, "(?,?,?),"); + q.p(ntohl(ti.m_ipa)); + if (ti.m_info_hash.empty()) + q.p_raw(const_memory_range("null")); + else + q.p(ti.m_info_hash); + q.p(time()); + m_scrape_log_buffer += q.read(); + } + std::string d; + d += "d5:filesd"; + if (ti.m_info_hashes.empty()) + { + m_stats.scraped_full++; + if (ti.m_compact) + { + Cvirtual_binary d; + byte* w = d.write_start(32 * m_files.size() + 1); + *w++ = 'x'; + BOOST_FOREACH(t_files::reference i, m_files) + { + if (!i.second.leechers && !i.second.seeders) + continue; + memcpy(w, i.first.data(), i.first.size()); + w += i.first.size(); + w = write_compact_int(w, i.second.seeders); + w = write_compact_int(w, i.second.leechers); + w = write_compact_int(w, std::min(i.second.completed, 1)); + } + d.resize(w - d); + return d; + } + d.reserve(90 * m_files.size()); + BOOST_FOREACH(t_files::reference i, m_files) + { + if (i.second.leechers || i.second.seeders) + d += (boost::format("20:%sd8:completei%de10:incompletei%dee") % i.first % i.second.seeders % i.second.leechers).str(); + } + } + else + { + m_stats.scraped_http++; + BOOST_FOREACH(Ctracker_input::t_info_hashes::const_reference j, ti.m_info_hashes) + { + if (t_file* i = find_ptr(m_files, j)) + d += (boost::format("20:%sd8:completei%de10:incompletei%dee") % j % i->seeders % i->leechers).str(); + } + } + d += "e"; + if (m_config.m_scrape_interval) + d += (boost::format("5:flagsd20:min_request_intervali%dee") % m_config.m_scrape_interval).str(); + d += "e"; + return Cvirtual_binary(d); +} + +void Cserver::read_db_deny_from_hosts() +{ + m_read_db_deny_from_hosts_time = time(); + if (!m_use_sql) + return; + try + { + Csql_result result = Csql_query(m_database, "select begin, end from ?").p_name(table_name(table_deny_from_hosts)).execute(); + BOOST_FOREACH(t_deny_from_hosts::reference i, m_deny_from_hosts) + i.second.marked = true; + for (Csql_row row; row = result.fetch_row(); ) + { + t_deny_from_host& deny_from_host = m_deny_from_hosts[row[1].i()]; + deny_from_host.marked = false; + deny_from_host.begin = row[0].i(); + } + for (t_deny_from_hosts::iterator i = m_deny_from_hosts.begin(); i != m_deny_from_hosts.end(); ) + { + if (i->second.marked) + m_deny_from_hosts.erase(i++); + else + i++; + } + } + catch (Cdatabase::exception&) + { + } +} + +void Cserver::read_db_files() +{ + m_read_db_files_time = time(); + if (m_use_sql) + read_db_files_sql(); + else if (!m_config.m_auto_register) + { + std::set new_files; + std::ifstream is("xbt_files.txt"); + std::string s; + while (getline(is, s)) + { + s = hex_decode(s); + if (s.size() != 20) + continue; + m_files[s]; + new_files.insert(s); + } + for (t_files::iterator i = m_files.begin(); i != m_files.end(); ) + { + if (!new_files.count(i->first)) + m_files.erase(i++); + else + i++; + } + } +} + +// TorrentPier begin +void Cserver::read_db_files_sql() +{ + try + { + Csql_query q(m_database); + if (!m_config.m_auto_register) + { + // XBT read only new torrents, so we need to mark deleted in "_del" table + q = "select rpad(info_hash,20,' '), ?, is_del, dl_percent from "+table_name(table_files)+"_del"; + q.p_name(column_name(column_files_fid)); + Csql_result result = q.execute(); + for (Csql_row row; row = result.fetch_row(); ) + { + // if (row[0].size() != 20) continue; + // fix + t_files::iterator i = m_files.find(row[0].s()); + if (i != m_files.end()) + { + if (row[2].i()) + { + for (t_peers::iterator j = i->second.peers.begin(); j != i->second.peers.end(); j++) + { + t_user* user = j->second.uid ? find_user_by_uid(j->second.uid) : NULL; + if (user && j->second.xbt_error_empty) + (j->second.left == e_downloader ? user->incompletes : user->completes)--; + } + m_files.erase(i); + } else { + i->second.dl_percent = row[3].i(); + } + } + // fix + q = "delete from "+table_name(table_files)+"_del where ? = ?"; + q.p_name(column_name(column_files_fid)); + q.p(row[1].i()); + q.execute(); + } + } + if (m_files.empty()) + m_database.query("update bb_bt_tracker_snap set " + + column_name(column_files_leechers) + " = 0, " + + column_name(column_files_seeders) + " = 0, speed_up=0, speed_down=0"); + else if (m_config.m_auto_register) + return; + q = "select rpad(bt.info_hash,20,' '), bt.?, bt.?, bt.reg_time, bt.size, bt.attach_id, bt.topic_id, bt.poster_id, " + + column_name(column_files_dl_percent) + " from ? bt where reg_time >= ?"; + q.p_name(column_name(column_files_completed)); + q.p_name(column_name(column_files_fid)); + q.p_name(table_name(table_files)); + q.p(m_fid_end); + Csql_result result = q.execute(); + for (Csql_row row; row = result.fetch_row(); ) + { + m_fid_end = std::max(m_fid_end, static_cast(row[3].i()) + 1); + if (row[0].size() != 20 || m_files.find(row[0].s()) != m_files.end()) + continue; + t_file& file = m_files[row[0].s()]; + if (file.fid) + continue; + file.completed = row[1].i(); + file.dirty = false; + file.fid = row[2].i(); + file.ctime = row[3].i(); + file.tor_size = row[4].i(); + file.tor_attach_id = row[5].i(); + file.tor_topic_id = row[6].i(); + file.tor_poster_id = row[7].i(); + file.dl_percent = row[8].i(); + } + } + catch (Cdatabase::exception&) + { + } +} +// TorrentPier end + +void Cserver::read_db_users() +{ + m_read_db_users_time = time(); + if (!m_use_sql) + return; + try + { + // TorrentPier begin + Csql_query q(m_database, "select bt.?, auth_key, " + column_name(column_users_can_leech) + ", " + + column_name(column_users_torrents_limit) + ", user_vip, user_vip_exp, user_park, u.user_active from ? bt LEFT JOIN bb_users u ON (u.user_id=bt.user_id)"); + // TorrentPier end + + q.p_name(column_name(column_users_uid)); + q.p_name(table_name(table_users)); + Csql_result result = q.execute(); + BOOST_FOREACH(t_users::reference i, m_users) + i.second.marked = true; + m_users_torrent_passes.clear(); + for (Csql_row row; row = result.fetch_row(); ) + { + t_user& user = m_users[row[0].i()]; + user.marked = false; + + // TorrentPier begin + user.uid = row[0].i(); + user.wait_time = 0; + user.torrents_limit = row[3].i(); + user.peers_limit = 2; // # of IP addresses user can leech from + user.can_leech = row[2].i(); + user.user_vip = row[4].i(); + user.user_vip_exp = row[5].i(); + user.user_park = row[6].i(); + user.user_active = row[7].i(); + if (row[1].size()) { + user.passkey = row[1].s(); + m_users_torrent_passes[user.passkey] = &user; + } + // TorrentPier end + } + for (t_users::iterator i = m_users.begin(); i != m_users.end(); ) + { + if (i->second.marked) + m_users.erase(i++); + else + i++; + } + } + catch (Cdatabase::exception&) + { + } +} + +void Cserver::write_db_files() +{ + m_write_db_files_time = time(); + if (!m_use_sql) + return; + try + { + std::string buffer; + BOOST_FOREACH(t_files::reference i, m_files) + { + t_file& file = i.second; + if (!file.dirty) + continue; + if (!file.fid) + { + // TorrentPier begin + Csql_query(m_database, "insert into ? (info_hash, reg_time) values (?, unix_timestamp())").p_name(table_name(table_files)).p(i.first).execute(); + // TorrentPier end + + file.fid = m_database.insert_id(); + } + + // TorrentPier begin + Csql_query q(m_database, "(?,?,?,?,?),"); + q.p(file.completed_inc); file.completed_inc = 0; + q.p(file.fid); + q.p(file.tor_seeder_last_seen); file.tor_seeder_last_seen = 0; + q.p(file.speed_ul); + q.p(file.speed_dl); + buffer += q.read(); + // TorrentPier end + + file.dirty = false; + } + if (!buffer.empty()) + { + buffer.erase(buffer.size() - 1); + + // TorrentPier begin + m_database.query("insert into " + table_name(table_files) + " (" + + column_name(column_files_completed) + ", " + + column_name(column_files_fid) + + ", seeder_last_seen, speed_up, speed_down) values " + + buffer + + " on duplicate key update speed_up=values(speed_up), speed_down=values(speed_down)," + + " " + column_name(column_files_completed) + " = " + column_name(column_files_completed) + " + values(" + column_name(column_files_completed) + ")," + + " seeder_last_seen = values(seeder_last_seen)" + ); + // TorrentPier end + } + } + catch (Cdatabase::exception&) + { + } + if (!m_announce_log_buffer.empty()) + { + try + { + m_announce_log_buffer.erase(m_announce_log_buffer.size() - 1); + m_database.query("insert delayed into " + table_name(table_announce_log) + " (ipa, port, event, info_hash, peer_id, downloaded, left0, uploaded, uid, mtime) values " + m_announce_log_buffer); + } + catch (Cdatabase::exception&) + { + } + m_announce_log_buffer.erase(); + } + if (!m_scrape_log_buffer.empty()) + { + try + { + m_scrape_log_buffer.erase(m_scrape_log_buffer.size() - 1); + m_database.query("insert delayed into " + table_name(table_scrape_log) + " (ipa, info_hash, mtime) values " + m_scrape_log_buffer); + } + catch (Cdatabase::exception&) + { + } + m_scrape_log_buffer.erase(); + } +} + +// TorrentPier begin +void Cserver::write_db_users() +{ + m_write_db_users_time = time(); + if (!m_use_sql) + return; + if (!m_files_users_updates_buffer.empty()) + { + m_files_users_updates_buffer.erase(m_files_users_updates_buffer.size() - 1); + try + { + m_database.query("insert into " + table_name(table_files_users) + + " (topic_id, peer_id, peer_hash, user_id, ip, ipv6, port, uploaded, downloaded, seeder, releaser, complete_percent, speed_up, speed_down, update_time, xbt_error, ul_gdc, ul_gdc_c, ul_16k_c, ul_eq_dl) values " + + m_files_users_updates_buffer + + " on duplicate key update" + + " topic_id = values(topic_id)," + + " peer_id = values(peer_id)," + + " peer_hash = values(peer_hash)," + + " user_id = values(user_id)," + + " ip = values(ip), ipv6 = values(ipv6)," + + " port = values(port)," + + " uploaded = uploaded + values(uploaded)," + + " downloaded = downloaded + values(downloaded)," + + " complete_percent = values(complete_percent)," + + " seeder = values(seeder)," + + " releaser = values(releaser)," + + " speed_up = values(speed_up)," + + " speed_down = values(speed_down)," + + " up_add = up_add + values(uploaded)," + + " down_add = down_add + values(downloaded)," + + " update_time = values(update_time)," + + " xbt_error=values(xbt_error), ul_gdc=values(ul_gdc), ul_gdc_c=values(ul_gdc_c), ul_16k_c=values(ul_16k_c), ul_eq_dl=values(ul_eq_dl)"); + } + catch (Cdatabase::exception&) + { + } + m_files_users_updates_buffer.erase(); + } + if (!m_users_updates_buffer.empty()) + { + m_users_updates_buffer.erase(m_users_updates_buffer.size() - 1); + try + { + m_database.query("insert into " + table_name(table_users) + " (u_down_total, u_up_total, " + column_name(column_users_uid) + ", u_up_release, u_up_bonus, max_up_speed, max_down_speed) values " + + m_users_updates_buffer + + " on duplicate key update" + + " u_down_total = u_down_total + values(u_down_total)," + + " u_up_total = u_up_total + values(u_up_total)," + + " u_up_release = u_up_release + values(u_up_release)," + + " u_up_bonus = u_up_bonus + values(u_up_bonus)," + + " max_up_speed = GREATEST(max_up_speed, values(max_up_speed))," + + " max_down_speed = GREATEST(max_down_speed, values(max_down_speed))," + + " u_down_today = u_down_today + values(u_down_total)," + + " u_up_today = u_up_today + values(u_up_total)," + + " u_release_today = u_release_today + values(u_up_release)," + + " u_bonus_today = u_bonus_today + values(u_up_bonus)," + + " u_up_speed_today = GREATEST(u_up_speed_today, values(max_up_speed))," + + " u_down_speed_today = GREATEST(u_down_speed_today, values(max_down_speed))"); + } + catch (Cdatabase::exception&) + { + } + m_users_updates_buffer.erase(); + } + if (!m_users_dl_status_buffer.empty()) + { + m_users_dl_status_buffer.erase(m_users_dl_status_buffer.size() - 1); + try + { + m_database.query("insert into bb_bt_dlstatus_main (topic_id,user_id,user_status) values" + + m_users_dl_status_buffer + + " on duplicate key update" + + " user_status = values(user_status)"); + } + catch (Cdatabase::exception&) + { + } + m_users_dl_status_buffer.erase(); + } + if (!m_tor_dl_stat_buffer.empty()) + { + m_tor_dl_stat_buffer.erase(m_tor_dl_stat_buffer.size() - 1); + try + { + m_database.query("insert into bb_bt_torrent_activity(user_id,topic_id,torrent_upload,torrent_download,torrent_speed_up,torrent_speed_down,torrent_dl_status, torrent_bonus, torrent_status, torrent_all_download, torrent_time_st, torrent_time) values" + + m_tor_dl_stat_buffer + + " on duplicate key update" + + " torrent_upload = torrent_upload + values(torrent_upload)," + + " torrent_speed_up = GREATEST(torrent_speed_up, values(torrent_speed_up))," + + " torrent_speed_down = GREATEST(torrent_speed_down, values(torrent_speed_down))," + + " torrent_download = torrent_download + values(torrent_download)," + + " torrent_all_download = torrent_all_download + values(torrent_all_download)," + + " torrent_time = torrent_time + values(torrent_time)," + + " torrent_status = GREATEST(torrent_status, values(torrent_status))," + + " torrent_bonus = torrent_bonus + values(torrent_bonus)"); + } + catch (Cdatabase::exception&) + { + } + m_tor_dl_stat_buffer.erase(); + } + //cheat + if (!m_cheat_buffer.empty()) + { + m_cheat_buffer.erase(m_cheat_buffer.size() - 1); + try + { + m_database.query("insert into bb_bt_cheat_log(cheat_user_id, cheat_uploaded, cheat_ip, cheat_log_time) values" + + m_cheat_buffer); + } + catch (Cdatabase::exception&) + { + } + m_cheat_buffer.erase(); + } + //vip + if (!m_vip_buffer.empty()) + { + m_vip_buffer.erase(m_vip_buffer.size() - 1); + try + { + m_database.query("UPDATE bb_bt_users SET user_vip = 0 WHERE user_id IN" + + m_vip_buffer ); + m_database.query("UPDATE bb_users SET user_rank = 0 WHERE user_rank = 20 AND user_id IN" + + m_vip_buffer ); + } + catch (Cdatabase::exception&) + { + } + m_vip_buffer.erase(); + } +} +// TorrentPier end + +void Cserver::read_config() +{ + if (m_use_sql) + { + try + { + Csql_result result = m_database.query("select name, value from " + table_name(table_config) + " where value is not null"); + Cconfig config; + for (Csql_row row; row = result.fetch_row(); ) + { + if (config.set(row[0].s(), row[1].s())) + std::cerr << "unknown config name: " << row[0].s() << std::endl; + } + config.load(m_conf_file); + if (config.m_torrent_pass_private_key.empty()) + { + config.m_torrent_pass_private_key = generate_random_string(27); + Csql_query(m_database, "insert into xbt_config (name, value) values ('torrent_pass_private_key', ?)").p(config.m_torrent_pass_private_key).execute(); + } + m_config = config; + } + catch (Cdatabase::exception&) + { + } + } + else + { + Cconfig config; + if (!config.load(m_conf_file)) + m_config = config; + } + + // TorrentPier begin + if (m_config.m_listen_ipas.empty()) + m_config.m_listen_ipas.insert("*"); + if (m_config.m_listen_ports.empty()) + m_config.m_listen_ports.insert("2710"); + // TorrentPier end + + m_read_config_time = time(); +} + +void Cserver::t_file::debug(std::ostream& os) const +{ + BOOST_FOREACH(t_peers::const_reference i, peers) + { + // TorrentPier begin + os << "" + Csocket::inet_ntoa(i.second.host_) + << "" << (i.second.ipv6set ? hex_encode(const_memory_range(i.second.ipv6,16)) : "") + // TorrentPier end + + << "" << ntohs(i.second.port) + << "" << i.second.uid + << "" << i.second.left + << "" << ::time(NULL) - i.second.mtime + + // TorrentPier begin + << "" << hex_encode(const_memory_range(i.first.c_str(), 20)); + // TorrentPier end + } +} + +std::string Cserver::debug(const Ctracker_input& ti) const +{ + std::ostringstream os; + os << "XBT Tracker"; + int leechers = 0; + int seeders = 0; + int torrents = 0; + os << ""; + if (ti.m_info_hash.empty()) + { + BOOST_FOREACH(t_files::const_reference i, m_files) + { + if (!i.second.leechers && !i.second.seeders) + continue; + leechers += i.second.leechers; + seeders += i.second.seeders; + torrents++; + os << "
" << i.second.fid + << "" << hex_encode(i.first) << "" + << "" << (i.second.dirty ? '*' : ' ') + << "" << i.second.leechers + << "" << i.second.seeders; + } + } + else + { + if (const t_file* i = find_ptr(m_files, ti.m_info_hash)) + i->debug(os); + } + os << "
"; + return os.str(); +} + +std::string Cserver::statistics() const +{ + std::ostringstream os; + os << "XBT Tracker"; + int leechers = 0; + int seeders = 0; + int torrents = 0; + BOOST_FOREACH(t_files::const_reference i, m_files) + { + leechers += i.second.leechers; + seeders += i.second.seeders; + torrents += i.second.leechers || i.second.seeders; + } + time_t t = time(); + os << "
leechers" << leechers + << "
seeders" << seeders + << "
peers" << leechers + seeders + << "
torrents" << torrents + << "
" + << "
accepted tcp" << m_stats.accepted_tcp + + // TorrentPier begin + << "
accepted tcp4" << m_stats.accepted_tcp4 << "" << m_stats.accepted_tcp4 * 100 / m_stats.accepted_tcp << " %" + << "
accepted tcp6" << m_stats.accepted_tcp6 << "" << m_stats.accepted_tcp6 * 100 / m_stats.accepted_tcp << " %" + // TorrentPier end + + << "
rejected tcp" << m_stats.rejected_tcp + << "
announced" << m_stats.announced(); + if (m_stats.announced()) + { + os << "
announced http " << m_stats.announced_http << "" << m_stats.announced_http * 100 / m_stats.announced() << " %" + << "
announced udp" << m_stats.announced_udp << "" << m_stats.announced_udp * 100 / m_stats.announced() << " %" + + // TorrentPier begin + << "
with &ipv6=" << m_stats.announced_with_ipv6 << "" << m_stats.announced_with_ipv6 * 100 / m_stats.announced() << " %"; + // TorrentPier end + } + os << "
scraped full" << m_stats.scraped_full + << "
scraped" << m_stats.scraped(); + if (m_stats.scraped()) + { + os << "
scraped http" << m_stats.scraped_http << "" << m_stats.scraped_http * 100 / m_stats.scraped() << " %" + << "
scraped udp" << m_stats.scraped_udp << "" << m_stats.scraped_udp * 100 / m_stats.scraped() << " %"; + } + os << "
" + << "
up time" << duration2a(time() - m_stats.start_time) + << "
" + << "
anonymous connect" << m_config.m_anonymous_connect + << "
anonymous announce" << m_config.m_anonymous_announce + << "
anonymous scrape" << m_config.m_anonymous_scrape + << "
auto register" << m_config.m_auto_register + << "
full scrape" << m_config.m_full_scrape + + // TorrentPier begin + << "
free leech" << m_config.m_free_leech + << "
announce interval" << m_config.m_announce_interval + // TorrentPier end + + << "
read config time" << t - m_read_config_time << " / " << m_config.m_read_config_interval + << "
clean up time" << t - m_clean_up_time << " / " << m_config.m_clean_up_interval + + // TorrentPier begin + << "
read db files time" << t - m_read_db_files_time << " / " << m_config.m_read_files_interval; + // TorrentPier end + + if (m_use_sql) + { + os << "
read db users time" << t - m_read_db_users_time << " / " << m_config.m_read_db_interval + << "
write db files time" << t - m_write_db_files_time << " / " << m_config.m_write_db_interval + << "
write db users time" << t - m_write_db_users_time << " / " << m_config.m_write_db_interval; + } + os << "
"; + return os.str(); +} + +Cserver::t_user* Cserver::find_user_by_torrent_pass(const std::string& v, const std::string& info_hash) +{ + // TorrentPier begin + if (v.size() == 32) if (t_user* user = find_user_by_uid(read_int(4, hex_decode(v.substr(0, 8))))) + { + if (Csha1((boost::format("%s %s %d %s") % m_config.m_torrent_pass_private_key % user->passkey % user->uid % info_hash).str()).read().substr(0, 12) == hex_decode(v.substr(8))) + return user; + } + // TorrentPier end + + t_user** i = find_ptr(m_users_torrent_passes, v); + return i ? *i : NULL; +} + +Cserver::t_user* Cserver::find_user_by_uid(int v) +{ + return find_ptr(m_users, v); +} + +void Cserver::sig_handler(int v) +{ + switch (v) + { + case SIGTERM: + g_sig_term = true; + break; + } +} + +void Cserver::term() +{ + g_sig_term = true; +} + +std::string Cserver::column_name(int v) const +{ + switch (v) + { + case column_files_completed: + return m_config.m_column_files_completed; + case column_files_leechers: + return m_config.m_column_files_leechers; + case column_files_seeders: + return m_config.m_column_files_seeders; + case column_files_fid: + return m_config.m_column_files_fid; + case column_users_uid: + return m_config.m_column_users_uid; + + // TorrentPier begin + case column_files_dl_percent: + return m_config.m_column_files_dl_percent; + case column_users_can_leech: + return m_config.m_column_users_can_leech; + case column_users_torrents_limit: + return m_config.m_column_users_torrents_limit; + // TorrentPier end + + } + assert(false); + return ""; +} + +std::string Cserver::table_name(int v) const +{ + switch (v) + { + case table_announce_log: + return m_config.m_table_announce_log.empty() ? m_table_prefix + "announce_log" : m_config.m_table_announce_log; + case table_config: + return m_table_prefix + "config"; + case table_deny_from_hosts: + return m_config.m_table_deny_from_hosts.empty() ? m_table_prefix + "deny_from_hosts" : m_config.m_table_deny_from_hosts; + case table_files: + return m_config.m_table_files.empty() ? m_table_prefix + "files" : m_config.m_table_files; + case table_files_users: + return m_config.m_table_files_users.empty() ? m_table_prefix + "files_users" : m_config.m_table_files_users; + case table_scrape_log: + return m_config.m_table_scrape_log.empty() ? m_table_prefix + "scrape_log" : m_config.m_table_scrape_log; + case table_users: + return m_config.m_table_users.empty() ? m_table_prefix + "users" : m_config.m_table_users; + } + assert(false); + return ""; +} + +int Cserver::test_sql() +{ + if (!m_use_sql) + return 0; + try + { + /*mysql_get_server_version(m_database.handle()); + //xbtt + m_database.query("select id, ipa, port, event, info_hash, peer_id, downloaded, left0, uploaded, uid, mtime from " + table_name(table_announce_log) + " where 0"); + m_database.query("select name, value from " + table_name(table_config) + " where 0"); + \m_database.query("select begin, end from " + table_name(table_deny_from_hosts) + " where 0"); + m_database.query("select id, ipa, info_hash, uid, mtime from " + table_name(table_scrape_log) + " where 0"); + + // TorrentPier begin + m_database.query("select peer_hash, user_id, ip, ipv6, port, uploaded, downloaded, seeder, speed_up, speed_down, update_time, ul_gdc, ul_gdc_c, ul_16k_c, ul_eq_dl from " + table_name(table_files_users) + " where 0"); // Note: `port_open` is not used any more + m_database.query("select " + column_name(column_users_uid) + ", auth_key, " + + column_name(column_users_can_leech) + " as u_cl, " + column_name(column_users_torrents_limit) + + " as u_tl, u_down_total, u_up_total, u_up_release, u_down_today, u_up_today, u_up_bonus, max_up_speed, max_down_speed from " + table_name(table_users) + " where 0"); + + m_database.query("select bbt.info_hash, bt.seeder, bbt.reg_time, bbt.size, bbt.attach_id, bbt.topic_id, bbt.seeder_last_seen, bt.speed_up, bt.speed_down, bbt.poster_id, " + + column_name(column_files_dl_percent) + " from " + table_name(table_files) + " bbt LEFT JOIN bb_bt_tracker bt ON (bt.topic_id = bbt.topic_id) where 0"); + // TorrentPier: Files deletion table = table_name(table_files) + "_del" suffix + \m_database.query("select rpad(info_hash,20,' '), " + column_name(column_files_fid) + \+ ", is_del, dl_percent from " + table_name(table_files) + " where 0"); + m_database.query("select topic_id,user_id,user_status,last_modified_dlstatus from bb_bt_dlstatus_main where 0"); + m_database.query("select torrent_id,user_id,attach_id,t_up_total,t_down_total,t_bonus_total from bb_bt_tor_dl_stat where 0"); + // TorrentPier end + + m_read_users_can_leech = m_database.query("show columns from " + table_name(table_users) + " like 'can_leech'"); + m_read_users_peers_limit = m_database.query("show columns from " + table_name(table_users) + " like 'peers_limit'"); + m_read_users_torrent_pass = m_database.query("show columns from " + table_name(table_users) + " like 'torrent_pass'"); + m_read_users_torrents_limit = m_database.query("show columns from " + table_name(table_users) + " like 'torrents_limit'"); + m_read_users_wait_time = m_database.query("show columns from " + table_name(table_users) + " like 'wait_time'"); + */ + return 0; + } + catch (Cdatabase::exception&) + { + } + return 1; +} diff --git a/install/xbt/linux/Tracker/server.h b/install/xbt/linux/Tracker/server.h new file mode 100644 index 000000000..9a5b88409 --- /dev/null +++ b/install/xbt/linux/Tracker/server.h @@ -0,0 +1,274 @@ +#pragma once + +#include "config.h" +#include "connection.h" +#include "epoll.h" +#include "stats.h" +#include "tcp_listen_socket.h" +#include "tracker_input.h" +#include "udp_listen_socket.h" +#include +#include +#include +#include +#include +#include + +class Cserver +{ +public: + // TorrentPier begin + typedef std::string peer_key_c; + // TorrentPier end + + enum t_complete_status + { + e_seeder, + e_incomplete, + e_downloader, + }; + + struct t_peer + { + t_peer() + { + mtime = 0; + + // TorrentPier begin + dl_status = 0; // TorrentPier: 1 = downloading, 2 = complete + ipv6set = false; + host_ = 0; + // TorrentPier end + } + + long long downloaded; + long long uploaded; + time_t mtime; + int uid; + short port; + t_complete_status left; + + // TorrentPier begin + // boost::array peer_id; + + long long speed_dl; + long long speed_ul; + int dl_status; + bool xbt_error_empty; + // Upload Greatest Common Divisor + long long ul_gdc, ul_gdc_16k; + int ul_gdc_count, ul_16k_count, ul_eq_dl_count, end_vip; + + bool ipv6set; + // boost::array ipv6; + char ipv6[16]; + int host_; + // TorrentPier end + }; + + typedef std::map t_peers; + + struct t_deny_from_host + { + unsigned int begin; + bool marked; + }; + + struct t_file + { + void clean_up(time_t t, Cserver&); + void debug(std::ostream&) const; + std::string select_peers(const Ctracker_input&) const; + + // TorrentPier begin + std::string select_peers6(const Ctracker_input&) const; + // TorrentPier end + + t_file() + { + completed = 0; + dirty = true; + fid = 0; + leechers = 0; + seeders = 0; + + // TorrentPier begin + completed_inc = 0; + tor_size = 0; + tor_attach_id = tor_topic_id = 0; + tor_seeder_last_seen = 0; + tor_last_seeder_uid = tor_poster_id = 0; + speed_dl = speed_ul = 0; + dl_percent = 100; + // TorrentPier end + } + + t_peers peers; + time_t ctime; + int completed; + int fid; + int leechers; + int seeders; + bool dirty; + + // TorrentPier begin + int completed_inc; + long long tor_size; + int tor_attach_id, tor_topic_id; + time_t tor_seeder_last_seen; + int tor_last_seeder_uid, tor_poster_id; + long long speed_dl, speed_ul; + int dl_percent; + // TorrentPier end + }; + + struct t_user + { + t_user() + { + can_leech = true; + completes = 0; + incompletes = 0; + peers_limit = 0; + torrents_limit = 0; + wait_time = 0; + user_vip = 0; + user_vip_exp = 0; + user_park = 0; + user_active = 1; + } + + bool can_leech; + bool marked; + int uid; + int completes; + int incompletes; + int peers_limit; + std::string passkey; + int torrents_limit; + int wait_time; + int user_vip; + int user_vip_exp; + int user_park; + int user_active; + }; + + int test_sql(); + void accept(const Csocket&); + t_user* find_user_by_torrent_pass(const std::string&, const std::string& info_hash); + t_user* find_user_by_uid(int); + void read_config(); + void write_db_files(); + void write_db_users(); + void read_db_deny_from_hosts(); + void read_db_files(); + void read_db_files_sql(); + void read_db_users(); + void clean_up(); + std::string insert_peer(const Ctracker_input&, bool udp, t_user*); + std::string debug(const Ctracker_input&) const; + std::string statistics() const; + Cvirtual_binary select_peers(const Ctracker_input&) const; + Cvirtual_binary scrape(const Ctracker_input&); + int run(); + static void term(); + Cserver(Cdatabase&, const std::string& table_prefix, bool use_sql, const std::string& conf_file); + + const t_file* file(const std::string& id) const + { + return find_ptr(m_files, id); + } + + const Cconfig& config() const + { + return m_config; + } + + long long secret() const + { + return m_secret; + } + + Cstats& stats() + { + return m_stats; + } + + time_t time() const + { + return m_time; + } +private: + enum + { + column_files_completed, + column_files_fid, + column_files_leechers, + column_files_seeders, + column_users_uid, + table_announce_log, + table_config, + table_deny_from_hosts, + table_files, + table_files_users, + table_scrape_log, + table_users, + + // TorrentPier begin + column_files_dl_percent, + column_users_can_leech, + column_users_torrents_limit, + // TorrentPier end + }; + + typedef boost::ptr_list t_connections; + typedef std::list t_tcp_sockets; + typedef std::list t_udp_sockets; + typedef std::map t_files; + typedef std::map t_deny_from_hosts; + typedef std::map t_users; + typedef std::map t_users_torrent_passes; + + static void sig_handler(int v); + std::string column_name(int v) const; + std::string table_name(int) const; + + Cconfig m_config; + Cstats m_stats; + bool m_read_users_can_leech; + bool m_read_users_peers_limit; + bool m_read_users_torrent_pass; + bool m_read_users_torrents_limit; + bool m_read_users_wait_time; + bool m_use_sql; + time_t m_clean_up_time; + time_t m_read_config_time; + time_t m_read_db_deny_from_hosts_time; + time_t m_read_db_files_time; + time_t m_read_db_users_time; + time_t m_time; + time_t m_write_db_files_time; + time_t m_write_db_users_time; + int m_fid_end; + long long m_secret; + t_connections m_connections; + Cdatabase& m_database; + Cepoll m_epoll; + t_deny_from_hosts m_deny_from_hosts; + t_files m_files; + t_users m_users; + t_users_torrent_passes m_users_torrent_passes; + std::string m_announce_log_buffer; + std::string m_conf_file; + std::string m_files_users_updates_buffer; + std::string m_scrape_log_buffer; + std::string m_table_prefix; + std::string m_users_updates_buffer; + + // TorrentPier begin + std::string m_users_dl_status_buffer; + std::string m_tor_dl_stat_buffer; + std::string m_cheat_buffer; + std::string m_vip_buffer; + // TorrentPier end +}; diff --git a/install/xbt/linux/Tracker/stats.h b/install/xbt/linux/Tracker/stats.h new file mode 100644 index 000000000..7570bdc7c --- /dev/null +++ b/install/xbt/linux/Tracker/stats.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +class Cstats +{ +public: + Cstats() + { + accepted_tcp = 0; + announced_http = 0; + announced_udp = 0; + rejected_tcp = 0; + scraped_full = 0; + scraped_http = 0; + scraped_udp = 0; + start_time = time(NULL); + + // TorrentPier begin + announced_with_ipv6 = 0; + accepted_tcp4 = 0; + accepted_tcp6 = 0; + // TorrentPier end + } + + long long announced() const + { + return announced_http + announced_udp; + } + + long long scraped() const + { + return scraped_http + scraped_udp; + } + + long long accepted_tcp; + long long announced_http; + long long announced_udp; + long long rejected_tcp; + long long scraped_full; + long long scraped_http; + long long scraped_udp; + time_t start_time; + + // TorrentPier begin + long long announced_with_ipv6; + long long accepted_tcp4; + long long accepted_tcp6; + // TorrentPier end +}; diff --git a/install/xbt/linux/Tracker/stdafx.cpp b/install/xbt/linux/Tracker/stdafx.cpp new file mode 100644 index 000000000..a27b824da --- /dev/null +++ b/install/xbt/linux/Tracker/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/install/xbt/linux/Tracker/stdafx.h b/install/xbt/linux/Tracker/stdafx.h new file mode 100644 index 000000000..80f2eb108 --- /dev/null +++ b/install/xbt/linux/Tracker/stdafx.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#define FD_SETSIZE 1024 +#define NOMINMAX + +#define atoll _atoi64 +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TorrentPier begin +#include +// TorrentPier end + +#endif + +typedef unsigned char byte; diff --git a/install/xbt/linux/Tracker/tcp_listen_socket.cpp b/install/xbt/linux/Tracker/tcp_listen_socket.cpp new file mode 100644 index 000000000..ac378b1d0 --- /dev/null +++ b/install/xbt/linux/Tracker/tcp_listen_socket.cpp @@ -0,0 +1,20 @@ +#include "stdafx.h" +#include "tcp_listen_socket.h" + +#include "server.h" + +Ctcp_listen_socket::Ctcp_listen_socket() +{ + m_server = NULL; +} + +Ctcp_listen_socket::Ctcp_listen_socket(Cserver* server, const Csocket& s) +{ + m_server = server; + m_s = s; +} + +void Ctcp_listen_socket::process_events(int events) +{ + m_server->accept(m_s); +} diff --git a/install/xbt/linux/Tracker/tcp_listen_socket.h b/install/xbt/linux/Tracker/tcp_listen_socket.h new file mode 100644 index 000000000..94316ff38 --- /dev/null +++ b/install/xbt/linux/Tracker/tcp_listen_socket.h @@ -0,0 +1,14 @@ +#pragma once + +#include "client.h" + +class Cserver; + +class Ctcp_listen_socket: public Cclient +{ +public: + virtual void process_events(int); + Cclient::s; + Ctcp_listen_socket(); + Ctcp_listen_socket(Cserver*, const Csocket&); +}; diff --git a/install/xbt/linux/Tracker/tracker_input.cpp b/install/xbt/linux/Tracker/tracker_input.cpp new file mode 100644 index 000000000..ab7d61705 --- /dev/null +++ b/install/xbt/linux/Tracker/tracker_input.cpp @@ -0,0 +1,347 @@ +#include "stdafx.h" +#include "tracker_input.h" + +#include +#include +#include + +// TorrentPier begin +#ifdef WIN32 + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int newval = (unsigned int) (*tp * 10 + (pch - digits)); + + if (newval > 255) + return (0); + *tp = newval; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(const char *src, unsigned char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} + +int my_inet_pton(int af, const char *src, void *dst) +{ + return (inet_pton6(src, (unsigned char *) dst)); +} + +#define inet_pton my_inet_pton + +#endif + +Ctracker_input::Ctracker_input(int family) +// TorrentPier end +{ + m_compact = false; + m_downloaded = 0; + m_event = e_none; + m_ipa = 0; + m_left = 0; + m_port = 0; + m_uploaded = 0; + m_num_want = -1; + + // TorrentPier begin + m_ipv6set = false; + m_family = family; + m_protocol = 0; + // TorrentPier end +} + +void Ctracker_input::set(const std::string& name, const std::string& value) +{ + if (name.empty()) + return; + switch (name[0]) + { + case 'c': + if (name == "compact") + m_compact = atoi(value.c_str()); + break; + case 'd': + if (name == "downloaded") + m_downloaded = atoll(value.c_str()); + break; + case 'e': + if (name == "event") + { + if (value == "completed") + m_event = e_completed; + else if (value == "started") + m_event = e_started; + else if (value == "stopped") + m_event = e_stopped; + else if (value == "paused") + m_event = e_paused; + else + m_event = e_none; + } + break; + case 'i': + if (name == "info_hash" && value.size() == 20) + { + m_info_hash = value; + m_info_hashes.push_back(value); + } + + // TorrentPier begin + else if (name == "ip" || name == "ipv4") + m_ipa = inet_addr(value.c_str()); + else if (name == "ipv6") { + m_ipv6set = inet_pton(AF_INET6, value.c_str(), m_ipv6bin); + if (m_ipv6bin[0] == '\xFE' && m_ipv6bin[1] == '\x80') m_ipv6set = false; + } + // TorrentPier end + + break; + case 'l': + if (name == "left") + m_left = atoll(value.c_str()); + break; + case 'n': + if (name == "numwant") + m_num_want = atoi(value.c_str()); + break; + case 'p': + if (name == "peer_id" && value.size() == 20) + m_peer_id = value; + else if (name == "port") + m_port = htons(atoi(value.c_str())); + + // TorrentPier begin + else if (name == "p") + m_protocol = atoi(value.c_str()); + // TorrentPier end + + break; + case 'u': + if (name == "uploaded") + m_uploaded = atoll(value.c_str()); + // TorrentPier begin + else if (name == "uk") + m_passkey = value; + // TorrentPier end + break; + } +} + +bool Ctracker_input::valid() const +{ + return m_downloaded >= 0 + && (m_event != e_completed || !m_left) + && m_info_hash.size() == 20 + && m_left >= -1 + && m_peer_id.size() == 20 + && m_port >= 0 + && m_uploaded >= 0; +} +bool Ctracker_input::banned() const +{ + if (m_peer_id[7] == '-') + // standard id + switch (m_peer_id[0]) + { + case '-': + switch (m_peer_id[1]) + { + case 'A': // -AZ* > Azureus + return boost::istarts_with(m_peer_id, "-AZ2304") + || boost::istarts_with(m_peer_id, "-AZ2302") + || boost::istarts_with(m_peer_id, "-AZ2300") + || boost::istarts_with(m_peer_id, "-AZ2206") + || boost::istarts_with(m_peer_id, "-AZ2205") + || boost::istarts_with(m_peer_id, "-AZ2204") + || boost::istarts_with(m_peer_id, "-AZ2203") + || boost::istarts_with(m_peer_id, "-AZ2202") + || boost::istarts_with(m_peer_id, "-AZ2201"); + case 'B': // -BC* > BitComet, -BB* > ? + return boost::istarts_with(m_peer_id, "-BB") + || boost::istarts_with(m_peer_id, "-BC0060"); + case 'F': // -FG* > FlashGet + return boost::istarts_with(m_peer_id, "-FG"); + case 'U': // -UT* > uTorrent + return boost::istarts_with(m_peer_id, "-UT11") + || boost::istarts_with(m_peer_id, "-UT11"); + case 'T': // -TS* > TorrentStorm + return boost::istarts_with(m_peer_id, "-TS"); + default: + return false; + } + //case 'A': // A* > ABC + //case 'M': // M* > Mainline + //case 'S': // S* > Shadow + //case 'T': // T* > BitTornado + //case 'X': // XBT* > XBT + //case 'O': // O* > Opera + default: + return false; + } + else + switch (m_peer_id[0]) + { + case '-': + switch (m_peer_id[1]) + { + //case 'G': // -G3* > G3 + case 'S': // -SZ* > ? + return boost::istarts_with(m_peer_id, "-SZ"); + default: + return false; + } + case 'e': // exbc* > BitComet/BitLord + return boost::istarts_with(m_peer_id, "exbc0L") + || boost::istarts_with(m_peer_id, "exbcL") + || boost::istarts_with(m_peer_id, "exbcLORD") + || boost::istarts_with(m_peer_id, "exbc\08") + || boost::istarts_with(m_peer_id, "exbc\09") + || boost::istarts_with(m_peer_id, "exbc\0:"); + //case 'S': // S57* > Shadow 57 + case 'O': // O* > Opera + return boost::istarts_with(m_peer_id, "O"); + case 'F': // FG* > FlashGet + return boost::istarts_with(m_peer_id, "FG"); + default: + return boost::istarts_with(m_peer_id, "BS") + || boost::istarts_with(m_peer_id, "FUTB") + || boost::istarts_with(m_peer_id, "TO038") + || boost::istarts_with(m_peer_id, "turbo"); + } + return false; +} diff --git a/install/xbt/linux/Tracker/tracker_input.h b/install/xbt/linux/Tracker/tracker_input.h new file mode 100644 index 000000000..dd29b1b52 --- /dev/null +++ b/install/xbt/linux/Tracker/tracker_input.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +// TorrentPier begin +#include +// TorrentPier end + +class Ctracker_input +{ +public: + void set(const std::string& name, const std::string& value); + bool valid() const; + + // TorrentPier begin + bool banned() const; + Ctracker_input(int family = AF_INET); + // TorrentPier end + + enum t_event + { + e_none, + e_completed, + e_started, + e_stopped, + e_paused, + }; + + typedef std::vector t_info_hashes; + + t_event m_event; + std::string m_info_hash; + t_info_hashes m_info_hashes; + int m_ipa; + std::string m_peer_id; + long long m_downloaded; + long long m_left; + int m_port; + long long m_uploaded; + int m_num_want; + bool m_compact; + + // TorrentPier begin + std::string m_passkey; + bool m_ipv6set; + char m_ipv6bin[16]; + int m_family; + int m_protocol; // 4 for IPv4-only, 6 for IPv6-only + // TorrentPier end +}; diff --git a/install/xbt/linux/Tracker/transaction.cpp b/install/xbt/linux/Tracker/transaction.cpp new file mode 100644 index 000000000..783fb05fb --- /dev/null +++ b/install/xbt/linux/Tracker/transaction.cpp @@ -0,0 +1,164 @@ +#include "stdafx.h" +#include "transaction.h" + +#include +#include +#include +#include +#include + +Ctransaction::Ctransaction(Cserver& server, const Csocket& s): + m_server(server) +{ + m_s = s; +} + +long long Ctransaction::connection_id() const +{ + const int cb_s = 12; + char s[cb_s]; + write_int(8, s, m_server.secret()); + write_int(4, s + 8, m_a.sin_addr.s_addr); + char d[20]; + (Csha1(const_memory_range(s, cb_s))).read(d); + return read_int(8, d); +} + +void Ctransaction::recv() +{ + const int cb_b = 2 << 10; + char b[cb_b]; + while (1) + { + socklen_t cb_a = sizeof(sockaddr_in); + int r = m_s.recvfrom(memory_range(b, cb_b), reinterpret_cast(&m_a), &cb_a); + if (r == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + std::cerr << "recv failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; + return; + } + if (r < uti_size) + return; + switch (read_int(4, b + uti_action, b + r)) + { + case uta_connect: + if (r >= utic_size) + send_connect(const_memory_range(b, r)); + break; + case uta_announce: + if (r >= utia_size) + send_announce(const_memory_range(b, r)); + break; + case uta_scrape: + if (r >= utis_size) + send_scrape(const_memory_range(b, r)); + break; + } + } +} + +void Ctransaction::send_connect(const_memory_range r) +{ + if (!m_server.config().m_anonymous_connect) + return; + if (read_int(8, r + uti_connection_id, r.end) != 0x41727101980ll) + return; + const int cb_d = 2 << 10; + char d[cb_d]; + write_int(4, d + uto_action, uta_connect); + write_int(4, d + uto_transaction_id, read_int(4, r + uti_transaction_id, r.end)); + write_int(8, d + utoc_connection_id, connection_id()); + send(const_memory_range(d, utoc_size)); +} + +void Ctransaction::send_announce(const_memory_range r) +{ + if (read_int(8, r + uti_connection_id, r.end) != connection_id()) + return; + if (!m_server.config().m_anonymous_announce) + { + send_error(r, "access denied"); + return; + } + Ctracker_input ti; + ti.m_downloaded = read_int(8, r + utia_downloaded, r.end); + ti.m_event = static_cast(read_int(4, r + utia_event, r.end)); + ti.m_info_hash.assign(reinterpret_cast(r + utia_info_hash), 20); + ti.m_ipa = read_int(4, r + utia_ipa, r.end) && is_private_ipa(m_a.sin_addr.s_addr) + ? htonl(read_int(4, r + utia_ipa, r.end)) + : m_a.sin_addr.s_addr; + ti.m_left = read_int(8, r + utia_left, r.end); + ti.m_num_want = read_int(4, r + utia_num_want, r.end); + ti.m_peer_id.assign(reinterpret_cast(r + utia_peer_id), 20); + ti.m_port = htons(read_int(2, r + utia_port, r.end)); + ti.m_uploaded = read_int(8, r + utia_uploaded, r.end); + std::string error = m_server.insert_peer(ti, true, NULL); + if (!error.empty()) + { + send_error(r, error); + return; + } + const Cserver::t_file* file = m_server.file(ti.m_info_hash); + if (!file) + return; + const int cb_d = 2 << 10; + char d[cb_d]; + write_int(4, d + uto_action, uta_announce); + write_int(4, d + uto_transaction_id, read_int(4, r + uti_transaction_id, r.end)); + write_int(4, d + utoa_interval, m_server.config().m_announce_interval); + write_int(4, d + utoa_leechers, file->leechers); + write_int(4, d + utoa_seeders, file->seeders); + std::string peers = file->select_peers(ti); + memcpy(d + utoa_size, peers.data(), peers.size()); + send(const_memory_range(d, d + utoa_size + peers.size())); +} + +void Ctransaction::send_scrape(const_memory_range r) +{ + if (read_int(8, r + uti_connection_id, r.end) != connection_id()) + return; + if (!m_server.config().m_anonymous_scrape) + { + send_error(r, "access denied"); + return; + } + const int cb_d = 2 << 10; + char d[cb_d]; + write_int(4, d + uto_action, uta_scrape); + write_int(4, d + uto_transaction_id, read_int(4, r + uti_transaction_id, r.end)); + char* w = d + utos_size; + for (r += utis_size; r + 20 <= r.end && w + 12 <= d + cb_d; r += 20) + { + if (const Cserver::t_file* file = m_server.file(r.sub_range(0, 20).string())) + { + w = write_int(4, w, file->seeders); + w = write_int(4, w, file->completed); + w = write_int(4, w, file->leechers); + } + else + { + w = write_int(4, w, 0); + w = write_int(4, w, 0); + w = write_int(4, w, 0); + } + } + m_server.stats().scraped_udp++; + send(const_memory_range(d, w)); +} + +void Ctransaction::send_error(const_memory_range r, const std::string& msg) +{ + const int cb_d = 2 << 10; + char d[cb_d]; + write_int(4, d + uto_action, uta_error); + write_int(4, d + uto_transaction_id, read_int(4, r + uti_transaction_id, r.end)); + memcpy(d + utoe_size, msg.data(), msg.size()); + send(const_memory_range(d, utoe_size + msg.size())); +} + +void Ctransaction::send(const_memory_range b) +{ + if (m_s.sendto(b, reinterpret_cast(&m_a), sizeof(sockaddr_in)) != b.size()) + std::cerr << "send failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; +} diff --git a/install/xbt/linux/Tracker/transaction.h b/install/xbt/linux/Tracker/transaction.h new file mode 100644 index 000000000..1a0f2faa1 --- /dev/null +++ b/install/xbt/linux/Tracker/transaction.h @@ -0,0 +1,20 @@ +#pragma once + +#include "server.h" + +class Ctransaction +{ +public: + long long connection_id() const; + void recv(); + void send(const_memory_range); + void send_announce(const_memory_range); + void send_connect(const_memory_range); + void send_scrape(const_memory_range); + void send_error(const_memory_range, const std::string& msg); + Ctransaction(Cserver&, const Csocket&); +private: + Cserver& m_server; + Csocket m_s; + sockaddr_in m_a; +}; diff --git a/install/xbt/linux/Tracker/udp_listen_socket.cpp b/install/xbt/linux/Tracker/udp_listen_socket.cpp new file mode 100644 index 000000000..13bceea8e --- /dev/null +++ b/install/xbt/linux/Tracker/udp_listen_socket.cpp @@ -0,0 +1,21 @@ +#include "stdafx.h" +#include "udp_listen_socket.h" + +#include "transaction.h" + +Cudp_listen_socket::Cudp_listen_socket() +{ + m_server = NULL; +} + +Cudp_listen_socket::Cudp_listen_socket(Cserver* server, const Csocket& s) +{ + m_server = server; + m_s = s; +} + +void Cudp_listen_socket::process_events(int events) +{ + if (events & EPOLLIN) + Ctransaction(*m_server, m_s).recv(); +} diff --git a/install/xbt/linux/Tracker/udp_listen_socket.h b/install/xbt/linux/Tracker/udp_listen_socket.h new file mode 100644 index 000000000..7e215e097 --- /dev/null +++ b/install/xbt/linux/Tracker/udp_listen_socket.h @@ -0,0 +1,14 @@ +#pragma once + +#include "client.h" + +class Cserver; + +class Cudp_listen_socket: public Cclient +{ +public: + virtual void process_events(int); + Cclient::s; + Cudp_listen_socket(); + Cudp_listen_socket(Cserver*, const Csocket&); +}; diff --git a/install/xbt/linux/Tracker/xbt_tracker b/install/xbt/linux/Tracker/xbt_tracker new file mode 100644 index 000000000..bb16e79da Binary files /dev/null and b/install/xbt/linux/Tracker/xbt_tracker differ diff --git a/install/xbt/linux/Tracker/xbt_tracker.pid b/install/xbt/linux/Tracker/xbt_tracker.pid new file mode 100644 index 000000000..65cbcc0f4 --- /dev/null +++ b/install/xbt/linux/Tracker/xbt_tracker.pid @@ -0,0 +1 @@ +43033 diff --git a/install/xbt/linux/Tracker/xbtt.sh b/install/xbt/linux/Tracker/xbtt.sh new file mode 100644 index 000000000..8c2ef8898 --- /dev/null +++ b/install/xbt/linux/Tracker/xbtt.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# + +# PROVIDE: xbtt +# REQUIRE: NETWORKING mysql + +# Add the following line to /etc/rc.conf to enable XBTT: +# xbtt_enable (bool): Set to "NO" by default. +# Set it to "YES" to enable XBTT. +# xbtt_path (str): Path to dir with xbt_tracker.conf + +. /etc/rc.subr + +name="xbtt" +rcvar=`set_rcvar` +start_precmd="${name}_prestart" + +command="/db/www/xbtt/Tracker/xbt_tracker" + +: ${xbtt_path="/db/www/xbtt/Tracker"} + +xbtt_prestart() +{ + cd ${xbtt_path} +} + +load_rc_config $name +run_rc_command "$1" + + diff --git a/install/xbt/linux/misc/alerts.cpp b/install/xbt/linux/misc/alerts.cpp new file mode 100644 index 000000000..4a33ed481 --- /dev/null +++ b/install/xbt/linux/misc/alerts.cpp @@ -0,0 +1,17 @@ +#include "stdafx.h" +#include "alerts.h" + +#include "bt_misc.h" + +int Calert::pre_dump() const +{ + return m_message.size() + m_source.size() + 16; +} + +void Calert::dump(Cstream_writer& w) const +{ + w.write_int(4, m_time); + w.write_int(4, m_level); + w.write_data(m_message); + w.write_data(m_source); +} diff --git a/install/xbt/linux/misc/alerts.h b/install/xbt/linux/misc/alerts.h new file mode 100644 index 000000000..3c81e8336 --- /dev/null +++ b/install/xbt/linux/misc/alerts.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include "stream_writer.h" + +class Calert +{ +public: + enum t_level + { + emerg, + alert, + crit, + error, + warn, + notice, + info, + debug, + }; + + time_t time() const + { + return m_time; + } + + t_level level() const + { + return m_level; + } + + const std::string& message() const + { + return m_message; + } + + void message(const std::string& v) + { + m_message = v; + } + + Calert(t_level level, const std::string& message) + { + m_time = ::time(NULL); + m_level = level; + m_message = message; + } + + Calert(t_level level, const std::string& source, const std::string& message) + { + m_time = ::time(NULL); + m_level = level; + m_message = message; + m_source = source; + } + + int pre_dump() const; + void dump(Cstream_writer&) const; +private: + time_t m_time; + t_level m_level; + std::string m_message; + std::string m_source; +}; + +class Calerts: public std::list +{ +public: + void push_back(const value_type& v) + { + std::list::push_back(v); + while (size() > 250) + erase(begin()); + } +}; diff --git a/install/xbt/linux/misc/bt_misc.cpp b/install/xbt/linux/misc/bt_misc.cpp new file mode 100644 index 000000000..4c5166fda --- /dev/null +++ b/install/xbt/linux/misc/bt_misc.cpp @@ -0,0 +1,354 @@ +#include "stdafx.h" +#include "bt_misc.h" + +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#pragma comment(lib, "ws2_32") +#endif + +std::string escape_string(const std::string& v) +{ + std::string w; + w.reserve(v.length()); + BOOST_FOREACH(char i, v) + { + if (isgraph(i & 0xff)) + w += i; + else + { + switch (i) + { + case '\0': + w += "\\0"; + break; + default: + w += "\\x" + hex_encode(2, i); + } + } + } + return w; +} + +std::string generate_random_string(int l) +{ + std::string v; + while (l--) + v += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[rand() % 62]; + return v; +} + +std::string get_env(const std::string& v) +{ + const char* p = getenv(v.c_str()); + return p ? p : ""; +} + +static int hex_decode(char v) +{ + if (v >= '0' && v <= '9') + return v - '0'; + if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + return -1; +}; + +std::string hex_decode(const std::string& v) +{ + std::string r; + r.resize(v.length() >> 1); + for (size_t i = 0; i + 2 <= v.length(); i += 2) + { + int a = hex_decode(v[i]); + r[i >> 1] = a << 4 | hex_decode(v[i + 1]); + } + return r; +} + +std::string hex_encode(int l, int v) +{ + std::string r; + r.resize(l); + while (l--) + { + r[l] = "0123456789abcdef"[v & 0xf]; + v >>= 4; + } + return r; +}; + +std::string n(long long v) +{ + char b[21]; +#ifdef WIN32 + sprintf(b, "%I64d", v); +#else + sprintf(b, "%lld", v); +#endif + return b; +} + +std::string hex_encode(const_memory_range v) +{ + std::string r; + r.reserve(v.size() << 1); + for (size_t i = 0; i < v.size(); i++) + r += hex_encode(2, v[i]); + return r; +} + +std::string js_encode(const std::string& v) +{ + std::string r; + BOOST_FOREACH(int i, v) + { + switch (i) + { + case '\"': + case '\'': + case '\\': + r += '\\'; + default: + r += i; + } + } + return r; +} + +std::string uri_decode(const std::string& v) +{ + std::string r; + r.reserve(v.length()); + for (size_t i = 0; i < v.length(); i++) + { + char c = v[i]; + switch (c) + { + case '%': + { + if (i + 1 > v.length()) + return ""; + int l = v[++i]; + r += hex_decode(l) << 4 | hex_decode(v[++i]); + break; + } + case '+': + r += ' '; + break; + default: + r += c; + } + } + return r; +}; + +std::string uri_encode(const std::string& v) +{ + std::string r; + r.reserve(v.length()); + BOOST_FOREACH(char c, v) + { + if (isalpha(c & 0xff) || isdigit(c & 0xff)) + r += c; + else + { + switch (c) + { + case ' ': + r += '+'; + break; + case '-': + case ',': + case '.': + case '@': + case '_': + r += c; + break; + default: + r += "%" + hex_encode(2, c); + } + } + } + return r; +}; + +bool is_private_ipa(int a) +{ + return (ntohl(a) & 0xff000000) == 0x0a000000 + || (ntohl(a) & 0xff000000) == 0x7f000000 + || (ntohl(a) & 0xfff00000) == 0xac100000 + || (ntohl(a) & 0xffff0000) == 0xc0a80000; +} + +std::string b2a(long long v, const char* postfix) +{ + int l; + for (l = 0; v < -9999 || v > 999999; l++) + v >>= 10; + char d[32]; + char* w = d; + if (v > 999) + { + l++; + int b = static_cast((v & 0x3ff) * 100 >> 10); + v >>= 10; + w += sprintf(w, "%d", static_cast(v)); + if (v < 10 && b % 10) + w += sprintf(w, ".%02d", b); + else if (v < 100 && b > 9) + w += sprintf(w, ".%d", b / 10); + } + else + w += sprintf(w, "%d", static_cast(v)); + const char* a[] = {"", " k", " m", " g", " t", " p", " e", " z", " y"}; + w += sprintf(w, "%s", a[l]); + if (postfix) + w += sprintf(w, "%s%s", l ? "" : " ", postfix); + return d; +} + +static std::string peer_id2a(const std::string& name, const std::string& peer_id, int i) +{ + for (size_t j = i; j < peer_id.size(); j++) + { + if (!isalnum(peer_id[j])) + return name + peer_id.substr(i, j - i); + } + return name + peer_id.substr(i); +} + +std::string peer_id2a(const std::string& v) +{ + if (v.length() != 20) + return ""; + if (v[7] == '-') + { + switch (v[0]) + { + case '-': + if (v[1] == 'A' && v[2] == 'Z') + return peer_id2a("Azureus ", v, 3); + if (v[1] == 'B' && v[2] == 'C') + return peer_id2a("BitComet ", v, 3); + if (v[1] == 'U' && v[2] == 'T') + return peer_id2a("uTorrent ", v, 3); + if (v[1] == 'T' && v[2] == 'S') + return peer_id2a("TorrentStorm ", v, 3); + break; + case 'A': + return peer_id2a("ABC ", v, 1); + case 'M': + return peer_id2a("Mainline ", v, 1); + case 'S': + return peer_id2a("Shadow ", v, 1); + case 'T': + return peer_id2a("BitTornado ", v, 1); + case 'X': + if (v[1] == 'B' && v[2] == 'T') + return peer_id2a("XBT Client ", v, 3) + (v.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWYXZabcdefghijklmnopqrstuvwyxz", 8) == std::string::npos ? "" : " (fake)"); + break; + } + } + switch (v[0]) + { + case '-': + if (v[1] == 'G' && v[2] == '3') + return "G3"; + break; + case 'S': + if (v[1] == 5 && v[2] == 7 && v[3] >= 0 && v[3] < 10) + return "Shadow 57" + n(v[3]); + break; + case 'e': + if (v[1] == 'x' && v[2] == 'b' && v[3] == 'c' && v[4] >= 0 && v[4] < 10 && v[5] >= 0 && v[5] < 100) + return "BitComet " + n(v[4]) + '.' + n(v[5] / 10) + n(v[5] % 10); + } + return "Unknown"; +} + +std::string duration2a(float v) +{ + char d[32]; + if (v > 31557600) + sprintf(d, "%.1f years", v / 31557600); + else if (v > 2629800) + sprintf(d, "%.1f months", v / 2629800); + else if (v > 604800) + sprintf(d, "%.1f weeks", v / 604800); + else if (v > 86400) + sprintf(d, "%.1f days", v / 86400); + else if (v > 3600) + sprintf(d, "%.1f hours", v / 3600); + else if (v > 60) + sprintf(d, "%.1f minutes", v / 60); + else + sprintf(d, "%.1f seconds", v); + return d; +} + +std::string time2a(time_t v) +{ + const tm* date = localtime(&v); + if (!date) + return ""; + char b[20]; + sprintf(b, "%04d-%02d-%02d %02d:%02d:%02d", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); + return b; +} + +int merkle_tree_size(int v) +{ + int r = 0; + while (v > 1) + { + r += v++; + v >>= 1; + } + if (v == 1) + r++; + return r; +} + +std::string backward_slashes(std::string v) +{ + std::replace(v.begin(), v.end(), '/', '\\'); + return v; +} + +std::string forward_slashes(std::string v) +{ + std::replace(v.begin(), v.end(), '\\', '/'); + return v; +} + +std::string native_slashes(const std::string& v) +{ +#ifdef WIN32 + return backward_slashes(v); +#else + return forward_slashes(v); +#endif +} + +int hms2i(int h, int m, int s) +{ + return 60 * (h + 60 * m) + s; +} + +int xbt_atoi(const std::string& a) +{ + int i = atoi(a.c_str()); + return n(i) == a ? i : 0; +} + +std::string xbt_version2a(int v) +{ + return n(v / 100) + "." + n(v / 10 % 10) + "." + n(v % 10); +} diff --git a/install/xbt/linux/misc/bt_misc.h b/install/xbt/linux/misc/bt_misc.h new file mode 100644 index 000000000..79907adda --- /dev/null +++ b/install/xbt/linux/misc/bt_misc.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +std::string b2a(long long v, const char* postfix = NULL); +std::string backward_slashes(std::string); +std::string duration2a(float); +std::string escape_string(const std::string&); +std::string forward_slashes(std::string); +std::string generate_random_string(int); +std::string get_env(const std::string&); +int hms2i(int h, int m, int s); +bool is_private_ipa(int a); +int merkle_tree_size(int v); +std::string n(long long); +std::string native_slashes(const std::string&); +std::string hex_decode(const std::string&); +std::string hex_encode(int l, int v); +std::string hex_encode(const_memory_range); +std::string js_encode(const std::string&); +std::string peer_id2a(const std::string&); +std::string time2a(time_t); +std::string uri_decode(const std::string&); +std::string uri_encode(const std::string&); +int xbt_atoi(const std::string&); +std::string xbt_version2a(int); + +inline long long htonll(long long v) +{ + const unsigned char* a = reinterpret_cast(&v); + long long b = a[0] << 24 | a[1] << 16 | a[2] << 8 | a[3]; + return b << 32 | static_cast(a[4]) << 24 | a[5] << 16 | a[6] << 8 | a[7]; +} + +inline long long ntohll(long long v) +{ + return htonll(v); +} + +enum +{ + hs_name_size = 0, + hs_name = 1, + hs_reserved = 20, + hs_info_hash = 28, + hs_size = 48, +}; + +enum +{ + uta_connect, + uta_announce, + uta_scrape, + uta_error, +}; + +enum +{ + uti_connection_id = 0, + uti_action = 8, + uti_transaction_id = 12, + uti_size = 16, + + utic_size = 16, + + utia_info_hash = 16, + utia_peer_id = 36, + utia_downloaded = 56, + utia_left = 64, + utia_uploaded = 72, + utia_event = 80, + utia_ipa = 84, + utia_key = 88, + utia_num_want = 92, + utia_port = 96, + utia_size = 98, + + utis_size = 16, + + uto_action = 0, + uto_transaction_id = 4, + uto_size = 8, + + utoc_connection_id = 8, + utoc_size = 16, + + utoa_interval = 8, + utoa_leechers = 12, + utoa_seeders = 16, + utoa_size = 20, + + utos_size = 8, + + utoe_size = 8, +}; diff --git a/install/xbt/linux/misc/bt_strings.h b/install/xbt/linux/misc/bt_strings.h new file mode 100644 index 000000000..d46ed2cc2 --- /dev/null +++ b/install/xbt/linux/misc/bt_strings.h @@ -0,0 +1,115 @@ +#pragma once + +enum +{ + bti_choke , + bti_unchoke, + bti_interested, + bti_uninterested, + bti_have, + bti_bitfield, + bti_request, + bti_piece, + bti_cancel, + + bti_get_info, + bti_info, + bti_get_peers, + bti_peers, + + bti_extended = 20, + + bti_bvalue = 0x40, +}; + +enum +{ + bti_extended_handshake, + bti_extended_ut_pex, +}; + +enum +{ + bti_none, + bti_completed, + bti_started, + bti_stopped, +}; + +const std::string bts_action = "action"; +const std::string bts_admin_port = "admin port"; +const std::string bts_admin_user = "admin user"; +const std::string bts_admin_pass = "admin pass"; +const std::string bts_announce = "announce"; +const std::string bts_announce_list = "announce-list"; +const std::string bts_banned_client = "access denied, banned client"; +const std::string bts_can_not_leech = "access denied, leeching forbidden, you are only allowed to seed"; +const std::string bts_park = "access denied, account parked"; +const std::string bts_close_torrent = "close torrent"; +const std::string bts_complete = "complete"; +const std::string bts_complete_total = "complete total"; +const std::string bts_completed_at = "completed at"; +const std::string bts_completes_dir = "completes dir"; +const std::string bts_down_rate = "down rate"; +const std::string bts_downloaded = "downloaded"; +const std::string bts_erase_torrent = "erase torrent"; +const std::string bts_events = "events"; +const std::string bts_failure_reason = "failure reason"; +const std::string bts_files = "files"; +const std::string bts_flags = "flags"; +const std::string bts_get_options = "get options"; +const std::string bts_get_status = "get status"; +const std::string bts_hash = "hash"; +const std::string bts_incomplete = "incomplete"; +const std::string bts_incomplete_total = "incomplete total"; +const std::string bts_incompletes_dir = "incompletes dir"; +const std::string bts_info = "info"; +const std::string bts_interval = "interval"; +const std::string bts_ipa = "ip"; +const std::string bts_left = "left"; +const std::string bts_length = "length"; +const std::string bts_login = "login"; +const std::string bts_merkle_hash = "merkle hash"; +const std::string bts_message = "message"; +const std::string bts_min_interval = "min interval"; +const std::string bts_min_request_interval = "min_request_interval"; +const std::string bts_name = "name"; +const std::string bts_open_torrent = "open torrent"; +const std::string bts_pass = "pass"; +const std::string bts_path = "path"; +const std::string bts_peer_id = "peer id"; +const std::string bts_peer_limit = "peer limit"; +const std::string bts_peer_port = "peer port"; +const std::string bts_peers = "peers"; +const std::string bts_peers_limit_reached = "access denied, peers limit reached"; +const std::string bts_piece_length = "piece length"; +const std::string bts_pieces = "pieces"; +const std::string bts_private = "private"; +const std::string bts_port = "port"; +const std::string bts_priority = "priority"; +const std::string bts_seeding_ratio = "seeding ratio"; +const std::string bts_set_options = "set options"; +const std::string bts_set_priority = "set priority"; +const std::string bts_set_state = "set state"; +const std::string bts_size = "size"; +const std::string bts_started_at = "started at"; +const std::string bts_state = "state"; +const std::string bts_time = "time"; +const std::string bts_torrent = "torrent"; +const std::string bts_torrent_limit = "torrent limit"; +const std::string bts_torrents_dir = "torrents dir"; +const std::string bts_torrents_limit_reached = "access denied, torrents limit reached"; +const std::string bts_total_downloaded = "total downloaded"; +const std::string bts_total_uploaded = "total uploaded"; +const std::string bts_tracker_port = "tracker port"; +const std::string bts_unregistered_ipa = "unregistered IP address"; +const std::string bts_unregistered_torrent = "unregistered torrent"; +const std::string bts_unregistered_torrent_pass = "unregistered torrent pass"; +const std::string bts_unsupported_tracker_protocol = "unsupported tracker protocol, please upgrade your client"; +const std::string bts_up_rate = "up rate"; +const std::string bts_upload_rate = "upload rate"; +const std::string bts_upload_slots = "upload slots"; +const std::string bts_user_agent = "user agent"; +const std::string bts_version = "version"; +const std::string bts_wait_time = "access denied, wait time in effect"; +const std::string bts_disabled = "access denied, account disabled"; \ No newline at end of file diff --git a/install/xbt/linux/misc/bt_torrent.cpp b/install/xbt/linux/misc/bt_torrent.cpp new file mode 100644 index 000000000..8adaac78b --- /dev/null +++ b/install/xbt/linux/misc/bt_torrent.cpp @@ -0,0 +1,77 @@ +#include "stdafx.h" +#include "bt_torrent.h" + +#include "bt_strings.h" + +Cbt_torrent::Cbt_torrent() +{ +} + +Cbt_torrent::Cbt_torrent(const Cbvalue& v) +{ + write(v); +} + +int Cbt_torrent::write(const Cbvalue& v) +{ + m_announce = v[bts_announce].s(); + m_announces.clear(); + const Cbvalue::t_list& announces = v[bts_announce_list].l(); + for (Cbvalue::t_list::const_iterator i = announces.begin(); i != announces.end(); i++) + { + for (Cbvalue::t_list::const_iterator j = i->l().begin(); j != i->l().end(); j++) + m_announces.push_back(j->s()); + } + return write_info(v[bts_info]); +} + +int Cbt_torrent::write_info(const Cbvalue& v) +{ + m_files.clear(); + const Cbvalue::t_list& files = v[bts_files].l(); + for (Cbvalue::t_list::const_iterator i = files.begin(); i != files.end(); i++) + { + std::string name; + long long size = (*i)[bts_length].i(); + { + const Cbvalue::t_list& path = (*i)[bts_path].l(); + for (Cbvalue::t_list::const_iterator i = path.begin(); i != path.end(); i++) + { + if (i->s().empty() || i->s()[0] == '.' || i->s().find_first_of("\"*/:<>?\\|") != std::string::npos) + return 1; + name += '/' + i->s(); + } + } + if (name.empty()) + return 1; + m_files.push_back(Cfile(name, size)); + } + if (m_files.empty()) + m_files.push_back(Cfile("", v[bts_length].i())); + m_name = v[bts_name].s(); + m_piece_size = v[bts_piece_length].i(); + return 0; +} + +long long Cbt_torrent::size() const +{ + long long r = 0; + for (t_files::const_iterator i = m_files.begin(); i != m_files.end(); i++) + r += i->size(); + return r; +} + +bool Cbt_torrent::valid() const +{ + for (t_files::const_iterator i = m_files.begin(); i != m_files.end(); i++) + { + if (i->size() < 0) + return false; + } + return !files().empty() + && !name().empty() + && name()[0] != '.' + && name().find_first_of("\"*/:<>?\\|") == std::string::npos + && piece_size() >= 16 << 10 + && piece_size() <= 4 << 20; +} diff --git a/install/xbt/linux/misc/bt_torrent.h b/install/xbt/linux/misc/bt_torrent.h new file mode 100644 index 000000000..7540d782b --- /dev/null +++ b/install/xbt/linux/misc/bt_torrent.h @@ -0,0 +1,75 @@ +#pragma once + +#include "bvalue.h" + +class Cbt_torrent +{ +public: + class Cfile + { + public: + const std::string& name() const + { + return m_name; + } + + long long size() const + { + return m_size; + } + + Cfile() + { + } + + Cfile(const std::string& name, long long size) + { + m_name = name; + m_size = size; + } + private: + std::string m_name; + long long m_size; + }; + + typedef std::vector t_announces; + typedef std::vector t_files; + + long long size() const; + bool valid() const; + int write(const Cbvalue&); + int write_info(const Cbvalue&); + Cbt_torrent(); + Cbt_torrent(const Cbvalue&); + + const std::string& announce() const + { + return m_announce; + } + + const t_announces& announces() const + { + return m_announces; + } + + const t_files& files() const + { + return m_files; + } + + const std::string& name() const + { + return m_name; + } + + int piece_size() const + { + return m_piece_size; + } +private: + std::string m_announce; + t_announces m_announces; + t_files m_files; + std::string m_name; + int m_piece_size; +}; diff --git a/install/xbt/linux/misc/bt_tracker_account.cpp b/install/xbt/linux/misc/bt_tracker_account.cpp new file mode 100644 index 000000000..9f3458af9 --- /dev/null +++ b/install/xbt/linux/misc/bt_tracker_account.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "xbt/virtual_binary.h" +#include "bt_tracker_account.h" + +#include "stream_reader.h" + +Cbt_tracker_account::Cbt_tracker_account() +{ +} + +Cbt_tracker_account::Cbt_tracker_account(const std::string& tracker, const std::string& user, const std::string& pass) +{ + m_tracker = tracker; + m_user = user; + m_pass = pass; +} + +int Cbt_tracker_account::pre_dump() const +{ + return tracker().size() + user().size() + pass().size() + 12; +} + +void Cbt_tracker_account::dump(Cstream_writer& w) const +{ + w.write_data(tracker()); + w.write_data(user()); + w.write_data(pass()); +} + +Cvirtual_binary Cbt_tracker_accounts::dump() const +{ + int cb_d = 4; + for (const_iterator i = begin(); i != end(); i++) + cb_d += i->pre_dump(); + Cvirtual_binary d; + Cstream_writer w(d.write_start(cb_d)); + w.write_int(4, size()); + for (const_iterator i = begin(); i != end(); i++) + i->dump(w); + assert(w.w() == d.end()); + return d; + +} + +const Cbt_tracker_account* Cbt_tracker_accounts::find(const std::string& v) const +{ + for (const_iterator i = begin(); i != end(); i++) + { + if (i->tracker() == v) + return &*i; + } + return NULL; +} + +void Cbt_tracker_accounts::load(const Cvirtual_binary& s) +{ + clear(); + if (s.size() < 4) + return; + Cstream_reader r(s); + for (int count = r.read_int(4); count--; ) + { + std::string tracker = r.read_string(); + std::string name = r.read_string(); + std::string pass = r.read_string(); + push_back(Cbt_tracker_account(tracker, name, pass)); + } +} diff --git a/install/xbt/linux/misc/bt_tracker_account.h b/install/xbt/linux/misc/bt_tracker_account.h new file mode 100644 index 000000000..34ee73247 --- /dev/null +++ b/install/xbt/linux/misc/bt_tracker_account.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +class Cbt_tracker_account +{ +public: + int pre_dump() const; + void dump(Cstream_writer&) const; + Cbt_tracker_account(); + Cbt_tracker_account(const std::string& tracker, const std::string& user, const std::string& pass); + + const std::string& tracker() const + { + return m_tracker; + } + + const std::string& user() const + { + return m_user; + } + + const std::string& pass() const + { + return m_pass; + } +private: + std::string m_tracker; + std::string m_user; + std::string m_pass; +}; + +class Cbt_tracker_accounts: public std::list +{ +public: + Cvirtual_binary dump() const; + const Cbt_tracker_account* find(const std::string&) const; + void load(const Cvirtual_binary&); +}; diff --git a/install/xbt/linux/misc/bt_tracker_url.cpp b/install/xbt/linux/misc/bt_tracker_url.cpp new file mode 100644 index 000000000..c31ed9711 --- /dev/null +++ b/install/xbt/linux/misc/bt_tracker_url.cpp @@ -0,0 +1,82 @@ +#include "stdafx.h" +#include "bt_tracker_url.h" + +#include + +Cbt_tracker_url::Cbt_tracker_url() +{ +} + +Cbt_tracker_url::Cbt_tracker_url(const std::string& v) +{ + write(v); +} + +void Cbt_tracker_url::clear() +{ + m_protocol = tp_unknown; + m_host.erase(); + m_port = 0; + m_path.erase(); +} + +bool Cbt_tracker_url::valid() const +{ + switch (m_protocol) + { + case tp_http: + if (m_path.empty() || m_path[0] != '/') + return false; + case tp_udp: + return !m_host.empty() + && m_port >= 0 && m_port < 0x10000; + } + return false; +} + +void Cbt_tracker_url::write(const std::string& v) +{ + clear(); + size_t a; + int protocol; + int port; + if (boost::istarts_with(v, "http://")) + { + a = 7; + protocol = tp_http; + port = 80; + } + else if (boost::istarts_with(v, "udp://")) + { + a = 6; + protocol = tp_udp; + port = 2710; + } + else + return; + size_t b = v.find_first_of("/:", a); + std::string host; + if (b == std::string::npos) + host = v.substr(a); + else + { + host = v.substr(a, b - a); + if (v[b] == '/') + m_path = v.substr(b); + else + { + b++; + a = v.find('/', b); + if (a == std::string::npos) + port = atoi(v.substr(b).c_str()); + else + { + port = atoi(v.substr(b, a - b).c_str()); + m_path = v.substr(a); + } + } + } + m_protocol = protocol; + m_host = host; + m_port = port; +} diff --git a/install/xbt/linux/misc/bt_tracker_url.h b/install/xbt/linux/misc/bt_tracker_url.h new file mode 100644 index 000000000..a6ad3c905 --- /dev/null +++ b/install/xbt/linux/misc/bt_tracker_url.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +class Cbt_tracker_url +{ +public: + enum + { + tp_http, + tp_udp, + tp_unknown + }; + + void clear(); + bool valid() const; + void write(const std::string&); + Cbt_tracker_url(const std::string&); + Cbt_tracker_url(); + + int m_protocol; + std::string m_host; + int m_port; + std::string m_path; +}; diff --git a/install/xbt/linux/misc/bvalue.cpp b/install/xbt/linux/misc/bvalue.cpp new file mode 100644 index 000000000..6daa9f371 --- /dev/null +++ b/install/xbt/linux/misc/bvalue.cpp @@ -0,0 +1,370 @@ +#include "stdafx.h" +#include "bvalue.h" + +#include +#include +#include "bt_misc.h" + +Cbvalue::Cbvalue(long long v) +{ + m_value_type = vt_int; + m_int = v; +} + +Cbvalue::Cbvalue(t_value_type t) +{ + switch (m_value_type = t) + { + case vt_int: + break; + case vt_string: + m_string = new std::string; + break; + case vt_list: + m_list = new t_list; + break; + case vt_dictionary: + m_map = new t_map; + break; + default: + assert(false); + } +} + +Cbvalue::Cbvalue(const std::string& v) +{ + m_value_type = vt_string; + m_string = new std::string(v); +} + +Cbvalue::Cbvalue(const Cbvalue& v) +{ + switch (m_value_type = v.m_value_type) + { + case vt_int: + m_int = v.m_int; + break; + case vt_string: + m_string = new std::string(*v.m_string); + break; + case vt_list: + m_list = new t_list(*v.m_list); + break; + case vt_dictionary: + m_map = new t_map(*v.m_map); + break; + default: + assert(false); + } +} + +Cbvalue::Cbvalue(const_memory_range s) +{ + m_value_type = vt_int; + if (write(s)) + clear(); +} + +Cbvalue::~Cbvalue() +{ + clear(); +} + +const Cbvalue& Cbvalue::operator=(const Cbvalue& v) +{ + clear(); + m_value_type = v.m_value_type; + switch (v.m_value_type) + { + case vt_int: + m_int = v.m_int; + break; + case vt_string: + m_string = new std::string(*v.m_string); + break; + case vt_list: + m_list = new t_list(*v.m_list); + break; + case vt_dictionary: + m_map = new t_map(*v.m_map); + break; + default: + assert(false); + } + return *this; +} + +int Cbvalue::write(const_memory_range s) +{ + return write(reinterpret_cast(s.begin), s.size()); +} + +int Cbvalue::write(const char* s, int cb_s) +{ + return write(s, s + cb_s); +} + +int Cbvalue::write(const char*& s, const char* s_end) +{ + clear(); + if (s >= s_end) + return 1; + switch (*s++) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + const char* a = s - 1; + while (s < s_end && *s != ':') + s++; + if (s++ >= s_end) + return 1; + int l = atoi(a); + if (s + l > s_end) + return 1; + m_value_type = vt_string; + m_string = new std::string(s, l); + s += l; + return 0; + } + case 'd': + { + m_value_type = vt_dictionary; + m_map = new t_map; + while (s < s_end && *s != 'e') + { + Cbvalue v; + Cbvalue w; + if (v.write(s, s_end) || v.m_value_type != vt_string) + return 1; + if (w.write(s, s_end)) + return 1; + (*m_map)[*v.m_string] = w; + } + if (s++ >= s_end) + return 1; + return 0; + } + break; + case 'i': + { + const char* a = s; + while (s < s_end && *s != 'e') + s++; + if (s++ >= s_end) + return 1; + m_value_type = vt_int; + m_int = atoll(a); + return 0; + } + case 'l': + { + m_value_type = vt_list; + m_list = new t_list; + while (s < s_end && *s != 'e') + { + Cbvalue v; + if (v.write(s, s_end)) + return 1; + m_list->push_back(v); + } + if (s++ >= s_end) + return 1; + return 0; + } + } + return 1; +} + +void Cbvalue::clear() +{ + switch (m_value_type) + { + case vt_int: + break; + case vt_string: + delete m_string; + break; + case vt_list: + delete m_list; + break; + case vt_dictionary: + delete m_map; + break; + default: + assert(false); + } + m_value_type = vt_int; +} + +const Cbvalue::t_map& Cbvalue::d() const +{ + static t_map z; + return m_value_type == vt_dictionary ? *m_map : z; +} + +bool Cbvalue::d_has(const std::string& v) const +{ + return m_value_type == vt_dictionary && m_map->find(v) != m_map->end(); +} + +const Cbvalue& Cbvalue::d(const std::string& v) const +{ + if (m_value_type == vt_dictionary) + { + t_map::const_iterator i = m_map->find(v); + if (i != m_map->end()) + return i->second; + } + static Cbvalue z; + return z; +} + +const Cbvalue& Cbvalue::operator[](const std::string& v) const +{ + return d(v); +} + +long long Cbvalue::i() const +{ + return m_value_type == vt_int ? m_int : 0; +} + +const Cbvalue::t_list& Cbvalue::l() const +{ + static t_list z; + return m_value_type == vt_list ? *m_list : z; +} + +const std::string& Cbvalue::s() const +{ + static std::string z; + return m_value_type == vt_string ? *m_string : z; +} + +Cbvalue& Cbvalue::d(const std::string& v, const Cbvalue& w) +{ + if (m_value_type != vt_dictionary) + { + clear(); + m_value_type = vt_dictionary; + m_map = new t_map; + } + (*m_map)[v] = w; + return *this; +} + +Cbvalue& Cbvalue::l(const Cbvalue& v) +{ + if (m_value_type != vt_list) + { + clear(); + m_value_type = vt_list; + m_list = new t_list; + } + (*m_list).push_back(v); + return *this; +} + +int Cbvalue::pre_read() const +{ + switch (m_value_type) + { + case vt_int: + return n(m_int).size() + 2; + case vt_string: + return n(m_string->size()).size() + m_string->size() + 1; + case vt_list: + { + int v = 2; + BOOST_FOREACH(t_list::const_reference i, *m_list) + v += i.pre_read(); + return v; + } + case vt_dictionary: + { + int v = 2; + BOOST_FOREACH(t_map::const_reference i, *m_map) + v += n(i.first.size()).size() + i.first.size() + i.second.pre_read() + 1; + return v; + } + } + assert(false); + return 0; +} + +Cvirtual_binary Cbvalue::read() const +{ + Cvirtual_binary d; + int cb_d = read(d.write_start(pre_read())); + assert(cb_d == d.size()); + return d; +} + +int Cbvalue::read(void* d) const +{ + return read(reinterpret_cast(d)); +} + +int Cbvalue::read(char* d) const +{ + char* w = d; + switch (m_value_type) + { + case vt_int: +#ifdef WIN32 + sprintf(d, "i%I64d", m_int); +#else + sprintf(d, "i%lld", m_int); +#endif + w += strlen(d); + *w++ = 'e'; + return w - d; + case vt_string: +#ifdef WIN32 + sprintf(w, "%d:", m_string->size()); +#else + sprintf(w, "%zu:", m_string->size()); +#endif + w += n(m_string->size()).size() + 1; + memcpy(w, m_string->data(), m_string->size()); + w += m_string->size(); + return w - d; + case vt_list: + { + *w++ = 'l'; + for (t_list::const_iterator i = m_list->begin(); i != m_list->end(); i++) + w += i->read(w); + *w++ = 'e'; + return w - d; + } + case vt_dictionary: + { + *w++ = 'd'; + for (t_map::const_iterator i = m_map->begin(); i != m_map->end(); i++) + { +#ifdef WIN32 + sprintf(w, "%d:", i->first.size()); +#else + sprintf(w, "%zu:", i->first.size()); +#endif + w += n(i->first.size()).size() + 1; + memcpy(w, i->first.data(), i->first.size()); + w += i->first.size(); + w += i->second.read(w); + } + *w++ = 'e'; + return w - d; + } + } + assert(false); + return 0; +} diff --git a/install/xbt/linux/misc/bvalue.h b/install/xbt/linux/misc/bvalue.h new file mode 100644 index 000000000..5a031617c --- /dev/null +++ b/install/xbt/linux/misc/bvalue.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include + +class Cbvalue +{ +public: + enum t_value_type + { + vt_int, + vt_string, + vt_list, + vt_dictionary, + }; + + typedef std::map t_map; + typedef std::vector t_list; + + void clear(); + const t_map& d() const; + const t_list& l() const; + long long i() const; + const std::string& s() const; + bool d_has(const std::string&) const; + Cbvalue& d(const std::string& v, const Cbvalue& w); + Cbvalue& l(const Cbvalue& v); + int pre_read() const; + int read(char* d) const; + int read(void* d) const; + Cvirtual_binary read() const; + int write(const char* s, int cb_s); + int write(const_memory_range); + Cbvalue(long long v = 0); + Cbvalue(t_value_type t); + Cbvalue(const std::string& v); + Cbvalue(const Cbvalue&); + Cbvalue(const_memory_range); + const Cbvalue& operator=(const Cbvalue&); + const Cbvalue& operator[](const std::string&) const; + ~Cbvalue(); +private: + const Cbvalue& d(const std::string&) const; + + t_value_type m_value_type; + + union + { + long long m_int; + std::string* m_string; + t_list* m_list; + t_map* m_map; + }; + + int write(const char*& s, const char* s_end); +}; diff --git a/install/xbt/linux/misc/config_base.h b/install/xbt/linux/misc/config_base.h new file mode 100644 index 000000000..18a8bd63b --- /dev/null +++ b/install/xbt/linux/misc/config_base.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include +#include +#include +#include + +class Cconfig_base +{ +public: + template + struct t_attribute + { + const char* key; + T* value; + T default_value; + }; + + template + class t_attributes: public std::map > + { + }; + + virtual int set(const std::string& name, const std::string& value) + { + t_attributes::iterator i = m_attributes_string.find(name); + if (i != m_attributes_string.end()) + *i->second.value = value; + else + return set(name, atoi(value.c_str())); + return 0; + } + + virtual int set(const std::string& name, int value) + { + t_attributes::iterator i = m_attributes_int.find(name); + if (i != m_attributes_int.end()) + *i->second.value = value; + else + return set(name, static_cast(value)); + return 0; + } + + virtual int set(const std::string& name, bool value) + { + t_attributes::iterator i = m_attributes_bool.find(name); + if (i != m_attributes_bool.end()) + *i->second.value = value; + else + return 1; + return 0; + } + + std::istream& load(std::istream& is) + { + for (std::string s; getline(is, s); ) + { + size_t i = s.find('='); + if (i != std::string::npos) + set(boost::trim_copy(s.substr(0, i)), boost::trim_copy(s.substr(i + 1))); + } + return is; + } + + int load(const std::string& file) + { + std::ifstream is(file.c_str()); + if (!is) + return 1; + load(is); + return !is.eof(); + } + + std::ostream& save(std::ostream& os) const + { + save_map(os, m_attributes_bool); + save_map(os, m_attributes_int); + save_map(os, m_attributes_string); + return os; + } + +protected: + t_attributes m_attributes_bool; + t_attributes m_attributes_int; + t_attributes m_attributes_string; + + template + void fill_map(t_attribute* attributes, const t_attributes* s, t_attributes& d) + { + for (t_attribute* i = attributes; i->key; i++) + { + *i->value = s ? *s->find(i->key)->second.value : i->default_value; + d[i->key] = *i; + } + } + + template + void save_map(std::ostream& os, const T& v) const + { + for (typename T::const_iterator i = v.begin(); i != v.end(); i++) + { + if (*i->second.value == i->second.default_value) + os << "# "; + os << i->first << " = " << *i->second.value << std::endl; + } + } +}; diff --git a/install/xbt/linux/misc/const_memory_range.h b/install/xbt/linux/misc/const_memory_range.h new file mode 100644 index 000000000..70fa7abf2 --- /dev/null +++ b/install/xbt/linux/misc/const_memory_range.h @@ -0,0 +1,252 @@ +#pragma once + +#include +#include +#include + +template +class memory_range_base +{ +public: + memory_range_base() + { + begin = NULL; + end = NULL; + } + + template + memory_range_base(const memory_range_base& v) + { + assign(v.begin, v.end); + } + + memory_range_base(void* begin_, void* end_) + { + assign(begin_, end_); + } + + memory_range_base(void* begin_, size_t size) + { + assign(begin_, size); + } + + template + memory_range_base(boost::array& v) + { + assign(&v.front(), v.size()); + } + + template + memory_range_base(boost::array& v) + { + assign(&v.front(), v.size()); + } + + memory_range_base(std::vector& v) + { + assign(&v.front(), v.size()); + } + + memory_range_base(std::vector& v) + { + assign(&v.front(), v.size()); + } + + memory_range_base assign(void* begin_, void* end_) + { + begin = reinterpret_cast(begin_); + end = reinterpret_cast(end_); + return *this; + } + + memory_range_base assign(void* begin_, size_t size) + { + begin = reinterpret_cast(begin_); + end = begin + size; + return *this; + } + + void clear() + { + begin = end = NULL; + } + + bool empty() const + { + return begin == end; + } + + size_t size() const + { + return end - begin; + } + + std::string string() const + { + return std::string(reinterpret_cast(begin), size()); + } + + memory_range_base sub_range(size_t o, size_t s) + { + return memory_range_base(begin + o, s); + } + + operator T() const + { + return begin; + } + + memory_range_base operator++(int) + { + memory_range_base t = *this; + begin++; + return t; + } + + memory_range_base operator+=(size_t v) + { + begin += v; + return *this; + } + + T begin; + T end; +}; + +typedef memory_range_base memory_range; + +template +class const_memory_range_base +{ +public: + const_memory_range_base() + { + begin = NULL; + end = NULL; + } + + template + const_memory_range_base(const const_memory_range_base& v) + { + assign(v.begin, v.end); + } + + template + const_memory_range_base(const memory_range_base& v) + { + assign(v.begin, v.end); + } + + const_memory_range_base(const void* begin_, const void* end_) + { + assign(begin_, end_); + } + + const_memory_range_base(const void* begin_, size_t size) + { + assign(begin_, size); + } + + const_memory_range_base(const std::string& v) + { + assign(v.data(), v.size()); + } + + template + const_memory_range_base(const boost::array& v) + { + assign(&v.front(), v.size()); + } + + template + const_memory_range_base(const boost::array& v) + { + assign(&v.front(), v.size()); + } + + const_memory_range_base(const std::vector& v) + { + assign(&v.front(), v.size()); + } + + const_memory_range_base(const std::vector& v) + { + assign(&v.front(), v.size()); + } + + const_memory_range_base assign(const void* begin_, const void* end_) + { + begin = reinterpret_cast(begin_); + end = reinterpret_cast(end_); + return *this; + } + + const_memory_range_base assign(const void* begin_, size_t size) + { + begin = reinterpret_cast(begin_); + end = begin + size; + return *this; + } + + void clear() + { + begin = end = NULL; + } + + bool empty() const + { + return begin == end; + } + + template + const_memory_range_base find(U v) const + { + const_memory_range_base t = *this; + while (!t.empty() && *t != v) + t++; + return t; + } + + long long i() const + { + return atoll(reinterpret_cast(begin)); + } + + size_t size() const + { + return end - begin; + } + + std::string string() const + { + return std::string(reinterpret_cast(begin), size()); + } + + const_memory_range_base sub_range(size_t o, size_t s) + { + return const_memory_range_base(begin + o, s); + } + + operator T() const + { + return begin; + } + + const_memory_range_base operator++(int) + { + const_memory_range_base t = *this; + begin++; + return t; + } + + const_memory_range_base operator+=(size_t v) + { + begin += v; + return *this; + } + + T begin; + T end; +}; + +typedef const_memory_range_base const_memory_range; diff --git a/install/xbt/linux/misc/find_ptr.h b/install/xbt/linux/misc/find_ptr.h new file mode 100644 index 000000000..231a447d1 --- /dev/null +++ b/install/xbt/linux/misc/find_ptr.h @@ -0,0 +1,15 @@ +#pragma once + +template +typename T::mapped_type* find_ptr(T& c, U v) +{ + typename T::iterator i = c.find(v); + return i == c.end() ? NULL : &i->second; +} + +template +const typename T::mapped_type* find_ptr(const T& c, U v) +{ + typename T::const_iterator i = c.find(v); + return i == c.end() ? NULL : &i->second; +} diff --git a/install/xbt/linux/misc/sha1.cpp b/install/xbt/linux/misc/sha1.cpp new file mode 100644 index 000000000..ff90e66b8 --- /dev/null +++ b/install/xbt/linux/misc/sha1.cpp @@ -0,0 +1,419 @@ +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "stdafx.h" +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = context->Intermediate_Hash[i>>2] + >> 8 * ( 3 - ( i & 0x03 ) ); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const void *message_array0, + size_t length) +{ + const uint8_t *message_array = reinterpret_cast(message_array0); + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + SHA1ProcessMessageBlock(context); +} + +Csha1::Csha1() +{ + SHA1Reset(&m_context); +} + +Csha1::Csha1(const_memory_range s) +{ + SHA1Reset(&m_context); + write(s); +} + +void Csha1::read(void* d) +{ + SHA1Result(&m_context, reinterpret_cast(d)); +} + +std::string Csha1::read() +{ + char d[SHA1HashSize]; + read(d); + return std::string(d, SHA1HashSize); +} + +void Csha1::write(const_memory_range s) +{ + SHA1Input(&m_context, s, s.size()); +} diff --git a/install/xbt/linux/misc/sha1.h b/install/xbt/linux/misc/sha1.h new file mode 100644 index 000000000..e26a11191 --- /dev/null +++ b/install/xbt/linux/misc/sha1.h @@ -0,0 +1,94 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#include +#include + +#ifdef WIN32 +typedef unsigned int uint32_t; +typedef int int_least16_t; +typedef unsigned char uint8_t; +#endif + +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typdef the following: + * name meaning + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const void *, + size_t); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +class Csha1 +{ +public: + void read(void*); + std::string read(); + void write(const_memory_range); + Csha1(); + Csha1(const_memory_range); +private: + SHA1Context m_context; +}; + +#endif + diff --git a/install/xbt/linux/misc/socket.cpp b/install/xbt/linux/misc/socket.cpp new file mode 100644 index 000000000..20e1f2c30 --- /dev/null +++ b/install/xbt/linux/misc/socket.cpp @@ -0,0 +1,223 @@ +#include "stdafx.h" +#include "socket.h" + +#ifdef WIN32 +#pragma comment(lib, "ws2_32.lib") +#else +#include +#include +#include +#include +#include +#endif + +#ifndef INADDR_NONE +const int INADDR_NONE = -1; +#endif + +#ifndef MSG_NOSIGNAL +const int MSG_NOSIGNAL = 0; +#endif + +static bool g_start_up_done = false; + +Csocket::Csocket(SOCKET s) +{ + m_source = s == INVALID_SOCKET ? NULL : new Csocket_source(s); +} + +int Csocket::accept(int& h, int& p) +{ + sockaddr_in a; + socklen_t cb_a = sizeof(sockaddr_in); + a.sin_family = AF_INET; + int r = ::accept(*this, reinterpret_cast(&a), &cb_a); + if (r == INVALID_SOCKET) + return r; + h = a.sin_addr.s_addr; + p = a.sin_port; + return 0; +} + +int Csocket::bind(int h, int p) +{ + sockaddr_in a = {0}; + a.sin_family = AF_INET; + a.sin_addr.s_addr = h; + a.sin_port = p; + return ::bind(*this, reinterpret_cast(&a), sizeof(sockaddr_in)); +} + +int Csocket::blocking(bool v) +{ +#ifdef FIONBIO + unsigned long p = !v; + return ioctlsocket(*this, FIONBIO, &p); +#else + return fcntl(*this, F_SETFL, v ? 0 : O_NONBLOCK) == -1; +#endif +} + +void Csocket::close() +{ + *this = INVALID_SOCKET; +} + +int Csocket::connect(int h, int p) +{ + sockaddr_in a = {0}; + a.sin_family = AF_INET; + a.sin_addr.s_addr = h; + a.sin_port = p; + return ::connect(*this, reinterpret_cast(&a), sizeof(sockaddr_in)); +} + +int Csocket::listen() +{ + return ::listen(*this, SOMAXCONN); +} + +const Csocket& Csocket::open(int t, bool _blocking) +{ + start_up(); + *this = socket(AF_INET, t, 0); + if (*this != INVALID_SOCKET && !_blocking && blocking(false)) + close(); + return *this; +} + +int Csocket::recv(memory_range d) const +{ + return ::recv(*this, reinterpret_cast(d.begin), d.size(), MSG_NOSIGNAL); +} + +int Csocket::recvfrom(memory_range d, sockaddr* a, socklen_t* cb_a) const +{ + return ::recvfrom(*this, reinterpret_cast(d.begin), d.size(), MSG_NOSIGNAL, a, cb_a); +} + +int Csocket::send(const_memory_range s) const +{ + return ::send(*this, reinterpret_cast(s.begin), s.size(), MSG_NOSIGNAL); +} + +int Csocket::sendto(const_memory_range s, const sockaddr* a, socklen_t cb_a) const +{ + return ::sendto(*this, reinterpret_cast(s.begin), s.size(), MSG_NOSIGNAL, a, cb_a); +} + +int Csocket::getsockopt(int level, int name, void* v, socklen_t& cb_v) +{ + return ::getsockopt(*this, level, name, reinterpret_cast(v), &cb_v); +} + +int Csocket::getsockopt(int level, int name, int& v) +{ + socklen_t cb_v = sizeof(int); + return getsockopt(level, name, &v, cb_v); +} + +int Csocket::setsockopt(int level, int name, const void* v, int cb_v) +{ + return ::setsockopt(*this, level, name, reinterpret_cast(v), cb_v); +} + +int Csocket::setsockopt(int level, int name, int v) +{ + return setsockopt(level, name, &v, sizeof(int)); +} + +int Csocket::get_host(const std::string& name) +{ + hostent* e = gethostbyname(name.c_str()); + return e && e->h_addrtype == AF_INET && e->h_length == sizeof(in_addr) && e->h_addr_list ? *reinterpret_cast(*e->h_addr_list) : INADDR_NONE; +} + +std::string Csocket::error2a(int v) +{ + switch (v) + { + case WSAEACCES: return "EACCES"; + case WSAEADDRINUSE: return "EADDRINUSE"; + case WSAEADDRNOTAVAIL: return "EADDRNOTAVAIL"; + case WSAEAFNOSUPPORT: return "EAFNOSUPPORT"; + case WSAEALREADY: return "EALREADY"; + case WSAEBADF: return "EBADF"; + case WSAECONNABORTED: return "ECONNABORTED"; + case WSAECONNREFUSED: return "ECONNREFUSED"; + case WSAECONNRESET: return "ECONNRESET"; + case WSAEDESTADDRREQ: return "EDESTADDRREQ"; + case WSAEDQUOT: return "EDQUOT"; + case WSAEFAULT: return "EFAULT"; + case WSAEHOSTDOWN: return "EHOSTDOWN"; + case WSAEHOSTUNREACH: return "EHOSTUNREACH"; + case WSAEINPROGRESS: return "EINPROGRESS"; + case WSAEINTR: return "EINTR"; + case WSAEINVAL: return "EINVAL"; + case WSAEISCONN: return "EISCONN"; + case WSAELOOP: return "ELOOP"; + case WSAEMFILE: return "EMFILE"; + case WSAEMSGSIZE: return "EMSGSIZE"; + case WSAENAMETOOLONG: return "ENAMETOOLONG"; + case WSAENETDOWN: return "ENETDOWN"; + case WSAENETRESET: return "ENETRESET"; + case WSAENETUNREACH: return "ENETUNREACH"; + case WSAENOBUFS: return "ENOBUFS"; + case WSAENOPROTOOPT: return "ENOPROTOOPT"; + case WSAENOTCONN: return "ENOTCONN"; + case WSAENOTEMPTY: return "ENOTEMPTY"; + case WSAENOTSOCK: return "ENOTSOCK"; + case WSAEOPNOTSUPP: return "EOPNOTSUPP"; + case WSAEPFNOSUPPORT: return "EPFNOSUPPORT"; + case WSAEPROTONOSUPPORT: return "EPROTONOSUPPORT"; + case WSAEPROTOTYPE: return "EPROTOTYPE"; + case WSAEREMOTE: return "EREMOTE"; + case WSAESHUTDOWN: return "ESHUTDOWN"; + case WSAESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT"; + case WSAESTALE: return "ESTALE"; + case WSAETIMEDOUT: return "ETIMEDOUT"; + case WSAETOOMANYREFS: return "ETOOMANYREFS"; + case WSAEUSERS: return "EUSERS"; + case WSAEWOULDBLOCK: return "EWOULDBLOCK"; +#ifdef WIN32 + case WSAECANCELLED: return "ECANCELLED"; + case WSAEDISCON: return "EDISCON"; + case WSAEINVALIDPROCTABLE: return "EINVALIDPROCTABLE"; + case WSAEINVALIDPROVIDER: return "EINVALIDPROVIDER"; + case WSAENOMORE: return "ENOMORE"; + case WSAEPROVIDERFAILEDINIT: return "EPROVIDERFAILEDINIT"; + case WSAEREFUSED: return "EREFUSED"; + case WSANOTINITIALISED: return "NOTINITIALISED"; + case WSASERVICE_NOT_FOUND: return "SERVICE_NOT_FOUND"; + case WSASYSCALLFAILURE: return "SYSCALLFAILURE"; + case WSASYSNOTREADY: return "SYSNOTREADY"; + case WSATYPE_NOT_FOUND: return "TYPE_NOT_FOUND"; + case WSAVERNOTSUPPORTED: return "VERNOTSUPPORTED"; + case WSA_E_CANCELLED: return "E_CANCELLED"; + case WSA_E_NO_MORE: return "E_NO_MORE"; +#endif + } + char b[12]; + sprintf(b, "%d", v); + return b; +} + +std::string Csocket::inet_ntoa(int v) +{ + in_addr a; + a.s_addr = v; + return ::inet_ntoa(a); +} + +int Csocket::start_up() +{ + if (g_start_up_done) + return 0; + g_start_up_done = true; +#ifdef WIN32 + WSADATA wsadata; + if (WSAStartup(MAKEWORD(2, 0), &wsadata)) + return 1; +#endif + return 0; +} diff --git a/install/xbt/linux/misc/socket.h b/install/xbt/linux/misc/socket.h new file mode 100644 index 000000000..2273bdbd0 --- /dev/null +++ b/install/xbt/linux/misc/socket.h @@ -0,0 +1,135 @@ +#pragma once + +#include +#include +#include +#include + +#ifdef WIN32 +#include + +typedef int socklen_t; +#else +#include +#include +#include + +#define closesocket close +#define ioctlsocket ioctl +#define WSAGetLastError() errno + +#define WSAEACCES EACCES +#define WSAEADDRINUSE EADDRINUSE +#define WSAEADDRNOTAVAIL EADDRNOTAVAIL +#define WSAEAFNOSUPPORT EAFNOSUPPORT +#define WSAEALREADY EALREADY +#define WSAEBADF EBADF +#define WSAECONNABORTED ECONNABORTED +#define WSAECONNREFUSED ECONNREFUSED +#define WSAECONNRESET ECONNRESET +#define WSAEDESTADDRREQ EDESTADDRREQ +#define WSAEDQUOT EDQUOT +#define WSAEFAULT EFAULT +#define WSAEHOSTDOWN EHOSTDOWN +#define WSAEHOSTUNREACH EHOSTUNREACH +#define WSAEINPROGRESS EINPROGRESS +#define WSAEINTR EINTR +#define WSAEINVAL EINVAL +#define WSAEISCONN EISCONN +#define WSAELOOP ELOOP +#define WSAEMFILE EMFILE +#define WSAEMSGSIZE EMSGSIZE +#define WSAENAMETOOLONG ENAMETOOLONG +#define WSAENETDOWN ENETDOWN +#define WSAENETRESET ENETRESET +#define WSAENETUNREACH ENETUNREACH +#define WSAENOBUFS ENOBUFS +#define WSAENOPROTOOPT ENOPROTOOPT +#define WSAENOTCONN ENOTCONN +#define WSAENOTEMPTY ENOTEMPTY +#define WSAENOTSOCK ENOTSOCK +#define WSAEOPNOTSUPP EOPNOTSUPP +#define WSAEPFNOSUPPORT EPFNOSUPPORT +#define WSAEPROTONOSUPPORT EPROTONOSUPPORT +#define WSAEPROTOTYPE EPROTOTYPE +#define WSAEREMOTE EREMOTE +#define WSAESHUTDOWN ESHUTDOWN +#define WSAESOCKTNOSUPPORT ESOCKTNOSUPPORT +#define WSAESTALE ESTALE +#define WSAETIMEDOUT ETIMEDOUT +#define WSAETOOMANYREFS ETOOMANYREFS +#define WSAEUSERS EUSERS +#define WSAEWOULDBLOCK EWOULDBLOCK + +typedef int SOCKET; + +const int INVALID_SOCKET = -1; +const int SOCKET_ERROR = -1; +#endif + +class Csocket_source: boost::noncopyable +{ +public: + Csocket_source(SOCKET s) + { + m_s = s; + mc_references = 0; + } + + ~Csocket_source() + { + closesocket(m_s); + } + + operator SOCKET() const + { + return m_s; + } + + friend void intrusive_ptr_add_ref(Csocket_source* v) + { + v->mc_references++; + } + + friend void intrusive_ptr_release(Csocket_source* v) + { + v->mc_references--; + if (!v->mc_references) + delete v; + } +private: + SOCKET m_s; + int mc_references; +}; + +class Csocket +{ +public: + static std::string error2a(int v); + static int get_host(const std::string& name); + static std::string inet_ntoa(int h); + static int start_up(); + int accept(int& h, int& p); + int bind(int h, int p); + int blocking(bool v); + void close(); + int connect(int h, int p); + int getsockopt(int level, int name, void* v, socklen_t& cb_v); + int getsockopt(int level, int name, int& v); + int listen(); + const Csocket& open(int t, bool blocking = false); + int recv(memory_range) const; + int recvfrom(memory_range, sockaddr* a, socklen_t* cb_a) const; + int send(const_memory_range) const; + int sendto(const_memory_range, const sockaddr* a, socklen_t cb_a) const; + int setsockopt(int level, int name, const void* v, int cb_v); + int setsockopt(int level, int name, int v); + Csocket(SOCKET = INVALID_SOCKET); + + operator SOCKET() const + { + return m_source ? static_cast(*m_source) : INVALID_SOCKET; + } +private: + boost::intrusive_ptr m_source; +}; diff --git a/install/xbt/linux/misc/sql/database.cpp b/install/xbt/linux/misc/sql/database.cpp new file mode 100644 index 000000000..67d739f56 --- /dev/null +++ b/install/xbt/linux/misc/sql/database.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "database.h" + +#include +#include +#include + +#ifdef WIN32 +#pragma comment(lib, "libmysql") +#else +#include +#endif + +Cdatabase::Cdatabase() +{ + mysql_init(&m_handle); +} + +Cdatabase::~Cdatabase() +{ + close(); +} + +void Cdatabase::open(const std::string& host, const std::string& user, const std::string& password, const std::string& database, bool echo_errors) +{ + m_echo_errors = echo_errors; + if (!mysql_init(&m_handle) || mysql_options(&m_handle, MYSQL_READ_DEFAULT_GROUP, "") || !mysql_real_connect(&m_handle, host.c_str(), user.c_str(), password.empty() ? NULL : password.c_str(), database.c_str(), 0, NULL, 0)) + throw exception(mysql_error(&m_handle)); + char a0 = true; + mysql_options(&m_handle, MYSQL_OPT_RECONNECT, &a0); +} + +Csql_result Cdatabase::query(const std::string& q) +{ + if (!m_query_log.empty()) + { + static std::ofstream f(m_query_log.c_str()); + f << q.substr(0, 239) << std::endl; + } + if (mysql_real_query(&m_handle, q.data(), q.size())) + { + if (m_echo_errors) + { + std::cerr << mysql_error(&m_handle) << std::endl + << q.substr(0, 239) << std::endl; + } +#ifndef WIN32 + syslog(LOG_ERR, "%s", mysql_error(&m_handle)); +#endif + throw exception(mysql_error(&m_handle)); + } + MYSQL_RES* result = mysql_store_result(&m_handle); + if (!result && mysql_errno(&m_handle)) + throw exception(mysql_error(&m_handle)); + return Csql_result(result); +} + +void Cdatabase::close() +{ + mysql_close(&m_handle); +} + +int Cdatabase::insert_id() +{ + return mysql_insert_id(&m_handle); +} + +void Cdatabase::set_query_log(const std::string& v) +{ + m_query_log = v; +} diff --git a/install/xbt/linux/misc/sql/database.h b/install/xbt/linux/misc/sql/database.h new file mode 100644 index 000000000..325908689 --- /dev/null +++ b/install/xbt/linux/misc/sql/database.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "sql_result.h" + +class Cdatabase: boost::noncopyable +{ +public: + class exception: public std::runtime_error + { + public: + exception(const std::string& s): runtime_error(s) + { + } + }; + + void open(const std::string& host, const std::string& user, const std::string& password, const std::string& database, bool echo_errors = false); + Csql_result query(const std::string&); + void set_query_log(const std::string&); + int insert_id(); + void close(); + Cdatabase(); + ~Cdatabase(); + + MYSQL* handle() + { + return &m_handle; + } +private: + bool m_echo_errors; + MYSQL m_handle; + std::string m_query_log; +}; diff --git a/install/xbt/linux/misc/sql/sql_query.cpp b/install/xbt/linux/misc/sql/sql_query.cpp new file mode 100644 index 000000000..ebd8e6aee --- /dev/null +++ b/install/xbt/linux/misc/sql/sql_query.cpp @@ -0,0 +1,77 @@ +#include "stdafx.h" +#include "sql_query.h" + +#include +#include +#include "database.h" + +Csql_query::Csql_query(Cdatabase& database, const std::string& v): + m_database(database) +{ + m_in = v; +} + +Csql_result Csql_query::execute() const +{ + return m_database.query(read()); +} + +std::string Csql_query::read() const +{ + return m_out + m_in; +} + +void Csql_query::operator=(const std::string& v) +{ + m_in = v; + m_out.clear(); +} + +void Csql_query::operator+=(const std::string& v) +{ + m_in += v; +} + +Csql_query& Csql_query::p_name(const std::string& v) +{ + std::vector r(2 * v.size() + 2); + r.resize(mysql_real_escape_string(m_database.handle(), &r.front() + 1, v.data(), v.size()) + 2); + r.front() = '`'; + r.back() = '`'; + p_raw(r); + return *this; +} + +Csql_query& Csql_query::p_raw(const_memory_range v) +{ + size_t i = m_in.find('?'); + m_out.append(m_in.data(), i); + if (i == std::string::npos) + m_in.clear(); + else + m_in.erase(0, i + 1); + m_out.append(v.begin, v.end); + return *this; +} + +Csql_query& Csql_query::p(long long v) +{ + char b[21]; +#ifdef WIN32 + sprintf(b, "%I64d", v); +#else + sprintf(b, "%lld", v); +#endif + p_raw(const_memory_range(b)); + return *this; +} + +Csql_query& Csql_query::p(const_memory_range v) +{ + std::vector r(2 * v.size() + 2); + r.resize(mysql_real_escape_string(m_database.handle(), &r.front() + 1, reinterpret_cast(v.begin), v.size()) + 2); + r.front() = '\''; + r.back() = '\''; + p_raw(r); + return *this; +} diff --git a/install/xbt/linux/misc/sql/sql_query.h b/install/xbt/linux/misc/sql/sql_query.h new file mode 100644 index 000000000..0f691e384 --- /dev/null +++ b/install/xbt/linux/misc/sql/sql_query.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +class Cdatabase; +class Csql_result; + +class Csql_query +{ +public: + Csql_result execute() const; + std::string read() const; + void operator=(const std::string&); + void operator+=(const std::string&); + Csql_query& p_name(const std::string&); + Csql_query& p_raw(const_memory_range); + Csql_query& p(long long); + Csql_query& p(const_memory_range); + Csql_query(Cdatabase&, const std::string& = ""); +private: + std::string m_in; + std::string m_out; + Cdatabase& m_database; +}; diff --git a/install/xbt/linux/misc/sql/sql_result.cpp b/install/xbt/linux/misc/sql/sql_result.cpp new file mode 100644 index 000000000..82a557f83 --- /dev/null +++ b/install/xbt/linux/misc/sql/sql_result.cpp @@ -0,0 +1,15 @@ +#include "stdafx.h" +#include "sql_result.h" + +Csql_row::Csql_row(MYSQL_ROW data, unsigned long* sizes, const boost::shared_ptr& source) +{ + m_data = data; + m_sizes = sizes; + m_source = source; +} + +Csql_row Csql_result::fetch_row() const +{ + MYSQL_ROW data = mysql_fetch_row(h()); + return Csql_row(data, mysql_fetch_lengths(h()), m_source); +} diff --git a/install/xbt/linux/misc/sql/sql_result.h b/install/xbt/linux/misc/sql/sql_result.h new file mode 100644 index 000000000..5ef5ee1ae --- /dev/null +++ b/install/xbt/linux/misc/sql/sql_result.h @@ -0,0 +1,142 @@ +#pragma once + +#include +#include +#include +#include +#ifdef _MSC_VER +#include +#include +#else +#include +#endif + +class Csql_result_source: boost::noncopyable +{ +public: + Csql_result_source(MYSQL_RES* h) + { + m_h = h; + } + + ~Csql_result_source() + { + mysql_free_result(m_h); + } + + MYSQL_RES* h() const + { + return m_h; + } +private: + MYSQL_RES* m_h; +}; + +class Csql_field +{ +public: + Csql_field(const char* begin, int size) + { + m_begin = begin; + m_size = size; + } + + const char* raw() const + { + return m_begin; + } + + int size() const + { + return m_size; + } + + float f(float d = 0) const + { + return raw() ? atof(raw()) : d; + } + + long long i(long long d = 0) const + { +#ifdef WIN32 + return raw() ? _atoi64(raw()) : d; +#else + return raw() ? atoll(raw()) : d; +#endif + } + + const std::string s(const std::string& d = "") const + { + return raw() ? std::string(raw(), size()) : d; + } + + const_memory_range vdata() const + { + return const_memory_range(raw(), size()); + } +private: + const char* m_begin; + int m_size; +}; + +class Csql_row +{ +public: + Csql_row(MYSQL_ROW, unsigned long* sizes, const boost::shared_ptr&); + + Csql_row() + { + } + + operator bool() const + { + return m_data; + } + + Csql_field operator[](size_t i) const + { + return Csql_field(m_data[i], m_sizes[i]); + } +private: + MYSQL_ROW m_data; + unsigned long* m_sizes; + boost::shared_ptr m_source; +}; + +class Csql_result +{ +public: + Csql_row fetch_row() const; + + Csql_result(MYSQL_RES* h) + { + m_source = boost::make_shared(h); + } + + operator bool() const + { + return c_rows(); + } + + int c_fields() const + { + return mysql_num_fields(h()); + } + + int c_rows() const + { + return mysql_num_rows(h()); + } + + void data_seek(int i) + { + mysql_data_seek(h(), i); + } +private: + MYSQL_RES* h() const + { + return m_source->h(); + } + + boost::shared_ptr m_source; +}; diff --git a/install/xbt/linux/misc/stream_int.h b/install/xbt/linux/misc/stream_int.h new file mode 100644 index 000000000..a008182aa --- /dev/null +++ b/install/xbt/linux/misc/stream_int.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +inline float read_float(const void* r) +{ + float v; + memcpy(&v, r, sizeof(float)); + return v; +} + +inline float read_float(const void* r0, const void* s_end) +{ + return read_float(r0); +} + +template +static T write_float(T w0, float v) +{ + unsigned char* w = reinterpret_cast(w0); + memcpy(w, &v, sizeof(float)); + return w + sizeof(float); +} + +inline long long read_int(int cb, const void* r0) +{ + const unsigned char* r = reinterpret_cast(r0); + long long v = 0; + while (cb--) + v = v << 8 | *r++; + return v; +} + +inline long long read_int(int cb, const_memory_range s) +{ + return s.size() < cb ? 0 : read_int(cb, s.begin); +} + +inline long long read_int(int cb, const void* r, const void* s_end) +{ + return read_int(cb, const_memory_range(r, s_end)); +} + +template +T write_int(int cb, T w0, long long v) +{ + unsigned char* w = reinterpret_cast(w0); + w += cb; + for (int i = 0; i < cb; i++) + { + *--w = v & 0xff; + v >>= 8; + } + return reinterpret_cast(w + cb); +} + +inline long long read_int_le(int cb, const void* r0) +{ + const unsigned char* r = reinterpret_cast(r0); + r += cb; + long long v = 0; + while (cb--) + v = v << 8 | *--r; + return v; +} + +inline long long read_int_le(int cb, const void* r, const void* s_end) +{ + return read_int_le(cb, r); +} + +template +T write_int_le(int cb, T w0, long long v) +{ + unsigned char* w = reinterpret_cast(w0); + for (int i = 0; i < cb; i++) + { + *w++ = v & 0xff; + v >>= 8; + } + return reinterpret_cast(w); +} diff --git a/install/xbt/linux/misc/stream_reader.cpp b/install/xbt/linux/misc/stream_reader.cpp new file mode 100644 index 000000000..f57d5ba6a --- /dev/null +++ b/install/xbt/linux/misc/stream_reader.cpp @@ -0,0 +1,3 @@ +#include "stdafx.h" +#include "stream_reader.h" + diff --git a/install/xbt/linux/misc/stream_reader.h b/install/xbt/linux/misc/stream_reader.h new file mode 100644 index 000000000..15e78fbe1 --- /dev/null +++ b/install/xbt/linux/misc/stream_reader.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +class Cstream_reader +{ +public: + const unsigned char* d() const + { + return m_d; + } + + const unsigned char* d_end() const + { + return m_d.end(); + } + + const unsigned char* r() const + { + return m_r; + } + + const unsigned char* read(int size) + { + m_r += size; + return m_r - size; + } + + long long read_int(int cb) + { + m_r += cb; + return ::read_int(cb, m_r - cb); + } + + Cvirtual_binary read_data() + { + int l = read_int(4); + return Cvirtual_binary(const_memory_range(read(l), l)); + } + + std::string read_string() + { + int l = read_int(4); + return std::string(reinterpret_cast(read(l)), l); + } + + Cstream_reader() + { + } + + Cstream_reader(const Cvirtual_binary& d) + { + m_r = m_d = d; + } +private: + Cvirtual_binary m_d; + const unsigned char* m_r; +}; diff --git a/install/xbt/linux/misc/stream_writer.cpp b/install/xbt/linux/misc/stream_writer.cpp new file mode 100644 index 000000000..88041c56b --- /dev/null +++ b/install/xbt/linux/misc/stream_writer.cpp @@ -0,0 +1,2 @@ +#include "stdafx.h" +#include "stream_writer.h" diff --git a/install/xbt/linux/misc/stream_writer.h b/install/xbt/linux/misc/stream_writer.h new file mode 100644 index 000000000..108f4c483 --- /dev/null +++ b/install/xbt/linux/misc/stream_writer.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +class Cstream_writer +{ +public: + unsigned char* w() const + { + return m_w; + } + + unsigned char* write(int size) + { + m_w += size; + return m_w - size; + } + + void write_int(int cb, long long v) + { + m_w = ::write_int(cb, m_w, v); + } + + void write_data(const_memory_range v) + { + write_int(4, v.size()); + memcpy(write(v.size()), v, v.size()); + } + + Cstream_writer() + { + } + + Cstream_writer(unsigned char* w) + { + m_w = w; + } +private: + unsigned char* m_w; +}; diff --git a/install/xbt/linux/misc/tf_misc.cpp b/install/xbt/linux/misc/tf_misc.cpp new file mode 100644 index 000000000..5a3927f78 --- /dev/null +++ b/install/xbt/linux/misc/tf_misc.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "tf_misc.h" + +#include +#include + +static std::string web_encode(const std::string& v) +{ + std::string d; + d.reserve(v.size() << 1); + for (int a = 0; a < v.size();) + { + int b = v.find_first_of("\"<&", a); + if (b == std::string::npos) + { + d += v.substr(a); + return d; + } + d += v.substr(a, b - a); + switch (v[b]) + { + case '"': + d += """; + break; + case '<': + d += "<"; + break; + case '&': + d += "&"; + break; + } + a = b + 1; + } + return d; +} + +static std::string web_link(const std::string& link_title, const std::string& link, bool encode) +{ + return encode + ? web_link(web_encode(link_title), web_encode(link), false) + : (boost::format("%s") % link % (link_title.empty() ? link : link_title)).str(); +} + +static std::string encode_local_url(const std::string& url, const std::string& local_domain_url) +{ + if (!local_domain_url.empty() && boost::istarts_with(url, local_domain_url)) + return url.substr(local_domain_url.length()); + return url; +} + +std::string encode_field(const std::string& v, const std::string& local_domain_url) +{ + std::string r; + r.reserve(v.length() << 1); + for (size_t i = 0; i < v.length(); ) + { + if (boost::istarts_with(v.c_str() + i, "ftp.") + || boost::istarts_with(v.c_str() + i, "ftp://") + || boost::istarts_with(v.c_str() + i, "http://") + || boost::istarts_with(v.c_str() + i, "https://") + || boost::istarts_with(v.c_str() + i, "mailto:") + || boost::istarts_with(v.c_str() + i, "www.")) + { + size_t p = i; + while (p < v.length() + && !isspace(v[p] & 0xff) + && v[p] != '\"' + && v[p] != '<' + && v[p] != '>') + { + p++; + } + if (v[p - 1] == '!' || v[p - 1] == ',' || v[p - 1] == '.' || v[p - 1] == '?') + p--; + if (v[p - 1] == ')') + p--; + std::string url = web_encode(v.substr(i, p - i)); + if (boost::istarts_with(v.c_str() + i, "ftp.")) + r += web_link(url, "ftp://" + url, false); + else if (boost::istarts_with(v.c_str() + i, "www.")) + r += web_link(url, "http://" + url, false); + else + r += web_link(boost::istarts_with(v.c_str() + i, "mailto:") ? url.substr(7) : encode_local_url(url, local_domain_url), url, false); + i = p; + } + else + { + char c = v[i++]; + switch (c) + { + case '<': + r += "<"; + break; + case '&': + r += "&"; + break; + default: + r += c; + } + } + } + return r; +} + +std::string encode_text(const std::string& v, const std::string& local_domain_url, bool add_span) +{ + std::string r; + r.reserve(v.length() << 1); + for (size_t i = 0; i < v.length(); ) + { + size_t p = v.find('\n', i); + if (p == std::string::npos) + p = v.length(); + std::string line = v.substr(i, p - i); + line = encode_field(line, local_domain_url); + r += add_span && boost::istarts_with(line, "> ") ? "" + line + "" : line; + r += "
"; + i = p + 1; + } + return r; +} + +std::string trim_field(const std::string& v) +{ + std::string r; + bool copy_white = false; + for (size_t i = 0; i < v.length(); i++) + { + if (isspace(v[i] & 0xff)) + copy_white = true; + else + { + if (copy_white) + { + if (!r.empty()) + r += ' '; + copy_white = false; + } + r += v[i]; + } + } + return r; +} + +std::string trim_text(const std::string& v) +{ + std::string r; + bool copy_white = false; + for (size_t i = 0; i < v.length(); ) + { + size_t p = v.find('\n', i); + if (p == std::string::npos) + p = v.length(); + std::string line = trim_field(v.substr(i, p - i)); + if (line.empty()) + copy_white = true; + else + { + if (copy_white) + { + if (!r.empty()) + r += '\n'; + copy_white = false; + } + r += line + '\n'; + } + i = p + 1; + } + return r; +} diff --git a/install/xbt/linux/misc/tf_misc.h b/install/xbt/linux/misc/tf_misc.h new file mode 100644 index 000000000..e9d8d0017 --- /dev/null +++ b/install/xbt/linux/misc/tf_misc.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +std::string encode_field(const std::string&, const std::string& local_domain_url); +std::string encode_text(const std::string&, const std::string& local_domain_url, bool add_span); +std::string trim_field(const std::string&); +std::string trim_text(const std::string&); diff --git a/install/xbt/linux/misc/virtual_binary.cpp b/install/xbt/linux/misc/virtual_binary.cpp new file mode 100644 index 000000000..caaa208fd --- /dev/null +++ b/install/xbt/linux/misc/virtual_binary.cpp @@ -0,0 +1,75 @@ +#include "stdafx.h" +#include "xbt/virtual_binary.h" + +#include +#include +#include + +Cvirtual_binary_source::Cvirtual_binary_source(const_memory_range d) +{ + m_range.begin = new unsigned char[d.size()]; + m_range.end = m_range.begin + d.size(); + if (d) + memcpy(m_range, d, d.size()); +} + +Cvirtual_binary::Cvirtual_binary(size_t v) +{ + m_source = boost::make_shared(const_memory_range(NULL, v)); +} + +Cvirtual_binary::Cvirtual_binary(const_memory_range d) +{ + m_source = boost::make_shared(d); +} + +int Cvirtual_binary::save(const std::string& fname) const +{ + FILE* f = fopen(fname.c_str(), "wb"); + if (!f) + return 1; + int error = fwrite(data(), 1, size(), f) != size(); + fclose(f); + return error; +} + +int Cvirtual_binary::load(const std::string& fname) +{ + FILE* f = fopen(fname.c_str(), "rb"); + if (!f) + return 1; + struct stat b; + int error = fstat(fileno(f), &b) ? 1 : fread(write_start(b.st_size), 1, b.st_size, f) != b.st_size; + fclose(f); + return error; +} + +Cvirtual_binary& Cvirtual_binary::load1(const std::string& fname) +{ + load(fname); + return *this; +} + +void Cvirtual_binary::clear() +{ + m_source.reset(); +} + +size_t Cvirtual_binary::read(void* d) const +{ + memcpy(d, data(), size()); + return size(); +} + +unsigned char* Cvirtual_binary::write_start(size_t cb_d) +{ + if (data() && size() == cb_d) + return data_edit(); + m_source = boost::make_shared(const_memory_range(NULL, cb_d)); + return data_edit(); +} + +void Cvirtual_binary::write(const_memory_range d) +{ + memcpy(write_start(d.size()), d, d.size()); +} diff --git a/install/xbt/linux/misc/windows/ETSLayout.cpp b/install/xbt/linux/misc/windows/ETSLayout.cpp new file mode 100644 index 000000000..222ba77bf --- /dev/null +++ b/install/xbt/linux/misc/windows/ETSLayout.cpp @@ -0,0 +1,3058 @@ +//////////////////////////////////////////// +// ___ ____ _________________ // +// / _/_ _// _______________/ // +// / _/ / / / / ___ ___ ____ // +// /__/ /_/ / / / // _/_ _/ // +// _________/ / / / // _/ / / // +// (c) 1998-2000_/ /___//_/ /_/ // +// // +//////////////////////////////////////////// +// all rights reserved // +//////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutDialog +// +// A class for smart layouting of Dialogs and such +// +// USAGE: See LayoutMgr.html +// +// AUTHOR: Erwin Tratar +// +// DISCLAIMER: +// +// This Sourcecode and all accompaning material is 1998-1999 Erwin Tratar. +// All rights reserved. +// +// The source code may be used in compiled form in any way you desire +// (including usage in commercial applications), providing that your +// application adds essential code (i.e. it is not only a wrapper) to the +// functionality found here +// +// Redistribution of the sourcecode itself, publication in any media or +// inclusion in a library requires the authors expressed written consent. +// You may not sale this code for profit. +// +// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. USE IT +// AT YOUR OWN RISK! THE AUTHOR ACCEPTS NO LIABILITY FOR ANY DAMAGE/LOSS OF +// BUSINESS THAT THIS PRODUCT MAY CAUSE. +// +// +// HISTORY: +// 1998/05/1 Initial Release +// 1998/05/13 Added ability to have a Pane with a control +// 1998/05/13 Added better support for TabControls +// 1998/05/14 automatically set Icon to IDR_MAINFRAME +// 1998/05/19 no flicker on restoring position in OnInitialUpdate +// Changed procedure for load/save, see constructor +// 1998/10/02 Added support for Maximum (tracking) size +// 1998/10/02 Much improved handling regarding RELATIVE/GREEDY +// /w critical minimum size +// 1998/10/02 turn on/off gripper at lower right corner +// 1998/10/05 Support for user defined minimum size for items +// (was hardcoded 5 before) +// 1998/10/07 Fix for FormViews +// 1998/10/31 Support for SECDialogBar/CDialogBar +// 1998/10/31 simplified interface +// 1998/10/31 Advanced positioning options +// 1998/10/31 Added paneNull for empty Pane (former: NULL) +// 1998/11/20 Swapped ETSLayoutDialog constructor parameters +// 1998/11/20 Added Pane::addItemSpaceBetween +// [Leo Zelevinsky] +// 1998/11/24 Added fixup for greedy panes +// 1998/11/24 addItemSpaceBetween now subtracts 2*nDefaultBorder +// 1998/11/24 addGrowing() added as a shortcut for a paneNull +// 1998/11/24 simplified interface: no more PaneBase:: / Pane:: +// needed +// 1998/11/24 added FILL_* Modes +// 1998/11/24 improved maximum size handling for greedy panes +// 1998/11/25 Fixup of greedy panes caused infinite loop in some +// cases +// 1999/01/07 addItemSpaceLike() added +// 1999/04/03 Fixed ETSLayoutFormView memory leak +// 1999/04/07 Fixed ALIGN_xCENTER +// 1999/04/08 New simple stream-interface added +// 1999/04/09 Added support for an empty Status-Bar for resizing +// instead of a gripper in the lower right corner +// [Andreas Kapust] +// 1999/04/11 New code for much less flickering, OnEraseBkgnd() +// overidden for this task +// 1999/05/12 Split Layout code into understandable pieces and adding +// a lot of comments +// 1999/06/20 ABSOLUTE_X + ALIGN_FILL_X expands item if there is any +// left space (after all Abs/Rel/Greedy processing is done) +// 1999/10/06 Changed Load() and Save() to use WINDOWPLACEMENT +// [Keith Bussell] +// 1999/11/18 Added possibility to add panes of the same orientation +// to another pane. This merges both panes in one big +// pane with the same orientation +// 1999/11/18 Added support for BCGDialogBar (only with BCG > 4.52!) +// 1999/11/25 Addes support for PropertyPages/Sheets. Uses some code +// of a code submission from Anreas Kapust +// 1999/11/25 Renamed classes to ETSLayoutXXX +// 1999/11/25 Use CreateRoot() and Root() instead of m_pRootPane in +// derived class. +// 1999/11/26 Added autopointer support. No need to use normal pointers +// when defining layout anymore. Changed m_pRootPane to +// m_RootPane +// 1999/11/26 Bug in Fixup Greedy II with multiple GREEDY panes and one +// of them min/max limited +// 1999/11/28 Fixed PaneTab::getConstrainVert() for ABSOLUTE_VERT +// 1999/11/28 Fixed itemFixed() +// 1999/11/28 Changed DWORD modeResize Arguments to layModeResize for +// better type safety. Added typesafe operator| +// 1999/12/04 Don't reposition window in UpdateLayout if it's a child +// (as a child Dialog or PropertyPage) +// 1999/12/04 Erase Backgroung with GCL_HBRBACKGROUND (if available) +// 1999/12/04 itemSpaceXXX() adds a NORESIZE item instead of ABSOLUTE_XXX +// this will fix unwanted growing in secondary direction +// +// Version: 1.0 [1999/12/04] Initial Article on CodeProject +// +// 1999/12/10 Erase Backgroung within TabCtrl was 'fixed' badly. Reverted to +// old working code +// 2000/02/02 When the Dialog is child of a View the class works correctly +// now [Didier BULTIAUW] +// 2000/02/15 Combo-Boxes were not working correctly (in all modes!) +// 2000/02/17 aligned SpinButton Controls (with buddy) now handled +// automatically +// !! do not add such a control to the layout !! it is always +// reattached to its buddy. +// 2000/02/17 changed some cotrol class names to the defined constants +// +// Version: 1.1 [2000/02/17] +// +// 2000/02/25 Fixed auto alignment of SpinButton Controls to only affect +// visible ones +// 2000/02/27 Put all the classes into the namespace 'ETSLayout' +// 2000/03/07 Fixed growing Dialog after minimizing and restoring +// 2000/05/22 Whole Statusbar (Gripper) is not excluded anymore in EraseBkgnd() +// instead only the triangular Gripper is excluded +// 2000/05/31 Fix for PropertySheets with PSH_WIZARDHASFINISH [Thmmi] +// 2000/05/31 Fix for UpDown-Controls with EditCtrl Buddy in PropertyPages. +// These were not repositioned every time the page is being show +// until the first resize +// 2000/07/28 Problems with resizing ActiveX Controls fixed [Micheal Chapman] +// 2000/07/28 Some strings were not properly wrapped with _T() +// 2000/08/03 Check for BS_GROUPBOX was not correct as BS_GROUPBOX is more than one Bit +// 2000/08/03 New override AddMainArea added to ETSLayoutPropertySheet in order to +// have a hook for additional controls in a PropertySheet (besides the Tab) +// 2000/08/03 New override AddButtons added to ETSLayoutPropertySheet in order to +// have a hook for additional controls in the bottem pane of a PropertySheet +// 2000/08/03 Removed the need for DECLARE_LAYOUT +// +// Version: 1.2 [2000/08/05] + +#define OEMRESOURCE +#include + +#include "stdafx.h" +#include "ETSLayout.h" + +using namespace ETSLayout; +#pragma warning(disable: 4097 4610 4510 4100) + + +#ifndef OBM_SIZE +#define OBM_SIZE 32766 +// taken from WinresRc.h +// if not used for any reason +#endif + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +static UINT auIDStatusBar[] = +{ + ID_SEPARATOR +}; + +const int ERASE_GROUP_BORDER = 10; +const int FIXUP_CUTOFF = 5; +const int TAB_SPACE = 5; + +// the _NULL-Pane +CWnd* ETSLayoutMgr::paneNull = 0; + +void ETSLayoutMgr::Layout(CRect& rcClient) +{ + if(rcClient.Height() && rcClient.Width() && m_RootPane.IsValid()) \ + m_RootPane->resizeTo(rcClient); \ +} + + +ETSLayoutMgr::CPane ETSLayoutMgr::pane( layOrientation orientation, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, + int sizeBorder /*=nDefaultBorder*/, int sizeExtraBorder /*=0*/, + int sizeSecondary /*=0*/) +{ + Pane* pPane = new Pane ( this, orientation, sizeBorder, sizeExtraBorder ); + pPane->m_sizeSecondary = sizeSecondary; + pPane->m_modeResize = modeResize; + + return CPane(pPane); +} + +ETSLayoutMgr::CPane ETSLayoutMgr::paneTab( CTabCtrl* pTab, layOrientation orientation, + ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeBorder /*=nDefaultBorder*/, + int sizeExtraBorder /*=0*/, int sizeSecondary /*=0*/) +{ + Pane* pPane = new PaneTab ( pTab, this, orientation, sizeBorder, sizeExtraBorder ); + pPane->m_sizeSecondary = sizeSecondary; + pPane->m_modeResize = modeResize; + + return CPane(pPane); +} + + +ETSLayoutMgr::CPane ETSLayoutMgr::paneCtrl( CWnd* pCtrl, layOrientation orientation, + ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeBorder /*=nDefaultBorder*/, + int sizeExtraBorder /*=0*/, int sizeTopExtra /*=0*/, + int sizeSecondary /*=0*/) +{ + Pane* pPane = new PaneCtrl ( pCtrl, this, orientation, sizeBorder, sizeExtraBorder, sizeTopExtra ); + pPane->m_sizeSecondary = sizeSecondary; + pPane->m_modeResize = modeResize; + + return CPane(pPane); +} + +ETSLayoutMgr::CPane ETSLayoutMgr::paneCtrl( UINT nID, layOrientation orientation, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, + int sizeBorder /*=nDefaultBorder*/, int sizeExtraBorder /*=0*/, + int sizeTopExtra /*=0*/, int sizeSecondary /*=0*/) +{ + Pane* pPane = new PaneCtrl ( nID, this, orientation, sizeBorder, sizeExtraBorder, sizeTopExtra ); + pPane->m_sizeSecondary = sizeSecondary; + pPane->m_modeResize = modeResize; + + return CPane(pPane); +} + + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::item(UINT nID, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeX /*=0*/, int sizeY /*=0*/, + int sizeXMin /*=-1*/, int sizeYMin /*=-1*/) +{ + return new PaneItem( nID, this, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); +} + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::item(CWnd* pWnd, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, + int sizeX /*=0*/, int sizeY /*=0*/, int sizeXMin /*=-1*/, + int sizeYMin /*=-1*/) +{ + return new PaneItem( pWnd, this, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); +} + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemFixed(layOrientation orientation, int sizePrimary) +{ + CPaneBase p = new PaneItem(paneNull, this, NORESIZE, (orientation==HORIZONTAL)?sizePrimary:0, (orientation==VERTICAL)?sizePrimary:0); + return p; +} + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemGrowing(layOrientation orientation) +{ + return new PaneItem(paneNull, this, (orientation==HORIZONTAL)?ABSOLUTE_VERT:ABSOLUTE_HORZ, 0, 0, -nDefaultBorder, -nDefaultBorder); +} + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceBetween( layOrientation orientation, CWnd* pWndFirst, CWnd* pWndSecond ) +{ + if( orientation == HORIZONTAL ) { + // I'm interested in horizontal spacing + + CRect rLeft, rRight; + pWndFirst->GetWindowRect(&rLeft); + pWndSecond->GetWindowRect(&rRight); + + int sizeX = rRight.left - rLeft.right; + + if( sizeX < 0 ) { + // compare top to top + sizeX = rRight.left - rLeft.left; + } + else { + sizeX -= 2*nDefaultBorder; + } + + return new PaneItem(paneNull, this, NORESIZE, sizeX, 0); + } + else { + // I'm interested in vertical spacing + CRect rTop, rBot; + pWndFirst->GetWindowRect(&rTop); + pWndSecond->GetWindowRect(&rBot); + + int sizeY = rBot.top - rTop.bottom; + + if( sizeY < 0 ) { + // compare top to top + sizeY = sizeY = rBot.top - rTop.top; + } + else { + sizeY -= 2*nDefaultBorder; + } + + return new PaneItem(paneNull, this, NORESIZE, 0, sizeY); + } +} + + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceBetween( layOrientation orientation, UINT nIDFirst, UINT nIDSecond ) +{ + CWnd *pFirst = GetWnd()->GetDlgItem(nIDFirst); + CWnd *pSecond = GetWnd()->GetDlgItem(nIDSecond); + + ASSERT( pFirst && pSecond ); + + return itemSpaceBetween( orientation, pFirst, pSecond ); +} + + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceLike( layOrientation orientation, CWnd* pWnd ) +{ + CRect rRect; + pWnd->GetWindowRect(&rRect); + + if( orientation == HORIZONTAL ) { + // I'm interested in horizontal spacing + return new PaneItem(paneNull, this, NORESIZE, rRect.Width(), 0); + } + else { + // I'm interested in vertical spacing + return new PaneItem(paneNull, this, NORESIZE, 0, rRect.Height() ); + } + +} + + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceLike( layOrientation orientation, UINT nID ) +{ + CWnd *pWnd = GetWnd()->GetDlgItem(nID); + ASSERT( pWnd ); + + return itemSpaceLike( orientation, pWnd ); +} + + + +ETSLayoutMgr::~ETSLayoutMgr() +{ +} + +void ETSLayoutMgr::UpdateLayout() +{ + if(!m_RootPane) + return; + + // Check constraints + CRect rcClient = GetRect(); + + if( m_pWnd->IsKindOf( RUNTIME_CLASS( CDialog ) ) && !(m_pWnd->GetStyle()&WS_CHILD) ) { + CRect rcWindow; + m_pWnd->GetWindowRect(rcWindow); + + // Added by Didier BULTIAUW + CWnd* parentWnd = m_pWnd->GetParent(); + if( (parentWnd != 0) && parentWnd->IsKindOf(RUNTIME_CLASS(CView)) ) + { + CRect rcParent; + parentWnd->GetWindowRect(rcParent); + rcWindow.OffsetRect(-rcParent.left,-rcParent.top); + } + // end add + + CRect rcBorder = rcWindow; + rcBorder -= rcClient; + + // Min and Max info + int minWidth = m_RootPane->getMinConstrainHorz() + rcBorder.Width() + 2*m_sizeRootBorders.cx; + int minHeight = m_RootPane->getMinConstrainVert() + rcBorder.Height() + 2*m_sizeRootBorders.cy; + int maxWidth = m_RootPane->getMaxConstrainHorz(); + if(maxWidth != -1) { + maxWidth += rcBorder.Width() + 2*m_sizeRootBorders.cx; + maxWidth = max(maxWidth, minWidth); + } + int maxHeight = m_RootPane->getMaxConstrainVert(); + if(maxHeight != -1) { + maxHeight += rcBorder.Height() + 2*m_sizeRootBorders.cy; + maxHeight = max(maxHeight, minHeight); + } + + if(rcWindow.Width() < minWidth) + rcWindow.right = rcWindow.left + minWidth; + if(rcWindow.Height() < minHeight) + rcWindow.bottom = rcWindow.top + minHeight; + + if(maxWidth != -1 && rcWindow.Width() > maxWidth) + rcWindow.right = rcWindow.left + maxWidth; + if(maxHeight != -1 && rcWindow.Height() > maxHeight) + rcWindow.bottom = rcWindow.top + maxHeight; + + m_pWnd->MoveWindow(rcWindow); + } + // Do the Layout + rcClient = GetRect(); + + // Add a Border around the rootPane + rcClient.top += m_sizeRootBorders.cy; + rcClient.bottom -= m_sizeRootBorders.cy; + rcClient.left += m_sizeRootBorders.cx; + rcClient.right -= m_sizeRootBorders.cx; + + if(GetWnd()->IsWindowVisible()) { + // Avoid ugly artifacts + //GetWnd()->SetRedraw(FALSE); + Layout(rcClient); + //GetWnd()->SetRedraw(TRUE); + } + else + Layout(rcClient); + + // Take special care of SpinButtons (Up-Down Controls) with Buddy set, enumerate + // all childs: + CWnd* pWndChild = GetWnd()->GetWindow(GW_CHILD); + TCHAR szClassName[ MAX_PATH ]; + while(pWndChild) + { + ::GetClassName( pWndChild->GetSafeHwnd(), szClassName, MAX_PATH ); + DWORD dwStyle = pWndChild->GetStyle(); + + // is it a SpinButton? + if( _tcscmp(szClassName, UPDOWN_CLASS)==0 && ::IsWindowVisible(pWndChild->GetSafeHwnd()) ) { + HWND hwndBuddy = (HWND)::SendMessage( pWndChild->GetSafeHwnd(), UDM_GETBUDDY, 0, 0); + if( hwndBuddy != 0 && (dwStyle&(UDS_ALIGNRIGHT|UDS_ALIGNLEFT)) != 0 ) + { + // reset Buddy + ::SendMessage( pWndChild->GetSafeHwnd(), UDM_SETBUDDY, (WPARAM)hwndBuddy, 0); + } + } + + + pWndChild = pWndChild->GetWindow(GW_HWNDNEXT); + } + + + GetWnd()->Invalidate(); +} + + +bool ETSLayoutMgr::Save(LPCTSTR lpstrRegKey) +{ + CRect rcWnd; + + if(IsWindow(GetWnd()->m_hWnd)) + { + WINDOWPLACEMENT wp; + if(GetWnd()->GetWindowPlacement(&wp)) + { + // Make sure we don't pop up + // minimized the next time + if(wp.showCmd != SW_SHOWMAXIMIZED) + wp.showCmd = SW_SHOWNORMAL; + + AfxGetApp()->WriteProfileBinary(lpstrRegKey, + _T("WindowPlacement"), + reinterpret_cast(&wp), sizeof(wp)); + } + } + return true; +} + +bool ETSLayoutMgr::Load(LPCTSTR lpstrRegKey) +{ + LPBYTE pbtData = 0; + UINT nSize = 0; + if(AfxGetApp()->GetProfileBinary(lpstrRegKey, + _T("WindowPlacement"), &pbtData, &nSize)) + { + WINDOWPLACEMENT* pwp = + reinterpret_cast(pbtData); + + ASSERT(nSize == sizeof(WINDOWPLACEMENT)); + if(nSize == sizeof(WINDOWPLACEMENT)) + GetWnd()->SetWindowPlacement(reinterpret_cast(pbtData)); + + delete [] pbtData; + } + return true; +} + + +void ETSLayoutMgr::EraseBkgnd(CDC* pDC) +{ + CRect rcClient; + GetWnd()->GetClientRect( rcClient ); + + CRgn rgn; + rgn.CreateRectRgnIndirect(rcClient); + TRACE("CreateRgn (%d,%d,%d,%d)\n", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom ); + + CRgn rgnRect; + rgnRect.CreateRectRgn(0,0,0,0); + + CRect rcChild; + CWnd* pWndChild = GetWnd()->GetWindow( GW_CHILD ); + + TCHAR szClassName[ MAX_PATH ]; + + pDC->SelectClipRgn(NULL); + + while( pWndChild ) { + + pWndChild->GetWindowRect(rcChild); + GetWnd()->ScreenToClient( rcChild ); + + rgnRect.SetRectRgn( rcChild ); + + ::GetClassName( pWndChild->GetSafeHwnd(), szClassName, MAX_PATH ); + DWORD dwStyle = pWndChild->GetStyle(); + + // doesn't make sense for hidden children + if( dwStyle & WS_VISIBLE ) { + + // Fix: BS_GROUPBOX is more than one Bit, extend check to (dwStyle & BS_GROUPBOX)==BS_GROUPBOX [ET] + if( _tcscmp(szClassName,_T("Button"))==0 && (dwStyle & BS_GROUPBOX)==BS_GROUPBOX ) { + // it is a group-box, ignore completely + } + else if( _tcscmp(szClassName,WC_TABCONTROL )==0 ) { + // ignore Tab-Control's inside rect + static_cast(pWndChild)->AdjustRect(FALSE,rcChild); + + CRgn rgnContent; + rgnContent.CreateRectRgnIndirect(rcChild); + + rgnRect.CombineRgn( &rgnRect, &rgnContent, RGN_DIFF ); + rgn.CombineRgn( &rgn, &rgnRect, RGN_DIFF ); + } + else if( _tcscmp(szClassName,STATUSCLASSNAME)==0 ) { + + CPoint ptTriangleGrip[3]; + ptTriangleGrip[0] = CPoint(rcChild.right,rcChild.top); + ptTriangleGrip[1] = CPoint(rcChild.right,rcChild.bottom); + ptTriangleGrip[2] = CPoint(rcChild.right-rcChild.Height(),rcChild.bottom); + + CRgn rgnGripper; + rgnGripper.CreatePolygonRgn(ptTriangleGrip,3, WINDING); + + rgn.CombineRgn( &rgn, &rgnGripper, RGN_DIFF ); + + } + else { + rgn.CombineRgn( &rgn, &rgnRect, RGN_DIFF ); + } + } + + pWndChild = pWndChild->GetNextWindow(); + } + + + HBRUSH hBrBack = (HBRUSH) ::GetClassLong(GetWnd()->GetSafeHwnd(), GCL_HBRBACKGROUND) ; + if( hBrBack == 0 ) + hBrBack = ::GetSysColorBrush(COLOR_BTNFACE); + + pDC->FillRgn( &rgn, + CBrush::FromHandle( hBrBack ) + ); + +} + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutMgr::PaneItem implementation + + +ETSLayoutMgr::PaneItem::PaneItem(CWnd* pWnd, ETSLayoutMgr* pMgr, ETSLayoutMgr::layResizeMode modeResize/*=GREEDY*/ + , int sizeX/*=0*/, int sizeY/*=0*/ + , int sizeXMin/*=-1*/, int sizeYMin/*=-1*/ ) : PaneBase( pMgr ) +{ + m_modeResize = modeResize; + m_hwndCtrl = pWnd->GetSafeHwnd(); + + m_sizeX = 0; + m_sizeY = 0; + + m_bComboSpecial = false; + + m_sizeXMin = sizeXMin; + m_sizeYMin = sizeYMin; + + if(!m_hwndCtrl) { // only Dummy! + m_sizeX = sizeX; + m_sizeY = sizeY; + } + else { + CRect rcControl; + ::GetWindowRect(m_hwndCtrl, &rcControl); + + if(sizeX == 0) { + m_sizeX = rcControl.Width(); + } + else { + m_sizeX = sizeX; + } + if( m_sizeXMin == -1 ) { + // do not make smaller than current size + m_sizeXMin = rcControl.Width(); + } + + if(sizeY == 0) { + m_sizeY = rcControl.Height(); + } + else { + m_sizeY = sizeY; + } + if( m_sizeYMin == -1 ) { + // do not make smaller than current size + m_sizeYMin = rcControl.Height(); + } + + TCHAR szClassName[ MAX_PATH ]; + ::GetClassName( m_hwndCtrl, szClassName, MAX_PATH ); + + // special treatment for combo-boxes + if( _tcscmp(szClassName,_T("ComboBox"))==0 || _tcscmp(szClassName,WC_COMBOBOXEX)==0) { + m_bComboSpecial = true; + } + } +} + +ETSLayoutMgr::PaneItem::PaneItem( UINT nID, ETSLayoutMgr* pMgr, ETSLayoutMgr::layResizeMode modeResize/*=GREEDY*/ + , int sizeX/*=0*/, int sizeY/*=0*/ + , int sizeXMin/*=-1*/, int sizeYMin/*=-1*/ ) : PaneBase( pMgr ) +{ + CWnd* pWnd = pMgr->GetWnd()->GetDlgItem(nID); + m_hwndCtrl = pWnd->GetSafeHwnd(); + + m_sizeX = 0; + m_sizeY = 0; + + m_bComboSpecial = false; + + m_modeResize = modeResize; + + m_sizeXMin = sizeXMin; + m_sizeYMin = sizeYMin; + + if(!m_hwndCtrl) { // only Dummy! + m_sizeX = sizeX; + m_sizeY = sizeY; + } + else { + CRect rcControl; + ::GetWindowRect(m_hwndCtrl, &rcControl); + + if(sizeX == 0) { + m_sizeX = rcControl.Width(); + } + else { + m_sizeX = sizeX; + } + if( m_sizeXMin == -1 ) { + // do not make smaller than current size + m_sizeXMin = rcControl.Width(); + } + + if(sizeY == 0) { + m_sizeY = rcControl.Height(); + } + else { + m_sizeY = sizeY; + } + if( m_sizeYMin == -1 ) { + // do not make smaller than current size + m_sizeYMin = rcControl.Height(); + } + + TCHAR szClassName[ MAX_PATH ]; + ::GetClassName( m_hwndCtrl, szClassName, MAX_PATH ); + + // special treatment for combo-boxes + if( _tcscmp(szClassName,_T("ComboBox"))==0 || _tcscmp(szClassName,WC_COMBOBOXEX)==0) { + m_bComboSpecial = true; + } + } +} + +int ETSLayoutMgr::PaneItem::getConstrainHorz(int sizeParent) +{ + if( m_modeResize & ABSOLUTE_HORZ) { + return m_sizeX; + } + if(m_modeResize & RELATIVE_HORZ) { + return (sizeParent * m_sizeX) / 100; + } + return -1; +} + +int ETSLayoutMgr::PaneItem::getConstrainVert(int sizeParent) +{ + if(m_modeResize & ABSOLUTE_VERT) { + return m_sizeY; + } + if(m_modeResize & RELATIVE_VERT) { + return (sizeParent * m_sizeY) / 100; + } + return -1; +} + +int ETSLayoutMgr::PaneItem::getMinConstrainHorz() +{ + if(m_modeResize & ABSOLUTE_HORZ) { + return m_sizeX; + } + return max(nMinConstrain,m_sizeXMin); +} + +int ETSLayoutMgr::PaneItem::getMinConstrainVert() +{ + if(m_modeResize & ABSOLUTE_VERT) { + return m_sizeY; + } + return max(nMinConstrain,m_sizeYMin); +} + +int ETSLayoutMgr::PaneItem::getMaxConstrainHorz() +{ + if(m_modeResize & ABSOLUTE_HORZ) { + return m_sizeX; + } + return -1; +} + +int ETSLayoutMgr::PaneItem::getMaxConstrainVert() +{ + if(m_modeResize & ABSOLUTE_VERT) { + return m_sizeY; + } + return -1; +} + +bool ETSLayoutMgr::PaneItem::resizeTo(CRect& rcNewArea) +{ + if(m_hwndCtrl) { + + CRect rcWnd; + ::GetWindowRect( m_hwndCtrl, rcWnd ); + + if( !(m_modeResize & ALIGN_FILL_HORZ) && m_modeResize & ABSOLUTE_HORZ ) { + + + if( (m_modeResize & ALIGN_HCENTER) == ALIGN_HCENTER ) { + rcNewArea.OffsetRect( (rcNewArea.Width() - rcWnd.Width())/2, 0 ); + } + else if( m_modeResize & ALIGN_RIGHT ) { + rcNewArea.OffsetRect( rcNewArea.Width() - rcWnd.Width(), 0 ); + } + + rcNewArea.right = rcNewArea.left + rcWnd.Width(); + } + if( !(m_modeResize & ALIGN_FILL_VERT) && m_modeResize & ABSOLUTE_VERT ) { + + + if( (m_modeResize & ALIGN_VCENTER) == ALIGN_VCENTER ) { + rcNewArea.OffsetRect( 0, (rcNewArea.Height()-rcWnd.Height())/2 ); + } + else if( m_modeResize & ALIGN_BOTTOM ) { + rcNewArea.OffsetRect( 0, rcNewArea.Height() - rcWnd.Height()); + } + + rcNewArea.bottom = rcNewArea.top + rcWnd.Height(); + + } + + DWORD dwStyle = ::GetWindowLong( m_hwndCtrl, GWL_STYLE ); + + // special treatment for combo-boxes + if( m_bComboSpecial && (dwStyle & CBS_DROPDOWN) ) { + // keep height (though only fully visible when dropped down) + rcNewArea.bottom = rcNewArea.top + rcWnd.Height(); + } + + // FIX: ::MoveWindow would case problems with some ActiveX Controls [Micheal Chapman] + CWnd* pTempWnd = CWnd::FromHandle( m_hwndCtrl ); + pTempWnd->MoveWindow( rcNewArea.left, rcNewArea.top, rcNewArea.Width(), rcNewArea.Height() ); + + if( m_bComboSpecial && !(dwStyle & CBS_DROPDOWN) && !(dwStyle & CBS_NOINTEGRALHEIGHT) ) { + + // Keep CB Size = Edit + LB ( if not CBS_NOINTEGRALHEIGHT) + + ::GetWindowRect( m_hwndCtrl, rcWnd ); + + CRect rcListBox; + HWND hwndListBox = ::GetDlgItem(m_hwndCtrl, 1000); // ListBox of CB + if( hwndListBox != 0 ) + { + ::GetWindowRect( hwndListBox, rcListBox ); + rcWnd.bottom = rcListBox.bottom; + + rcNewArea.bottom = rcNewArea.top + rcWnd.Height(); + + // FIX: ::MoveWindow would case problems with some ActiveX Controls [Micheal Chapman] + CWnd* pTempWnd = CWnd::FromHandle( m_hwndCtrl ); + pTempWnd->MoveWindow( rcNewArea.left, rcNewArea.top, rcNewArea.Width(), rcNewArea.Height(), true ); + } + } + + ::RedrawWindow(m_hwndCtrl,0,0, RDW_INVALIDATE | RDW_UPDATENOW ); + + } + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutMgr::PaneTab implementation + + +ETSLayoutMgr::PaneTab::PaneTab( CTabCtrl* pTab, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /*= nDefaultBorder*/, int sizeExtraBorder /*= 0*/ ) +: ETSLayoutMgr::Pane(pMgr, orientation, sizeBorder, sizeExtraBorder) +{ + ASSERT(pTab); + m_pTab = pTab; +} + +int ETSLayoutMgr::PaneTab::getConstrainHorz(int sizeParent) +{ + CRect rcTab; + m_pTab->AdjustRect(TRUE, &rcTab); + + if(rcTab.Width() > sizeParent) + return rcTab.Width(); + + return Pane::getConstrainHorz(sizeParent /*- rcTab.Width()*/); +} + +int ETSLayoutMgr::PaneTab::getConstrainVert(int sizeParent) +{ + CRect rcTab; + m_pTab->AdjustRect(TRUE, &rcTab); + + if( m_modeResize & ABSOLUTE_VERT ) { + return m_sizeSecondary + rcTab.Height(); + } + + if(rcTab.Height() > sizeParent) + return rcTab.Height(); + + return Pane::getConstrainVert(sizeParent /*- rcTab.Height()*/); +} + +int ETSLayoutMgr::PaneTab::getMinConstrainHorz() +{ + CRect rcTab(0,0,0,0); + m_pTab->AdjustRect(TRUE, &rcTab); + + return Pane::getMinConstrainHorz() + rcTab.Width() ; +} + +int ETSLayoutMgr::PaneTab::getMinConstrainVert() +{ + CRect rcTab(0,0,0,0); + m_pTab->AdjustRect(TRUE, &rcTab); + + return Pane::getMinConstrainVert() + rcTab.Height(); +} + +int ETSLayoutMgr::PaneTab::getMaxConstrainHorz() +{ + CRect rcTab(0,0,0,0); + m_pTab->AdjustRect(TRUE, &rcTab); + + int paneMax = Pane::getMaxConstrainHorz(); + return (paneMax != -1) ? paneMax + rcTab.Width() : -1; +} + +int ETSLayoutMgr::PaneTab::getMaxConstrainVert() +{ + CRect rcTab(0,0,0,0); + m_pTab->AdjustRect(TRUE, &rcTab); + + int paneMax = Pane::getMaxConstrainVert(); + return (paneMax != -1) ? paneMax + rcTab.Height() : -1; +} + +bool ETSLayoutMgr::PaneTab::resizeTo(CRect& rcNewArea) +{ + m_pTab->MoveWindow(rcNewArea); + m_pTab->AdjustRect(FALSE,rcNewArea); + + return Pane::resizeTo(rcNewArea); +} + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutMgr::PaneCtrl implementation + + +ETSLayoutMgr::PaneCtrl::PaneCtrl( CWnd* pCtrl, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /*= nDefaultBorder*/, int sizeExtraBorder /*= 0*/, int sizeTopExtra /*= 0*/ ) +: ETSLayoutMgr::Pane(pMgr, orientation, sizeBorder, sizeExtraBorder) +{ + m_sizeTopExtra = sizeTopExtra; + + ASSERT(pCtrl); + m_hwndCtrl = pCtrl->GetSafeHwnd(); +} + +ETSLayoutMgr::PaneCtrl::PaneCtrl( UINT nID, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /*= nDefaultBorder*/, int sizeExtraBorder /*= 0*/, int sizeTopExtra /*= 0*/ ) +: ETSLayoutMgr::Pane(pMgr, orientation, sizeBorder, sizeExtraBorder) +{ + m_sizeTopExtra = sizeTopExtra; + + m_hwndCtrl = ::GetDlgItem(pMgr->GetWnd()->GetSafeHwnd(), nID); + ASSERT(m_hwndCtrl); +} + +int ETSLayoutMgr::PaneCtrl::getConstrainHorz(int sizeParent) +{ + return Pane::getConstrainHorz(sizeParent) ; +} + +int ETSLayoutMgr::PaneCtrl::getConstrainVert(int sizeParent) +{ + return Pane::getConstrainVert(sizeParent); +} + +int ETSLayoutMgr::PaneCtrl::getMinConstrainHorz() +{ + return Pane::getMinConstrainHorz(); +} + +int ETSLayoutMgr::PaneCtrl::getMinConstrainVert() +{ + return Pane::getMinConstrainVert() + m_sizeTopExtra; +} + +int ETSLayoutMgr::PaneCtrl::getMaxConstrainHorz() +{ + int paneMax = Pane::getMaxConstrainHorz(); + return ( paneMax == -1) ? -1 : paneMax ; +} + +int ETSLayoutMgr::PaneCtrl::getMaxConstrainVert() +{ + int paneMax = Pane::getMaxConstrainVert(); + return ( paneMax == -1) ? -1 : paneMax + m_sizeTopExtra; +} + +bool ETSLayoutMgr::PaneCtrl::resizeTo(CRect& rcNewArea) +{ + // FIX: ::MoveWindow would case problems with some ActiveX Controls [Micheal Chapman] + CWnd* pTempWnd = CWnd::FromHandle( m_hwndCtrl ); + pTempWnd->MoveWindow( rcNewArea.left, rcNewArea.top, rcNewArea.Width(), rcNewArea.Height(), true ); + + ::RedrawWindow(m_hwndCtrl,0,0, RDW_INVALIDATE | RDW_UPDATENOW |RDW_ERASE); + rcNewArea.top += m_sizeTopExtra; + return Pane::resizeTo(rcNewArea); +} + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutMgr::Pane implementation + +ETSLayoutMgr::Pane::Pane( ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /* = nDefaultBorder */, int sizeExtraBorder /*= 0*/) +: PaneBase(pMgr) +{ + m_Orientation = orientation; + m_sizeBorder = sizeBorder; + m_sizeSecondary = 0; + m_modeResize = 0; + m_sizeExtraBorder= sizeExtraBorder; +} + + +ETSLayoutMgr::Pane::~Pane() +{ +} + + +bool ETSLayoutMgr::Pane::addItem( CWnd* pWnd, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeX /*=0*/, int sizeY /*=0*/, int sizeXMin /*=0*/, int sizeYMin /*=0*/) +{ + CPaneBase pItem = new PaneItem( pWnd, m_pMgr, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); + return addPane( pItem ); +} + +bool ETSLayoutMgr::Pane::addItem( UINT nID, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeX /*=0*/, int sizeY /*=0*/, int sizeXMin /*=0*/, int sizeYMin /*=0*/) +{ + CPaneBase pItem = new PaneItem( nID, m_pMgr, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); + return addPane( pItem ); +} + +bool ETSLayoutMgr::Pane::addItemFixed(int size) +{ + CPaneBase pNewItem = m_pMgr->itemFixed(m_Orientation, size); + return addPane( pNewItem ); +} + +bool ETSLayoutMgr::Pane::addItemGrowing() +{ + CPaneBase pNewItem = m_pMgr->itemGrowing(m_Orientation); + return addPane( pNewItem ); +} + +bool ETSLayoutMgr::Pane::addItemSpaceBetween( CWnd* pWndFirst, CWnd* pWndSecond ) +{ + CPaneBase pNewItem = m_pMgr->itemSpaceBetween(m_Orientation, pWndFirst, pWndSecond); + return addPane( pNewItem ); +} + +bool ETSLayoutMgr::Pane::addItemSpaceBetween( UINT nIDFirst, UINT nIDSecond ) +{ + CPaneBase pNewItem = m_pMgr->itemSpaceBetween(m_Orientation, nIDFirst, nIDSecond); + return addPane( pNewItem ); +} + +bool ETSLayoutMgr::Pane::addItemSpaceLike( CWnd* pWnd ) +{ + CPaneBase pNewItem = m_pMgr->itemSpaceLike(m_Orientation, pWnd); + return addPane( pNewItem ); +} + +bool ETSLayoutMgr::Pane::addItemSpaceLike( UINT nID ) +{ + CPaneBase pNewItem = m_pMgr->itemSpaceLike(m_Orientation, nID); + return addPane( pNewItem ); +} + +bool ETSLayoutMgr::Pane::addPane( CPane pSubpane, ETSLayoutMgr::layResizeMode modeResize, int sizeSecondary /* = 0 */) +{ + if( pSubpane->getOrientation() == m_Orientation) + { + // wrap in subpane of opposite orientation + CPane pPaneWrap = new Pane(m_pMgr, m_Orientation==HORIZONTAL?VERTICAL:HORIZONTAL,0,0); + pPaneWrap->addPane( pSubpane ); + + addPane( pPaneWrap, modeResize, sizeSecondary ); + } + else + { + pSubpane->m_modeResize = modeResize; + + if(m_Orientation==HORIZONTAL && (modeResize & ABSOLUTE_HORZ) ) { + if(sizeSecondary == 0) { + pSubpane->m_sizeSecondary = pSubpane->getMinConstrainHorz(); + } + } + else if(m_Orientation==HORIZONTAL && (modeResize & RELATIVE_HORZ) ) { + pSubpane->m_sizeSecondary = sizeSecondary; + } + else if(m_Orientation==VERTICAL && (modeResize & ABSOLUTE_VERT) ) { + if(sizeSecondary == 0) { + pSubpane->m_sizeSecondary = pSubpane->getMinConstrainVert(); + } + } + else if(m_Orientation==VERTICAL && (modeResize & RELATIVE_VERT) ) { + pSubpane->m_sizeSecondary = sizeSecondary; + } + + m_paneItems.Add(pSubpane); + } + + return true; +} + +bool ETSLayoutMgr::Pane::addPane( CPaneBase pItem ) +{ + m_paneItems.Add(pItem); + return true; +} + +int ETSLayoutMgr::Pane::getConstrainHorz(int sizeParent) +{ + ASSERT( m_Orientation == VERTICAL); + + if( m_modeResize & RELATIVE_HORZ ) { + return (sizeParent * m_sizeSecondary) / 100; + } + else if( m_modeResize & ABSOLUTE_HORZ ){ + return m_sizeSecondary; + } + else + return 0; +} + + +int ETSLayoutMgr::Pane::getConstrainVert(int sizeParent) +{ + ASSERT( m_Orientation == HORIZONTAL); + + if( m_modeResize & RELATIVE_VERT ) { + return (sizeParent * m_sizeSecondary) / 100; + } + else if( m_modeResize & ABSOLUTE_VERT ) { + return m_sizeSecondary; + } + else { + return 0; + } +} + +int ETSLayoutMgr::Pane::getMaxConstrainHorz() +{ + if(m_Orientation == HORIZONTAL) { + int nMaxConstr = -1; + for(int i=0; igetMaxConstrainHorz(); + if(nConstrain == -1) + return -1; + + nMaxConstr += nConstrain; + } + return (nMaxConstr == -1) ? -1 : nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; + } + else if( m_modeResize & ABSOLUTE_HORZ && m_sizeSecondary!=0) { + return m_sizeSecondary; // + 2*m_sizeExtraBorder; + } + else { + int nMaxConstr = -1; + for(int i=0; igetMaxConstrainHorz(); + + if( nConstrain == -1) + return -1; + else + nMaxConstr = max(nMaxConstr, nConstrain); + + } + return (nMaxConstr == -1) ? -1 : nMaxConstr + 2*m_sizeExtraBorder; + } +} + +int ETSLayoutMgr::Pane::getMaxConstrainVert() +{ + if(m_Orientation == VERTICAL) { + int nMaxConstr = -1; + for(int i=0; igetMaxConstrainVert(); + if(nConstrain == -1) + return -1; + + nMaxConstr += nConstrain; + } + return (nMaxConstr == -1) ? -1 : nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; + } + else if( m_modeResize & ABSOLUTE_VERT && m_sizeSecondary!=0) { + return m_sizeSecondary; // + 2*m_sizeExtraBorder; + } + else { + int nMaxConstr = -1; + for(int i=0; igetMaxConstrainVert(); + + if( nConstrain == -1) + return -1; + else + nMaxConstr = max(nMaxConstr, nConstrain); + + } + return (nMaxConstr == -1) ? -1 : nMaxConstr + 2*m_sizeExtraBorder; + } +} + +int ETSLayoutMgr::Pane::getMinConstrainHorz() +{ + if(m_Orientation == HORIZONTAL) { + int nMaxConstr = 0; + for(int i=0; igetMinConstrainHorz()); + } + return nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; + } + else if( m_modeResize & ABSOLUTE_HORZ && m_sizeSecondary!=0) { + return m_sizeSecondary; // + 2*m_sizeExtraBorder; + } + else { + int nMaxConstr = 0; + for(int i=0; igetMinConstrainHorz(); + nMaxConstr = max(nMaxConstr, nConstrain); + } + return nMaxConstr + 2*m_sizeExtraBorder; + } +} + +int ETSLayoutMgr::Pane::getMinConstrainVert() +{ + if(m_Orientation == VERTICAL) { + int nMaxConstr = 0; + for(int i=0; igetMinConstrainVert()); + } + return nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; + } + else if( m_modeResize & ABSOLUTE_VERT && m_sizeSecondary!=0) { + return m_sizeSecondary; // + 2*m_sizeExtraBorder; + } + else { + int nMaxConstr = 0; + for(int i=0; igetMinConstrainVert(); + nMaxConstr = max(nMaxConstr, nConstrain); + } + return nMaxConstr + 2*m_sizeExtraBorder; + } +} + + +int ETSLayoutMgr::Pane::resizeToAbsolute(int& availSpace, CArray& sizePrimary, + CArray& sizeMin, CArray& sizeMax) +{ + // count all greedy items as returnvalue + int nGreedy = 0; + + // first, subtract all absoulute items from available space + for(int i=0; imodeResize() & ABSOLUTE_HORZ) { + availSpace -= (sizePrimary[i] = pItem->getConstrainHorz(0)); + } + + // count Greedy items for later + if(!(pItem->modeResize() & ABSOLUTE_HORZ) && !(pItem->modeResize() & RELATIVE_HORZ)) { + nGreedy++; + } + + sizeMin[i] = pItem->getMinConstrainHorz(); + sizeMax[i] = pItem->getMaxConstrainHorz(); + } + else { + + // for absolute items subtract their size from available space + if(pItem->modeResize() & ABSOLUTE_VERT) { + availSpace -= (sizePrimary[i] = pItem->getConstrainVert(0)); + } + + // count Greedy items for later + if(!(pItem->modeResize() & ABSOLUTE_VERT) && !(pItem->modeResize() & RELATIVE_VERT)) { + nGreedy++; + } + + sizeMin[i] = pItem->getMinConstrainVert(); + sizeMax[i] = pItem->getMaxConstrainVert(); + } + + } + + // Must not be negative !! + availSpace = max(availSpace, 0); + + return nGreedy; +} + +bool ETSLayoutMgr::Pane::resizeToRelative(int& availSpace, CArray& sizePrimary, + CArray& sizeMin, CArray& sizeMax) +{ + // Then all relative items as percentage of left space (as of now after + // all absolute items are subtracted + + int availRel = availSpace; // At the beginning all of remaining space is available. We want all + // operation to be relative to the left space at this moment, so we + // save this amount here. Then we safly can lower availSpace + + int relDiff = 0; // The cumulated difference between first proposed size and + // eventual maximum/minimum size. This amount has to be + // saved in some other place (i.e. where relativ items/subpane + // are not limited by min/max + + int relLeft = 0; // The cumulated amout of space that can be saved by + // shrinking the items/panes up to the minimum + + int relCount = 0; // Actually allocated item/subpane's cumulated primary sizes + // of non-limited items/subpanes (these can be modified in fixup) + // needed for equally distribution of differences amoung non-limited + // relative items/subpanes + + for(int i=0; imodeResize() & RELATIVE_HORZ) + || + (m_Orientation==VERTICAL && pItem->modeResize() & RELATIVE_VERT) ) + { + // minimum item/subpane size in primary direction (pixels) + int nSizeRelMin = sizeMin[i]; + + // maximum item/subpane size in primary direction (pixels) + int nSizeRelMax = sizeMax[i]; + + // Relative size in primary direction (pixels) + int nSizeRel = (m_Orientation==HORIZONTAL) + ? + (pItem->getConstrainHorz(availRel)) + : + (pItem->getConstrainVert(availRel)); + + if( nSizeRel < nSizeRelMin) { + // The item/pane is shrinked too small! + // We will grow it to it's minimum-size. In order not to modify + // this item later when fixing up set the size to the negative + // minimum size + sizePrimary[i] = -nSizeRelMin; + + // As we grew one item/subpane we have to shrink another one. + // We keep count on how much space we needed to grow the item + // to it's minimum size + relDiff += ( nSizeRelMin - nSizeRel ); + } + else if( nSizeRelMax != -1 && nSizeRel > nSizeRelMax) { + // if there's a maximum size (nSizeRelMax != -1) and our item/subpane + // is to be resized over that amount correct it. In order not to modify + // this item later when fixing up set the size to the negative + // maximum size + sizePrimary[i] = -nSizeRelMax; + + // As we shrinked one item/subpane we have to grow another one. + // We keep count on how much space we needed to grow the item + // to it's maximum size. + relDiff += ( nSizeRelMax - nSizeRel ); + } + else { + // this is the normal case: neither are we minimum limited nor maximum + // limited + + // As this item/subpane is larger that it's minimum we could later (if + // necessary for fixup) shrink it for the difference amount of pixels + relLeft += ( nSizeRel - nSizeRelMin ); + + // Set the primary size of this item/pane. Can later be modified by fixup + sizePrimary[i] = nSizeRel; + + // Add this item/subpane's primary size to the count of already allocated + // cumulated size of non-limited items/subpanes (these can be modified in fixup) + relCount += nSizeRel; + } + + // decrease available space by used space in this step + availSpace -= nSizeRel; + } + } + + // We now have the situation that some items/subpanes had to be adjusted for cumulated + // relDiff pixels (positive value means more space taken than indicated by percentage of + // left space). On the other hand we have some items/subpanes which were not limited (in + // their current dimensions) but could be if necessary up to relLeft pixels. + if(relLeft < relDiff && availSpace >= (relDiff-relLeft) ){ + + // If it's not possible to shrink other (relative) panes in order to distribute the + // difference because the left for shrinking (relLeft) is too small we need to aquire + // more space from the globally left space (if available at all) + availSpace -= (relDiff-relLeft); + relDiff = relLeft; + } + + // At this point we should have some space left (at least not be negative with the leftover + // space) and on the other hand there's enough space for the limit-difference to be distributed +// ASSERT( availSpace >= 0 && relLeft >= relDiff); + + // Fixup Relative: + // Distribute (if anecessary) relDiff on other (not limited) relative items/subpanes + // (if available - if not later just grow the limited panes) + while( relDiff != 0 && relCount >= 0 ) { + + // in every iteration there must be some space distributed (of the difference) or it could + // come to endless looping. Save the amount of space actually distributed in this iteration + int relDist = 0; + + for(int i=0; imodeResize() & RELATIVE_HORZ) && sizePrimary[i] > 0) + || + (m_Orientation==VERTICAL && (pItem->modeResize() & RELATIVE_VERT) && sizePrimary[i] > 0) ) + { + // keep a flag for termination of this iteration + bool bLast = false; + + // the difference should be distributed amoung all non-limited items/subpanes equally. + // nDiff is the amount for the current item/subpane + int nDiff = (relDiff * sizePrimary[i]) / relCount; + + // if it's a too small value just add it to the current pane and break iteration + if( abs(relDiff) <= FIXUP_CUTOFF ) { + // take it all in this step + nDiff = relDiff; + + // set break flag + bLast = true; + } + + // calculate the new size for the current item/subpane + int nNewSize = sizePrimary[i] - nDiff; + + if( nNewSize < sizeMin[i] ) { + // oh, we are limited here. Revise our plan: + + // Not all of the space could be saved, add the actually possible space + // to the sum + relDist += ( sizePrimary[i] - sizeMin[i] ); + + // set it to the minimum possible size + sizePrimary[i] = -sizeMin[i]; + + // as this item/subpane is now limited it's occupied space doesn't count + // for relCount anymore + relCount-= ( sizePrimary[i] ); + } + else { + // account the difference of the sizes in relDist and set new size + relDist += ( sizePrimary[i] - nNewSize ); + sizePrimary[i] = nNewSize; + + // if it's the last one break now + if(bLast) + break; + } + } + } + // Distributed some relDiff-space in every iteration +// ASSERT(relDist != 0); + relDiff -= relDist; + + if( relDist == 0 ) + break; + } + + { + // Fixup Relative: invert all negative (limited) sized to correct value + for(int i=0; imodeResize() & RELATIVE_HORZ) && sizePrimary[i] < 0) + || + (m_Orientation==VERTICAL && (pItem->modeResize() & RELATIVE_VERT) && sizePrimary[i] < 0) ) + { + sizePrimary[i] *= -1; + } + } + } + + return true; +} + +bool ETSLayoutMgr::Pane::resizeToGreedy(int& availSpace, int nGreedy, CArray& sizePrimary, + CArray& sizeMin, CArray& sizeMax) +{ + // Now resize all Greedy items/subpanes equally among the remaining space + int greedyDiff = 0; // The cumulated difference between first proposed size and + // eventual maximum/minimum size. This amount has to be + // saved in some other place (i.e. where items/subpane + // are not limited by min/max + + int greedyLeft = 0; // The cumulated amount of space that can be saved by + // shrinking the items/panes up to the minimum + + int greedyCount = 0; // Actually allocated item/subpane's cumulated primary sizes + // of non-limited items/subpanes (these can be modified in fixup) + // needed for equally distribution of differences amoung non-limited + // items/subpanes + + for(int i=0; imodeResize()&ABSOLUTE_HORZ) + && !(pItem->modeResize()&RELATIVE_HORZ) + ) + || + (m_Orientation==VERTICAL + && !(pItem->modeResize()&ABSOLUTE_VERT) + && !(pItem->modeResize()&RELATIVE_VERT) + ) + ) + { + + // All greedy items get an equal portion of the left space + int nSize = availSpace / nGreedy; + + // minimum item/subpane size in primary direction (pixels) + int nSizeMin = sizeMin[i]; + + // maximum item/subpane size in primary direction (pixels) + int nSizeMax = sizeMax[i]; + + + // the last gets the all of the remaining space + if( nGreedy == 1 ) + nSize = availSpace; + + if( nSize < nSizeMin) { + // The item/pane is shrinked too small! + // We will grow it to it's minimum-size. In order not to modify + // this item later when fixing up set the size to the negative + // minimum size + sizePrimary[i] = -nSizeMin; + + // As we grew one item/subpane we have to shrink another one. + // We keep count on how much space we needed to grow the item + // to it's minimum size + greedyDiff += ( nSizeMin - nSize ); + } + else if( nSizeMax != -1 && nSize > nSizeMax) { + // if there's a maximum size (nSizeRelMax != -1) and our item/subpane + // is to be resized over that amount correct it. In order not to modify + // this item later when fixing up set the size to the negative + // maximum size + sizePrimary[i] = -nSizeMax; + + // As we shrinked one item/subpane we have to grow another one. + // We keep count on how much space we needed to grow the item + // to it's maximum size. + greedyDiff += ( nSizeMax - nSize ); + } + else { + + // this is the normal case: neither are we minimum limited nor maximum + // limited + + // As this item/subpane is larger that it's minimum we could later (if + // necessary for fixup) shrink it for the difference amount of pixels + greedyLeft += ( nSize - nSizeMin ); + + // Set the primary size of this item/pane. Can later be modified by fixup + sizePrimary[i] = nSize; + + // Add this item/subpane's primary size to the count of already allocated + // cumulated size of non-limited items/subpanes (these can be modified in fixup) + greedyCount += nSize; + } + + // decrease available space by used space in this step + availSpace -= nSize; + + // one greedy item/subpane complete + --nGreedy; + } + } + + + // Fixup Greedy I + // Distribute (if anecessary) greedyDiff on other (not limited) greedy items/subpanes + // (if available - if not later just grow the limited panes) + + // at least on not limited item present + bool bAtLeastOne = true; + + while( bAtLeastOne && greedyDiff != 0 && greedyCount > 0) { + + // in every iteration there must be some space distributed (of the difference) or it could + // come to endless looping. Save the amount of space actually distributed in this iteration + int greedyDist = 0; + + // at least on not limited item present + bAtLeastOne = false; + + for(int i=0; imodeResize()&ABSOLUTE_HORZ) + && !(pItem->modeResize()&RELATIVE_HORZ) + && sizePrimary[i] > 0 + ) + || + (m_Orientation==VERTICAL + && !(pItem->modeResize()&ABSOLUTE_VERT) + && !(pItem->modeResize()&RELATIVE_VERT) + && sizePrimary[i] > 0 + ) + ) + { + // keep a flag for termination of this iteration + bool bLast = false; + + // the difference should be distributed among all non-limited items/subpanes equally. + // nDiff is the amount for the current item/subpane + int nDiff = (greedyDiff * sizePrimary[i]) / greedyCount; + + // if it's a too small value just add it to the current pane and break iteration + if( abs(greedyDiff) <= FIXUP_CUTOFF || nDiff == 0) { + // take it all in this step + nDiff = greedyDiff; + + // set break flag + bLast = true; + } + + // calculate the new size for the current item/subpane + int nNewSize = sizePrimary[i] - nDiff; + + if( nNewSize < sizeMin[i] ) { + // oh, we are limited here. Revise our plan: + + if( sizePrimary[i] != sizeMin[i] ) + bAtLeastOne = true; + + // Not all of the space could be saved, add the actually possible space + // to the sum + greedyDist += ( sizePrimary[i] - sizeMin[i] ); + + // set it to the minimum possible size + sizePrimary[i] = sizeMin[i]; + + // as this item/subpane is now limited its occupied space doesn't count + // for relCount anymore + greedyCount -= ( sizePrimary[i] ); + } + else { + // yes, there is one + bAtLeastOne = true; + + // account the difference of the sizes in relDist and set new size + greedyDist += ( sizePrimary[i] - nNewSize ); + sizePrimary[i] = nNewSize; + + // if it's the last one break now + if(bLast) + break; + } + } + } + // Distributed some greedyDiff-space in every iteration + ASSERT(!bAtLeastOne || greedyDist != 0 || greedyCount<=0); + greedyDiff -= greedyDist; + } + + + // Fixup Greedy II + if( greedyDiff < 0 ) { + // still difference, some space left + + // are there any items which are minimum-limited where we can give more space? + for(int i=0; imodeResize()&ABSOLUTE_HORZ) + && !(pItem->modeResize()&RELATIVE_HORZ) + ) + || + (m_Orientation==VERTICAL + && !(pItem->modeResize()&ABSOLUTE_VERT) + && !(pItem->modeResize()&RELATIVE_VERT) + ) + ) + { + if( sizePrimary[i] == -sizeMin[i] ) { + // fill this one up as much as possible + if( sizeMax[i] == -1) { + // all fits in + sizePrimary[i] += greedyDiff; + greedyDiff = 0; + } + else { + sizePrimary[i] += -min( -greedyDiff, sizeMax[i]-sizeMin[i]); + greedyDiff -= -min( -greedyDiff, sizeMax[i]-sizeMin[i]); + } + } + } + } + } + + { + // Fixup Greedy III: invert all negative (limited) sized to correct value + for(int i=0; imodeResize() & ABSOLUTE_HORZ) + && !(pItem->modeResize() & RELATIVE_HORZ) + && sizePrimary[i] < 0 + && sizeMin[i] >= 0 + ) + || + (m_Orientation==VERTICAL + && !(pItem->modeResize() & ABSOLUTE_VERT) + && !(pItem->modeResize() & RELATIVE_VERT) + && sizePrimary[i] < 0 + && sizeMin[i] >= 0 + ) + ) + { + if(sizePrimary[i] < 0) + sizePrimary[i] *= -1; + } + } + } + + return true; +} + + +bool ETSLayoutMgr::Pane::resizeTo(CRect& rcNewArea) +{ + // There must be some items or subpanes + ASSERT(m_paneItems.GetSize()); + + // This Array holds the size in primary direction for each item/subpane + CArray sizePrimary; + sizePrimary.SetSize(m_paneItems.GetSize()); + + // This Array holds information about the minimum size in primary direction + CArray sizeMin; + sizeMin.SetSize(m_paneItems.GetSize()); + + // This Array holds information about the maximum size in primary direction + CArray sizeMax; + sizeMax.SetSize(m_paneItems.GetSize()); + + + // How much space is actually available, subtract all borders between items + int availSpace = (m_Orientation == HORIZONTAL ? rcNewArea.Width() : rcNewArea.Height() ) - (m_paneItems.GetUpperBound()*m_sizeBorder); + + // If there is some Extra border (on top/bottem resp. left/right) subtract it too + availSpace -= 2*m_sizeExtraBorder; + + // Add the extra Border to top/bottem resp. left/right + if(m_Orientation == HORIZONTAL) { + rcNewArea.top += m_sizeExtraBorder; + rcNewArea.bottom -= m_sizeExtraBorder; + } + else { + rcNewArea.left += m_sizeExtraBorder; + rcNewArea.right -= m_sizeExtraBorder; + } + + // Counts the number of greedy items/subpanes + int nGreedy = resizeToAbsolute(availSpace, sizePrimary, sizeMin, sizeMax ); + + if(nGreedy == -1) + return false; + + if(! resizeToRelative(availSpace, sizePrimary, sizeMin, sizeMax ) ) + return false; + + if(! resizeToGreedy(availSpace, nGreedy, sizePrimary, sizeMin, sizeMax ) ) + return false; + + + // If there is any left space and there are ALIGN_FILL_* Items to assign it + // equally among them + if( availSpace > 0 ) { + // Count possible Items + int nFillItems = 0; + + for(int i=0; imodeResize() & ABSOLUTE_HORZ ) + && (pItem->modeResize() & ALIGN_FILL_HORZ) + + || + + (pItem->modeResize() & ABSOLUTE_VERT ) + && (pItem->modeResize() & ALIGN_FILL_VERT) + ) + { + ++nFillItems; + } + } + + if( nFillItems > 0 ) { + // okay, there are nFillItems, make them all availSpace/nFillItems bigger + for(int i=0; imodeResize() & ABSOLUTE_HORZ ) + && (pItem->modeResize() & ALIGN_FILL_HORZ) + + || + + (pItem->modeResize() & ABSOLUTE_VERT ) + && (pItem->modeResize() & ALIGN_FILL_VERT) + ) + { + + if( nFillItems == 1 ) { + // the last one gets all the rest + sizePrimary[i] += availSpace; + availSpace = 0; + --nFillItems; + } + else { + sizePrimary[i] += availSpace/nFillItems; + availSpace -= availSpace/nFillItems; + --nFillItems; + } + + } + } + } + + } + + // Now reposition all items: + + // starting offset + int nOffset = (m_Orientation==HORIZONTAL ? rcNewArea.left : rcNewArea.top ) + m_sizeExtraBorder; + for(int i=0; iresizeTo( rcPane ); + + // go to the next position (old pos + size + border) + ASSERT(sizePrimary[i] >= 0); + nOffset += m_sizeBorder + sizePrimary[i]; + } + + + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutDialog dialog + +#pragma warning(disable: 4355) +ETSLayoutDialog::ETSLayoutDialog(UINT nID, CWnd* pParent /*=NULL*/, LPCTSTR strName /*=NULL*/, bool bGripper /*=true*/) + : CBaseDialog(nID, pParent), ETSLayoutMgr( this ) +{ + //{{AFX_DATA_INIT(ETSLayoutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + m_bGripper = bGripper; + + if(strName) + m_strRegStore = strName; +} +#pragma warning(default: 4355) + +BEGIN_MESSAGE_MAP(ETSLayoutDialog, CBaseDialog) + //{{AFX_MSG_MAP(ETSLayoutDialog) + ON_WM_SIZE() + ON_WM_GETMINMAXINFO() + ON_WM_ERASEBKGND() + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutDialog message handlers + +BOOL ETSLayoutDialog::OnEraseBkgnd(CDC* pDC) +{ + EraseBkgnd(pDC); + return true; +} + +void ETSLayoutDialog::OnSize(UINT nType, int cx, int cy) +{ + CBaseDialog::OnSize(nType, cx, cy); + + if( abs(cx) + abs(cy) > 0) + { + // Reposition Size Marker + // Re-Layout all controls + UpdateLayout(); + RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); + } + +} + +void ETSLayoutDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + if(m_RootPane.IsValid()) { + + CRect rcClient = GetRect(); + if( rcClient.Height() > 0 || rcClient.Width() > 0 ) + { + + CRect rcWnd; + GetWindowRect(rcWnd); + + // How much do Window and Client differ + int nDiffHorz = rcWnd.Width() - rcClient.Width(); + int nDiffVert = rcWnd.Height() - rcClient.Height(); + + // Take into account that there is a border around the rootPane + lpMMI->ptMinTrackSize = CPoint(m_RootPane->getMinConstrainHorz() + nDiffHorz + 2*m_sizeRootBorders.cx, + m_RootPane->getMinConstrainVert() + nDiffVert + 2*m_sizeRootBorders.cy); + + int maxWidth = m_RootPane->getMaxConstrainHorz(); + int maxHeight = m_RootPane->getMaxConstrainVert(); + + if( maxWidth != -1 ) { + lpMMI->ptMaxTrackSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; + lpMMI->ptMaxSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; + } + + if( maxHeight != -1 ) { + lpMMI->ptMaxTrackSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; + lpMMI->ptMaxSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; + } + } + } +} + + +CRect ETSLayoutDialog::GetRect() +{ + CRect r; + GetClientRect(r); + + if( m_bGripper ) + { + if( ::IsWindow(m_StatusBar.GetSafeHwnd()) ) + { + CRect rcSizeIcon; + m_StatusBar.GetWindowRect( rcSizeIcon); + r.bottom -= (rcSizeIcon.Height() - m_sizeRootBorders.cy - 5); + } + } + + return r; +} + + +BOOL ETSLayoutDialog::OnInitDialog() +{ + CBaseDialog::OnInitDialog(); + + // Ensure that the dialog is resizable + this->ModifyStyle(0, WS_THICKFRAME); + + if(!m_strRegStore.IsEmpty()) { + Load(m_strRegStore); + } + +#ifdef _AUTO_SET_ICON + POSITION pos = AfxGetApp()->GetFirstDocTemplatePosition(); + if(pos) { + + class ETSPseudoDocTemplate : public CDocTemplate + { + friend class ETSLayoutDialog; + }; + + ETSPseudoDocTemplate* pDocT = (ETSPseudoDocTemplate*) AfxGetApp()->GetNextDocTemplate(pos); + SetIcon( AfxGetApp()->LoadIcon(pDocT->m_nIDResource) ,FALSE); + } +#endif + + // Sizing icon + if(m_bGripper) + { + if(m_StatusBar.Create(m_pWnd)) + { + m_StatusBar.SetIndicators(auIDStatusBar, sizeof(auIDStatusBar) / sizeof(UINT)); + m_StatusBar.SetWindowText(_T("")); + m_StatusBar.SetPaneStyle( 0, SBPS_STRETCH | SBPS_NOBORDERS ); + m_pWnd -> RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); + } + else + AfxMessageBox(_T("Error - Statusbar")); + + } + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void ETSLayoutDialog::OnDestroy() +{ + // Store size/position + if(!m_strRegStore.IsEmpty()) { + Save(m_strRegStore); + } + + // manually delete layout definition if object is reused + m_RootPane = 0; + + CBaseDialog::OnDestroy(); +} + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutDialog dialog + +#pragma warning(disable: 4355) +#ifdef CS_HELP +ETSLayoutDialogBar::ETSLayoutDialogBar(UINT nID ) + : CBaseDialogBar( nID ), ETSLayoutMgr( this ) +#else +ETSLayoutDialogBar::ETSLayoutDialogBar() + : ETSLayoutMgr( this ) +#endif +{ + //{{AFX_DATA_INIT(ETSLayoutDialogBar) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + m_bInitialized = false; + setRootBorders(0,0); +} +#pragma warning(default: 4355) + +BEGIN_MESSAGE_MAP(ETSLayoutDialogBar, CBaseDialogBar) + //{{AFX_MSG_MAP(ETSLayoutDialogBar) + ON_WM_SIZE() + ON_WM_GETMINMAXINFO() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + ON_MESSAGE(WM_INITDIALOG, OnInitDialog) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutDialogBar message handlers + +LRESULT ETSLayoutDialogBar::OnInitDialog(WPARAM, LPARAM) +{ + Default(); + Initialize(); + return TRUE; +} + +void ETSLayoutDialogBar::UpdateLayout() +{ + ETSLayoutMgr::UpdateLayout(); + + if(m_RootPane.IsValid()) { + CRect rcClient = GetRect(); + + CRect rcWnd; + GetWindowRect(rcWnd); + + // How much do Window and Client differ + CSize sizeDiff( rcWnd.Width() - rcClient.Width(), rcWnd.Height() - rcClient.Height()); + + // Take into account that there is a border around the rootPane +// m_szMin = CSize(m_RootPane->getMinConstrainHorz() + sizeDiff.cx + 2*m_sizeRootBorders.cx, +// m_RootPane->getMinConstrainVert() + sizeDiff.cy + 2*m_sizeRootBorders.cy); + } +} + +CSize ETSLayoutDialogBar::CalcDynamicLayout(int nLength, DWORD dwMode) +{ + CSize sizeRet = CBaseDialogBar::CalcDynamicLayout(nLength, dwMode); + + CSize sizeMin = sizeRet; + CSize sizeMax = sizeRet; + + if(m_RootPane.IsValid()) { + CRect rcClient = GetRect(); + + CRect rcWnd; + GetWindowRect(rcWnd); + + // How much do Window and Client differ + CSize sizeDiff( rcWnd.Width() - rcClient.Width(), rcWnd.Height() - rcClient.Height()); + + // Take into account that there is a border around the rootPane +// sizeMin = CSize(m_RootPane->getMinConstrainHorz() + sizeDiff.cx + 2*m_sizeRootBorders.cx, +// m_RootPane->getMinConstrainVert() + sizeDiff.cy + 2*m_sizeRootBorders.cy); + + + int maxWidth = m_RootPane->getMaxConstrainHorz(); + int maxHeight = m_RootPane->getMaxConstrainVert(); + + if( maxWidth != -1 ) { + sizeMax.cx = maxWidth + sizeDiff.cy + 2*m_sizeRootBorders.cx; + } + + if( maxHeight != -1 ) { + sizeMax.cy = maxHeight + sizeDiff.cy + 2*m_sizeRootBorders.cy; + } + } + + if( IsFloating() || !(dwMode&LM_HORZ)) + { + sizeRet.cx = min( sizeRet.cx, sizeMax.cx ); + } + if( IsFloating() || (dwMode&LM_HORZ)) + { + sizeRet.cy = min( sizeRet.cy, sizeMax.cy ); + } + + sizeRet.cx = max( sizeRet.cx, sizeMin.cx ); + sizeRet.cy = max( sizeRet.cy, sizeMin.cy ); + + return sizeRet; +} + +BOOL ETSLayoutDialogBar::OnEraseBkgnd(CDC* pDC) +{ + EraseBkgnd(pDC); + return true; +} + + +void ETSLayoutDialogBar::OnSize(UINT nType, int cx, int cy) +{ + CBaseDialogBar::OnSize(nType, cx, cy); + + if( abs(cx) + abs(cy) > 0) + { + // Re-Layout all controls + UpdateLayout(); + } + RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); + +} + + +CRect ETSLayoutDialogBar::GetRect() +{ + CRect r; + GetClientRect(r); + + if( IsFloating() ) + r.DeflateRect(4,4); + + return r; +} + + +void ETSLayoutDialogBar::OnDestroy() +{ + // Store size/position on your own! + CBaseDialogBar::OnDestroy(); +} + + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutFormView dialog + +IMPLEMENT_DYNAMIC(ETSLayoutFormView, CFormView) + +#pragma warning(disable: 4355) +ETSLayoutFormView::ETSLayoutFormView(UINT nID, LPCTSTR strName /*=NULL*/) + : CBaseFormView(nID), ETSLayoutMgr( this ) +{ + if(strName) + m_strRegStore = strName; +} +#pragma warning(default: 4355) + +BEGIN_MESSAGE_MAP(ETSLayoutFormView, CBaseFormView) + //{{AFX_MSG_MAP(ETSLayoutFormView) + ON_WM_SIZE() + ON_WM_GETMINMAXINFO() + ON_WM_ERASEBKGND() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutFormView message handlers + +BOOL ETSLayoutFormView::OnEraseBkgnd(CDC* pDC) +{ + EraseBkgnd(pDC); + return true; +} + + +void ETSLayoutFormView::OnSize(UINT nType, int cx, int cy) +{ +// CBaseFormView::OnSize(nType, cx, cy); + SetScrollSizes(MM_TEXT, CSize(cx,cy)); + if( abs(cx) + abs(cy) > 0) { + // Re-Layout all controls + UpdateLayout(); + } +// MoveWindow(0,0,cx,cy); +} + +/* +void ETSLayoutFormView::UpdateLayout() +{ + ETSLayoutMgr::UpdateLayout(); + + if(m_RootPane.IsValid()) { + // Force MainFrame to re-layout + CFrameWnd* pFrame = static_cast(GetParent()); + if(pFrame) { + + CRect rcWnd; + pFrame->GetWindowRect(rcWnd); + pFrame->MoveWindow(rcWnd); + pFrame->RecalcLayout(); + + } + return; + } +} +*/ + +void ETSLayoutFormView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + // To use this you'll have to modify your CMainFrame: + // + // 1) Add a handler for WM_GETMINMAXINFO() + // 2) Let this handler be: + // void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) + // { + // CFrameWnd::OnGetMinMaxInfo(lpMMI); + // + // if( GetActiveView() && GetActiveView()->IsKindOf( RUNTIME_CLASS(ETSLayoutFormView) ) ) { + // GetActiveView()->SendMessage( WM_GETMINMAXINFO, 0, (LPARAM) lpMMI ); + // } + // } + // 3) Add "#include "dialogmgr.h" to MainFrm.cpp + + if(m_RootPane.IsValid()) { + CRect rcClient = GetRect(); + + CRect rcWnd; + GetParent()->GetWindowRect(rcWnd); + + // How much do Window and Client differ + rcWnd-=rcClient; + + // Take into account that there is a border around the rootPane + lpMMI->ptMinTrackSize = CPoint(m_RootPane->getMinConstrainHorz() + rcWnd.Width() + 2*m_sizeRootBorders.cx, + m_RootPane->getMinConstrainVert() + rcWnd.Height() + 2*m_sizeRootBorders.cy); + + int maxWidth = m_RootPane->getMaxConstrainHorz(); + int maxHeight = m_RootPane->getMaxConstrainVert(); + + if( maxWidth != -1 ) { + lpMMI->ptMaxTrackSize.x = maxWidth + rcWnd.Width()+ 2*m_sizeRootBorders.cx; + lpMMI->ptMaxSize.x = maxWidth + rcWnd.Width()+ 2*m_sizeRootBorders.cx; + } + + if( maxHeight != -1 ) { + lpMMI->ptMaxTrackSize.y = maxHeight + rcWnd.Height() + 2*m_sizeRootBorders.cy; + lpMMI->ptMaxSize.y = maxHeight + rcWnd.Height() + 2*m_sizeRootBorders.cy; + } + } +} + +ETSLayoutFormView::~ETSLayoutFormView() +{ + // Cleanup +} + + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutPropertyPage + +#ifdef CS_HELP + IMPLEMENT_DYNCREATE(ETSLayoutPropertyPage, ETSCSHelpPropPage) +#else + IMPLEMENT_DYNCREATE(ETSLayoutPropertyPage, CPropertyPage) +#endif + +#pragma warning(disable: 4355) +ETSLayoutPropertyPage::ETSLayoutPropertyPage( ) : ETSLayoutMgr( this ) +{ + m_bLockMove = false; + m_bResetBuddyOnNextTimeVisible = true; +} + +ETSLayoutPropertyPage::ETSLayoutPropertyPage( UINT nIDTemplate, UINT nIDCaption /*= 0*/ ) + : CBasePropertyPage(nIDTemplate, nIDCaption), ETSLayoutMgr( this ) +{ + m_bLockMove = false; + m_bResetBuddyOnNextTimeVisible = true; +} + +ETSLayoutPropertyPage::ETSLayoutPropertyPage( LPCTSTR lpszTemplateName, UINT nIDCaption /*= 0*/ ) + : CBasePropertyPage(lpszTemplateName, nIDCaption), ETSLayoutMgr( this ) +{ + m_bLockMove = false; + m_bResetBuddyOnNextTimeVisible = true; +} +#pragma warning(default: 4355) + +ETSLayoutPropertyPage::~ETSLayoutPropertyPage() +{ +} + + +BEGIN_MESSAGE_MAP(ETSLayoutPropertyPage, CBasePropertyPage) + //{{AFX_MSG_MAP(ETSLayoutPropertyPage) + ON_WM_SIZE() + ON_WM_GETMINMAXINFO() + ON_WM_ERASEBKGND() + ON_WM_WINDOWPOSCHANGING() + ON_WM_DESTROY() + ON_WM_WINDOWPOSCHANGED() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fr Nachrichten ETSLayoutPropertyPage + + + +void ETSLayoutPropertyPage::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) +{ + CBasePropertyPage::OnWindowPosChanged(lpwndpos); + + // This code is needed in order to reset the buddy after this page has + // been activated. At least on Win2k this is not done thru normal resizing, + // as the page is not visible when first layouted. And without the page + // being visible it's not possible to tell if the attached buddy is visible + // or not (at least I don't know any way to do so) + + if( ::IsWindowVisible( GetWnd()->GetSafeHwnd() ) ) + { + if( m_bResetBuddyOnNextTimeVisible ) + { + // Take special care of SpinButtons (Up-Down Controls) with Buddy set, enumerate + // all childs: + CWnd* pWndChild = GetWnd()->GetWindow(GW_CHILD); + TCHAR szClassName[ MAX_PATH ]; + while(pWndChild) + { + ::GetClassName( pWndChild->GetSafeHwnd(), szClassName, MAX_PATH ); + DWORD dwStyle = pWndChild->GetStyle(); + + // is it a SpinButton? + if( _tcscmp(szClassName, UPDOWN_CLASS)==0 && ::IsWindowVisible(pWndChild->GetSafeHwnd()) ) { + HWND hwndBuddy = (HWND)::SendMessage( pWndChild->GetSafeHwnd(), UDM_GETBUDDY, 0, 0); + if( hwndBuddy != 0 && (dwStyle&(UDS_ALIGNRIGHT|UDS_ALIGNLEFT)) != 0 ) + { + // reset Buddy + ::SendMessage( pWndChild->GetSafeHwnd(), UDM_SETBUDDY, (WPARAM)hwndBuddy, 0); + } + } + + + pWndChild = pWndChild->GetWindow(GW_HWNDNEXT); + } + + m_bResetBuddyOnNextTimeVisible = false; + } + } + else + { + // has been hidden again + m_bResetBuddyOnNextTimeVisible = true; + } +} + +void ETSLayoutPropertyPage::OnWindowPosChanging( WINDOWPOS* lpwndpos ) +{ + // In WizardMode the System calls SetWindowPos with the + // original size at every activation. This could cause + // some flicker in certain circumstances. Therefore we lock + // moving the page and unlock it only if _we_ move the page + if( m_bLockMove) + { + lpwndpos->flags |= SWP_NOMOVE | SWP_NOSIZE; + } + CBasePropertyPage::OnWindowPosChanging( lpwndpos ); +} + +BOOL ETSLayoutPropertyPage::OnEraseBkgnd(CDC* pDC) +{ + EraseBkgnd(pDC); + return true; +} + +void ETSLayoutPropertyPage::OnDestroy() +{ + // manually delete layout definition if object is reused + m_RootPane = 0; + + CBasePropertyPage::OnDestroy(); +} + +void ETSLayoutPropertyPage::OnSize(UINT nType, int cx, int cy) +{ + CBasePropertyPage::OnSize(nType, cx, cy); + + if( abs(cx) + abs(cy) > 0) + { + // Re-Layout all controls + UpdateLayout(); + } +} + +void ETSLayoutPropertyPage::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + if(m_RootPane.IsValid()) { + CRect rcClient = GetRect(); + + CRect rcWnd; + GetWindowRect(rcWnd); + + // How much do Window and Client differ + int nDiffHorz = rcWnd.Width() - rcClient.Width(); + int nDiffVert = rcWnd.Height() - rcClient.Height(); + + // Take into account that there is a border around the rootPane + lpMMI->ptMinTrackSize = CPoint(m_RootPane->getMinConstrainHorz() + nDiffHorz + 2*m_sizeRootBorders.cx, + m_RootPane->getMinConstrainVert() + nDiffVert + 2*m_sizeRootBorders.cy); + + int maxWidth = m_RootPane->getMaxConstrainHorz(); + int maxHeight = m_RootPane->getMaxConstrainVert(); + + if( maxWidth != -1 ) { + lpMMI->ptMaxTrackSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; + lpMMI->ptMaxSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; + } + + if( maxHeight != -1 ) { + lpMMI->ptMaxTrackSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; + lpMMI->ptMaxSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; + } + } +} + + +CRect ETSLayoutPropertyPage::GetRect() +{ + CRect r; + GetClientRect(r); + return r; +} + + +BOOL ETSLayoutPropertyPage::OnInitDialog() +{ + CBasePropertyPage::OnInitDialog(); + UpdateLayout(); + + ETSLayoutPropertySheet* pSheet = (ETSLayoutPropertySheet*) GetParent(); + + ASSERT_KINDOF( ETSLayoutPropertySheet, pSheet); + if(pSheet) + { + if(pSheet->IsWizard()) + { + m_bLockMove = true; + } + } + + return TRUE; +} + +BOOL ETSLayoutPropertyPage::OnSetActive() +{ + ETSLayoutPropertySheet* pSheet = (ETSLayoutPropertySheet*) GetParent(); + + ASSERT_KINDOF( ETSLayoutPropertySheet, pSheet); + if(pSheet) + { + if(pSheet->IsWizard()) + { + // In WizardMode the System calls SetWindowPos with the + // original size on Page Activation. This will position the + // page at the correct position + m_bLockMove = false; + MoveWindow(pSheet->m_rcPage); + m_bLockMove = true; + } + } + + UpdateLayout(); + + return CBasePropertyPage::OnSetActive(); +} + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutPropertySheet + +IMPLEMENT_DYNAMIC(ETSLayoutPropertySheet, CPropertySheet) + +#pragma warning(disable: 4355) +ETSLayoutPropertySheet::ETSLayoutPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage, + LPCTSTR strName /*=NULL*/, bool bGripper/*=true*/) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage), ETSLayoutMgr( this ) +{ + Init(strName, bGripper); +} + +ETSLayoutPropertySheet::ETSLayoutPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage, + LPCTSTR strName /*=NULL*/, bool bGripper/*=true*/) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage), ETSLayoutMgr( this ) +{ + Init(strName, bGripper); +} +#pragma warning(default: 4355) + +void ETSLayoutPropertySheet::Init(LPCTSTR strName, bool bGripper) +{ + m_bGripper = bGripper; + if(strName) + m_strRegStore = strName; + + m_bAutoDestroy = false; + m_bAutoDestroyPages = false; + m_bModelessButtons = false; +} + +ETSLayoutPropertySheet::~ETSLayoutPropertySheet() +{ +} + + +BEGIN_MESSAGE_MAP(ETSLayoutPropertySheet, CPropertySheet) + //{{AFX_MSG_MAP(ETSLayoutPropertySheet) + ON_WM_CREATE() + ON_WM_SIZE() + ON_WM_GETMINMAXINFO() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// Behandlungsroutinen fr Nachrichten ETSLayoutPropertySheet + +BOOL ETSLayoutPropertySheet::OnEraseBkgnd(CDC* pDC) +{ + EraseBkgnd(pDC); + return true; +} + + +int ETSLayoutPropertySheet::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CPropertySheet::OnCreate(lpCreateStruct) == -1) + return -1; + + ModifyStyle(0,WS_THICKFRAME| WS_SYSMENU); + return 0; +} + + +void ETSLayoutPropertySheet::Resize(int cx, int cy) +{ + if( abs(cx) + abs(cy) > 0 && m_RootPane.IsValid() ) + { + UpdateLayout(); + + // Fix for PSH_WIZARDHASFINISH [Thmmi] + if (IsWizard() && !(m_psh.dwFlags & PSH_WIZARDHASFINISH) ) + { + // manual reposition of the FINISH button + // can not be done with normaly layouting because it + // shares position with the NEXT button + CWnd *pWndFinish; + pWndFinish=GetDlgItem(ID_WIZFINISH); + + if(pWndFinish) + { + CRect rcWnd; + GetDlgItem(ID_WIZNEXT)->GetWindowRect(&rcWnd); + ScreenToClient(&rcWnd); + pWndFinish->MoveWindow(rcWnd); + pWndFinish->RedrawWindow(0,0, RDW_INVALIDATE | RDW_UPDATENOW ); + } + } + + // reposition Gripper + if(m_bGripper) + RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); + + CPropertyPage* pPage = (CPropertyPage*)GetActivePage(); + + if(pPage) + { + CRect rcWnd; + GetTabControl()->GetWindowRect(&rcWnd); + ScreenToClient(&rcWnd); + + if(!IsWizard()) { + // get inside of tab + GetTabControl()->AdjustRect(FALSE, &rcWnd); + } + else + { + rcWnd.bottom += 5; + } + + // we need this size in WizardMode in order to + // reposition newly activated page correctly + m_rcPage = rcWnd; + + if( IsWizard() && pPage->IsKindOf(RUNTIME_CLASS(ETSLayoutPropertyPage)) ) + { + ETSLayoutPropertyPage* pEtsPage = reinterpret_cast(pPage); + + pEtsPage->m_bLockMove = false; + pEtsPage->MoveWindow(m_rcPage); + pEtsPage->m_bLockMove = true; + } + else + { + pPage->MoveWindow(m_rcPage); + } + + } + + if(IsWindowVisible()) + { + RedrawWindow(0,0, RDW_INVALIDATE|RDW_UPDATENOW ); + + if(!IsWizard()) + GetTabControl()->RedrawWindow(0,0, RDW_INVALIDATE|RDW_UPDATENOW ); + } + } +} + +void ETSLayoutPropertySheet::OnSize(UINT nType, int cx, int cy) +{ + CPropertySheet::OnSize(nType, cx, cy); + Resize(cx,cy); +} + +// IDs of all PropertySheet controls +long _PropertySheetIDs[] = +{ + ID_WIZBACK, + ID_WIZNEXT, + ID_WIZFINISH, + IDOK, + IDCANCEL, + ID_APPLY_NOW, + IDHELP +}; + +void ETSLayoutPropertySheet::AddMainArea(CPane paneRoot, CPaneBase itemTab) +{ + // the default is: Whole main Area is covered by the TabCtrl + paneRoot << itemTab; +} + +void ETSLayoutPropertySheet::AddButtons(CPane paneBottom) +{ + // first item greedy to keep others right + paneBottom->addItem (paneNull, GREEDY); + + + // add all Controls to the layouting + bool bFirst = true; + for(int i = 0; i < (sizeof(_PropertySheetIDs) / sizeof(long)) ; i++) + { + // Prevent movement of finish button, if it is not shown explicitly [Thmmi] + if( IsWizard() + && _PropertySheetIDs[i] == ID_WIZFINISH + && !(m_psh.dwFlags & PSH_WIZARDHASFINISH) ) + { + continue; + } + + CWnd* pWnd = GetDlgItem(_PropertySheetIDs[i]); + + if(pWnd) + { + + if(!(m_psh.dwFlags & PSH_HASHELP) && _PropertySheetIDs[i] == IDHELP) + { + // don't insert + continue; + } + + if((m_psh.dwFlags & PSH_NOAPPLYNOW) && _PropertySheetIDs[i] == ID_APPLY_NOW) + { + // don't insert + continue; + } + + // space before first one and between BACK & NEXT + if( IsWizard() ) + { + if( !bFirst && !(_PropertySheetIDs[i]==ID_WIZNEXT) ) + { + paneBottom->addItem(paneNull, NORESIZE,12,0,0,0); + } + } + + pWnd->ShowWindow(true); + paneBottom->addItem(_PropertySheetIDs[i], NORESIZE); + bFirst = false; + } + } + +} + +BOOL ETSLayoutPropertySheet::OnInitDialog() +{ + BOOL bRet = CPropertySheet::OnInitDialog(); + + ASSERT(!m_RootPane); + + // Save initial rect + GetWindowRect(&m_rcStart); + + CPropertyPage* pPage = CPropertySheet::GetActivePage(); + ASSERT(pPage); + + CRect rcPage; + pPage->GetClientRect(&rcPage); + + CreateRoot(VERTICAL); + ASSERT(m_RootPane.IsValid()); + + // Add Tabcontrol to root pane + m_ItemTab = item( GetTabControl(), GREEDY, 0, 0, 0, 0); + AddMainArea(m_RootPane, m_ItemTab); + + // Tabcontrol is invisible in WizardMode + if(IsWizard()) + { + GetTabControl()->ShowWindow(false); + } + + // add horizontal line in WizardMode + if(IsWizard() && GetDlgItem(ID_WIZFINISH+1)) + { + m_RootPane << item(ID_WIZFINISH+1, ABSOLUTE_VERT, 0, 0, 0, 0); + } + + if( IsWizard() || !m_bModeless || m_bModelessButtons ) + { + // No spaces in WizardMode in order to keep BACK & NEXT together + CPane bottomPane = pane(HORIZONTAL, ABSOLUTE_VERT, IsWizard() ? 0 : 5); + + AddButtons(bottomPane); + // add bottom (button) pane if any controls were added + if(bottomPane->m_paneItems.GetSize() > 0) { + m_RootPane << bottomPane; + } + } + + + + // some Space between Buttons und Gripper + if(m_bGripper) + { + m_RootPane->addItem(paneNull, ABSOLUTE_VERT,0,2); + + if(m_StatusBar.Create(m_pWnd)) + { + m_StatusBar.SetIndicators(auIDStatusBar, + sizeof(auIDStatusBar) / sizeof(UINT)); + m_StatusBar.SetWindowText(_T("")); + RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); + } + else + { + AfxMessageBox(_T("Error - Statusbar")); + } + } + + if(!m_strRegStore.IsEmpty()) + { + Load(m_strRegStore); + } + + Resize(1,1); // Fix. for 95/98/NT difference + + CRect rcWnd; + GetWindowRect( & rcWnd ); + MoveWindow( rcWnd ); + + return bRet; +} + + +void ETSLayoutPropertySheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + if(m_RootPane.IsValid() && GetTabControl() != 0 ) + { + CRect rcWnd; + GetWindowRect(rcWnd); + + CRect rcClient = GetRect(); + rcWnd-=rcClient; + + // ask for MinMax of all pages + CSize sizePageMax(0,0); + CSize sizePageMin(0,0); + for( int nPage=0; nPageGetSafeHwnd()) ) + { + pPage->SendMessage(WM_GETMINMAXINFO, 0, (LPARAM) &mmi); + + if(mmi.ptMaxTrackSize.x != 0) + { + sizePageMax.cx = min(sizePageMax.cx, mmi.ptMaxTrackSize.x); + } + if(mmi.ptMaxTrackSize.y != 0) + { + sizePageMax.cy = min(sizePageMax.cy, mmi.ptMaxTrackSize.y); + } + if(mmi.ptMinTrackSize.x != 0) + { + sizePageMin.cx = max(sizePageMin.cx, mmi.ptMinTrackSize.x); + } + if(mmi.ptMinTrackSize.y != 0) + { + sizePageMin.cy = max(sizePageMin.cy, mmi.ptMinTrackSize.y); + } + } + } + } + static_cast( m_ItemTab.GetPaneBase() )->m_sizeXMin = sizePageMin.cx; + static_cast( m_ItemTab.GetPaneBase() )->m_sizeYMin = sizePageMin.cy; + + // calculate the needed size of the tabctrl in non-wizard-mode + CRect rcItem(0,0,0,0); + if(!IsWizard()) + { + GetTabControl()->AdjustRect( TRUE, rcItem ); + } + + lpMMI->ptMinTrackSize.x = m_RootPane->getMinConstrainHorz() + rcWnd.Width() + 2*m_sizeRootBorders.cx + + rcItem.Width(); + + lpMMI->ptMinTrackSize.y = m_RootPane->getMinConstrainVert() + rcWnd.Height() + 2*m_sizeRootBorders.cy + + rcItem.Height(); + + // never smaller than inital size! + lpMMI->ptMinTrackSize.x = max(lpMMI->ptMinTrackSize.x, m_rcStart.Width() ); + lpMMI->ptMinTrackSize.y = max(lpMMI->ptMinTrackSize.y, m_rcStart.Height() ); + + // Rest like ETSLayoutMgr + + int maxWidth = m_RootPane->getMaxConstrainHorz(); + int maxHeight = m_RootPane->getMaxConstrainVert(); + + if( maxWidth != -1 ) + { + lpMMI->ptMaxSize.x = sizePageMax.cx + rcWnd.Width()+ 2*m_sizeRootBorders.cx + rcItem.Width() ; + } + + if( maxHeight != -1 ) + { + lpMMI->ptMaxSize.y = sizePageMax.cy + rcWnd.Height() + 2*m_sizeRootBorders.cy + rcItem.Width() ; + } + + lpMMI->ptMaxTrackSize = lpMMI->ptMaxSize; + + } +} + + +void ETSLayoutPropertySheet::OnDestroy() +{ + // Store size/position + if(!m_strRegStore.IsEmpty()) + { + Save(m_strRegStore); + } + m_RootPane = 0; + + CPropertySheet::OnDestroy(); +} + +void ETSLayoutPropertySheet::PostNcDestroy() +{ + if(m_bAutoDestroyPages) + { + // walk all pages and destry them + for( int nPage=0; nPageRelease(); +} + +void ETSLayoutMgr::CPaneBase::operator=( PaneBase* pPane ) +{ + if(m_pPaneHolder) + { + m_pPaneHolder->Release(); + m_pPaneHolder = 0; + } + + if( pPane != 0 ) + m_pPaneHolder = new PaneHolder( pPane ); +} + +void ETSLayoutMgr::CPaneBase::operator=( const CPaneBase& other ) +{ + ASSERT( other.m_pPaneHolder ); + + if(m_pPaneHolder) + { + m_pPaneHolder->Release(); + m_pPaneHolder = 0; + } + + other.m_pPaneHolder->AddRef(); + m_pPaneHolder = other.m_pPaneHolder; +} + +ETSLayoutMgr::PaneBase* ETSLayoutMgr::CPaneBase::operator->() const +{ + ASSERT(m_pPaneHolder); + + if(!m_pPaneHolder) + return 0; + + return (m_pPaneHolder->m_pPane); +} + + + +ETSLayoutMgr::CPane::CPane( ) +{ +} + +ETSLayoutMgr::CPane::CPane( Pane* pPane ) : ETSLayoutMgr::CPaneBase( static_cast(pPane) ) +{ +} + +ETSLayoutMgr::CPane::CPane( const CPane& other ) +{ + operator=(other); +} + +ETSLayoutMgr::CPane::~CPane() +{ +} + +void ETSLayoutMgr::CPane::operator=( Pane* pPane ) +{ + CPaneBase::operator=(pPane); +} + +void ETSLayoutMgr::CPane::operator=( const ETSLayoutMgr::CPane& other ) +{ + ASSERT( other.m_pPaneHolder ); + + if(m_pPaneHolder) + { + m_pPaneHolder->Release(); + m_pPaneHolder = 0; + } + + other.m_pPaneHolder->AddRef(); + m_pPaneHolder = other.m_pPaneHolder; +} + +ETSLayoutMgr::Pane* ETSLayoutMgr::CPane::operator->() const +{ + ASSERT(m_pPaneHolder); + + if(!m_pPaneHolder) + return 0; + + return reinterpret_cast(m_pPaneHolder->m_pPane); +} + +ETSLayoutMgr::CPaneBase ETSLayoutMgr::CPane::ConvertBase() const +{ + ASSERT(m_pPaneHolder); + return CPaneBase( m_pPaneHolder->m_pPane ); +} + +ETSLayoutMgr::CPane& ETSLayoutMgr::CPane::operator<< ( const ETSLayoutMgr::CPane pPane ) +{ + GetPane()->addPane( pPane, (ETSLayoutMgr::layResizeMode)pPane->m_modeResize, pPane->m_sizeSecondary); + return (*this); +} + +ETSLayoutMgr::CPane& ETSLayoutMgr::CPane::operator<< ( const ETSLayoutMgr::CPaneBase pItem ) +{ + GetPane()->addPane( pItem ); + return (*this); +} diff --git a/install/xbt/linux/misc/windows/ETSLayout.h b/install/xbt/linux/misc/windows/ETSLayout.h new file mode 100644 index 000000000..43d912fcc --- /dev/null +++ b/install/xbt/linux/misc/windows/ETSLayout.h @@ -0,0 +1,964 @@ +//////////////////////////////////////////// +// ___ ____ _________________ // +// / _/_ _// _______________/ // +// / _/ / / / / ___ ___ ____ // +// /__/ /_/ / / / // _/_ _/ // +// _________/ / / / // _/ / / // +// (c) 1998-2000_/ /___//_/ /_/ // +// // +//////////////////////////////////////////// +// all rights reserved // +//////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// ETSLayoutDialog +// +// A class for smart layouting of Dialogs and such +// +// USAGE: See LayoutMgr.html +// +// AUTHOR: Erwin Tratar +// +// DISCLAIMER: +// +// This Sourcecode and all accompaning material is 1998-1999 Erwin Tratar. +// All rights reserved. +// +// The source code may be used in compiled form in any way you desire +// (including usage in commercial applications), providing that your +// application adds essential code (i.e. it is not only a wrapper) to the +// functionality found here +// +// Redistribution of the sourcecode itself, publication in any media or +// inclusion in a library requires the authors expressed written consent. +// You may not sale this code for profit. +// +// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. USE IT +// AT YOUR OWN RISK! THE AUTHOR ACCEPTS NO LIABILITY FOR ANY DAMAGE/LOSS OF +// BUSINESS THAT THIS PRODUCT MAY CAUSE. + + +#if !defined(ETS_LAYOUTMGR_INCLUDED_) +#define ETS_LAYOUTMGR_INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// DialogMgr.h : header file +// + +namespace ETSLayout +{ + +#ifdef CS_HELP + typedef ETSCSHelpDialog CBaseDialog; + typedef ETSCSHelpFormView CBaseFormView; + typedef ETSCSHelpDlgBar CBaseDialogBar; + typedef ETSCSHelpPropPage CBasePropertyPage; +#else + typedef CDialog CBaseDialog; + typedef CFormView CBaseFormView; + typedef CDialogBar CBaseDialogBar; + typedef CPropertyPage CBasePropertyPage; +#endif +} + +// Support for CBCGDialogBar instead of CDialogBar available: +// you just have to change the typedef to CBaseDialogBar + +#ifndef ETSGUI_EXT_CLASS +#define ETSGUI_EXT_CLASS +#endif + +#include + +// Support for CBCGDialogBar instead of CDialogBar + +/** + * Controls whether the Icon is automatically set to IDR_MAINFRAME + */ +#define _AUTO_SET_ICON + +/** + * Forward class declarations + */ +class ETSLayoutDialog; +class ETSLayoutDialogBar; +class ETSLayoutFormView; +class ETSLayoutMgr; +class ETSLayoutPropertyPage; +class ETSLayoutPropertySheet; + + +/** + * These are NOOPs now + */ +#define DECLARE_LAYOUT() +#define IMPLEMENT_LAYOUT() + +/** + * This is the default border size between the panes. You + * may override it in Pane constructor, but it is the + * fixed border around the root pane + */ +const int nDefaultBorder = 5; + +/** + * The minimum size for not ABSOLUTE_XXX items + */ +const int nMinConstrain = 5; + +class ETSGUI_EXT_CLASS ETSLayoutMgr +{ +public: + + enum layResizeMode { + GREEDY = 0, // Will eat up as much as it can + ABSOLUTE_HORZ = 1 << 0, // Horizontal size is absolute + RELATIVE_HORZ = 1 << 1, // Horizontal size in percent + ABSOLUTE_VERT = 1 << 2, // Vertical size is absolute + RELATIVE_VERT = 1 << 3, // Vertical size in percent + + NORESIZE = ABSOLUTE_HORZ | ABSOLUTE_VERT, + + SIZE_MASK = NORESIZE, + + ALIGN_LEFT = 1 << 4, // following only for NORESIZE + ALIGN_RIGHT = 1 << 5, + ALIGN_TOP = 1 << 6, + ALIGN_BOTTOM = 1 << 7, + + ALIGN_HCENTER = ALIGN_LEFT | ALIGN_RIGHT, + ALIGN_VCENTER = ALIGN_TOP | ALIGN_BOTTOM, + + ALIGN_CENTER = ALIGN_HCENTER | ALIGN_VCENTER, + + ALIGN_FILL_HORZ = 1 << 8, + ALIGN_FILL_VERT = 1 << 9, + ALIGN_FILL = ALIGN_FILL_HORZ | ALIGN_FILL_VERT, + +/* TRACKER_LEFT = 1 << 10, // not yet. May allow tracking of borders + TRACKER_RIGHT = 1 << 11, // between items in the future + TRACKER_TOP = 1 << 12, + TRACKER_BOTTOM = 1 << 13, +*/ + }; + + enum layOrientation { + HORIZONTAL, + VERTICAL + }; + + /** + * This is the base class for all kind of panes. + */ + class ETSGUI_EXT_CLASS PaneBase { + friend class ETSLayoutMgr; + friend class CPaneBase; + friend class CPane; + + public: + + /** + * Informs the caller how much of the given space this pane would + * like to receive in horizontal direction + */ + virtual int getConstrainHorz(int sizeParent) = 0; + + + /** + * Informs the caller how much of the given space this pane would + * like to receive in vertical direction + */ + virtual int getConstrainVert(int sizeParent) = 0; + + /** + * Informs the caller how much of the given space this pane + * minimally need. This would be an absolute Value if + * the mode contains ABSOLUTE_HORZ or an explicit minimum + * value, else nMinConstrain + */ + virtual int getMinConstrainHorz() = 0; + /** + * Informs the caller if there is an restriction for maximum + * space this pane needs. Return -1 for unrestricted (GREEDY + * or RELATIVE) + */ + virtual int getMaxConstrainHorz() = 0; + + /** + * Informs the caller how much of the given space this pane + * minimally need. This would be an absolute Value if + * the mode contains ABSOLUTE_VERT or an explicit minimum + * value, else nMinConstrain + */ + virtual int getMinConstrainVert() = 0; + + /** + * Informs the caller if there is an restriction for maximum + * space this pane needs. Return -1 for unrestricted (GREEDY + * or RELATIVE) + */ + virtual int getMaxConstrainVert() = 0; + + /** + * This will do the actual resize operation after the + * caller computed a new area for this pane + */ + virtual bool resizeTo(CRect& rcNewArea) = 0; + + /** + * Constructor needed pointer to LayoutManager + */ + PaneBase( ETSLayoutMgr* pMgr ) { m_pMgr = pMgr; }; + + /** + * Virtual destructor needed in Container operations + */ + virtual ~PaneBase() {}; + + /** + * Returs the Resize Mode of this pane + */ + DWORD modeResize() { return m_modeResize; }; + + protected: + /** + * How this Item will be resized, a combination of the flags above + */ + DWORD m_modeResize; + + /** + * A pointer to the holding LayoutManager derivate + */ + ETSLayoutMgr* m_pMgr; + }; + + /** + * CPaneBase represents an autopointer to a PaneBase. Use this and you won't have to worry + * about cleaning up any Panes. Also this autopointer lets you return Pane objects + * from function without using pointers (at least you won't see them :) ) + */ + struct ETSGUI_EXT_CLASS PaneHolder + { + PaneHolder(PaneBase* pPane ); + ~PaneHolder(); + + void AddRef(); + void Release(); + + PaneBase* m_pPane; + long m_nRefCount; + }; + + class ETSGUI_EXT_CLASS CPaneBase + { + protected: + PaneHolder* m_pPaneHolder; + + public: + // Standardconstructor + CPaneBase( ); + CPaneBase( PaneBase* pPane ); + CPaneBase( const CPaneBase& other ); + + ~CPaneBase(); + + void operator=( PaneBase* pPane ); + void operator=( const CPaneBase& other ); + PaneBase* operator->() const; + PaneBase* GetPaneBase() { return operator->(); } + + bool IsValid() { return (m_pPaneHolder != 0); } + bool operator !() { return (m_pPaneHolder == 0); } + + }; + + class Pane; + class ETSGUI_EXT_CLASS CPane : public CPaneBase + { + public: + // Standardconstructor + CPane( ); + CPane( Pane* pPane ); + CPane( const CPane& other ); + + ~CPane(); + + void operator=( Pane* pPane ); + void operator=( const CPane& other ); + Pane* operator->() const; + Pane* GetPane() { return operator->(); } + + CPaneBase ConvertBase() const; + + CPane& operator<< ( const CPane pPane ); + CPane& operator<< ( const CPaneBase pItem ); + }; + + + + /** + * PaneItem represents a single control + */ + class ETSGUI_EXT_CLASS PaneItem : public PaneBase { + friend class ETSLayoutMgr; + friend class Pane; + protected: + /** + * Creates a new PaneItem from an Control. If sizeX or sizeY are 0 + * and modeResize is ABSOLUTE will copy the current dimensions of + * the control to m_sizeX/Y. So the appearance does not change + * from the Dialog Editor + */ + PaneItem( CWnd* pWnd, ETSLayoutMgr* pMgr, layResizeMode modeResize = GREEDY, int sizeX=0, int sizeY=0, int sizeXMin=0, int sizeYMin=0); + + /** + * If your control is not mapped you can name it by its ChildID. Pass + * the pMgr to receive the CWnd* of nID. + * The rest as stated above + */ + PaneItem( UINT nID, ETSLayoutMgr* pMgr, layResizeMode modeResize = GREEDY, int sizeX=0, int sizeY=0, int sizeXMin=0, int sizeYMin=0); + + + public: + /** + * see PaneBase + */ + virtual int getConstrainHorz(int sizeParent); + virtual int getConstrainVert(int sizeParent); + virtual int getMinConstrainHorz(); + virtual int getMinConstrainVert(); + virtual int getMaxConstrainHorz(); + virtual int getMaxConstrainVert(); + virtual bool resizeTo(CRect& rcNewArea); + + bool isDummy() { return (m_hwndCtrl == 0); } + + protected: + friend class ETSLayoutPropertySheet; + + /** + * The horizontal size of the control (see m_modeResize) + */ + int m_sizeX; + int m_sizeXMin; + + /** + * The vertical size of the control (see m_modeResize) + */ + int m_sizeY; + int m_sizeYMin; + + /** + * Child Control pointer + */ + HWND m_hwndCtrl; + + /** + * Combo box needs special treatment + */ + bool m_bComboSpecial; + }; + + + /** + * This class encapsulates a Subpane (and indeed the root Pane too) + * it is a container of PaneBase* which it will recursivly resize + */ + class ETSGUI_EXT_CLASS Pane : public PaneBase { + friend class ETSLayoutMgr; + friend class CPaneBase; + friend class CPane; + friend class ETSLayoutPropertySheet; + + protected: + /** + * Tell the pane in which direction it is positioned. A HORIZONTAL pane + * arranges it's subpanes from left to right, a VERTICAL from top to bottom + */ + Pane( ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0 ); + + public: + /** + * If your control is not mapped you can name it by its ChildID. Pass + * the pMgr to receive the CWnd* of nID. + * The rest as stated above + */ + bool addItem( UINT nID, layResizeMode modeResize = GREEDY, int sizeX=0, int sizeY=0, int sizeXMin=-1, int sizeYMin=-1); + + /** + * Creates a new PaneItem from an Control. If sizeX or sizeY are 0 + * and modeResize is ABSOLUTE will copy the current dimensions of + * the control to m_sizeX/Y. So the appearance does not change + * from the Dialog Editor + */ + bool addItem( CWnd* pWnd, layResizeMode modeResize = GREEDY, int sizeX=0, int sizeY=0, int sizeXMin=-1, int sizeYMin=-1); + + + /** + * Add a whitespace Item (paneNull) of variable size with + * a minimum size of 0 + */ + bool addItemGrowing(); + + /** + * Add a whitespace Item (paneNull) with fixed size + */ + bool addItemFixed(int size); + + /** + * Add a whitespace Item (paneNull) of fixed size based on the + * current layout (as in the dialog template). Based on the layout + * of the pane vertical or horizontal spacing is considered + * + * First argument is the left (top) item for a HORIZONTAL (VERTICAL) pane + */ + bool addItemSpaceBetween( CWnd* pWndFirst, CWnd* pWndSecond ); + bool addItemSpaceBetween( UINT nIDFirst, UINT nIDSecond ); + + + /** + * Add a whitespace Item (paneNull) of fixed size based on the + * size of another item + */ + bool addItemSpaceLike( CWnd* pWnd ); + bool addItemSpaceLike( UINT nID ); + + + /** + * Add an item to the pane, appending at the end. This may be either obtained + * by a call to ETSLayoutMgr::item() or one of the ETSLayoutMgr::paneXXX() calls + */ + bool addPane( CPaneBase pItem ); + bool addPane( CPane pSubpane, layResizeMode modeResize, int sizeSecondary /* = 0 */); + + virtual int getConstrainHorz(int sizeParent); + virtual int getConstrainVert(int sizeParent); + virtual int getMinConstrainHorz(); + virtual int getMinConstrainVert(); + virtual int getMaxConstrainHorz(); + virtual int getMaxConstrainVert(); + virtual bool resizeTo(CRect& rcNewArea); + + /** + * The destructor takes care of destroying all Subpanes and items + */ + virtual ~Pane(); + + /** + * Access to the orientation of this pane + */ + layOrientation getOrientation() { return m_Orientation; }; + + + protected: + + int resizeToAbsolute(int& availSpace, CArray& sizePrimary, + CArray& sizeMin, CArray& sizeMax); + + bool resizeToRelative(int& availSpace, CArray& sizePrimary, + CArray& sizeMin, CArray& sizeMax); + + bool resizeToGreedy( int& availSpace, int nGreedy, CArray& sizePrimary, + CArray& sizeMin, CArray& sizeMax); + + /** + * The orientation of the pane. Keep in mind that all subpanes + * must have the complementary orientation, i.e. a VERTICAL + * pane must have all HORIZONTAL SubPanes (or normal Items + * of course) + */ + layOrientation m_Orientation; + + /** + * This array holds the pointers to the Items/SubPanes + */ + CArray m_paneItems; + + /** + * The secondary constrain + */ + int m_sizeSecondary; + + /** + * Size of gap between childs + */ + int m_sizeBorder; + int m_sizeExtraBorder; + }; + + + /** + * This class encapsulates a Subpane which is a Tab + * it will use calls to AdjustRect to position it's + * childs + */ + class ETSGUI_EXT_CLASS PaneTab : public Pane + { + friend class ETSLayoutMgr; + + protected: + /** + * Tell the pane in which direction it is positioned. A HORIZONTAL pane + * arranges it's subpanes from left to right, a VERTICAL from top to bottom + */ + PaneTab( CTabCtrl* pTab, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0 ); + + public: + virtual int getConstrainHorz(int sizeParent); + virtual int getConstrainVert(int sizeParent); + virtual int getMinConstrainHorz(); + virtual int getMinConstrainVert(); + virtual int getMaxConstrainHorz(); + virtual int getMaxConstrainVert(); + virtual bool resizeTo(CRect& rcNewArea); + + private: + CTabCtrl* m_pTab; + }; + + /** + * This class encapsulates a Subpane which is a Static + * it will use calls to AdjustRect to position it's + * childs + */ + class ETSGUI_EXT_CLASS PaneCtrl : public Pane + { + friend class ETSLayoutMgr; + protected: + /** + * Tell the pane in which direction it is positioned. A HORIZONTAL pane + * arranges it's subpanes from left to right, a VERTICAL from top to bottom + */ + PaneCtrl( CWnd* pCtrl, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0, int sizeTopExtra = 0); + PaneCtrl( UINT nID, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0, int sizeTopExtra = 0 ); + + public: + + virtual int getConstrainHorz(int sizeParent); + virtual int getConstrainVert(int sizeParent); + virtual int getMinConstrainHorz(); + virtual int getMinConstrainVert(); + virtual int getMaxConstrainHorz(); + virtual int getMaxConstrainVert(); + virtual bool resizeTo(CRect& rcNewArea); + + private: + HWND m_hwndCtrl; + int m_sizeTopExtra; + }; + + + + + ETSLayoutMgr(CWnd* pWnd) { m_pWnd = pWnd; m_sizeRootBorders = CSize(5,5); }; + virtual ~ETSLayoutMgr(); + + virtual CRect GetRect() { CRect r; m_pWnd->GetClientRect(r); return r; }; + CWnd* m_pWnd; + CWnd* GetWnd() { return m_pWnd; }; + void setRootBorders(int cx, int cy) { m_sizeRootBorders = CSize(cx,cy); }; + + /** + * Pass this for a pseudo Pane with no content + */ + static CWnd* paneNull; + + /** + * Loads the current position and size from the registry using a supplied + * key. Will be loaded with AfxGetApp()->WriteProfileXXX(). You may + * specify a subfolder (e.g. Load( _T("MyDialog\\Layout") ); ). Will + * load the following keys: + * + * - lpstrRegKey+"SizeX"; + * - lpstrRegKey+"SizeY"; + * - lpstrRegKey+"PosX"; + * - lpstrRegKey+"PosY"; + * + * Is automatically called during OnActivate() if key specified in + * constructor. + */ + bool Load(LPCTSTR lpstrRegKey); + + /** + * Store the current position and size to the registry using a supplied + * key. Will be stored with AfxGetApp()->WriteProfileXXX(). You may + * specify a subfolder (e.g. Save( _T("MyDialog\\Layout") ); ). Will + * create the following keys: + * + * - lpstrRegKey+"SizeX"; + * - lpstrRegKey+"SizeY"; + * - lpstrRegKey+"PosX"; + * - lpstrRegKey+"PosY"; + * + * Is automatically called during DestroyWindow() if key specified in + * constructor. + */ + bool Save(LPCTSTR lpstrRegKey); + + /** + * Updates the layout after you specify the new + * layout + */ + virtual void UpdateLayout(); + virtual void UpdateLayout(CPane p) { + if(m_RootPane.IsValid()) + { + // free old root + m_RootPane = 0; + } + m_RootPane = p; + UpdateLayout(); + } + + /** + * Does the actual Layout, called from OnSize() + * Default implementation does nothing, use + * IMPLEMENT_LAYOUT in your derived class (see above) + */ + virtual void Layout(CRect& rcClient); + + + /** + * Erasing only the these parts of the client area where + * there is no child window. Extra-code for group-boxes + * included! + */ + void EraseBkgnd(CDC* pDC); + + /** + * Helperfunctions for the stream-interface. For usage see sample Application + * and/or documentation. + */ + + /** + * Create a new Pane. You may specify the resize + * mode for both directions. If you add modes for the secondary direction + * (i.e. *_VERT for a HORIZONTAL pane) then sizeSecondary is used as it's + * size. If you do not specify sizeSecondary and the mode is ABSOLUTE_VERT + * it will be computed as the maximum Height of all SubPanes (the same is + * true for VERTICAL panes and subpanes with *_HORZ) + */ + CPane pane( layOrientation orientation, layResizeMode modeResize = GREEDY, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0, int sizeSecondary = 0); + + /** + * Create one of the special control panes. Parameter are like pane(). For + * additional information see documentation + */ + CPane paneTab( CTabCtrl* pTab, layOrientation orientation, layResizeMode modeResize = GREEDY, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0, int sizeSecondary = 0); + CPane paneCtrl( UINT nID, layOrientation orientation, layResizeMode modeResize = GREEDY, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0, int sizeTopExtra = 0, int sizeSecondary = 0); + CPane paneCtrl( CWnd* pCtrl, layOrientation orientation, layResizeMode modeResize = GREEDY, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0, int sizeTopExtra = 0, int sizeSecondary = 0); + + /** + * Creates a new PaneItem for an Control. If sizeX or sizeY are 0 + * and modeResize is ABSOLUTE will copy the current dimensions of + * the control to m_sizeX/Y. So the appearance does not change + * from the Dialog Editor. size*Min = -1 means: do not make smaller + * than in Dialog Template. + */ + CPaneBase item(UINT nID, layResizeMode modeResize = GREEDY, int sizeX =0, int sizeY =0, int sizeXMin =-1, int sizeYMin =-1); + CPaneBase item(CWnd* pWnd, layResizeMode modeResize = GREEDY, int sizeX =0, int sizeY =0, int sizeXMin =-1, int sizeYMin =-1); + + + /** + * Add a whitespace Item (paneNull) of variable size with + * a minimum size of 0 + */ + CPaneBase itemGrowing(layOrientation orientation); + + /** + * Add a whitespace Item (paneNull) with fixed size + */ + CPaneBase itemFixed(layOrientation orientation, int sizePrimary); + + /** + * Add a whitespace Item (paneNull) of fixed size based on the + * current layout (as in the dialog template). Based on the layout + * of the pane vertical or horizontal spacing is considered + * + * First argument is the left (top) item for a HORIZONTAL (VERTICAL) pane + */ + CPaneBase itemSpaceBetween( layOrientation orientation, CWnd* pWndFirst, CWnd* pWndSecond ); + CPaneBase itemSpaceBetween( layOrientation orientation, UINT nIDFirst, UINT nIDSecond ); + + /** + * Add a whitespace Item (paneNull) of fixed size based on the + * size of another item + */ + CPaneBase itemSpaceLike( layOrientation orientation, CWnd* pWnd ); + CPaneBase itemSpaceLike( layOrientation orientation, UINT nID ); + +protected: + /** + * This holds the root pane. Fill in InitDialog() + */ + CPane m_RootPane; + + /** + * Create a root pane + */ + CPane CreateRoot(layOrientation orientation, int sizeBorder = nDefaultBorder, int sizeExtraBorder = 0 ) + { + if(m_RootPane.IsValid()) + { + // free old root + m_RootPane = 0; + } + m_RootPane = new Pane( this, orientation, sizeBorder, sizeExtraBorder); + return m_RootPane; + } + + /** + * Key in Registry where to store Size + */ + CString m_strRegStore; + + /** + * Borders around root + */ + CSize m_sizeRootBorders; +}; + +inline ETSLayoutMgr::layResizeMode operator|(const ETSLayoutMgr::layResizeMode m1, + const ETSLayoutMgr::layResizeMode m2) + { return (ETSLayoutMgr::layResizeMode)( (DWORD)m1|(DWORD)m2); } + + +/** + * Base class for the Layout function. Derive your own class + * from this or derive it from CDialog and modify _all_ + * references to CDialog to ETSLayoutDialog + */ +class ETSGUI_EXT_CLASS ETSLayoutDialog : public ETSLayout::CBaseDialog, protected ETSLayoutMgr +{ +// Construction +public: + ETSLayoutDialog(UINT nID, CWnd* pParent = NULL, LPCTSTR strName = NULL, bool bGripper = true); // standard constructor + +// Dialog Data + //{{AFX_DATA(ETSLayoutDialog) + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(ETSLayoutDialog) + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(ETSLayoutDialog) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + virtual BOOL OnInitDialog(); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + virtual CRect GetRect(); + + bool m_bGripper; + CStatusBar m_StatusBar; +}; + + +/** + * Base class for the Layout function. Derive your own class + * from this or derive it from CDialog and modify _all_ + * references to CFormView to ETSLayoutFormView + */ +class ETSGUI_EXT_CLASS ETSLayoutFormView : public ETSLayout::CBaseFormView, public ETSLayoutMgr +{ +// Construction + DECLARE_DYNAMIC(ETSLayoutFormView) +public: + ETSLayoutFormView(UINT nID, LPCTSTR strName = NULL); // standard constructor + virtual ~ETSLayoutFormView(); + +// virtual void UpdateLayout(); + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(ETSLayoutDialog) + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(ETSLayoutDialog) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +/** + * Base class for the Layout function. Derive your own class + * from this or derive it from CBCGDialogBar/CDialogBar and + * modify _all_ references to CBCGDialogBar/CDialogBar to + * ETSLayoutDialogBar + */ +class ETSGUI_EXT_CLASS ETSLayoutDialogBar : public ETSLayout::CBaseDialogBar, protected ETSLayoutMgr +{ +// Construction +public: +#ifdef CS_HELP + ETSLayoutDialogBar(UINT nID); +#else + ETSLayoutDialogBar(); +#endif + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(ETSLayoutDialogBar) + virtual CSize CalcDynamicLayout(int nLength, DWORD dwMode); + //}}AFX_VIRTUAL + + /** + * Override this to define Layout + */ + virtual BOOL Initialize() { return false; }; + virtual void UpdateLayout(); + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(ETSLayoutDialogBar) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //}}AFX_MSG + LRESULT OnInitDialog(WPARAM, LPARAM); + DECLARE_MESSAGE_MAP() + + virtual CRect GetRect(); + bool m_bInitialized; +}; + + + +/************************************************** + ** ! the code is only tested for modal sheets ! ** + **************************************************/ + + +/** + * Resizable PropertySheet. Use this class standalone + * or as your base class (instead CProptertySheet) + */ +class ETSGUI_EXT_CLASS ETSLayoutPropertySheet : public CPropertySheet, protected ETSLayoutMgr +{ + DECLARE_DYNAMIC(ETSLayoutPropertySheet) + +// Construction +public: + ETSLayoutPropertySheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0, LPCTSTR strName=NULL, bool bGripper=true); + ETSLayoutPropertySheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0, LPCTSTR strName=NULL, bool bGripper=true); + +// Operationen +public: + void SetAutoDestroy() { m_bAutoDestroy = true; } + void SetAutoDestroyPages() { m_bAutoDestroyPages = true; } + void ModelessWithButtons() { m_bModelessButtons = true; } +// Overrides + virtual void AddMainArea(CPane paneRoot, CPaneBase itemTab); + virtual void AddButtons(CPane paneBottom); + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(ETSLayoutPropertySheet) + public: + virtual BOOL OnInitDialog(); + virtual void PostNcDestroy(); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~ETSLayoutPropertySheet(); + + // Generated message map functions +protected: + //{{AFX_MSG(ETSLayoutPropertySheet) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + void Resize(int cx, int cy); + +friend class ETSLayoutPropertyPage; + + void Init(LPCTSTR strName, bool bGripper); + CRect m_rcStart; + CRect m_rcPage; + bool m_bGripper; + CStatusBar m_StatusBar; + CPaneBase m_ItemTab; + bool m_bAutoDestroy; + bool m_bAutoDestroyPages; + bool m_bModelessButtons; +}; + +/** + * Base class for the Layout function. Derive your own class + * from this or derive it from CPropertyPage and + * modify _all_ references to CPropertyPage to + * ETSLayoutPropertyPage + */ +class ETSGUI_EXT_CLASS ETSLayoutPropertyPage : public ETSLayout::CBasePropertyPage, protected ETSLayoutMgr +{ +friend class ETSLayoutPropertySheet; + + DECLARE_DYNCREATE(ETSLayoutPropertyPage) + +// Konstruktion +public: + ETSLayoutPropertyPage( ); + ETSLayoutPropertyPage( UINT nIDTemplate, UINT nIDCaption = 0 ); + ETSLayoutPropertyPage( LPCTSTR lpszTemplateName, UINT nIDCaption = 0 ); + + ~ETSLayoutPropertyPage(); + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(ETSLayoutPropertyPage) + public: + virtual BOOL OnSetActive(); + //}}AFX_VIRTUAL + +// Implementation +protected: + // Generated message map functions + //{{AFX_MSG(ETSLayoutPropertyPage) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + virtual BOOL OnInitDialog(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnWindowPosChanging( WINDOWPOS* lpwndpos ); + afx_msg void OnDestroy(); + afx_msg void OnWindowPosChanged(WINDOWPOS FAR* lpwndpos); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + virtual CRect GetRect(); + bool m_bLockMove; + bool m_bResetBuddyOnNextTimeVisible; +}; + + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(ETS_LAYOUTMGR_INCLUDED_) diff --git a/install/xbt/linux/misc/windows/browse_for_directory.cpp b/install/xbt/linux/misc/windows/browse_for_directory.cpp new file mode 100644 index 000000000..04010b571 --- /dev/null +++ b/install/xbt/linux/misc/windows/browse_for_directory.cpp @@ -0,0 +1,33 @@ +#include "stdafx.h" +#include "browse_for_directory.h" + +int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + if (uMsg == BFFM_INITIALIZED) + SendMessage(hwnd, BFFM_SETSELECTION, true, lpData); + return 0; +} + +int browse_for_directory(HWND hWnd, const std::string& title, std::string& directory) +{ + BROWSEINFO bi; + ZeroMemory(&bi, sizeof(BROWSEINFO)); + bi.hwndOwner = hWnd; + bi.lpszTitle = title.c_str(); + bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; + bi.lpfn = BrowseCallbackProc; + bi.lParam = reinterpret_cast(directory.c_str()); + ITEMIDLIST* idl = SHBrowseForFolder(&bi); + if (!idl) + return 1; + char path[MAX_PATH]; + if (!SHGetPathFromIDList(idl, path)) + *path = 0; + LPMALLOC lpm; + if (SHGetMalloc(&lpm) == NOERROR) + lpm->Free(idl); + if (!*path) + return 1; + directory = path; + return 0; +} \ No newline at end of file diff --git a/install/xbt/linux/misc/windows/browse_for_directory.h b/install/xbt/linux/misc/windows/browse_for_directory.h new file mode 100644 index 000000000..bd275bd77 --- /dev/null +++ b/install/xbt/linux/misc/windows/browse_for_directory.h @@ -0,0 +1,3 @@ +#pragma once + +int browse_for_directory(HWND, const std::string& title, std::string& directory); diff --git a/install/xbt/linux/misc/windows/nt_service.cpp b/install/xbt/linux/misc/windows/nt_service.cpp new file mode 100644 index 000000000..392f46c57 --- /dev/null +++ b/install/xbt/linux/misc/windows/nt_service.cpp @@ -0,0 +1,67 @@ +#include "stdafx.h" +#include "nt_service.h" + +#include + +int nt_service_install(const char* name) +{ + SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!scm) + return 1; + char file_name[MAX_PATH]; + GetModuleFileName(NULL, file_name, MAX_PATH); + SC_HANDLE service = CreateService(scm, + name, + name, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + file_name, + NULL, + NULL, + NULL, + "NT AUTHORITY\\LocalService", + NULL); + if (!service) + { + service = CreateService(scm, + name, + name, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + file_name, + NULL, + NULL, + NULL, + NULL, + NULL); + } + if (!service) + { + CloseServiceHandle(scm); + return 1; + } + CloseServiceHandle(service); + CloseServiceHandle(scm); + return 0; +} + +int nt_service_uninstall(const char* name) +{ + SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!scm) + return 1; + int result = 1; + SC_HANDLE service = OpenService(scm, name, DELETE); + if (service) + { + if (DeleteService(service)) + result = 0; + CloseServiceHandle(service); + } + CloseServiceHandle(scm); + return result; +} diff --git a/install/xbt/linux/misc/windows/nt_service.h b/install/xbt/linux/misc/windows/nt_service.h new file mode 100644 index 000000000..0102ab78f --- /dev/null +++ b/install/xbt/linux/misc/windows/nt_service.h @@ -0,0 +1,4 @@ +#pragma once + +int nt_service_install(const char* name); +int nt_service_uninstall(const char* name); diff --git a/install/xbt/linux/misc/xbt/virtual_binary.h b/install/xbt/linux/misc/xbt/virtual_binary.h new file mode 100644 index 000000000..b0d4ac09d --- /dev/null +++ b/install/xbt/linux/misc/xbt/virtual_binary.h @@ -0,0 +1,129 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class Cvirtual_binary_source: boost::noncopyable +{ +public: + Cvirtual_binary_source(const_memory_range); + + ~Cvirtual_binary_source() + { + delete[] m_range.begin; + } + + memory_range range() + { + return m_range; + } + + void resize(size_t v) + { + assert(v <= m_range.size()); + m_range.end = m_range.begin + v; + } +private: + memory_range m_range; +}; + +class Cvirtual_binary +{ +public: + int save(const std::string&) const; + int load(const std::string&); + Cvirtual_binary& load1(const std::string&); + void clear(); + size_t read(void* d) const; + unsigned char* write_start(size_t cb_d); + void write(const_memory_range); + Cvirtual_binary(size_t); + Cvirtual_binary(const_memory_range); + + Cvirtual_binary() + { + } + + const unsigned char* begin() const + { + return range().begin; + } + + unsigned char* mutable_begin() + { + return mutable_range().begin; + } + + const unsigned char* data() const + { + return range().begin; + } + + unsigned char* data_edit() + { + return mutable_range().begin; + } + + const unsigned char* end() const + { + return range().end; + } + + unsigned char* mutable_end() + { + return mutable_range().end; + } + + const_memory_range range() const + { + return m_source ? m_source->range() : memory_range(); + } + + memory_range mutable_range() + { + if (!m_source) + return memory_range(); + if (!m_source.unique()) + m_source = boost::make_shared(range()); + return m_source->range(); + } + + bool empty() const + { + return range().empty(); + } + + size_t size() const + { + return range().size(); + } + + void resize(size_t v) + { + if (!m_source) + write_start(v); + mutable_range(); + m_source->resize(v); + } + + operator const unsigned char*() const + { + return data(); + } + + operator const_memory_range() const + { + return range(); + } + + operator memory_range() + { + return mutable_range(); + } +private: + boost::shared_ptr m_source; +}; diff --git a/install/xbt/linux/misc/xcc_z.cpp b/install/xbt/linux/misc/xcc_z.cpp new file mode 100644 index 000000000..97bb10566 --- /dev/null +++ b/install/xbt/linux/misc/xcc_z.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "xcc_z.h" + +#include +#include +#include +#include "stream_int.h" + +Cvirtual_binary xcc_z::gunzip(const_memory_range s) +{ + if (s.size() < 18) + return Cvirtual_binary(); + Cvirtual_binary d; + z_stream stream; + stream.zalloc = NULL; + stream.zfree = NULL; + stream.opaque = NULL; + stream.next_in = const_cast(s.begin) + 10; + stream.avail_in = s.size() - 18; + stream.next_out = d.write_start(read_int_le(4, s.end - 4)); + stream.avail_out = d.size(); + return stream.next_out + && Z_OK == inflateInit2(&stream, -MAX_WBITS) + && Z_STREAM_END == inflate(&stream, Z_FINISH) + && Z_OK == inflateEnd(&stream) + ? d + : Cvirtual_binary(); +} + +Cvirtual_binary xcc_z::gzip(const_memory_range s) +{ + Cvirtual_binary d; + unsigned long cb_d = s.size() + (s.size() + 999) / 1000 + 12; + unsigned char* w = d.write_start(10 + cb_d + 8); + *w++ = 0x1f; + *w++ = 0x8b; + *w++ = Z_DEFLATED; + *w++ = 0; + *w++ = 0; + *w++ = 0; + *w++ = 0; + *w++ = 0; + *w++ = 0; + *w++ = 3; + { + z_stream stream; + stream.zalloc = NULL; + stream.zfree = NULL; + stream.opaque = NULL; + deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); + stream.next_in = const_cast(s.begin); + stream.avail_in = s.size(); + stream.next_out = w; + stream.avail_out = cb_d; + deflate(&stream, Z_FINISH); + deflateEnd(&stream); + w = stream.next_out; + } + w = write_int_le(4, w, crc32(crc32(0, NULL, 0), s, s.size())); + w = write_int_le(4, w, s.size()); + d.resize(w - d.data()); + return d; +} + +void xcc_z::gzip_out(const_memory_range s) +{ + gzFile f = gzdopen(fileno(stdout), "wb"); + gzwrite(f, const_cast(s.begin), s.size()); + gzflush(f, Z_FINISH); +} diff --git a/install/xbt/linux/misc/xcc_z.h b/install/xbt/linux/misc/xcc_z.h new file mode 100644 index 000000000..0d10e08ec --- /dev/null +++ b/install/xbt/linux/misc/xcc_z.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace xcc_z +{ + Cvirtual_binary gunzip(const_memory_range); + Cvirtual_binary gzip(const_memory_range); + void gzip_out(const_memory_range); +} diff --git a/install/xbt/linux/misc/xif_key.cpp b/install/xbt/linux/misc/xif_key.cpp new file mode 100644 index 000000000..e90165e0d --- /dev/null +++ b/install/xbt/linux/misc/xif_key.cpp @@ -0,0 +1,196 @@ +#include "stdafx.h" +#include "xif_key.h" + +#include +#include "stream_int.h" + +static int read_int(const byte*& r) +{ + r += 4; + return read_int_le(4, r - 4); +} + +void Cxif_key::load_old(const byte*& data) +{ + for (int count = read_int(data); count--; ) + { + Cxif_key& i = set_key(read_int(data)); + i.load_old(data); + } + for (int count = read_int(data); count--; ) + { + Cxif_value& i = set_value(read_int(data)); + i.load_old(data); + } +} + +void Cxif_key::load_new(const byte*& data) +{ + for (int count = read_int(data), id = 0; count--; ) + { + id += read_int(data); + open_key_write(id).load_new(data); + } + for (int count = read_int(data), id = 0; count--; ) + { + id += read_int(data); + open_value_write(id).load_new(data); + } +} + +void Cxif_key::load_external(const byte*& data) +{ + BOOST_FOREACH(t_xif_key_map::reference i, m_keys) + i.second.load_external(data); + BOOST_FOREACH(t_xif_value_map::reference i, m_values) + i.second.load_external(data); +} + +int Cxif_key::get_size() const +{ + int size = 8; + BOOST_FOREACH(t_xif_key_map::const_reference i, m_keys) + size += 4 + i.second.get_size(); + BOOST_FOREACH(t_xif_value_map::const_reference i, m_values) + { + size += 9; + switch (i.second.get_type()) + { + case vt_bin32: + case vt_int32: + break; + default: + if (!i.second.external_data()) + size += i.second.get_size(); + } + } + return size; +} + +int Cxif_key::get_external_size() const +{ + int size = 0; + BOOST_FOREACH(t_xif_key_map::const_reference i, m_keys) + size += i.second.get_external_size(); + BOOST_FOREACH(t_xif_value_map::const_reference i, m_values) + if (i.second.external_data()) + size += i.second.get_size(); + return size; +} + +void Cxif_key::save(byte*& data) const +{ + { + data = write_int_le(4, data, m_keys.size()); + int id = 0; + BOOST_FOREACH(t_xif_key_map::const_reference i, m_keys) + { + data = write_int_le(4, data, i.first - id); + id = i.first; + i.second.save(data); + } + } + { + data = write_int_le(4, data, m_values.size()); + int id = 0; + BOOST_FOREACH(t_xif_value_map::const_reference i, m_values) + { + data = write_int_le(4, data, i.first - id); + id = i.first; + i.second.save(data); + } + } +} + +void Cxif_key::external_save(byte*& data) const +{ + BOOST_FOREACH(t_xif_key_map::const_reference i, m_keys) + i.second.external_save(data); + BOOST_FOREACH(t_xif_value_map::const_reference i, m_values) + i.second.external_save(data); +} + +int Cxif_key::load_key(const byte* data, size_t size) +{ + const byte* read_p = data; + const t_xif_header_fast& header = *reinterpret_cast(read_p); + if (size < sizeof(t_xif_header_old) + || header.id != file_id + || header.version != file_version_old && header.version != file_version_new && header.version != file_version_fast) + return 1; + int error = 0; + if (header.version == file_version_old) + { + read_p += sizeof(t_xif_header_old) - 4; + load_old(read_p); + error = size != read_p - data; + } + else + { + unsigned long cb_d = header.size_uncompressed; + if (cb_d) + { + Cvirtual_binary d; + if (header.version == file_version_new) + error = Z_OK != uncompress(d.write_start(cb_d), &cb_d, data + sizeof(t_xif_header_old), size - sizeof(t_xif_header_old)); + else + error = Z_OK != uncompress(d.write_start(cb_d), &cb_d, data + sizeof(t_xif_header_fast), header.size_compressed); + if (!error) + { + read_p = d.data(); + load_new(read_p); + error = read_p != d.end(); + if (header.version == file_version_fast && !error) + { + read_p = data + sizeof(t_xif_header_fast) + header.size_compressed; + load_external(read_p); + error = size != read_p - data; + } + } + } + else + { + read_p = data + (header.version == file_version_fast ? sizeof(t_xif_header_fast) : sizeof(t_xif_header_old)); + load_new(read_p); + load_external(read_p); + error = size != read_p - data; + } + } + return error; +} + +Cvirtual_binary Cxif_key::vdata(bool fast) const +{ + Cvirtual_binary d; + int size = get_size(); + int external_size = get_external_size(); + if (fast) + { + t_xif_header_fast& header = *reinterpret_cast(d.write_start(sizeof(t_xif_header_fast) + size + external_size)); + header.id = file_id; + header.version = file_version_fast; + header.size_uncompressed = 0; + header.size_compressed = size; + header.size_external = external_size; + byte* w = d.data_edit() + sizeof(t_xif_header_fast); + save(w); + external_save(w); + assert(d.end() == w); + return d; + } + Cvirtual_binary s; + byte* w = s.write_start(size); + save(w); + unsigned long cb_d = s.size() + (s.size() + 999) / 1000 + 12; + t_xif_header_fast& header = *reinterpret_cast(d.write_start(sizeof(t_xif_header_fast) + cb_d + external_size)); + compress(d.data_edit() + sizeof(t_xif_header_fast), &cb_d, s.data(), s.size()); + w = d.data_edit() + sizeof(t_xif_header_fast) + cb_d; + external_save(w); + header.id = file_id; + header.version = file_version_fast; + header.size_uncompressed = size; + header.size_compressed = cb_d; + header.size_external = external_size; + d.resize(sizeof(t_xif_header_fast) + cb_d + external_size); + return d; +} diff --git a/install/xbt/linux/misc/xif_key.h b/install/xbt/linux/misc/xif_key.h new file mode 100644 index 000000000..ea9fc4850 --- /dev/null +++ b/install/xbt/linux/misc/xif_key.h @@ -0,0 +1,252 @@ +#pragma once + +#include +#include +#include +#include + +const static int file_id = 0x1a464958; // *reinterpret_cast("XIF\x1a"); +const static int file_version_old = 0; +const static int file_version_new = 1; +const static int file_version_fast = 2; + +struct t_xif_header_old +{ + int id; + int version; + int size_uncompressed; +}; + +struct t_xif_header_fast +{ + int id; + int version; + int size_uncompressed; + int size_compressed; + int size_external; +}; + +class Cxif_key; + +typedef std::map t_xif_key_map; +typedef std::map t_xif_value_map; + +class Cxif_key +{ +public: + Cxif_key(): + m_keys(*new t_xif_key_map) + { + } + + ~Cxif_key() + { + delete &m_keys; + } + + Cxif_key(const Cxif_key& v): + m_keys(*new t_xif_key_map) + { + m_keys = v.m_keys; + m_values = v.m_values; + } + + explicit Cxif_key(const Cvirtual_binary& v): + m_keys(*new t_xif_key_map) + { + load_key(v); + } + + const Cxif_key& operator=(const Cxif_key& v) + { + m_keys = v.m_keys; + m_values = v.m_values; + return *this; + } + + Cxif_key& set_key(int id) + { + m_keys[id] = Cxif_key(); + return m_keys[id]; + } + + const Cxif_key& open_key_read(int id) const + { + return m_keys.find(id)->second; + } + + Cxif_key& open_key_edit(int id) + { + return m_keys[id]; + } + + Cxif_key& open_key_write() + { + return open_key_write(m_keys.empty() ? 0 : m_keys.rbegin()->first + 1); + } + + Cxif_key& open_key_write(int id) + { + m_keys[id] = Cxif_key(); + return m_keys[id]; + } + + const Cxif_value& open_value_read(int id) const + { + return m_values.find(id)->second; + } + + Cxif_value& open_value_edit(int id) + { + return m_values[id]; + } + + Cxif_value& open_value_write(int id) + { + m_values[id] = Cxif_value(); + return m_values[id]; + } + + Cxif_value& set_value(int id) + { + m_values[id] = Cxif_value(); + return m_values[id]; + } + + void set_value_bin(int id, int v) + { + m_values[id] = Cxif_value(vt_bin32, v); + } + + void set_value_binary(int id, const Cvirtual_binary v, bool fast = false) + { + m_values[id] = Cxif_value(v, fast); + } + + void set_value_float(int id, float v) + { + m_values[id] = Cxif_value(v); + } + + void set_value_int(int id, int v) + { + m_values[id] = Cxif_value(vt_int32, v); + } + + void set_value_string(int id, const std::string& v) + { + m_values[id] = Cxif_value(v); + } + + void set_value_int64(int id, long long v) + { + set_value_binary(id, Cvirtual_binary(const_memory_range(&v, 8))); + } + + const Cxif_key& get_key(int id) const + { + static Cxif_key z; + t_xif_key_map::iterator i = m_keys.find(id); + return i == m_keys.end() ? z : i->second; + } + + const Cxif_value& get_value(int id) const + { + static Cxif_value z; + t_xif_value_map::const_iterator i = m_values.find(id); + return i == m_values.end() ? z : i->second; + } + + float get_value_float(int id) const + { + return get_value(id).get_float(); + } + + float get_value_float(int id, float v) const + { + return get_value(id).get_float(v); + } + + int get_value_int(int id) const + { + return get_value(id).get_int(); + } + + int get_value_int(int id, int v) const + { + return get_value(id).get_int(v); + } + + long long get_value_int64(int id) const + { + return *reinterpret_cast(get_value(id).get_data()); + } + + std::string get_value_string(int id) const + { + return get_value(id).get_string(); + } + + std::string get_value_string(int id, const std::string& v) const + { + return get_value(id).get_string(v); + } + + bool exists_key(int id) const + { + return m_keys.find(id) != m_keys.end(); + } + + bool exists_value(int id) const + { + return m_values.find(id) != m_values.end(); + } + + int c_keys() const + { + return m_keys.size(); + } + + int c_values() const + { + return m_values.size(); + } + + int load_key(const Cvirtual_binary& data) + { + return load_key(data.data(), data.size()); + } + + void delete_key(int id) + { + m_keys.erase(id); + } + + void delete_value(int id) + { + m_values.erase(id); + } + + void clear() + { + m_keys.clear(); + m_values.clear(); + } + + void dump(std::ostream& os, bool show_ratio, int depth = 0, Cvirtual_binary* t = NULL) const; + void dump_ratio(std::ostream& os, Cvirtual_binary* t) const; + Cvirtual_binary export_bz() const; + int load_key(const byte* data, size_t size); + Cvirtual_binary vdata(bool fast = false) const; + + t_xif_key_map& m_keys; + t_xif_value_map m_values; +private: + int get_size() const; + int get_external_size() const; + void load_old(const byte*& data); + void load_new(const byte*& data); + void load_external(const byte*& data); + void save(byte*& data) const; + void external_save(byte*& data) const; +}; diff --git a/install/xbt/linux/misc/xif_key_r.cpp b/install/xbt/linux/misc/xif_key_r.cpp new file mode 100644 index 000000000..58ee3db22 --- /dev/null +++ b/install/xbt/linux/misc/xif_key_r.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "xif_key_r.h" + +#include +#include +#include +#include + +static int read_int(const byte*& r) +{ + r += 4; + return read_int_le(4, r - 4); +} + +int Cxif_key_r::import(const_memory_range s) +{ + Cvirtual_binary d; + const t_xif_header_fast& h = *reinterpret_cast(s.begin); + if (s.size() < sizeof(t_xif_header_fast) + 8 + || h.id != file_id + || h.version != file_version_fast) + return 1; + unsigned long cb_d = h.size_uncompressed; + if (cb_d) + { + if (Z_OK != uncompress(d.write_start(cb_d), &cb_d, s + sizeof(t_xif_header_fast), h.size_compressed)) + return 1; + /* + if (uncompress(d.write_start(cb_d), &cb_d, s + sizeof(t_xif_header_fast), h.size_compressed) != Z_OK) + return 1; + */ + load(d); + // m_external_data = d + h.size_compressed; + } + else + { + load(s + sizeof(t_xif_header_fast)); + // m_external_data = s + sizeof(t_xif_header_fast) + h.size_uncompressed + } + + return 0; +} + +int Cxif_key_r::load(const byte* s) +{ + const byte* r = s; + { + int count = read_int(r); + int id = 0; + m_keys.reserve(count); + while (count--) + { + id += read_int(r); + m_keys.push_back(std::make_pair(id, Cxif_key_r())); + r += m_keys.rbegin()->second.load(r); + } + } + { + int count = read_int(r); + int id = 0; + m_values.reserve(count); + while (count--) + { + id += read_int(r); + m_values.push_back(std::make_pair(id, Cxif_value())); + m_values.rbegin()->second.load_new(r); + } + } + return r - s; +} + +Cxif_key_r::t_key_map::const_iterator Cxif_key_r::find_key(int id) const +{ + t_key_map::const_iterator i = keys().begin(); + while (i != keys().end() && i->first != id) + i++; + return i; +} + +Cxif_key_r::t_value_map::const_iterator Cxif_key_r::find_value(int id) const +{ + t_value_map::const_iterator i = values().begin(); + while (i != values().end() && i->first != id) + i++; + return i; +} diff --git a/install/xbt/linux/misc/xif_key_r.h b/install/xbt/linux/misc/xif_key_r.h new file mode 100644 index 000000000..690a253d3 --- /dev/null +++ b/install/xbt/linux/misc/xif_key_r.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include "xif_value.h" + +class Cxif_key_r +{ +public: + typedef std::vector > t_key_map; + typedef std::vector > t_value_map; + + const Cxif_key_r& get_key(int id) const + { + return find_key(id)->second; + } + + const Cxif_value& get_value(int id) const + { + static Cxif_value z; + t_value_map::const_iterator i = find_value(id); + return i == values().end() ? z : i->second; + } + + float get_value_float(int id) const + { + return get_value(id).get_float(); + } + + float get_value_float(int id, float v) const + { + return get_value(id).get_float(v); + } + + int get_value_int(int id) const + { + return get_value(id).get_int(); + } + + int get_value_int(int id, int v) const + { + return get_value(id).get_int(v); + } + + long long get_value_int64(int id) const + { + return *reinterpret_cast(get_value(id).get_data()); + } + + std::string get_value_string(int id) const + { + return get_value(id).get_string(); + } + + std::string get_value_string(int id, const std::string& v) const + { + return get_value(id).get_string(v); + } + + const t_key_map& keys() const + { + return m_keys; + } + + const t_value_map& values() const + { + return m_values; + } + + int c_keys() const + { + return keys().size(); + } + + int c_values() const + { + return values().size(); + } + + bool has_key(int id) const + { + return find_key(id) != keys().end(); + } + + bool has_value(int id) const + { + return find_value(id) != values().end(); + } + + t_key_map::const_iterator find_key(int id) const; + t_value_map::const_iterator find_value(int id) const; + int import(const_memory_range); +private: + int load(const byte* s); + + t_key_map m_keys; + t_value_map m_values; +}; diff --git a/install/xbt/linux/misc/xif_value.cpp b/install/xbt/linux/misc/xif_value.cpp new file mode 100644 index 000000000..eceb9d6b9 --- /dev/null +++ b/install/xbt/linux/misc/xif_value.cpp @@ -0,0 +1,151 @@ +#include "stdafx.h" +#include "xif_value.h" + +#include +#include "stream_int.h" + +static float read_float(const byte*& r) +{ + assert(sizeof(float) == 4); + float v; + memcpy(&v, r, 4); + r += 4; + return v; +} + +static int read_int(const byte*& r) +{ + r += 4; + return read_int_le(4, r - 4); +} + +t_vt Cxif_value::get_type() const +{ + if (m_type != vt_unknown) + return m_type; + const byte* data = m_data.data(); + if (!data) + return vt_binary; + int size = m_data.size(); + if (!data[size - 1]) + { + const byte* r = data; + int c = size - 1; + while (c--) + { + if (*r != 9 && *r < 0x20) + break; + r++; + } + if (c == -1) + return vt_string; + } + if (size == 4) + return vt_int32; + return vt_binary; +} + +void Cxif_value::load_old(const byte*& data) +{ + m_data.clear(); + int size = read_int(data); + if (size == 4) + memcpy(m_value, data, size); + memcpy(m_data.write_start(size), data, size); + data += size; + m_type = vt_unknown; + m_type = get_type(); +} + +void Cxif_value::load_new(const byte*& data) +{ + m_data.clear(); + m_type = static_cast(*data++); + switch (m_type) + { + case vt_bin32: + case vt_int32: + m_value_int = read_int(data); + break; + case vt_float: + m_value_float = read_float(data); + break; + case vt_external_binary: + m_data.write_start(read_int(data)); + break; + default: + { + int size = read_int(data); + memcpy(m_data.write_start(size), data, size); + data += size; + } + } +} + +void Cxif_value::load_external(const byte*& data) +{ + if (!external_data()) + return; + memcpy(m_data.data_edit(), data, get_size()); + data += get_size(); +} + +int Cxif_value::skip(const byte* s) +{ + const byte* r = s; + t_vt type = static_cast(*r++); + switch (type) + { + case vt_bin32: + case vt_int32: + read_int(r); + break; + case vt_float: + read_float(r); + break; + case vt_external_binary: + read_int(r); + break; + default: + r += read_int(r); + } + return r - s; +} + +void Cxif_value::save(byte*& data) const +{ + *data++ = external_data() ? vt_external_binary : m_type; + switch (m_type) + { + case vt_bin32: + case vt_int32: + data = write_int_le(4, data, get_int()); + break; + case vt_float: + data = write_float(data, get_float()); + break; + default: + { + int size = get_size(); + data = write_int_le(4, data, size); + if (!external_data()) + { + memcpy(data, get_data(), size); + data += size; + } + } + } +} + +bool Cxif_value::external_data() const +{ + return m_type == vt_external_binary; +} + +void Cxif_value::external_save(byte*& data) const +{ + if (!external_data()) + return; + memcpy(data, get_data(), get_size()); + data += get_size(); +} diff --git a/install/xbt/linux/misc/xif_value.h b/install/xbt/linux/misc/xif_value.h new file mode 100644 index 000000000..f248c2193 --- /dev/null +++ b/install/xbt/linux/misc/xif_value.h @@ -0,0 +1,113 @@ +#pragma once + +#include +#include + +enum t_vt {vt_bin32, vt_binary, vt_int32, vt_string, vt_external_binary, vt_float, vt_unknown}; + +class Cxif_value +{ +public: + Cxif_value() + { + m_type = vt_unknown; + } + + Cxif_value(float v) + { + m_type = vt_float; + m_value_float = v; + } + + Cxif_value(t_vt type, int v) + { + m_type = type; + m_value_int = v; + } + + Cxif_value(const Cvirtual_binary v, bool fast = false) + { + m_type = fast ? vt_external_binary : vt_binary; + m_data = v; + } + + Cxif_value(const std::string& v) + { + m_type = vt_string; + memcpy(m_data.write_start(v.length() + 1), v.c_str(), v.length() + 1); + } + + Cvirtual_binary get_vdata() const + { + assert(!idata()); + return m_data; + } + + const byte* get_data() const + { + return idata() ? m_value : m_data.data(); + } + + int get_size() const + { + return idata() ? 4 : m_data.size(); + } + + float get_float() const + { + assert(get_size() == 4); + return m_value_float; + } + + float get_float(float v) const + { + return get_size() ? get_float() : v; + } + + int get_int() const + { + assert(get_size() == 4); + return m_value_int; + } + + int get_int(int v) const + { + return get_size() ? get_int() : v; + } + + std::string get_string() const + { + assert(get_size()); + return reinterpret_cast(get_data()); + } + + std::string get_string(const std::string& v) const + { + return get_size() ? get_string() : v; + } + + bool idata() const + { + // internal data? + return get_type() == vt_bin32 || get_type() == vt_float || get_type() == vt_int32; + } + + void dump(std::ostream& os, int depth = 0) const; + t_vt get_type() const; + void load_old(const byte*& data); + void load_new(const byte*& data); + void load_external(const byte*& data); + void save(byte*& data) const; + static int skip(const byte* s); + bool external_data() const; + void external_save(byte*& data) const; +private: + Cvirtual_binary m_data; + t_vt m_type; + union + { + byte m_value[4]; + float m_value_float; + int m_value_int; + }; +}; diff --git a/install/xbt/sql/update_mysql.sql b/install/xbt/sql/update_mysql.sql new file mode 100644 index 000000000..581bdd8a1 --- /dev/null +++ b/install/xbt/sql/update_mysql.sql @@ -0,0 +1,81 @@ +CREATE TABLE IF NOT EXISTS `bb_bt_tor_dl_stat` ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_id` mediumint(9) NOT NULL default '0', + `attach_id` mediumint(8) unsigned NOT NULL default '0', + `t_up_total` bigint(20) unsigned NOT NULL default '0', + `t_down_total` bigint(20) unsigned NOT NULL default '0', + `t_bonus_total` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY (`topic_id`,`user_id`) +); + +CREATE TABLE IF NOT EXISTS `bb_bt_torrents_del` ( + `topic_id` mediumint(8) unsigned NOT NULL, + `info_hash` tinyblob NOT NULL, + `is_del` tinyint(4) NOT NULL default '1', + `dl_percent` tinyint(4) NOT NULL default '100', + PRIMARY KEY (`topic_id`) +); + +ALTER TABLE `bb_bt_tracker` ADD `peer_id` varchar(20) NOT NULL AFTER `topic_id`; +ALTER TABLE `bb_bt_tracker` ADD `ipv6` varchar(32) DEFAULT NULL; +ALTER TABLE `bb_bt_tracker` ADD `complete_percent` bigint(20) NOT NULL default '0'; + +ALTER TABLE bb_bt_torrents ADD speed_up mediumint(8) NOT NULL default 0; +ALTER TABLE bb_bt_torrents ADD speed_down mediumint(8) NOT NULL default 0; + +----------------- +-- XBTT Tables -- +----------------- +CREATE TABLE IF NOT EXISTS `xbt_announce_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ipa` int(10) unsigned NOT NULL DEFAULT '0', + `port` int(11) NOT NULL DEFAULT '0', + `event` int(11) NOT NULL DEFAULT '0', + `info_hash` blob NOT NULL, + `peer_id` blob NOT NULL, + `downloaded` bigint(20) NOT NULL DEFAULT '0', + `left0` bigint(20) NOT NULL DEFAULT '0', + `uploaded` bigint(20) NOT NULL DEFAULT '0', + `uid` int(11) NOT NULL DEFAULT '0', + `mtime` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +); + +CREATE TABLE IF NOT EXISTS `xbt_config` ( + `name` varchar(255) NOT NULL DEFAULT '', + `value` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`name`) +); + +CREATE TABLE IF NOT EXISTS `xbt_deny_from_hosts` ( + `begin` int(11) NOT NULL DEFAULT '0', + `end` int(11) NOT NULL DEFAULT '0' +); + +CREATE TABLE IF NOT EXISTS `xbt_files_users` ( + `fid` int(11) NOT NULL DEFAULT '0', + `uid` int(11) NOT NULL DEFAULT '0', + `active` tinyint(4) NOT NULL DEFAULT '0', + `announced` int(11) NOT NULL DEFAULT '0', + `completed` int(11) NOT NULL DEFAULT '0', + `downloaded` bigint(20) NOT NULL DEFAULT '0', + `left` bigint(20) NOT NULL DEFAULT '0', + `uploaded` bigint(20) NOT NULL DEFAULT '0', + `mtime` int(11) NOT NULL DEFAULT '0', + UNIQUE KEY `fid` (`fid`,`uid`), + KEY `uid` (`uid`) +); + +CREATE TABLE IF NOT EXISTS `xbt_scrape_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ipa` int(11) NOT NULL DEFAULT '0', + `info_hash` blob, + `uid` int(11) NOT NULL DEFAULT '0', + `mtime` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +); + +-- bb_config -- +insert into bb_config +select * from xbt_config +where name='torrent_pass_private_key'; \ No newline at end of file diff --git a/install/xbt/windows/XBT Tracker.exe b/install/xbt/windows/XBT Tracker.exe new file mode 100644 index 000000000..d6087c23e Binary files /dev/null and b/install/xbt/windows/XBT Tracker.exe differ diff --git a/install/xbt/windows/htdocs/xbt.css b/install/xbt/windows/htdocs/xbt.css new file mode 100644 index 000000000..612de46ab --- /dev/null +++ b/install/xbt/windows/htdocs/xbt.css @@ -0,0 +1,5 @@ +img {border-style: none;} +table {border-collapse: collapse;} +td, th {border: 1px solid #000000;} +td {background-color: #cccccc;} +th {background-color: #ccccff;} diff --git a/install/xbt/windows/htdocs/xbt_config.php b/install/xbt/windows/htdocs/xbt_config.php new file mode 100644 index 000000000..4ceb32f6e --- /dev/null +++ b/install/xbt/windows/htdocs/xbt_config.php @@ -0,0 +1,6 @@ + diff --git a/install/xbt/windows/htdocs/xbt_files.php b/install/xbt/windows/htdocs/xbt_files.php new file mode 100644 index 000000000..e7e1f471d --- /dev/null +++ b/install/xbt/windows/htdocs/xbt_files.php @@ -0,0 +1,59 @@ + + + +XBT Files +'); + printf('completed%d', $result['completed']); + printf('peers%d100 %%', $result['peers']); + if ($result['peers']) + { + printf('leechers%d%d %%', $result['leechers'], $result['leechers'] * 100 / $result['peers']); + printf('seeders%d%d %%', $result['seeders'], $result['seeders'] * 100 / $result['peers']); + } + printf('torrents%d', $result['torrents']); + printf('time%s', gmdate('Y-m-d H:i:s')); + echo(''); + echo('
'); + $results = mysql_query("select * from xbt_files where leechers or seeders order by ctime desc"); + echo(''); + echo(''); + echo(''); + printf('
fid'); + echo('info_hash'); + echo('leechers'); + echo('seeders'); + echo('completed'); + echo('modified'); + echo('created'); + while ($result = mysql_fetch_assoc($results)) + { + echo('
%d', $result['fid']); + printf('%s', bin2hex($result['info_hash'])); + echo(''); + if ($result['leechers']) + printf('%d', $result['leechers']); + echo(''); + if ($result['seeders']) + printf('%d', $result['seeders']); + echo(''); + if ($result['completed']) + printf('%d', $result['completed']); + printf('%s', gmdate('Y-m-d H:i:s', $result['mtime'])); + printf('%s', gmdate('Y-m-d H:i:s', $result['ctime'])); + } + echo('
'); +?> +
+
+ XBT project at SF + Valid CSS! + Valid HTML 4.01! +
\ No newline at end of file diff --git a/install/xbt/windows/libmysql.dll b/install/xbt/windows/libmysql.dll new file mode 100644 index 000000000..a80f347fc Binary files /dev/null and b/install/xbt/windows/libmysql.dll differ diff --git a/install/xbt/windows/xbt_tracker.conf b/install/xbt/windows/xbt_tracker.conf new file mode 100644 index 000000000..81d394bb2 --- /dev/null +++ b/install/xbt/windows/xbt_tracker.conf @@ -0,0 +1,47 @@ +mysql_host = localhost +mysql_database = forum +mysql_user = user +mysql_password = user + +auto_register = 0 +anonymous_announce = 0 +anonymous_scrape = 0 +anonymous_connect = 0 +full_scrape = 0 +listen_check = 0 + +gzip_debug = 0 +gzip_scrape = 1 +full_scrape = 0 + +announce_interval = 700 +clean_up_interval = 60 +read_config_interval = 60 +read_db_interval = 150 +scrape_interval = 0 +write_db_interval = 3 +read_files_interval = 2 + +table_files = bb_bt_torrents +table_users = bb_bt_users +table_files_users = bb_bt_tracker + +column_files_completed = complete_count +column_files_fid = topic_id +column_users_uid = user_id + +column_users_can_leech = case when bt.u_down_total>5368709120 and (bt.u_up_total+bt.u_up_bonus)greatest(5368709120,bt.u_down_total) then 0 when bt.u_up_total>5368709120 and bt.u_down_total>0 then floor((bt.u_up_total+bt.u_up_bonus)/0.3/bt.u_down_total)+1 when (bt.u_up_total+bt.u_up_bonus)>bt.u_down_total then 3 else 2 end + +column_files_dl_percent = (select case tor.tor_type when 1 then 0 when 2 then 50 else 100 end from bb_bt_torrents tor where tor.topic_id=bt.topic_id) as dl_percent + +log_announce = 0 +gdc = 1 +debug = 0 +#free_leech = 0 +log_access = 0 + +redirect_url = http://site.ru/forum/ +trust_ipv6 = 1 +pid_file = F:/AnimeTracker/XBTT/xbt_tracker.pid + diff --git a/install/xbt/windows/zlibwapi.dll b/install/xbt/windows/zlibwapi.dll new file mode 100644 index 000000000..1c9092e7e Binary files /dev/null and b/install/xbt/windows/zlibwapi.dll differ diff --git a/install/xbt/windows/Установка.txt b/install/xbt/windows/Установка.txt new file mode 100644 index 000000000..466f5f2b9 --- /dev/null +++ b/install/xbt/windows/Установка.txt @@ -0,0 +1,2 @@ + ( - - cmd). + C:\ \"XBT Tracker".exe --install \ No newline at end of file diff --git a/install/xbt/xbt_tracker.conf b/install/xbt/xbt_tracker.conf new file mode 100644 index 000000000..affea3aa7 --- /dev/null +++ b/install/xbt/xbt_tracker.conf @@ -0,0 +1,47 @@ +mysql_host = localhost +mysql_database = forum +mysql_user = user +mysql_password = user + +auto_register = 0 +anonymous_announce = 0 +anonymous_scrape = 0 +anonymous_connect = 0 +full_scrape = 0 +listen_check = 0 + +gzip_debug = 0 +gzip_scrape = 1 +full_scrape = 0 + +announce_interval = 700 +clean_up_interval = 60 +read_config_interval = 60 +read_db_interval = 150 +scrape_interval = 0 +write_db_interval = 3 +read_files_interval = 2 + +table_files = bb_bt_torrents +table_users = bb_bt_users +table_files_users = bb_bt_tracker + +column_files_completed = complete_count +column_files_fid = topic_id +column_users_uid = user_id + +column_users_can_leech = case when bt.u_down_total>5368709120 and (bt.u_up_total+bt.u_up_bonus)greatest(5368709120,bt.u_down_total) then 0 when bt.u_up_total>5368709120 and bt.u_down_total>0 then floor((bt.u_up_total+bt.u_up_bonus)/0.3/bt.u_down_total)+1 when (bt.u_up_total+bt.u_up_bonus)>bt.u_down_total then 3 else 2 end + +column_files_dl_percent = (select case tor.tor_type when 1 then 0 when 2 then 50 else 100 end from bb_bt_torrents tor where tor.topic_id=bt.topic_id) as dl_percent + +log_announce = 0 +gdc = 1 +debug = 0 +#free_leech = 0 +log_access = 0 + +redirect_url = http://site.ru/forum/ +trust_ipv6 = 1 +pid_file = xbt_tracker.pid + diff --git a/upload/.htaccess b/upload/.htaccess new file mode 100644 index 000000000..b5e089499 --- /dev/null +++ b/upload/.htaccess @@ -0,0 +1,15 @@ +## Set charset server +AddDefaultCharset UTF-8 +## Set charset for php mb-functions +php_value mbstring.internal_encoding UTF-8 + +## RSS MOD +RewriteEngine On +RewriteRule ^rss.xml$ rss.php [L] + +## Access control + +deny from all + + +# Copyright (c) 2008-2011, Pandora. \ No newline at end of file diff --git a/upload/admin/.htaccess b/upload/admin/.htaccess new file mode 100644 index 000000000..c2c2cc412 --- /dev/null +++ b/upload/admin/.htaccess @@ -0,0 +1,8 @@ +AddDefaultCharset UTF-8 +#order allow deny +#deny from all +#allow from 127.0.0.1 + + +allow from all + \ No newline at end of file diff --git a/upload/admin/admin_attach_cp.php b/upload/admin/admin_attach_cp.php new file mode 100644 index 000000000..fc56a70a5 --- /dev/null +++ b/upload/admin/admin_attach_cp.php @@ -0,0 +1,592 @@ +'; + +for($i = 0; $i < count($view_types_text); $i++) +{ + $selected = ($view == $view_types[$i]) ? ' selected="selected"' : ''; + $select_view .= ''; +} +$select_view .= ''; + +if (count($mode_types_text) > 0) +{ + $select_sort_mode = ''; +} + +$select_sort_order = ''; + +$submit_change = ( isset($_POST['submit_change']) ) ? TRUE : FALSE; +$delete = ( isset($_POST['delete']) ) ? TRUE : FALSE; +$delete_id_list = get_var('delete_id_list', array(0)); + +$confirm = isset($_POST['confirm']); + +if ($confirm && sizeof($delete_id_list) > 0) +{ + $attachments = array(); + + delete_attachment(0, $delete_id_list); +} +else if ($delete && sizeof($delete_id_list) > 0) +{ + // Not confirmed, show confirmation message + $hidden_fields = ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + + for ($i = 0; $i < sizeof($delete_id_list); $i++) + { + $hidden_fields .= ''; + } + + print_confirmation(array( + 'FORM_ACTION' => "admin_attach_cp.php", + 'HIDDEN_FIELDS' => $hidden_fields, + )); +} + +// Assign Default Template Vars +$template->assign_vars(array( + 'S_VIEW_SELECT' => $select_view, + 'S_MODE_ACTION' => append_sid('admin_attach_cp.php')) +); + +if ($submit_change && $view == 'attachments') +{ + $attach_change_list = get_var('attach_id_list', array(0)); + $attach_comment_list = get_var('attach_comment_list', array('')); + $attach_download_count_list = get_var('attach_count_list', array(0)); + + // Generate correct Change List + $attachments = array(); + + for ($i = 0; $i < count($attach_change_list); $i++) + { + $attachments['_' . $attach_change_list[$i]]['comment'] = $attach_comment_list[$i]; + $attachments['_' . $attach_change_list[$i]]['download_count'] = $attach_download_count_list[$i]; + } + + $sql = 'SELECT * + FROM ' . BB_ATTACHMENTS_DESC . ' + ORDER BY attach_id'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t get Attachment informations', '', __LINE__, __FILE__, $sql); + } + + while ( $attachrow = DB()->sql_fetchrow($result) ) + { + if ( isset($attachments['_' . $attachrow['attach_id']]) ) + { + if ($attachrow['comment'] != $attachments['_' . $attachrow['attach_id']]['comment'] || $attachrow['download_count'] != $attachments['_' . $attachrow['attach_id']]['download_count']) + { + $sql = "UPDATE " . BB_ATTACHMENTS_DESC . " + SET comment = '" . attach_mod_sql_escape($attachments['_' . $attachrow['attach_id']]['comment']) . "', download_count = " . (int) $attachments['_' . $attachrow['attach_id']]['download_count'] . " + WHERE attach_id = " . (int) $attachrow['attach_id']; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Couldn\'t update Attachments Informations', '', __LINE__, __FILE__, $sql); + } + } + } + } + DB()->sql_freeresult($result); +} + +// Statistics +if ($view == 'stats') +{ + $upload_dir_size = get_formatted_dirsize(); + + if ($attach_config['attachment_quota'] >= 1048576) + { + $attachment_quota = round($attach_config['attachment_quota'] / 1048576 * 100) / 100 . ' ' . $lang['MB']; + } + else if ($attach_config['attachment_quota'] >= 1024) + { + $attachment_quota = round($attach_config['attachment_quota'] / 1024 * 100) / 100 . ' ' . $lang['KB']; + } + else + { + $attachment_quota = $attach_config['attachment_quota'] . ' ' . $lang['BYTES']; + } + + // number_of_attachments + $row = DB()->fetch_row(" + SELECT COUNT(*) AS total FROM ". BB_ATTACHMENTS_DESC ." + "); + $number_of_attachments = $number_of_posts = $row['total']; + + $number_of_pms = 0; + + // number_of_topics + $row = DB()->fetch_row(" + SELECT COUNT(*) AS topics FROM ". BB_TOPICS ." WHERE topic_attachment = 1 + "); + $number_of_topics = $row['topics']; + + // number_of_users + $row = DB()->fetch_row(" + SELECT COUNT(DISTINCT user_id_1) AS users FROM ". BB_ATTACHMENTS ." WHERE post_id != 0 + "); + $number_of_users = $row['users']; + + $template->assign_vars(array( + 'TPL_ATTACH_STATISTICS' => true, + + 'TOTAL_FILESIZE' => $upload_dir_size, + 'ATTACH_QUOTA' => $attachment_quota, + 'NUMBER_OF_ATTACHMENTS' => $number_of_attachments, + 'NUMBER_OF_POSTS' => $number_of_posts, + 'NUMBER_OF_PMS' => $number_of_pms, + 'NUMBER_OF_TOPICS' => $number_of_topics, + 'NUMBER_OF_USERS' => $number_of_users) + ); + +} + +// Search +if ($view == 'search') +{ + // Get Forums and Categories + //sf - add [, f.forum_parent] + $sql = "SELECT c.cat_title, c.cat_id, f.forum_name, f.forum_id, f.forum_parent + FROM " . BB_CATEGORIES . " c, " . BB_FORUMS . " f + WHERE f.cat_id = c.cat_id + ORDER BY c.cat_id, f.forum_order"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain forum_name/forum_id', '', __LINE__, __FILE__, $sql); + } + + $s_forums = ''; + while ($row = DB()->sql_fetchrow($result)) + { //sf + $s_forums .= ''; + + if( empty($list_cat[$row['cat_id']]) ) + { + $list_cat[$row['cat_id']] = $row['cat_title']; + } + } + + if( $s_forums != '' ) + { + $s_forums = '' . $s_forums; + + // Category to search + $s_categories = ''; + + foreach ($list_cat as $cat_id => $cat_title) + { + $s_categories .= ''; + } + } + else + { + message_die(GENERAL_MESSAGE, $lang['NO_SEARCHABLE_FORUMS']); + } + + $template->assign_vars(array( + 'TPL_ATTACH_SEARCH' => true, + + 'S_FORUM_OPTIONS' => $s_forums, + 'S_CATEGORY_OPTIONS' => $s_categories, + 'S_SORT_OPTIONS' => $select_sort_mode, + 'S_SORT_ORDER' => $select_sort_order) + ); +} + +// Username +if ($view == 'username') +{ + $template->assign_vars(array( + 'TPL_ATTACH_USER' => true, + + 'S_MODE_SELECT' => $select_sort_mode, + 'S_ORDER_SELECT' => $select_sort_order) + ); + $total_rows = 0; + bb_die('removed'); +} + +// Attachments +if ($view == 'attachments') +{ + $user_based = ($uid) ? TRUE : FALSE; + $search_based = (isset($_POST['search']) && $_POST['search']) ? TRUE : FALSE; + + $hidden_fields = ''; + + $template->assign_vars(array( + 'TPL_ATTACH_ATTACHMENTS' => true, + + 'S_MODE_SELECT' => $select_sort_mode, + 'S_ORDER_SELECT' => $select_sort_order) + ); + + $total_rows = 0; + + // Are we called from Username ? + if ($user_based) + { + $sql = "SELECT username + FROM " . BB_USERS . " + WHERE user_id = " . intval($uid); + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Error getting username', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + $username = $row['username']; + + $s_hidden = ''; + + $template->assign_block_vars('switch_user_based', array()); + + $template->assign_vars(array( + 'S_USER_HIDDEN' => $s_hidden, + 'L_STATISTICS_FOR_USER' => sprintf($lang['STATISTICS_FOR_USER'], $username)) + ); + + $sql = "SELECT attach_id + FROM " . BB_ATTACHMENTS . " + WHERE user_id_1 = " . intval($uid) . " + GROUP BY attach_id"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $attach_ids = DB()->sql_fetchrowset($result); + $num_attach_ids = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_attach_ids == 0) + { + message_die(GENERAL_MESSAGE, 'For some reason no Attachments are assigned to the User "' . $username . '".'); + } + + $total_rows = $num_attach_ids; + + $attach_id = array(); + + for ($j = 0; $j < $num_attach_ids; $j++) + { + $attach_id[] = intval($attach_ids[$j]['attach_id']); + } + + $sql = "SELECT a.* + FROM " . BB_ATTACHMENTS_DESC . " a + WHERE a.attach_id IN (" . implode(', ', $attach_id) . ") " . + $order_by; + + } + else if ($search_based) + { + // we are called from search + $attachments = search_attachments($order_by, $total_rows); + } + + if (!$search_based) + { + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $attachments = DB()->sql_fetchrowset($result); + $num_attach = DB()->num_rows($result); + DB()->sql_freeresult($result); + } + + if (sizeof($attachments) > 0) + { + for ($i = 0; $i < sizeof($attachments); $i++) + { + $delete_box = ''; + + for ($j = 0; $j < count($delete_id_list); $j++) + { + if ($delete_id_list[$j] == $attachments[$i]['attach_id']) + { + $delete_box = ''; + break; + } + } + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + // Is the Attachment assigned to more than one post ? + // If it's not assigned to any post, it's an private message thingy. ;) + $post_titles = array(); + + $sql = "SELECT * + FROM " . BB_ATTACHMENTS . " + WHERE attach_id = " . intval($attachments[$i]['attach_id']); + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $ids = DB()->sql_fetchrowset($result); + $num_ids = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($j = 0; $j < $num_ids; $j++) + { + if ($ids[$j]['post_id'] != 0) + { + $sql = "SELECT t.topic_title + FROM " . BB_TOPICS . " t, " . BB_POSTS . " p + WHERE p.post_id = " . intval($ids[$j]['post_id']) . " AND p.topic_id = t.topic_id + GROUP BY t.topic_id, t.topic_title"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query topic', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + $post_title = $row['topic_title']; + + if (strlen($post_title) > 32) + { + $post_title = substr($post_title, 0, 30) . '...'; + } + + $view_topic = append_sid(BB_ROOT . 'viewtopic.php?' . POST_POST_URL . '=' . $ids[$j]['post_id'] . '#' . $ids[$j]['post_id']); + + $post_titles[] = '' . $post_title . ''; + } + else + { + $post_titles[] = $lang['PRIVATE_MESSAGE']; + } + } + + $post_titles = implode('
', $post_titles); + + $hidden_field = ''; + + $template->assign_block_vars('attachrow', array( + 'ROW_NUMBER' => $i + ( @$_GET['start'] + 1 ), + 'ROW_CLASS' => $row_class, + + 'FILENAME' => htmlspecialchars($attachments[$i]['real_filename']), + 'COMMENT' => htmlspecialchars($attachments[$i]['comment']), + 'EXTENSION' => $attachments[$i]['extension'], + 'SIZE' => round(($attachments[$i]['filesize'] / MEGABYTE), 2), + 'DOWNLOAD_COUNT' => $attachments[$i]['download_count'], + 'POST_TIME' => bb_date($attachments[$i]['filetime']), + 'POST_TITLE' => $post_titles, + + 'S_DELETE_BOX' => $delete_box, + 'S_HIDDEN' => $hidden_field, + 'U_VIEW_ATTACHMENT' => append_sid(BB_ROOT . 'download.php?id=' . $attachments[$i]['attach_id'])) + ); + + } + } + + if (!$search_based && !$user_based) + { + if ($total_attachments == 0) + { + $sql = "SELECT attach_id FROM " . BB_ATTACHMENTS_DESC; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query Attachment Description Table', '', __LINE__, __FILE__, $sql); + } + + $total_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + } + } +} + +// Generate Pagination +if ($do_pagination && $total_rows > $bb_cfg['topics_per_page']) +{ + $pagination = generate_pagination('admin_attach_cp.php?view=' . $view . '&mode=' . $mode . '&order=' . $sort_order . '&uid=' . $uid, $total_rows, $bb_cfg['topics_per_page'], $start).' '; + + $template->assign_vars(array( + 'PAGINATION' => $pagination, + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], ( floor( $start / $bb_cfg['topics_per_page'] ) + 1 ), ceil( $total_rows / $bb_cfg['topics_per_page'] )), + )); +} + +print_page('admin_attach_cp.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_attachments.php b/upload/admin/admin_attachments.php new file mode 100644 index 000000000..e1c781125 --- /dev/null +++ b/upload/admin/admin_attachments.php @@ -0,0 +1,997 @@ +sql_query($sql)) +{ + message_die(GENERAL_ERROR, 'Could not find Attachment Config Table', '', __LINE__, __FILE__, $sql); +} + +while ($row = DB()->sql_fetchrow($result)) +{ + $config_name = $row['config_name']; + $config_value = $row['config_value']; + + $new_attach[$config_name] = get_var($config_name, trim($attach_config[$config_name])); + + if (!$size && !$submit && $config_name == 'max_filesize') + { + $size = ($attach_config[$config_name] >= 1048576) ? 'mb' : (($attach_config[$config_name] >= 1024) ? 'kb' : 'b'); + } + + if (!$quota_size && !$submit && $config_name == 'attachment_quota') + { + $quota_size = ($attach_config[$config_name] >= 1048576) ? 'mb' : (($attach_config[$config_name] >= 1024) ? 'kb' : 'b'); + } + + if (!$pm_size && !$submit && $config_name == 'max_filesize_pm') + { + $pm_size = ($attach_config[$config_name] >= 1048576) ? 'mb' : (($attach_config[$config_name] >= 1024) ? 'kb' : 'b'); + } + + if (!$submit && ($config_name == 'max_filesize' || $config_name == 'attachment_quota' || $config_name == 'max_filesize_pm')) + { + if ($new_attach[$config_name] >= 1048576) + { + $new_attach[$config_name] = round($new_attach[$config_name] / 1048576 * 100) / 100; + } + else if ($new_attach[$config_name] >= 1024) + { + $new_attach[$config_name] = round($new_attach[$config_name] / 1024 * 100) / 100; + } + } + + if ( $submit && ( $mode == 'manage' || $mode == 'cats') ) + { + if ($config_name == 'max_filesize') + { + $old = $new_attach[$config_name]; + $new_attach[$config_name] = ( $size == 'kb' ) ? round($new_attach[$config_name] * 1024) : ( ($size == 'mb') ? round($new_attach[$config_name] * 1048576) : $new_attach[$config_name] ); + } + + if ($config_name == 'attachment_quota') + { + $old = $new_attach[$config_name]; + $new_attach[$config_name] = ( $quota_size == 'kb' ) ? round($new_attach[$config_name] * 1024) : ( ($quota_size == 'mb') ? round($new_attach[$config_name] * 1048576) : $new_attach[$config_name] ); + } + + if ($config_name == 'max_filesize_pm') + { + $old = $new_attach[$config_name]; + $new_attach[$config_name] = ( $pm_size == 'kb' ) ? round($new_attach[$config_name] * 1024) : ( ($pm_size == 'mb') ? round($new_attach[$config_name] * 1048576) : $new_attach[$config_name] ); + } + + if ($config_name == 'ftp_server' || $config_name == 'ftp_path' || $config_name == 'download_path') + { + $value = trim($new_attach[$config_name]); + + if ($value[strlen($value)-1] == '/') + { + $value[strlen($value)-1] = ' '; + } + + $new_attach[$config_name] = trim($value); + + } + + if ($config_name == 'max_filesize') + { + $old_size = $attach_config[$config_name]; + $new_size = $new_attach[$config_name]; + + if ($old_size != $new_size) + { + // See, if we have a similar value of old_size in Mime Groups. If so, update these values. + $sql = 'UPDATE ' . BB_EXTENSION_GROUPS . ' + SET max_filesize = ' . (int) $new_size . ' + WHERE max_filesize = ' . (int) $old_size; + + if ( !($result_2 = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not update Extension Group informations', '', __LINE__, __FILE__, $sql); + } + + } + + $sql = "UPDATE " . BB_ATTACH_CONFIG . " + SET config_value = '" . attach_mod_sql_escape($new_attach[$config_name]) . "' + WHERE config_name = '" . attach_mod_sql_escape($config_name) . "'"; + } + else + { + $sql = "UPDATE " . BB_ATTACH_CONFIG . " + SET config_value = '" . attach_mod_sql_escape($new_attach[$config_name]) . "' + WHERE config_name = '" . attach_mod_sql_escape($config_name) . "'"; + } + + if( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Failed to update attachment configuration for ' . $config_name, '', __LINE__, __FILE__, $sql); + } + + if ($config_name == 'max_filesize' || $config_name == 'attachment_quota' || $config_name == 'max_filesize_pm') + { + $new_attach[$config_name] = $old; + } + } +} +DB()->sql_freeresult($result); + +// Clear cached config +CACHE('bb_cache')->rm('attach_config'); + +$select_size_mode = size_select('size', $size); +$select_quota_size_mode = size_select('quota_size', $quota_size); +$select_pm_size_mode = size_select('pm_size', $pm_size); + +// Search Imagick +if ($search_imagick) +{ + $imagick = ''; + + if (preg_match('/convert/i', $imagick)) + { + return true; + } + else if ($imagick != 'none') + { + if (!preg_match('/WIN/i', PHP_OS)) + { + $retval = @exec('whereis convert'); + $paths = explode(' ', $retval); + + if (is_array($paths)) + { + for ( $i=0; $i < sizeof($paths); $i++) + { + $path = basename($paths[$i]); + + if ($path == 'convert') + { + $imagick = $paths[$i]; + } + } + } + } + else if (preg_match('/WIN/i', PHP_OS)) + { + $path = 'c:/imagemagick/convert.exe'; + + if ( !@file_exists(@amod_realpath($path))) + { + $imagick = $path; + } + } + } + + if ( !@file_exists(@amod_realpath(trim($imagick)))) + { + $new_attach['img_imagick'] = trim($imagick); + } + else + { + $new_attach['img_imagick'] = ''; + } +} + +// Check Settings +if ($check_upload) +{ + // Some tests... + $attach_config = array(); + + $sql = 'SELECT * + FROM ' . BB_ATTACH_CONFIG; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not find Attachment Config Table', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < $num_rows; $i++) + { + $attach_config[$row[$i]['config_name']] = trim($row[$i]['config_value']); + } + + if ($attach_config['upload_dir'][0] == '/' || ($attach_config['upload_dir'][0] != '/' && $attach_config['upload_dir'][1] == ':')) + { + $upload_dir = $attach_config['upload_dir']; + } + else + { + $upload_dir = BB_ROOT . $attach_config['upload_dir']; + } + + $error = false; + + // Does the target directory exist, is it a directory and writeable. (only test if ftp upload is disabled) + if (intval($attach_config['allow_ftp_upload']) == 0) + { + if ( !@file_exists(@amod_realpath($upload_dir)) ) + { + $error = true; + $error_msg = sprintf($lang['DIRECTORY_DOES_NOT_EXIST'], $attach_config['upload_dir']) . '
'; + } + + if (!$error && !is_dir($upload_dir)) + { + $error = TRUE; + $error_msg = sprintf($lang['DIRECTORY_IS_NOT_A_DIR'], $attach_config['upload_dir']) . '
'; + } + + if (!$error) + { + if ( !($fp = @fopen($upload_dir . '/0_000000.000', 'w')) ) + { + $error = TRUE; + $error_msg = sprintf($lang['DIRECTORY_NOT_WRITEABLE'], $attach_config['upload_dir']) . '
'; + } + else + { + @fclose($fp); + unlink_attach($upload_dir . '/0_000000.000'); + } + } + } + else + { + // Check FTP Settings + $server = ( empty($attach_config['ftp_server']) ) ? 'localhost' : $attach_config['ftp_server']; + + $conn_id = @ftp_connect($server); + + if (!$conn_id) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_CONNECT'], $server) . '
'; + } + + $login_result = @ftp_login($conn_id, $attach_config['ftp_user'], $attach_config['ftp_pass']); + + if ( (!$login_result) && (!$error) ) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_LOGIN'], $attach_config['ftp_user']) . '
'; + } + + if (!@ftp_pasv($conn_id, intval($attach_config['ftp_pasv_mode']))) + { + $error = TRUE; + $error_msg = $lang['FTP_ERROR_PASV_MODE']; + } + + if (!$error) + { + // Check Upload + $tmpfname = @tempnam('/tmp', 't0000'); + + @unlink($tmpfname); // unlink for safety on php4.0.3+ + + $fp = @fopen($tmpfname, 'w'); + + @fwrite($fp, 'test'); + + @fclose($fp); + + $result = @ftp_chdir($conn_id, $attach_config['ftp_path']); + + if (!$result) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_PATH'], $attach_config['ftp_path']) . '
'; + } + else + { + $res = @ftp_put($conn_id, 't0000', $tmpfname, FTP_ASCII); + + if (!$res) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_UPLOAD'], $attach_config['ftp_path']) . '
'; + } + else + { + $res = @ftp_delete($conn_id, 't0000'); + + if (!$res) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_DELETE'], $attach_config['ftp_path']) . '
'; + } + } + } + + @ftp_quit($conn_id); + + @unlink($tmpfname); + } + } + + if (!$error) + { + message_die(GENERAL_MESSAGE, $lang['TEST_SETTINGS_SUCCESSFUL'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', '')); + } +} + +// Management +if ($submit && $mode == 'manage') +{ + if (!$error) + { + message_die(GENERAL_MESSAGE, $lang['ATTACH_CONFIG_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', '')); + } +} + +if ($mode == 'manage') +{ + $yes_no_switches = array('disable_mod', 'allow_pm_attach', 'allow_ftp_upload', 'display_order', 'ftp_pasv_mode'); + + for ($i = 0; $i < sizeof($yes_no_switches); $i++) + { + eval("\$" . $yes_no_switches[$i] . "_yes = ( \$new_attach['" . $yes_no_switches[$i] . "'] != '0' ) ? 'checked=\"checked\"' : '';"); + eval("\$" . $yes_no_switches[$i] . "_no = ( \$new_attach['" . $yes_no_switches[$i] . "'] == '0' ) ? 'checked=\"checked\"' : '';"); + } + + if (!function_exists('ftp_connect')) + { + $template->assign_block_vars('switch_no_ftp', array()); + } + else + { + $template->assign_block_vars('switch_ftp', array()); + } + + $template->assign_vars(array( + 'TPL_ATTACH_MANAGE' => true, + + 'L_MANAGE_TITLE' => $lang['ATTACH_SETTINGS'], + 'L_MANAGE_EXPLAIN' => $lang['MANAGE_ATTACHMENTS_EXPLAIN'], + 'L_ATTACHMENT_SETTINGS' => $lang['ATTACH_SETTINGS'], + 'L_ATTACHMENT_FILESIZE_SETTINGS' => $lang['ATTACH_FILESIZE_SETTINGS'], + 'L_ATTACHMENT_NUMBER_SETTINGS' => $lang['ATTACH_NUMBER_SETTINGS'], + 'L_ATTACHMENT_OPTIONS_SETTINGS' => $lang['ATTACH_OPTIONS_SETTINGS'], + 'L_ATTACHMENT_FTP_SETTINGS' => $lang['FTP_INFO'], + 'L_NO_FTP_EXTENSIONS' => $lang['NO_FTP_EXTENSIONS_INSTALLED'], + 'L_UPLOAD_DIR' => $lang['UPLOAD_DIRECTORY'], + 'L_UPLOAD_DIR_EXPLAIN' => $lang['UPLOAD_DIRECTORY_EXPLAIN'], + 'L_ATTACHMENT_IMG_PATH' => $lang['ATTACH_IMG_PATH'], + 'L_IMG_PATH_EXPLAIN' => $lang['ATTACH_IMG_PATH_EXPLAIN'], + 'L_ATTACHMENT_TOPIC_ICON' => $lang['ATTACH_TOPIC_ICON'], + 'L_TOPIC_ICON_EXPLAIN' => $lang['ATTACH_TOPIC_ICON_EXPLAIN'], + 'L_DISPLAY_ORDER' => $lang['ATTACH_DISPLAY_ORDER'], + 'L_DISPLAY_ORDER_EXPLAIN' => $lang['ATTACH_DISPLAY_ORDER_EXPLAIN'], + 'L_MAX_FILESIZE' => $lang['MAX_FILESIZE_ATTACH'], + 'L_MAX_FILESIZE_EXPLAIN' => $lang['MAX_FILESIZE_ATTACH_EXPLAIN'], + 'L_PM_ATTACH' => $lang['PM_ATTACHMENTS'], + 'L_PM_ATTACH_EXPLAIN' => $lang['PM_ATTACHMENTS_EXPLAIN'], + 'L_ATTACHMENT_FTP_PATH' => $lang['ATTACH_FTP_PATH'], + 'L_ATTACHMENT_FTP_USER' => $lang['FTP_USERNAME'], + 'L_ATTACHMENT_FTP_PASS' => $lang['FTP_PASSWORD'], + 'L_ATTACHMENT_FTP_PATH_EXPLAIN' => $lang['ATTACH_FTP_PATH_EXPLAIN'], + 'L_ATTACHMENT_FTP_SERVER' => $lang['FTP_SERVER'], + 'L_ATTACHMENT_FTP_SERVER_EXPLAIN' => $lang['FTP_SERVER_EXPLAIN'], + 'L_DOWNLOAD_PATH' => $lang['FTP_DOWNLOAD_PATH'], + 'L_DOWNLOAD_PATH_EXPLAIN' => $lang['FTP_DOWNLOAD_PATH_EXPLAIN'], + + 'S_ATTACH_ACTION' => append_sid('admin_attachments.php?mode=manage'), + 'S_FILESIZE' => $select_size_mode, + 'S_FILESIZE_QUOTA' => $select_quota_size_mode, + 'S_FILESIZE_PM' => $select_pm_size_mode, + 'S_DEFAULT_UPLOAD_LIMIT' => default_quota_limit_select('default_upload_quota', intval(trim($new_attach['default_upload_quota']))), + 'S_DEFAULT_PM_LIMIT' => default_quota_limit_select('default_pm_quota', intval(trim($new_attach['default_pm_quota']))), + + 'UPLOAD_DIR' => $new_attach['upload_dir'], + 'ATTACHMENT_IMG_PATH' => $new_attach['upload_img'], + 'TOPIC_ICON' => $new_attach['topic_icon'], + 'MAX_FILESIZE' => $new_attach['max_filesize'], + 'ATTACHMENT_QUOTA' => $new_attach['attachment_quota'], + 'MAX_FILESIZE_PM' => $new_attach['max_filesize_pm'], + 'MAX_ATTACHMENTS' => $new_attach['max_attachments'], + 'MAX_ATTACHMENTS_PM' => $new_attach['max_attachments_pm'], + 'FTP_SERVER' => $new_attach['ftp_server'], + 'FTP_PATH' => $new_attach['ftp_path'], + 'FTP_USER' => $new_attach['ftp_user'], + 'FTP_PASS' => $new_attach['ftp_pass'], + 'DOWNLOAD_PATH' => $new_attach['download_path'], + 'DISABLE_MOD_YES' => $disable_mod_yes, + 'DISABLE_MOD_NO' => $disable_mod_no, + 'PM_ATTACH_YES' => $allow_pm_attach_yes, + 'PM_ATTACH_NO' => $allow_pm_attach_no, + 'FTP_UPLOAD_YES' => $allow_ftp_upload_yes, + 'FTP_UPLOAD_NO' => $allow_ftp_upload_no, + 'FTP_PASV_MODE_YES' => $ftp_pasv_mode_yes, + 'FTP_PASV_MODE_NO' => $ftp_pasv_mode_no, + 'DISPLAY_ORDER_ASC' => $display_order_yes, + 'DISPLAY_ORDER_DESC' => $display_order_no, + )); +} + +if ($submit && $mode == 'cats') +{ + if (!$error) + { + message_die(GENERAL_MESSAGE, $lang['ATTACH_CONFIG_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', '')); + } +} + +if ($mode == 'cats') +{ + $s_assigned_group_images = $lang['NONE']; + $s_assigned_group_streams = $lang['NONE']; + $s_assigned_group_flash = $lang['NONE']; + + $sql = 'SELECT group_name, cat_id + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE cat_id > 0 + ORDER BY cat_id'; + + $s_assigned_group_images = array(); + $s_assigned_group_streams = array(); + $s_assigned_group_flash = array(); + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Group Names from ' . BB_EXTENSION_GROUPS, '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < sizeof($row); $i++) + { + if ($row[$i]['cat_id'] == IMAGE_CAT) + { + $s_assigned_group_images[] = $row[$i]['group_name']; + } + else if ($row[$i]['cat_id'] == STREAM_CAT) + { + $s_assigned_group_streams[] = $row[$i]['group_name']; + } + else if ($row[$i]['cat_id'] == SWF_CAT) + { + $s_assigned_group_flash[] = $row[$i]['group_name']; + } + } + + $display_inlined_yes = ( $new_attach['img_display_inlined'] != '0' ) ? 'checked="checked"' : ''; + $display_inlined_no = ( $new_attach['img_display_inlined'] == '0' ) ? 'checked="checked"' : ''; + + $create_thumbnail_yes = ( $new_attach['img_create_thumbnail'] != '0' ) ? 'checked="checked"' : ''; + $create_thumbnail_no = ( $new_attach['img_create_thumbnail'] == '0' ) ? 'checked="checked"' : ''; + + $use_gd2_yes = ( $new_attach['use_gd2'] != '0' ) ? 'checked="checked"' : ''; + $use_gd2_no = ( $new_attach['use_gd2'] == '0' ) ? 'checked="checked"' : ''; + + // Check Thumbnail Support + if (!is_imagick() && !@extension_loaded('gd')) + { + $new_attach['img_create_thumbnail'] = '0'; + } + else + { + $template->assign_block_vars('switch_thumbnail_support', array()); + } + + $template->assign_vars(array( + 'TPL_ATTACH_SPECIAL_CATEGORIES' => true, + + 'L_MANAGE_CAT_TITLE' => $lang['MANAGE_CATEGORIES'], + 'L_MANAGE_CAT_EXPLAIN' => $lang['MANAGE_CATEGORIES_EXPLAIN'], + 'L_SETTINGS_CAT_STREAM' => $lang['SETTINGS_CAT_STREAMS'], + 'L_CREATE_THUMBNAIL' => $lang['IMAGE_CREATE_THUMBNAIL'], + 'L_CREATE_THUMBNAIL_EXPLAIN' => $lang['IMAGE_CREATE_THUMBNAIL_EXPLAIN'], + 'L_MIN_THUMB_FILESIZE' => $lang['IMAGE_MIN_THUMB_FILESIZE'], + 'L_MIN_THUMB_FILESIZE_EXPLAIN' => $lang['IMAGE_MIN_THUMB_FILESIZE_EXPLAIN'], + 'L_IMAGICK_PATH' => $lang['IMAGE_IMAGICK_PATH'], + 'L_IMAGICK_PATH_EXPLAIN' => $lang['IMAGE_IMAGICK_PATH_EXPLAIN'], + 'L_SEARCH_IMAGICK' => $lang['IMAGE_SEARCH_IMAGICK'], + + 'IMAGE_MAX_HEIGHT' => $new_attach['img_max_height'], + 'IMAGE_MAX_WIDTH' => $new_attach['img_max_width'], + + 'IMAGE_LINK_HEIGHT' => $new_attach['img_link_height'], + 'IMAGE_LINK_WIDTH' => $new_attach['img_link_width'], + 'IMAGE_MIN_THUMB_FILESIZE' => $new_attach['img_min_thumb_filesize'], + 'IMAGE_IMAGICK_PATH' => $new_attach['img_imagick'], + + 'DISPLAY_INLINED_YES' => $display_inlined_yes, + 'DISPLAY_INLINED_NO' => $display_inlined_no, + + 'CREATE_THUMBNAIL_YES' => $create_thumbnail_yes, + 'CREATE_THUMBNAIL_NO' => $create_thumbnail_no, + + 'USE_GD2_YES' => $use_gd2_yes, + 'USE_GD2_NO' => $use_gd2_no, + + 'S_ASSIGNED_GROUP_IMAGES' => implode(', ', $s_assigned_group_images), + 'S_ATTACH_ACTION' => append_sid('admin_attachments.php?mode=cats')) + ); +} + +// Check Cat Settings +if ($check_image_cat) +{ + // Some tests... + $attach_config = array(); + + $sql = 'SELECT * + FROM ' . BB_ATTACH_CONFIG; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not find Attachment Config Table', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < $num_rows; $i++) + { + $attach_config[$row[$i]['config_name']] = trim($row[$i]['config_value']); + } + + if ($attach_config['upload_dir'][0] == '/' || ($attach_config['upload_dir'][0] != '/' && $attach_config['upload_dir'][1] == ':')) + { + $upload_dir = $attach_config['upload_dir']; + } + else + { + $upload_dir = BB_ROOT . $attach_config['upload_dir']; + } + + $upload_dir = $upload_dir . '/' . THUMB_DIR; + + $error = false; + + // Does the target directory exist, is it a directory and writeable. (only test if ftp upload is disabled) + if (intval($attach_config['allow_ftp_upload']) == 0 && intval($attach_config['img_create_thumbnail']) == 1) + { + if ( !@file_exists(@amod_realpath($upload_dir)) ) + { + @mkdir($upload_dir, 0755); + @chmod($upload_dir, 0777); + + if ( !@file_exists(@amod_realpath($upload_dir)) ) + { + $error = TRUE; + $error_msg = sprintf($lang['DIRECTORY_DOES_NOT_EXIST'], $upload_dir) . '
'; + } + + } + + if (!$error && !is_dir($upload_dir)) + { + $error = TRUE; + $error_msg = sprintf($lang['DIRECTORY_IS_NOT_A_DIR'], $upload_dir) . '
'; + } + + if (!$error) + { + if ( !($fp = @fopen($upload_dir . '/0_000000.000', 'w')) ) + { + $error = TRUE; + $error_msg = sprintf($lang['DIRECTORY_NOT_WRITEABLE'], $upload_dir) . '
'; + } + else + { + @fclose($fp); + @unlink($upload_dir . '/0_000000.000'); + } + } + } + else if (intval($attach_config['allow_ftp_upload']) && intval($attach_config['img_create_thumbnail'])) + { + // Check FTP Settings + $server = ( empty($attach_config['ftp_server']) ) ? 'localhost' : $attach_config['ftp_server']; + + $conn_id = @ftp_connect($server); + + if (!$conn_id) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_CONNECT'], $server) . '
'; + } + + $login_result = @ftp_login($conn_id, $attach_config['ftp_user'], $attach_config['ftp_pass']); + + if (!$login_result && !$error) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_LOGIN'], $attach_config['ftp_user']) . '
'; + } + + if (!@ftp_pasv($conn_id, intval($attach_config['ftp_pasv_mode']))) + { + $error = TRUE; + $error_msg = $lang['FTP_ERROR_PASV_MODE']; + } + + if (!$error) + { + // Check Upload + $tmpfname = @tempnam('/tmp', 't0000'); + + @unlink($tmpfname); // unlink for safety on php4.0.3+ + + $fp = @fopen($tmpfname, 'w'); + + @fwrite($fp, 'test'); + + @fclose($fp); + + $result = @ftp_chdir($conn_id, $attach_config['ftp_path'] . '/' . THUMB_DIR); + + if (!$result) + { + @ftp_mkdir($conn_id, $attach_config['ftp_path'] . '/' . THUMB_DIR); + } + + $result = @ftp_chdir($conn_id, $attach_config['ftp_path'] . '/' . THUMB_DIR); + + if (!$result) + { + + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_PATH'], $attach_config['ftp_path'] . '/' . THUMB_DIR) . '
'; + } + else + { + $res = @ftp_put($conn_id, 't0000', $tmpfname, FTP_ASCII); + + if (!$res) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_UPLOAD'], $attach_config['ftp_path'] . '/' . THUMB_DIR) . '
'; + } + else + { + $res = @ftp_delete($conn_id, 't0000'); + + if (!$res) + { + $error = TRUE; + $error_msg = sprintf($lang['FTP_ERROR_DELETE'], $attach_config['ftp_path'] . '/' . THUMB_DIR) . '
'; + } + } + } + + @ftp_quit($conn_id); + + @unlink($tmpfname); + } + } + + if (!$error) + { + message_die(GENERAL_MESSAGE, $lang['TEST_SETTINGS_SUCCESSFUL'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', '')); + } +} + +// Quota Limit Settings +if ($submit && $mode == 'quota') +{ + // Change Quota Limit + $quota_change_list = get_var('quota_change_list', array(0)); + $quota_desc_list = get_var('quota_desc_list', array('')); + $filesize_list = get_var('max_filesize_list', array(0)); + $size_select_list = get_var('size_select_list', array('')); + + $allowed_list = array(); + + for ($i = 0; $i < sizeof($quota_change_list); $i++) + { + $filesize_list[$i] = ( $size_select_list[$i] == 'kb' ) ? round($filesize_list[$i] * 1024) : ( ($size_select_list[$i] == 'mb') ? round($filesize_list[$i] * 1048576) : $filesize_list[$i] ); + + $sql = 'UPDATE ' . BB_QUOTA_LIMITS . " + SET quota_desc = '" . attach_mod_sql_escape($quota_desc_list[$i]) . "', quota_limit = " . (int) $filesize_list[$i] . " + WHERE quota_limit_id = " . (int) $quota_change_list[$i]; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t update Quota Limits', '', __LINE__, __FILE__, $sql); + } + } + + // Delete Quota Limits + $quota_id_list = get_var('quota_id_list', array(0)); + + $quota_id_sql = implode(', ', $quota_id_list); + + if ($quota_id_sql != '') + { + $sql = 'DELETE + FROM ' . BB_QUOTA_LIMITS . ' + WHERE quota_limit_id IN (' . $quota_id_sql . ')'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not delete Quota Limits', '', __LINE__, __FILE__, $sql); + } + + // Delete Quotas linked to this setting + $sql = 'DELETE + FROM ' . BB_QUOTA . ' + WHERE quota_limit_id IN (' . $quota_id_sql . ')'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not delete Quotas', '', __LINE__, __FILE__, $sql); + } + } + + // Add Quota Limit ? + $quota_desc = get_var('quota_description', ''); + $filesize = get_var('add_max_filesize', 0); + $size_select = get_var('add_size_select', ''); + $add = ( isset($_POST['add_quota_check']) ) ? TRUE : FALSE; + + if ($quota_desc != '' && $add) + { + // check Quota Description + $sql = 'SELECT quota_desc + FROM ' . BB_QUOTA_LIMITS; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query Quota Limits Table', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ( $num_rows > 0 ) + { + for ($i = 0; $i < $num_rows; $i++) + { + if ($row[$i]['quota_desc'] == $quota_desc) + { + $error = TRUE; + if( isset($error_msg) ) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['QUOTA_LIMIT_EXIST'], $extension_group); + } + } + } + + if (!$error) + { + $filesize = ( $size_select == 'kb' ) ? round($filesize * 1024) : ( ($size_select == 'mb') ? round($filesize * 1048576) : $filesize ); + + $sql = "INSERT INTO " . BB_QUOTA_LIMITS . " (quota_desc, quota_limit) + VALUES ('" . attach_mod_sql_escape($quota_desc) . "', " . (int) $filesize . ")"; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not add Quota Limit', '', __LINE__, __FILE__, $sql); + } + } + + } + + if (!$error) + { + $message = $lang['ATTACH_CONFIG_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + } + +} + +if ($mode == 'quota') +{ + $max_add_filesize = $attach_config['max_filesize']; + $size = ($max_add_filesize >= 1048576) ? 'mb' : ( ($max_add_filesize >= 1024) ? 'kb' : 'b' ); + + if ($max_add_filesize >= 1048576) + { + $max_add_filesize = round($max_add_filesize / 1048576 * 100) / 100; + } + else if ( $max_add_filesize >= 1024) + { + $max_add_filesize = round($max_add_filesize / 1024 * 100) / 100; + } + + $template->assign_vars(array( + 'TPL_ATTACH_QUOTA' => true, + + 'L_MANAGE_QUOTAS_TITLE' => $lang['MANAGE_QUOTAS'], + 'L_SIZE' => $lang['MAX_FILESIZE_ATTACH'], + 'MAX_FILESIZE' => $max_add_filesize, + + 'S_FILESIZE' => size_select('add_size_select', $size), + + 'S_ATTACH_ACTION' => append_sid('admin_attachments.php?mode=quota')) + ); + + $sql = "SELECT * FROM " . BB_QUOTA_LIMITS . " ORDER BY quota_limit DESC"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get quota limits', '', __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < sizeof($rows); $i++) + { + $size_format = ($rows[$i]['quota_limit'] >= 1048576) ? 'mb' : ( ($rows[$i]['quota_limit'] >= 1024) ? 'kb' : 'b' ); + + if ( $rows[$i]['quota_limit'] >= 1048576) + { + $rows[$i]['quota_limit'] = round($rows[$i]['quota_limit'] / 1048576 * 100) / 100; + } + else if($rows[$i]['quota_limit'] >= 1024) + { + $rows[$i]['quota_limit'] = round($rows[$i]['quota_limit'] / 1024 * 100) / 100; + } + + $template->assign_block_vars('limit_row', array( + 'QUOTA_NAME' => $rows[$i]['quota_desc'], + 'QUOTA_ID' => $rows[$i]['quota_limit_id'], + 'S_FILESIZE' => size_select('size_select_list[]', $size_format), + 'U_VIEW' => append_sid("admin_attachments.php?mode=$mode&e_mode=view_quota&quota_id=" . $rows[$i]['quota_limit_id']), + 'MAX_FILESIZE' => $rows[$i]['quota_limit']) + ); + } +} + +if ($mode == 'quota' && $e_mode == 'view_quota') +{ + $quota_id = get_var('quota_id', 0); + + if (!$quota_id) + { + message_die(GENERAL_MESSAGE, 'Invalid Call'); + } + + $template->assign_block_vars('switch_quota_limit_desc', array()); + + $sql = "SELECT * FROM " . BB_QUOTA_LIMITS . " WHERE quota_limit_id = " . (int) $quota_id . " LIMIT 1"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get quota limits', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $template->assign_vars(array( + 'L_QUOTA_LIMIT_DESC' => $row['quota_desc'], + )); + + $sql = 'SELECT q.user_id, u.username, q.quota_type + FROM ' . BB_QUOTA . ' q, ' . BB_USERS . ' u + WHERE q.quota_limit_id = ' . (int) $quota_id . ' + AND q.user_id <> 0 + AND q.user_id = u.user_id'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get quota limits', '', __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < $num_rows; $i++) + { + if ($rows[$i]['quota_type'] == QUOTA_UPLOAD_LIMIT) + { + $template->assign_block_vars('users_upload_row', array( + 'USER_ID' => $rows[$i]['user_id'], + 'USERNAME' => $rows[$i]['username']) + ); + } + else if ($rows[$i]['quota_type'] == QUOTA_PM_LIMIT) + { + $template->assign_block_vars('users_pm_row', array( + 'USER_ID' => $rows[$i]['user_id'], + 'USERNAME' => $rows[$i]['username']) + ); + } + } + + $sql = 'SELECT q.group_id, g.group_name, q.quota_type + FROM ' . BB_QUOTA . ' q, ' . BB_GROUPS . ' g + WHERE q.quota_limit_id = ' . (int) $quota_id . ' + AND q.group_id <> 0 + AND q.group_id = g.group_id'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get quota limits', '', __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < $num_rows; $i++) + { + if ($rows[$i]['quota_type'] == QUOTA_UPLOAD_LIMIT) + { + $template->assign_block_vars('groups_upload_row', array( + 'GROUP_ID' => $rows[$i]['group_id'], + 'GROUPNAME' => $rows[$i]['group_name']) + ); + } + else if ($rows[$i]['quota_type'] == QUOTA_PM_LIMIT) + { + $template->assign_block_vars('groups_pm_row', array( + 'GROUP_ID' => $rows[$i]['group_id'], + 'GROUPNAME' => $rows[$i]['group_name']) + ); + } + } +} + +if ($error) +{ + $template->assign_vars(array('ERROR_MESSAGE' => $error_msg)); +} + +print_page('admin_attachments.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_board.php b/upload/admin/admin_board.php new file mode 100644 index 000000000..92ed102d2 --- /dev/null +++ b/upload/admin/admin_board.php @@ -0,0 +1,178 @@ +sql_query($sql)) +{ + message_die(CRITICAL_ERROR, "Could not query config information in admin_board", "", __LINE__, __FILE__, $sql); +} +else +{ + while( $row = DB()->sql_fetchrow($result) ) + { + $config_name = $row['config_name']; + $config_value = $row['config_value']; + $default_config[$config_name] = $config_value; + + $new[$config_name] = isset($_POST[$config_name]) ? $_POST[$config_name] : $default_config[$config_name]; + + // Attempt to prevent a mistake with this value. + if ($config_name == 'avatar_path') + { + $new['avatar_path'] = trim($new['avatar_path']); + if (strstr($new['avatar_path'], "\0") || !is_dir(BB_ROOT . $new['avatar_path']) || !is_writable(BB_ROOT . $new['avatar_path'])) + { + $new['avatar_path'] = $default_config['avatar_path']; + } + } + + if (isset($_POST['submit']) && $row['config_value'] != $new[$config_name]) + { + bb_update_config(array($config_name => $new[$config_name])); + } + } + + if( isset($_POST['submit']) ) + { + $message = $lang['CONFIG_UPDATED'] . "

" . sprintf($lang['CLICK_RETURN_CONFIG'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + } +} + +$lang_select = language_select($new['default_lang'], 'default_lang', "language"); +$timezone_select = tz_select($new['board_timezone'], 'board_timezone'); + +$disable_board_yes = ( $new['board_disable'] ) ? "checked=\"checked\"" : ""; +$disable_board_no = ( !$new['board_disable'] ) ? "checked=\"checked\"" : ""; + +$bbcode_yes = ( $new['allow_bbcode'] ) ? "checked=\"checked\"" : ""; +$bbcode_no = ( !$new['allow_bbcode'] ) ? "checked=\"checked\"" : ""; + +$activation_none = ( $new['require_activation'] == USER_ACTIVATION_NONE ) ? "checked=\"checked\"" : ""; +$activation_user = ( $new['require_activation'] == USER_ACTIVATION_SELF ) ? "checked=\"checked\"" : ""; +$activation_admin = ( $new['require_activation'] == USER_ACTIVATION_ADMIN ) ? "checked=\"checked\"" : ""; + +$confirm_yes = ($new['enable_confirm']) ? 'checked="checked"' : ''; +$confirm_no = (!$new['enable_confirm']) ? 'checked="checked"' : ''; + +$allow_autologin_yes = ($new['allow_autologin']) ? 'checked="checked"' : ''; +$allow_autologin_no = (!$new['allow_autologin']) ? 'checked="checked"' : ''; + +$board_email_form_yes = ( $new['board_email_form'] ) ? "checked=\"checked\"" : ""; +$board_email_form_no = ( !$new['board_email_form'] ) ? "checked=\"checked\"" : ""; + +$privmsg_on = ( !$new['privmsg_disable'] ) ? "checked=\"checked\"" : ""; +$privmsg_off = ( $new['privmsg_disable'] ) ? "checked=\"checked\"" : ""; + +$prune_yes = ( $new['prune_enable'] ) ? "checked=\"checked\"" : ""; +$prune_no = ( !$new['prune_enable'] ) ? "checked=\"checked\"" : ""; + +$smile_yes = ( $new['allow_smilies'] ) ? "checked=\"checked\"" : ""; +$smile_no = ( !$new['allow_smilies'] ) ? "checked=\"checked\"" : ""; + +$sig_yes = ( $new['allow_sig'] ) ? "checked=\"checked\"" : ""; +$sig_no = ( !$new['allow_sig'] ) ? "checked=\"checked\"" : ""; + +$namechange_yes = ( $new['allow_namechange'] ) ? "checked=\"checked\"" : ""; +$namechange_no = ( !$new['allow_namechange'] ) ? "checked=\"checked\"" : ""; + +$avatars_local_yes = ( $new['allow_avatar_local'] ) ? "checked=\"checked\"" : ""; +$avatars_local_no = ( !$new['allow_avatar_local'] ) ? "checked=\"checked\"" : ""; +$avatars_remote_yes = ( $new['allow_avatar_remote'] ) ? "checked=\"checked\"" : ""; +$avatars_remote_no = ( !$new['allow_avatar_remote'] ) ? "checked=\"checked\"" : ""; +$avatars_upload_yes = ( $new['allow_avatar_upload'] ) ? "checked=\"checked\"" : ""; +$avatars_upload_no = ( !$new['allow_avatar_upload'] ) ? "checked=\"checked\"" : ""; + +$smtp_yes = ( $new['smtp_delivery'] ) ? "checked=\"checked\"" : ""; +$smtp_no = ( !$new['smtp_delivery'] ) ? "checked=\"checked\"" : ""; + +// +// Escape any quotes in the site description for proper display in the text +// box on the admin page +// +$template->assign_vars(array( + "S_CONFIG_ACTION"=> append_sid("admin_board.php"), + + "SITENAME" => htmlCHR($new['sitename']), + "CONFIG_SITE_DESCRIPTION" => htmlCHR($new['site_desc']), + "S_DISABLE_BOARD_YES" => $disable_board_yes, + "S_DISABLE_BOARD_NO" => $disable_board_no, + "ACTIVATION_NONE" => USER_ACTIVATION_NONE, + "ACTIVATION_NONE_CHECKED" => $activation_none, + "ACTIVATION_USER" => USER_ACTIVATION_SELF, + "ACTIVATION_USER_CHECKED" => $activation_user, + "ACTIVATION_ADMIN" => USER_ACTIVATION_ADMIN, + "ACTIVATION_ADMIN_CHECKED" => $activation_admin, + "CONFIRM_ENABLE" => $confirm_yes, + "CONFIRM_DISABLE" => $confirm_no, + "ALLOW_AUTOLOGIN_YES" => $allow_autologin_yes, + "ALLOW_AUTOLOGIN_NO" => $allow_autologin_no, + "AUTOLOGIN_TIME" => (int) $new['max_autologin_time'], + "BOARD_EMAIL_FORM_ENABLE" => $board_email_form_yes, + "BOARD_EMAIL_FORM_DISABLE" => $board_email_form_no, + "MAX_POLL_OPTIONS" => $new['max_poll_options'], + "FLOOD_INTERVAL" => $new['flood_interval'], + "TOPICS_PER_PAGE" => $new['topics_per_page'], + "POSTS_PER_PAGE" => $new['posts_per_page'], + "HOT_TOPIC" => $new['hot_threshold'], + "LANG_SELECT" => $lang_select, + "DEFAULT_DATEFORMAT" => $new['default_dateformat'], + "TIMEZONE_SELECT" => $timezone_select, + "S_PRIVMSG_ENABLED" => $privmsg_on, + "S_PRIVMSG_DISABLED" => $privmsg_off, + "INBOX_LIMIT" => $new['max_inbox_privmsgs'], + "SENTBOX_LIMIT" => $new['max_sentbox_privmsgs'], + "SAVEBOX_LIMIT" => $new['max_savebox_privmsgs'], + "MAX_LOGIN_ATTEMPTS" => $new['max_login_attempts'], + "LOGIN_RESET_TIME" => $new['login_reset_time'], + "PRUNE_YES" => $prune_yes, + "PRUNE_NO" => $prune_no, + "BBCODE_YES" => $bbcode_yes, + "BBCODE_NO" => $bbcode_no, + "SMILE_YES" => $smile_yes, + "SMILE_NO" => $smile_no, + "SIG_YES" => $sig_yes, + "SIG_NO" => $sig_no, + "SIG_SIZE" => $new['max_sig_chars'], + "NAMECHANGE_YES" => $namechange_yes, + "NAMECHANGE_NO" => $namechange_no, + "AVATARS_LOCAL_YES" => $avatars_local_yes, + "AVATARS_LOCAL_NO" => $avatars_local_no, + "AVATARS_REMOTE_YES" => $avatars_remote_yes, + "AVATARS_REMOTE_NO" => $avatars_remote_no, + "AVATARS_UPLOAD_YES" => $avatars_upload_yes, + "AVATARS_UPLOAD_NO" => $avatars_upload_no, + "AVATAR_FILESIZE" => $new['avatar_filesize'], + "AVATAR_MAX_HEIGHT" => $new['avatar_max_height'], + "AVATAR_MAX_WIDTH" => $new['avatar_max_width'], + "AVATAR_PATH" => $new['avatar_path'], + "AVATAR_GALLERY_PATH" => $new['avatar_gallery_path'], + "SMILIES_PATH" => $new['smilies_path'], + "INBOX_PRIVMSGS" => $new['max_inbox_privmsgs'], + "SENTBOX_PRIVMSGS" => $new['max_sentbox_privmsgs'], + "SAVEBOX_PRIVMSGS" => $new['max_savebox_privmsgs'], + "EMAIL_FROM" => $new['board_email'], + "EMAIL_SIG" => $new['board_email_sig'], + "SMTP_YES" => $smtp_yes, + "SMTP_NO" => $smtp_no, + "SMTP_HOST" => $new['smtp_host'], + "SMTP_USERNAME" => $new['smtp_username'], + "SMTP_PASSWORD" => $new['smtp_password']) +); + +print_page('admin_board.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_bt_forum_cfg.php b/upload/admin/admin_bt_forum_cfg.php new file mode 100644 index 000000000..892ca642c --- /dev/null +++ b/upload/admin/admin_bt_forum_cfg.php @@ -0,0 +1,157 @@ + 'http://yourdomain.com/bt/', + 'bt_add_comment' => '', + 'bt_add_publisher' => '', +); + +$default_cfg_bool = array( + 'bt_disable_dht' => 1, + 'bt_show_peers' => 1, + 'bt_add_auth_key' => 1, + 'bt_show_dl_list' => 0, + 'bt_dl_list_only_1st_page' => 1, + 'bt_dl_list_only_count' => 1, + 'bt_gen_passkey_on_reg' => 1, + 'bt_replace_ann_url' => 1, + 'bt_show_ip_only_moder' => 1, + 'bt_show_port_only_moder' => 1, + 'bt_check_announce_url' => 0, + 'bt_show_dl_list_buttons' => 1, + 'bt_show_dl_but_will' => 1, + 'bt_show_dl_but_down' => 0, + 'bt_show_dl_but_compl' => 1, + 'bt_show_dl_but_cancel' => 1, + 'bt_show_dl_stat_on_index' => 1, + 'bt_newtopic_auto_reg' => 1, + 'bt_tor_browse_only_reg' => 1, + 'bt_search_bool_mode' => 1, + 'bt_allow_spmode_change' => 1, + 'bt_del_addit_ann_urls' => 1, + 'bt_set_dltype_on_tor_reg' => 1, + 'bt_unset_dltype_on_tor_unreg' => 0, +); + +$default_cfg_num = array( + 'bt_show_peers_mode' => SHOW_PEERS_COUNT, +); + +$default_cfg = array_merge($default_cfg_str, $default_cfg_bool, $default_cfg_num); + +$db_fields_bool = array( + 'allow_reg_tracker' => 0, // Allowed forums for registering torrents on tracker + 'allow_dl_topic' => 0, // Allowed forums for dl-topics + 'self_moderated' => 0, // Users can move theirs topic to another forum +); + +// Get config +$cfg = bb_get_config(BB_CONFIG, true, false); + +// Submit new config +if ($submit && $confirm) +{ + foreach ($db_fields_bool as $field_name => $field_def_val) + { + update_table_bool(BB_FORUMS, 'forum_id', $field_name, $field_def_val); + } + + update_config_table(BB_CONFIG, $default_cfg_str, $cfg, 'str'); + update_config_table(BB_CONFIG, $default_cfg_bool, $cfg, 'bool'); + update_config_table(BB_CONFIG, $default_cfg_num, $cfg, 'num'); + + $datastore->update('cat_forums'); + + $message = $lang['CONFIG_UPD'] .'

'. sprintf($lang['RETURN_CONFIG'], '', '') .'

'. sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + message_die(GENERAL_MESSAGE, $message); +} + +// Set template vars +set_tpl_vars ($default_cfg_str, $cfg); +set_tpl_vars_lang ($default_cfg_str); + +set_tpl_vars_bool ($default_cfg_bool, $cfg); +set_tpl_vars_lang ($default_cfg_bool); + +set_tpl_vars ($default_cfg_num, $cfg); +set_tpl_vars_lang ($default_cfg_num); + +set_tpl_vars_lang ($db_fields_bool); + +// Get Forums list +$sql = "SELECT f.* + FROM ". BB_CATEGORIES ." c, ". BB_FORUMS ." f + WHERE f.cat_id = c.cat_id + ORDER BY c.cat_order, f.forum_order"; + +if (!$result = DB()->sql_query($sql)) +{ + message_die(GENERAL_ERROR, 'Could not obtain forum names', '', __LINE__, __FILE__, $sql); +} + +$rowset = DB()->sql_fetchrowset($result); +$forum_rows = min($max_forum_rows, count($rowset)); + +foreach ($db_fields_bool as $field_name => $field_def_val) +{ + $$field_name = ''; +} + +foreach ($rowset as $rid => $forum) +{ + foreach ($db_fields_bool as $field_name => $field_def_val) + { + $forum_name = $forum['forum_name']; + $selected = ($forum[$field_name]) ? ' selected="selected"' : ''; + + $forum_name = str_short($forum_name, $max_forum_name_len); + + $$field_name .= '\n"; + } +} + +foreach ($db_fields_bool as $field_name => $field_def_val) +{ + $$field_name = ''; + $template->assign_vars(array('S_'. strtoupper($field_name) => $$field_name)); +} + +$template->assign_vars(array( + 'L_BT_SHOW_PEERS_MODE_COUNT' => ($cfg['bt_show_peers_mode'] == SHOW_PEERS_COUNT) ? ''. $lang['BT_SHOW_PEERS_MODE_COUNT'] .'' : $lang['BT_SHOW_PEERS_MODE_COUNT'], + 'L_BT_SHOW_PEERS_MODE_NAMES' => ($cfg['bt_show_peers_mode'] == SHOW_PEERS_NAMES) ? ''. $lang['BT_SHOW_PEERS_MODE_NAMES'] .'' : $lang['BT_SHOW_PEERS_MODE_NAMES'], + 'L_BT_SHOW_PEERS_MODE_FULL' => ($cfg['bt_show_peers_mode'] == SHOW_PEERS_FULL) ? ''. $lang['BT_SHOW_PEERS_MODE_FULL'] .'' : $lang['BT_SHOW_PEERS_MODE_FULL'], + + 'BT_SHOW_PEERS_MODE_COUNT_VAL' => SHOW_PEERS_COUNT, + 'BT_SHOW_PEERS_MODE_NAMES_VAL' => SHOW_PEERS_NAMES, + 'BT_SHOW_PEERS_MODE_FULL_VAL' => SHOW_PEERS_FULL, + + 'BT_SHOW_PEERS_MODE_COUNT_SEL' => ($cfg['bt_show_peers_mode'] == SHOW_PEERS_COUNT) ? HTML_CHECKED : '', + 'BT_SHOW_PEERS_MODE_NAMES_SEL' => ($cfg['bt_show_peers_mode'] == SHOW_PEERS_NAMES) ? HTML_CHECKED : '', + 'BT_SHOW_PEERS_MODE_FULL_SEL' => ($cfg['bt_show_peers_mode'] == SHOW_PEERS_FULL) ? HTML_CHECKED : '', + + 'S_HIDDEN_FIELDS' => '', + 'S_CONFIG_ACTION' => append_sid("admin_bt_forum_cfg.php"), +)); + +print_page('admin_bt_forum_cfg.tpl', 'admin'); diff --git a/upload/admin/admin_bt_tracker_cfg.php b/upload/admin/admin_bt_tracker_cfg.php new file mode 100644 index 000000000..b19179d6b --- /dev/null +++ b/upload/admin/admin_bt_tracker_cfg.php @@ -0,0 +1,65 @@ + 'Tracker is disabled', + 'browser_redirect_url' => 'http://yourdomain.com/', +); + +$default_cfg_bool = array( + 'autoclean' => 1, + 'off' => 0, + 'compact_mode' => 1, + 'update_dlstat' => 1, + 'limit_active_tor' => 0, + 'limit_concurrent_ips' => 0, +); + +$default_cfg_num = array( + 'numwant' => 50, + 'expire_factor' => 4, + 'limit_seed_count' => 20, + 'limit_leech_count' => 4, + 'leech_expire_factor' => 60, + 'limit_seed_ips' => 0, + 'limit_leech_ips' => 0, +); + +// Set template vars +set_tpl_vars ($default_cfg_str, $tr_cfg); +set_tpl_vars_lang ($default_cfg_str); + +set_tpl_vars_bool ($default_cfg_bool, $tr_cfg); +set_tpl_vars_lang ($default_cfg_bool); + +set_tpl_vars ($default_cfg_num, $tr_cfg); +set_tpl_vars_lang ($default_cfg_num); + +$template->assign_vars(array( + 'L_CONFIGURATION_TITLE' => $lang['TRACKER_CFG_TITLE'], + + 'IGNORE_REPORTED_IP' => $bb_cfg['ignore_reported_ip'], + 'ANNOUNCE_INTERVAL' => $bb_cfg['announce_interval'], + 'PASSKEY_KEY' => $bb_cfg['passkey_key'], + 'DISABLE_SUBMIT' => true, + + 'S_HIDDEN_FIELDS' => '', + 'S_CONFIG_ACTION' => append_sid("admin_bt_tracker_cfg.php"), +)); + +print_page('admin_bt_tracker_cfg.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_cron.php b/upload/admin/admin_cron.php new file mode 100644 index 000000000..15896d559 --- /dev/null +++ b/upload/admin/admin_cron.php @@ -0,0 +1,361 @@ +session_start(); + redirect('admin/'.basename(__FILE__) . '?mode=list'); +} +else { + require('./pagestart.php'); +} +// ACP Header - END + +require(LANG_DIR .'lang_admin_cron.php'); +require(INC_DIR .'functions_admin_torrent.php'); +require(INC_DIR .'functions_admin_cron.php'); + +if ($mode == 'list') { + $sql = "SELECT * + FROM ". BB_CRON ." + ORDER BY cron_id"; + + if( !$result1 = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not query cron list", "", __LINE__, __FILE__, $sql); + } + + while($row = DB()->sql_fetchrow($result1)) + { + $cron_id = $row['cron_id']; + $cron_active = $row['cron_active'] ? $lang['YES'] : $lang['NO']; + $cron_title = $row['cron_title']; + $cron_script = $row['cron_script']; + $schedule = $row['schedule']; + $leech = $row['run_day']; + $row_style = ( !($i % 2) ) ? 'row1' : 'row2'; + $last_run = $row['last_run']; + $next_run = $row['next_run']; + $run_count = $row['run_counter']; + + $tpl .= ""; + $tpl .= ""; + $tpl .= "$cron_id"; + $tpl .= "$cron_active"; + $tpl .= "$cron_title"; + $tpl .= "$cron_script"; + $tpl .= " $schedule "; + $tpl .= " $last_run "; + $tpl .= " $next_run "; + $tpl .= " $run_count"; + $tpl .= " + + [Run] + [Edit] + [Del] + + "; + + $tpl .= ""; + + $i++; + } +// $tpl .= ""; + $template->assign_vars(array( + 'TPL_CRON_LIST' => true, + 'LIST' => $tpl, + 'S_CRON_ACTION' => append_sid("admin_cron.php"), + 'S_MODE' => 'list', + )); + + $default_cfg_bool = array( + 'cron_enabled' => true, + ); + $default_cfg_num = array( + 'cron_check_interval' => $bb_cfg['cron_check_interval'], + ); + + $cfg = array_merge($default_cfg_bool, $default_cfg_num); + + set_tpl_vars_bool ($default_cfg_bool, $cfg); + set_tpl_vars_lang ($default_cfg_bool); + + set_tpl_vars ($default_cfg_num, $cfg); + set_tpl_vars_lang ($default_cfg_num); + + //detect cron status + if (@file_exists('../triggers/cron_running')){ + $template->assign_vars(array( + 'CRON_RUNNING' => true, + )); + } + print_page('admin_cron.tpl', 'admin'); +} +if ($mode == 'repair') { + if (@file_exists('../triggers/cron_running')) { + rename("../triggers/cron_running", "../triggers/cron_allowed"); + } + redirect('admin/'.basename(__FILE__) . '?mode=list'); +} +if (($mode == 'run' && $job_id)) { + run_jobs($job_id); + redirect('admin/'.basename(__FILE__) . '?mode=list'); +} + +if ($mode == 'edit' && $job_id) { + $sql = "SELECT * + FROM ". BB_CRON ." + WHERE cron_id = $job_id"; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not query cron", "", __LINE__, __FILE__, $sql); + } + + while($row = DB()->sql_fetchrow($result)) + { + $cron_id = $row['cron_id']; + $cron_active = $row['cron_active']; + $cron_title = $row['cron_title']; + $cron_script = $row['cron_script']; + $schedule = $row['schedule']; + $run_day = $row['run_day']; + $run_time = $row['run_time']; + $run_order = $row['run_order']; + $last_run = $row['last_run']; + $next_run = $row['next_run']; + $run_interval = $row['run_interval']; + $log_enabled = $row['log_enabled']; + $log_file = $row['log_file']; + $log_sql_queries = $row['log_sql_queries']; + $disable_board = $row['disable_board']; + $run_counter = $row['run_counter']; + + } + //build schedule html + $schedule_html = ''; + $schedule_option = 'value="'.$schedule.'"'; + $schedule_selected = 'value="'.$schedule.'" selected="selected"'; + $schedule_result = str_replace( $schedule_option, $schedule_selected, $schedule_html); + //build run_day html + $run_day_html = ''; + // + $template->assign_vars(array( + 'TPL_CRON_EDIT' => true, + 'S_CRON_ACTION' => append_sid("admin_cron.php"), + 'S_MODE' => 'edit', + 'SCHEDULE' => $schedule_result, + 'RUN_DAY' => $run_day_html, + 'L_CRON_EDIT_HEAD' => $lang['CRON_EDIT_HEAD_EDIT'], + )); + + + $default_cfg_str = array( + 'cron_title' => $cron_title, + 'cron_script' => $cron_script, + 'run_time' => $run_time, + 'last_run' => $last_run, + 'next_run' => $next_run, + 'run_interval' => $run_interval, + 'log_file' => $log_file, + ); + $default_cfg_bool = array( + 'cron_active' => $cron_active, + 'log_enabled' => $log_enabled, + 'log_sql_queries' => $log_sql_queries, + 'disable_board' => $disable_board, + ); + $default_cfg_num = array( + 'cron_id' => $cron_id, + 'run_order' => $run_order, + 'run_counter' => $run_counter, + ); + + $cfg = array_merge($default_cfg_str, $default_cfg_bool, $default_cfg_num); + + set_tpl_vars ($default_cfg_str, $cfg); + set_tpl_vars_lang ($default_cfg_str); + + set_tpl_vars_bool ($default_cfg_bool, $cfg); + set_tpl_vars_lang ($default_cfg_bool); + + set_tpl_vars ($default_cfg_num, $cfg); + set_tpl_vars_lang ($default_cfg_num); + + print_page('admin_cron.tpl', 'admin'); +} +if ($mode == 'add') { + + $cron_id = 'none'; + $cron_active = 1; + $cron_title = ''; + $cron_script = ''; + $schedule = ''; + $run_day = ''; + $run_time = ''; + $run_order = 255; + $last_run = '0000-00-00 00:00:00'; + $next_run = '0000-00-00 00:00:00'; + $run_interval = ''; + $log_enabled = 0; + $log_file = ''; + $log_sql_queries = 0; + $disable_board = 0; + $run_counter = 0; + + + //build schedule html + $schedule_html = ''; + $schedule_option = 'value="'.$schedule.'"'; + $schedule_selected = 'value="'.$schedule.'" selected="selected"'; + $schedule_result = str_replace( $schedule_option, $schedule_selected, $schedule_html); + //build run_day html + $run_day_html = ''; + // + $template->assign_vars(array( + 'TPL_CRON_EDIT' => true, + 'S_CRON_ACTION' => append_sid("admin_cron.php"), + 'S_MODE' => 'add', + 'SCHEDULE' => $schedule_result, + 'RUN_DAY' => $run_day_html, + 'L_CRON_EDIT_HEAD' => $lang['CRON_EDIT_HEAD_ADD'], + )); + + + $default_cfg_str = array( + 'cron_title' => $cron_title, + 'cron_script' => $cron_script, + 'run_time' => $run_time, + 'last_run' => $last_run, + 'next_run' => $next_run, + 'run_interval' => $run_interval, + 'log_file' => $log_file, + ); + $default_cfg_bool = array( + 'cron_active' => $cron_active, + 'log_enabled' => $log_enabled, + 'log_sql_queries' => $log_sql_queries, + 'disable_board' => $disable_board, + ); + $default_cfg_num = array( + 'cron_id' => $cron_id, + 'run_order' => $run_order, + 'run_counter' => $run_counter, + ); + + $cfg = array_merge($default_cfg_str, $default_cfg_bool, $default_cfg_num); + + set_tpl_vars ($default_cfg_str, $cfg); + set_tpl_vars_lang ($default_cfg_str); + + set_tpl_vars_bool ($default_cfg_bool, $cfg); + set_tpl_vars_lang ($default_cfg_bool); + + set_tpl_vars ($default_cfg_num, $cfg); + set_tpl_vars_lang ($default_cfg_num); + + print_page('admin_cron.tpl', 'admin'); +} + +if ($mode == 'delete' && $job_id) { + if (isset($_GET['confirm'])) { + delete_jobs($job_id); + redirect('admin/'.basename(__FILE__) . '?mode=list'); + } + else { + message_die(GENERAL_MESSAGE, "Are you sure?
Delete Back"); + } +} + +if ($submit && $confirm) { + if ($_POST['mode'] == 'list') { + if ($cron_action == 'run' && $jobs) { + run_jobs($jobs); + } + else if ($cron_action == 'delete' && $jobs) { + delete_jobs($jobs); + } + else if (($cron_action == 'disable' || $cron_action == 'enable') && $jobs) { + toggle_active($jobs, $cron_action); + } + $bb_cfg_options = array( + 'cron_enabled', + 'cron_check_interval' + ); + foreach ($bb_cfg_options as $option) { + update_config_php($option, $_POST[$option]); + } + redirect('admin/'.basename(__FILE__) . '?mode=list'); + } + else if (validate_cron_post($_POST) == 1) { + if($_POST['mode'] == 'edit') { + update_cron_job($_POST); + } + else if ($_POST['mode'] == 'add'){ + insert_cron_job($_POST); + } + else { + bb_die(); + } + redirect('admin/'.basename(__FILE__) . '?mode=list'); + } + else { + $message = validate_cron_post($_POST); + message_die(GENERAL_MESSAGE, $message); + } + +} \ No newline at end of file diff --git a/upload/admin/admin_disallow.php b/upload/admin/admin_disallow.php new file mode 100644 index 000000000..e510ddaaa --- /dev/null +++ b/upload/admin/admin_disallow.php @@ -0,0 +1,107 @@ +sql_query( $sql ); + if ( !$result ) + { + message_die(GENERAL_ERROR, "Could not add disallowed user.", "",__LINE__, __FILE__, $sql); + } + $message = $lang['DISALLOW_SUCCESSFUL']; + } + + $message .= "

" . sprintf($lang['CLICK_RETURN_DISALLOWADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); +} +else if( isset($_POST['delete_name']) ) +{ + $disallowed_id = ( isset($_POST['disallowed_id']) ) ? intval( $_POST['disallowed_id'] ) : intval( $_GET['disallowed_id'] ); + + $sql = "DELETE FROM " . BB_DISALLOW . " + WHERE disallow_id = $disallowed_id"; + $result = DB()->sql_query($sql); + if( !$result ) + { + message_die(GENERAL_ERROR, "Couldn't removed disallowed user.", "",__LINE__, __FILE__, $sql); + } + + $message .= $lang['DISALLOWED_DELETED'] . "

" . sprintf($lang['CLICK_RETURN_DISALLOWADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + +} + +// +// Grab the current list of disallowed usernames... +// +$sql = "SELECT * + FROM " . BB_DISALLOW; +$result = DB()->sql_query($sql); +if( !$result ) +{ + message_die(GENERAL_ERROR, "Couldn't get disallowed users.", "", __LINE__, __FILE__, $sql ); +} + +$disallowed = DB()->sql_fetchrowset($result); + +// +// Ok now generate the info for the template, which will be put out no matter +// what mode we are in. +// +$disallow_select = ''; + +$template->assign_vars(array( + "S_DISALLOW_SELECT" => $disallow_select, + "S_FORM_ACTION" => append_sid("admin_disallow.php"), + + "L_DISALLOW_TITLE" => $lang['DISALLOW_CONTROL'], + "L_DELETE_DISALLOW" => $lang['DELETE_DISALLOW_TITLE'], + "L_DELETE_EXPLAIN" => $lang['DELETE_DISALLOW_EXPLAIN'], + "L_ADD" => $lang['ADD_DISALLOW'], + "L_ADD_DISALLOW" => $lang['ADD_DISALLOW_TITLE'], + "L_ADD_EXPLAIN" => $lang['ADD_DISALLOW_EXPLAIN'], +)); + +print_page('admin_disallow.tpl', 'admin'); diff --git a/upload/admin/admin_extensions.php b/upload/admin/admin_extensions.php new file mode 100644 index 000000000..85689bf5b --- /dev/null +++ b/upload/admin/admin_extensions.php @@ -0,0 +1,819 @@ +update('attach_extensions'); +} +register_shutdown_function('update_attach_extensions'); + +require('./pagestart.php'); +// ACP Header - END + +if (!intval($attach_config['allow_ftp_upload'])) +{ + if ( ($attach_config['upload_dir'][0] == '/') || ( ($attach_config['upload_dir'][0] != '/') && ($attach_config['upload_dir'][1] == ':') ) ) + { + $upload_dir = $attach_config['upload_dir']; + } + else + { + $upload_dir = BB_ROOT . $attach_config['upload_dir']; + } +} +else +{ + $upload_dir = $attach_config['download_path']; +} + +include(BB_ROOT .'attach_mod/includes/functions_selects.php'); + +// Check if the language got included +if (!isset($lang['TEST_SETTINGS_SUCCESSFUL'])) +{ + // include_once is used within the function + include_attach_lang(); +} + +// Init Vars +$types_download = array(INLINE_LINK, PHYSICAL_LINK); +$modes_download = array('inline', 'physical'); + +$types_category = array(IMAGE_CAT, STREAM_CAT, SWF_CAT); +$modes_category = array($lang['CATEGORY_IMAGES'], $lang['CATEGORY_STREAM_FILES'], $lang['CATEGORY_SWF_FILES']); + +$size = get_var('size', ''); +$mode = get_var('mode', ''); +$e_mode = get_var('e_mode', ''); + +$submit = (isset($_POST['submit'])) ? TRUE : FALSE; + +// Get Attachment Config +$attach_config = array(); + +$sql = 'SELECT * +FROM ' . bb_ATTACH_CONFIG; + +if ( !($result = DB()->sql_query($sql)) ) +{ + message_die(GENERAL_ERROR, 'Could not query attachment information', '', __LINE__, __FILE__, $sql); +} + +while ($row = DB()->sql_fetchrow($result)) +{ + $attach_config[$row['config_name']] = trim($row['config_value']); +} +DB()->sql_freeresult($result); + +// Extension Management +if ($submit && $mode == 'extensions') +{ + // Change Extensions ? + $extension_change_list = get_var('extension_change_list', array(0)); + $extension_explain_list = get_var('extension_explain_list', array('')); + $group_select_list = get_var('group_select', array(0)); + + // Generate correct Change List + $extensions = array(); + + for ($i = 0; $i < sizeof($extension_change_list); $i++) + { + $extensions['_' . $extension_change_list[$i]]['comment'] = $extension_explain_list[$i]; + $extensions['_' . $extension_change_list[$i]]['group_id'] = intval($group_select_list[$i]); + } + + $sql = 'SELECT * + FROM ' . BB_EXTENSIONS . ' + ORDER BY ext_id'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t get Extension Informations.', '', __LINE__, __FILE__, $sql); + } + + $num_rows = DB()->num_rows($result); + $extension_row = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if ($num_rows > 0) + { + for ($i = 0; $i < sizeof($extension_row); $i++) + { + if ($extension_row[$i]['comment'] != $extensions['_' . $extension_row[$i]['ext_id']]['comment'] || intval($extension_row[$i]['group_id']) != intval($extensions['_' . $extension_row[$i]['ext_id']]['group_id'])) + { + $sql_ary = array( + 'comment' => (string) $extensions['_' . $extension_row[$i]['ext_id']]['comment'], + 'group_id' => (int) $extensions['_' . $extension_row[$i]['ext_id']]['group_id'] + ); + + $sql = 'UPDATE ' . BB_EXTENSIONS . ' SET ' . attach_mod_sql_build_array('UPDATE', $sql_ary) . ' + WHERE ext_id = ' . (int) $extension_row[$i]['ext_id']; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Couldn\'t update Extension Informations', '', __LINE__, __FILE__, $sql); + } + } + } + } + + // Delete Extension? + $extension_id_list = get_var('extension_id_list', array(0)); + + $extension_id_sql = implode(', ', $extension_id_list); + + if ($extension_id_sql != '') + { + $sql = 'DELETE + FROM ' . BB_EXTENSIONS . ' + WHERE ext_id IN (' . $extension_id_sql . ')'; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete Extensions', '', __LINE__, __FILE__, $sql); + } + } + + // Add Extension ? + $extension = get_var('add_extension', ''); + $extension_explain = get_var('add_extension_explain', ''); + $extension_group = get_var('add_group_select', 0); + $add = ( isset($_POST['add_extension_check']) ) ? TRUE : FALSE; + + if ($extension != '' && $add) + { + $template->assign_vars(array( + 'ADD_EXTENSION' => $extension, + 'ADD_EXTENSION_EXPLAIN' => $extension_explain) + ); + + if (!$error) + { + // check extension + $sql = 'SELECT extension + FROM ' . BB_EXTENSIONS; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query Extensions', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_rows > 0) + { + for ($i = 0; $i < $num_rows; $i++) + { + if (strtolower(trim($row[$i]['extension'])) == strtolower(trim($extension))) + { + $error = TRUE; + if( isset($error_msg) ) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['EXTENSION_EXIST'], strtolower(trim($extension))); + } + } + } + + if (!$error) + { + $sql_ary = array( + 'group_id' => (int) $extension_group, + 'extension' => (string) strtolower($extension), + 'comment' => (string) $extension_explain + ); + + $sql = 'INSERT INTO ' . BB_EXTENSIONS . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not add Extension', '', __LINE__, __FILE__, $sql); + } + + } + } + } + + if (!@$error) + { + $message = $lang['ATTACH_CONFIG_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + } +} + +if ($mode == 'extensions') +{ + // Extensions + $template->assign_vars(array( + 'TPL_ATTACH_EXTENSIONS' => true, + + 'L_EXTENSIONS_TITLE' => $lang['MANAGE_EXTENSIONS'], + 'L_EXTENSIONS_EXPLAIN' => $lang['MANAGE_EXTENSIONS_EXPLAIN'], + + 'S_CANCEL_ACTION' => append_sid("admin_extensions.php?mode=extensions"), + 'S_ATTACH_ACTION' => append_sid("admin_extensions.php?mode=extensions")) + ); + + if ($submit) + { + $template->assign_vars(array( + 'S_ADD_GROUP_SELECT' => group_select('add_group_select', $extension_group)) + ); + } + else + { + $template->assign_vars(array( + 'S_ADD_GROUP_SELECT' => group_select('add_group_select')) + ); + } + + $sql = 'SELECT * + FROM ' . BB_EXTENSIONS . ' + ORDER BY group_id'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t get Extension informations', '', __LINE__, __FILE__, $sql); + } + + $extension_row = DB()->sql_fetchrowset($result); + $num_extension_row = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_extension_row > 0) + { + $extension_row = sort_multi_array($extension_row, 'group_name', 'ASC'); + + for ($i = 0; $i < $num_extension_row; $i++) + { + if ($submit) + { + $template->assign_block_vars('extension_row', array( + 'EXT_ID' => $extension_row[$i]['ext_id'], + 'EXTENSION' => $extension_row[$i]['extension'], + 'EXTENSION_EXPLAIN' => $extension_explain_list[$i], + 'S_GROUP_SELECT' => group_select('group_select[]', $group_select_list[$i])) + ); + } + else + { + $template->assign_block_vars('extension_row', array( + 'EXT_ID' => $extension_row[$i]['ext_id'], + 'EXTENSION' => $extension_row[$i]['extension'], + 'EXTENSION_EXPLAIN' => $extension_row[$i]['comment'], + 'S_GROUP_SELECT' => group_select('group_select[]', $extension_row[$i]['group_id'])) + ); + } + } + } + +} + +// Extension Groups +if ($submit && $mode == 'groups') +{ + // Change Extension Groups ? + $group_change_list = get_var('group_change_list', array(0)); + $extension_group_list = get_var('extension_group_list', array('')); + $group_allowed_list = get_var('allowed_list', array(0)); + $download_mode_list = get_var('download_mode_list', array(0)); + $category_list = get_var('category_list', array(0)); + $upload_icon_list = get_var('upload_icon_list', array('')); + $filesize_list = get_var('max_filesize_list', array(0)); + $size_select_list = get_var('size_select_list', array('')); + + $allowed_list = array(); + + for ($i = 0; $i < sizeof($group_allowed_list); $i++) + { + for ($j = 0; $j < sizeof($group_change_list); $j++) + { + if ($group_allowed_list[$i] == $group_change_list[$j]) + { + $allowed_list[$j] = 1; + } + } + } + + for ($i = 0; $i < sizeof($group_change_list); $i++) + { + $allowed = (isset($allowed_list[$i])) ? 1 : 0; + + $filesize_list[$i] = ($size_select_list[$i] == 'kb') ? round($filesize_list[$i] * 1024) : ( ($size_select_list[$i] == 'mb') ? round($filesize_list[$i] * 1048576) : $filesize_list[$i] ); + + $sql_ary = array( + 'group_name' => (string) $extension_group_list[$i], + 'cat_id' => (int) $category_list[$i], + 'allow_group' => (int) $allowed, + 'download_mode' => (int) $download_mode_list[$i], + 'upload_icon' => (string) $upload_icon_list[$i], + 'max_filesize' => (int) $filesize_list[$i] + ); + + $sql = 'UPDATE ' . BB_EXTENSION_GROUPS . ' SET ' . attach_mod_sql_build_array('UPDATE', $sql_ary) . ' + WHERE group_id = ' . (int) $group_change_list[$i]; + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t update Extension Groups Informations', '', __LINE__, __FILE__, $sql); + } + } + + // Delete Extension Groups + $group_id_list = get_var('group_id_list', array(0)); + + $group_id_sql = implode(', ', $group_id_list); + + if ($group_id_sql != '') + { + $sql = 'DELETE + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE group_id IN (' . $group_id_sql . ')'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not delete Extension Groups', '', __LINE__, __FILE__, $sql); + } + + // Set corresponding Extensions to a pending Group + $sql = 'UPDATE ' . BB_EXTENSIONS . ' + SET group_id = 0 + WHERE group_id IN (' . $group_id_sql . ')'; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not assign Extensions to Pending Group.', '', __LINE__, __FILE__, $sql); + } + } + + // Add Extensions? + $extension_group = get_var('add_extension_group', ''); + $download_mode = get_var('add_download_mode', 0); + $cat_id = get_var('add_category', 0); + $upload_icon = get_var('add_upload_icon', ''); + $filesize = get_var('add_max_filesize', 0); + $size_select = get_var('add_size_select', ''); + + $is_allowed = (isset($_POST['add_allowed'])) ? 1 : 0; + $add = ( isset($_POST['add_extension_group_check']) ) ? TRUE : FALSE; + + if ($extension_group != '' && $add) + { + // check Extension Group + $sql = 'SELECT group_name + FROM ' . BB_EXTENSION_GROUPS; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query Extension Groups Table', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_rows > 0) + { + for ($i = 0; $i < $num_rows; $i++) + { + if ($row[$i]['group_name'] == $extension_group) + { + $error = TRUE; + if( isset($error_msg) ) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['EXTENSION_GROUP_EXIST'], $extension_group); + } + } + } + + if (!$error) + { + $filesize = ($size_select == 'kb') ? round($filesize * 1024) : ( ($size_select == 'mb') ? round($filesize * 1048576) : $filesize ); + + $sql_ary = array( + 'group_name' => (string) $extension_group, + 'cat_id' => (int) $cat_id, + 'allow_group' => (int) $is_allowed, + 'download_mode' => (int) $download_mode, + 'upload_icon' => (string) $upload_icon, + 'max_filesize' => (int) $filesize, + 'forum_permissions' => '' + ); + + $sql = 'INSERT INTO ' . BB_EXTENSION_GROUPS . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not add Extension Group', '', __LINE__, __FILE__, $sql); + } + } + + } + + if (!@$error) + { + $message = $lang['ATTACH_CONFIG_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_ATTACH_CONFIG'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + } +} + +if ($mode == 'groups') +{ + // Extension Groups + if (!$size && !$submit) + { + $max_add_filesize = $attach_config['max_filesize']; + + $size = ($max_add_filesize >= 1048576) ? 'mb' : ( ($max_add_filesize >= 1024) ? 'kb' : 'b' ); + } + + if ($max_add_filesize >= 1048576) + { + $max_add_filesize = round($max_add_filesize / 1048576 * 100) / 100; + } + else if ( $max_add_filesize >= 1024) + { + $max_add_filesize = round($max_add_filesize / 1024 * 100) / 100; + } + + $viewgroup = get_var(POST_GROUPS_URL, 0); + + $template->assign_vars(array( + 'TPL_ATTACH_EXTENSION_GROUPS' => true, + + 'L_EXTENSION_GROUPS_TITLE' => $lang['MANAGE_EXTENSION_GROUPS'], + 'L_EXTENSION_GROUPS_EXPLAIN' => $lang['MANAGE_EXTENSION_GROUPS_EXPLAIN'], + 'L_MAX_FILESIZE' => $lang['MAX_GROUPS_FILESIZE'], + 'L_FORUM_PERMISSIONS' => $lang['EXT_GROUP_PERMISSIONS'], + + 'ADD_GROUP_NAME' => ( isset($submit) ) ? @$extension_group : '', + 'MAX_FILESIZE' => $max_add_filesize, + + 'S_FILESIZE' => size_select('add_size_select', $size), + 'S_ADD_DOWNLOAD_MODE' => download_select('add_download_mode'), + 'S_SELECT_CAT' => category_select('add_category'), + 'S_CANCEL_ACTION' => append_sid("admin_extensions.php?mode=groups"), + 'S_ATTACH_ACTION' => append_sid("admin_extensions.php?mode=groups")) + ); + + $sql = 'SELECT * + FROM ' . BB_EXTENSION_GROUPS; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t get Extension Group informations', '', __LINE__, __FILE__, $sql); + } + + $extension_group = DB()->sql_fetchrowset($result); + $num_extension_group = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($i = 0; $i < $num_extension_group; $i++) + { + // Format the filesize + if (!$extension_group[$i]['max_filesize']) + { + $extension_group[$i]['max_filesize'] = $attach_config['max_filesize']; + } + + $size_format = ($extension_group[$i]['max_filesize'] >= 1048576) ? 'mb' : ( ($extension_group[$i]['max_filesize'] >= 1024) ? 'kb' : 'b' ); + + if ( $extension_group[$i]['max_filesize'] >= 1048576) + { + $extension_group[$i]['max_filesize'] = round($extension_group[$i]['max_filesize'] / 1048576 * 100) / 100; + } + else if($extension_group[$i]['max_filesize'] >= 1024) + { + $extension_group[$i]['max_filesize'] = round($extension_group[$i]['max_filesize'] / 1024 * 100) / 100; + } + + $s_allowed = ($extension_group[$i]['allow_group'] == 1) ? 'checked="checked"' : ''; + + $template->assign_block_vars('grouprow', array( + 'GROUP_ID' => $extension_group[$i]['group_id'], + 'EXTENSION_GROUP' => $extension_group[$i]['group_name'], + 'UPLOAD_ICON' => $extension_group[$i]['upload_icon'], + + 'S_ALLOW_SELECTED' => $s_allowed, + 'S_SELECT_CAT' => category_select('category_list[]', $extension_group[$i]['group_id']), + 'S_DOWNLOAD_MODE' => download_select('download_mode_list[]', $extension_group[$i]['group_id']), + 'S_FILESIZE' => size_select('size_select_list[]', $size_format), + + 'MAX_FILESIZE' => $extension_group[$i]['max_filesize'], + 'CAT_BOX' => ( $viewgroup == $extension_group[$i]['group_id'] ) ? $lang['DECOLLAPSE'] : $lang['COLLAPSE'], + 'U_VIEWGROUP' => ( $viewgroup == $extension_group[$i]['group_id'] ) ? append_sid("admin_extensions.php?mode=groups") : append_sid("admin_extensions.php?mode=groups&" . POST_GROUPS_URL . "=" . $extension_group[$i]['group_id']), + 'U_FORUM_PERMISSIONS' => append_sid("admin_extensions.php?mode=$mode&e_mode=perm&e_group=" . $extension_group[$i]['group_id'])) + ); + + if ($viewgroup && $viewgroup == $extension_group[$i]['group_id']) + { + $sql = 'SELECT comment, extension + FROM ' . BB_EXTENSIONS . ' + WHERE group_id = ' . (int) $viewgroup; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Couldn\'t get Extension informations', '', __LINE__, __FILE__, $sql); + } + + $extension = DB()->sql_fetchrowset($result); + $num_extension = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($j = 0; $j < $num_extension; $j++) + { + $template->assign_block_vars('grouprow.extensionrow', array( + 'EXPLANATION' => $extension[$j]['comment'], + 'EXTENSION' => $extension[$j]['extension']) + ); + } + } + } +} + +if ($e_mode == 'perm') +{ + $group = get_var('e_group', 0); + + $add_forum = (isset($_POST['add_forum'])) ? TRUE : FALSE; + $delete_forum = (isset($_POST['del_forum'])) ? TRUE : FALSE; + + if (isset($_POST['close_perm'])) + { + $e_mode = ''; + } +} + +// Add Forums +if (@$add_forum && $e_mode == 'perm' && $group) +{ + $add_forums_list = get_var('entries', array(0)); + $add_all_forums = FALSE; + + for ($i = 0; $i < sizeof($add_forums_list); $i++) + { + if ($add_forums_list[$i] == GPERM_ALL) + { + $add_all_forums = TRUE; + } + } + + // If we add ALL FORUMS, we are able to overwrite the Permissions + if ($add_all_forums) + { + $sql = 'UPDATE ' . BB_EXTENSION_GROUPS . " SET forum_permissions = '' WHERE group_id = " . (int) $group; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not update Permissions', '', __LINE__, __FILE__, $sql); + } + } + + // Else we have to add Permissions + if (!$add_all_forums) + { + $sql = 'SELECT forum_permissions + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE group_id = ' . intval($group) . ' + LIMIT 1'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get Group Permissions from ' . BB_EXTENSION_GROUPS, '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (trim($row['forum_permissions']) == '') + { + $auth_p = array(); + } + else + { + $auth_p = auth_unpack($row['forum_permissions']); + } + + // Generate array for Auth_Pack, do not add doubled forums + for ($i = 0; $i < sizeof($add_forums_list); $i++) + { + if (!in_array($add_forums_list[$i], $auth_p)) + { + $auth_p[] = $add_forums_list[$i]; + } + } + + $auth_bitstream = auth_pack($auth_p); + + $sql = 'UPDATE ' . BB_EXTENSION_GROUPS . " SET forum_permissions = '" . attach_mod_sql_escape($auth_bitstream) . "' WHERE group_id = " . (int) $group; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not update Permissions', '', __LINE__, __FILE__, $sql); + } + } + +} + +// Delete Forums +if (@$delete_forum && $e_mode == 'perm' && $group) +{ + $delete_forums_list = get_var('entries', array(0)); + + // Get the current Forums + $sql = 'SELECT forum_permissions + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE group_id = ' . intval($group) . ' + LIMIT 1'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get Group Permissions from ' . BB_EXTENSION_GROUPS, '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $auth_p2 = auth_unpack(trim($row['forum_permissions'])); + $auth_p = array(); + + // Generate array for Auth_Pack, delete the chosen ones + for ($i = 0; $i < sizeof($auth_p2); $i++) + { + if (!in_array($auth_p2[$i], $delete_forums_list)) + { + $auth_p[] = $auth_p2[$i]; + } + } + + $auth_bitstream = (sizeof($auth_p) > 0) ? auth_pack($auth_p) : ''; + + $sql = 'UPDATE ' . BB_EXTENSION_GROUPS . " SET forum_permissions = '" . attach_mod_sql_escape($auth_bitstream) . "' WHERE group_id = " . (int) $group; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not update Permissions', '', __LINE__, __FILE__, $sql); + } +} + +// Display the Group Permissions Box for configuring it +if ($e_mode == 'perm' && $group) +{ + $sql = 'SELECT group_name, forum_permissions + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE group_id = ' . intval($group) . ' + LIMIT 1'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get Group Name from ' . BB_EXTENSION_GROUPS, '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $group_name = $row['group_name']; + $allowed_forums = trim($row['forum_permissions']); + + $forum_perm = array(); + + if ($allowed_forums == '') + { + $forum_perm[0]['forum_id'] = 0; + $forum_perm[0]['forum_name'] = $lang['PERM_ALL_FORUMS']; + } + else + { + $forum_p = array(); + $act_id = 0; + $forum_p = auth_unpack($allowed_forums); + $sql = "SELECT forum_id, forum_name FROM " . BB_FORUMS . " WHERE forum_id IN (" . implode(', ', $forum_p) . ")"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Forum Names', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + $forum_perm[$act_id]['forum_id'] = $row['forum_id']; + $forum_perm[$act_id]['forum_name'] = $row['forum_name']; + $act_id++; + } + } + + for ($i = 0; $i < sizeof($forum_perm); $i++) + { + $template->assign_block_vars('allow_option_values', array( + 'VALUE' => $forum_perm[$i]['forum_id'], + 'OPTION' => htmlCHR($forum_perm[$i]['forum_name'])) + ); + } + + $template->assign_vars(array( + 'TPL_ATTACH_EXTENSION_GROUPS_PERMISSIONS' => true, + + 'L_GROUP_PERMISSIONS_TITLE' => sprintf($lang['GROUP_PERMISSIONS_TITLE_ADMIN'], trim($group_name)), + 'A_PERM_ACTION' => append_sid("admin_extensions.php?mode=groups&e_mode=perm&e_group=$group")) + ); + + $forum_option_values = array(GPERM_ALL => $lang['PERM_ALL_FORUMS']); + + $sql = "SELECT forum_id, forum_name FROM " . BB_FORUMS; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Forums', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + $forum_option_values[intval($row['forum_id'])] = $row['forum_name']; + } + DB()->sql_freeresult($result); + + foreach ($forum_option_values as $value => $option) + { + $template->assign_block_vars('forum_option_values', array( + 'VALUE' => $value, + 'OPTION' => htmlCHR($option)) + ); + } + + $empty_perm_forums = array(); + + $sql = "SELECT forum_id, forum_name FROM " . BB_FORUMS . " WHERE auth_attachments < " . AUTH_ADMIN; + + if ( !($f_result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Forums.', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($f_result)) + { + $forum_id = $row['forum_id']; + + $sql = "SELECT forum_permissions + FROM " . BB_EXTENSION_GROUPS . " + WHERE allow_group = 1 + ORDER BY group_name ASC"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query Extension Groups.', '', __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + $found_forum = FALSE; + + for ($i = 0; $i < $num_rows; $i++) + { + $allowed_forums = auth_unpack(trim($rows[$i]['forum_permissions'])); + if (in_array($forum_id, $allowed_forums) || trim($rows[$i]['forum_permissions']) == '') + { + $found_forum = TRUE; + break; + } + } + + if (!$found_forum) + { + $empty_perm_forums[$forum_id] = $row['forum_name']; + } + } + DB()->sql_freeresult($f_result); + + $message = ''; + + foreach ($empty_perm_forums as $forum_id => $forum_name) + { + $message .= ( $message == '' ) ? $forum_name : '
' . $forum_name; + } + + if (sizeof($empty_perm_forums) > 0) + { + $template->assign_vars(array('ERROR_MESSAGE' => $lang['NOTE_ADMIN_EMPTY_GROUP_PERMISSIONS'] . $message)); + } +} + +if (@$error) +{ + $template->assign_vars(array('ERROR_MESSAGE' => $error_msg)); +} + +print_page('admin_extensions.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_forum_prune.php b/upload/admin/admin_forum_prune.php new file mode 100644 index 000000000..246cb5a02 --- /dev/null +++ b/upload/admin/admin_forum_prune.php @@ -0,0 +1,72 @@ +fetch_rowset($sql) as $i => $row) + { + $pruned_topics = topic_delete('prune', $row['forum_id'], $prunetime, !empty($_POST['prune_all_topic_types'])); + $pruned_total += $pruned_topics; + $prune_performed = true; + + $template->assign_block_vars('pruned', array( + 'ROW_CLASS' => !($i % 2) ? 'prow1' : 'prow2', + 'FORUM_NAME' => htmlCHR($row['forum_name']), + 'PRUNED_TOPICS' => $pruned_topics, + )); + } + if (!$prune_performed) + { + message_die(GENERAL_MESSAGE, return_msg_prune($lang['NONE_SELECTED'])); + } + if (!$pruned_total) + { + message_die(GENERAL_MESSAGE, return_msg_prune($lang['NO_SEARCH_MATCH'])); + } +} + +$template->assign_vars(array( + 'L_PRUNE_RESULT' => $lang['PRUNE_SUCCESS'], + 'L_PRUNE_EXPLAIN' => $lang['FORUM_PRUNE_EXPLAIN'], + 'L_PRUNE_TOPICS' => $lang['PRUNE_TOPICS_NOT_POSTED'], + + 'PRUNED_TOTAL' => $pruned_total, + 'S_PRUNE_ACTION' => basename(__FILE__), + 'SEL_FORUM' => get_forum_select('admin', 'f[]', null, 65, 16, '', $all_forums), +)); + +print_page('admin_forum_prune.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_forumauth.php b/upload/admin/admin_forumauth.php new file mode 100644 index 000000000..d3867e1ff --- /dev/null +++ b/upload/admin/admin_forumauth.php @@ -0,0 +1,266 @@ + array(AUTH_ALL, AUTH_ALL, AUTH_ALL, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_ALL, AUTH_ALL, AUTH_MOD, AUTH_MOD), // Public +/* Reg */ 1 => array(AUTH_ALL, AUTH_ALL, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_MOD, AUTH_MOD), // Registered +/* Reg [Hid] */ 2 => array(AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_MOD, AUTH_MOD), // Registered [Hidden] +/* Priv */ 3 => array(AUTH_REG, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_MOD, AUTH_MOD), // Private +/* Priv [Hid] */ 4 => array(AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_MOD, AUTH_MOD), // Private [Hidden] +/* MOD */ 5 => array(AUTH_REG, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD), // Moderators +/* MOD [Hid] */ 6 => array(AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD), // Moderators [Hidden] +); + +$simple_auth_types = array( + $lang['PUBLIC'], + $lang['REGISTERED'], + $lang['REGISTERED'] .' ['. $lang['HIDDEN'] .']', + $lang['PRIVATE'], + $lang['PRIVATE'] .' ['. $lang['HIDDEN'] .']', + $lang['MODERATORS'], + $lang['MODERATORS'] .' ['. $lang['HIDDEN'] .']', +); + +$field_names = array(); +foreach ($forum_auth_fields as $auth_type) +{ + $field_names[$auth_type] = $lang[strtoupper($auth_type)]; +} + +$forum_auth_levels = array('ALL', 'REG', 'PRIVATE', 'MOD', 'ADMIN'); +$forum_auth_const = array(AUTH_ALL, AUTH_REG, AUTH_ACL, AUTH_MOD, AUTH_ADMIN); + +if (@$_REQUEST[POST_FORUM_URL]) +{ + $forum_id = (int) $_REQUEST[POST_FORUM_URL]; + $forum_sql = "WHERE forum_id = $forum_id"; +} +else +{ + unset($forum_id); + $forum_sql = ''; +} + +if( isset($_GET['adv']) ) +{ + $adv = intval($_GET['adv']); +} +else +{ + unset($adv); +} + +// +// Start program proper +// +if( isset($_POST['submit']) ) +{ + $sql = ''; + + if(!empty($forum_id)) + { + if(isset($_POST['simpleauth'])) + { + $simple_ary = $simple_auth_ary[intval($_POST['simpleauth'])]; + + for($i = 0; $i < count($simple_ary); $i++) + { + $sql .= ( ( $sql != '' ) ? ', ' : '' ) . $forum_auth_fields[$i] . ' = ' . $simple_ary[$i]; + } + + if (is_array($simple_ary)) + { + $sql = "UPDATE " . BB_FORUMS . " SET $sql WHERE forum_id = $forum_id"; + } + } + else + { + for($i = 0; $i < count($forum_auth_fields); $i++) + { + $value = intval($_POST[$forum_auth_fields[$i]]); + + if ( $forum_auth_fields[$i] == 'auth_vote' ) + { + if ( $_POST['auth_vote'] == AUTH_ALL ) + { + $value = AUTH_REG; + } + } + + $sql .= ( ( $sql != '' ) ? ', ' : '' ) .$forum_auth_fields[$i] . ' = ' . $value; + } + + $sql = "UPDATE " . BB_FORUMS . " SET $sql WHERE forum_id = $forum_id"; + } + + if ( $sql != '' ) + { + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update auth table', '', __LINE__, __FILE__, $sql); + } + } + + $forum_sql = ''; + $adv = 0; + } + + $datastore->update('cat_forums'); + $message = $lang['FORUM_AUTH_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_FORUMAUTH'], '', ""); + message_die(GENERAL_MESSAGE, $message); + +} // End of submit + +// +// Get required information, either all forums if +// no id was specified or just the requsted if it +// was +// +$forum_rows = DB()->fetch_rowset("SELECT * FROM ". BB_FORUMS ." $forum_sql"); + +if (empty($forum_id)) +{ + // Output the selection table if no forum id was specified + $template->assign_vars(array( + 'TPL_AUTH_SELECT_FORUM' => true, + + 'L_AUTH_TITLE' => $lang['AUTH_CONTROL_FORUM'], + 'L_AUTH_EXPLAIN' => $lang['FORUM_AUTH_EXPLAIN'], + 'L_AUTH_SELECT' => $lang['SELECT_A_FORUM'], + + 'S_AUTH_ACTION' => "admin_forumauth.php", + 'S_AUTH_SELECT' => get_forum_select('admin', 'f', null, 80), + )); + +} +else +{ + // Output the authorisation details if an id was specified + $forum_name = $forum_rows[0]['forum_name']; + + @reset($simple_auth_ary); + while( list($key, $auth_levels) = each($simple_auth_ary)) + { + $matched = 1; + for($k = 0; $k < count($auth_levels); $k++) + { + $matched_type = $key; + + if ( $forum_rows[0][$forum_auth_fields[$k]] != $auth_levels[$k] ) + { + $matched = 0; + } + } + + if ( $matched ) + { + break; + } + } + + // + // If we didn't get a match above then we + // automatically switch into 'advanced' mode + // + if ( !isset($adv) && !$matched ) + { + $adv = 1; + } + + $s_column_span = 0; + + if ( empty($adv) ) + { + $simple_auth = ''; + + $template->assign_block_vars('forum_auth', array( + 'CELL_TITLE' => $lang['SIMPLE_MODE'], + 'S_AUTH_LEVELS_SELECT' => $simple_auth, + )); + + $s_column_span++; + } + else + { + // + // Output values of individual + // fields + // + for($j = 0; $j < count($forum_auth_fields); $j++) + { + $custom_auth[$j] = '  '; + + $cell_title = $field_names[$forum_auth_fields[$j]]; + + $template->assign_block_vars('forum_auth', array( + 'CELL_TITLE' => $cell_title, + 'S_AUTH_LEVELS_SELECT' => $custom_auth[$j], + )); + + $s_column_span++; + } + } + + $adv_mode = ( empty($adv) ) ? '1' : '0'; + $switch_mode = "admin_forumauth.php?f=$forum_id&adv=$adv_mode"; + $switch_mode_text = ( empty($adv) ) ? $lang['ADVANCED_MODE'] : $lang['SIMPLE_MODE']; + $u_switch_mode = '' . $switch_mode_text . ''; + + $s_hidden_fields = ''; + + $template->assign_vars(array( + 'TPL_EDIT_FORUM_AUTH' => true, + + 'FORUM_NAME' => htmlCHR($forum_name), + + 'L_AUTH_TITLE' => $lang['AUTH_CONTROL_FORUM'], + 'L_AUTH_EXPLAIN' => $lang['FORUM_AUTH_EXPLAIN'], + + 'U_SWITCH_MODE' => $u_switch_mode, + + 'S_FORUMAUTH_ACTION' => "admin_forumauth.php", + 'S_COLUMN_SPAN' => $s_column_span, + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); +} + +print_page('admin_forumauth.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_forumauth_list.php b/upload/admin/admin_forumauth_list.php new file mode 100644 index 000000000..6c900cd24 --- /dev/null +++ b/upload/admin/admin_forumauth_list.php @@ -0,0 +1,396 @@ + array(AUTH_ALL, AUTH_ALL, AUTH_ALL, AUTH_ALL, AUTH_REG, AUTH_REG, AUTH_MOD, AUTH_MOD, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_ALL), // Public +/* Reg */ 1 => array(AUTH_ALL, AUTH_ALL, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_MOD, AUTH_MOD, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG), // Registered +/* Reg [Hid] */ 2 => array(AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_MOD, AUTH_MOD, AUTH_REG, AUTH_REG, AUTH_REG, AUTH_REG), // Registered [Hidden] +/* Priv */ 3 => array(AUTH_REG, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_MOD, AUTH_MOD, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL), // Private +/* Priv [Hid] */ 4 => array(AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_MOD, AUTH_MOD, AUTH_ACL, AUTH_ACL, AUTH_ACL, AUTH_ACL), // Private [Hidden] +/* MOD */ 5 => array(AUTH_REG, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD), // Moderators +/* MOD [Hid] */ 6 => array(AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD, AUTH_MOD), // Moderators [Hidden] +); + +$simple_auth_types = array( + $lang['PUBLIC'], + $lang['REGISTERED'], + $lang['REGISTERED'] .' ['. $lang['HIDDEN'] .']', + $lang['PRIVATE'], + $lang['PRIVATE'] .' ['. $lang['HIDDEN'] .']', + $lang['MODERATORS'], + $lang['MODERATORS'] .' ['. $lang['HIDDEN'] .']', +); + +$forum_auth_fields = array( + 'auth_view', + 'auth_read', + 'auth_reply', + 'auth_edit', + 'auth_delete', + 'auth_vote', + 'auth_pollcreate', + 'auth_attachments', + 'auth_download', + 'auth_post', + 'auth_sticky', + 'auth_announce', +); + +$field_names = array(); +foreach ($forum_auth_fields as $auth_type) +{ + $field_names[$auth_type] = $lang[strtoupper($auth_type)]; +} + +$forum_auth_levels = array('ALL', 'REG', 'PRIVATE', 'MOD', 'ADMIN'); +$forum_auth_const = array(AUTH_ALL, AUTH_REG, AUTH_ACL, AUTH_MOD, AUTH_ADMIN); + +if(isset($_GET[POST_FORUM_URL]) || isset($_POST[POST_FORUM_URL])) +{ + $forum_id = (isset($_POST[POST_FORUM_URL])) ? intval($_POST[POST_FORUM_URL]) : intval($_GET[POST_FORUM_URL]); + $forum_sql = "AND forum_id = $forum_id"; +} +else +{ + unset($forum_id); + $forum_sql = ''; +} + +if(isset($_GET[POST_CAT_URL]) || isset($_POST[POST_CAT_URL])) +{ + $cat_id = (isset($_POST[POST_CAT_URL])) ? intval($_POST[POST_CAT_URL]) : intval($_GET[POST_CAT_URL]); + $cat_sql = "AND c.cat_id = $cat_id"; +} +else +{ + unset($cat_id); + $cat_sql = ''; +} + +if( isset($_GET['adv']) ) +{ + $adv = intval($_GET['adv']); +} +else +{ + unset($adv); +} + +// +// Start program proper +// +if( isset($_POST['submit']) ) +{ + $sql = ''; + + if(!empty($forum_id)) + { + if(isset($_POST['simpleauth'])) + { + $simple_ary = $simple_auth_ary[intval($_POST['simpleauth'])]; + + for($i = 0; $i < count($simple_ary); $i++) + { + $sql .= ( ( $sql != '' ) ? ', ' : '' ) . $forum_auth_fields[$i] . ' = ' . $simple_ary[$i]; + } + + if (is_array($simple_ary)) + { + $sql = "UPDATE " . BB_FORUMS . " SET $sql WHERE forum_id = $forum_id"; + } + } + else + { + for($i = 0; $i < count($forum_auth_fields); $i++) + { + $value = intval($_POST[$forum_auth_fields[$i]]); + + if ( $forum_auth_fields[$i] == 'auth_vote' ) + { + if ( $_POST['auth_vote'] == AUTH_ALL ) + { + $value = AUTH_REG; + } + } + + $sql .= ( ( $sql != '' ) ? ', ' : '' ) .$forum_auth_fields[$i] . ' = ' . $value; + } + + $sql = "UPDATE " . BB_FORUMS . " SET $sql WHERE forum_id = $forum_id"; + } + + if ( $sql != '' ) + { + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update auth table', '', __LINE__, __FILE__, $sql); + } + } + + $forum_sql = ''; + $adv = 0; + } + elseif (!empty($cat_id)) + { + for($i = 0; $i < count($forum_auth_fields); $i++) + { + $value = intval($_POST[$forum_auth_fields[$i]]); + + if ( $forum_auth_fields[$i] == 'auth_vote' ) + { + if ( $_POST['auth_vote'] == AUTH_ALL ) + { + $value = AUTH_REG; + } + } + + $sql .= ( ( $sql != '' ) ? ', ' : '' ) .$forum_auth_fields[$i] . ' = ' . $value; + } + + $sql = "UPDATE " . BB_FORUMS . " SET $sql WHERE cat_id = $cat_id"; + + if ( $sql != '' ) + { + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update auth table', '', __LINE__, __FILE__, $sql); + } + } + + $cat_sql = ''; + } + + $datastore->update('cat_forums'); + $message = $lang['FORUM_AUTH_UPDATED'] . '

' . sprintf($lang['CLICK_RETURN_FORUMAUTH'], '', ""); + message_die(GENERAL_MESSAGE, $message); + +} // End of submit + +// +// Get required information, either all forums if +// no id was specified or just the requsted forum +// or category if it was +// +$sql = "SELECT f.* + FROM " . BB_FORUMS . " f, " . BB_CATEGORIES . " c + WHERE c.cat_id = f.cat_id + $forum_sql $cat_sql + ORDER BY c.cat_order ASC, f.forum_order ASC"; +if ( !($result = DB()->sql_query($sql)) ) +{ + message_die(GENERAL_ERROR, "Couldn't obtain forum list", "", __LINE__, __FILE__, $sql); +} + +$forum_rows = DB()->sql_fetchrowset($result); +DB()->sql_freeresult($result); + +if( empty($forum_id) && empty($cat_id) ) +{ + // + // Output the summary list if no forum id was + // specified + // + $template->assign_vars(array( + 'TPL_AUTH_FORUM_LIST' => true, + + 'L_AUTH_TITLE' => $lang['PERMISSIONS_LIST'], + 'L_AUTH_EXPLAIN' => $lang['FORUM_AUTH_LIST_EXPLAIN'], + 'S_COLUMN_SPAN' => count($forum_auth_fields)+1, + )); + + for ($i=0; $iassign_block_vars('forum_auth_titles', array( + 'CELL_TITLE' => $field_names[$forum_auth_fields[$i]]) + ); + } + + // Obtain the category list + $sql = "SELECT c.cat_id, c.cat_title, c.cat_order + FROM " . BB_CATEGORIES . " c + ORDER BY c.cat_order"; + if( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query categories list', '', __LINE__, __FILE__, $sql); + } + + $category_rows = DB()->sql_fetchrowset($result); + $cat_count = count($category_rows); + + for ($i=0; $i<$cat_count; $i++) + { + $cat_id = $category_rows[$i]['cat_id']; + + $template->assign_block_vars('cat_row', array( + 'CAT_NAME' => htmlCHR($category_rows[$i]['cat_title']), + 'CAT_URL' => append_sid('admin_forumauth_list.php'.'?'.POST_CAT_URL.'='.$category_rows[$i]['cat_id'])) + ); + + for ($j=0; $jassign_block_vars('cat_row.forum_row', array( + 'ROW_CLASS' => !($j % 2) ? 'row4' : 'row5', + 'FORUM_NAME' => ''.htmlCHR($forum_rows[$j]['forum_name']).'', + 'IS_SUBFORUM' => $forum_rows[$j]['forum_parent'], + )); + + for ($k=0; $kassign_block_vars('cat_row.forum_row.forum_auth_data', array( + 'CELL_VALUE' => $lang['FORUM_' . $item_auth_level], + 'AUTH_EXPLAIN' => sprintf($lang[strtoupper('FORUM_AUTH_LIST_EXPLAIN_' . $forum_auth_fields[$k])], $lang[strtoupper('FORUM_AUTH_LIST_EXPLAIN_' . $item_auth_level)])) + ); + } + } + } + } +} +else +{ + // + // output the authorisation details if an category id was + // specified + // + + // + // first display the current details for all forums + // in the category + // + for ($i=0; $iassign_block_vars('forum_auth_titles', array( + 'CELL_TITLE' => $field_names[$forum_auth_fields[$i]]) + ); + } + + // obtain the category list + $sql = "SELECT c.cat_id, c.cat_title, c.cat_order + FROM " . BB_CATEGORIES . " c + WHERE c.cat_id = $cat_id + ORDER BY c.cat_order"; + if( !($result = DB()->sql_query($sql)) ) + { + message_die(general_error, 'Could not query categories list', '', __line__, __file__, $sql); + } + + $category_rows = DB()->sql_fetchrowset($result); + + $cat_id = $category_rows[0]['cat_id']; + $cat_name = $category_rows[0]['cat_title']; + + $template->assign_block_vars('cat_row', array( + 'CAT_NAME' => htmlCHR($cat_name), + 'CAT_URL' => append_sid('admin_forumauth_list.php'.'?'.POST_CAT_URL.'='.$cat_id)) + ); + + for ($j=0; $jassign_block_vars('cat_row.forum_row', array( + 'ROW_CLASS' => !($j % 2) ? 'row4' : 'row5', + 'FORUM_NAME' => ''.htmlCHR($forum_rows[$j]['forum_name']).'', + 'IS_SUBFORUM' => $forum_rows[$j]['forum_parent'], + )); + + for ($k=0; $kassign_block_vars('cat_row.forum_row.forum_auth_data', array( + 'CELL_VALUE' => $lang['FORUM_' . $item_auth_level], + 'AUTH_EXPLAIN' => sprintf($lang[strtoupper('FORUM_AUTH_LIST_EXPLAIN_' . $forum_auth_fields[$k])], $lang[strtoupper('FORUM_AUTH_LIST_EXPLAIN_' . $item_auth_level)])) + ); + } + } + } + + // + // next generate the information to allow the permissions to be changed + // note: we always read from the first forum in the category + // + for($j = 0; $j < count($forum_auth_fields); $j++) + { + $custom_auth[$j] = ''; + + $template->assign_block_vars('forum_auth_data', array( + 'S_AUTH_LEVELS_SELECT' => $custom_auth[$j]) + ); + } + + // + // finally pass any remaining items to the template + // + $s_hidden_fields = ''; + + $template->assign_vars(array( + 'TPL_AUTH_CAT' => true, + 'CAT_NAME' => htmlCHR($cat_name), + + 'L_AUTH_TITLE' => $lang['AUTH_CONTROL_CATEGORY'], + 'L_AUTH_EXPLAIN' => $lang['CAT_AUTH_LIST_EXPLAIN'], + + 'S_FORUMAUTH_ACTION' => append_sid("admin_forumauth_list.php"), + 'S_COLUMN_SPAN' => count($forum_auth_fields)+1, + 'S_HIDDEN_FIELDS' => $s_hidden_fields) + ); +} + +print_page('admin_forumauth_list.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_forums.php b/upload/admin/admin_forums.php new file mode 100644 index 000000000..36f48b914 --- /dev/null +++ b/upload/admin/admin_forums.php @@ -0,0 +1,1259 @@ + AUTH_ALL, + 'auth_read' => AUTH_ALL, + 'auth_post' => AUTH_REG, + 'auth_reply' => AUTH_REG, + 'auth_edit' => AUTH_REG, + 'auth_delete' => AUTH_REG, + 'auth_sticky' => AUTH_MOD, + 'auth_announce' => AUTH_MOD, + 'auth_vote' => AUTH_REG, + 'auth_pollcreate' => AUTH_REG, + 'auth_attachments' => AUTH_REG, + 'auth_download' => AUTH_REG, +); + +$mode = (@$_REQUEST['mode']) ? (string) $_REQUEST['mode'] : ''; + +$cat_forums = get_cat_forums(); + +if ($orphan_sf_sql = get_orphan_sf()) +{ + fix_orphan_sf($orphan_sf_sql, TRUE); +} +$forum_parent = $cat_id = 0; +$forumname = ''; + +if (isset($_REQUEST['addforum']) || isset($_REQUEST['addcategory'])) +{ + $mode = (isset($_REQUEST['addforum'])) ? "addforum" : "addcat"; + + if ($mode == 'addforum' && isset($_POST['addforum']) && isset($_POST['forumname']) && is_array($_POST['addforum'])) + { + $req_cat_id = array_keys($_POST['addforum']); + $cat_id = $req_cat_id[0]; + $forumname = stripslashes($_POST['forumname'][$cat_id]); + } +} + +$show_main_page = false; + +if ($mode) +{ + switch ($mode) + { + case 'addforum': + case 'editforum': + // + // Show form to create/modify a forum + // + if ($mode == 'editforum') + { + // $newmode determines if we are going to INSERT or UPDATE after posting? + + $l_title = $lang['EDIT_FORUM']; + $newmode = 'modforum'; + $buttonvalue = $lang['UPDATE']; + + $forum_id = intval($_GET[POST_FORUM_URL]); + + $row = get_info('forum', $forum_id); + + $cat_id = $row['cat_id']; + $forumname = $row['forum_name']; + $forumdesc = $row['forum_desc']; + $forumstatus = $row['forum_status']; + $forum_display_sort = $row['forum_display_sort']; + $forum_display_order = $row['forum_display_order']; + $forum_parent = $row['forum_parent']; + $show_on_index = $row['show_on_index']; + $prune_enabled = ($row['prune_days']) ? HTML_CHECKED : ''; + $prune_days = $row['prune_days']; + } + else + { + $l_title = $lang['CREATE_FORUM']; + $newmode = 'createforum'; + $buttonvalue = $lang['CREATE_FORUM']; + + $forumdesc = ''; + $forumstatus = FORUM_UNLOCKED; + $forum_display_sort = 0; + $forum_display_order = 0; + $forum_id = ''; + $show_on_index = 1; + $prune_enabled = ''; + $prune_days = 0; + } + + if (isset($_REQUEST['forum_parent'])) + { + $forum_parent = intval($_REQUEST['forum_parent']); + + if ($parent = get_forum_data($forum_parent)) + { + $cat_id = $parent['cat_id']; + } + } + else if (isset($_REQUEST['c'])) + { + $cat_id = (int) $_REQUEST['c']; + } + + $catlist = get_list('category', $cat_id, TRUE); + $forumlocked = $forumunlocked = ''; + + $forumstatus == ( FORUM_LOCKED ) ? $forumlocked = "selected=\"selected\"" : $forumunlocked = "selected=\"selected\""; + + // These two options ($lang['STATUS_UNLOCKED'] and $lang['STATUS_LOCKED']) seem to be missing from + // the language files. + $lang['STATUS_UNLOCKED'] = isset($lang['STATUS_UNLOCKED']) ? $lang['STATUS_UNLOCKED'] : 'Unlocked'; + $lang['STATUS_LOCKED'] = isset($lang['STATUS_LOCKED']) ? $lang['STATUS_LOCKED'] : 'Locked'; + + $statuslist = "\n"; + $statuslist .= "\n"; + + $forum_display_sort_list = get_forum_display_sort_option($forum_display_sort, 'list', 'sort'); + $forum_display_order_list = get_forum_display_sort_option($forum_display_order, 'list', 'order'); + + $s_hidden_fields = ''; + + $s_parent = '\n"; + $sel_forum = ($forum_parent && !isset($_REQUEST['forum_parent'])) ? $forum_id : $forum_parent; + $s_parent .= sf_get_list('forum', $forum_id, $sel_forum); + + $template->assign_vars(array( + 'TPL_EDIT_FORUM' => true, + + 'S_FORUM_DISPLAY_SORT_LIST' => $forum_display_sort_list, + 'S_FORUM_DISPLAY_ORDER_LIST' => $forum_display_order_list, + 'S_FORUM_ACTION' => append_sid("admin_forums.php"), + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_SUBMIT_VALUE' => $buttonvalue, + 'S_CAT_LIST' => $catlist, + 'S_STATUS_LIST' => $statuslist, + 'S_PRUNE_ENABLED' => $prune_enabled, + + 'SHOW_ON_INDEX' => $show_on_index, + 'L_SHOW_ON_INDEX' => $lang['SF_SHOW_ON_INDEX'], + 'L_PARENT_FORUM' => $lang['SF_PARENT_FORUM'], + 'S_PARENT_FORUM' => $s_parent, + 'CAT_LIST_CLASS' => ($forum_parent) ? 'hidden' : '', + 'SHOW_ON_INDEX_CLASS' => (!$forum_parent) ? 'hidden' : '', + + 'L_FORUM_TITLE' => $l_title, + 'L_FORUM_EXPLAIN' => $lang['FORUM_EDIT_DELETE_EXPLAIN'], + 'L_FORUM_DESCRIPTION' => $lang['FORUM_DESC'], + 'L_AUTO_PRUNE' => $lang['FORUM_PRUNING'], + + 'PRUNE_DAYS' => $prune_days, + 'FORUM_NAME' => htmlCHR($forumname), + 'DESCRIPTION' => htmlCHR($forumdesc), + )); + break; + + case 'createforum': + // + // Create a forum in the DB + // + $cat_id = intval($_POST[POST_CAT_URL]); + $forum_name = str_replace("\'", "''", trim($_POST['forumname'])); + $forum_desc = str_replace("\'", "''", trim($_POST['forumdesc'])); + $forum_status = intval($_POST['forumstatus']); + + $prune_enable = isset($_POST['prune_enable']); + $prune_days = ($prune_enable) ? intval($_POST['prune_days']) : 0; + + $forum_parent = ($_POST['forum_parent'] != -1) ? intval($_POST['forum_parent']) : 0; + $show_on_index = ($forum_parent) ? intval($_POST['show_on_index']) : 1; + + $forum_display_sort = intval($_POST['forum_display_sort']); + $forum_display_order = intval($_POST['forum_display_order']); + + if (!$forum_name) + { + message_die(GENERAL_ERROR, "Can't create a forum without a name"); + } + + if ($forum_parent) + { + if (!$parent = get_forum_data($forum_parent)) + { + message_die(GENERAL_ERROR, "Parent forum with id=$forum_parent not found"); + } + + $cat_id = $parent['cat_id']; + $forum_parent = ($parent['forum_parent']) ? $parent['forum_parent'] : $parent['forum_id']; + $forum_order = $parent['forum_order'] + 5; + } + else + { + $max_order = get_max_forum_order($cat_id); + $forum_order = $max_order + 5; + } + + if ($prune_enable && !$prune_days) + { + message_die(GENERAL_MESSAGE, $lang['SET_PRUNE_DATA']); + } + + // Default permissions of public forum + $field_sql = $value_sql = ''; + + foreach ($default_forum_auth as $field => $value) + { + $field_sql .= ", $field"; + $value_sql .= ", $value"; + } + + $columns = ' forum_name, cat_id, forum_desc, forum_order, forum_status, prune_days, forum_parent, show_on_index, forum_display_sort, forum_display_order'. $field_sql; + $values = "'$forum_name', $cat_id, '$forum_desc', $forum_order, $forum_status, $prune_days, $forum_parent, $show_on_index, $forum_display_sort, $forum_display_order". $value_sql; + + DB()->query("INSERT INTO ". BB_FORUMS ." ($columns) VALUES ($values)"); + + renumber_order('forum', $cat_id); + $datastore->update('cat_forums'); + + $message = $lang['FORUMS_UPDATED'] . "

" . sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + message_die(GENERAL_MESSAGE, $message); + + break; + + case 'modforum': + // + // Modify a forum in the DB + // + $cat_id = intval($_POST[POST_CAT_URL]); + $forum_id = intval($_POST[POST_FORUM_URL]); + $forum_name = str_replace("\'", "''", trim($_POST['forumname'])); + $forum_desc = str_replace("\'", "''", trim($_POST['forumdesc'])); + $forum_status = intval($_POST['forumstatus']); + + $prune_enable = isset($_POST['prune_enable']); + $prune_days = ($prune_enable) ? intval($_POST['prune_days']) : 0; + + $forum_parent = ($_POST['forum_parent'] != -1) ? intval($_POST['forum_parent']) : 0; + $show_on_index = ($forum_parent) ? intval($_POST['show_on_index']) : 1; + + $forum_display_order = intval($_POST['forum_display_order']); + $forum_display_sort = intval($_POST['forum_display_sort']); + + $forum_data = get_forum_data($forum_id); + $old_cat_id = $forum_data['cat_id']; + $forum_order = $forum_data['forum_order']; + + if (!$forum_name) + { + message_die(GENERAL_ERROR, "Can't modify a forum without a name"); + } + + if ($forum_parent) + { + if (!$parent = get_forum_data($forum_parent)) + { + message_die(GENERAL_ERROR, "Parent forum with id=$forum_parent not found"); + } + + $cat_id = $parent['cat_id']; + $forum_parent = ($parent['forum_parent']) ? $parent['forum_parent'] : $parent['forum_id']; + $forum_order = $parent['forum_order'] + 5; + + if ($forum_id == $forum_parent) + { + message_die(GENERAL_ERROR, "Ambiguous forum ID's. Please select other parent forum", '', __LINE__, __FILE__); + } + } + else if ($cat_id != $old_cat_id) + { + $max_order = get_max_forum_order($cat_id); + $forum_order = $max_order + 5; + } + else if ($forum_data['forum_parent']) + { + $old_parent = $forum_data['forum_parent']; + $forum_order = $cat_forums[$old_cat_id]['f'][$old_parent]['forum_order'] - 5; + } + + if ($prune_enable && !$prune_days) + { + message_die(GENERAL_MESSAGE, $lang['SET_PRUNE_DATA']); + } + + DB()->query(" + UPDATE ". BB_FORUMS ." SET + forum_name = '$forum_name', + cat_id = $cat_id, + forum_desc = '$forum_desc', + forum_order = $forum_order, + forum_status = $forum_status, + prune_days = $prune_days, + forum_parent = $forum_parent, + show_on_index = $show_on_index, + forum_display_order = $forum_display_order, + forum_display_sort = $forum_display_sort + WHERE forum_id = $forum_id + "); + + if ($cat_id != $old_cat_id) + { + change_sf_cat($forum_id, $cat_id, $forum_order); + renumber_order('forum', $cat_id); + } + + renumber_order('forum', $old_cat_id); + + $cat_forums = get_cat_forums(); + $fix = fix_orphan_sf(); + $datastore->update('cat_forums'); + + $message = $lang['FORUMS_UPDATED'] . "

"; + $message .= ($fix) ? "$fix

" : ''; + $message .= sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + message_die(GENERAL_MESSAGE, $message); + + break; + + case 'addcat': + // + // Create a category in the DB + // + verify_sid(); + + if (!$new_cat_title = trim($_POST['categoryname'])) + { + bb_die('Category name is empty'); + } + + check_name_dup('cat', $new_cat_title); + + $order = DB()->fetch_row("SELECT MAX(cat_order) AS max_order FROM ". BB_CATEGORIES); + + $args = DB()->build_array('INSERT', array( + 'cat_title' => (string) $new_cat_title, + 'cat_order' => (int) $order['max_order'] + 10, + )); + + DB()->query("INSERT INTO ". BB_CATEGORIES . $args); + + $datastore->update('cat_forums'); + + $message = $lang['FORUMS_UPDATED'] . "

" . sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + message_die(GENERAL_MESSAGE, $message); + + break; + + case 'editcat': + // + // Show form to edit a category + // + $cat_id = (int) $_GET['c']; + $cat_info = get_info('category', $cat_id); + + $hidden_fields = array( + 'mode' => 'modcat', + 'c' => $cat_id, + ); + + $template->assign_vars(array( + 'TPL_EDIT_CATEGORY' => true, + + 'CAT_TITLE' => htmlCHR($cat_info['cat_title']), + 'L_EDIT_CAT' => $lang['EDIT_CATEGORY'], + 'L_EDIT_CAT_EXPL' => $lang['EDIT_CATEGORY_EXPLAIN'], + 'S_HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + 'S_SUBMIT_VALUE' => $lang['UPDATE'], + 'S_FORUM_ACTION' => "admin_forums.php", + )); + + break; + + case 'modcat': + // + // Modify a category in the DB + // + verify_sid(); + + if (!$new_cat_title = trim($_POST['cat_title'])) + { + bb_die('Category name is empty'); + } + + $cat_id = (int) $_POST['c']; + + $row = get_info('category', $cat_id); + $cur_cat_title = $row['cat_title']; + + if ($cur_cat_title && $cur_cat_title !== $new_cat_title) + { + check_name_dup('cat', $new_cat_title); + + $new_cat_title_sql = DB()->escape($new_cat_title); + + DB()->query(" + UPDATE ". BB_CATEGORIES ." SET + cat_title = '$new_cat_title_sql' + WHERE cat_id = $cat_id + "); + } + + $datastore->update('cat_forums'); + + $message = $lang['FORUMS_UPDATED'] . "

" . sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + message_die(GENERAL_MESSAGE, $message); + + break; + + case 'deleteforum': + // + // Show form to delete a forum + // + $forum_id = (int) $_GET['f']; + + $move_to_options = ''; + $move_to_options .= sf_get_list('forum', $forum_id, 0); + + $foruminfo = get_info('forum', $forum_id); + + $hidden_fields = array( + 'mode' => 'movedelforum', + 'from_id' => $forum_id, + ); + + $template->assign_vars(array( + 'TPL_DELETE_FORUM' => true, + + 'WHAT_TO_DELETE' => htmlCHR($foruminfo['forum_name']), + 'DELETE_TITLE' => $lang['FORUM_DELETE'], + 'L_DELETE_EXPL' => $lang['FORUM_DELETE_EXPLAIN'], + 'L_MOVE_CONTENTS' => $lang['MOVE_CONTENTS'], + 'CAT_FORUM_NAME' => $lang['FORUM_NAME'], + + 'S_HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + 'S_FORUM_ACTION' => "admin_forums.php", + 'MOVE_TO_OPTIONS' => $move_to_options, + 'S_SUBMIT_VALUE' => $lang['MOVE_AND_DELETE'], + )); + + break; + + case 'movedelforum': + // + // Move or delete a forum in the DB + // + verify_sid(); + + $from_id = (int) $_POST['from_id']; + $to_id = (int) $_POST['to_id']; + + if ($to_id == -1) + { + // Delete everything from forum + topic_delete('prune', $from_id, 0, true); + } + else + { + // Move all posts + $sql = "SELECT * FROM ". BB_FORUMS ." WHERE forum_id IN($from_id, $to_id)"; + $result = DB()->query($sql); + + if (DB()->num_rows($result) != 2) + { + message_die(GENERAL_ERROR, "Ambiguous forum ID's", "", __LINE__, __FILE__); + } + + // Update topics + DB()->query(" + UPDATE ". BB_TOPICS ." SET + forum_id = $to_id + WHERE forum_id = $from_id + "); + + // Update posts + DB()->query(" + UPDATE ". BB_POSTS ." SET + forum_id = $to_id + WHERE forum_id = $from_id + "); + + // Update torrents + DB()->query(" + UPDATE ". BB_BT_TORRENTS ." SET + forum_id = $to_id + WHERE forum_id = $from_id + "); + + sync('forum', $to_id); + } + + DB()->query("DELETE FROM ". BB_FORUMS ." WHERE forum_id = $from_id"); + DB()->query("DELETE FROM ". BB_AUTH_ACCESS ." WHERE forum_id = $from_id"); + DB()->query("DELETE FROM ". BB_AUTH_ACCESS_SNAP ." WHERE forum_id = $from_id"); + + $cat_forums = get_cat_forums(); + fix_orphan_sf(); + update_user_level('all'); + $datastore->update('cat_forums'); + + $message = $lang['FORUMS_UPDATED'] . "

" . sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + message_die(GENERAL_MESSAGE, $message); + + break; + + case 'deletecat': + // + // Show form to delete a category + // + $cat_id = (int) $_GET['c']; + $catinfo = get_info('category', $cat_id); + $categories_count = $catinfo['number']; + + if ($categories_count == 1) + { + $row = DB()->fetch_row("SELECT COUNT(*) AS forums_count FROM ". BB_FORUMS); + + if ($row['forums_count'] > 0) + { + message_die(GENERAL_ERROR, $lang['MUST_DELETE_FORUMS']); + } + else + { + $template->assign_var('NOWHERE_TO_MOVE', $lang['NOWHERE_TO_MOVE']); + } + } + + $hidden_fields = array( + 'mode' => 'movedelcat', + 'from_id' => $cat_id, + ); + + $template->assign_vars(array( + 'TPL_DELETE_FORUM' => true, + + 'WHAT_TO_DELETE' => htmlCHR($catinfo['cat_title']), + 'DELETE_TITLE' => $lang['CATEGORY_DELETE'], + 'L_DELETE_EXPL' => $lang['FORUM_DELETE_EXPLAIN'], + 'CAT_FORUM_NAME' => $lang['CATEGORY'], + + 'S_HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + 'S_FORUM_ACTION' => "admin_forums.php", + 'MOVE_TO_OPTIONS' => get_list('category', $cat_id, 0), + 'S_SUBMIT_VALUE' => $lang['MOVE_AND_DELETE'], + )); + + break; + + case 'movedelcat': + // + // Move or delete a category in the DB + // + verify_sid(); + + $from_id = (int) $_POST['from_id']; + $to_id = (int) $_POST['to_id']; + + if ($from_id == $to_id || !cat_exists($from_id) || !cat_exists($to_id)) + { + bb_die('Bad input'); + } + + $order_shear = get_max_forum_order($to_id) + 10; + + DB()->query(" + UPDATE ". BB_FORUMS ." SET + cat_id = $to_id, + forum_order = forum_order + $order_shear + WHERE cat_id = $from_id + "); + + DB()->query("DELETE FROM ". BB_CATEGORIES ." WHERE cat_id = $from_id"); + + renumber_order('forum', $to_id); + $cat_forums = get_cat_forums(); + $fix = fix_orphan_sf(); + $datastore->update('cat_forums'); + + $message = $lang['FORUMS_UPDATED'] . "

"; + $message .= ($fix) ? "$fix

" : ''; + $message .= sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + message_die(GENERAL_MESSAGE, $message); + + break; + + case 'forum_order': + // + // Change order of forums + // + $move = intval($_GET['move']); + $forum_id = intval($_GET[POST_FORUM_URL]); + + $forum_info = get_info('forum', $forum_id); + renumber_order('forum', $forum_info['cat_id']); + + $cat_id = $forum_info['cat_id']; + + $move_down_forum_id = FALSE; + $forums = $cat_forums[$cat_id]['f_ord']; + $forum_order = $forum_info['forum_order']; + $prev_forum = (isset($forums[$forum_order - 10])) ? $forums[$forum_order - 10] : FALSE; + $next_forum = (isset($forums[$forum_order + 10])) ? $forums[$forum_order + 10] : FALSE; + + // move selected forum ($forum_id) UP + if ($move < 0 && $prev_forum) + { + if ($forum_info['forum_parent'] && $prev_forum['forum_parent'] != $forum_info['forum_parent']) + { + break; + } + else if ($move_down_forum_id = get_prev_root_forum_id($forums, $forum_order)) + { + $move_up_forum_id = $forum_id; + $move_down_ord_val = (get_sf_count($forum_id) + 1) * 10; + $move_up_ord_val = ((get_sf_count($move_down_forum_id) + 1) * 10) + $move_down_ord_val; + $move_down_forum_order = $cat_forums[$cat_id]['f'][$move_down_forum_id]['forum_order']; + } + } + // move selected forum ($forum_id) DOWN + else if ($move > 0 && $next_forum) + { + if ($forum_info['forum_parent'] && $next_forum['forum_parent'] != $forum_info['forum_parent']) + { + break; + } + else if ($move_up_forum_id = get_next_root_forum_id($forums, $forum_order)) + { + $move_down_forum_id = $forum_id; + $move_down_forum_order = $forum_order; + $move_down_ord_val = (get_sf_count($move_up_forum_id) + 1) * 10; + $move_up_ord_val = ((get_sf_count($move_down_forum_id) + 1) * 10) + $move_down_ord_val; + } + } + else + { + $show_main_page = true; + break; + } + + if ($forum_info['forum_parent']) + { + $sql = 'UPDATE ' . BB_FORUMS . " SET + forum_order = forum_order + $move + WHERE forum_id = $forum_id"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't change forum order", '', __LINE__, __FILE__, $sql); + } + } + else if ($move_down_forum_id) + { + $sql = 'UPDATE '. BB_FORUMS ." SET + forum_order = forum_order + $move_down_ord_val + WHERE cat_id = $cat_id + AND forum_order >= $move_down_forum_order"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't change forum order", '', __LINE__, __FILE__, $sql); + } + + $sql = 'UPDATE '. BB_FORUMS ." SET + forum_order = forum_order - $move_up_ord_val + WHERE forum_id = $move_up_forum_id + OR forum_parent = $move_up_forum_id"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't change forum order", '', __LINE__, __FILE__, $sql); + } + } + + renumber_order('forum', $forum_info['cat_id']); + $datastore->update('cat_forums'); + + $show_main_page = true; + break; + + case 'cat_order': + $move = (int) $_GET['move']; + $cat_id = (int) $_GET['c']; + + DB()->query(" + UPDATE ". BB_CATEGORIES ." SET + cat_order = cat_order + $move + WHERE cat_id = $cat_id + "); + + renumber_order('category'); + $datastore->update('cat_forums'); + + $show_main_page = true; + break; + + case 'forum_sync': + sync('forum', intval($_GET['f'])); + $datastore->update('cat_forums'); + + $show_main_page = true; + break; + + default: + message_die(GENERAL_MESSAGE, $lang['NO_MODE']); + + break; + } +} + +if (!$mode || $show_main_page) +{ + $template->assign_vars(array( + 'TPL_FORUMS_LIST' => true, + + 'S_FORUM_ACTION' => append_sid("admin_forums.php"), + 'L_FORUM_TITLE' => $lang['FORUM_ADMIN_MAIN'], + 'L_FORUM_EXPLAIN' => $lang['FORUM_ADMIN_EXPLAIN'], + 'L_EDIT' => 'edit', //$lang['EDIT'], + 'L_RESYNC' => 'sync', //$lang['RESYNC'] + )); + + $sql = "SELECT cat_id, cat_title, cat_order + FROM " . BB_CATEGORIES . " + ORDER BY cat_order"; + if( !$q_categories = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not query categories list", "", __LINE__, __FILE__, $sql); + } + + if( $total_categories = DB()->num_rows($q_categories) ) + { + $category_rows = DB()->sql_fetchrowset($q_categories); + + $where_cat_sql = $req_cat_id = ''; + + if ($c =& $_REQUEST['c']) + { + if ($c !== 'all') + { + $req_cat_id = (int) $c; + $where_cat_sql = "WHERE cat_id = $req_cat_id"; + } + else + { + $req_cat_id = 'all'; + } + } + else + { + $where_cat_sql = "WHERE cat_id = '-1'"; + } + + $sql = "SELECT * + FROM ". BB_FORUMS ." + $where_cat_sql + ORDER BY cat_id, forum_order"; + if(!$q_forums = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not query forums information", "", __LINE__, __FILE__, $sql); + } + + if( $total_forums = DB()->num_rows($q_forums) ) + { + $forum_rows = DB()->sql_fetchrowset($q_forums); + } + + // + // Okay, let's build the index + // + $gen_cat = array(); + + $bgr_class_1 = 'prow1'; + $bgr_class_2 = 'prow2'; + $bgr_class_over = 'prow3'; + + $template->assign_vars(array( + 'U_ALL_FORUMS' => "admin_forums.php?c=all", + )); + + for($i = 0; $i < $total_categories; $i++) + { + $cat_id = $category_rows[$i]['cat_id']; + + $template->assign_block_vars("catrow", array( + 'S_ADD_FORUM_SUBMIT' => "addforum[$cat_id]", + 'S_ADD_FORUM_NAME' => "forumname[$cat_id]", + + 'CAT_ID' => $cat_id, + 'CAT_DESC' => htmlCHR($category_rows[$i]['cat_title']), + + 'U_CAT_EDIT' => "admin_forums.php?mode=editcat&c=$cat_id", + 'U_CAT_DELETE' => "admin_forums.php?mode=deletecat&c=$cat_id", + 'U_CAT_MOVE_UP' => "admin_forums.php?mode=cat_order&move=-15&c=$cat_id", + 'U_CAT_MOVE_DOWN' => "admin_forums.php?mode=cat_order&move=15&c=$cat_id", + 'U_VIEWCAT' => "admin_forums.php?c=$cat_id", + 'U_CREATE_FORUM' => "admin_forums.php?mode=addforum&c=$cat_id", + )); + + for($j = 0; $j < $total_forums; $j++) + { + $forum_id = $forum_rows[$j]['forum_id']; + + $bgr_class = (!($j % 2)) ? $bgr_class_2 : $bgr_class_1; + $row_bgr = " class=\"$bgr_class\" onmouseover=\"this.className='$bgr_class_over';\" onmouseout=\"this.className='$bgr_class';\""; + + if ($forum_rows[$j]['cat_id'] == $cat_id) + { + + $template->assign_block_vars("catrow.forumrow", array( + 'FORUM_NAME' => htmlCHR($forum_rows[$j]['forum_name']), + 'FORUM_DESC' => htmlCHR($forum_rows[$j]['forum_desc']), + 'NUM_TOPICS' => $forum_rows[$j]['forum_topics'], + 'NUM_POSTS' => $forum_rows[$j]['forum_posts'], + 'PRUNE_DAYS' => ($forum_rows[$j]['prune_days']) ? $forum_rows[$j]['prune_days'] : '-', + + 'ORDER' => $forum_rows[$j]['forum_order'], + 'FORUM_ID' => $forum_rows[$j]['forum_id'], + 'ROW_BGR' => $row_bgr, + + 'SHOW_ON_INDEX' => (bool) $forum_rows[$j]['show_on_index'], + 'FORUM_PARENT' => $forum_rows[$j]['forum_parent'], + 'SF_PAD' => ($forum_rows[$j]['forum_parent']) ? ' style="padding-left: 20px;" ' : '', + 'FORUM_NAME_CLASS' => ($forum_rows[$j]['forum_parent']) ? 'genmed' : 'gen', + 'ADD_SUB_HREF' => "admin_forums.php?mode=addforum&forum_parent={$forum_rows[$j]['forum_id']}", + 'U_VIEWFORUM' => BB_ROOT ."viewforum.php?f=$forum_id", + 'U_FORUM_EDIT' => "admin_forums.php?mode=editforum&f=$forum_id", + 'U_FORUM_DELETE' => "admin_forums.php?mode=deleteforum&f=$forum_id", + 'U_FORUM_MOVE_UP' => "admin_forums.php?mode=forum_order&move=-15&f=$forum_id&c=$req_cat_id", + 'U_FORUM_MOVE_DOWN' => "admin_forums.php?mode=forum_order&move=15&f=$forum_id&c=$req_cat_id", + 'U_FORUM_RESYNC' => "admin_forums.php?mode=forum_sync&f=$forum_id", + )); + + }// if ... forumid == catid + } // for ... forums + } // for ... categories + }// if ... total_categories +} + +print_page('admin_forums.tpl', 'admin'); + +// +// Functions +// +function get_info($mode, $id) +{ + switch($mode) + { + case 'category': + $table = BB_CATEGORIES; + $idfield = 'cat_id'; + $namefield = 'cat_title'; + break; + + case 'forum': + $table = BB_FORUMS; + $idfield = 'forum_id'; + $namefield = 'forum_name'; + break; + + default: + message_die(GENERAL_ERROR, "Wrong mode for generating select list", "", __LINE__, __FILE__); + break; + } + $sql = "SELECT count(*) as total + FROM $table"; + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't get Forum/Category information", "", __LINE__, __FILE__, $sql); + } + $count = DB()->sql_fetchrow($result); + $count = $count['total']; + + $sql = "SELECT * + FROM $table + WHERE $idfield = $id"; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't get Forum/Category information", "", __LINE__, __FILE__, $sql); + } + + if( DB()->num_rows($result) != 1 ) + { + message_die(GENERAL_ERROR, "Forum/Category doesn't exist or multiple forums/categories with ID $id", "", __LINE__, __FILE__); + } + + $return = DB()->sql_fetchrow($result); + $return['number'] = $count; + return $return; +} + +function get_list($mode, $id, $select) +{ + switch($mode) + { + case 'category': + $table = BB_CATEGORIES; + $idfield = 'cat_id'; + $namefield = 'cat_title'; + $order = 'cat_order'; + break; + + case 'forum': + $table = BB_FORUMS; + $idfield = 'forum_id'; + $namefield = 'forum_name'; + $order = 'cat_id, forum_order'; + break; + + default: + message_die(GENERAL_ERROR, "Wrong mode for generating select list", "", __LINE__, __FILE__); + break; + } + + $sql = "SELECT * + FROM $table"; + if( $select == 0 ) + { + $sql .= " WHERE $idfield <> $id"; + } + $sql .= " ORDER BY $order"; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't get list of Categories/Forums", "", __LINE__, __FILE__, $sql); + } + + $catlist = ''; + + while( $row = DB()->sql_fetchrow($result) ) + { + $s = ""; + if ($row[$idfield] == $id) + { + $s = " selected=\"selected\""; + } + $catlist .= "\n"; + } + + return($catlist); +} + +function renumber_order($mode, $cat = 0) +{ + switch($mode) + { + case 'category': + $table = BB_CATEGORIES; + $idfield = 'cat_id'; + $orderfield = 'cat_order'; + $cat = 0; + break; + + case 'forum': + $table = BB_FORUMS; + $idfield = 'forum_id'; + $orderfield = 'forum_order'; + $catfield = 'cat_id'; + break; + + default: + message_die(GENERAL_ERROR, "Wrong mode for generating select list", "", __LINE__, __FILE__); + break; + } + + $sql = "SELECT * FROM $table"; + if( $cat != 0) + { + $sql .= " WHERE $catfield = $cat"; + } + $sql .= " ORDER BY $orderfield ASC"; + + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't get list of Categories", "", __LINE__, __FILE__, $sql); + } + + $i = 10; + $inc = 10; + + while( $row = DB()->sql_fetchrow($result) ) + { + $sql = "UPDATE $table + SET $orderfield = $i + WHERE $idfield = " . $row[$idfield]; + if( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't update order fields", "", __LINE__, __FILE__, $sql); + } + $i += 10; + } + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't get list of Categories", "", __LINE__, __FILE__, $sql); + } + +} + +function get_cat_forums ($cat_id = FALSE) +{ + $forums = array(); + $where_sql = ''; + + if ($cat_id = intval($cat_id)) + { + $where_sql = "AND f.cat_id = $cat_id"; + } + + $sql = 'SELECT c.cat_title, f.* + FROM '. BB_FORUMS .' f, '. BB_CATEGORIES ." c + WHERE f.cat_id = c.cat_id + $where_sql + ORDER BY c.cat_order, f.cat_id, f.forum_order"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't get list of Categories", "", __LINE__, __FILE__, $sql); + } + + if ($rowset = DB()->sql_fetchrowset($result)) + { + foreach ($rowset as $rid => $row) + { + $forums[$row['cat_id']]['cat_title'] = $row['cat_title']; + $forums[$row['cat_id']]['f'][$row['forum_id']] = $row; + $forums[$row['cat_id']]['f_ord'][$row['forum_order']] = $row; + } + } + + return $forums; +} + +function get_sf_count ($forum_id) +{ + global $cat_forums; + + $sf_count = 0; + + foreach ($cat_forums as $cid => $c) + { + foreach ($c['f'] as $fid => $f) + { + if ($f['forum_parent'] == $forum_id) + { + $sf_count++; + } + } + } + + return $sf_count; +} + +function get_prev_root_forum_id ($forums, $curr_forum_order) +{ + $i = $curr_forum_order - 10; + + while ($i > 0) + { + if (isset($forums[$i]) && !$forums[$i]['forum_parent']) + { + return $forums[$i]['forum_id']; + } + $i = $i - 10; + } + + return FALSE; +} + +function get_next_root_forum_id ($forums, $curr_forum_order) +{ + $i = $curr_forum_order + 10; + $limit = (count($forums) * 10) + 10; + + while ($i < $limit) + { + if (isset($forums[$i]) && !$forums[$i]['forum_parent']) + { + return $forums[$i]['forum_id']; + } + $i = $i + 10; + } + + return FALSE; +} + +function get_orphan_sf () +{ + global $cat_forums; + + $last_root = 0; + $bad_sf_ary = array(); + + foreach ($cat_forums as $cid => $c) + { + foreach ($c['f'] as $fid => $f) + { + if ($f['forum_parent']) + { + if ($f['forum_parent'] != $last_root) + { + $bad_sf_ary[] = $f['forum_id']; + } + } + else + { + $last_root = $f['forum_id']; + } + } + } + + return implode(',', $bad_sf_ary); +} + +function fix_orphan_sf ($orphan_sf_sql = '', $show_mess = FALSE) +{ + global $lang; + + $done_mess = ''; + + if (!$orphan_sf_sql) + { + $orphan_sf_sql = get_orphan_sf(); + } + + if ($orphan_sf_sql) + { + $sql = "UPDATE ". BB_FORUMS ." SET + forum_parent = 0, + show_on_index = 1 + WHERE forum_id IN($orphan_sf_sql)"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't change subforums data", '', __LINE__, __FILE__, $sql); + } + + if ($affectedrows = DB()->affected_rows()) + { + $done_mess = "Subforums data corrected. $affectedrows orphan subforum(s) moved to root level."; + } + + if ($show_mess) + { + $message = $done_mess .'

'; + $message .= sprintf($lang['CLICK_RETURN_FORUMADMIN'], "", '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ''); + message_die(GENERAL_MESSAGE, $message); + } + } + + return $done_mess; +} + +function sf_get_list ($mode, $exclude = 0, $select = 0) +{ + global $cat_forums, $forum_parent; + + $opt = ''; + + if ($mode == 'forum') + { + foreach ($cat_forums as $cid => $c) + { + $opt .= ''; + + foreach ($c['f'] as $fid => $f) + { + $selected = ($fid == $select) ? HTML_SELECTED : ''; + $disabled = ($fid == $exclude && !$forum_parent) ? HTML_DISABLED : ''; + $style = ($disabled) ? ' style="color: gray" ' : (($fid == $exclude) ? ' style="color: darkred" ' : ''); + $opt .= '\n"; + } + + $opt .= ''; + } + } + + return $opt; +} + +function get_forum_data ($forum_id) +{ + global $cat_forums; + + foreach ($cat_forums as $cid => $c) + { + foreach ($c['f'] as $fid => $f) + { + if ($fid == $forum_id) + { + return $f; + } + } + } + + return FALSE; +} + +function get_max_forum_order ($cat_id) +{ + $row = DB()->fetch_row(" + SELECT MAX(forum_order) AS max_forum_order + FROM ". BB_FORUMS ." + WHERE cat_id = $cat_id + "); + + return intval($row['max_forum_order']); +} + +function check_name_dup ($mode, $name, $die_on_error = true) +{ + $name_sql = DB()->escape($name); + + if ($mode == 'cat') + { + $what_checked = 'Category'; + $sql = "SELECT cat_id FROM ". BB_CATEGORIES ." WHERE cat_title = '$name_sql'"; + } + else + { + $what_checked = 'Forum'; + $sql = "SELECT forum_id FROM ". BB_FORUMS ." WHERE forum_name = '$name_sql'"; + } + + $name_is_dup = DB()->fetch_row($sql); + + if ($name_is_dup && $die_on_error) + { + bb_die("This $what_checked name taken, please choose something else"); + } + + return $name_is_dup; +} + +/** + * Change subforums cat_id if parent's cat_id was changed + */ +function change_sf_cat ($parent_id, $new_cat_id, $order_shear) +{ + DB()->query(" + UPDATE ". BB_FORUMS ." SET + cat_id = $new_cat_id, + forum_order = forum_order + $order_shear + WHERE forum_parent = $parent_id + "); +} diff --git a/upload/admin/admin_groups.php b/upload/admin/admin_groups.php new file mode 100644 index 000000000..1c82a6291 --- /dev/null +++ b/upload/admin/admin_groups.php @@ -0,0 +1,184 @@ + $row['group_name'], + 'group_description' => $row['group_description'], + 'group_moderator' => $row['group_moderator'], + 'group_mod_name' => $row['moderator_name'], + 'group_type' => $row['group_type'], + ); + $mode = 'editgroup'; + $template->assign_block_vars('group_edit', array()); + } + else if (!empty($_POST['new'])) + { + $group_info = array( + 'group_name' => '', + 'group_description' => '', + 'group_moderator' => '', + 'group_mod_name' => '', + 'group_type' => GROUP_OPEN, + ); + $mode = 'newgroup'; + } + + // Ok, now we know everything about them, let's show the page. + $s_hidden_fields = ' + + + '; + + $template->assign_vars(array( + 'TPL_EDIT_GROUP' => true, + + 'GROUP_NAME' => stripslashes(htmlspecialchars($group_info['group_name'])), + 'GROUP_DESCRIPTION' => stripslashes(htmlspecialchars($group_info['group_description'])), + 'GROUP_MODERATOR' => replace_quote($group_info['group_mod_name']), + 'T_GROUP_EDIT_DELETE' => ($mode == 'newgroup') ? $lang['CREATE_NEW_GROUP'] : $lang['EDIT_GROUP'], + 'U_SEARCH_USER' => append_sid(BB_ROOT ."search.php?mode=searchuser"), + 'S_GROUP_OPEN_TYPE' => GROUP_OPEN, + 'S_GROUP_CLOSED_TYPE' => GROUP_CLOSED, + 'S_GROUP_HIDDEN_TYPE' => GROUP_HIDDEN, + 'S_GROUP_OPEN_CHECKED' => ($group_info['group_type'] == GROUP_OPEN) ? HTML_CHECKED : '', + 'S_GROUP_CLOSED_CHECKED' => ($group_info['group_type'] == GROUP_CLOSED) ? HTML_CHECKED : '', + 'S_GROUP_HIDDEN_CHECKED' => ($group_info['group_type'] == GROUP_HIDDEN ) ? HTML_CHECKED : '', + 'S_GROUP_ACTION' => append_sid("admin_groups.php"), + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); +} +else if (!empty($_POST['group_update'])) +{ + if (!empty($_POST['group_delete'])) + { + if (!$group_info = get_group_data($group_id)) + { + bb_die($lang['GROUP_NOT_EXIST']); + } + // Delete Group + delete_group($group_id); + + $message = $lang['DELETED_GROUP'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_GROUPSADMIN'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); + } + else + { + $group_type = isset($_POST['group_type']) ? intval($_POST['group_type']) : GROUP_OPEN; + $group_name = isset($_POST['group_name']) ? trim($_POST['group_name']) : ''; + $group_desc = isset($_POST['group_description']) ? trim($_POST['group_description']) : ''; + + $group_moderator = isset($_POST['username']) ? $_POST['username'] : ''; + + if ($group_name === '') + { + bb_die($lang['NO_GROUP_NAME']); + } + else if ($group_moderator === '') + { + bb_die($lang['NO_GROUP_MODERATOR']); + } + $this_userdata = get_userdata($group_moderator, true); + + if (!$group_moderator = $this_userdata['user_id']) + { + bb_die($lang['NO_GROUP_MODERATOR']); + } + + $sql_ary = array( + 'group_type' => (int) $group_type, + 'group_name' => (string) $group_name, + 'group_description' => (string) $group_desc, + 'group_moderator' => (int) $group_moderator, + 'group_single_user' => 0, + ); + + if ($mode == "editgroup") + { + if (!$group_info = get_group_data($group_id)) + { + bb_die($lang['GROUP_NOT_EXIST']); + } + + if ($group_info['group_moderator'] != $group_moderator) + { + // Create user_group for new group's moderator + add_user_into_group($group_id, $group_moderator); + + // Delete old moderator's user_group + if (@$_POST['delete_old_moderator']) + { + delete_user_group($group_id, $group_info['group_moderator']); + } + } + + $sql_args = DB()->build_array('UPDATE', $sql_ary); + + // Update group's data + DB()->query("UPDATE ". BB_GROUPS ." SET $sql_args WHERE group_id = $group_id"); + + $message = $lang['UPDATED_GROUP'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_GROUPSADMIN'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); + } + else if ($mode == 'newgroup') + { + $sql_args = DB()->build_array('INSERT', $sql_ary); + + // Create new group + DB()->query("INSERT INTO ". BB_GROUPS ." $sql_args"); + $new_group_id = DB()->sql_nextid(); + + // Create user_group for group's moderator + add_user_into_group($new_group_id, $group_moderator); + + $message = $lang['ADDED_NEW_GROUP'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_GROUPSADMIN'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); + } + else + { + bb_die($lang['NO_GROUP_ACTION']); + } + } +} +else +{ + $template->assign_vars(array( + 'TPL_GROUP_SELECT' => true, + + 'S_GROUP_ACTION' => append_sid("admin_groups.php"), + 'S_GROUP_SELECT' => stripslashes(get_select('groups')), + )); +} + +print_page('admin_groups.tpl', 'admin'); diff --git a/upload/admin/admin_log.php b/upload/admin/admin_log.php new file mode 100644 index 000000000..6e6c381e2 --- /dev/null +++ b/upload/admin/admin_log.php @@ -0,0 +1,435 @@ +enqueue(array( + 'moderators', +)); + +$log_action->init(); + +$per_page = 50; +$row_class_1 = 'prow1'; +$row_class_2 = 'prow2'; +$def_days = 3; +$def_datetime = TIMENOW; +$max_forum_name_len = 40; +$title_match_max_len = 60; +$poster_name_max_len = 25; +$select_max_height = 16; +$dt_format = 'Y-m-d'; // used in one-day filter + +$url = append_sid(basename(__FILE__)); + +// Key names +$type_key = 'type'; +$forum_key = 'f'; +$topic_key = 't'; +$user_key = 'u'; +$datetime_key = 'dt'; // value should be strtotime() time ("2006-06-25" etc.) +$daysback_key = 'db'; +$sort_key = 'sort'; +$title_match_key = 'tm'; + +// Key values +$all_types = 0; // =| +$all_users = 0; // |> only "0" is a valid value +$all_forums = 0; // =| + +$sort_asc = 'ASC'; +$sort_desc = 'DESC'; + +// Defaults +$def_types = $all_types; +$def_users = $all_users; +$def_forums = $all_forums; +$def_sort = $sort_desc; + +// Moderators data +if (!$mod = $datastore->get('moderators')) +{ + $datastore->update('moderators'); + $mod = $datastore->get('moderators'); +} +array_deep($mod['moderators'], 'html_entity_decode'); +array_deep($mod['admins'], 'html_entity_decode'); + +$users = array($lang['ACTS_LOG_ALL_ACTIONS'] => $all_users) + array_flip($mod['moderators']) + array_flip($mod['admins']); + +unset($mod); + +// Forums data +if (!$forums = $datastore->get('cat_forums')) +{ + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); +} +$f_data = $forums['f']; + +unset($forums); + +// Start +$start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; + +// Type +$type_selected = array($def_types); +$type_csv = ''; + +if ($var =& $_REQUEST[$type_key]) +{ + $type_selected = get_id_ary($var); + + if (in_array($all_types, $type_selected)) + { + $type_selected = array($all_types); + } + $type_csv = join(',', $type_selected); + $url = ($type_csv != $def_types) ? url_arg($url, $type_key, $type_csv) : $url; +} + +// User +$user_selected = array($def_users); +$user_csv = ''; + +if ($var =& $_REQUEST[$user_key]) +{ + $user_selected = get_id_ary($var); + + if (in_array($all_users, $user_selected)) + { + $user_selected = array($all_users); + } + $user_csv = join(',', $user_selected); + $url = ($user_csv != $def_users) ? url_arg($url, $user_key, $user_csv) : $url; +} + +// Forum +$forum_selected = array($def_forums); +$forum_csv = ''; + +if ($var =& $_REQUEST[$forum_key]) +{ + $forum_selected = get_id_ary($var); + + if (in_array($all_forums, $forum_selected)) + { + $forum_selected = array($all_forums); + } + $forum_csv = join(',', $forum_selected); + $url = ($forum_csv != $def_forums) ? url_arg($url, $forum_key, $forum_csv) : $url; +} + +// Topic +$topic_selected = null; +$topic_csv = ''; + +if ($var =& $_REQUEST[$topic_key]) +{ + $topic_selected = get_id_ary($var); + $topic_csv = join(',', $topic_selected); + $url = ($topic_csv) ? url_arg($url, $topic_key, $topic_csv) : $url; +} + +// Order +$order_val = 'log_time'; + +// Sort +$sort_val = $def_sort; + +if ($var =& $_REQUEST[$sort_key] AND $var != $def_sort) +{ + $sort_val = ($var == $sort_asc) ? $sort_asc : $sort_desc; + $url = url_arg($url, $sort_key, $sort_val); +} + +// Time +$datetime_val = $def_datetime; +$daysback_val = $def_days; + +if ($var =& $_REQUEST[$daysback_key] AND $var != $def_days) +{ + $daysback_val = max(intval($var), 1); + $url = url_arg($url, $daysback_key, $daysback_val); +} +if ($var =& $_REQUEST[$datetime_key] AND $var != $def_datetime) +{ + $tz = TIMENOW + (3600 * $bb_cfg['board_timezone']); + if (($tmp_timestamp = strtotime($var, $tz)) > 0) + { + $datetime_val = $tmp_timestamp; + $url = url_arg($url, $datetime_key, date($dt_format, $datetime_val)); + } +} + +$time_end_val = 86400 + mktime(0, 0, 0, date('m', $datetime_val), date('d', $datetime_val), date('Y', $datetime_val)); +$time_start_val = $time_end_val - 86400*$daysback_val; + +// First log time +$row = DB()->fetch_row("SELECT MIN(log_time) AS first_log_time FROM ". BB_LOG); +$first_log_time = (int) $row['first_log_time']; + +// Title match +$title_match_val = $title_match_sql = ''; + +if ($var =& $_REQUEST[$title_match_key]) +{ + if ($tmp_title_match = substr(urldecode(trim($var)), 0, $title_match_max_len)) + { + $title_match_val = htmlspecialchars($tmp_title_match); + $title_match_sql = DB()->escape($tmp_title_match); + $url = url_arg($url, $title_match_key, urlencode($tmp_title_match)); + } +} + +// +// SQL +// +$select = "SELECT *"; + +$from = "FROM ". BB_LOG; + +$where = " + WHERE log_time BETWEEN $time_start_val AND $time_end_val +"; +$where .= ($type_csv) ? " + AND log_type_id IN($type_csv) +" : ''; +$where .= ($user_csv) ? " + AND log_user_id IN($user_csv) +" : ''; +$where .= ($forum_csv) ? " + AND log_forum_id IN($forum_csv) +" : ''; +$where .= ($topic_csv) ? " + AND log_topic_id IN($topic_csv) +" : ''; +$where .= ($title_match_sql) ? " + AND MATCH (log_topic_title) AGAINST ('$title_match_sql' IN BOOLEAN MODE) +" : ''; + +$order = "ORDER BY $order_val"; + +$sort = $sort_val; + +$limit = "LIMIT $start, ". ($per_page + 1); + +$sql = " + $select + $from + $where + $order + $sort + $limit +"; + +$log_rowset = DB()->fetch_rowset($sql); +$log_count = count($log_rowset); + +if ($log_count == $per_page + 1) +{ + $items_count = $start + ($per_page * 2); + $pages = '?'; + array_pop($log_rowset); +} +else +{ + $items_count = $start + $log_count; + $pages = (!$log_count) ? 1 : ceil($items_count / $per_page); +} + +$template->assign_vars(array( + 'PAGINATION' => generate_pagination($url, $items_count, $per_page, $start), + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], floor($start / $per_page) + 1, $pages), +)); + +$filter = array(); + +if ($log_rowset) +{ + $log_type = $log_action->log_type; + $log_type_flip = array_flip($log_type); + + foreach ($log_rowset as $row_num => $row) + { + $msg = ''; + $forum_name = $forum_name_new = ''; + $topic_title = $topic_title_new = ''; + + $topic_deleted = ($row['log_type_id'] == $log_type['mod_topic_delete']); + + switch ($row['log_type_id']) + { + case $log_type['mod_topic_delete']: + case $log_type['mod_topic_move']: + case $log_type['mod_topic_lock']: + case $log_type['mod_topic_unlock']: + case $log_type['mod_post_delete']: + case $log_type['mod_topic_split']: + // topic_title + if (!empty($row['log_topic_title'])) + { + $topic_title = $row['log_topic_title']; + } + // topic_title_new + if (!empty($row['log_topic_title_new'])) + { + $topic_title_new = $row['log_topic_title_new']; + } + // forum_name + if ($fid =& $row['log_forum_id']) + { + $forum_name = ($fname =& $f_data[$fid]['forum_name']) ? $fname : 'id:'. $row['log_forum_id']; + } + // forum_name_new + if ($fid =& $row['log_forum_id_new']) + { + $forum_name_new = ($fname =& $f_data[$fid]['forum_name']) ? $fname : 'id:'. $row['log_forum_id']; + } + + break; + } + + $msg .= " $row[log_msg]"; + + $row_class = !($row_num & 1) ? $row_class_1 : $row_class_2; + + $datetime_href_s = url_arg($url, $datetime_key, date($dt_format, $row['log_time'])); + $datetime_href_s = url_arg($datetime_href_s, $daysback_key, 1); + + $template->assign_block_vars('log', array( + 'ACTION_DESC' => $lang['LOG_ACTION']['LOG_TYPE'][$log_type_flip[$row['log_type_id']]], + 'ACTION_HREF_S' => url_arg($url, $type_key, $row['log_type_id']), + + 'USER_ID' => $row['log_user_id'], + 'USERNAME' => $row['log_username'], + 'USER_HREF_S' => url_arg($url, $user_key, $row['log_user_id']), + 'USER_IP' => decode_ip($row['log_user_ip']), + + 'FORUM_ID' => $row['log_forum_id'], + 'FORUM_HREF' => BB_ROOT . FORUM_URL . $row['log_forum_id'], + 'FORUM_HREF_S' => url_arg($url, $forum_key, $row['log_forum_id']), + 'FORUM_NAME' => htmlCHR($forum_name), + + 'FORUM_ID_NEW' => $row['log_forum_id_new'], + 'FORUM_HREF_NEW' => BB_ROOT . FORUM_URL . $row['log_forum_id_new'], + 'FORUM_HREF_NEW_S' => url_arg($url, $forum_key, $row['log_forum_id_new']), + 'FORUM_NAME_NEW' => htmlCHR($forum_name_new), + + 'TOPIC_ID' => $row['log_topic_id'], + 'TOPIC_HREF' => (!$topic_deleted) ? BB_ROOT . TOPIC_URL . $row['log_topic_id'] : '', + 'TOPIC_HREF_S' => url_arg($url, $topic_key, $row['log_topic_id']), + 'TOPIC_TITLE' => $topic_title, + + 'TOPIC_ID_NEW' => $row['log_topic_id_new'], + 'TOPIC_HREF_NEW' => BB_ROOT . TOPIC_URL . $row['log_topic_id_new'], + 'TOPIC_HREF_NEW_S' => url_arg($url, $topic_key, $row['log_topic_id_new']), + 'TOPIC_TITLE_NEW' => $topic_title_new, + + 'DATE' => bb_date($row['log_time'], 'j-M'), + 'TIME' => bb_date($row['log_time'], 'H:i'), + 'DATETIME_HREF_S' => $datetime_href_s, + 'MSG' => $msg, + 'ROW_CLASS' => $row_class, + + )); + + // Topics + if ($topic_csv && empty($filter['topics'][$row['log_topic_title']])) + { + $template->assign_block_vars('topics', array( + 'TOPIC_TITLE' => $row['log_topic_title'], + )); + $filter['topics'][$row['log_topic_title']] = true; + } + // Forums + if ($forum_csv && empty($filter['forums'][$forum_name])) + { + $template->assign_block_vars('forums', array( + 'FORUM_NAME' => htmlCHR($forum_name), + )); + $filter['forums'][$forum_name] = true; + } + // Users + if ($user_csv && empty($filter['users'][$row['log_username']])) + { + $template->assign_block_vars('users', array( + 'USERNAME' => $row['log_username'], + )); + $filter['users'][$row['log_username']] = true; + } + } + + $template->assign_vars(array( + 'FILTERS' => ($topic_csv || $forum_csv || $user_csv), + 'FILTER_TOPICS' => !empty($filter['topics']), + 'FILTER_FORUMS' => !empty($filter['forums']), + 'FILTER_USERS' => !empty($filter['users']), + )); +} +else +{ + $template->assign_block_vars('log_not_found', array()); +} + +// +// Selects +// +$log_type_select = array($lang['ACTS_LOG_ALL_ACTIONS'] => $all_types) + $log_action->log_type_select; + +// Order select +$order_options = ''; + +$template->assign_vars(array( + 'LOG_COLSPAN' => 4, + + 'L_NO_MATCH' => $lang['NO_MATCH'], + 'L_ADM_LOG_ALL_ACTIONS' => $lang['ACTS_LOG_ALL_ACTIONS'], + 'L_ADM_LOG_SEARCH_OPTIONS' => $lang['ACTS_LOG_SEARCH_OPTIONS'], + 'L_ADM_LOG_FORUM' => $lang['ACTS_LOG_FORUM'], + 'L_ADM_LOG_ACTION' => $lang['ACTS_LOG_ACTION'], + 'L_ADM_LOG_USER' => $lang['ACTS_LOG_USER'], + 'L_ADM_LOG_LOGS_FROM' => $lang['ACTS_LOG_LOGS_FROM'], + 'L_ADM_LOG_FIRST' => $lang['ACTS_LOG_FIRST'], + 'L_ADM_LOG_DAYS_BACK' => $lang['ACTS_LOG_DAYS_BACK'], + 'L_ADM_LOG_TOPIC_MATCH' => $lang['ACTS_LOG_TOPIC_MATCH'], + 'L_ADM_LOG_SORT_BY' => $lang['ACTS_LOG_SORT_BY'], + 'L_ADM_LOG_ACTION' => $lang['ACTS_LOG_LOGS_ACTION'], + 'L_ADM_LOG_USERNAME' => $lang['ACTS_LOG_USERNAME'], + 'L_ADM_LOG_TIME' => $lang['ACTS_LOG_TIME'], + 'L_ADM_LOG_INFO' => $lang['ACTS_LOG_INFO'], + + 'DATETIME_NAME' => $datetime_key, + 'DATETIME_VAL' => date('Y-m-d', $datetime_val), + 'DAYSBACK_NAME' => $daysback_key, + 'DAYSBACK_VAL' => $daysback_val, + 'FIRST_LOG_TIME' => ($first_log_time) ? date('Y-m-d', $first_log_time) : 'none', + + 'TITLE_MATCH_MAX' => $title_match_max_len, + 'TITLE_MATCH_NAME' => $title_match_key, + 'TITLE_MATCH_VAL' => $title_match_val, + + 'ORDER_NAME' => '', + 'ORDER_OPTIONS' => $order_options, + + 'SORT_NAME' => $sort_key, + 'SORT_ASC' => $sort_asc, + 'SORT_DESC' => $sort_desc, + 'SORT_ASC_CHECKED' => ($sort_val == $sort_asc) ? HTML_CHECKED : '', + 'SORT_DESC_CHECKED' => ($sort_val == $sort_desc) ? HTML_CHECKED : '', + + 'SEL_FORUM' => get_forum_select('admin', "{$forum_key}[]", $forum_selected, $max_forum_name_len, $select_max_height, '', $all_forums), + 'SEL_LOG_TYPE' => build_select("{$type_key}[]", $log_type_select, $type_selected, 60, $select_max_height), + 'SEL_USERS' => build_select("{$user_key}[]", $users, $user_selected, 16, $select_max_height), + + 'S_LOG_ACTION' => append_sid("admin_log.php"), + 'TOPIC_CSV' => $topic_csv, +)); + +print_page('admin_log.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_mass_email.php b/upload/admin/admin_mass_email.php new file mode 100644 index 000000000..53b839a12 --- /dev/null +++ b/upload/admin/admin_mass_email.php @@ -0,0 +1,162 @@ +' . $lang['EMPTY_SUBJECT'] : $lang['EMPTY_SUBJECT']; + } + + if ( empty($message) ) + { + $error = true; + $error_msg .= ( !empty($error_msg) ) ? '
' . $lang['EMPTY_MESSAGE'] : $lang['EMPTY_MESSAGE']; + } + + $group_id = intval($_POST[POST_GROUPS_URL]); + + $sql = ( $group_id != -1 ) ? "SELECT u.user_email FROM " . BB_USERS . " u, " . BB_USER_GROUP . " ug WHERE ug.group_id = $group_id AND ug.user_pending <> 1 AND u.user_id = ug.user_id" : "SELECT user_email FROM " . BB_USERS; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select group members', '', __LINE__, __FILE__, $sql); + } + + if ( $row = DB()->sql_fetchrow($result) ) + { + $bcc_list = array(); + do + { + $bcc_list[] = $row['user_email']; + } + while ( $row = DB()->sql_fetchrow($result) ); + + DB()->sql_freeresult($result); + } + else + { + $message = ( $group_id != -1 ) ? $lang['GROUP_NOT_EXIST'] : $lang['NO_SUCH_USER']; + + $error = true; + $error_msg .= ( !empty($error_msg) ) ? '
' . $message : $message; + } + + if ( !$error ) + { + include(INC_DIR . 'emailer.class.php'); + + // + // Let's do some checking to make sure that mass mail functions + // are working in win32 versions of php. + // + if ( preg_match('/[c-z]:\\\.*/i', getenv('PATH')) && !$bb_cfg['smtp_delivery']) + { + $ini_val = ( @phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var'; + + // We are running on windows, force delivery to use our smtp functions + // since php's are broken by default + $bb_cfg['smtp_delivery'] = 1; + $bb_cfg['smtp_host'] = @$ini_val('SMTP'); + } + + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + for ($i = 0; $i < count($bcc_list); $i++) + { + $emailer->bcc($bcc_list[$i]); + } + + $email_headers = 'X-AntiAbuse: Board servername - ' . $bb_cfg['server_name'] . "\n"; + $email_headers .= 'X-AntiAbuse: User_id - ' . $userdata['user_id'] . "\n"; + $email_headers .= 'X-AntiAbuse: Username - ' . $userdata['username'] . "\n"; + $email_headers .= 'X-AntiAbuse: User IP - ' . CLIENT_IP . "\n"; + + $emailer->use_template('admin_send_email'); + $emailer->email_address($bb_cfg['board_email']); + $emailer->set_subject($subject); + $emailer->extra_headers($email_headers); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'BOARD_EMAIL' => $bb_cfg['board_email'], + 'MESSAGE' => $message) + ); + $emailer->send(); + $emailer->reset(); + + message_die(GENERAL_MESSAGE, $lang['EMAIL_SENT'] . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', '')); + } +} + +if ( @$error ) +{ + $template->assign_vars(array('ERROR_MESSAGE' => $error_msg)); +} + +// +// Initial selection +// + +$sql = "SELECT group_id, group_name + FROM ".BB_GROUPS . " + WHERE group_single_user <> 1"; +if ( !($result = DB()->sql_query($sql)) ) +{ + message_die(GENERAL_ERROR, 'Could not obtain list of groups', '', __LINE__, __FILE__, $sql); +} + +$select_list = ''; + +// +// Generate page +// +require(PAGE_HEADER); + +$template->assign_vars(array( + 'MESSAGE' => $message, + 'SUBJECT' => $subject, + + 'L_EMAIL_EXPLAIN' => $lang['MASS_EMAIL_EXPLAIN'], + 'L_EMAIL_SUBJECT' => $lang['SUBJECT'], + 'L_NOTICE' => @$notice, + + 'S_USER_ACTION' => append_sid('admin_mass_email.php'), + 'S_GROUP_SELECT' => $select_list) +); + +print_page('admin_mass_email.tpl', 'admin'); diff --git a/upload/admin/admin_phpinfo.php b/upload/admin/admin_phpinfo.php new file mode 100644 index 000000000..954ae38a4 --- /dev/null +++ b/upload/admin/admin_phpinfo.php @@ -0,0 +1,12 @@ +update('ranks'); } +register_shutdown_function('update_ranks'); + +require('./pagestart.php'); +// ACP Header - END + +$_POST['special_rank'] = 1; +$_POST['min_posts'] = -1; + +if( isset($_GET['mode']) || isset($_POST['mode']) ) +{ + $mode = isset($_GET['mode']) ? $_GET['mode'] : $_POST['mode']; +} +else +{ + // + // These could be entered via a form button + // + if( isset($_POST['add']) ) + { + $mode = "add"; + } + else if( isset($_POST['save']) ) + { + $mode = "save"; + } + else + { + $mode = ""; + } +} + + +if( $mode != "" ) +{ + if( $mode == "edit" || $mode == "add" ) + { + // + // They want to add a new rank, show the form. + // + $rank_id = ( isset($_GET['id']) ) ? intval($_GET['id']) : 0; + + $s_hidden_fields = ""; + + if( $mode == "edit" ) + { + if( empty($rank_id) ) + { + message_die(GENERAL_MESSAGE, $lang['MUST_SELECT_RANK']); + } + + $sql = "SELECT * FROM " . BB_RANKS . " + WHERE rank_id = $rank_id"; + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't obtain rank data", "", __LINE__, __FILE__, $sql); + } + + $rank_info = DB()->sql_fetchrow($result); + $s_hidden_fields .= ''; + + } + else + { + $rank_info['rank_special'] = 0; + } + + $s_hidden_fields .= ''; + + $rank_is_special = ( $rank_info['rank_special'] ) ? "checked=\"checked\"" : ""; + $rank_is_not_special = ( !$rank_info['rank_special'] ) ? "checked=\"checked\"" : ""; + + $template->assign_vars(array( + 'TPL_RANKS_EDIT' => true, + + "RANK" => @$rank_info['rank_title'], + "SPECIAL_RANK" => $rank_is_special, + "NOT_SPECIAL_RANK" => $rank_is_not_special, + "MINIMUM" => ( $rank_is_special ) ? "" : @$rank_info['rank_min'], + "IMAGE" => ( @$rank_info['rank_image'] ) ? $rank_info['rank_image'] : "images/ranks/rank_image.gif", + "IMAGE_DISPLAY" => ( @$rank_info['rank_image'] ) ? '' : "", + + "L_RANKS_TEXT" => $lang['RANKS_EXPLAIN'], + + "S_RANK_ACTION" => append_sid("admin_ranks.php"), + "S_HIDDEN_FIELDS" => $s_hidden_fields) + ); + + } + else if( $mode == "save" ) + { + // + // Ok, they sent us our info, let's update it. + // + + $rank_id = ( isset($_POST['id']) ) ? intval($_POST['id']) : 0; + $rank_title = ( isset($_POST['title']) ) ? trim($_POST['title']) : ""; + $special_rank = ( $_POST['special_rank'] == 1 ) ? TRUE : 0; + $min_posts = ( isset($_POST['min_posts']) ) ? intval($_POST['min_posts']) : -1; + $rank_image = ( (isset($_POST['rank_image'])) ) ? trim($_POST['rank_image']) : ""; + + if( $rank_title == "" ) + { + message_die(GENERAL_MESSAGE, $lang['MUST_SELECT_RANK']); + } + + if( $special_rank == 1 ) + { + $max_posts = -1; + $min_posts = -1; + } + + // + // The rank image has to be a jpg, gif or png + // + if($rank_image != "") + { + if ( !preg_match("/(\.gif|\.png|\.jpg)$/is", $rank_image)) + { + $rank_image = ""; + } + } + + if ($rank_id) + { + if (!$special_rank) + { + $sql = "UPDATE " . BB_USERS . " + SET user_rank = 0 + WHERE user_rank = $rank_id"; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, $lang['NO_UPDATE_RANKS'], "", __LINE__, __FILE__, $sql); + } + } + $sql = "UPDATE " . BB_RANKS . " + SET rank_title = '" . str_replace("\'", "''", $rank_title) . "', rank_special = $special_rank, rank_min = $min_posts, rank_image = '" . str_replace("\'", "''", $rank_image) . "' + WHERE rank_id = $rank_id"; + + $message = $lang['RANK_UPDATED']; + } + else + { + $sql = "INSERT INTO " . BB_RANKS . " (rank_title, rank_special, rank_min, rank_image) + VALUES ('" . str_replace("\'", "''", $rank_title) . "', $special_rank, $min_posts, '" . str_replace("\'", "''", $rank_image) . "')"; + + $message = $lang['RANK_ADDED']; + } + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't update/insert into ranks table", "", __LINE__, __FILE__, $sql); + } + + $message .= "

" . sprintf($lang['CLICK_RETURN_RANKADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + + } + else if( $mode == "delete" ) + { + // + // Ok, they want to delete their rank + // + + if( isset($_POST['id']) || isset($_GET['id']) ) + { + $rank_id = ( isset($_POST['id']) ) ? intval($_POST['id']) : intval($_GET['id']); + } + else + { + $rank_id = 0; + } + + if( $rank_id ) + { + $sql = "DELETE FROM " . BB_RANKS . " + WHERE rank_id = $rank_id"; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't delete rank data", "", __LINE__, __FILE__, $sql); + } + + $sql = "UPDATE " . BB_USERS . " + SET user_rank = 0 + WHERE user_rank = $rank_id"; + + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, $lang['NO_UPDATE_RANKS'], "", __LINE__, __FILE__, $sql); + } + + $message = $lang['RANK_REMOVED'] . "

" . sprintf($lang['CLICK_RETURN_RANKADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + + } + else + { + message_die(GENERAL_MESSAGE, $lang['MUST_SELECT_RANK']); + } + } + else + { + message_die(GENERAL_MESSAGE, 'Invalid mode'); + } +} +else +{ + // + // Show the default page + // + $sql = "SELECT * FROM " . BB_RANKS . " + ORDER BY rank_min, rank_title"; + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't obtain ranks data", "", __LINE__, __FILE__, $sql); + } + $rank_count = DB()->num_rows($result); + + $rank_rows = DB()->sql_fetchrowset($result); + + $template->assign_vars(array( + 'TPL_RANKS_LIST' => true, + + "L_RANKS_TEXT" => $lang['RANKS_EXPLAIN'], + "L_RANK" => $lang['RANK_TITLE'], + "L_ADD_RANK" => $lang['ADD_NEW_RANK'], + + "S_RANKS_ACTION" => append_sid("admin_ranks.php")) + ); + + for($i = 0; $i < $rank_count; $i++) + { + $rank = $rank_rows[$i]['rank_title']; + $special_rank = $rank_rows[$i]['rank_special']; + $rank_id = $rank_rows[$i]['rank_id']; + $rank_min = $rank_rows[$i]['rank_min']; + + if( $special_rank == 1 ) + { + $rank_min = $rank_max = "-"; + } + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $rank_is_special = ( $special_rank ) ? $lang['YES'] : $lang['NO']; + + $template->assign_block_vars("ranks", array( + "ROW_CLASS" => $row_class, + "RANK" => $rank, + "IMAGE_DISPLAY" => ( @$rank_rows[$i]['rank_image'] ) ? '' : "", + "SPECIAL_RANK" => $rank_is_special, + "RANK_MIN" => $rank_min, + + "U_RANK_EDIT" => append_sid("admin_ranks.php?mode=edit&id=$rank_id"), + "U_RANK_DELETE" => append_sid("admin_ranks.php?mode=delete&id=$rank_id")) + ); + } +} + +print_page('admin_ranks.tpl', 'admin'); diff --git a/upload/admin/admin_rebuild_search.php b/upload/admin/admin_rebuild_search.php new file mode 100644 index 000000000..98a9d0a75 --- /dev/null +++ b/upload/admin/admin_rebuild_search.php @@ -0,0 +1,635 @@ +query(" + UPDATE ". BB_SEARCH_REBUILD ." SET + rebuild_session_status = ". REBUILD_SEARCH_ABORTED ." + WHERE rebuild_session_id = $last_session_id + "); + } + + $message = sprintf($lang['REBUILD_SEARCH_ABORTED'], $last_session_data['end_post_id']) .'

'. sprintf($lang['CLICK_RETURN_REBUILD_SEARCH'], '', ''); + message_die(GENERAL_MESSAGE, $message); +} + +// from which post to start processing +$start = abs(intval(@$_REQUEST['start'])); + +// get the total number of posts in the db +$total_posts = get_total_posts(); + +// clear the search tables and clear mode (delete or truncate) +$clear_search = isset($_REQUEST['clear_search']) ? (int) $_REQUEST['clear_search'] : 0; + +// get the number of total/session posts already processed +$total_posts_processed = ( $start != 0 ) ? get_total_posts('before', $last_session_data['end_post_id']) : 0; +$session_posts_processed = ( $mode == 'refresh' ) ? get_processed_posts('session') : 0; + +// find how many posts aren't processed +$total_posts_processing = $total_posts - $total_posts_processed; + +// how many posts to process in this session +if ($session_posts_processing = @intval($_REQUEST['session_posts_processing'])) +{ + if ($mode == 'submit') + { + // check if we passed over total_posts just after submitting + if ($session_posts_processing + $total_posts_processed > $total_posts) + { + $session_posts_processing = $total_posts - $total_posts_processed; + } + } + // correct it when posts are deleted during processing + $session_posts_processing = ($session_posts_processing > $total_posts) ? $total_posts : $session_posts_processing; +} +else +{ + // if we have finished, get all the posts, else only the remaining + $session_posts_processing = (!$total_posts_processing) ? $total_posts : $total_posts_processing; +} + +// how many posts to process per cycle +$post_limit = isset($_REQUEST['post_limit']) ? (int) $_REQUEST['post_limit'] : $def_post_limit; + +// correct the post_limit when we pass over it +if ( $session_posts_processed + $post_limit > $session_posts_processing ) +{ + $post_limit = $session_posts_processing - $session_posts_processed; +} + +// how much time to wait per cycle +if (isset($_REQUEST['time_limit'])) +{ + $time_limit = (int) $_REQUEST['time_limit']; +} +else +{ + $time_limit = $def_time_limit; + $time_limit_explain = $lang['TIME_LIMIT_EXPLAIN']; + + // check for safe mode timeout + if ( ini_get('safe_mode') ) + { + // get execution time + $max_execution_time = ini_get('max_execution_time'); + $time_limit_explain .= '
' . sprintf($lang['TIME_LIMIT_EXPLAIN_SAFE'], $max_execution_time); + + if ( $time_limit > $max_execution_time ) + { + $time_limit = $max_execution_time; + } + } + + // check for webserver timeout (IE returns null) + if ( isset($_SERVER["HTTP_KEEP_ALIVE"]) ) + { + // get webserver timeout + $webserver_timeout = intval($_SERVER["HTTP_KEEP_ALIVE"]); + $time_limit_explain .= '
' . sprintf($lang['TIME_LIMIT_EXPLAIN_WEBSERVER'], $webserver_timeout); + + if ( $time_limit > $webserver_timeout ) + { + $time_limit = $webserver_timeout; + } + } +} + +// how much time to wait between page refreshes +$refresh_rate = isset($_REQUEST['refresh_rate']) ? (int) $_REQUEST['refresh_rate'] : $def_refresh_rate; + +// check if the user gave wrong input +if ($mode == 'submit') +{ + if ($session_posts_processing <= 0 || $post_limit <= 0 || $refresh_rate <= 0 || $time_limit <=0) + { + $message = $lang['WRONG_INPUT'] .'

'. sprintf($lang['CLICK_RETURN_REBUILD_SEARCH'], '', ''); + message_die(GENERAL_MESSAGE, $message); + } +} + +//--------------------------------------------------------------------- +// Main code starts from here +// + +// Increase maximum execution time in case of a lot of posts, but don't complain about it if it isn't allowed. +@set_time_limit($time_limit + 20); + +// check if we are should start processing +if ($mode == 'submit' || $mode == 'refresh') +{ + // check if we are in the beginning of processing + if ($start == 0) + { + $last_session_data = get_empty_last_session_data(); + clear_search_tables($clear_search); + } + + // get the db sizes + list($search_data_size, $search_index_size, $search_tables_size) = get_db_sizes(); + + // get the post subject/text of each post + $result = DB()->query(" + SELECT + pt.post_id, + pt.post_text, pt.bbcode_uid, + IF(p.post_id = t.topic_first_post_id, t.topic_title, '') AS post_subject + FROM + ". BB_POSTS_TEXT ." pt, + ". BB_POSTS ." p, + ". BB_TOPICS ." t + WHERE p.post_id = pt.post_id + AND t.topic_id = p.topic_id + AND p.poster_id NOT IN(". BOT_UID .") + AND pt.post_id >= $start + ORDER BY pt.post_id ASC + LIMIT $post_limit + "); + + $expire_time = $start_time + $time_limit - 5; + $start_post_id = $end_post_id = $num_rows = 0; + $timer_expired = false; + $words_sql = array(); + + while ($row = DB()->fetch_next($result) AND !$timer_expired) + { + @set_time_limit(600); + $start_post_id = ($num_rows == 0) ? $row['post_id'] : $start_post_id; + $end_post_id = $row['post_id']; + + // Get search words + $words_sql[] = array( + 'post_id' => (int) $row['post_id'], + 'search_words' => add_search_words($row['post_id'], stripslashes($row['post_text']), stripslashes($row['post_subject']), $row['bbcode_uid'], true), + ); + + $timer_expired = (time() > $expire_time); + $num_rows++; + } + + // Store search words + if ($words_sql) + { + DB()->query("REPLACE INTO ". BB_POSTS_SEARCH . DB()->build_array('MULTI_INSERT', $words_sql)); + } + + // find how much time the last cycle took + $last_cycle_time = intval(time() - $start_time); + + // check if we had any data + if ($num_rows != 0) + { + if ($mode == 'submit') + { + // insert a new session entry + $args = DB()->build_array('INSERT', array( + 'end_post_id' => (int) $end_post_id, + 'end_time' => (int) time(), + 'last_cycle_time' => (int) $last_cycle_time, + 'session_time' => (int) $last_cycle_time, + 'session_posts' => (int) $num_rows, + 'session_cycles' => (int) 1, + 'start_post_id' => (int) $start_post_id, + 'start_time' => (int) $start_time, + 'search_size' => (int) $search_tables_size, + 'rebuild_session_status' => REBUILD_SEARCH_PROCESSED, + )); + DB()->query("REPLACE INTO ". BB_SEARCH_REBUILD . $args); + } + else // refresh + { + // update the last session entry + DB()->query(" + UPDATE ". BB_SEARCH_REBUILD ." SET + end_post_id = $end_post_id, + end_time = ". time() .", + last_cycle_time = $last_cycle_time, + session_time = session_time + $last_cycle_time, + session_posts = session_posts + $num_rows, + session_cycles = session_cycles + 1, + rebuild_session_status = ". REBUILD_SEARCH_PROCESSED ." + WHERE rebuild_session_id = $last_session_id + "); + } + } + + $last_session_data = get_rebuild_session_details('last', 'all'); + $template->assign_vars(array('TPL_REBUILD_SEARCH_PROGRESS' => true)); + + $processing_messages = ''; + $processing_messages .= ($timer_expired) ? sprintf($lang['TIMER_EXPIRED'], time() - $start_time) : ''; + $processing_messages .= ($start == 0 && $clear_search) ? $lang['CLEARED_SEARCH_TABLES'] : ''; + + // check if we have reached the end of our post processing + $session_posts_processed = get_processed_posts('session'); + $total_posts_processed = get_total_posts('before', $last_session_data['end_post_id']); + $total_posts = get_total_posts(); + + if ( $session_posts_processed < $session_posts_processing && $total_posts_processed < $total_posts ) + { + $form_parameters = '&start='.($end_post_id+1); + $form_parameters .= '&session_posts_processing='.$session_posts_processing; + $form_parameters .= '&post_limit='.$post_limit; + $form_parameters .= '&time_limit='.$time_limit; + $form_parameters .= '&refresh_rate='.$refresh_rate; + + $form_action = append_sid('admin_rebuild_search.php'.'?mode=refresh'.$form_parameters); + $next_button = $lang['NEXT']; + $progress_bar_img = $images['progress_bar']; + + $processing_messages .= sprintf($lang['PROCESSING_NEXT_POSTS'], $post_limit); + + // create the meta tag for refresh + $template->assign_vars(array( + 'META' => '', + 'CANCEL_BUTTON' => true, + )); + } + else // end of processing + { + $form_action = append_sid("admin_rebuild_search.php"); + $next_button = $lang['FINISHED']; + $progress_bar_img = $images['progress_bar_full']; + + $processing_messages .= ( $session_posts_processed < $session_posts_processing ) ? sprintf($lang['DELETED_POSTS'], $session_posts_processing - $session_posts_processed) : ''; + $processing_messages .= ( $total_posts_processed == $total_posts ) ? $lang['ALL_POSTS_PROCESSED'] : $lang['ALL_SESSION_POSTS_PROCESSED']; + + // if we have processed all the db posts we need to update the rebuild_status + DB()->query("UPDATE ". BB_SEARCH_REBUILD ." SET + rebuild_session_status = ". REBUILD_SEARCH_COMPLETED ." + WHERE rebuild_session_id = $last_session_id + AND end_post_id = $max_post_id + "); + + // optimize all search tables when finished + $table_ary = array(BB_POSTS_SEARCH); + + foreach ($table_ary as $table) + { + DB()->query("ANALYZE TABLE $table"); + DB()->query("OPTIMIZE TABLE $table"); + } + + $processing_messages .= '
' . $lang['ALL_TABLES_OPTIMIZED']; + } + + // calculate the percent + $session_percent = ($session_posts_processed / $session_posts_processing) * 100; + $total_percent = ($total_posts_processed / $total_posts) * 100; + + // get the db sizes + list($search_data_size, $search_index_size, $search_tables_size) = get_db_sizes(); + + // calculate the final (estimated) values + $final_search_tables_size = ''; + + if ($search_tables_size) + { + $start_search_tables_size = $last_session_data['search_size']; + $final_search_tables_size = $start_search_tables_size + round(($search_tables_size - $start_search_tables_size) * (100 / $session_percent)); + } + + // calculate various times + $session_time = $last_session_data['session_time']; + $session_average_cycle_time = round($session_time / $last_session_data['session_cycles']); + $session_estimated_time = round($session_time * (100 / $session_percent)) - $session_time; + + // create the percent boxes + create_percent_box('session', create_percent_color($session_percent), $session_percent); + create_percent_box('total', create_percent_color($total_percent), $total_percent); + + $template->assign_vars(array( + 'L_NEXT' => $next_button, + + 'L_TIME_LAST_POSTS_ADMIN' => sprintf($lang['TIME_LAST_POSTS'], $num_rows), + 'L_TIME_BEGINNING' => $lang['TIME_FROM_THE_BEGINNING'], + + 'L_ESTIMATED_VALUES' => $lang['INFO_ESTIMATED_VALUES'], + + 'PROCESSING_POSTS' => sprintf($lang['PROCESSED_POST_IDS'], $start_post_id, $end_post_id), + 'PROCESSING_MESSAGES' => $processing_messages, + 'PROGRESS_BAR_IMG' => $progress_bar_img, + + 'SESSION_DETAILS' => sprintf($lang['PROCESS_DETAILS'], $session_posts_processed - $num_rows + 1, $session_posts_processed, $session_posts_processing), + 'SESSION_PERCENT' => sprintf($lang['PERCENT_COMPLETED'], round($session_percent, 2)), + + 'TOTAL_DETAILS' => sprintf($lang['PROCESS_DETAILS'], $total_posts_processed - $num_rows + 1, $total_posts_processed, $total_posts), + 'TOTAL_PERCENT' => sprintf($lang['PERCENT_COMPLETED'], round($total_percent, 2)), + + 'LAST_CYCLE_TIME' => delta_time(time()), + 'SESSION_TIME' => delta_time($last_session_data['start_time']), + 'SESSION_AVERAGE_CYCLE_TIME'=> delta_time($session_average_cycle_time, 0), + 'SESSION_ESTIMATED_TIME' => delta_time($session_estimated_time, 0), + + 'SEARCH_TABLES_SIZE' => humn_size($search_tables_size), + 'FINAL_SEARCH_TABLES_SIZE' => humn_size($final_search_tables_size), + 'SEARCH_DATA_SIZE' => humn_size($search_data_size), + 'SEARCH_INDEX_SIZE' => humn_size($search_index_size), + + 'START_POST' => $last_session_data['start_post_id'], + 'POST_LIMIT' => $num_rows, + 'TIME_LIMIT' => $time_limit, + 'REFRESH_RATE' => $refresh_rate, + + 'S_REBUILD_SEARCH_ACTION' => $form_action, + )); +} +else // show the input page +{ + // create the page + // used only with the select input + $post_limit_hidden = ( $def_post_limit > $total_posts ) ? $total_posts : $def_post_limit; + + $s_hidden_fields = ''; + $s_hidden_fields .= ''; + + $next_start_post_id = 0; + $last_saved_processing = ''; + $clear_search_disabled = ''; + + if ($last_session_data['rebuild_session_id']) + { + $last_saved_post_id = $last_session_data['end_post_id']; + $next_start_post_id = $last_saved_post_id + 1; + $last_saved_date = bb_date($last_session_data['end_time']); + + // check our last status + if ( $last_session_data['rebuild_session_status'] == REBUILD_SEARCH_PROCESSED ) + { + $last_saved_processing = sprintf($lang['INFO_PROCESSING_STOPPED'], $last_saved_post_id, $total_posts_processed, $last_saved_date); + $clear_search_disabled = 'disabled="disabled"'; + + $template->assign_block_vars("start_select_input", array()); + } + elseif ( $last_session_data['rebuild_session_status'] == REBUILD_SEARCH_ABORTED ) + { + $last_saved_processing = sprintf($lang['INFO_PROCESSING_ABORTED'], $last_saved_post_id, $total_posts_processed, $last_saved_date); + // check if the interrupted cycle has finished + if ( time() - $last_session_data['end_time'] < $last_session_data['last_cycle_time'] ) + { + $last_saved_processing .= '
'.$lang['INFO_PROCESSING_ABORTED_SOON']; + } + $clear_search_disabled = 'disabled="disabled"'; + + $template->assign_block_vars("start_select_input", array()); + } + else // when finished + { + if ( $last_session_data['end_post_id'] < $max_post_id ) + { + $last_saved_processing = sprintf($lang['INFO_PROCESSING_FINISHED_NEW'], $last_saved_post_id, $total_posts_processed, $last_saved_date, ($total_posts - $total_posts_processed)); + $clear_search_disabled = 'disabled="disabled"'; + + $template->assign_block_vars("start_select_input", array()); + } + else + { + $last_saved_processing = sprintf($lang['INFO_PROCESSING_FINISHED'], $total_posts, $last_saved_date); + + $template->assign_block_vars("start_text_input", array()); + } + } + + $template->assign_block_vars("last_saved_info", array()); + } + else + { + $template->assign_block_vars("start_text_input", array()); + } + + // create the output of page + $template->assign_vars(array( + 'TPL_REBUILD_SEARCH_MAIN' => true, + + 'L_TIME_LIMIT_EXPLAIN' => $time_limit_explain, + + 'NEXT_START_POST_ID' => $next_start_post_id, + 'CLEAR_SEARCH_DISABLED' => $clear_search_disabled, + 'SESSION_POSTS_PROCESSING' => $session_posts_processing, + 'POST_LIMIT' => $post_limit, + 'REFRESH_RATE' => $refresh_rate, + 'TIME_LIMIT' => $time_limit, + + 'LAST_SAVED_PROCESSING' => $last_saved_processing, + + 'SESSION_ID' => $userdata['session_id'], + + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_REBUILD_SEARCH_ACTION' => append_sid("admin_rebuild_search.php?mode=submit"), + )); +} + +print_page('admin_rebuild_search.tpl', 'admin'); + +// +// Functions +// +function get_db_sizes () +{ + $search_data_size = $search_index_size = 0; + $search_table_like = DB()->escape(BB_POSTS_SEARCH); + + $sql = "SHOW TABLE STATUS FROM `". DB()->selected_db ."` LIKE '$search_table_like'"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $search_data_size += $row['Data_length']; + $search_index_size += $row['Index_length']; + } + + return array($search_data_size, $search_index_size, $search_data_size+$search_index_size); +} + +// get the latest post_id in the forum +function get_latest_post_id () +{ + $row = DB()->fetch_row("SELECT MAX(post_id) as post_id FROM ". BB_POSTS_TEXT); + + return (int) $row['post_id']; +} + +function get_empty_last_session_data () +{ + return array( + 'rebuild_session_id' => 0, + 'start_post_id' => 0, + 'end_post_id' => 0, + 'start_time' => 0, + 'end_time' => 0, + 'last_cycle_time' => 0, + 'session_time' => 0, + 'session_posts' => 0, + 'session_cycles' => 0, + 'search_size' => 0, + 'rebuild_session_status' => REBUILD_SEARCH_COMPLETED, + ); +} + +// get some or all of the rebuild details of a specific session or of the last session +// $id is the id or the 'last' id +// $details is one of the fields or 'all' of them +function get_rebuild_session_details ($id, $details = 'all') +{ + $session_details = get_empty_last_session_data(); + + if ($id != 'last') + { + $sql = "SELECT * FROM ". BB_SEARCH_REBUILD ." WHERE rebuild_session_id = $id"; + } + else + { + $sql = "SELECT * FROM ". BB_SEARCH_REBUILD ." ORDER BY rebuild_session_id DESC LIMIT 1"; + } + + if ($row = DB()->fetch_row($sql)) + { + $session_details = ($details == 'all') ? $row : $row[$details]; + } + + return $session_details; +} + +// get the number of processed posts in the last session or in all sessions +// 'total' to get the sum of posts of all sessions +// 'session' to get the posts of the last session +function get_processed_posts ($mode = 'session') +{ + global $last_session_data; + + if ($mode == 'total') + { + $sql = "SELECT SUM(session_posts) as posts FROM ". BB_SEARCH_REBUILD; + $row = DB()->fetch_row($sql); + } + else + { + $row['posts'] = $last_session_data['session_posts']; + } + + return (int) $row['posts']; +} + +// how many posts are in the db before or after a specific post_id +// after/before require and the post_id +function get_total_posts ($mode = 'after', $post_id = 0) +{ + if ($post_id) + { + $sql = "SELECT COUNT(post_id) as total_posts FROM " . BB_POSTS_TEXT . " + WHERE post_id " . (($mode == 'after') ? '>= ' : '<= ' ) . (int) $post_id; + } + else + { + $sql = "SELECT COUNT(*) as total_posts FROM " . BB_POSTS_TEXT; + } + + $row = DB()->fetch_row($sql); + + return (int) $row['total_posts']; +} + +function clear_search_tables ($mode = '') +{ + DB()->query("DELETE FROM ". BB_SEARCH_REBUILD); + + if ($mode) + { + $table_ary = array(BB_POSTS_SEARCH); + + foreach ($table_ary as $table) + { + $sql = (($mode == 1) ? "DELETE FROM " : "TRUNCATE TABLE ") . $table; + DB()->query($sql); + } + } +} + +// Create the percent color +// We use an array with the color percent limits. +// One color stays constantly at FF when the percent is between its limits +// and we adjust the other 2 accordingly to percent, from 200 to 0. +// We limit the result to 200, in order to avoid white (255). +function create_percent_color($percent) +{ + $percent_ary = array( + 'r' => array(86, 100), + 'g' => array(0, 50), + 'b' => array(51, 85), + ); + + foreach ($percent_ary as $key => $value) + { + if ( $percent <= $value[1] ) + { + $percent_color = create_color($key, round(200-($percent-$value[0])*(200/($value[1]-$value[0])))); + break; + } + } + + return $percent_color; +} + +// create the hex representation of color +function create_color($mode, $code) +{ + return (($mode == 'r') ? 'FF': sprintf("%02X", $code)) . (($mode == 'g') ? 'FF': sprintf("%02X", $code)) . (($mode == 'b') ? 'FF': sprintf("%02X", $code)); +} + +// create the percent bar & box +function create_percent_box($box, $percent_color, $percent_width) +{ + global $template; + + if ($box == 'session') + { + $template->assign_vars(array( + 'SESSION_PERCENT_BOX' => true, + 'SESSION_PERCENT_COLOR' => $percent_color, + 'SESSION_PERCENT_WIDTH' => round($percent_width), + )); + } + else + { + $template->assign_vars(array( + 'TOTAL_PERCENT_BOX' => true, + 'TOTAL_PERCENT_COLOR' => $percent_color, + 'TOTAL_PERCENT_WIDTH' => round($percent_width), + )); + } +} \ No newline at end of file diff --git a/upload/admin/admin_reports.php b/upload/admin/admin_reports.php new file mode 100644 index 000000000..d85c10521 --- /dev/null +++ b/upload/admin/admin_reports.php @@ -0,0 +1,612 @@ + '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''), + 'config' => '

' . sprintf($lang['CLICK_RETURN_REPORT_CONFIG'], '', ''), + 'admin' => '

' . sprintf($lang['CLICK_RETURN_REPORT_ADMIN'], '', '') +); + +$redirect_url = append_sid("admin/admin_reports.php", true); + +$template->assign_var('S_REPORT_ACTION', append_sid("admin_reports.php")); + +if (isset($_POST['mode']) || isset($_GET['mode'])) +{ + $mode = (isset($_POST['mode'])) ? $_POST['mode'] : $_GET['mode']; + + // + // allow multiple modes (we need this for sub-modes, e.g. the report reasons) + // + if (is_array($mode)) + { + $modes = $mode; + $mode = $modes[0]; + } + else + { + $modes = array($mode); + } +} +else +{ + $mode = ''; + $modes = array(); +} + +// +// Configuration page +// +if ($mode == 'config') +{ + if (isset($_POST['submit'])) + { + $config_update = (isset($_POST['bb_cfg'])) ? $_POST['bb_cfg'] : array(); + + bb_update_config($config_update); + report_modules_cache_clean(); + + message_die(GENERAL_MESSAGE, $lang['REPORT_CONFIG_UPDATED'] . $return_links['config'] . $return_links['index']); + } + else + { + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => '', + + 'REPORT_SUBJECT_AUTH_ON' => ($bb_cfg['report_subject_auth']) ? ' checked="checked"' : '', + 'REPORT_SUBJECT_AUTH_OFF' => (!$bb_cfg['report_subject_auth']) ? ' checked="checked"' : '', + 'REPORT_MODULES_CACHE_ON' => ($bb_cfg['report_modules_cache']) ? ' checked="checked"' : '', + 'REPORT_MODULES_CACHE_OFF' => (!$bb_cfg['report_modules_cache']) ? ' checked="checked"' : '', + 'REPORT_NOTIFY_CHANGE' => ($bb_cfg['report_notify'] == REPORT_NOTIFY_CHANGE) ? ' checked="checked"' : '', + 'REPORT_NOTIFY_NEW' => ($bb_cfg['report_notify'] == REPORT_NOTIFY_NEW) ? ' checked="checked"' : '', + 'REPORT_NOTIFY_OFF' => (!$bb_cfg['report_notify']) ? ' checked="checked"' : '', + 'REPORT_LIST_ADMIN_ON' => ($bb_cfg['report_list_admin']) ? ' checked="checked"' : '', + 'REPORT_LIST_ADMIN_OFF' => (!$bb_cfg['report_list_admin']) ? ' checked="checked"' : '', + 'REPORT_NEW_WINDOW_ON' => ($bb_cfg['report_new_window']) ? ' checked="checked"' : '', + 'REPORT_NEW_WINDOW_OFF' => (!$bb_cfg['report_new_window']) ? ' checked="checked"' : '', + + 'L_CONFIGURATION_TITLE' => $lang['REPORTS'] . ': ' . $lang['CONFIGURATION'], + 'L_CONFIGURATION_EXPLAIN' => $lang['REPORT_CONFIG_EXPLAIN']) + ); + + print_page('report_config_body.tpl'); + } +} +else if (isset($_POST[POST_CAT_URL]) || isset($_GET[POST_CAT_URL])) +{ + $module_id = (isset($_POST[POST_CAT_URL])) ? (int) $_POST[POST_CAT_URL] : (int) $_GET[POST_CAT_URL]; + + if (!$report_module = report_modules('id', $module_id)) + { + message_die(GENERAL_MESSAGE, $lang['REPORT_MODULE_NOT_EXISTS'] . $return_links['admin'] . $return_links['index']); + } + + switch ($mode) + { + // + // Edit module + // + case 'edit': + if (isset($_POST['submit'])) + { + $module_notify = (isset($_POST['report_module_notify']) && $_POST['report_module_notify'] == 1) ? 1 : 0; + $module_prune = (isset($_POST['report_module_prune'])) ? (int) $_POST['report_module_prune'] : $report_module->data['report_module_prune']; + + $auth_write = (isset($_POST['auth_write'])) ? (int) $_POST['auth_write'] : $report_module->data['auth_write']; + $auth_view = (isset($_POST['auth_view'])) ? (int) $_POST['auth_view'] : $report_module->data['auth_view']; + $auth_notify = (isset($_POST['auth_notify'])) ? (int) $_POST['auth_notify'] : $report_module->data['auth_notify']; + $auth_delete = (isset($_POST['auth_delete'])) ? (int) $_POST['auth_delete'] : $report_module->data['auth_delete']; + + report_module_edit($module_id, $module_notify, $module_prune, $auth_write, $auth_view, $auth_notify, $auth_delete); + + message_die(GENERAL_MESSAGE, $lang['REPORT_MODULE_EDITED'] . $return_links['admin'] . $return_links['index']); + } + else if (isset($_POST['cancel'])) + { + redirect($redirect_url); + } + + $module_info = $report_module->info(); + + $hidden_fields = ''; + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'MODULE_TITLE' => $module_info['title'], + 'MODULE_EXPLAIN' => $module_info['explain'], + 'MODULE_NOTIFY_ON' => ($report_module->data['report_module_notify']) ? ' checked="checked"' : '', + 'MODULE_NOTIFY_OFF' => (!$report_module->data['report_module_notify']) ? ' checked="checked"' : '', + 'MODULE_PRUNE' => $report_module->data['report_module_prune'], + + 'L_EDIT_MODULE' => $lang['EDIT_REPORT_MODULE'], + 'L_AUTH_WRITE' => $lang['WRITE'], + 'L_AUTH_VIEW' => $lang['VIEW'], + 'L_AUTH_NOTIFY' => $lang['REPORT_NOTIFY'], + 'L_AUTH_NOTIFY_EXPLAIN' => $lang['REPORT_AUTH_NOTIFY_EXPLAIN'], + 'L_AUTH_DELETE' => $lang['DELETE'], + 'L_AUTH_DELETE_EXPLAIN' => $lang['REPORT_AUTH_DELETE_EXPLAIN']) + ); + + // + // Authorisation selects + // + report_auth_select('auth_write', $report_module->data['auth_write'], array(REPORT_AUTH_USER, REPORT_AUTH_MOD, REPORT_AUTH_ADMIN)); + report_auth_select('auth_view', $report_module->data['auth_view']); + report_auth_select('auth_notify', $report_module->data['auth_notify']); + report_auth_select('auth_delete', $report_module->data['auth_delete'], array(REPORT_AUTH_MOD, REPORT_AUTH_CONFIRM, REPORT_AUTH_ADMIN)); + + print_page('report_module_edit_body.tpl'); + break; + + // + // Report reasons + // + case 'reasons': + $reason_mode = (isset($modes[1])) ? $modes[1] : ''; + + $temp_url = append_sid("admin_reports.php?mode=reasons&" . POST_CAT_URL . "=$module_id"); + $return_links['reasons'] = '

' . sprintf($lang['CLICK_RETURN_REPORT_REASONS'], '', ''); + + $redirect_url = append_sid("admin/admin_reports.php?mode=reasons&" . POST_CAT_URL . "=$module_id", true); + + if (isset($_POST[POST_REPORT_REASON_URL]) || isset($_GET[POST_REPORT_REASON_URL])) + { + $reason_id = (isset($_POST[POST_REPORT_REASON_URL])) ? (int) $_POST[POST_REPORT_REASON_URL] : (int) $_GET[POST_REPORT_REASON_URL]; + + switch ($reason_mode) + { + // + // Edit reason + // + case 'edit': + $errors = array(); + + if (isset($_POST['submit'])) + { + $reason_desc = (isset($_POST['report_reason_desc'])) ? htmlspecialchars($_POST['report_reason_desc']) : ''; + + // + // Validate reason desc + // + if (empty($reason_desc)) + { + $errors[] = $lang['REASON_DESC_EMPTY']; + } + + if (empty($errors)) + { + $reason_desc = str_replace("\'", "'", $reason_desc); + + report_reason_edit($reason_id, $module_id, $reason_desc); + + message_die(GENERAL_MESSAGE, $lang['REPORT_REASON_EDITED'] . $return_links['reasons'] . $return_links['admin'] . $return_links['index']); + } + } + else if (isset($_POST['cancel'])) + { + redirect($redirect_url); + } + + // + // Show validation errors + // + if (!empty($errors)) + { + $template->assign_block_vars('switch_report_errors', array()); + foreach ($errors as $error) + { + $template->assign_block_vars('switch_report_errors.report_errors', array( + 'MESSAGE' => $error) + ); + } + } + + if (!$report_reason = report_reason_obtain($reason_id)) + { + message_die(GENERAL_MESSAGE, $lang['REPORT_REASON_NOT_EXISTS'] . $return_links['reasons'] . $return_links['admin'] . $return_links['index']); + } + + if (isset($reason_desc)) + { + $report_reason['report_reason_desc'] = stripslashes($reason_desc); + } + + $hidden_fields = ''; + $hidden_fields .= ''; + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'REASON_DESC' => $report_reason['report_reason_desc'], + + 'L_EDIT_REASON' => $lang['EDIT_REASON'], + 'L_REASON_DESC' => $lang['FORUM_DESC'], + 'L_REASON_DESC_EXPLAIN' => $lang['REASON_DESC_EXPLAIN'], + 'L_SUBMIT' => $lang['SUBMIT'], + 'L_CANCEL' => $lang['CANCEL']) + ); + + print_page('report_reason_edit_body.tpl'); + break; + + // + // Move reason up/down + // + case 'up': + case 'down': + report_reason_move($reason_mode, $reason_id); + + redirect($redirect_url); + break; + + // + // Delete reason + // + case 'delete': + if (isset($_POST['confirm'])) + { + report_reason_delete($reason_id); + + message_die(GENERAL_MESSAGE, $lang['REPORT_REASON_DELETED'] . $return_links['reasons'] . $return_links['admin'] . $return_links['index']); + } + else if (isset($_POST['cancel'])) + { + redirect($redirect_url); + } + + $hidden_fields = ''; + $hidden_fields .= ''; + + $template->assign_vars(array( + 'S_CONFIRM_ACTION' => append_sid("admin_reports.php"), + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'MESSAGE_TITLE' => $lang['DELETE_REASON'], + 'MESSAGE_TEXT' => $lang['DELETE_REPORT_REASON_EXPLAIN'], + + 'L_YES' => $lang['YES'], + 'L_NO' => $lang['NO']) + ); + + print_page('confirm_body.tpl'); + break; + + default: + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['reasons'] . $return_links['admin'] . $return_links['index']); + break; + } + } + else + { + switch ($reason_mode) + { + // + // Add reason + // + case 'add': + $errors = array(); + + if (isset($_POST['submit'])) + { + $reason_desc = (isset($_POST['report_reason_desc'])) ? htmlspecialchars($_POST['report_reason_desc']) : ''; + + // + // Validate reason desc + // + if (empty($reason_desc)) + { + $errors[] = $lang['REASON_DESC_EMPTY']; + } + + if (empty($errors)) + { + $reason_desc = str_replace("\'", "'", $reason_desc); + + report_reason_insert($module_id, $reason_desc); + + message_die(GENERAL_MESSAGE, $lang['REPORT_REASON_ADDED'] . $return_links['reasons'] . $return_links['admin'] . $return_links['index']); + } + } + else if (isset($_POST['cancel'])) + { + redirect($redirect_url); + } + + // + // Show validation errors + // + if (!empty($errors)) + { + $template->assign_block_vars('switch_report_errors', array()); + foreach ($errors as $error) + { + $template->assign_block_vars('switch_report_errors.report_errors', array( + 'MESSAGE' => $error) + ); + } + } + + $hidden_fields = ''; + $hidden_fields .= ''; + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'REASON_DESC' => (isset($reason_desc)) ? stripslashes($reason_desc) : '', + + 'L_EDIT_REASON' => $lang['ADD_REASON'], + 'L_REASON_DESC' => $lang['FORUM_DESC']) + ); + + print_page('report_reason_edit_body.tpl'); + break; + + case '': + + if ($report_reasons = $report_module->reasons_obtain()) + { + foreach ($report_reasons as $reason_id => $reason_desc) + { + $template->assign_block_vars('report_reasons', array( + 'DESC' => $reason_desc, + + 'U_EDIT' => append_sid("admin_reports.php?mode[]=reasons&" . POST_CAT_URL . "=$module_id&mode[]=edit&" . POST_REPORT_REASON_URL . "=$reason_id"), + 'U_MOVE_UP' => append_sid("admin_reports.php?mode[]=reasons&" . POST_CAT_URL . "=$module_id&mode[]=up&" . POST_REPORT_REASON_URL . "=$reason_id"), + 'U_MOVE_DOWN' => append_sid("admin_reports.php?mode[]=reasons&" . POST_CAT_URL . "=$module_id&mode[]=down&" . POST_REPORT_REASON_URL . "=$reason_id"), + 'U_DELETE' => append_sid("admin_reports.php?mode[]=reasons&" . POST_CAT_URL . "=$module_id&mode[]=delete&" . POST_REPORT_REASON_URL . "=$reason_id")) + ); + } + } + else + { + $template->assign_block_vars('switch_no_reasons', array()); + } + + $template->assign_vars(array( + 'U_ADD_REASON' => append_sid("admin_reports.php?mode[]=reasons&" . POST_CAT_URL . "=$module_id&mode[]=add"), + 'U_MODULES' => append_sid("admin_reports.php")) + ); + + print_page('report_module_reasons_body.tpl'); + break; + + default: + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['reasons'] . $return_links['admin'] . $return_links['index']); + break; + } + } + break; + + // + // Move module up/down + // + case 'up': + case 'down': + report_module_move($mode, $module_id); + + redirect($redirect_url); + break; + + // + // Synchronize module + // + case 'sync': + if (!method_exists($report_module, 'sync')) + { + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['admin'] . $return_links['index']); + } + + $report_module->sync(); + + message_die(GENERAL_MESSAGE, $lang['REPORT_MODULE_SYNCED'] . $return_links['admin'] . $return_links['index']); + break; + + // + // Uninstall module + // + case 'uninstall': + if (isset($_POST['confirm'])) + { + report_module_uninstall($module_id); + + message_die(GENERAL_MESSAGE, $lang['REPORT_MODULE_UNINSTALLED'] . $return_links['admin'] . $return_links['index']); + } + else if (isset($_POST['cancel'])) + { + redirect($redirect_url); + } + + $hidden_fields = ''; + + $template->assign_vars(array( + 'S_CONFIRM_ACTION' => append_sid("admin_reports.php"), + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'MESSAGE_TITLE' => $lang['UNINSTALL_REPORT_MODULE'], + 'MESSAGE_TEXT' => $lang['UNINSTALL_REPORT_MODULE_EXPLAIN']) + ); + + print_page('confirm_body.tpl'); + break; + + default: + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['admin'] . $return_links['index']); + break; + } +} +else if (isset($_POST['module']) || isset($_GET['module'])) +{ + $module_name = (isset($_POST['module'])) ? stripslashes($_POST['module']) : stripslashes($_GET['module']); + + if (!$report_module = report_modules_inactive('name', $module_name)) + { + message_die(GENERAL_MESSAGE, $lang['REPORT_MODULE_NOT_EXISTS'] . $return_links['admin'] . $return_links['index']); + } + + switch ($mode) + { + // + // Install module + // + case 'install': + if (isset($_POST['submit'])) + { + $module_notify = (isset($_POST['report_module_notify']) && $_POST['report_module_notify'] == 1) ? 1 : 0; + $module_prune = (isset($_POST['report_module_prune'])) ? (int) $_POST['report_module_prune'] : 0; + + $auth_write = (isset($_POST['auth_write'])) ? (int) $_POST['auth_write'] : REPORT_AUTH_USER; + $auth_view = (isset($_POST['auth_view'])) ? (int) $_POST['auth_view'] : REPORT_AUTH_MOD; + $auth_notify = (isset($_POST['auth_notify'])) ? (int) $_POST['auth_notify'] : REPORT_AUTH_MOD; + $auth_delete = (isset($_POST['auth_delete'])) ? (int) $_POST['auth_delete'] : REPORT_AUTH_ADMIN; + + report_module_install($module_notify, $module_prune, $module_name, $auth_write, $auth_view, $auth_notify, $auth_delete, false); + + message_die(GENERAL_MESSAGE, $lang['REPORT_MODULE_INSTALLED'] . $return_links['admin'] . $return_links['index']); + } + else if (isset($_POST['cancel'])) + { + redirect($redirect_url); + } + + $module_info = $report_module->info(); + + $hidden_fields = ''; + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'MODULE_TITLE' => $module_info['title'], + 'MODULE_EXPLAIN' => $module_info['explain'], + 'MODULE_NOTIFY_ON' => ($bb_cfg['report_notify']) ? ' checked="checked"' : '', + 'MODULE_NOTIFY_OFF' => (!$bb_cfg['report_notify']) ? ' checked="checked"' : '', + 'MODULE_PRUNE' => 0, + + 'L_EDIT_MODULE' => $lang['INSTALL_REPORT_MODULE'], + 'L_AUTH_WRITE' => $lang['WRITE'], + 'L_AUTH_VIEW' => $lang['VIEW'], + 'L_AUTH_NOTIFY' => $lang['REPORT_NOTIFY'], + 'L_AUTH_NOTIFY_EXPLAIN' => $lang['REPORT_AUTH_NOTIFY_EXPLAIN'], + 'L_AUTH_DELETE' => $lang['DELETE'], + 'L_AUTH_DELETE_EXPLAIN' => $lang['REPORT_AUTH_DELETE_EXPLAIN']) + ); + + // + // Authorisation selects + // + report_auth_select('auth_write', REPORT_AUTH_USER, array(REPORT_AUTH_USER, REPORT_AUTH_MOD, REPORT_AUTH_ADMIN)); + report_auth_select('auth_view', REPORT_AUTH_MOD); + report_auth_select('auth_notify', REPORT_AUTH_MOD); + report_auth_select('auth_delete', REPORT_AUTH_CONFIRM, array(REPORT_AUTH_MOD, REPORT_AUTH_CONFIRM, REPORT_AUTH_ADMIN)); + + print_page('report_module_edit_body.tpl'); + break; + + default: + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['admin'] . $return_links['index']); + break; + } +} +else +{ + switch ($mode) + { + case '': + $report_modules = report_modules(); + + $template->assign_vars(array( + 'L_REPORTS_TITLE' => $lang['REPORTS'] . ': ' . $lang['MODULES_REASONS'], + 'L_REPORTS_EXPLAIN' => $lang['REPORT_ADMIN_EXPLAIN'], + + 'L_REPORT_COUNT' => $lang['REPORTS'], + 'L_INSTALL' => $lang['INSTALL2']) + ); + + $report_counts = report_counts_obtain(); + $report_reason_counts = report_reason_counts_obtain(); + + // + // Display installed modules + // + $template->assign_block_vars('installed_modules', array()); + foreach (array_keys($report_modules) as $report_module_id) + { + $report_module =& $report_modules[$report_module_id]; + $module_info = $report_module->info(); + + $template->assign_block_vars('installed_modules.modules', array( + 'L_REASONS' => sprintf($lang['REASONS'], $report_reason_counts[$report_module->id]), + + 'MODULE_TITLE' => $module_info['title'], + 'MODULE_EXPLAIN' => $module_info['explain'], + 'REPORT_COUNT' => $report_counts[$report_module->id], + + 'U_EDIT' => append_sid("admin_reports.php?mode=edit&" . POST_CAT_URL . '=' . $report_module->id), + 'U_REASONS' => append_sid("admin_reports.php?mode=reasons&" . POST_CAT_URL . '=' . $report_module->id), + 'U_MOVE_UP' => append_sid("admin_reports.php?mode=up&" . POST_CAT_URL . '=' . $report_module->id), + 'U_MOVE_DOWN' => append_sid("admin_reports.php?mode=down&" . POST_CAT_URL . '=' . $report_module->id), + 'U_SYNC' => append_sid("admin_reports.php?mode=sync&" . POST_CAT_URL . '=' . $report_module->id), + 'U_UNINSTALL' => append_sid("admin_reports.php?mode=uninstall&" . POST_CAT_URL . '=' . $report_module->id)) + ); + + // + // Display sync option if available + // + if (method_exists($report_module, 'sync')) + { + $template->assign_block_vars('installed_modules.modules.switch_sync', array()); + } + } + + if (empty($report_modules)) + { + $template->assign_block_vars('installed_modules.switch_no_modules', array()); + } + + $report_modules_inactive = report_modules_inactive(); + + // + // Display inactive modules + // + $template->assign_block_vars('inactive_modules', array()); + foreach (array_keys($report_modules_inactive) as $key) + { + $report_module =& $report_modules_inactive[$key]; + $module_info = $report_module->info(); + + $template->assign_block_vars('inactive_modules.modules', array( + 'MODULE_TITLE' => $module_info['title'], + 'MODULE_EXPLAIN' => $module_info['explain'], + 'REPORT_COUNT' => '-', + + 'U_INSTALL' => append_sid("admin_reports.php?mode=install&module=" . $report_module->data['module_name'])) + ); + } + + if (empty($report_modules_inactive)) + { + $template->assign_block_vars('inactive_modules.switch_no_modules', array()); + } + + print_page('report_modules_body.tpl'); + break; + + default: + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['admin'] . $return_links['index']); + break; + } +} \ No newline at end of file diff --git a/upload/admin/admin_smilies.php b/upload/admin/admin_smilies.php new file mode 100644 index 000000000..8fe2beac3 --- /dev/null +++ b/upload/admin/admin_smilies.php @@ -0,0 +1,474 @@ +update('smile_replacements'); } +register_shutdown_function('update_smilies'); + +require('./pagestart.php'); +// ACP Header - END + +// +// Check to see what mode we should operate in. +// +if( isset($_POST['mode']) || isset($_GET['mode']) ) +{ + $mode = ( isset($_POST['mode']) ) ? $_POST['mode'] : $_GET['mode']; + $mode = htmlspecialchars($mode); +} +else +{ + $mode = ""; +} + +$delimeter = '=+:'; + +// +// Read a listing of uploaded smilies for use in the add or edit smliey code... +// +$dir = @opendir(BB_ROOT . $bb_cfg['smilies_path']); + +while($file = @readdir($dir)) +{ + if( !@is_dir(phpbb_realpath(BB_ROOT . $bb_cfg['smilies_path'] . '/' . $file)) ) + { + $img_size = @getimagesize(BB_ROOT . $bb_cfg['smilies_path'] . '/' . $file); + + if( $img_size[0] && $img_size[1] ) + { + $smiley_images[] = $file; + } + else if( preg_match('/.pak$/i', $file) ) + { + $smiley_paks[] = $file; + } + } +} + +@closedir($dir); + +// +// Select main mode +// +if( isset($_GET['import_pack']) || isset($_POST['import_pack']) ) +{ + // + // Import a list a "Smiley Pack" + // + $smile_pak = ( isset($_POST['smile_pak']) ) ? $_POST['smile_pak'] : $_GET['smile_pak']; + $clear_current = ( isset($_POST['clear_current']) ) ? $_POST['clear_current'] : $_GET['clear_current']; + $replace_existing = ( isset($_POST['replace']) ) ? $_POST['replace'] : $_GET['replace']; + + if ( !empty($smile_pak) ) + { + // + // The user has already selected a smile_pak file.. Import it. + // + if( !empty($clear_current) ) + { + $sql = "DELETE + FROM " . BB_SMILIES; + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't delete current smilies", "", __LINE__, __FILE__, $sql); + } + } + else + { + $sql = "SELECT code + FROM ". BB_SMILIES; + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't get current smilies", "", __LINE__, __FILE__, $sql); + } + + $cur_smilies = DB()->sql_fetchrowset($result); + + for( $i = 0; $i < count($cur_smilies); $i++ ) + { + $k = $cur_smilies[$i]['code']; + $smiles[$k] = 1; + } + } + + $fcontents = @file(BB_ROOT . $bb_cfg['smilies_path'] . '/'. $smile_pak); + + if( empty($fcontents) ) + { + message_die(GENERAL_ERROR, "Couldn't read smiley pak file", "", __LINE__, __FILE__, $sql); + } + + for( $i = 0; $i < count($fcontents); $i++ ) + { + $smile_data = explode($delimeter, trim(addslashes($fcontents[$i]))); + + for( $j = 2; $j < count($smile_data); $j++) + { + // + // Replace > and < with the proper html_entities for matching. + // + $smile_data[$j] = str_replace("<", "<", $smile_data[$j]); + $smile_data[$j] = str_replace(">", ">", $smile_data[$j]); + $k = $smile_data[$j]; + + if( $smiles[$k] == 1 ) + { + if( !empty($replace_existing) ) + { + $sql = "UPDATE " . BB_SMILIES . " + SET smile_url = '" . str_replace("\'", "''", $smile_data[0]) . "', emoticon = '" . str_replace("\'", "''", $smile_data[1]) . "' + WHERE code = '" . str_replace("\'", "''", $smile_data[$j]) . "'"; + } + else + { + $sql = ''; + } + } + else + { + $sql = "INSERT INTO " . BB_SMILIES . " (code, smile_url, emoticon) + VALUES('" . str_replace("\'", "''", $smile_data[$j]) . "', '" . str_replace("\'", "''", $smile_data[0]) . "', '" . str_replace("\'", "''", $smile_data[1]) . "')"; + } + + if( $sql != '' ) + { + $result = DB()->sql_query($sql); + if( !$result ) + { + message_die(GENERAL_ERROR, "Couldn't update smilies!", "", __LINE__, __FILE__, $sql); + } + } + } + } + + $message = $lang['SMILEY_IMPORT_SUCCESS'] . "

" . sprintf($lang['CLICK_RETURN_SMILEADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + + } + else + { + // + // Display the script to get the smile_pak cfg file... + // + $smile_paks_select = ""; + + $hidden_vars = ""; + + $template->assign_vars(array( + 'TPL_SMILE_IMPORT' => true, + + "L_SMILEY_EXPLAIN" => $lang['SMILEY_IMPORT_INST'], + "L_SELECT_LBL" => $lang['CHOOSE_SMILE_PAK'], + "L_CONFLICTS" => $lang['SMILE_CONFLICTS'], + "L_DEL_EXISTING" => $lang['DEL_EXISTING_SMILEYS'], + + "S_SMILEY_ACTION" => append_sid("admin_smilies.php"), + "S_SMILE_SELECT" => $smile_paks_select, + "S_HIDDEN_FIELDS" => $hidden_vars) + ); + } +} +else if( isset($_POST['export_pack']) || isset($_GET['export_pack']) ) +{ + // + // Export our smiley config as a smiley pak... + // + if ( $_GET['export_pack'] == "send" ) + { + $sql = "SELECT * + FROM " . BB_SMILIES; + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not get smiley list", "", __LINE__, __FILE__, $sql); + } + + $resultset = DB()->sql_fetchrowset($result); + + $smile_pak = ""; + for($i = 0; $i < count($resultset); $i++ ) + { + $smile_pak .= $resultset[$i]['smile_url'] . $delimeter; + $smile_pak .= $resultset[$i]['emoticon'] . $delimeter; + $smile_pak .= $resultset[$i]['code'] . "\n"; + } + + header("Content-Type: text/x-delimtext; name=\"smiles.pak\""); + header("Content-disposition: attachment; filename=smiles.pak"); + + echo $smile_pak; + + exit; + } + + $message = sprintf($lang['EXPORT_SMILES'], "", "") . "

" . sprintf($lang['CLICK_RETURN_SMILEADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + +} +else if( isset($_POST['add']) || isset($_GET['add']) ) +{ + // + // Admin has selected to add a smiley. + // + $filename_list = ""; + for( $i = 0; $i < count($smiley_images); $i++ ) + { + $filename_list .= ''; + } + + $s_hidden_fields = ''; + + $template->assign_vars(array( + 'TPL_SMILE_EDIT' => true, + + "L_SMILEY_EXPLAIN" => $lang['SMILE_DESC'], + "L_SMILEY_EMOTION" => $lang['SMILEY_EMOT'], + + "SMILEY_IMG" => BB_ROOT . $bb_cfg['smilies_path'] . '/' . $smiley_images[0], + + "S_SMILEY_ACTION" => append_sid("admin_smilies.php"), + "S_HIDDEN_FIELDS" => $s_hidden_fields, + "S_FILENAME_OPTIONS" => $filename_list, + "S_SMILEY_BASEDIR" => BB_ROOT . $bb_cfg['smilies_path']) + ); +} +else if ( $mode != "" ) +{ + switch( $mode ) + { + case 'delete': + // + // Admin has selected to delete a smiley. + // + + $smiley_id = ( !empty($_POST['id']) ) ? $_POST['id'] : $_GET['id']; + $smiley_id = intval($smiley_id); + + $sql = "DELETE FROM " . BB_SMILIES . " + WHERE smilies_id = " . $smiley_id; + $result = DB()->sql_query($sql); + if( !$result ) + { + message_die(GENERAL_ERROR, "Couldn't delete smiley", "", __LINE__, __FILE__, $sql); + } + + $message = $lang['SMILEY_DEL_SUCCESS'] . "

" . sprintf($lang['CLICK_RETURN_SMILEADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + break; + + case 'edit': + // + // Admin has selected to edit a smiley. + // + + $smiley_id = ( !empty($_POST['id']) ) ? $_POST['id'] : $_GET['id']; + $smiley_id = intval($smiley_id); + + $sql = "SELECT * + FROM " . BB_SMILIES . " + WHERE smilies_id = " . $smiley_id; + $result = DB()->sql_query($sql); + if( !$result ) + { + message_die(GENERAL_ERROR, 'Could not obtain emoticon information', "", __LINE__, __FILE__, $sql); + } + $smile_data = DB()->sql_fetchrow($result); + + $filename_list = ""; + for( $i = 0; $i < count($smiley_images); $i++ ) + { + if( $smiley_images[$i] == $smile_data['smile_url'] ) + { + $smiley_selected = "selected=\"selected\""; + $smiley_edit_img = $smiley_images[$i]; + } + else + { + $smiley_selected = ""; + } + + $filename_list .= ''; + } + + $s_hidden_fields = ''; + + $template->assign_vars(array( + 'TPL_SMILE_EDIT' => true, + + "SMILEY_CODE" => $smile_data['code'], + "SMILEY_EMOTICON" => $smile_data['emoticon'], + + "L_SMILEY_EXPLAIN" => $lang['SMILE_DESC'], + "L_SMILEY_EMOTION" => $lang['SMILEY_EMOT'], + + "SMILEY_IMG" => BB_ROOT . $bb_cfg['smilies_path'] . '/' . $smiley_edit_img, + + "S_SMILEY_ACTION" => append_sid("admin_smilies.php"), + "S_HIDDEN_FIELDS" => $s_hidden_fields, + "S_FILENAME_OPTIONS" => $filename_list, + "S_SMILEY_BASEDIR" => BB_ROOT . $bb_cfg['smilies_path']) + ); + + break; + + case "save": + // + // Admin has submitted changes while editing a smiley. + // + + // + // Get the submitted data, being careful to ensure that we only + // accept the data we are looking for. + // + $smile_code = ( isset($_POST['smile_code']) ) ? trim($_POST['smile_code']) : trim($_GET['smile_code']); + $smile_url = ( isset($_POST['smile_url']) ) ? trim($_POST['smile_url']) : trim($_GET['smile_url']); + $smile_url = phpbb_ltrim(basename($smile_url), "'"); + $smile_emotion = ( isset($_POST['smile_emotion']) ) ? trim($_POST['smile_emotion']) : trim($_GET['smile_emotion']); + $smile_id = ( isset($_POST['smile_id']) ) ? intval($_POST['smile_id']) : intval($_GET['smile_id']); + + // If no code was entered complain ... + if ($smile_code == '' || $smile_url == '') + { + message_die(GENERAL_MESSAGE, $lang['FIELDS_EMPTY']); + } + + // + // Convert < and > to proper htmlentities for parsing. + // + $smile_code = str_replace('<', '<', $smile_code); + $smile_code = str_replace('>', '>', $smile_code); + + // + // Proceed with updating the smiley table. + // + $sql = "UPDATE " . BB_SMILIES . " + SET code = '" . str_replace("\'", "''", $smile_code) . "', smile_url = '" . str_replace("\'", "''", $smile_url) . "', emoticon = '" . str_replace("\'", "''", $smile_emotion) . "' + WHERE smilies_id = $smile_id"; + if( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Couldn't update smilies info", "", __LINE__, __FILE__, $sql); + } + + $message = $lang['SMILEY_EDIT_SUCCESS'] . "

" . sprintf($lang['CLICK_RETURN_SMILEADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + break; + + case "savenew": + // + // Admin has submitted changes while adding a new smiley. + // + + // + // Get the submitted data being careful to ensure the the data + // we recieve and process is only the data we are looking for. + // + $smile_code = ( isset($_POST['smile_code']) ) ? $_POST['smile_code'] : $_GET['smile_code']; + $smile_url = ( isset($_POST['smile_url']) ) ? $_POST['smile_url'] : $_GET['smile_url']; + $smile_url = phpbb_ltrim(basename($smile_url), "'"); + $smile_emotion = ( isset($_POST['smile_emotion']) ) ? $_POST['smile_emotion'] : $_GET['smile_emotion']; + $smile_code = trim($smile_code); + $smile_url = trim($smile_url); + $smile_emotion = trim($smile_emotion); + + // If no code was entered complain ... + if ($smile_code == '' || $smile_url == '') + { + message_die(GENERAL_MESSAGE, $lang['FIELDS_EMPTY']); + } + + // + // Convert < and > to proper htmlentities for parsing. + // + $smile_code = str_replace('<', '<', $smile_code); + $smile_code = str_replace('>', '>', $smile_code); + + // + // Save the data to the smiley table. + // + $sql = "INSERT INTO " . BB_SMILIES . " (code, smile_url, emoticon) + VALUES ('" . str_replace("\'", "''", $smile_code) . "', '" . str_replace("\'", "''", $smile_url) . "', '" . str_replace("\'", "''", $smile_emotion) . "')"; + $result = DB()->sql_query($sql); + if( !$result ) + { + message_die(GENERAL_ERROR, "Couldn't insert new smiley", "", __LINE__, __FILE__, $sql); + } + + $message = $lang['SMILEY_ADD_SUCCESS'] . "

" . sprintf($lang['CLICK_RETURN_SMILEADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + break; + } +} +else +{ + + // + // This is the main display of the page before the admin has selected + // any options. + // + $sql = "SELECT * + FROM " . BB_SMILIES; + $result = DB()->sql_query($sql); + if( !$result ) + { + message_die(GENERAL_ERROR, "Couldn't obtain smileys from database", "", __LINE__, __FILE__, $sql); + } + + $smilies = DB()->sql_fetchrowset($result); + + $template->assign_vars(array( + 'TPL_SMILE_MAIN' => true, + + "L_SMILEY_TEXT" => $lang['SMILE_DESC'], + "L_SMILEY_ADD" => $lang['SMILE_ADD'], + "L_EMOT" => $lang['EMOTION'], + "L_IMPORT_PACK" => $lang['IMPORT_SMILE_PACK'], + "L_EXPORT_PACK" => $lang['EXPORT_SMILE_PACK'], + + "S_HIDDEN_FIELDS" => @$s_hidden_fields, + "S_SMILEY_ACTION" => append_sid("admin_smilies.php")) + ); + + // + // Loop throuh the rows of smilies setting block vars for the template. + // + for($i = 0; $i < count($smilies); $i++) + { + // + // Replace htmlentites for < and > with actual character. + // + $smilies[$i]['code'] = str_replace('<', '<', $smilies[$i]['code']); + $smilies[$i]['code'] = str_replace('>', '>', $smilies[$i]['code']); + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars("smiles", array( + "ROW_CLASS" => $row_class, + + "SMILEY_IMG" => BB_ROOT . $bb_cfg['smilies_path'] . '/' . $smilies[$i]['smile_url'], + "CODE" => $smilies[$i]['code'], + "EMOT" => $smilies[$i]['emoticon'], + + "U_SMILEY_EDIT" => append_sid("admin_smilies.php?mode=edit&id=" . $smilies[$i]['smilies_id']), + "U_SMILEY_DELETE" => append_sid("admin_smilies.php?mode=delete&id=" . $smilies[$i]['smilies_id'])) + ); + } +} + +print_page('admin_smilies.tpl', 'admin'); diff --git a/upload/admin/admin_topic_templates.php b/upload/admin/admin_topic_templates.php new file mode 100644 index 000000000..90c1ebf58 --- /dev/null +++ b/upload/admin/admin_topic_templates.php @@ -0,0 +1,89 @@ +fetch_rowset(" + SELECT f.forum_id, f.forum_parent, f.topic_tpl_id, f.forum_name + FROM ". BB_CATEGORIES ." c, ". BB_FORUMS ." f + WHERE f.cat_id = c.cat_id + ORDER BY c.cat_order, f.forum_order +"); + +$tpl_ary = array(); +$available_tpl_id = array(0); +$tpl_select = array($lang['TPL_NONE'] => 0); + +$sql = "SELECT * FROM ". BB_TOPIC_TPL ." ORDER BY tpl_name"; + +foreach (DB()->fetch_rowset($sql) as $row) +{ + $tpl_ary[$row['tpl_id']] = $row; + $available_tpl_id[] = $row['tpl_id']; + + $name = isset($lang[strtoupper('TPL_'. $row['tpl_name'])]) ? $lang[strtoupper('TPL_'. $row['tpl_name'])] : $row['tpl_desc']; + $tpl_select[$name] = $row['tpl_id']; +} + +if (isset($_POST['submit']) && @is_array($_POST['forum_tpl'])) +{ + $cur_val = $new_val = array(); + + foreach ($forums as $forum) + { + $cur_val["{$forum['forum_id']}"] = (int) $forum['topic_tpl_id']; + } + foreach ($_POST['forum_tpl'] as $forum_id => $tpl_id) + { + if (isset($cur_val["$forum_id"]) && in_array($tpl_id, $available_tpl_id)) + { + $new_val["$forum_id"] = (int) $tpl_id; + } + } + if ($new_settings = array_diff_assoc($new_val, $cur_val)) + { + foreach ($new_settings as $forum_id => $tpl_id) + { + DB()->query(" + UPDATE ". BB_FORUMS ." SET + topic_tpl_id = ". (int) $tpl_id ." + WHERE forum_id = ". (int) $forum_id ." + "); + } + } + + $message = $lang['CONFIG_UPD'] .'

'; + $message .= sprintf($lang['RETURN_CONFIG'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); +} + +foreach ($forums as $i => $forum) +{ + $template->assign_block_vars('forum', array( + 'ROW_CLASS' => !($i % 2) ? 'row4' : 'row5', + 'SF_PAD' => ($forum['forum_parent']) ? 'padding-left: 20px;' : '', + 'TPL_SELECT' => build_select("forum_tpl[{$forum['forum_id']}]", $tpl_select, $forum['topic_tpl_id']), + 'FORUM_CLASS' => ($forum['forum_parent']) ? 'gen' : 'gen', + 'FORUM_STYLE' => ($forum['topic_tpl_id']) ? 'font-weight: bold;' : '', + 'FORUM_ID' => $forum['forum_id'], + 'FORUM_NAME' => htmlCHR($forum['forum_name']), + )); +} + +$template->assign_vars(array( + 'L_ADMIN_TITLE' => $lang['RELEASE_TEMPLATES'], + 'L_ADMIN_TEXT' => $lang['RELEASE_EXP'], + 'S_ACTION' => append_sid("admin_topic_templates.php"), +)); + +print_page('admin_topic_templates.tpl', 'admin'); diff --git a/upload/admin/admin_ug_auth.php b/upload/admin/admin_ug_auth.php new file mode 100644 index 000000000..a5ab72903 --- /dev/null +++ b/upload/admin/admin_ug_auth.php @@ -0,0 +1,476 @@ +fetch_row($sql)) + { + $group_id = $row['group_id']; + } + else + { + $group_id = create_user_group($user_id); + } + + if (!$group_id || !$user_id || is_null($this_user_level)) + { + trigger_error('data missing', E_USER_ERROR); + } + + // Make user an admin (if already user) + if (@$_POST['userlevel'] === 'admin') + { + if ($userdata['user_id'] == $user_id || $user_id == ANONYMOUS || $user_id == BOT_UID) + { + bb_die("Couldn't update admin status"); + } + + DB()->query("UPDATE ". BB_USERS ." SET user_level = ". ADMIN ." WHERE user_id = $user_id LIMIT 1"); + + // Delete any entries in auth_access, they are not required if user is becoming an admin + delete_permissions($group_id, $user_id); + + $message = $lang['AUTH_UPDATED'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_USERAUTH'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); + } + // Make admin a user (if already admin) + else if (@$_POST['userlevel'] === 'user') + { + // ignore if you're trying to change yourself from an admin to user! + if ($userdata['user_id'] == $user_id) + { + bb_die("Couldn't update admin status

Couldn't change yourself from an admin to user"); + } + // Update users level, reset to USER + DB()->query("UPDATE ". BB_USERS ." SET user_level = ". USER ." WHERE user_id = $user_id LIMIT 1"); + + delete_permissions($group_id, $user_id); + + $message = $lang['AUTH_UPDATED'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_USERAUTH'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); + } + + // + // Submit new USER permissions + // + $auth = array(); + + if (is_array(@$_POST['auth'])) + { + array_deep($_POST['auth'], 'intval'); + + foreach ($_POST['auth'] as $f_id => $bf_ary) + { + if (array_sum($bf_ary)) + { + $auth[$f_id] = bit2dec(array_keys($bf_ary, 1)); + } + } + } + + delete_permissions($group_id, null, $cat_id); + store_permissions($group_id, $auth); + + update_user_level($user_id); + + $l_auth_return = ($mode == 'user') ? $lang['CLICK_RETURN_USERAUTH'] : $lang['CLICK_RETURN_GROUPAUTH']; + $message = $lang['AUTH_UPDATED'] .'

'; + $message .= sprintf($l_auth_return, '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); +} +// +// Submit new GROUP permissions +// +else if ($submit && $mode == 'group' && is_array(@$_POST['auth'])) +{ + if (!$group_data = get_group_data($group_id)) + { + bb_die($lang['GROUP_NOT_EXIST']); + } + + $auth = array(); + array_deep($_POST['auth'], 'intval'); + + foreach ($_POST['auth'] as $f_id => $bf_ary) + { + if (array_sum($bf_ary)) + { + $auth[$f_id] = bit2dec(array_keys($bf_ary, 1)); + } + } + + delete_permissions($group_id, null, $cat_id); + store_permissions($group_id, $auth); + + update_user_level('all'); + + $l_auth_return = $lang['CLICK_RETURN_GROUPAUTH']; + $message = $lang['AUTH_UPDATED'] .'

'; + $message .= sprintf($l_auth_return, '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + bb_die($message); +} + +// +// Front end (changing permissions) +// +if ($mode == 'user' && (!empty($_POST['username']) || $user_id)) +{ + $page_cfg['quirks_mode'] = true; + + if (!empty($_POST['username'])) + { + $this_userdata = get_userdata($_POST['username'], true); + $user_id = $this_userdata['user_id']; + } + else + { + $this_userdata = get_userdata($user_id); + } + if (!$this_userdata) + { + bb_die($lang['NO_SUCH_USER']); + } + + if (!$forums = $datastore->get('cat_forums')) + { + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); + } + $base_url = basename(__FILE__) ."?mode=user&u=$user_id"; + + $ug_data = $this_userdata; + $ug_data['session_logged_in'] = 1; + + $u_access = auth(AUTH_ALL, AUTH_LIST_ALL, $ug_data, array(), UG_PERM_USER_ONLY); + $g_access = auth(AUTH_ALL, AUTH_LIST_ALL, $ug_data, array(), UG_PERM_GROUP_ONLY); + + foreach ($forums['c'] as $c_id => $c_data) + { + $template->assign_block_vars('c', array( + 'CAT_ID' => $c_id, + 'CAT_TITLE' => $forums['cat_title_html'][$c_id], + 'CAT_HREF' => "$base_url&c=$c_id", + )); + + if (!$c =& $_REQUEST['c'] OR !in_array($c, array('all', $c_id))) + { + continue; + } + + foreach ($c_data['forums'] as $f_id) + { + $f_data = $forums['f'][$f_id]; + $auth_mod = ($u_access[$f_id]['auth_mod'] || $g_access[$f_id]['auth_mod']); + $disabled = $g_access[$f_id]['auth_mod']; + + $template->assign_block_vars('c.f', array( + 'DISABLED' => $disabled, + 'FORUM_ID' => $f_id, + 'FORUM_NAME' => str_short($forums['forum_name_html'][$f_id], $max_forum_name_length), + 'SF_SPACER' => ($f_data['forum_parent']) ? HTML_SF_SPACER : '', + 'IS_MODERATOR' => (bool) $auth_mod, + 'MOD_STATUS' => ($auth_mod) ? $lang['MODERATOR'] : $lang['NO'], + 'MOD_CLASS' => ($auth_mod) ? (($disabled) ? 'yesDisabled' : 'yesMOD') : 'noMOD', + 'AUTH_MOD_VAL' => ($auth_mod) ? 1 : 0, + )); + + foreach ($forum_auth_fields as $auth_type) + { + $bf_num = $bf['forum_perm'][$auth_type]; + $f_perm = $f_data[$auth_type]; + $auth_via_acl = ($u_access[$f_id][$auth_type] || $g_access[$f_id][$auth_type]); + + if ($f_perm == AUTH_ACL) + { + $disabled = ($auth_mod || $g_access[$f_id][$auth_type]); + $perm_sign = ($auth_via_acl || $auth_mod) ? $yes_sign : $no_sign; + $acl_class = ($auth_via_acl || $auth_mod) ? 'yes' : 'no'; + } + else + { + $disabled = true; + $perm_sign = ($auth_via_acl) ? $yes_sign : $no_sign; + $acl_class = ($auth_via_acl) ? 'yes' : 'no'; + } + + $template->assign_block_vars('c.f.acl', array( + 'DISABLED' => $disabled, + 'PERM_SIGN' => $perm_sign, + 'ACL_CLASS' => $acl_class, + 'FORUM_ID' => $f_id, + 'ACL_TYPE_BF' => $bf_num, + 'ACL_VAL' => ($auth_via_acl) ? 1 : 0, + )); + } + } + } + + $template->assign_vars(array( + 'AUTH_MOD_BF' => AUTH_MOD, + )); + + $s_column_span = 2; + + foreach ($forum_auth_fields as $auth_type) + { + $template->assign_block_vars('acltype', array( + 'ACL_TYPE_NAME' => preg_replace("#(.{5})#u", "\\1
", $lang[strtoupper($auth_type)]), + 'ACL_TYPE_BF' => $bf['forum_perm'][$auth_type], + )); + $s_column_span++; + } + + unset($forums, $u_access, $g_access); + $datastore->rm('cat_forums'); + + $s_hidden_fields = ' + + + '; + + $s_user_type = ($this_userdata['user_level'] == ADMIN) ? ' + + ' : ' + + '; + + $template->assign_block_vars('switch_user_auth', array()); + + $template->assign_vars(array( + 'TPL_AUTH_UG_MAIN' => true, + + 'USER_OR_GROUPNAME' => $this_userdata['username'], + 'USER_LEVEL' => $lang['USER_LEVEL'] .' : '. $s_user_type, + 'USER_GROUP_MEMBERSHIPS' => $lang['GROUP_MEMBERSHIPS'], + )); + + $template->assign_vars(array( + 'T_USER_OR_GROUPNAME' => $lang['USERNAME'], + 'T_AUTH_TITLE' => $lang['AUTH_CONTROL_USER'], + 'T_AUTH_EXPLAIN' => $lang['USER_AUTH_EXPLAIN'], + + 'S_COLUMN_SPAN' => $s_column_span, + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); +} +else if ($mode == 'group' && $group_id) +{ + $page_cfg['quirks_mode'] = true; + + if (!$group_data = get_group_data($group_id)) + { + bb_die($lang['GROUP_NOT_EXIST']); + } + + if (!$forums = $datastore->get('cat_forums')) + { + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); + } + $base_url = basename(__FILE__) ."?mode=group&g=$group_id"; + + $ug_data = array('group_id' => $group_id); + $u_access = auth(AUTH_ALL, AUTH_LIST_ALL, $ug_data); + + foreach ($forums['c'] as $c_id => $c_data) + { + $template->assign_block_vars('c', array( + 'CAT_ID' => $c_id, + 'CAT_TITLE' => $forums['cat_title_html'][$c_id], + 'CAT_HREF' => "$base_url&c=$c_id", + )); + + if (!$c =& $_REQUEST['c'] OR !in_array($c, array('all', $c_id)) OR empty($c_data['forums'])) + { + continue; + } + + foreach ($c_data['forums'] as $f_id) + { + $f_data = $forums['f'][$f_id]; + $auth_mod = $u_access[$f_id]['auth_mod']; + + $template->assign_block_vars('c.f', array( + 'DISABLED' => false, + 'FORUM_ID' => $f_id, + 'FORUM_NAME' => str_short($forums['forum_name_html'][$f_id], $max_forum_name_length), + 'SF_SPACER' => ($f_data['forum_parent']) ? HTML_SF_SPACER : '', + 'IS_MODERATOR' => (bool) $auth_mod, + 'MOD_STATUS' => ($auth_mod) ? $lang['MODERATOR'] : $lang['NO'], + 'MOD_CLASS' => ($auth_mod) ? 'yesMOD' : 'noMOD', + 'AUTH_MOD_VAL' => ($auth_mod) ? 1 : 0, + )); + + foreach ($forum_auth_fields as $auth_type) + { + $bf_num = $bf['forum_perm'][$auth_type]; + $f_perm = $f_data[$auth_type]; + $auth_via_acl = $u_access[$f_id][$auth_type]; + + if ($f_perm == AUTH_ACL) + { + $disabled = $auth_mod; + $perm_sign = ($auth_via_acl || $auth_mod) ? $yes_sign : $no_sign; + $acl_class = ($auth_via_acl || $auth_mod) ? 'yes' : 'no'; + } + else + { + $disabled = true; + $perm_sign = ($auth_via_acl) ? $yes_sign : $no_sign; + $acl_class = ($auth_via_acl) ? 'yes' : 'no'; + } + + $template->assign_block_vars('c.f.acl', array( + 'DISABLED' => $disabled, + 'PERM_SIGN' => $perm_sign, + 'ACL_CLASS' => $acl_class, + 'FORUM_ID' => $f_id, + 'ACL_TYPE_BF' => $bf_num, + 'ACL_VAL' => ($auth_via_acl) ? 1 : 0, + )); + } + } + } + + $template->assign_vars(array( + 'AUTH_MOD_BF' => AUTH_MOD, + )); + + $s_column_span = 2; + + foreach ($forum_auth_fields as $auth_type) + { + $template->assign_block_vars('acltype', array( + 'ACL_TYPE_NAME' => preg_replace("#(.{5})#u", "\\1
", $lang[strtoupper($auth_type)]), + 'ACL_TYPE_BF' => $bf['forum_perm'][$auth_type], + )); + $s_column_span++; + } + + unset($forums, $ug_data, $u_access); + $datastore->rm('cat_forums'); + + $s_hidden_fields = ' + + + '; + + $template->assign_vars(array( + 'TPL_AUTH_UG_MAIN' => true, + + 'T_USER_OR_GROUPNAME' => $lang['GROUP_NAME'], + 'USER_LEVEL' => false, + 'T_AUTH_TITLE' => $lang['AUTH_CONTROL_GROUP'], + 'T_AUTH_EXPLAIN' => $lang['GROUP_AUTH_EXPLAIN'], + 'USER_OR_GROUPNAME' => htmlCHR($group_data['group_name']), + 'S_COLUMN_SPAN' => $s_column_span, + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); +} +else +{ + // Select a user/group + if ($mode == 'user') + { + $template->assign_vars(array( + 'TPL_SELECT_USER' => true, + 'U_SEARCH_USER' => BB_ROOT ."search.php?mode=searchuser", + )); + } + else + { + $template->assign_vars(array( + 'TPL_SELECT_GROUP' => true, + 'S_GROUP_SELECT' => get_select('groups'), + )); + } + + $s_hidden_fields = ''; + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); +} + +$template->assign_vars(array( + 'YES_SIGN' => $yes_sign, + 'NO_SIGN' => $no_sign, + 'T_MOD_YES' => $lang['MODERATOR'], + 'T_MOD_NO' => $lang['NO'], + 'S_AUTH_ACTION' => append_sid("admin_ug_auth.php"), + 'SELECTED_CAT' => !empty($_REQUEST['c']) ? $_REQUEST['c'] : '', + 'U_ALL_FORUMS' => !empty($base_url) ? "$base_url&c=all" : '', +)); + +print_page('admin_ug_auth.tpl', 'admin'); diff --git a/upload/admin/admin_user_ban.php b/upload/admin/admin_user_ban.php new file mode 100644 index 000000000..67a42b7a2 --- /dev/null +++ b/upload/admin/admin_user_ban.php @@ -0,0 +1,403 @@ +sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Couldn't obtain banlist information", "", __LINE__, __FILE__, $sql); + } + + $current_banlist = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + $kill_session_sql = ''; + for($i = 0; $i < count($user_list); $i++) + { + $in_banlist = false; + for($j = 0; $j < count($current_banlist); $j++) + { + if ( $user_list[$i] == $current_banlist[$j]['ban_userid'] ) + { + $in_banlist = true; + } + } + + if ( !$in_banlist ) + { + $kill_session_sql .= ( ( $kill_session_sql != '' ) ? ' OR ' : '' ) . "session_user_id = " . $user_list[$i]; + + $sql = "INSERT INTO " . BB_BANLIST . " (ban_userid) + VALUES (" . $user_list[$i] . ")"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't insert ban_userid info into database", "", __LINE__, __FILE__, $sql); + } + } + } + + for($i = 0; $i < count($ip_list); $i++) + { + $in_banlist = false; + for($j = 0; $j < count($current_banlist); $j++) + { + if ( $ip_list[$i] == $current_banlist[$j]['ban_ip'] ) + { + $in_banlist = true; + } + } + + if ( !$in_banlist ) + { + if ( preg_match('/(ff\.)|(\.ff)/is', chunk_split($ip_list[$i], 2, '.')) ) + { + $kill_ip_sql = "session_ip LIKE '" . str_replace('.', '', preg_replace('/(ff\.)|(\.ff)/is', '%', chunk_split($ip_list[$i], 2, "."))) . "'"; + } + else + { + $kill_ip_sql = "session_ip = '" . $ip_list[$i] . "'"; + } + + $kill_session_sql .= ( ( $kill_session_sql != '' ) ? ' OR ' : '' ) . $kill_ip_sql; + + $sql = "INSERT INTO " . BB_BANLIST . " (ban_ip) + VALUES ('" . $ip_list[$i] . "')"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't insert ban_ip info into database", "", __LINE__, __FILE__, $sql); + } + } + } + + // + // Now we'll delete all entries from the session table with any of the banned + // user or IP info just entered into the ban table ... this will force a session + // initialisation resulting in an instant ban + // + if ( $kill_session_sql != '' ) + { + $sql = "DELETE FROM " . BB_SESSIONS . " + WHERE $kill_session_sql"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't delete banned sessions from database", "", __LINE__, __FILE__, $sql); + } + } + + for($i = 0; $i < count($email_list); $i++) + { + $in_banlist = false; + for($j = 0; $j < count($current_banlist); $j++) + { + if ( $email_list[$i] == $current_banlist[$j]['ban_email'] ) + { + $in_banlist = true; + } + } + + if ( !$in_banlist ) + { + $sql = "INSERT INTO " . BB_BANLIST . " (ban_email) + VALUES ('" . str_replace("\'", "''", $email_list[$i]) . "')"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't insert ban_email info into database", "", __LINE__, __FILE__, $sql); + } + } + } + + $where_sql = ''; + + if ( isset($_POST['unban_user']) ) + { + $user_list = $_POST['unban_user']; + + for($i = 0; $i < count($user_list); $i++) + { + if ( $user_list[$i] != -1 ) + { + $where_sql .= ( ( $where_sql != '' ) ? ', ' : '' ) . intval($user_list[$i]); + } + } + } + + if ( isset($_POST['unban_ip']) ) + { + $ip_list = $_POST['unban_ip']; + + for($i = 0; $i < count($ip_list); $i++) + { + if ( $ip_list[$i] != -1 ) + { + $where_sql .= ( ( $where_sql != '' ) ? ', ' : '' ) . str_replace("\'", "''", $ip_list[$i]); + } + } + } + + if ( isset($_POST['unban_email']) ) + { + $email_list = $_POST['unban_email']; + + for($i = 0; $i < count($email_list); $i++) + { + if ( $email_list[$i] != -1 ) + { + $where_sql .= ( ( $where_sql != '' ) ? ', ' : '' ) . str_replace("\'", "''", $email_list[$i]); + } + } + } + + if ( $where_sql != '' ) + { + $sql = "DELETE FROM " . BB_BANLIST . " + WHERE ban_id IN ($where_sql)"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Couldn't delete ban info from database", "", __LINE__, __FILE__, $sql); + } + } + + $message = $lang['BAN_UPDATE_SUCESSFUL'] . '

' . sprintf($lang['CLICK_RETURN_BANADMIN'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + +} +else +{ + $template->assign_vars(array( + 'L_BAN_TITLE' => $lang['BAN_CONTROL'], + 'L_IP_OR_HOSTNAME' => $lang['IP_HOSTNAME'], + + 'S_BANLIST_ACTION' => append_sid("admin_user_ban.php")) + ); + + $template->assign_vars(array( + 'L_BAN_USER' => $lang['BAN_USERNAME'], + 'L_BAN_USER_EXPLAIN' => $lang['BAN_USERNAME_EXPLAIN']) + ); + + $userban_count = 0; + $ipban_count = 0; + $emailban_count = 0; + + $sql = "SELECT b.ban_id, u.user_id, u.username + FROM " . BB_BANLIST . " b, " . BB_USERS . " u + WHERE u.user_id = b.ban_userid + AND b.ban_userid <> 0 + AND u.user_id <> " . ANONYMOUS . " + ORDER BY u.username ASC"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select current user_id ban list', '', __LINE__, __FILE__, $sql); + } + + $user_list = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + $select_userlist = ''; + for($i = 0; $i < count($user_list); $i++) + { + $select_userlist .= ''; + $userban_count++; + } + + if( $select_userlist == '' ) + { + $select_userlist = ''; + } + + $select_userlist = ''; + + $sql = " + SELECT ban_id, ban_ip, ban_email + FROM ". BB_BANLIST ." + ORDER BY ban_ip + "; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select current ip ban list', '', __LINE__, __FILE__, $sql); + } + + $banlist = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + $select_iplist = ''; + $select_emaillist = ''; + + for($i = 0; $i < count($banlist); $i++) + { + $ban_id = $banlist[$i]['ban_id']; + + if ( !empty($banlist[$i]['ban_ip']) ) + { + $ban_ip = str_replace('255', '*', decode_ip($banlist[$i]['ban_ip'])); + $select_iplist .= ''; + $ipban_count++; + } + else if ( !empty($banlist[$i]['ban_email']) ) + { + $ban_email = $banlist[$i]['ban_email']; + $select_emaillist .= ''; + $emailban_count++; + } + } + + if ( $select_iplist == '' ) + { + $select_iplist = ''; + } + + if ( $select_emaillist == '' ) + { + $select_emaillist = ''; + } + + $select_iplist = ''; + $select_emaillist = ''; + + $template->assign_vars(array( + 'L_UNBAN_USER' => $lang['UNBAN_USERNAME'], + 'L_UNBAN_USER_EXPLAIN' => $lang['UNBAN_USERNAME_EXPLAIN'], + + 'U_SEARCH_USER' => append_sid("./../search.php?mode=searchuser"), + 'S_UNBAN_USERLIST_SELECT' => $select_userlist, + 'S_UNBAN_IPLIST_SELECT' => $select_iplist, + 'S_UNBAN_EMAILLIST_SELECT' => $select_emaillist, + 'S_BAN_ACTION' => append_sid("admin_user_ban.php")) + ); +} + +print_page('admin_user_ban.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_user_search.php b/upload/admin/admin_user_search.php new file mode 100644 index 000000000..7cb8d908c --- /dev/null +++ b/upload/admin/admin_user_search.php @@ -0,0 +1,1344 @@ +sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not select group data', '', __LINE__, __FILE__, $sql); + } + + $group_list = ''; + + if(DB()->num_rows($result) != 0) + { + $template->assign_block_vars('groups_exist', array()); + + while($row = DB()->sql_fetchrow($result)) + { + $group_list .= ''; + } + } + + + $sql = "SELECT * FROM " . BB_RANKS . " + WHERE rank_special = 1 + ORDER BY rank_title"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain ranks data', '', __LINE__, __FILE__, $sql); + } + $rank_select_box = ''; + if(DB()->num_rows($result) != 0) + { + $template->assign_block_vars('ranks_exist', array()); + while( $row = DB()->sql_fetchrow($result) ) + { + $rank = $row['rank_title']; + $rank_id = $row['rank_id']; + $rank_select_box .= ''; + } + } + + + $language_list = language_select('', 'language_type'); + $timezone_list = tz_select('', 'timezone_type'); + + $sql = "SELECT f.forum_id, f.forum_name, f.forum_parent, c.cat_id, c.cat_title + FROM ( ". BB_FORUMS ." AS f INNER JOIN ". BB_CATEGORIES ." AS c ON c.cat_id = f.cat_id ) + ORDER BY c.cat_order, f.forum_order ASC"; + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not select forum data', '', __LINE__, __FILE__, $sql); + } + + $forums = array(); + + if(DB()->num_rows($result) != 0) + { + $template->assign_block_vars('forums_exist', array()); + + $last_cat_id = -1; + + $forums_list = ''; + + while($row = DB()->sql_fetchrow($result)) + { + if($row['cat_id'] != $last_cat_id) + { + $forums_list .= ''; + $last_cat_id = $row['cat_id']; + } + + $forums_list .= ''; + } + } + + $styles_list = $bb_cfg['tpl_name']; + + $lastvisited = array(1, 7, 14, 30, 60, 120, 365, 500, 730, 1000); + $lastvisited_list = ''; + + foreach($lastvisited as $days) + { + $lastvisited_list .= ''; + } + + $template->assign_vars(array( + 'TPL_ADMIN_USER_SEARCH_MAIN' => true, + + 'L_USER_SEARCH' => $lang['SEARCH_USERS_ADVANCED'], + 'L_SEARCH_EXPLAIN' => $lang['SEARCH_USERS_EXPLAIN'], + 'L_USERNAME_EXPLAIN' => $lang['SEARCH_USERNAME_EXPLAIN'], + 'L_EMAIL' => $lang['EMAIL_ADDRESS'], + 'L_EMAIL_EXPLAIN' => $lang['SEARCH_EMAIL_EXPLAIN'], + 'L_IP' => $lang['IP_ADDRESS'], + 'L_IP_EXPLAIN' => $lang['SEARCH_IP_EXPLAIN'], + 'L_USERS_JOINED' => $lang['SEARCH_USERS_JOINED'], + 'L_REGEX' => $lang['REGULAR_EXPRESSION'], + 'L_JOIN_DATE_EXPLAIN' => $lang['SEARCH_USERS_JOINED_EXPLAIN'], + 'L_SEARCH_USERS_GROUPS_EXPLAIN' => $lang['SEARCH_USERS_GROUPS_EXPLAIN'], + 'L_ADMINS' => $lang['ADMINISTRATORS'], + 'L_POSTCOUNT_EXPLAIN' => $lang['SEARCH_USERS_POSTCOUNT_EXPLAIN'], + 'L_GREATERTHAN' => $lang['GREATER_THAN'], + 'L_LESSERTHAN' => $lang['LESS_THAN'], + 'L_USERFIELD_EXPLAIN' => $lang['SEARCH_USERS_USERFIELD_EXPLAIN'], + 'L_LASTVISITED' => $lang['SEARCH_USERS_LASTVISITED'], + 'L_LASTVISITED_EXPLAIN' => $lang['SEARCH_USERS_LASTVISITED_EXPLAIN'], + 'L_LANGUAGE' => $lang['BOARD_LANG'], + 'L_LANGUAGE_EXPLAIN' => $lang['SEARCH_USERS_LANGUAGE_EXPLAIN'], + 'L_TIMEZONE_EXPLAIN' => $lang['SEARCH_USERS_TIMEZONE_EXPLAIN'], + 'L_STYLE' => $lang['BOARD_STYLE'], + 'L_STYLE_EXPLAIN' => $lang['SEARCH_USERS_STYLE_EXPLAIN'], + 'L_MODERATORS_OF_EXPLAIN' => $lang['SEARCH_USERS_MODERATORS_EXPLAIN'], + 'L_MISC_EXPLAIN' => $lang['SEARCH_USERS_MISC_EXPLAIN'], + + 'YEAR' => date("Y"), + 'MONTH' => date("m"), + 'DAY' => date("d"), + 'GROUP_LIST' => $group_list, + 'RANK_SELECT_BOX' => $rank_select_box, + 'LANGUAGE_LIST' => $language_list, + 'TIMEZONE_LIST' => $timezone_list, + 'FORUMS_LIST' => $forums_list, + 'STYLE_LIST' => $styles_list, + 'LASTVISITED_LIST' => $lastvisited_list, + + 'S_SEARCH_ACTION' => append_sid("admin_user_search.php") + )); +} +else +{ + $mode = ''; + + // validate mode + if(isset($_POST['search_username'])||isset($_GET['search_username'])) + { + $mode = 'search_username'; + } + else if(isset($_POST['search_email'])||isset($_GET['search_email'])) + { + $mode = 'search_email'; + } + else if(isset($_POST['search_ip'])||isset($_GET['search_ip'])) + { + $mode = 'search_ip'; + } + else if(isset($_POST['search_joindate'])||isset($_GET['search_joindate'])) + { + $mode = 'search_joindate'; + } + else if(isset($_POST['search_group'])||isset($_GET['search_group'])) + { + $mode = 'search_group'; + } + else if(isset($_POST['search_rank'])||isset($_GET['search_rank'])) + { + $mode = 'search_rank'; + } + else if(isset($_POST['search_postcount'])||isset($_GET['search_postcount'])) + { + $mode = 'search_postcount'; + } + else if(isset($_POST['search_userfield'])||isset($_GET['search_userfield'])) + { + $mode = 'search_userfield'; + } + else if(isset($_POST['search_lastvisited'])||isset($_GET['search_lastvisited'])) + { + $mode = 'search_lastvisited'; + } + else if(isset($_POST['search_language'])||isset($_GET['search_language'])) + { + $mode = 'search_language'; + } + else if(isset($_POST['search_timezone'])||isset($_GET['search_timezone'])) + { + $mode = 'search_timezone'; + } + else if(isset($_POST['search_style'])||isset($_GET['search_style'])) + { + $mode = 'search_style'; + } + else if(isset($_POST['search_moderators'])||isset($_GET['search_moderators'])) + { + $mode = 'search_moderators'; + } + else if(isset($_POST['search_misc'])||isset($_GET['search_misc'])) + { + $mode = 'search_misc'; + } + + // validate fields (that they exist) + switch($mode) + { + case 'search_username': + $username = ( isset($_GET['username']) ) ? $_GET['username'] : $_POST['username']; + $regex = ( @$_POST['search_username_regex'] ) ? true : ( @$_GET['regex'] ) ? true : false; + + if(!$username) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_USERNAME']); + } + + break; + case 'search_email': + $email = ( isset($_GET['email']) ) ? $_GET['email'] : $_POST['email']; + $regex = ( @$_POST['search_email_regex'] ) ? true : ( @$_GET['regex'] ) ? true : false; + + if(!$email) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_EMAIL']); + } + + break; + case 'search_ip': + $ip_address = ( isset($_POST['ip_address'] ) ) ? $_POST['ip_address'] : $_GET['ip_address']; + + if(!$ip_address) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_IP']); + } + break; + case 'search_joindate': + $date_type = ( isset($_POST['date_type'] ) ) ? $_POST['date_type'] : $_GET['date_type']; + $date_day = ( isset($_POST['date_day'] ) ) ? $_POST['date_day'] : $_GET['date_day']; + $date_month = ( isset($_POST['date_month'] ) ) ? $_POST['date_month'] : $_GET['date_month']; + $date_year = ( isset($_POST['date_year'] ) ) ? $_POST['date_year'] : $_GET['date_year']; + + if(!$date_type || !$date_day || !$date_month || !$date_year) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_DATE']); + } + break; + case 'search_group': + $group_id = ( isset($_POST['group_id'] ) ) ? $_POST['group_id'] : $_GET['group_id']; + if(!$group_id) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_GROUP']); + } + break; + case 'search_rank': + $rank_id = ( isset($_POST['rank_id'] ) ) ? $_POST['rank_id'] : $_GET['rank_id']; + if(!$rank_id) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_RANK']); + } + break; + case 'search_postcount': + $postcount_type = ( isset($_POST['postcount_type'] ) ) ? $_POST['postcount_type'] : $_GET['postcount_type']; + $postcount_value = ( isset($_POST['postcount_value'] ) ) ? $_POST['postcount_value'] : $_GET['postcount_value']; + + if(!$postcount_type || ( !$postcount_value && $postcount_value != 0)) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_POSTCOUNT']); + } + break; + case 'search_userfield': + $userfield_type = ( isset($_POST['userfield_type'] ) ) ? $_POST['userfield_type'] : $_GET['userfield_type']; + $userfield_value = ( isset($_POST['userfield_value'] ) ) ? $_POST['userfield_value'] : $_GET['userfield_value']; + $regex = ( @$_POST['search_userfield_regex'] ) ? true : ( @$_GET['regex'] ) ? true : false; + + if(!$userfield_type || !$userfield_value) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_USERFIELD']); + } + + break; + case 'search_lastvisited': + $lastvisited_days = ( isset($_POST['lastvisited_days'] ) ) ? $_POST['lastvisited_days'] : $_GET['lastvisited_days']; + $lastvisited_type = ( isset($_POST['lastvisited_type'] ) ) ? $_POST['lastvisited_type'] : $_GET['lastvisited_type']; + + if(!$lastvisited_days || !$lastvisited_type) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_LASTVISITED']); + } + + break; + case 'search_language': + $language_type = ( isset($_POST['language_type'] ) ) ? $_POST['language_type'] : $_GET['language_type']; + + if(!$language_type) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_LANGUAGE']); + } + + break; + case 'search_timezone': + $timezone_type = ( isset($_POST['timezone_type'] ) ) ? $_POST['timezone_type'] : $_GET['timezone_type']; + + if(!$timezone_type && $timezone_type != 0) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_TIMEZONE']); + } + + break; + case 'search_style': + $style_type = ( isset($_POST['style_type'] ) ) ? $_POST['style_type'] : $_GET['style_type']; + + if(!$style_type) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_STYLE']); + } + + break; + case 'search_moderators': + $moderators_forum = ( isset($_POST['moderators_forum'] ) ) ? $_POST['moderators_forum'] : $_GET['moderators_forum']; + + if(!$moderators_forum) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_MODERATORS']); + } + + break; + case 'search_misc': + default: + $misc = ( isset($_POST['misc'] ) ) ? $_POST['misc'] : $_GET['misc']; + if(!$misc) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID']); + } + } + + $base_url = "admin_user_search.php?dosearch=true"; + + $select_sql = "SELECT u.user_id, u.username, u.user_email, u.user_posts, u.user_regdate, u.user_level, u.user_active, u.user_lastvisit + FROM ".BB_USERS." AS u"; + + $lower_b = 'LOWER('; + $lower_e = ')'; + if(@$regex) + { + switch(SQL_LAYER) + { + case 'postgres': + $op = '~'; + break; + case 'oracle': + // Oracle uses a different syntax, we'll handle that a little later + break; + case 'mysql': + case 'mysql4': + $op = 'REGEXP'; + break; + default: + message_die(GENERAL_MESSAGE, $lang['SEARCH_NO_REGEXP']); + } + + $lower_b = ''; + $lower_e = ''; + } + + // validate data & prepare sql + switch($mode) + { + case 'search_username': + $base_url .= "&search_username=true&username=".rawurlencode(stripslashes($username)); + + $text = sprintf($lang['SEARCH_FOR_USERNAME'], strip_tags(htmlspecialchars(stripslashes($username)))); + + if(!$regex) + { + $username = preg_replace('/\*/', '%', trim(strip_tags(strtolower($username)))); + + if(strstr($username, '%')) + { + $op = 'LIKE'; + } + else + { + $op = '='; + } + } + else + { + $username = preg_replace('/\\\\\\\(? ".ANONYMOUS; + + $select_sql .= " WHERE REGEXP_LIKE(u.username, '".str_replace("\'", "''", $username)."') + AND u.user_id <> ".ANONYMOUS; + } + else + { + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE {$lower_b}username{$lower_e} $op '".str_replace("\'", "''", $username)."' + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE {$lower_b}u.username{$lower_e} $op '".str_replace("\'", "''", $username)."' + AND u.user_id <> ".ANONYMOUS; + } + break; + case 'search_email': + $base_url .= "&search_email=true&email=".rawurlencode(stripslashes($email)); + + $text = sprintf($lang['SEARCH_FOR_EMAIL'], strip_tags(htmlspecialchars(stripslashes($email)))); + + if(!$regex) + { + $email = preg_replace('/\*/', '%', trim(strip_tags(strtolower($email)))); + + if(strstr($email, '%')) + { + $op = 'LIKE'; + } + else + { + $op = '='; + } + } + else + { + $email = preg_replace('/\\\\\\\(? ".ANONYMOUS; + + $select_sql .= " WHERE REGEXP_LIKE(u.user_email, '".str_replace("\'", "''", $email)."') + AND u.user_id <> ".ANONYMOUS; + } + else + { + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE {$lower_b}user_email{$lower_e} $op '".str_replace("\'", "''", $email)."' + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE {$lower_b}u.user_email{$lower_e} $op '".str_replace("\'", "''", $email)."' + AND u.user_id <> ".ANONYMOUS; + } + break; + case 'search_ip': + $base_url .= "&search_ip=true&ip_address=".rawurlencode(stripslashes($ip_address)); + + // Remove any whitespace + $ip_address = trim($ip_address); + + $text = sprintf($lang['SEARCH_FOR_IP'], strip_tags(htmlspecialchars(stripslashes($ip_address)))); + + unset($users); + $users = array(); + + // Let's see if they entered a full valid IPv4 address + if( preg_match('/^([0-9]{1,2}|[0-2][0-9]{0,2})(\.([0-9]{1,2}|[0-2][0-9]{0,2})){3}$/', $ip_address) ) + { + // Encode the ip into hexademicals + $ip = encode_ip($ip_address); + + // Because we will be deleting based on IP's, we will store the encoded IP alone + $users[] = $ip; + } + // We will also support wildcards, is this an xxx.xxx.* address? + else if( preg_match('/^([0-9]{1,2}|[0-2][0-9]{0,2})(\.([0-9]{1,2}|[0-2][0-9]{0,2})){0,2}\.\*/', $ip_address) ) + { + // Alright, now we do the ugly part, converting them to encoded ips + // We need to deal with the three ways it can be done + // xxx.* + // xxx.xxx.* + // xxx.xxx.xxx.* + + // First we will split the IP into its quads + $ip_split = explode('.', $ip_address); + + // Now we'll work with which type of wildcard we have + switch( count($ip_split) ) + { + // xxx.xxx.xxx.* + case 4: + // We will encode the ip into hexademical quads + $users[] = encode_ip($ip_split[0].".".$ip_split[1].".".$ip_split[2].".255"); + break; + // xxx.xxx.* + case 3: + // We will encode the ip into hexademical quads again.. + $users[] = encode_ip($ip_split[0].".".$ip_split[1].".255.255"); + break; + // xxx.* + case 2: + // We will encode the ip into hexademical quads again again.... + $users[] = encode_ip($ip_split[0].".255.255.255"); + break; + } + } + // Lastly, let's see if they have a range in the last quad, like xxx.xxx.xxx.xxx - xxx.xxx.xxx.yyy + else if( preg_match('/^([0-9]{1,2}|[0-2][0-9]{0,2})(\.([0-9]{1,2}|[0-2][0-9]{0,2})){3}(\s)*-(\s)*([0-9]{1,2}|[0-2][0-9]{0,2})(\.([0-9]{1,2}|[0-2][0-9]{0,2})){3}$/', $ip_address) ) + { + // We will split the two ranges + $range = preg_split('/[-\s]+/', $ip_address); + + // This is where break the start and end ips into quads + $start_range = explode('.', $range[0]); + $end_range = explode('.', $range[1]); + + // Confirm if we are in the same subnet or the last quad in the beginning range is greater than the last in the ending range + if( ($start_range[0].$start_range[1].$start_range[2] != $end_range[0].$end_range[1].$end_range[2]) || ($start_range[3] > $end_range[3]) ) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_IP']); + } + + // Ok, we need to store each IP in the range.. + for( $i = $start_range[3]; $i <= $end_range[3]; $i++ ) + { + // let's put it in the big array.. + $users[] = encode_ip($start_range[0].".".$start_range[1 ].".".$start_range[2].".".$i); + } + } + // This is not a valid IP based on what we want.. + else + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_IP']); + } + + $ip_in_sql = ''; + $ip_like_sql = ''; + $ip_like_sql_flylast = ''; + $ip_like_sql_flyreg = ''; + + foreach($users as $address) + { + // Is this IP a range? + if( preg_match('/(ff){1,3}$/i', $address) ) + { + // num.xxx.xxx.xxx + if( preg_match('/[0-9a-f]{2}ffffff/i', $address) ) + { + $ip_start = substr($address, 0, 2); + } + // num.num.xxx.xxx + else if( preg_match('/[0-9a-f]{4}ffff/i', $address) ) + { + $ip_start = substr($address, 0, 4); + + } + // num.num.num.xxx + else if( preg_match('/[0-9a-f]{6}ff/i', $address) ) + { + $ip_start = substr($address, 0, 6); + } + + $ip_like_sql_flylast = $ip_like_sql . ( $ip_like_sql != '' ) ? " OR user_last_ip LIKE '".$ip_start."%'" : "user_last_ip LIKE '".$ip_start."%'"; + $ip_like_sql_flyreg = $ip_like_sql . ( $ip_like_sql != '' ) ? " OR user_reg_ip LIKE '".$ip_start."%'" : "user_reg_ip LIKE '".$ip_start."%'"; + $ip_like_sql .= ( $ip_like_sql != '' ) ? " OR poster_ip LIKE '".$ip_start."%'" : "poster_ip LIKE '".$ip_start."%'"; + } + else + { + $ip_in_sql .= ( $ip_in_sql == '' ) ? "'$address'" : ", '$address'"; + } + } + + $where_sql = ''; + $where_sql .= ( $ip_in_sql != '' ) ? "poster_ip IN ($ip_in_sql)": ""; + $where_sql .= ( $ip_like_sql != '' ) ? ( $where_sql != "" ) ? " OR $ip_like_sql" : "$ip_like_sql": ""; + + if (!$where_sql) bb_die('invalid request'); + + // start search + $no_result_search = false; + $ip_users_sql = ''; + $sql = "SELECT poster_id + FROM ".BB_POSTS." + WHERE poster_id <> ".ANONYMOUS." + AND ($where_sql) + GROUP BY poster_id"; + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not count users", '', __LINE__, __FILE__, $sql); + } + + if(DB()->num_rows($result)==0) + { + $no_result_search = true; + // message_die(GENERAL_MESSAGE, $lang['SEARCH_NO_RESULTS']); + } + else + { + $total_pages['total'] = DB()->num_rows($result); + + $total_sql = NULL; + + $ip_users_sql = ''; + + while($row = DB()->sql_fetchrow($result)) + { + $ip_users_sql .= ( $ip_users_sql == '' ) ? $row['poster_id'] : ', '.$row['poster_id']; + } + } + + // fly_indiz addon [START] + // user last ip + $where_sql = ''; + $where_sql .= ( $ip_in_sql != '' ) ? "user_last_ip IN ($ip_in_sql)": ""; + $where_sql .= ( $ip_like_sql_flylast != '' ) ? ( $where_sql != "" ) ? " OR $ip_like_sql_flylast" : "$ip_like_sql_flylast": ""; + $sql = "SELECT user_id + FROM ".BB_USERS." + WHERE user_id <> ".ANONYMOUS." + AND ($where_sql) + GROUP BY user_id"; + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not count users", '', __LINE__, __FILE__, $sql); + } + if(DB()->num_rows($result)!=0) + { + if ($no_result_search == true) $no_result_search = false; + $total_pages['total'] = DB()->num_rows($result); + $total_sql = NULL; + while($row = DB()->sql_fetchrow($result)) + { + $ip_users_sql .= ( $ip_users_sql == '' ) ? $row['user_id'] : ', '.$row['user_id']; + } + } + // user reg ip + $where_sql = ''; + $where_sql .= ( $ip_in_sql != '' ) ? "user_reg_ip IN ($ip_in_sql)": ""; + $where_sql .= ( $ip_like_sql_flyreg != '' ) ? ( $where_sql != "" ) ? " OR $ip_like_sql_flyreg" : "$ip_like_sql_flyreg": ""; + $sql = "SELECT user_id + FROM ".BB_USERS." + WHERE user_id <> ".ANONYMOUS." + AND ($where_sql) + GROUP BY user_id"; + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not count users", '', __LINE__, __FILE__, $sql); + } + if(DB()->num_rows($result)!=0) + { + if ($no_result_search == true) $no_result_search = false; + $total_pages['total'] = DB()->num_rows($result); + $total_sql = NULL; + while($row = DB()->sql_fetchrow($result)) + { + $ip_users_sql .= ( $ip_users_sql == '' ) ? $row['user_id'] : ', '.$row['user_id']; + } + } + if ($no_result_search == true) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_NO_RESULTS']); + } + // fly_indiz addon [END] + + $select_sql .= " WHERE u.user_id IN ($ip_users_sql)"; + + break; + case 'search_joindate': + $base_url .= "&search_joindate=true&date_type=".rawurlencode($date_type)."&date_day=".rawurlencode($date_day)."&date_month=".rawurlencode($date_month)."&date_year=".rawurlencode(stripslashes($date_year)); + + $date_type = trim(strtolower($date_type)); + + if($date_type != 'before' && $date_type != 'after') + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_DATE']); + } + + $date_day = intval($date_day); + + if( !preg_match('/^([1-9]|[0-2][0-9]|3[0-1])$/', $date_day) ) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_DAY']); + } + + $date_month = intval($date_month); + + if( !preg_match('/^(0?[1-9]|1[0-2])$/', $date_month) ) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_MONTH']); + } + + $date_year = intval($date_year); + + if( !preg_match('/^(20[0-9]{2}|19[0-9]{2})$/', $date_year) ) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_YEAR']); + } + + $text = sprintf($lang['SEARCH_FOR_DATE'], strip_tags(htmlspecialchars(stripslashes($date_type))), $date_year, $date_month, $date_day); + + $time = mktime(0,0,0,$date_month, $date_day, $date_year); + + if($date_type == 'before') + { + $arg = '<'; + } + else + { + $arg = '>'; + } + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_regdate $arg $time + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_regdate $arg $time + AND u.user_id <> ".ANONYMOUS; + + break; + case 'search_group': + $group_id = intval($group_id); + + $base_url .= "&search_group=true&group_id=".rawurlencode($group_id); + + if(!$group_id) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_GROUP']); + } + + $sql = "SELECT group_name + FROM ".BB_GROUPS." + WHERE group_id = $group_id + AND group_single_user = 0"; + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not select group data', '', __LINE__, __FILE__, $sql); + } + + if(DB()->num_rows($result)==0) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_GROUP']); + } + + $group_name = DB()->sql_fetchrow($result); + + $text = sprintf($lang['SEARCH_FOR_GROUP'], strip_tags(htmlspecialchars($group_name['group_name']))); + + $total_sql .= "SELECT COUNT(u.user_id) AS total + FROM ".BB_USERS." AS u, ".BB_USER_GROUP." AS ug + WHERE u.user_id = ug.user_id + AND ug.group_id = $group_id + AND u.user_id <> ".ANONYMOUS; + + $select_sql .= ", ".BB_USER_GROUP." AS ug + WHERE u.user_id = ug.user_id + AND ug.group_id = $group_id + AND u.user_id <> ".ANONYMOUS; + + break; + case 'search_rank': + $rank_id = intval($rank_id); + + $base_url .= "&search_rank=true&rank_id=".rawurlencode($rank_id); + + if(!$rank_id) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_RANK']); + } + + $sql = "SELECT rank_title + FROM ".BB_RANKS." + WHERE rank_id = $rank_id + AND rank_special = 1"; + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not select rank data', '', __LINE__, __FILE__, $sql); + } + + if(DB()->num_rows($result)==0) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_RANK']); + } + + $rank_title = DB()->sql_fetchrow($result); + + $text = sprintf($lang['SEARCH_FOR_RANK'], strip_tags(htmlspecialchars($rank_title['rank_title']))); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_rank = $rank_id + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_rank = $rank_id + AND u.user_id <> ".ANONYMOUS; + + break; + case 'search_postcount': + $postcount_type = trim(strtolower($postcount_type)); + $postcount_value = trim(strtolower($postcount_value)); + + $base_url .= "&search_postcount=true&postcount_type=".rawurlencode($postcount_type)."&postcount_value=".rawurlencode(stripslashes($postcount_value)); + + switch($postcount_type) + { + case 'greater': + $postcount_value = intval($postcount_value); + + $text = sprintf($lang['SEARCH_FOR_POSTCOUNT_GREATER'], $postcount_value); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_posts > $postcount_value + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_posts > $postcount_value + AND u.user_id <> ".ANONYMOUS; + break; + case 'lesser': + $postcount_value = intval($postcount_value); + + $text = sprintf($lang['SEARCH_FOR_POSTCOUNT_LESSER'], $postcount_value); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_posts < $postcount_value + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_posts < $postcount_value + AND u.user_id <> ".ANONYMOUS; + break; + case 'equals': + // looking for a - + if(strstr($postcount_value, '-')) + { + $range = preg_split('/[-\s]+/', $postcount_value); + + $range_begin = intval($range[0]); + $range_end = intval($range[1]); + + if($range_begin > $range_end) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_POSTCOUNT']); + } + + $text = sprintf($lang['SEARCH_FOR_POSTCOUNT_RANGE'], $range_begin, $range_end); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_posts >= $range_begin + AND user_posts <= $range_end + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_posts >= $range_begin + AND u.user_posts <= $range_end + AND u.user_id <> ".ANONYMOUS; + } + else + { + $postcount_value = intval($postcount_value); + + $text = sprintf($lang['SEARCH_FOR_POSTCOUNT_EQUALS'], $postcount_value); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_posts = $postcount_value + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_posts = $postcount_value + AND u.user_id <> ".ANONYMOUS; + } + break; + default: + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID']); + } + + break; + case 'search_userfield': + $base_url .= "&search_userfield=true&userfield_type=".rawurlencode($userfield_type)."&userfield_value=".rawurlencode(stripslashes($userfield_value)); + + $text = strip_tags(htmlspecialchars(stripslashes($userfield_value))); + + if(!$regex) + { + $userfield_value = preg_replace('/\*/', '%', trim(strip_tags(strtolower($userfield_value)))); + + if(strstr($userfield_value, '%')) + { + $op = 'LIKE'; + } + else + { + $op = '='; + } + } + else + { + $userfield_value = preg_replace('/\\\\\\\(? ".ANONYMOUS; + + $select_sql .= " WHERE REGEXP_LIKE(u.$field, '".str_replace("\'", "''", $userfield_value)."') + AND u.user_id <> ".ANONYMOUS; + } + else + { + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE {$lower_b}$field{$lower_e} $op '".str_replace("\'", "''", $userfield_value)."' + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE {$lower_b}u.$field{$lower_e} $op '".str_replace("\'", "''", $userfield_value)."' + AND u.user_id <> ".ANONYMOUS; + } + + break; + case 'search_lastvisited': + $lastvisited_type = trim(strtolower($lastvisited_type)); + $lastvisited_days = intval($lastvisited_days); + + $base_url .= "&search_lastvisited=true&lastvisited_type=".rawurlencode(stripslashes($lastvisited_type))."&lastvisited_days=".rawurlencode($lastvisited_days); + + $lastvisited_seconds = ( time() - ( ( ( $lastvisited_days * 24 ) * 60 ) * 60 ) ); + + switch($lastvisited_type) + { + case 'in': + $text = sprintf($lang['SEARCH_FOR_LASTVISITED_INTHELAST'], $lastvisited_days, ( ( $lastvisited_days > 1 ) ? $lang['DAYS'] : $lang['DAY'] ) ); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_lastvisit >= $lastvisited_seconds + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_lastvisit >= $lastvisited_seconds + AND u.user_id <> ".ANONYMOUS; + break; + case 'after': + $text = sprintf($lang['SEARCH_FOR_LASTVISITED_AFTERTHELAST'], $lastvisited_days, ( ( $lastvisited_days > 1 ) ? $lang['DAYS'] : $lang['DAY'] )); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_lastvisit < $lastvisited_seconds + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_lastvisit < $lastvisited_seconds + AND u.user_id <> ".ANONYMOUS; + + break; + default: + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_LASTVISITED']); + } + + break; + case 'search_language': + $base_url .= "&search_language=true&language_type=".rawurlencode(stripslashes($language_type)); + + $language_type = trim(strtolower(stripslashes($language_type))); + + if($language_type == '') + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_LANGUAGE']); + } + + $text = sprintf($lang['SEARCH_FOR_LANGUAGE'], strip_tags(htmlspecialchars($language_type))); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_lang = '".str_replace("\'", "''", $language_type)."' + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_lang = '".str_replace("\'", "''", $language_type)."' + AND u.user_id <> ".ANONYMOUS; + + break; + case 'search_timezone': + $base_url .= "&search_timezone=true&timezone_type=".rawurlencode(stripslashes($timezone_type)); + $text = sprintf($lang['SEARCH_FOR_TIMEZONE'], strip_tags(htmlspecialchars(stripslashes($timezone_type)))); + + $timezone_type = intval($timezone_type); + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_timezone = $timezone_type + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_timezone = $timezone_type + AND u.user_id <> ".ANONYMOUS; + + break; + case 'search_style': + message_die(GENERAL_MESSAGE, 'Disabled'); + break; + case 'search_moderators': + $base_url .= "&search_moderators=true&moderators_forum=".rawurlencode(stripslashes($moderators_forum)); + $moderators_forum = intval($moderators_forum); + + $sql = "SELECT forum_name + FROM ".BB_FORUMS." + WHERE forum_id = ".$moderators_forum; + + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not select forum data', '', __LINE__, __FILE__, $sql); + } + + if(DB()->num_rows($result)==0) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID_MODERATORS']); + } + + $forum_name = DB()->sql_fetchrow($result); + + $text = sprintf($lang['SEARCH_FOR_MODERATORS'], htmlCHR($forum_name['forum_name'])); + + $total_sql .= "SELECT COUNT(DISTINCT u.user_id) AS total + FROM ".BB_USERS." AS u, ".BB_GROUPS." AS g, ".BB_USER_GROUP." AS ug, ".BB_AUTH_ACCESS." AS aa + WHERE u.user_id = ug.user_id + AND ug.group_id = g.group_id + AND g.group_id = aa.group_id + AND aa.forum_id = ". $moderators_forum ." + AND aa.forum_perm & ". BF_AUTH_MOD ." + AND u.user_id <> ".ANONYMOUS; + + $select_sql .= ", ".BB_GROUPS." AS g, ".BB_USER_GROUP." AS ug, ".BB_AUTH_ACCESS." AS aa + WHERE u.user_id = ug.user_id + AND ug.group_id = g.group_id + AND g.group_id = aa.group_id + AND aa.forum_id = ". $moderators_forum ." + AND aa.forum_perm & ". BF_AUTH_MOD ." + AND u.user_id <> ".ANONYMOUS." + GROUP BY u.user_id, u.username, u.user_email, u.user_posts, u.user_regdate, u.user_level, u.user_active, u.user_lastvisit"; + break; + case 'search_misc': + default: + $misc = trim(strtolower($misc)); + + $base_url .= "&search_misc=true&misc=".rawurlencode(stripslashes($misc)); + + switch($misc) + { + case 'admins': + $text = $lang['SEARCH_FOR_ADMINS']; + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_level = ".ADMIN." + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_level = ".ADMIN." + AND u.user_id <> ".ANONYMOUS; + break; + case 'mods': + $text = $lang['SEARCH_FOR_MODS']; + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_level = ".MOD." + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_level = ".MOD." + AND u.user_id <> ".ANONYMOUS; + break; + case 'banned': + $text = $lang['SEARCH_FOR_BANNED']; + + $total_sql .= "SELECT COUNT(u.user_id) AS total + FROM ".BB_USERS." AS u, ".BB_BANLIST." AS b + WHERE u.user_id = b.ban_userid + AND u.user_id <> ".ANONYMOUS; + + $select_sql .= ", ".BB_BANLIST." AS b + WHERE u.user_id = b.ban_userid + AND u.user_id <> ".ANONYMOUS; + + break; + case 'disabled': + $text = $lang['SEARCH_FOR_DISABLED']; + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_active = 0 + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_active = 0 + AND u.user_id <> ".ANONYMOUS; + + break; + case 'disabled_pms': + $text = $lang['SEARCH_FOR_DISABLED_PMS']; + + $total_sql .= "SELECT COUNT(user_id) AS total + FROM ".BB_USERS." + WHERE user_allow_pm = 0 + AND user_id <> ".ANONYMOUS; + + $select_sql .= " WHERE u.user_allow_pm = 0 + AND u.user_id <> ".ANONYMOUS; + + break; + default: + message_die(GENERAL_MESSAGE, $lang['SEARCH_INVALID']); + } + } + + if(@$regex) + { + $base_url .= '®ex=1'; + } + + $select_sql .= " ORDER BY "; + + switch(strtolower(@$_GET['sort'])) + { + case 'regdate': + $sort = 'regdate'; + + $select_sql .= "u.user_regdate"; + break; + case 'posts': + $sort = 'posts'; + + $select_sql .= "u.user_posts"; + break; + case 'user_email': + $sort = 'user_email'; + + $select_sql .= "u.user_email"; + break; + case 'lastvisit': + $sort = 'lastvisit'; + + $select_sql .= "u.user_lastvisit"; + break; + case 'username': + default: + $sort = 'username'; + + $select_sql .= "u.username"; + } + + switch(@$_GET['order']) + { + case 'DESC': + $order = "DESC"; + $o_order = "ASC"; + break; + case 'DESC': + default: + $o_order = "DESC"; + $order = "ASC"; + } + + $select_sql .= " $order"; + + $page = ( isset($_GET['page']) ) ? intval($_GET['page']) : intval(trim(@$_POST['page'])); + + if($page < 1) + { + $page = 1; + } + + if($page == 1) + { + $offset = 0; + } + else + { + $offset = ( ($page - 1) * $bb_cfg['topics_per_page']); + } + + $limit = "LIMIT $offset, ".$bb_cfg['topics_per_page']; + + $select_sql .= " $limit"; + + if(!is_null($total_sql)) + { + if(!$result = DB()->sql_query($total_sql)) + { + message_die(GENERAL_ERROR, "Could not count users", '', __LINE__, __FILE__, $total_sql); + } + + $total_pages = DB()->sql_fetchrow($result); + + if($total_pages['total'] == 0) + { + message_die(GENERAL_MESSAGE, $lang['SEARCH_NO_RESULTS']); + } + } + $num_pages = ceil( ( $total_pages['total'] / $bb_cfg['topics_per_page'] ) ); + + $pagination = ''; + + if($page > 1) + { + $pagination .= ''.$lang['PREVIOUS'].''; + } + + if($page < $num_pages) + { + $pagination .= ( $pagination == '' ) ? ''.$lang['NEXT'].'' : ' | '.$lang['NEXT'].''; + } + + if($num_pages > 2) + { + $pagination .= '   '; + } + + $template->assign_vars(array( + 'TPL_ADMIN_USER_SEARCH_RESULTS' => true, + + 'L_USER_SEARCH' => $lang['SEARCH_USERS_ADVANCED'], + 'L_EMAIL' => $lang['EMAIL_ADDRESS'], + 'L_JOINDATE' => $lang['JOINED'], + 'L_LASTVISIT' => $lang['LAST_VISIT'], + + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], $page, $num_pages), + 'PAGINATION' => $pagination, + 'NEW_SEARCH' => sprintf($lang['SEARCH_USERS_NEW'],$text, $total_pages['total'],append_sid("admin_user_search.php")), + + 'U_USERNAME' => ( ( $sort == 'username' ) ? append_sid("$base_url&sort=$sort&order=$o_order") : append_sid("$base_url&sort=username&order=$order") ), + 'U_EMAIL' => ( ( $sort == 'user_email' ) ? append_sid("$base_url&sort=$sort&order=$o_order") : append_sid("$base_url&sort=user_email&order=$order") ), + 'U_POSTS' => ( ( $sort == 'posts' ) ? append_sid("$base_url&sort=$sort&order=$o_order") : append_sid("$base_url&sort=posts&order=$order") ), + 'U_JOINDATE' => ( ( $sort == 'regdate' ) ? append_sid("$base_url&sort=$sort&order=$o_order") : append_sid("$base_url&sort=regdate&order=$order") ), + 'U_LASTVISIT' => ( ( $sort == 'lastvisit' ) ? append_sid("$base_url&sort=$sort&order=$o_order") : append_sid("$base_url&sort=lastvisit&order=$order") ), + + 'S_POST_ACTION' => append_sid("$base_url&sort=$sort&order=$order") + )); + + if(!$result = DB()->sql_query($select_sql)) + { + message_die(GENERAL_ERROR, "Could not select user data", '', __LINE__, __FILE__, $select_sql); + } + + $rowset = DB()->sql_fetchrowset($result); + + $users_sql = ''; + + foreach($rowset as $array) + { + $users_sql .= ( $users_sql == '' ) ? $array['user_id'] : ', '.$array['user_id']; + } + + $sql = "SELECT ban_userid AS user_id + FROM ".BB_BANLIST." + WHERE ban_userid IN ($users_sql)"; + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not select banned data", '', __LINE__, __FILE__, $sql); + } + + unset($banned); + + $banned = array(); + + while($row = DB()->sql_fetchrow($result)) + { + $banned[$row['user_id']] = true; + } + + for($i = 0; $i < count($rowset); $i++) + { + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars('userrow', array( + 'ROW_CLASS' => $row_class, + 'USERNAME' => $rowset[$i]['username'], + 'EMAIL' => $rowset[$i]['user_email'], + 'JOINDATE' => bb_date($rowset[$i]['user_regdate']), + 'LASTVISIT' => bb_date($rowset[$i]['user_lastvisit']), + 'POSTS' => $rowset[$i]['user_posts'], + 'BAN' => ( ( !isset($banned[$rowset[$i]['user_id']]) ) ? $lang['NOT_BANNED'] : $lang['BANNED'] ), + 'ABLED' => ( ( $rowset[$i]['user_active'] ) ? $lang['ENABLED'] : $lang['DISABLED'] ), + + 'U_VIEWPROFILE' => append_sid("../profile.php?mode=viewprofile&".POST_USERS_URL."=".$rowset[$i]['user_id']), + 'U_VIEWPOSTS' => append_sid("../search.php?search_author=1&uid={$rowset[$i]['user_id']}"), + 'U_MANAGE' => append_sid("admin_users.php?mode=edit&".POST_USERS_URL."=".$rowset[$i]['user_id']), + 'U_PERMISSIONS' => append_sid("admin_ug_auth.php?mode=user&".POST_USERS_URL."=".$rowset[$i]['user_id']), + )); + } +} + +print_page('admin_user_search.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_users.php b/upload/admin/admin_users.php new file mode 100644 index 000000000..1f4a067eb --- /dev/null +++ b/upload/admin/admin_users.php @@ -0,0 +1,970 @@ +#'); +$html_entities_replace = array('<', '>'); + +$message = $error_msg = $username_sql = $signature_bbcode_uid = ''; +$group_moderator = $mark_list = array(); + +$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : ''; + +function return_msg_ua ($status_msg) +{ + global $lang; + + $message = $status_msg; + + $message .= '

'; + $message .= sprintf($lang['CLICK_RETURN_USERADMIN'], '', ''); + $message .= '

'; + $message .= sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + return $message; +} + +// +// Begin program +// +if ( $mode == 'edit' || $mode == 'save' && ( isset($_POST['username']) || isset($_GET[POST_USERS_URL]) || isset( $_POST[POST_USERS_URL]) ) ) +{ + attachment_quota_settings('user', @$_POST['submit'], $mode); + + // + // Ok, the profile has been modified and submitted, let's update + // + if ( ( $mode == 'save' && isset( $_POST['submit'] ) ) || isset( $_POST['avatargallery'] ) || isset( $_POST['submitavatar'] ) || isset( $_POST['cancelavatar'] ) ) + { + $user_id = (int) $_POST['id']; + + if (!$this_userdata = get_userdata($user_id)) + { + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED']); + } + + if ($userdata['user_id'] != $user_id) + { + if (!empty($_POST['deleteuser'])) + { + delete_user_sessions($user_id); + user_delete($user_id, !empty($_POST['delete_user_posts'])); + + if ($this_userdata['user_level'] == MOD) + { + $datastore->update('moderators'); + } + + message_die(GENERAL_MESSAGE, return_msg_ua($lang['USER_DELETED'])); + } + else if (!empty($_POST['delete_user_posts'])) + { + post_delete('user', $user_id); + message_die(GENERAL_MESSAGE, return_msg_ua('User posts were deleted')); + } + } + + $username = ( !empty($_POST['username']) ) ? clean_username($_POST['username']) : ''; + $email = ( !empty($_POST['email']) ) ? trim(strip_tags(htmlspecialchars( $_POST['email'] ) )) : ''; + + $password = ( !empty($_POST['password']) ) ? trim(strip_tags(htmlspecialchars( $_POST['password'] ) )) : ''; + $password_confirm = ( !empty($_POST['password_confirm']) ) ? trim(strip_tags(htmlspecialchars( $_POST['password_confirm'] ) )) : ''; + + $icq = ( !empty($_POST['icq']) ) ? trim(strip_tags( $_POST['icq'] ) ) : ''; + + $website = ( !empty($_POST['website']) ) ? trim(strip_tags( $_POST['website'] ) ) : ''; + $location = ( !empty($_POST['location']) ) ? trim(strip_tags( $_POST['location'] ) ) : ''; + $occupation = ( !empty($_POST['occupation']) ) ? trim(strip_tags( $_POST['occupation'] ) ) : ''; + $interests = ( !empty($_POST['interests']) ) ? trim(strip_tags( $_POST['interests'] ) ) : ''; + $signature = ( !empty($_POST['signature']) ) ? trim(str_replace('
', "\n", $_POST['signature'] ) ) : ''; + + validate_optional_fields($icq, $website, $location, $occupation, $interests, $signature); + + $allowviewonline = ( isset( $_POST['hideonline']) ) ? ( ( $_POST['hideonline'] ) ? 0 : TRUE ) : TRUE; + $notifyreply = ( isset( $_POST['notifyreply']) ) ? ( ( $_POST['notifyreply'] ) ? TRUE : 0 ) : 0; + $notifypm = ( isset( $_POST['notifypm']) ) ? ( ( $_POST['notifypm'] ) ? TRUE : 0 ) : TRUE; + $viewemail = (int) !empty($_POST['viewemail']); + $attachsig = (int) !empty($_POST['attachsig']); + + $user_lang = ( $_POST['language'] != $bb_cfg['board_lang'] ) ? $_POST['language'] : ''; + $user_timezone = ( isset($_POST['timezone']) ) ? str_replace(',', '.', doubleval($_POST['timezone'])) : $bb_cfg['board_timezone']; + + $user_flag = (@$_POST['user_flag'] && $_POST['user_flag'] != 'blank.gif') ? $_POST['user_flag'] : ''; + + $user_template = ( @$_POST['template'] ) ? $_POST['template'] : @$bb_cfg['board_template']; + $user_dateformat = (!empty($_POST['dateformat']) && $_POST['dateformat'] != $bb_cfg['board_dateformat']) ? $_POST['dateformat'] : ''; + + $user_avatar_local = ( isset( $_POST['avatarselect'] ) && !empty($_POST['submitavatar'] ) && $bb_cfg['allow_avatar_local'] ) ? $_POST['avatarselect'] : ( ( isset( $_POST['avatarlocal'] ) ) ? $_POST['avatarlocal'] : '' ); + $user_avatar_category = ( isset($_POST['avatarcatname']) && $bb_cfg['allow_avatar_local'] ) ? htmlspecialchars($_POST['avatarcatname']) : '' ; + + $user_avatar_remoteurl = ( !empty($_POST['avatarremoteurl']) ) ? trim( $_POST['avatarremoteurl'] ) : ''; + $user_avatar_url = ( !empty($_POST['avatarurl']) ) ? trim( $_POST['avatarurl'] ) : ''; + $user_avatar_loc = ( @$_FILES['avatar']['tmp_name'] != "none") ? $_FILES['avatar']['tmp_name'] : ''; + $user_avatar_name = ( !empty($_FILES['avatar']['name']) ) ? $_FILES['avatar']['name'] : ''; + $user_avatar_size = ( !empty($_FILES['avatar']['size']) ) ? $_FILES['avatar']['size'] : 0; + $user_avatar_filetype = ( !empty($_FILES['avatar']['type']) ) ? $_FILES['avatar']['type'] : ''; + + $user_avatar = ( empty($user_avatar_loc) ) ? $this_userdata['user_avatar'] : ''; + $user_avatar_type = ( empty($user_avatar_loc) ) ? $this_userdata['user_avatar_type'] : ''; + + $user_status = ( !empty($_POST['user_status']) ) ? intval( $_POST['user_status'] ) : 0; + $user_allowpm = ( !empty($_POST['user_allowpm']) ) ? intval( $_POST['user_allowpm'] ) : 0; + $user_rank = ( !empty($_POST['user_rank']) ) ? intval( $_POST['user_rank'] ) : 0; + $user_allowavatar = ( !empty($_POST['user_allowavatar']) ) ? intval( $_POST['user_allowavatar'] ) : 0; + + if( isset( $_POST['avatargallery'] ) || isset( $_POST['submitavatar'] ) || isset( $_POST['cancelavatar'] ) ) + { + $username = stripslashes($username); + $email = stripslashes($email); + $password = ''; + $password_confirm = ''; + + $icq = stripslashes($icq); + + $website = htmlspecialchars(stripslashes($website)); + $location = htmlspecialchars(stripslashes($location)); + $occupation = htmlspecialchars(stripslashes($occupation)); + $interests = htmlspecialchars(stripslashes($interests)); + $signature = htmlspecialchars(stripslashes($signature)); + + $user_lang = stripslashes($user_lang); + $user_dateformat = htmlspecialchars(stripslashes($user_dateformat)); + + if ( !isset($_POST['cancelavatar'])) + { + $user_avatar = $user_avatar_category . '/' . $user_avatar_local; + $user_avatar_type = USER_AVATAR_GALLERY; + } + } + } + + if( isset( $_POST['submit'] ) ) + { + include(INC_DIR . 'ucp/usercp_avatar.php'); + + $error = FALSE; + + if (stripslashes($username) != $this_userdata['username']) + { + unset($rename_user); + + if ( stripslashes(strtolower($username)) != strtolower($this_userdata['username']) ) + { + $result = validate_username($username); + if ( $result['error'] ) + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $result['error_msg']; + } + else if ( strtolower(str_replace("\\'", "''", $username)) == strtolower($userdata['username']) ) + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $lang['USERNAME_TAKEN']; + } + } + + if (!$error) + { + $username_sql = "username = '" . str_replace("\\'", "''", $username) . "', "; + $rename_user = $username; // Used for renaming usergroup + } + } + + $passwd_sql = ''; + if( !empty($password) && !empty($password_confirm) ) + { + // + // Awww, the user wants to change their password, isn't that cute.. + // + if($password != $password_confirm) + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $lang['PASSWORD_MISMATCH']; + } + else + { + $password = md5($password); + $passwd_sql = "user_password = '$password', "; + } + } + else if( $password && !$password_confirm ) + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $lang['PASSWORD_MISMATCH']; + } + else if( !$password && $password_confirm ) + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $lang['PASSWORD_MISMATCH']; + } + + if ($signature != '') + { + $sig_length_check = preg_replace('/(\[.*?)(=.*?)\]/is', '\\1]', stripslashes($signature)); + $signature_bbcode_uid = ($bb_cfg['allow_bbcode']) ? make_bbcode_uid() : ''; + $signature = prepare_message($signature, $bb_cfg['allow_bbcode'], $bb_cfg['allow_smilies'], $signature_bbcode_uid); + + if ( strlen($sig_length_check) > $bb_cfg['max_sig_chars'] ) + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $lang['SIGNATURE_TOO_LONG']; + } + } + + // + // Avatar stuff + // + $avatar_sql = ""; + if( isset($_POST['avatardel']) ) + { + if( $this_userdata['user_avatar_type'] == USER_AVATAR_UPLOAD && $this_userdata['user_avatar'] != "" ) + { + if( @file_exists(@phpbb_realpath('./../' . $bb_cfg['avatar_path'] . "/" . $this_userdata['user_avatar'])) ) + { + @unlink('./../' . $bb_cfg['avatar_path'] . "/" . $this_userdata['user_avatar']); + } + } + $avatar_sql = ", user_avatar = '', user_avatar_type = " . USER_AVATAR_NONE; + } + else if( ( $user_avatar_loc != "" || !empty($user_avatar_url) ) && !$error ) + { + // + // Only allow one type of upload, either a + // filename or a URL + // + if( !empty($user_avatar_loc) && !empty($user_avatar_url) ) + { + $error = TRUE; + if( isset($error_msg) ) + { + $error_msg .= "
"; + } + $error_msg .= $lang['ONLY_ONE_AVATAR']; + } + + if( $user_avatar_loc != "" ) + { + if( file_exists(@phpbb_realpath($user_avatar_loc)) && preg_match("/\.(gif|jpg|png)$/", $user_avatar_name) ) + { + if( $user_avatar_size <= $bb_cfg['avatar_filesize'] && $user_avatar_size > 0) + { + $error_type = false; + + // + // Opera appends the image name after the type, not big, not clever! + // + preg_match("'image\/[x\-]*([a-z]+)'", $user_avatar_filetype, $user_avatar_filetype); + $user_avatar_filetype = $user_avatar_filetype[1]; + + switch( $user_avatar_filetype ) + { + case "jpeg": + case "pjpeg": + case "jpg": + $imgtype = '.jpg'; + break; + case "gif": + $imgtype = '.gif'; + break; + case "png": + $imgtype = '.png'; + break; + default: + $error = true; + $error_msg = (!empty($error_msg)) ? $error_msg . "
" . $lang['AVATAR_FILETYPE'] : $lang['AVATAR_FILETYPE']; + break; + } + + if( !$error ) + { + list($width, $height) = @getimagesize($user_avatar_loc); + + if( $width <= $bb_cfg['avatar_max_width'] && $height <= $bb_cfg['avatar_max_height'] ) + { + $user_id = $this_userdata['user_id']; + + $avatar_filename = $user_id . $imgtype; + + if( $this_userdata['user_avatar_type'] == USER_AVATAR_UPLOAD && $this_userdata['user_avatar'] != "" ) + { + if( @file_exists(@phpbb_realpath("./../" . $bb_cfg['avatar_path'] . "/" . $this_userdata['user_avatar'])) ) + { + @unlink("./../" . $bb_cfg['avatar_path'] . "/". $this_userdata['user_avatar']); + } + } + @copy($user_avatar_loc, "./../" . $bb_cfg['avatar_path'] . "/$avatar_filename"); + + $avatar_sql = ", user_avatar = '$avatar_filename', user_avatar_type = " . USER_AVATAR_UPLOAD; + } + else + { + $l_avatar_size = sprintf($lang['AVATAR_IMAGESIZE'], $bb_cfg['avatar_max_width'], $bb_cfg['avatar_max_height']); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $l_avatar_size : $l_avatar_size; + } + } + } + else + { + $l_avatar_size = sprintf($lang['AVATAR_FILESIZE'], round($bb_cfg['avatar_filesize'] / 1024)); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $l_avatar_size : $l_avatar_size; + } + } + else + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $lang['AVATAR_FILETYPE'] : $lang['AVATAR_FILETYPE']; + } + } + else if( !empty($user_avatar_url) ) + { + // + // First check what port we should connect + // to, look for a :[xxxx]/ or, if that doesn't + // exist assume port 80 (http) + // + preg_match("/^(http:\/\/)?([\w\-\.]+)\:?([0-9]*)\/(.*)$/", $user_avatar_url, $url_ary); + + if( !empty($url_ary[4]) ) + { + $port = (!empty($url_ary[3])) ? $url_ary[3] : 80; + + $fsock = @fsockopen($url_ary[2], $port, $errno, $errstr); + if( $fsock ) + { + $base_get = "/" . $url_ary[4]; + + // + // Uses HTTP 1.1, could use HTTP 1.0 ... + // + @fputs($fsock, "GET $base_get HTTP/1.1\r\n"); + @fputs($fsock, "HOST: " . $url_ary[2] . "\r\n"); + @fputs($fsock, "Connection: close\r\n\r\n"); + + $avatar_data = ''; + while( !@feof($fsock) ) + { + $avatar_data .= @fread($fsock, $bb_cfg['avatar_filesize']); + } + @fclose($fsock); + + if( preg_match("/Content-Length\: ([0-9]+)[^\/ ][\s]+/i", $avatar_data, $file_data1) && preg_match("/Content-Type\: image\/[x\-]*([a-z]+)[\s]+/i", $avatar_data, $file_data2) ) + { + $file_size = $file_data1[1]; + $file_type = $file_data2[1]; + + switch( $file_type ) + { + case "jpeg": + case "pjpeg": + case "jpg": + $imgtype = '.jpg'; + break; + case "gif": + $imgtype = '.gif'; + break; + case "png": + $imgtype = '.png'; + break; + default: + $error = true; + $error_msg = (!empty($error_msg)) ? $error_msg . "
" . $lang['AVATAR_FILETYPE'] : $lang['AVATAR_FILETYPE']; + break; + } + + if( !$error && $file_size > 0 && $file_size < $bb_cfg['avatar_filesize'] ) + { + $avatar_data = substr($avatar_data, strlen($avatar_data) - $file_size, $file_size); + + $tmp_filename = tempnam ("/tmp", $this_userdata['user_id'] . "-"); + $fptr = @fopen($tmp_filename, "wb"); + $bytes_written = @fwrite($fptr, $avatar_data, $file_size); + @fclose($fptr); + + if( $bytes_written == $file_size ) + { + list($width, $height) = @getimagesize($tmp_filename); + + if( $width <= $bb_cfg['avatar_max_width'] && $height <= $bb_cfg['avatar_max_height'] ) + { + $user_id = $this_userdata['user_id']; + + $avatar_filename = $user_id . $imgtype; + + if( $this_userdata['user_avatar_type'] == USER_AVATAR_UPLOAD && $this_userdata['user_avatar'] != "") + { + if( file_exists(@phpbb_realpath("./../" . $bb_cfg['avatar_path'] . "/" . $this_userdata['user_avatar'])) ) + { + @unlink("./../" . $bb_cfg['avatar_path'] . "/" . $this_userdata['user_avatar']); + } + } + @copy($tmp_filename, "./../" . $bb_cfg['avatar_path'] . "/$avatar_filename"); + @unlink($tmp_filename); + + $avatar_sql = ", user_avatar = '$avatar_filename', user_avatar_type = " . USER_AVATAR_UPLOAD; + } + else + { + $l_avatar_size = sprintf($lang['AVATAR_IMAGESIZE'], $bb_cfg['avatar_max_width'], $bb_cfg['avatar_max_height']); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $l_avatar_size : $l_avatar_size; + } + } + else + { + // + // Error writing file + // + @unlink($tmp_filename); + message_die(GENERAL_ERROR, "Could not write avatar file to local storage. Please contact the board administrator with this message", "", __LINE__, __FILE__); + } + } + } + else + { + // + // No data + // + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $lang['FILE_NO_DATA'] : $lang['FILE_NO_DATA']; + } + } + else + { + // + // No connection + // + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $lang['NO_CONNECTION_URL'] : $lang['NO_CONNECTION_URL']; + } + } + else + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $lang['INCOMPLETE_URL'] : $lang['INCOMPLETE_URL']; + } + } + else if( !empty($user_avatar_name) ) + { + $l_avatar_size = sprintf($lang['AVATAR_FILESIZE'], round($bb_cfg['avatar_filesize'] / 1024)); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $l_avatar_size : $l_avatar_size; + } + } + else if( $user_avatar_remoteurl != "" && $avatar_sql == "" && !$error ) + { + if( !preg_match("#^http:\/\/#i", $user_avatar_remoteurl) ) + { + $user_avatar_remoteurl = "http://" . $user_avatar_remoteurl; + } + + if( preg_match("#^(http:\/\/[a-z0-9\-]+?\.([a-z0-9\-]+\.)*[a-z]+\/.*?\.(gif|jpg|png)$)#is", $user_avatar_remoteurl) ) + { + $avatar_sql = ", user_avatar = '" . str_replace("\'", "''", $user_avatar_remoteurl) . "', user_avatar_type = " . USER_AVATAR_REMOTE; + } + else + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . "
" . $lang['WRONG_REMOTE_AVATAR_FORMAT'] : $lang['WRONG_REMOTE_AVATAR_FORMAT']; + } + } + else if( $user_avatar_local != "" && $avatar_sql == "" && !$error ) + { + $avatar_sql = ", user_avatar = '" . str_replace("\'", "''", phpbb_ltrim(basename($user_avatar_category), "'") . '/' . phpbb_ltrim(basename($user_avatar_local), "'")) . "', user_avatar_type = " . USER_AVATAR_GALLERY; + } + + // + // Update entry in DB + // + if( !$error ) + { + $update_user_opt = array( + 'viewemail', + 'attachsig', + ); + $user_opt = $this_userdata['user_opt']; + + foreach ($update_user_opt as $opt) + { + setbit($user_opt, $bf['user_opt'][$opt], !empty($_POST[$opt])); + } + + $sql = "UPDATE " . BB_USERS . " + SET " . $username_sql . $passwd_sql . " + user_email = '" . str_replace("\'", "''", $email) . "', + user_icq = '" . str_replace("\'", "''", $icq) . "', + user_website = '" . str_replace("\'", "''", $website) . "', + user_occ = '" . str_replace("\'", "''", $occupation) . "', + user_from = '" . str_replace("\'", "''", $location) . "', + user_from_flag = '$user_flag', + user_interests = '" . str_replace("\'", "''", $interests) . "', + user_sig = '" . str_replace("\'", "''", $signature) . "', + user_opt = $user_opt, + user_allow_viewonline = $allowviewonline, + user_notify = $notifyreply, + user_notify_pm = $notifypm, + user_sig_bbcode_uid = '$signature_bbcode_uid', + user_allowavatar = $user_allowavatar, + user_allow_pm = $user_allowpm, + user_lang = '" . str_replace("\'", "''", $user_lang) . "', + user_timezone = $user_timezone, + user_dateformat = '" . str_replace("\'", "''", $user_dateformat) . "', + user_active = $user_status, + user_rank = $user_rank" . $avatar_sql . ", + user_actkey = '' + WHERE user_id = $user_id"; + + if( $result = DB()->sql_query($sql) ) + { + // Delete user session, to prevent the user navigating the forum (if logged in) when disabled + if (!$user_status) + { + delete_user_sessions($user_id); + } + + $message .= $lang['ADMIN_USER_UPDATED']; + } + else + { + $error = TRUE; + $error_msg .= ( ( isset($error_msg) ) ? '
' : '' ) . $lang['ADMIN_USER_FAIL']; + } + + if ($this_userdata['user_level'] == MOD) + { + $datastore->update('moderators'); + } + + if ($this_userdata['user_active'] != $user_status) + { + $log_action_type = (!$user_status) ? 'adm_user_ban' : 'adm_user_unban'; + + $log_action->admin($log_action_type, array( + 'log_msg' => 'user: '. get_usernames_for_log($user_id), + )); + } + + $message .= '

' . sprintf($lang['CLICK_RETURN_USERADMIN'], '', '') . '

' . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + } + else + { + $template->assign_vars(array('ERROR_MESSAGE' => $error_msg)); + + $username = htmlspecialchars(stripslashes($username)); + $email = stripslashes($email); + $password = ''; + $password_confirm = ''; + + $icq = stripslashes($icq); + + $website = htmlspecialchars(stripslashes($website)); + $location = htmlspecialchars(stripslashes($location)); + $occupation = htmlspecialchars(stripslashes($occupation)); + $interests = htmlspecialchars(stripslashes($interests)); + $signature = htmlspecialchars(stripslashes($signature)); + + $user_lang = stripslashes($user_lang); + $user_dateformat = htmlspecialchars(stripslashes($user_dateformat)); + } + } + else if( !isset( $_POST['submit'] ) && $mode != 'save' && !isset( $_POST['avatargallery'] ) && !isset( $_POST['submitavatar'] ) && !isset( $_POST['cancelavatar'] ) ) + { + if( isset( $_GET[POST_USERS_URL]) || isset( $_POST[POST_USERS_URL]) ) + { + $user_id = ( isset( $_POST[POST_USERS_URL]) ) ? intval( $_POST[POST_USERS_URL]) : intval( $_GET[POST_USERS_URL]); + $this_userdata = get_userdata($user_id); + if( !$this_userdata ) + { + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED'] ); + } + } + else + { + $this_userdata = get_userdata($_POST['username'], true); + if( !$this_userdata ) + { + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED'] ); + } + } + + // + // Now parse and display it as a template + // + $user_id = $this_userdata['user_id']; + $username = $this_userdata['username']; + $email = $this_userdata['user_email']; + $password = ''; + $password_confirm = ''; + + $icq = $this_userdata['user_icq']; + + $website = htmlspecialchars($this_userdata['user_website']); + $location = htmlspecialchars($this_userdata['user_from']); + $user_flag = htmlspecialchars($this_userdata['user_from_flag']); + + $occupation = htmlspecialchars($this_userdata['user_occ']); + $interests = htmlspecialchars($this_userdata['user_interests']); + + $signature = ($this_userdata['user_sig_bbcode_uid'] != '') ? preg_replace('#:' . $this_userdata['user_sig_bbcode_uid'] . '#si', '', $this_userdata['user_sig']) : $this_userdata['user_sig']; + $signature = preg_replace($html_entities_match, $html_entities_replace, $signature); + + $viewemail = bf($this_userdata['user_opt'], 'user_opt', 'viewemail'); + $notifypm = $this_userdata['user_notify_pm']; + $notifyreply = $this_userdata['user_notify']; + $attachsig = bf($this_userdata['user_opt'], 'user_opt', 'attachsig'); + $allowviewonline = $this_userdata['user_allow_viewonline']; + + $user_avatar = $this_userdata['user_avatar']; + $user_avatar_type = $this_userdata['user_avatar_type']; + $user_timezone = $this_userdata['user_timezone']; + + $user_lang = ($this_userdata['user_lang']) ? $this_userdata['user_lang'] : $bb_cfg['default_lang']; + $user_dateformat = ($this_userdata['user_dateformat']) ? $this_userdata['user_dateformat'] : $bb_cfg['default_dateformat']; + + $user_status = $this_userdata['user_active']; + $user_allowavatar = $this_userdata['user_allowavatar']; + $user_allowpm = $this_userdata['user_allow_pm']; + + $bbcode_status = ($bb_cfg['allow_bbcode']) ? $lang['BBCODE_IS_ON'] : $lang['BBCODE_IS_OFF']; + $smilies_status = ($bb_cfg['allow_smilies']) ? $lang['SMILIES_ARE_ON'] : $lang['SMILIES_ARE_OFF']; + } + + if( isset($_POST['avatargallery']) && !$error ) + { + if( !$error ) + { + $user_id = intval($_POST['id']); + + $dir = @opendir("../" . $bb_cfg['avatar_gallery_path']); + + $avatar_images = array(); + while( $file = @readdir($dir) ) + { + if( $file != "." && $file != ".." && !is_file(phpbb_realpath("./../" . $bb_cfg['avatar_gallery_path'] . "/" . $file)) && !is_link(phpbb_realpath("./../" . $bb_cfg['avatar_gallery_path'] . "/" . $file)) ) + { + $sub_dir = @opendir("../" . $bb_cfg['avatar_gallery_path'] . "/" . $file); + + $avatar_row_count = 0; + $avatar_col_count = 0; + + while( $sub_file = @readdir($sub_dir) ) + { + if( preg_match("/(\.gif$|\.png$|\.jpg)$/is", $sub_file) ) + { + $avatar_images[$file][$avatar_row_count][$avatar_col_count] = $sub_file; + + $avatar_col_count++; + if( $avatar_col_count == 5 ) + { + $avatar_row_count++; + $avatar_col_count = 0; + } + } + } + } + } + + @closedir($dir); + + if( isset($_POST['avatarcategory']) ) + { + $category = htmlspecialchars($_POST['avatarcategory']); + } + else + { + list($category, ) = each($avatar_images); + } + @reset($avatar_images); + + $s_categories = ""; + while( list($key) = each($avatar_images) ) + { + $selected = ( $key == $category ) ? "selected=\"selected\"" : ""; + if( count($avatar_images[$key]) ) + { + $s_categories .= ''; + } + } + + $s_colspan = 0; + for($i = 0; $i < count($avatar_images[$category]); $i++) + { + $template->assign_block_vars("avatar_row", array()); + + $s_colspan = max($s_colspan, count($avatar_images[$category][$i])); + + for($j = 0; $j < count($avatar_images[$category][$i]); $j++) + { + $template->assign_block_vars("avatar_row.avatar_column", array( + "AVATAR_IMAGE" => "../" . $bb_cfg['avatar_gallery_path'] . '/' . $category . '/' . $avatar_images[$category][$i][$j]) + ); + + $template->assign_block_vars("avatar_row.avatar_option_column", array( + "S_OPTIONS_AVATAR" => $avatar_images[$category][$i][$j]) + ); + } + } + + $s_hidden_fields = ''; + $s_hidden_fields .= ''; + + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + +// FLAGHACK-start + $s_hidden_fields .= ''; +// FLAGHACK-end + + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + $s_hidden_fields .= ''; + + $template->assign_vars(array( + 'TPL_ADMIN_USER_AVATAR_GALLERY' => true, + + "L_USER_EXPLAIN" => $lang['USER_ADMIN_EXPLAIN'], + + "S_OPTIONS_CATEGORIES" => $s_categories, + "S_COLSPAN" => $s_colspan, + "S_PROFILE_ACTION" => append_sid("admin_users.php?mode=$mode"), + "S_HIDDEN_FIELDS" => $s_hidden_fields) + ); + } + } + else + { + $s_hidden_fields = ''; + $s_hidden_fields .= ''; + + if( !empty($user_avatar_local) ) + { + $s_hidden_fields .= ''; + } + + if( $user_avatar_type ) + { + switch( $user_avatar_type ) + { + case USER_AVATAR_UPLOAD: + $avatar = ''; + break; + case USER_AVATAR_REMOTE: + $avatar = ''; + break; + case USER_AVATAR_GALLERY: + $avatar = ''; + break; + } + } + else + { + $avatar = ""; + } + + $sql = "SELECT * FROM " . BB_RANKS . " + WHERE rank_special = 1 + ORDER BY rank_title"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain ranks data', '', __LINE__, __FILE__, $sql); + } + + $rank_select_box = ''; + while( $row = DB()->sql_fetchrow($result) ) + { + $rank = $row['rank_title']; + $rank_id = $row['rank_id']; + + $selected = ( $this_userdata['user_rank'] == $rank_id ) ? ' selected="selected"' : ''; + $rank_select_box .= ''; + } + + // + // Let's do an overall check for settings/versions which would prevent + // us from doing file uploads.... + // + $ini_val = ( phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var'; + $form_enctype = ( !@$ini_val('file_uploads') || phpversion() == '4.0.4pl1' || !$bb_cfg['allow_avatar_upload'] || ( phpversion() < '4.0.3' && @$ini_val('open_basedir') != '' ) ) ? '' : 'enctype="multipart/form-data"'; + + // query to get the list of flags + $sql = "SELECT * + FROM " . BB_COUNTRIES . " + ORDER BY country_id"; + if(!$flags_result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't obtain flags information.", "", __LINE__, __FILE__, $sql); + } + $flag_row = DB()->sql_fetchrowset($flags_result); + $num_flags = DB()->num_rows($flags_result); + + // build the html select statement + if(!defined('COUNTRIES_LANG')) + { + include(LANG_DIR . "lang_countries.php"); + } + + $flag_start_image = 'blank.gif' ; + $selected = ( isset($user_flag) ) ? '' : HTML_SELECTED; + $flag_select = "'; + + $template->assign_vars(array( + 'TPL_ADMIN_USER_EDIT' => true, + + 'USERNAME' => $username, + 'EMAIL' => $email, + 'ICQ' => $icq, + 'OCCUPATION' => $occupation, + 'INTERESTS' => $interests, + 'LOCATION' => $location, + 'L_FLAG' => $lang['COUNTRY_FLAG'], + 'FLAG_SELECT' => $flag_select, + 'FLAG_START' => $flag_start_image, + + 'WEBSITE' => $website, + 'SIGNATURE' => str_replace('
', "\n", $signature), + 'VIEW_EMAIL_YES' => ($viewemail) ? 'checked="checked"' : '', + 'VIEW_EMAIL_NO' => (!$viewemail) ? 'checked="checked"' : '', + 'HIDE_USER_YES' => (!$allowviewonline) ? 'checked="checked"' : '', + 'HIDE_USER_NO' => ($allowviewonline) ? 'checked="checked"' : '', + 'NOTIFY_PM_YES' => ($notifypm) ? 'checked="checked"' : '', + 'NOTIFY_PM_NO' => (!$notifypm) ? 'checked="checked"' : '', + 'ALWAYS_ADD_SIGNATURE_YES' => ($attachsig) ? 'checked="checked"' : '', + 'ALWAYS_ADD_SIGNATURE_NO' => (!$attachsig) ? 'checked="checked"' : '', + 'NOTIFY_REPLY_YES' => ( $notifyreply ) ? 'checked="checked"' : '', + 'NOTIFY_REPLY_NO' => ( !$notifyreply ) ? 'checked="checked"' : '', + 'ADMIN_AVATAR' => $avatar, + 'LANGUAGE_SELECT' => language_select($user_lang), + 'TIMEZONE_SELECT' => tz_select($user_timezone), + 'STYLE_SELECT' => $bb_cfg['tpl_name'], + 'DATE_FORMAT' => $user_dateformat, + 'ALLOW_PM_YES' => ($user_allowpm) ? 'checked="checked"' : '', + 'ALLOW_PM_NO' => (!$user_allowpm) ? 'checked="checked"' : '', + 'ALLOW_AVATAR_YES' => ($user_allowavatar) ? 'checked="checked"' : '', + 'ALLOW_AVATAR_NO' => (!$user_allowavatar) ? 'checked="checked"' : '', + 'USER_ACTIVE_YES' => ($user_status) ? 'checked="checked"' : '', + 'USER_ACTIVE_NO' => (!$user_status) ? 'checked="checked"' : '', + 'RANK_SELECT_BOX' => $rank_select_box, + + 'L_USER_EXPLAIN' => $lang['USER_ADMIN_EXPLAIN'], + 'L_BOARD_LANGUAGE' => $lang['BOARD_LANG'], + 'L_ALWAYS_ADD_SIGNATURE' => $lang['ALWAYS_ADD_SIG'], + + 'L_SPECIAL' => $lang['USER_SPECIAL'], + 'L_SPECIAL_EXPLAIN' => $lang['USER_SPECIAL_EXPLAIN'], + 'L_USER_ACTIVE' => $lang['USER_STATUS'], + 'L_ALLOW_PM' => $lang['USER_ALLOWPM'], + 'L_ALLOW_AVATAR' => $lang['USER_ALLOWAVATAR'], + + 'L_AVATAR_EXP' => $lang['ADMIN_AVATAR_EXPLAIN'], + 'L_DELETE_AVATAR' => $lang['DELETE_IMAGE'], + 'L_AVATAR_GALLERY' => $lang['SELECT_FROM_GALLERY'], + 'L_SHOW_GALLERY' => $lang['VIEW_AVATAR_GALLERY'], + 'L_LINK_REMOTE_AVATAR' => $lang['LINK_REMOTE_AVATAR'], + + 'L_SIGNATURE_EXP' => sprintf($lang['SIGNATURE_EXPLAIN'], $bb_cfg['max_sig_chars'] ), + 'L_NOTIFY_ON_REPLY' => $lang['ALWAYS_NOTIFY'], + 'L_PROFILE_INFO_NOTICE' => $lang['PROFILE_INFO_WARN'], + 'S_FORM_ENCTYPE' => $form_enctype, + + 'BBCODE_STATUS' => sprintf(@$bbcode_status, '', ''), + 'SMILIES_STATUS' => @$smilies_status, + + 'L_DELETE_USER' => $lang['USER_DELETE'], + 'L_DELETE_USER_EXPLAIN' => $lang['USER_DELETE_EXPLAIN'], + 'L_SELECT_RANK' => $lang['RANK_TITLE'], + + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_PROFILE_ACTION' => append_sid("admin_users.php")) + ); + + if( file_exists(@phpbb_realpath('./../' . $bb_cfg['avatar_path'])) && ($bb_cfg['allow_avatar_upload'] == TRUE) ) + { + if ( $form_enctype != '' ) + { + $template->assign_block_vars('avatar_local_upload', array() ); + } + $template->assign_block_vars('avatar_remote_upload', array() ); + } + + if( file_exists(@phpbb_realpath('./../' . $bb_cfg['avatar_gallery_path'])) && ($bb_cfg['allow_avatar_local'] == TRUE) ) + { + $template->assign_block_vars('avatar_local_gallery', array() ); + } + + if( $bb_cfg['allow_avatar_remote'] == TRUE ) + { + $template->assign_block_vars('avatar_remote_link', array() ); + } + } +} +else +{ + // + // Default user selection box + // + $template->assign_vars(array( + 'TPL_ADMIN_USER_SELECT' => true, + + 'L_USER_EXPLAIN' => $lang['USER_ADMIN_EXPLAIN'], + + 'U_SEARCH_USER' => append_sid("./../search.php?mode=searchuser"), + + 'S_USER_ACTION' => append_sid("admin_users.php"), + 'S_USER_SELECT' => @$select_list) + ); +} + +print_page('admin_users.tpl', 'admin'); \ No newline at end of file diff --git a/upload/admin/admin_words.php b/upload/admin/admin_words.php new file mode 100644 index 000000000..bc6797486 --- /dev/null +++ b/upload/admin/admin_words.php @@ -0,0 +1,175 @@ +
($bb_cfg[\'use_word_censor\'] in config.php)'); +} + +$mode = request_var('mode', ''); +$mode = htmlspecialchars($mode); +// +// These could be entered via a form button +// +if( isset($_POST['add']) ) +{ + $mode = "add"; +} +else if( isset($_POST['save']) ) +{ + $mode = "save"; +} + +if( $mode != "" ) +{ + if( $mode == "edit" || $mode == "add" ) + { + $word_id = intval(request_var('id', 0)); + + $s_hidden_fields = $word = $replacement = ''; + + if( $mode == "edit" ) + { + if( $word_id ) + { + $sql = "SELECT * + FROM " . BB_WORDS . " + WHERE word_id = $word_id"; + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not query words table", "Error", __LINE__, __FILE__, $sql); + } + + $word_info = DB()->sql_fetchrow($result); + $s_hidden_fields .= ''; + $word = $word_info['word']; + $replacement = $word_info['replacement']; + } + else + { + message_die(GENERAL_MESSAGE, $lang['NO_WORD_SELECTED']); + } + } + + $template->assign_vars(array( + 'TPL_ADMIN_WORDS_EDIT' => true, + + "WORD" => $word, + "REPLACEMENT" => $replacement, + + "L_WORDS_TEXT" => $lang['WORDS_EXPLAIN'], + "L_WORD_CENSOR" => $lang['EDIT_WORD_CENSOR'], + + "S_WORDS_ACTION" => append_sid("admin_words.php"), + "S_HIDDEN_FIELDS" => $s_hidden_fields) + ); + } + else if( $mode == "save" ) + { + $word_id = intval(request_var('id', 0)); + $word = trim(request_var('word', "")); + $replacement = trim(request_var('replacement', "")); + + if($word == "" || $replacement == "") + { + message_die(GENERAL_MESSAGE, $lang['MUST_ENTER_WORD']); + } + + if( $word_id ) + { + $sql = "UPDATE " . BB_WORDS . " + SET word = '" . str_replace("\'", "''", $word) . "', replacement = '" . str_replace("\'", "''", $replacement) . "' + WHERE word_id = $word_id"; + $message = $lang['WORD_UPDATED']; + } + else + { + $sql = "INSERT INTO " . BB_WORDS . " (word, replacement) + VALUES ('" . str_replace("\'", "''", $word) . "', '" . str_replace("\'", "''", $replacement) . "')"; + $message = $lang['WORD_ADDED']; + } + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not insert data into words table", $lang['ERROR'], __LINE__, __FILE__, $sql); + } + + $message .= "

" . sprintf($lang['CLICK_RETURN_WORDADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + } + else if( $mode == "delete" ) + { + $word_id = intval(request_var('id', 0)); + + if( $word_id ) + { + $sql = "DELETE FROM " . BB_WORDS . " + WHERE word_id = $word_id"; + + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not remove data from words table", $lang['ERROR'], __LINE__, __FILE__, $sql); + } + + $message = $lang['WORD_REMOVED'] . "

" . sprintf($lang['CLICK_RETURN_WORDADMIN'], "", "") . "

" . sprintf($lang['CLICK_RETURN_ADMIN_INDEX'], "", ""); + + message_die(GENERAL_MESSAGE, $message); + } + else + { + message_die(GENERAL_MESSAGE, $lang['NO_WORD_SELECTED']); + } + } +} +else +{ + $sql = "SELECT * + FROM " . BB_WORDS . " + ORDER BY word"; + if( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not query words table", $lang['ERROR'], __LINE__, __FILE__, $sql); + } + + $word_rows = DB()->sql_fetchrowset($result); + $word_count = count($word_rows); + + $template->assign_vars(array( + 'TPL_ADMIN_WORDS_LIST' => true, + + "L_WORDS_TEXT" => $lang['WORDS_EXPLAIN'], + "L_ADD_WORD" => $lang['ADD_NEW_WORD'], + + "S_WORDS_ACTION" => append_sid("admin_words.php"), + "S_HIDDEN_FIELDS" => '') + ); + + for($i = 0; $i < $word_count; $i++) + { + $word = $word_rows[$i]['word']; + $replacement = $word_rows[$i]['replacement']; + $word_id = $word_rows[$i]['word_id']; + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars("words", array( + "ROW_CLASS" => $row_class, + "WORD" => $word, + "REPLACEMENT" => $replacement, + + "U_WORD_EDIT" => append_sid("admin_words.php?mode=edit&id=$word_id"), + "U_WORD_DELETE" => append_sid("admin_words.php?mode=delete&id=$word_id")) + ); + } +} + +print_page('admin_words.tpl', 'admin'); diff --git a/upload/admin/admin_xs.php b/upload/admin/admin_xs.php new file mode 100644 index 000000000..4e4d6aa9a --- /dev/null +++ b/upload/admin/admin_xs.php @@ -0,0 +1,15 @@ +assign_vars(array( + 'TPL_ADMIN_NAVIGATE' => true, + + "L_FRAME_NO_SUPPORT" => $lang['IDX_BROWSER_NSP_FRAME'], + + "U_FORUM_INDEX" => append_sid("../index.php"), + "U_ADMIN_INDEX" => append_sid("index.php?pane=right")) + ); + + ksort($module); + + while( list($cat, $action_array) = each($module) ) + { + $cat = ( !empty($lang[strtoupper($cat)]) ) ? $lang[strtoupper($cat)] : preg_replace("/_/", " ", $cat); + + $template->assign_block_vars("catrow", array( + "ADMIN_CATEGORY" => $cat) + ); + + ksort($action_array); + + $row_count = 0; + while( list($action, $file) = each($action_array) ) + { + $row_class = !($row_count % 2) ? 'row1' : 'row2'; + + $action = ( !empty($lang[strtoupper($action)]) ) ? $lang[strtoupper($action)] : preg_replace("/_/", " ", $action); + + $template->assign_block_vars("catrow.modulerow", array( + "ROW_CLASS" => $row_class, + + "ADMIN_MODULE" => $action, + "U_ADMIN_MODULE" => append_sid($file)) + ); + $row_count++; + } + } +} +else if( isset($_GET['pane']) && $_GET['pane'] == 'right' ) +{ + $template->assign_vars(array( + 'TPL_ADMIN_MAIN' => true, + + "L_LAST_UPDATE" => $lang['LAST_UPDATED'], + "L_DB_SIZE" => $lang['DATABASE_SIZE']) + ); + + // + // Get forum statistics + // + $total_posts = get_db_stat('postcount'); + $total_users = get_db_stat('usercount'); + $total_topics = get_db_stat('topiccount'); + + $start_date = bb_date($bb_cfg['board_startdate']); + + $boarddays = ( time() - $bb_cfg['board_startdate'] ) / 86400; + + $posts_per_day = sprintf("%.2f", $total_posts / $boarddays); + $topics_per_day = sprintf("%.2f", $total_topics / $boarddays); + $users_per_day = sprintf("%.2f", $total_users / $boarddays); + + $avatar_dir_size = 0; + + if ($avatar_dir = @opendir(BB_ROOT . $bb_cfg['avatar_path'])) + { + while( $file = @readdir($avatar_dir) ) + { + if( $file != "." && $file != ".." ) + { + $avatar_dir_size += @filesize(BB_ROOT . $bb_cfg['avatar_path'] . "/" . $file); + } + } + @closedir($avatar_dir); + + // + // This bit of code translates the avatar directory size into human readable format + // Borrowed the code from the PHP.net annoted manual, origanally written by: + // Jesse (jesse@jess.on.ca) + // + if($avatar_dir_size >= 1048576) + { + $avatar_dir_size = round($avatar_dir_size / 1048576 * 100) / 100 . " MB"; + } + else if($avatar_dir_size >= 1024) + { + $avatar_dir_size = round($avatar_dir_size / 1024 * 100) / 100 . " KB"; + } + else + { + $avatar_dir_size = $avatar_dir_size . " Bytes"; + } + + } + else + { + // Couldn't open Avatar dir. + $avatar_dir_size = $lang['NOT_AVAILABLE']; + } + + if(intval($posts_per_day) > $total_posts) + { + $posts_per_day = $total_posts; + } + + if(intval($topics_per_day) > $total_topics) + { + $topics_per_day = $total_topics; + } + + if($users_per_day > $total_users) + { + $users_per_day = $total_users; + } + + // + // DB size ... MySQL only + // + // This code is heavily influenced by a similar routine + // in phpMyAdmin 2.2.0 + // + /* + if( preg_match("/^mysql/", SQL_LAYER) ) + { + $sql = "SELECT VERSION() AS mysql_version"; + if($result = DB()->sql_query($sql)) + { + $row = DB()->sql_fetchrow($result); + $version = $row['mysql_version']; + + if( preg_match("/^(3\.23|4\.|5\.)/", $version) ) + { + $db_name = ( preg_match("/^(3\.23\.[6-9])|(3\.23\.[1-9][1-9])|(4\.)|(5\.)/", $version) ) ? "`".DBNAME."`" : DBNAME; + + $sql = "SHOW TABLE STATUS FROM " . $db_name; + if($result = DB()->sql_query($sql)) + { + $tabledata_ary = DB()->sql_fetchrowset($result); + + $dbsize = 0; + for($i = 0; $i < count($tabledata_ary); $i++) + { + if( @$tabledata_ary[$i]['Type'] != "MRG_MyISAM" ) + { + $dbsize += $tabledata_ary[$i]['Data_length'] + $tabledata_ary[$i]['Index_length']; + } + } + } // Else we couldn't get the table status. + } + else + { + $dbsize = $lang['NOT_AVAILABLE']; + } + } + else + { + $dbsize = $lang['NOT_AVAILABLE']; + } + } + else if( preg_match("/^mssql/", SQL_LAYER) ) + { + $sql = "SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize + FROM sysfiles"; + if( $result = DB()->sql_query($sql) ) + { + $dbsize = ( $row = DB()->sql_fetchrow($result) ) ? intval($row['dbsize']) : $lang['NOT_AVAILABLE']; + } + else + { + $dbsize = $lang['NOT_AVAILABLE']; + } + } + else + { + $dbsize = $lang['NOT_AVAILABLE']; + } + */ + $dbsize = $lang['NOT_AVAILABLE']; + + if ( is_integer($dbsize) ) + { + if( $dbsize >= 1048576 ) + { + $dbsize = sprintf("%.2f MB", ( $dbsize / 1048576 )); + } + else if( $dbsize >= 1024 ) + { + $dbsize = sprintf("%.2f KB", ( $dbsize / 1024 )); + } + else + { + $dbsize = sprintf("%.2f Bytes", $dbsize); + } + } + + $template->assign_vars(array( + "NUMBER_OF_POSTS" => $total_posts, + "NUMBER_OF_TOPICS" => $total_topics, + "NUMBER_OF_USERS" => $total_users, + "START_DATE" => $start_date, + "POSTS_PER_DAY" => $posts_per_day, + "TOPICS_PER_DAY" => $topics_per_day, + "USERS_PER_DAY" => $users_per_day, + "AVATAR_DIR_SIZE" => $avatar_dir_size, + "DB_SIZE" => $dbsize, + "GZIP_COMPRESSION" => ( $bb_cfg['gzip_compress'] ) ? $lang['ON'] : $lang['OFF']) + ); + // + // End forum statistics + // + if (@$_GET['users_online']) + { + $template->assign_vars(array( + 'SHOW_USERS_ONLINE' => true, + )); + // + // Get users online information. + // + $sql = "SELECT u.user_id, u.username, s.session_time AS user_session_time, u.user_allow_viewonline, s.session_logged_in, s.session_ip, s.session_start + FROM " . BB_USERS . " u, " . BB_SESSIONS . " s + WHERE s.session_logged_in = 1 + AND u.user_id = s.session_user_id + AND u.user_id <> " . ANONYMOUS . " + AND s.session_time >= " . ( time() - 300 ) . " + ORDER BY s.session_ip ASC, s.session_time DESC"; + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't obtain regd user/online information.", "", __LINE__, __FILE__, $sql); + } + $onlinerow_reg = DB()->sql_fetchrowset($result); + + $sql = "SELECT session_logged_in, session_time, session_ip, session_start + FROM " . BB_SESSIONS . " + WHERE session_logged_in = 0 + AND session_time >= " . ( time() - 300 ) . " + ORDER BY session_ip ASC, session_time DESC"; + if(!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Couldn't obtain guest user/online information.", "", __LINE__, __FILE__, $sql); + } + $onlinerow_guest = DB()->sql_fetchrowset($result); + + $sql = "SELECT forum_name, forum_id + FROM " . BB_FORUMS; + if($forums_result = DB()->sql_query($sql)) + { + while($forumsrow = DB()->sql_fetchrow($forums_result)) + { + $forum_data[$forumsrow['forum_id']] = $forumsrow['forum_name']; + } + } + else + { + message_die(GENERAL_ERROR, "Couldn't obtain user/online forums information.", "", __LINE__, __FILE__, $sql); + } + + $reg_userid_ary = array(); + + if( count($onlinerow_reg) ) + { + $registered_users = 0; + + for($i=0, $cnt=count($onlinerow_reg); $i < $cnt; $i++) + { + if( !inarray($onlinerow_reg[$i]['user_id'], $reg_userid_ary) ) + { + $reg_userid_ary[] = $onlinerow_reg[$i]['user_id']; + + $username = $onlinerow_reg[$i]['username']; + + if( $onlinerow_reg[$i]['user_allow_viewonline'] ) + { + $registered_users++; + $hidden = FALSE; + } + else + { + @$hidden_users++; + $hidden = TRUE; + } + + $row_class = 'row1'; + + $reg_ip = decode_ip($onlinerow_reg[$i]['session_ip']); + + $template->assign_block_vars("reg_user_row", array( + "ROW_CLASS" => $row_class, + "USERNAME" => $username, + "STARTED" => bb_date($onlinerow_reg[$i]['session_start'], 'H:i'), + "LASTUPDATE" => bb_date($onlinerow_reg[$i]['user_session_time'], 'H:i'), + "IP_ADDRESS" => $reg_ip, + + "U_WHOIS_IP" => "http://www.dnsstuff.com/tools/whois/?ip=$reg_ip", + "U_USER_PROFILE" => append_sid("admin_users.php?mode=edit&" . POST_USERS_URL . "=" . $onlinerow_reg[$i]['user_id']), + )); + } + } + + } + else + { + $template->assign_vars(array( + "L_NO_REGISTERED_USERS_BROWSING" => $lang['NO_USERS_BROWSING']) + ); + } + + // + // Guest users + // + if( count($onlinerow_guest) ) + { + $guest_users = 0; + + for($i = 0; $i < count($onlinerow_guest); $i++) + { + $guest_userip_ary[] = $onlinerow_guest[$i]['session_ip']; + $guest_users++; + + $row_class = 'row2'; + + $guest_ip = decode_ip($onlinerow_guest[$i]['session_ip']); + + $template->assign_block_vars("guest_user_row", array( + "ROW_CLASS" => $row_class, + "USERNAME" => $lang['GUEST'], + "STARTED" => bb_date($onlinerow_guest[$i]['session_start'], 'H:i'), + "LASTUPDATE" => bb_date($onlinerow_guest[$i]['session_time'], 'H:i'), + "IP_ADDRESS" => $guest_ip, + + "U_WHOIS_IP" => "http://www.dnsstuff.com/tools/whois/?ip=$guest_ip", + )); + } + } + else + { + $template->assign_vars(array( + "L_NO_GUESTS_BROWSING" => $lang['NO_USERS_BROWSING']) + ); + } + } + else + { + $template->assign_vars(array( + 'USERS_ONLINE_HREF' => "index.php?pane=right&users_online=1&sid={$userdata['session_id']}", + )); + } + + $template->assign_vars(array( + 'U_CLEAR_DATASTORE' => "index.php?clear_datastore=1", + 'U_CLEAR_TPL_CACHE' => "xs_cache.php?clear=", + 'U_UPDATE_USER_LEVEL' => "index.php?update_user_level=1", + 'U_SYNC_TOPICS' => "index.php?sync_topics=1", + 'U_SYNC_USER_POSTS' => "index.php?sync_user_posts=1", + )); +} +else if (isset($_REQUEST['clear_datastore'])) +{ + $datastore->clean(); + bb_die($lang['DATASTORE_CLEARED']); +} +else if (isset($_REQUEST['update_user_level'])) +{ + require(INC_DIR .'functions_group.php'); + update_user_level('all'); + bb_die($lang['USER_LEVELS_UPDATED']); +} +else if (isset($_REQUEST['sync_topics'])) +{ + sync('topic', 'all'); + sync('forum', 'all'); + bb_die($lang['TOPICS_DATA_SYNCHRONIZED']); +} +else if (isset($_REQUEST['sync_user_posts'])) +{ + sync('user_posts', 'all'); + bb_die($lang['USER POSTS COUNT SYNCHRONIZED']); +} +else +{ + // + // Generate frameset + // + $template->assign_vars(array( + 'TPL_ADMIN_FRAMESET' => true, + 'S_FRAME_NAV' => "index.php?pane=left", + 'S_FRAME_MAIN' => "index.php?pane=right", + )); + send_no_cache_headers(); + print_page('index.tpl', 'admin', 'no_header'); +} + +print_page('index.tpl', 'admin'); + +// +// Functions +// +function inarray($needle, $haystack) +{ + for($i = 0; $i < sizeof($haystack); $i++ ) + { + if( $haystack[$i] == $needle ) + { + return true; + } + } + return false; +} diff --git a/upload/admin/pagestart.php b/upload/admin/pagestart.php new file mode 100644 index 000000000..30a7014e8 --- /dev/null +++ b/upload/admin/pagestart.php @@ -0,0 +1,26 @@ +session_start(); + +if (IS_GUEST) +{ + redirect("login.php?redirect=admin/index.php"); +} +if (!IS_ADMIN) +{ + message_die(GENERAL_MESSAGE, $lang['NOT_ADMIN']); +} +if (!$userdata['session_admin']) +{ + $redirect = url_arg($_SERVER['REQUEST_URI'], 'admin', 1); + redirect("login.php?redirect=$redirect"); +} diff --git a/upload/admin/xs_cache.php b/upload/admin/xs_cache.php new file mode 100644 index 000000000..175568c7f --- /dev/null +++ b/upload/admin/xs_cache.php @@ -0,0 +1,263 @@ +xs_version) || $template->xs_version !== 8) +{ + message_die(GENERAL_ERROR, isset($lang['XS_ERROR_NOT_INSTALLED']) ? $lang['XS_ERROR_NOT_INSTALLED'] : 'eXtreme Styles mod is not installed. You forgot to upload includes/template.php'); +} + +define('IN_XS', true); +include('xs_include.php'); + +$template->assign_block_vars('nav_left',array('ITEM' => '» ' . $lang['XS_MANAGE_CACHE'] . '')); + +$data = ''; + +$skip_files = array( + '.', + '..', + '.htaccess', + 'index.htm', + 'index.html', + 'index.php', + 'attach_config.php', + ); + +// +// clear cache +// +if(isset($_GET['clear']) && !defined('DEMO_MODE')) +{ + @set_time_limit(XS_MAX_TIMEOUT); + $clear = $_GET['clear']; + if(!$clear) + { + // clear all cache + $match = ''; + } + else + { + $match = XS_TPL_PREFIX . $clear . XS_SEPARATOR; + } + $match_len = strlen($match); + $style_len = strlen(STYLE_EXTENSION); + $backup_len = strlen(XS_BACKUP_EXT); + $dir = $template->cachedir; + $res = @opendir($dir); + if(!$res) + { + $data = $lang['XS_CACHE_NOWRITE']; + } + else + { + $num = 0; + $num_error = 0; + while(($file = readdir($res)) !== false) + { + $len = strlen($file); + // delete only files that match pattern, that aren't in exclusion list and that aren't downloaded styles. + if(substr($file, 0, $match_len) === $match && !in_array($file, $skip_files)) + if(substr($file, $len - $style_len) !== STYLE_EXTENSION && substr($file, $len - $backup_len) !== XS_BACKUP_EXT) + { + $res2 = @unlink($dir . $file); + if($res2) + { + $data .= str_replace('{FILE}', $file, $lang['XS_CACHE_LOG_DELETED']) . "
\n"; + $num ++; + } + elseif(@is_file($dir . $file)) + { + $data .= str_replace('{FILE}', $file, $lang['XS_CACHE_LOG_NODELETE']) . "
\n"; + $num_error ++; + } + } + } + closedir($res); + if(!$num && !$num_error) + { + if($clear) + { + $data .= str_replace('{TPL}', $clear, $lang['XS_CACHE_LOG_NOTHING']) . "
\n"; + } + else + { + $data .= $lang['XS_CACHE_LOG_NOTHING2'] . "
\n"; + } + } + else + { + $data .= str_replace('{NUM}', $num, $lang['XS_CACHE_LOG_COUNT']) . "
\n"; + if($num_error) + { + $data .= str_replace('{NUM}', $num_error, $lang['XS_CACHE_LOG_COUNT2']) . "
\n"; + } + } + } +} + + +// +// compile cache +// +if(isset($_GET['compile']) && !defined('DEMO_MODE')) +{ + $tpl = $_GET['compile']; + @set_time_limit(XS_MAX_TIMEOUT); + $num_errors = 0; + $num_compiled = 0; + if($tpl) + { + $dir = $template->tpldir . $tpl . '/'; + compile_cache($dir, '', $tpl); + } + else + { + $res = opendir('../templates'); + while(($file = readdir($res)) !== false) + { + if($file !== '.' && $file !== '..' && is_dir('../templates/'.$file) && @file_exists('../templates/'.$file.'/page_header.tpl')) + { + compile_cache('../templates/'.$file.'/', '', $file); + } + } + closedir($res); + } + $data .= str_replace('{NUM}', $num_compiled, $lang['XS_CACHE_LOG_COMPILED']) . "
\n"; + $data .= str_replace('{NUM}', $num_errors, $lang['XS_CACHE_LOG_ERRORS']) . "
\n"; +} + +function compile_cache($dir, $subdir, $tpl) +{ + global $data, $template, $num_errors, $num_compiled, $lang; + $str = $dir . $subdir; + $res = @opendir($dir . $subdir); + if(!$res) + { + $data .= str_replace('{DIR}', $dir.$subdir, $lang['XS_CACHE_LOG_NOACCESS']) . "
\n"; + $num_errors ++; + return; + } + while(($file = readdir($res)) !== false) + { + if(@is_dir($str . $file) && $file !== '.' && $file !== '..' && $file !== 'CVS') + { + compile_cache($dir, $subdir . $file . '/', $tpl); + } + elseif(substr($file, strlen($file) - 4) === '.tpl') + { + $res2 = $template->precompile($tpl, $subdir . $file); + if($res2) + { + $data .= str_replace('{FILE}', $dir.$subdir.$file, $lang['XS_CACHE_LOG_COMPILED2']) . "
\n"; + $num_compiled ++; + } + else + { + $data .= str_replace('{FILE}', $dir.$subdir.$file, $lang['XS_CACHE_LOG_NOCOMPILE']) . "
\n"; + $num_errors ++; + } + } + } + closedir($res); +} + +// +// get list of installed styles +// +$style_rowset = array( + 0 => array( + 'themes_id' => 1, + 'template_name' => 'default', + 'style_name' => 'default', + ), + 1 => array( + 'themes_id' => 2, + 'template_name' => $bb_cfg['tpl_name'], + 'style_name' => $bb_cfg['tpl_name'], + ), +); +$template->set_filenames(array('body' => XS_TPL_PATH . 'cache.tpl')); + +$prev_id = -1; +$prev_tpl = ''; +$style_names = array(); +$j = 0; +for($i=0; $i 0) + { + $str = implode('
', $style_names); + $str2 = urlencode($prev_tpl); + $row_class = $xs_row_class[$j % 2]; + $j++; + $template->assign_block_vars('styles', array( + 'ROW_CLASS' => $row_class, + 'TPL' => $prev_tpl, + 'STYLES' => $str, + 'U_CLEAR' => "xs_cache.php?clear={$str2}&sid={$userdata['session_id']}", + 'U_COMPILE' => "xs_cache.php?compile={$str2}&sid={$userdata['session_id']}", + ) + ); + } + $prev_id = $item['themes_id']; + $prev_tpl = $item['template_name']; + $style_names = array(htmlspecialchars($item['style_name'])); + } +} +if($prev_id > 0) +{ + $str = implode('
', $style_names); + $str2 = urlencode($prev_tpl); + $row_class = $xs_row_class[$j % 2]; + $j++; + $template->assign_block_vars('styles', array( + 'ROW_CLASS' => $row_class, + 'TPL' => $prev_tpl, + 'STYLES' => $str, + 'U_CLEAR' => "xs_cache.php?clear={$str2}&sid={$userdata['session_id']}", + 'U_COMPILE' => "xs_cache.php?compile={$str2}&sid={$userdata['session_id']}", + ) + ); +} + +$template->assign_vars(array( + 'U_CLEAR_ALL' => "xs_cache.php?clear=&sid={$userdata['session_id']}", + 'U_COMPILE_ALL' => "xs_cache.php?compile=&sid={$userdata['session_id']}", + 'RESULT' => '

' . $data + ) +); + +$template->pparse('body'); +xs_exit(); \ No newline at end of file diff --git a/upload/admin/xs_config.php b/upload/admin/xs_config.php new file mode 100644 index 000000000..0d2033102 --- /dev/null +++ b/upload/admin/xs_config.php @@ -0,0 +1,138 @@ +xs_version) || $template->xs_version !== 8) +{ + message_die(GENERAL_ERROR, isset($lang['XS_ERROR_NOT_INSTALLED']) ? $lang['XS_ERROR_NOT_INSTALLED'] : 'eXtreme Styles mod is not installed. You forgot to upload includes/template.php'); +} + +define('IN_XS', true); +include('xs_include.php'); + +$template->assign_block_vars('nav_left',array('ITEM' => '» ' . $lang['XS_CONFIGURATION'] . '')); + +$lang['XS_CONFIG_UPDATED_EXPLAIN'] = str_replace('{URL}', append_sid('xs_config.php'), $lang['XS_CONFIG_UPDATED_EXPLAIN']); +$lang['XS_CONFIG_TITLE'] = str_replace('{VERSION}', $template->xs_versiontxt, $lang['XS_CONFIG_TITLE']); +$lang['XS_CONFIG_WARNING_EXPLAIN'] = str_replace('{URL}', append_sid('xs_chmod.php'), $lang['XS_CONFIG_WARNING_EXPLAIN']); +$lang['XS_CONFIG_BACK'] = str_replace('{URL}', append_sid('xs_config.php'), $lang['XS_CONFIG_BACK']); + +// +// Updating configuration +// +if(isset($_POST['submit']) && !defined('DEMO_MODE')) +{ + $vars = array('xs_use_cache', 'xs_auto_compile', 'xs_auto_recompile', 'xs_php', 'xs_add_comments', 'xs_shownav'); + // checking navigation config + $shownav = 0; + for($i=0; $iassign_block_vars('left_refresh', array( + 'ACTION' => append_sid('index.php?pane=left') + )); + } + $_POST['xs_shownav'] = $shownav; + // checking submitted data + $update_time = false; + foreach($vars as $var) + { + if (!isset($_POST[$var])) continue; + + $new[$var] = trim($_POST[$var]); + if(($var == 'xs_auto_recompile') && !$new['xs_auto_compile']) + { + $new[$var] = 0; + } + if($bb_cfg[$var] !== $new[$var]) + { + bb_update_config(array($var => $new[$var])); + $bb_cfg[$var] = $new[$var]; + } + } + if($update_time) + { + $bb_cfg['xs_template_time'] = time() + 10; // set time 10 seconds in future in case if some tpl file would be compiled right now with current settings + bb_update_config(array('xs_template_time' => $bb_cfg['xs_template_time'])); + } + $template->assign_block_vars('switch_updated', array()); + $template->load_config($template->root, false); +} + +$template->assign_vars(array( + 'XS_USE_CACHE_0' => $bb_cfg['xs_use_cache'] ? '' : ' checked="checked"', + 'XS_USE_CACHE_1' => $bb_cfg['xs_use_cache'] ? ' checked="checked"' : '', + 'XS_AUTO_COMPILE_0' => $bb_cfg['xs_auto_compile'] ? '' : ' checked="checked"', + 'XS_AUTO_COMPILE_1' => $bb_cfg['xs_auto_compile'] ? ' checked="checked"' : '', + 'XS_AUTO_RECOMPILE_0' => $bb_cfg['xs_auto_recompile'] ? '' : ' checked="checked"', + 'XS_AUTO_RECOMPILE_1' => $bb_cfg['xs_auto_recompile'] ? ' checked="checked"' : '', + 'XS_PHP' => htmlspecialchars($bb_cfg['xs_php']), + 'XS_ADD_COMMENTS_0' => $bb_cfg['xs_add_comments'] ? '' : ' checked="checked"', + 'XS_ADD_COMMENTS_1' => $bb_cfg['xs_add_comments'] ? ' checked="checked"' : '', + 'FORM_ACTION' => append_sid('xs_config.php'), + )); + +for($i=0; $iassign_block_vars('shownav', array( + 'NUM' => $i, + 'LABEL' => $lang['XS_CONFIG_SHOWNAV'][$i], + 'CHECKED' => (($bb_cfg['xs_shownav'] & $num) > 0) ? 'checked="checked"' : '' + )); + } +} + +// test cache +$tpl_filename = $template->make_filename('_xs_test.tpl'); +$cache_filename = $template->make_filename_cache($tpl_filename); +$str = ''; +if(!xs_check_cache($cache_filename)) +{ + $template->assign_block_vars('switch_xs_warning', array()); +} +@unlink($cache_filename); +$debug_data = $str; +$template->assign_vars(array( + 'XS_DEBUG_HDR1' => sprintf($lang['XS_CHECK_HDR'], '_xs_test.tpl'), + 'XS_DEBUG_FILENAME1' => $tpl_filename, + 'XS_DEBUG_FILENAME2' => $cache_filename, + 'XS_DEBUG_DATA' => $debug_data, + )); + +$template->set_filenames(array('body' => XS_TPL_PATH . 'config.tpl')); +$template->pparse('body'); +xs_exit(); \ No newline at end of file diff --git a/upload/admin/xs_frameset.php b/upload/admin/xs_frameset.php new file mode 100644 index 000000000..1d7731011 --- /dev/null +++ b/upload/admin/xs_frameset.php @@ -0,0 +1,95 @@ +xs_version) || $template->xs_version !== 8) +{ + message_die(GENERAL_ERROR, isset($lang['XS_ERROR_NOT_INSTALLED']) ? $lang['XS_ERROR_NOT_INSTALLED'] : 'eXtreme Styles mod is not installed. You forgot to upload includes/template.php'); +} + +define('IN_XS', true); +define('NO_XS_HEADER', true); +include('xs_include.php'); + +$action = isset($_GET['action']) ? $_GET['action'] : ''; +$get_data = array(); +foreach($_GET as $var => $value) +{ + if($var !== 'action' && $var !== 'sid') + { + $get_data[] = $var . '=' . urlencode(stripslashes($value)); + } +} + +// check for style download command +if(isset($_POST['action']) && $_POST['action'] === 'web') +{ + $action = 'import'; + $get_data[] = 'get_remote=' . urlencode(stripslashes($_POST['source'])); + if(isset($_POST['return'])) + { + $get_data[] = 'return=' . urlencode(stripslashes($_POST['return'])); + } +} + +$get_data = count($get_data) ? 'php?' . implode('&', $get_data) : 'php'; + +$content_url = array( + 'config' => append_sid('xs_config.'.$get_data), + 'install' => append_sid('xs_install.'.$get_data), + 'uninstall' => append_sid('xs_uninstall.'.$get_data), + 'default' => append_sid('xs_styles.'.$get_data), + 'cache' => append_sid('xs_cache.'.$get_data), + 'import' => append_sid('xs_import.'.$get_data), + 'export' => append_sid('xs_export.'.$get_data), + 'clone' => append_sid('xs_clone.'.$get_data), + 'download' => append_sid('xs_download.'.$get_data), + 'edittpl' => append_sid('xs_edit.'.$get_data), + 'editdb' => append_sid('xs_edit_data.'.$get_data), + 'exportdb' => append_sid('xs_export_data.'.$get_data), + 'updates' => append_sid('xs_update.'.$get_data), + 'portal' => append_sid('xs_portal.'.$get_data), + 'style_config' => append_sid('xs_style_config.'.$get_data), + ); + +if(isset($content_url[$action])) +{ + $content = $content_url[$action]; +} +else +{ + $content = append_sid('xs_index.'.$get_data); +} + +$template->set_filenames(array('body' => XS_TPL_PATH . 'frameset.tpl')); +$template->assign_vars(array( + 'FRAME_TOP' => append_sid('xs_frame_top.php'), + 'FRAME_MAIN' => $content, + )); + +$template->pparse('body'); +xs_exit(); \ No newline at end of file diff --git a/upload/admin/xs_include.php b/upload/admin/xs_include.php new file mode 100644 index 000000000..9f25df27f --- /dev/null +++ b/upload/admin/xs_include.php @@ -0,0 +1,331 @@ + 0 && isset($xs_shownav_action[$i])) + { + $module[$module_name][$lang['XS_CONFIG_SHOWNAV'][$i]] = 'xs_frameset.php'.'?action=' . $xs_shownav_action[$i]; + } + } + // add menu for style configuration + foreach($bb_cfg as $var => $value) + { + if(substr($var, 0, 9) === 'xs_style_') + { + $str = substr($var, 9); + $module['Template_Config'][$str] = 'xs_frameset.php'.'?action=style_config&tpl='.urlencode($str); + } + } +} + + +if(!empty($setmodules)) +{ + if(@function_exists('jr_admin_get_module_list')) + { + $tmp_mod = $module; + global $module; + $module = $tmp_mod; + xs_admin_override(true); + } + return; +} + +// +// Global defines for eXtreme Styles mod administration panel +// +define('STYLE_HEADER_START', 'xs_style_01'); +define('STYLE_HEADER_END', ''); +define('STYLE_HEADER_VERSION', '1'); +define('STYLE_EXTENSION', '.style'); +define('XS_MAX_ITEMS_PER_STYLE', 32); +define('XS_FTP_LOCAL', 'no_ftp'); +define('XS_UPDATE_STYLE', 1); +define('XS_UPDATE_MOD', 2); +define('XS_UPDATE_PHPBB', 3); +define('XS_TPL_PATH', TEMPLATES_DIR .'xs_mod/tpl/'); +define('XS_BACKUP_PREFIX', 'backup.'); +define('XS_BACKUP_EXT', '.backup'); +define('XS_MAX_TIMEOUT', 600); // maximum timeout for downloads/import/installation + +$xs_row_class = array('row1', 'row2'); + +$template_dir = 'templates/'; + +$template->assign_vars(array( + 'XS_PATH' => TEMPLATES_DIR .'xs_mod/', + 'XS_UL' => '', + 'XS_UL2' => '
', + 'XS_LI' => '', + 'XS_LI2' => '', + 'S_HIDDEN_FIELDS' => '', + )); + +if(!defined('NO_XS_HEADER')) +{ + $template->set_filenames(array( + 'xs_header' => XS_TPL_PATH . 'xs_header.tpl', + 'xs_footer' => XS_TPL_PATH . 'xs_footer.tpl', + )); + $template->preparse = 'xs_header'; + $template->postparse = 'xs_footer'; + $template->assign_block_vars('nav_left',array('ITEM' => '' . $lang['XS_MENU'] . '')); +} + +// check if cache is writable +function xs_check_cache($filename) +{ + // check if filename is valid + global $str, $template, $lang; + if(substr($filename, 0, strlen($template->cachedir)) !== $template->cachedir) + { + $str .= $lang['XS_CHECK_FILENAME'] . "
\n"; + return false; + } + else + { + // try to open file + $file = @fopen($filename, 'w'); + if(!$file) + { + $str .= sprintf($lang['XS_CHECK_OPENFILE1'], $filename) . "
\n"; + // try to create directories + $dir = substr($filename, strlen($template->cachedir), strlen($filename)); + $dirs = explode('/', $dir); + $path = $template->cachedir; + @umask(0); + if(!@is_dir($path)) + { + $str .= sprintf($lang['XS_CHECK_NODIR'], $path) . "
\n"; + if(!@mkdir($path)) + { + $str .= sprintf($lang['XS_CHECK_NODIR2'], $path) . "
\n"; + return false; + } + else + { + $str .= sprintf($lang['XS_CHECK_CREATEDDIR'], $path) . "
\n"; + @chmod($path, 0777); + } + } + else + { + $str .= sprintf($lang['XS_CHECK_DIR'] , $path) . "
\n"; + } + if(count($dirs) > 0) + for($i=0; $i0) + { + $path .= '/'; + } + $path .= $dirs[$i]; + if(!@is_dir($path)) + { + $str .= sprintf($lang['XS_CHECK_NODIR'], $path) . "
\n"; + if(!@mkdir($path)) + { + $str .= sprintf($lang['XS_CHECK_NODIR2'], $path) . "
\n"; + return false; + } + else + { + $str .= sprintf($lang['XS_CHECK_CREATEDDIR'], $path) . "
\n"; + @chmod($path, 0777); + } + } + else + { + $str .= sprintf($lang['XS_CHECK_DIR'] , $path) . "
\n"; + } + } + // try to open file again after directories were created + $file = @fopen($filename, 'w'); + } + if(!$file) + { + $str .= sprintf($lang['XS_CHECK_OPENFILE2'], $filename) . "
\n"; + return false; + } + $str .= sprintf($lang['XS_CHECK_OK'], $filename) . "
\n"; + fputs($file, ' '); + fclose($file); + @chmod($filename, 0777); + return true; + } +} + +// show error and exit +function xs_error($error, $line = 0, $file = '') +{ + global $template, $lang; + if($line || $file) + { + $error = basename($file) . '(' . $line . '): ' . $error; + } + $template->set_filenames(array('errormsg' => XS_TPL_PATH . 'message.tpl')); + $template->assign_vars(array( + 'MESSAGE_TITLE' => $lang['ERROR'], + 'MESSAGE_TEXT' => $error + )); + $template->pparse('errormsg'); + xs_exit(); +} + +// show message and exit +function xs_message($title, $message) +{ + global $template; + $template->set_filenames(array('msg' => XS_TPL_PATH . 'message.tpl')); + $template->assign_vars(array( + 'MESSAGE_TITLE' => $title, + 'MESSAGE_TEXT' => $message + )); + $template->pparse('msg'); + xs_exit(); +} + +// strip slashes for sql +function xs_sql($sql, $strip = false) +{ + if($strip) + { + $sql = stripslashes($sql); + } + return str_replace('\\\'', '\'\'', addslashes($sql)); +} + +// clean template name +function xs_tpl_name($name) +{ + return str_replace(array('\\', '/', "'", '"'), array('','','',''), $name); +} + +// close database and maybe do some other stuff +function xs_exit() +{ + require(PAGE_FOOTER); +} + +// check directory name/filename +function xs_fix_dir($dir) +{ + $dir = str_replace('\\', '/', $dir); + $dir = str_replace('../', './', $dir); + while(strlen($dir > 1) && substr($dir, strlen($dir) - 2) === '..') + { + $dir = substr($dir, 0, strlen($dir) - 1); + } + return $dir; +} \ No newline at end of file diff --git a/upload/admin/xs_index.php b/upload/admin/xs_index.php new file mode 100644 index 000000000..67ea449b9 --- /dev/null +++ b/upload/admin/xs_index.php @@ -0,0 +1,61 @@ +xs_version) || $template->xs_version !== 8) +{ + message_die(GENERAL_ERROR, isset($lang['XS_ERROR_NOT_INSTALLED']) ? $lang['XS_ERROR_NOT_INSTALLED'] : 'eXtreme Styles mod is not installed. You forgot to upload includes/template.php'); +} + +define('IN_XS', true); +include('xs_include.php'); + +if(isset($_GET['showwarning'])) +{ + $msg = str_replace('{URL}', append_sid('xs_index.php'), $lang['XS_MAIN_COMMENT3']); + xs_message($lang['INFORMATION'], $msg); +} + +$template->assign_vars(array( + 'U_CONFIG' => append_sid('xs_config.php'), + 'U_DEFAULT_STYLE' => append_sid('xs_styles.php'), + 'U_MANAGE_CACHE' => append_sid('xs_cache.php'), + 'U_IMPORT_STYLES' => append_sid('xs_import.php'), + 'U_EXPORT_STYLES' => append_sid('xs_export.php'), + 'U_CLONE_STYLE' => append_sid('xs_clone.php'), + 'U_DOWNLOAD_STYLES' => append_sid('xs_download.php'), + 'U_INSTALL_STYLES' => append_sid('xs_install.php'), + 'U_UNINSTALL_STYLES' => append_sid('xs_uninstall.php'), + 'U_EDIT_STYLES' => append_sid('xs_edit.php'), + 'U_EDIT_STYLES_DATA' => append_sid('xs_edit_data.php'), + 'U_EXPORT_DATA' => append_sid('xs_export_data.php'), + 'U_UPDATES' => append_sid('xs_update.php'), + )); + +$template->set_filenames(array('body' => XS_TPL_PATH . 'index.tpl')); +$template->pparse('body'); +xs_exit(); \ No newline at end of file diff --git a/upload/ajax.php b/upload/ajax.php new file mode 100644 index 000000000..3beee530d --- /dev/null +++ b/upload/ajax.php @@ -0,0 +1,310 @@ +init(); + +// Handle "board disabled via ON/OFF trigger" +if (file_exists(BB_DISABLED)) +{ + $ajax->ajax_die($bb_cfg['board_disabled_msg']); +} + +// Load actions required modules +switch ($ajax->action) +{ + case 'view_post': + case 'view_message': + require(INC_DIR .'bbcode.php'); + break; + + case 'view_torrent': + case 'mod_action': + case 'change_tor_status': + require(INC_DIR .'functions_torrent.php'); + break; + + case 'change_torrent': + require(BB_ROOT .'attach_mod/attachment_mod.php'); + require(INC_DIR .'functions_torrent.php'); + break; + + case 'user_register': + require(INC_DIR .'functions_validate.php'); + break; +} + +// position in $ajax->valid_actions['xxx'] +define('AJAX_AUTH', 0); // 'guest', 'user', 'mod', 'admin' + +$user->session_start(); +$ajax->exec(); + +// +// Ajax +// +class ajax_common +{ + var $request = array(); + var $response = array(); + + var $valid_actions = array( + // ACTION NAME AJAX_AUTH + 'edit_user_profile' => array('admin'), + + 'change_torrent' => array('mod'), + 'change_tor_status' => array('mod'), + 'mod_action' => array('mod'), + + 'view_post' => array('guest'), + 'view_message' => array('guest'), + 'view_torrent' => array('guest'), + 'user_register' => array('guest'), + ); + + var $action = null; + + /** + * Constructor + */ + function ajax_common () + { + ob_start(array(&$this, 'ob_handler')); + header('Content-Type: text/plain'); + } + + /** + * Perform action + */ + function exec () + { + global $lang; + + // Exit if we already have errors + if (!empty($this->response['error_code'])) + { + $this->send(); + } + + // Check that requested action is valid + $action = $this->action; + + if (!$action || !is_string($action)) + { + $this->ajax_die('no action specified'); + } + else if (!$action_params =& $this->valid_actions[$action]) + { + $this->ajax_die('invalid action: '. $action); + } + + // Auth check + switch ($action_params[AJAX_AUTH]) + { + // GUEST + case 'guest': + break; + + // USER + case 'user': + if (IS_GUEST) + { + $this->ajax_die($lang['NEED_TO_LOGIN_FIRST']); + } + break; + + // MOD + case 'mod': + if (!(IS_MOD || IS_ADMIN)) + { + $this->ajax_die($lang['ONLY_FOR_MOD']); + } + $this->check_admin_session(); + break; + + // ADMIN + case 'admin': + if (!IS_ADMIN) + { + $this->ajax_die($lang['ONLY_FOR_ADMIN']); + } + $this->check_admin_session(); + break; + + default: + trigger_error("invalid auth type for $action", E_USER_ERROR); + } + + // Run action + $this->$action(); + + // Send output + $this->send(); + } + + /** + * Exit on error + */ + function ajax_die ($error_msg, $error_code = E_AJAX_GENERAL_ERROR) + { + $this->response['error_code'] = $error_code; + $this->response['error_msg'] = $error_msg; + + $this->send(); + } + + /** + * Initialization + */ + function init () + { + $this->request = $_POST; + + $this->action =& $this->request['action']; + } + + /** + * Send data + */ + function send () + { + $this->response['action'] = $this->action; + + if (DBG_USER && SQL_DEBUG && !empty($_COOKIE['sql_log'])) + { + $this->response['sql_log'] = get_sql_log(); + } + + // sending output will be handled by $this->ob_handler() + exit(); + } + + /** + * OB Handler + */ + function ob_handler ($contents) + { + if (DBG_USER) + { + if ($contents) + { + $this->response['raw_output'] = $contents; + } + } + + + $response_js = bb_json_encode($this->response); + + if (GZIP_OUTPUT_ALLOWED && !defined('NO_GZIP')) + { + if (UA_GZIP_SUPPORTED && strlen($response_js) > 2000) + { + header('Content-Encoding: gzip'); + $response_js = gzencode($response_js, 1); + } + } + + return $response_js; + } + + /** + * Admin session + */ + function check_admin_session () + { + global $user; + + if (!$user->data['session_admin']) + { + if (empty($this->request['user_password'])) + { + $this->prompt_for_password(); + } + else + { + $login_args = array( + 'login_username' => $user->data['username'], + 'login_password' => $_POST['user_password'], + ); + if (!$user->login($login_args, true)) + { + $this->ajax_die('Wrong password'); + } + } + } + } + + /** + * Prompt for password + */ + function prompt_for_password () + { + $this->response['prompt_password'] = 1; + $this->send(); + } + + /** + * Verify mod rights + */ + function verify_mod_rights ($forum_id) + { + global $userdata, $lang; + + $is_auth = auth(AUTH_MOD, $forum_id, $userdata); + + if (!$is_auth['auth_mod']) + { + $this->ajax_die($lang['ONLY_FOR_MOD']); + } + } + + function edit_user_profile () + { + require(AJAX_DIR .'edit_user_profile.php'); + } + + function view_post () + { + require(AJAX_DIR .'view_post.php'); + } + + function view_message () + { + global $lang; + + $message = (string) $this->request['message']; + if(!trim($message)) $this->ajax_die($lang['EMPTY_MESSAGE']); + $message = bbcode2html(DB()->escape($message)); + $message = str_replace('\n', '
', $message); + $this->response['html'] = $message; + } + + function change_tor_status () + { + require(AJAX_DIR .'change_tor_status.php'); + } + + function change_torrent () + { + require(AJAX_DIR .'change_torrent.php'); + } + + function view_torrent () + { + require(AJAX_DIR .'view_torrent.php'); + } + + function user_register() + { + require(AJAX_DIR .'user_register.php'); + } + + function mod_action() + { + require(AJAX_DIR .'mod_action.php'); + } + +} diff --git a/upload/ajax/change_tor_status.php b/upload/ajax/change_tor_status.php new file mode 100644 index 000000000..e0d5f9057 --- /dev/null +++ b/upload/ajax/change_tor_status.php @@ -0,0 +1,77 @@ +request['attach_id'])) +{ + $this->ajax_die('empty attach_id'); +} +if (!isset($this->request['status'])) +{ + $this->ajax_die('empty tor_status'); +} +$attach_id = (int) $this->request['attach_id']; +$new_status = (int) $this->request['status']; + +// Валидность статуса +if (!isset($lang['tor_status'][$new_status])) +{ + $this->ajax_die("Такого статуса не существует: $new_status"); +} + +$tor = DB()->fetch_row(" + SELECT + tor.forum_id, tor.topic_id, tor.tor_status, tor.checked_time, tor.checked_user_id, f.cat_id + FROM ". BB_BT_TORRENTS ." tor + INNER JOIN ". BB_FORUMS ." f ON(f.forum_id = tor.forum_id) + WHERE tor.attach_id = $attach_id + LIMIT 1 +"); +if (!$tor) $this->ajax_die('torrent not found'); + +// Тот же статус +if ($tor['tor_status'] == $new_status) +{ + $this->ajax_die('Раздача имеет тот же статус'); +} +// Запрет на изменение/присвоение CH-статуса модератором +if ($new_status == TOR_CLOSED_CPHOLD && !(IS_ADMIN || IS_CP_HOLDER)) +{ + $this->ajax_die('Изменение статуса невозможно'); +} + +// Права на изменение статуса +if ($tor['tor_status'] == TOR_CLOSED_CPHOLD) +{ + if (!(IS_ADMIN || IS_CP_HOLDER)) + { + $this->verify_mod_rights($tor['forum_id']); + } + DB()->query("UPDATE ". BB_TOPICS ." SET topic_status = ". TOPIC_UNLOCKED ." WHERE topic_id = {$tor['topic_id']} LIMIT 1"); + $new_status = TOR_NOT_APPROVED; +} +else +{ + $this->verify_mod_rights($tor['forum_id']); +} + +// Подтверждение изменения статуса, выставленного другим модератором +if ($tor['tor_status'] != TOR_NOT_APPROVED && $tor['checked_user_id'] != $userdata['user_id'] && $tor['checked_time'] + 2*3600 > TIMENOW) +{ + if (empty($this->request['confirmed'])) + { + $msg = "Раздача имеет статус: {$lang['tor_status'][$tor['tor_status']]}\n\n"; + $msg .= ($username = get_username($tor['checked_user_id'])) ? "Статус изменен: ". html_entity_decode($username) .", ". delta_time($tor['checked_time']) ." назад\n\n" : ""; + $msg .= "Продолжить?"; + $this->prompt_for_confirm($msg); + } +} + +change_tor_status($attach_id, $new_status); + +$this->response['attach_id'] = $attach_id; +$this->response['status'] = $bb_cfg['tor_icons'][$new_status] .' '. $lang['tor_status'][$new_status]; \ No newline at end of file diff --git a/upload/ajax/change_torrent.php b/upload/ajax/change_torrent.php new file mode 100644 index 000000000..1dc9623b9 --- /dev/null +++ b/upload/ajax/change_torrent.php @@ -0,0 +1,87 @@ +request['attach_id'])) +{ + $this->ajax_die('empty attach_id'); +} +if (!isset($this->request['type'])) +{ + $this->ajax_die('type'); +} +$attach_id = (int) $this->request['attach_id']; +$type = (string) $this->request['type']; + +$torrent = DB()->fetch_row(" + SELECT + a.post_id, d.physical_filename, d.extension, d.tracker_status, + t.topic_first_post_id, + p.poster_id, p.topic_id, p.forum_id, + f.allow_reg_tracker + FROM + ". BB_ATTACHMENTS ." a, + ". BB_ATTACHMENTS_DESC ." d, + ". BB_POSTS ." p, + ". BB_TOPICS ." t, + ". BB_FORUMS ." f + WHERE + a.attach_id = $attach_id + AND d.attach_id = $attach_id + AND p.post_id = a.post_id + AND t.topic_id = p.topic_id + AND f.forum_id = p.forum_id + LIMIT 1 + "); + +if (!$torrent) $this->ajax_die('Invalid attach_id'); +$title = $url = ''; +switch($type) +{ case 'set_gold'; + case 'set_silver'; + case 'unset_silver_gold'; + if ($type == 'set_silver') + { + $tor_type = TOR_TYPE_SILVER; + } + elseif ($type == 'set_gold') + { + $tor_type = TOR_TYPE_GOLD; + } + else + { + $tor_type = 0; + } + change_tor_type($attach_id, $tor_type); + $title = 'Тип торрента изменён'; + $url = make_url(TOPIC_URL . $torrent['topic_id']); + break; + + case 'reg'; + tracker_register($attach_id); + $url = (TOPIC_URL . $torrent['topic_id']); + break; + + case 'unreg'; + tracker_unregister($attach_id); + $url = (TOPIC_URL . $torrent['topic_id']); + break; + + case 'del_torrent'; + delete_torrent($attach_id); + $url = make_url(TOPIC_URL . $torrent['topic_id']); + break; + + case 'del_torrent_move_topic'; + delete_torrent($attach_id); + $url = make_url("modcp.php?t={$torrent['topic_id']}&mode=move&sid={$userdata['session_id']}"); + break; } + + + +$this->response['url'] = $url; +$this->response['title'] = $title; \ No newline at end of file diff --git a/upload/ajax/edit_user_profile.php b/upload/ajax/edit_user_profile.php new file mode 100644 index 000000000..a04d126e9 --- /dev/null +++ b/upload/ajax/edit_user_profile.php @@ -0,0 +1,76 @@ +request['user_id']) OR !$profiledata = get_userdata($user_id)) +{ + $this->ajax_die('invalid user_id'); +} +if (!$field = (string) $this->request['field']) +{ + $this->ajax_die('invalid profile field'); +} + +$table = BB_USERS; +$value = (string) $this->request['value']; + +switch ($field) +{ + case 'user_regdate': + case 'user_lastvisit': + $tz = TIMENOW + (3600 * $bb_cfg['board_timezone']); + if (($value = strtotime($value, $tz)) < $bb_cfg['board_startdate'] OR $value > TIMENOW) + { + $this->ajax_die('invalid date: '. $this->request['value']); + } + $this->response['new_value'] = bb_date($value); + break; + + case 'ignore_srv_load': + $value = ($this->request['value']) ? 0 : 1; + $this->response['new_value'] = ($profiledata['user_level'] != USER || $value) ? $lang['NO'] : $lang['YES']; + break; + + case 'u_up_total': + case 'u_down_total': + case 'u_up_release': + case 'u_up_bonus': + if (!IS_SUPER_ADMIN) + { + $this->ajax_die($lang['ONLY_FOR_SUPER_ADMIN']); + } + + $table = BB_BT_USERS; + $value = (float) str_replace(',', '.', $this->request['value']); + + foreach (array('KB'=>1,'MB'=>2,'GB'=>3,'TB'=>4) as $s => $m) + { + if (strpos($this->request['value'], $s) !== false) + { + $value *= pow(1024, $m); + break; + } + } + $value = sprintf('%.0f', $value); + $this->response['new_value'] = humn_size($value, null, null, ' '); + + if (!$btu = get_bt_userdata($user_id)) + { + require(INC_DIR .'functions_torrent.php'); + generate_passkey($user_id, true); + $btu = get_bt_userdata($user_id); + } + $btu[$field] = $value; + $this->response['update_ids']['u_ratio'] = (string) get_bt_ratio($btu); + break; + + default: + $this->ajax_die("invalid profile field: $field"); +} + +$value_sql = DB()->escape($value, true); +DB()->query("UPDATE $table SET $field = $value_sql WHERE user_id = $user_id LIMIT 1"); + +$this->response['edit_id'] = $this->request['edit_id']; \ No newline at end of file diff --git a/upload/ajax/html/jumpbox_guest.html b/upload/ajax/html/jumpbox_guest.html new file mode 100644 index 000000000..2050de135 --- /dev/null +++ b/upload/ajax/html/jumpbox_guest.html @@ -0,0 +1,9 @@ + + diff --git a/upload/ajax/html/jumpbox_user.html b/upload/ajax/html/jumpbox_user.html new file mode 100644 index 000000000..2050de135 --- /dev/null +++ b/upload/ajax/html/jumpbox_user.html @@ -0,0 +1,9 @@ + + diff --git a/upload/ajax/mod_action.php b/upload/ajax/mod_action.php new file mode 100644 index 000000000..4048d5fab --- /dev/null +++ b/upload/ajax/mod_action.php @@ -0,0 +1,54 @@ +request['mode']; + +switch ($mode) +{ + case 'tor_status': + $topics = (string) $this->request['topic_ids']; + $status = (int) $this->request['status']; + + // Валидность статуса + if (!isset($lang['tor_status'][$status])) + { + $this->ajax_die("Такого статуса не существует: $new_status"); + } + + $topic_ids = DB()->fetch_rowset("SELECT attach_id FROM ". BB_BT_TORRENTS ." WHERE topic_id IN($topics)", 'attach_id'); + + foreach($topic_ids as $attach_id) + { + change_tor_status($attach_id, $status); + } + $this->response['status'] = $bb_cfg['tor_icons'][$status]; + $this->response['topics'] = explode(',', $topics); + break; + + case 'edit_topic_title': + $topic_id = (int) $this->request['topic_id']; + $topic_title = (string) $this->request['topic_title']; + $new_title = clean_topic_title($topic_title); + + if (!$topic_id) $this->ajax_die('invalid topic_id (empty)'); + if ($new_title == '') $this->ajax_die('Вы должны указать заголовок сообщения'); + + if (!$t_data = DB()->fetch_row("SELECT forum_id FROM ". BB_TOPICS ." WHERE topic_id = $topic_id LIMIT 1")) + { + $this->ajax_die('invalid topic_id (not found in db)'); + } + $this->verify_mod_rights($t_data['forum_id']); + + $topic_title_sql = DB()->escape($new_title); + + DB()->query("UPDATE ". BB_TOPICS ." SET topic_title = '$topic_title_sql' WHERE topic_id = $topic_id LIMIT 1"); + + $this->response['topic_id'] = $topic_id; + $this->response['topic_title'] = $new_title; + break; +} diff --git a/upload/ajax/user_register.php b/upload/ajax/user_register.php new file mode 100644 index 000000000..17c84ad2d --- /dev/null +++ b/upload/ajax/user_register.php @@ -0,0 +1,58 @@ +request['mode']; + +$html = ''; +switch($mode) +{ + case 'check_name': + $username = clean_username($this->request['username']); + + if (empty($username)) + { + $html = ' Вы должны выбрать имя'; + } + else if($err = validate_username($username)) + { + $html = ' '. $err .''; + } + break; + case 'check_email': + $email = (string) $this->request['email']; + + if (empty($email)) + { + $html = ' Вы должны указать e-mail'; + } + else if($err = validate_email($email)) + { + $html = ' '. $err .''; + } + break; + case 'check_pass': + $pass = (string) $this->request['pass']; + $pass_confirm = (string) $this->request['pass_confirm']; + if (empty($pass) || empty($pass_confirm)) + { + $html = ' Поля для ввода пароля не должны быть пустыми!'; + } + else + { + if ($pass != $pass_confirm) + { + $html = ' Введённые пароли не совпадают'; + } + else + { + $html = ' Пароли совпадают, можете продолжить регистрацию.'; + } + } + break; +} + +$this->response['html'] = $html; +$this->response['mode'] = $mode; \ No newline at end of file diff --git a/upload/ajax/view_post.php b/upload/ajax/view_post.php new file mode 100644 index 000000000..7e4ff07bc --- /dev/null +++ b/upload/ajax/view_post.php @@ -0,0 +1,54 @@ +request['post_id']; +$topic_id = (int) @$this->request['topic_id']; + +if (!$post_id) +{ + $post_id = DB()->fetch_row("SELECT topic_first_post_id FROM ". BB_TOPICS ." WHERE topic_id = $topic_id", 'topic_first_post_id'); +} + +$sql = " + SELECT + p.*, + h.post_html, IF(h.post_html IS NULL, pt.post_text, NULL) AS post_text, + pt.post_subject, pt.bbcode_uid, + f.auth_read + FROM ". BB_POSTS ." p + INNER JOIN ". BB_POSTS_TEXT ." pt ON(pt.post_id = p.post_id) + LEFT JOIN ". BB_POSTS_HTML ." h ON(h.post_id = pt.post_id) + INNER JOIN ". BB_FORUMS ." f ON(f.forum_id = p.forum_id) + WHERE + p.post_id = $post_id + LIMIT 1 +"; + +if (!$post_data = DB()->fetch_row($sql)) +{ + $this->ajax_die($lang['TOPIC_POST_NOT_EXIST']); +} + +// Auth check +if ($post_data['auth_read'] == AUTH_REG) +{ + if (IS_GUEST) + { + $this->ajax_die($lang['NEED_TO_LOGIN_FIRST']); + } +} +else if ($post_data['auth_read'] != AUTH_ALL) +{ + $is_auth = auth(AUTH_READ, $post_data['forum_id'], $user->data, $post_data); + if (!$is_auth['auth_read']) + { + $this->ajax_die($lang['TOPIC_POST_NOT_EXIST']); + } +} + +$this->response['post_id'] = $post_id; +$this->response['topic_id'] = $topic_id; +$this->response['post_html'] = get_parsed_post($post_data); \ No newline at end of file diff --git a/upload/ajax/view_torrent.php b/upload/ajax/view_torrent.php new file mode 100644 index 000000000..60a68317c --- /dev/null +++ b/upload/ajax/view_torrent.php @@ -0,0 +1,170 @@ +request['attach_id'])) +{ + $this->ajax_die('empty attach_id'); +} +$attach_id = (int) $this->request['attach_id']; + +$torrent = DB()->fetch_row("SELECT at.attach_id, at.physical_filename + FROM ". BB_ATTACHMENTS_DESC ." at + WHERE at.attach_id = $attach_id + LIMIT 1"); +if(!$torrent) $this->ajax_die('empty attach_id'); +$filename = get_attachments_dir() .'/'. $torrent['physical_filename']; + +if (($file_contents = @file_get_contents($filename)) === false) +{ + if(IS_AM) + { + $this->ajax_die('torrent not found on disk: '. htmlCHR($filename)); + } + else + { + $this->ajax_die('файл временно не доступен'); + } + +} + +// Построение списка +$tor_filelist = build_tor_filelist($file_contents); + +function build_tor_filelist ($file_contents) +{ + if (!$tor = bdecode($file_contents)) + { + return 'invalid torrent file'; + } + + $torrent = new torrent($tor); + + return $torrent->get_filelist(); +} + +class torrent +{ + var $tor_decoded = array(); + var $files_ary = array('/' => ''); + var $multiple = null; + var $root_dir = ''; + var $files_html = ''; + + function torrent ($decoded_file_contents) + { + $this->tor_decoded = $decoded_file_contents; + } + + function get_filelist () + { + $this->build_filelist_array(); + + if ($this->multiple) + { + if ($this->files_ary['/'] !== '') + { + $this->files_ary = array_merge($this->files_ary, $this->files_ary['/']); + unset($this->files_ary['/']); + } + $filelist = $this->build_filelist_html(); + return "
{$this->root_dir}
$filelist"; + } + else + { + return join('', $this->files_ary['/']); + } + } + + function build_filelist_array () + { + $info = $this->tor_decoded['info']; + + if (isset($info['name.utf-8'])) + { + $info['name'] =& $info['name.utf-8']; + } + + if (isset($info['files']) && is_array($info['files'])) + { + $this->root_dir = isset($info['name']) ? '../'. clean_tor_dirname($info['name']) : '...'; + $this->multiple = true; + + foreach ($info['files'] as $f) + { + if (isset($f['path.utf-8'])) + { + $f['path'] =& $f['path.utf-8']; + } + if (!isset($f['path']) || !is_array($f['path'])) + { + continue; + } + array_deep($f['path'], 'clean_tor_dirname'); + + $length = isset($f['length']) ? (int) $f['length'] : 0; + $subdir_count = count($f['path']) - 1; + + if ($subdir_count > 0) + { + $name = array_pop($f['path']); + $cur_files_ary =& $this->files_ary; + + for ($i=0,$j=1; $i < $subdir_count; $i++,$j++) + { + $subdir = $f['path'][$i]; + + if (!isset($cur_files_ary[$subdir])) + { + $cur_files_ary[$subdir] = array(); + } + $cur_files_ary =& $cur_files_ary[$subdir]; + + if ($j == $subdir_count) + { + if (is_string($cur_files_ary)) + { + $this->ajax_die('Error: cannot build filelist [string]'); + } + $cur_files_ary[] = $this->build_file_item($name, $length); + } + } + } + else + { + $name = $f['path'][0]; + $this->files_ary['/'][] = $this->build_file_item($name, $length); + } + } + } + else + { + $this->multiple = false; + $name = isset($info['name']) ? clean_tor_dirname($info['name']) : ''; + $length = isset($info['length']) ? (int) $info['length'] : 0; + + $this->files_ary['/'][] = $this->build_file_item($name, $length); + } + } + + function build_file_item ($name, $length) + { + return "$name $length"; + } + + function build_filelist_html () + { + global $html; + return $html->array2html($this->files_ary); + } +} + +function clean_tor_dirname ($dirname) +{ + return str_replace(array('[', ']', '<', '>', "'"), array('[', ']', '<', '>', '''), $dirname); +} + +$this->response['html'] = $tor_filelist; + diff --git a/upload/attach_mod/.htaccess b/upload/attach_mod/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/attach_mod/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/attach_mod/attachment_mod.php b/upload/attach_mod/attachment_mod.php new file mode 100644 index 000000000..d68b19806 --- /dev/null +++ b/upload/attach_mod/attachment_mod.php @@ -0,0 +1,115 @@ +sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query attachment information', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + $attach_config[$row['config_name']] = trim($row['config_value']); + } + + // We assign the original default board language here, because it gets overwritten later with the users default language + $attach_config['board_lang'] = trim($bb_cfg['default_lang']); + + return $attach_config; +} + +// Get Attachment Config +$attach_config = array(); + +if (!($attach_config = CACHE('bb_cache')->get('attach_config'))) +{ + $attach_config = get_config(); + CACHE('bb_cache')->set('attach_config', $attach_config, 86400); +} + +// Please do not change the include-order, it is valuable for proper execution. +// Functions for displaying Attachment Things +include(BB_ROOT .'attach_mod/displaying.php'); +// Posting Attachments Class (HAVE TO BE BEFORE PM) +include(BB_ROOT .'attach_mod/posting_attachments.php'); + +if (!intval($attach_config['allow_ftp_upload'])) +{ + $upload_dir = $attach_config['upload_dir']; +} +else +{ + $upload_dir = $attach_config['download_path']; +} \ No newline at end of file diff --git a/upload/attach_mod/displaying.php b/upload/attach_mod/displaying.php new file mode 100644 index 000000000..4b26d4111 --- /dev/null +++ b/upload/attach_mod/displaying.php @@ -0,0 +1,490 @@ +update('attach_extensions'); //get_extension_informations() + $extension_informations = get_extension_informations(); + } + $allowed_extensions = array(); + + for ($i = 0, $size = sizeof($extension_informations); $i < $size; $i++) + { + $extension = strtolower(trim($extension_informations[$i]['extension'])); + $allowed_extensions[] = $extension; + $display_categories[$extension] = intval($extension_informations[$i]['cat_id']); + $download_modes[$extension] = intval($extension_informations[$i]['download_mode']); + $upload_icons[$extension] = trim($extension_informations[$i]['upload_icon']); + } +} + +/** +* Writing Data into plain Template Vars +*/ +function init_display_template($template_var, $replacement, $filename = 'viewtopic_attach.tpl') +{ + global $template; + + // This function is adapted from the old template class + // I wish i had the functions from the 3.x one. :D (This class rocks, can't await to use it in Mods) + + // Handle Attachment Informations + if (!isset($template->uncompiled_code[$template_var]) && empty($template->uncompiled_code[$template_var])) + { + // If we don't have a file assigned to this handle, die. + if (!isset($template->files[$template_var])) + { + die("Template->loadfile(): No file specified for handle $template_var"); + } + + $filename_2 = $template->files[$template_var]; + + $str = implode('', @file($filename_2)); + if (empty($str)) + { + die("Template->loadfile(): File $filename_2 for handle $template_var is empty"); + } + + $template->uncompiled_code[$template_var] = $str; + } + + $complete_filename = $filename; + if (substr($complete_filename, 0, 1) != '/') + { + $complete_filename = $template->root . '/' . $complete_filename; + } + + if (!file_exists($complete_filename)) + { + die("Template->make_filename(): Error - file $complete_filename does not exist"); + } + + $content = implode('', file($complete_filename)); + if (empty($content)) + { + die('Template->loadfile(): File ' . $complete_filename . ' is empty'); + } + + // replace $replacement with uncompiled code in $filename + $template->uncompiled_code[$template_var] = str_replace($replacement, $content, $template->uncompiled_code[$template_var]); +} + +/** +* Display Attachments in Posts +*/ +function display_post_attachments($post_id, $switch_attachment) +{ + global $attach_config, $is_auth; + + if (intval($switch_attachment) == 0 || intval($attach_config['disable_mod'])) + { + return; + } + + if ($is_auth['auth_download'] && $is_auth['auth_view']) + { + display_attachments($post_id); + } + else + { + // Display Notice (attachment there but not having permissions to view it) + // Not included because this would mean template and language file changes (at this stage this is not a wise step. ;)) + } +} + +/** +* Initializes some templating variables for displaying Attachments in Posts +*/ +function init_display_post_attachments($switch_attachment) +{ + global $attach_config, $is_auth, $template, $lang, $postrow, $total_posts, $attachments, $forum_row, $t_data; + + if (empty($t_data) && !empty($forum_row)) + { + $switch_attachment = $forum_row['topic_attachment']; + } + + if (intval($switch_attachment) == 0 || intval($attach_config['disable_mod']) || (!($is_auth['auth_download'] && $is_auth['auth_view']))) + { + init_display_template('body', '{postrow.ATTACHMENTS}', 'viewtopic_attach_guest.tpl'); + return; + } + + $post_id_array = array(); + + for ($i = 0; $i < $total_posts; $i++) + { + if ($postrow[$i]['post_attachment'] == 1) + { + $post_id_array[] = (int) $postrow[$i]['post_id']; + } + } + + if (sizeof($post_id_array) == 0) + { + return; + } + + $rows = get_attachments_from_post($post_id_array); + $num_rows = sizeof($rows); + + if ($num_rows == 0) + { + return; + } + + @reset($attachments); + + for ($i = 0; $i < $num_rows; $i++) + { + $attachments['_' . $rows[$i]['post_id']][] = $rows[$i]; + //bt + if ($rows[$i]['tracker_status']) + { + if (defined('TORRENT_POST')) + { + message_die(GENERAL_ERROR, 'Multiple registered torrents in one topic

first torrent found in post_id = '. TORRENT_POST .'
current post_id = '. $rows[$i]['post_id'] .'

attachments info:
'. print_r($rows, TRUE) .'
'); + } + define('TORRENT_POST', $rows[$i]['post_id']); + } + //bt end + } + + init_display_template('body', '{postrow.ATTACHMENTS}'); + + init_complete_extensions_data(); + + $template->assign_vars(array( + 'L_POSTED_ATTACHMENTS' => $lang['POSTED_ATTACHMENTS'], + 'L_KILOBYTE' => $lang['KB']) + ); +} + +/** +* END ATTACHMENT DISPLAY IN POSTS +*/ + +/** +* Assign Variables and Definitions based on the fetched Attachments - internal +* used by all displaying functions, the Data was collected before, it's only dependend on the template used. :) +* before this function is usable, init_display_attachments have to be called for specific pages (pm, posting, review etc...) +*/ +function display_attachments($post_id) +{ + global $template, $upload_dir, $userdata, $allowed_extensions, $display_categories, $download_modes, $lang, $attachments, $upload_icons, $attach_config; + + $num_attachments = @sizeof($attachments['_' . $post_id]); + + if ($num_attachments == 0) + { + return; + } + + $template->assign_block_vars('postrow.attach', array()); + + for ($i = 0; $i < $num_attachments; $i++) + { + // Some basic things... + $filename = $upload_dir . '/' . basename($attachments['_' . $post_id][$i]['physical_filename']); + $thumbnail_filename = $upload_dir . '/' . THUMB_DIR . '/t_' . basename($attachments['_' . $post_id][$i]['physical_filename']); + + $upload_image = ''; + + if ($attach_config['upload_img'] && empty($upload_icons[$attachments['_' . $post_id][$i]['extension']])) + { + $upload_image = ''; + } + else if (trim($upload_icons[$attachments['_' . $post_id][$i]['extension']]) != '') + { + $upload_image = ''; + } + + $filesize = $attachments['_' . $post_id][$i]['filesize']; + $size_lang = ($filesize >= 1048576) ? $lang['MB'] : ( ($filesize >= 1024) ? $lang['KB'] : $lang['BYTES'] ); + if ($filesize >= 1048576) + { + $filesize = (round((round($filesize / 1048576 * 100) / 100), 2)); + } + else if ($filesize >= 1024) + { + $filesize = (round((round($filesize / 1024 * 100) / 100), 2)); + } + + $display_name = htmlspecialchars($attachments['_' . $post_id][$i]['real_filename']); + $comment = htmlspecialchars($attachments['_' . $post_id][$i]['comment']); + $comment = str_replace("\n", '
', $comment); + + $denied = false; + + // Admin is allowed to view forbidden Attachments, but the error-message is displayed too to inform the Admin + if (!in_array($attachments['_' . $post_id][$i]['extension'], $allowed_extensions)) + { + $denied = true; + + $template->assign_block_vars('postrow.attach.denyrow', array( + 'L_DENIED' => sprintf($lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachments['_' . $post_id][$i]['extension'])) + ); + } + + if (!$denied || IS_ADMIN) + { + // Some basic Template Vars + $template->assign_vars(array( + 'L_DESCRIPTION' => $lang['DESCRIPTION'], + 'L_DOWNLOAD' => $lang['DOWNLOAD'], + 'L_FILENAME' => $lang['FILE_NAME'], + 'L_FILESIZE' => $lang['FILESIZE']) + ); + + // define category + $image = FALSE; + $stream = FALSE; + $swf = FALSE; + $thumbnail = FALSE; + $link = FALSE; + + if (@intval($display_categories[$attachments['_' . $post_id][$i]['extension']]) == STREAM_CAT) + { + $stream = TRUE; + } + else if (@intval($display_categories[$attachments['_' . $post_id][$i]['extension']]) == SWF_CAT) + { + $swf = TRUE; + } + else if (@intval($display_categories[$attachments['_' . $post_id][$i]['extension']]) == IMAGE_CAT && intval($attach_config['img_display_inlined'])) + { + if (intval($attach_config['img_link_width']) != 0 || intval($attach_config['img_link_height']) != 0) + { + list($width, $height) = image_getdimension($filename); + + if ($width == 0 && $height == 0) + { + $image = TRUE; + } + else + { + if ($width <= intval($attach_config['img_link_width']) && $height <= intval($attach_config['img_link_height'])) + { + $image = TRUE; + } + } + } + else + { + $image = TRUE; + } + } + + if (@intval($display_categories[$attachments['_' . $post_id][$i]['extension']]) == IMAGE_CAT && $attachments['_' . $post_id][$i]['thumbnail'] == 1) + { + $thumbnail = TRUE; + $image = FALSE; + } + + if (!$image && !$stream && !$swf && !$thumbnail) + { + $link = TRUE; + } + + if ($image) + { + // Images + // NOTE: If you want to use the download.php everytime an image is displayed inlined, replace the + // Section between BEGIN and END with (Without the // of course): + // $img_source = append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id']); + // $download_link = TRUE; + // + // + if (intval($attach_config['allow_ftp_upload']) && trim($attach_config['download_path']) == '') + { + $img_source = append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id']); + $download_link = TRUE; + } + else + { + // Check if we can reach the file or if it is stored outside of the webroot + if ($attach_config['upload_dir'][0] == '/' || ( $attach_config['upload_dir'][0] != '/' && $attach_config['upload_dir'][1] == ':')) + { + $img_source = append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id']); + $download_link = TRUE; + } + else + { + // BEGIN + $img_source = $filename; + $download_link = FALSE; + // END + } + } + + $template->assign_block_vars('postrow.attach.cat_images', array( + 'DOWNLOAD_NAME' => $display_name, + 'S_UPLOAD_IMAGE' => $upload_image, + + 'IMG_SRC' => $img_source, + 'FILESIZE' => $filesize, + 'SIZE_VAR' => $size_lang, + 'COMMENT' => $comment, + )); + + // Directly Viewed Image ... update the download count + if (!$download_link) + { + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . ' + SET download_count = download_count + 1 + WHERE attach_id = ' . (int) $attachments['_' . $post_id][$i]['attach_id']; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t update attachment download count.', '', __LINE__, __FILE__, $sql); + } + } + } + + if ($thumbnail) + { + // Images, but display Thumbnail + // NOTE: If you want to use the download.php everytime an thumnmail is displayed inlined, replace the + // Section between BEGIN and END with (Without the // of course): + // $thumb_source = append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id'] . '&thumb=1'); + // + if (intval($attach_config['allow_ftp_upload']) && trim($attach_config['download_path']) == '') + { + $thumb_source = append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id'] . '&thumb=1'); + } + else + { + // Check if we can reach the file or if it is stored outside of the webroot + if ($attach_config['upload_dir'][0] == '/' || ( $attach_config['upload_dir'][0] != '/' && $attach_config['upload_dir'][1] == ':')) + { + $thumb_source = append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id'] . '&thumb=1'); + } + else + { + // BEGIN + $thumb_source = $thumbnail_filename; + // END + } + } + + $template->assign_block_vars('postrow.attach.cat_thumb_images', array( + 'DOWNLOAD_NAME' => $display_name, + 'S_UPLOAD_IMAGE' => $upload_image, + + 'IMG_SRC' => append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id']), + 'IMG_THUMB_SRC' => $thumb_source, + 'FILESIZE' => $filesize, + 'SIZE_VAR' => $size_lang, + 'COMMENT' => $comment, + )); + } + + if ($stream) + { + // Streams + $template->assign_block_vars('postrow.attach.cat_stream', array( + 'U_DOWNLOAD_LINK' => $filename, + 'S_UPLOAD_IMAGE' => $upload_image, + + 'DOWNLOAD_NAME' => $display_name, + 'FILESIZE' => $filesize, + 'SIZE_VAR' => $size_lang, + 'COMMENT' => $comment, + 'DOWNLOAD_COUNT' => sprintf($lang['DOWNLOAD_NUMBER'], $attachments['_' . $post_id][$i]['download_count'])) + ); + + // Viewed/Heared File ... update the download count (download.php is not called here) + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . ' + SET download_count = download_count + 1 + WHERE attach_id = ' . (int) $attachments['_' . $post_id][$i]['attach_id']; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t update attachment download count', '', __LINE__, __FILE__, $sql); + } + } + + if ($swf) + { + // Macromedia Flash Files + list($width, $height) = swf_getdimension($filename); + + $template->assign_block_vars('postrow.attach.cat_swf', array( + 'U_DOWNLOAD_LINK' => $filename, + 'S_UPLOAD_IMAGE' => $upload_image, + + 'DOWNLOAD_NAME' => $display_name, + 'FILESIZE' => $filesize, + 'SIZE_VAR' => $size_lang, + 'COMMENT' => $comment, + 'DOWNLOAD_COUNT' => sprintf($lang['DOWNLOAD_NUMBER'], $attachments['_' . $post_id][$i]['download_count']), + 'WIDTH' => $width, + 'HEIGHT' => $height) + ); + + // Viewed/Heared File ... update the download count (download.php is not called here) + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . ' + SET download_count = download_count + 1 + WHERE attach_id = ' . (int) $attachments['_' . $post_id][$i]['attach_id']; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t update attachment download count', '', __LINE__, __FILE__, $sql); + } + } + + //bt + if ($link && ($attachments['_'. $post_id][$i]['extension'] === TORRENT_EXT)) + { + include(BB_ROOT .'attach_mod/displaying_torrent.php'); + } + else if ($link) + //bt end + { + $target_blank = ( (@intval($display_categories[$attachments['_' . $post_id][$i]['extension']]) == IMAGE_CAT) ) ? 'target="_blank"' : ''; + + // display attachment + $template->assign_block_vars('postrow.attach.attachrow', array( + 'U_DOWNLOAD_LINK' => append_sid(BB_ROOT . 'download.php?id=' . $attachments['_' . $post_id][$i]['attach_id']), + 'S_UPLOAD_IMAGE' => $upload_image, + + 'DOWNLOAD_NAME' => $display_name, + 'FILESIZE' => $filesize, + 'SIZE_VAR' => $size_lang, + 'COMMENT' => $comment, + 'TARGET_BLANK' => $target_blank, + + 'DOWNLOAD_COUNT' => sprintf($lang['DOWNLOAD_NUMBER'], $attachments['_' . $post_id][$i]['download_count']), + )); + } + } + } +} \ No newline at end of file diff --git a/upload/attach_mod/displaying_torrent.php b/upload/attach_mod/displaying_torrent.php new file mode 100644 index 000000000..917e58555 --- /dev/null +++ b/upload/attach_mod/displaying_torrent.php @@ -0,0 +1,640 @@ +'; + +$peers_cnt = $seed_count = 0; +$seeders = $leechers = ''; +$tor_info = array(); + +$template->assign_vars(array( + 'SEED_COUNT' => false, + 'LEECH_COUNT' => false, + 'TOR_SPEED_UP' => false, + 'TOR_SPEED_DOWN' => false, + 'SHOW_RATIO_WARN' => false, +)); + +// Define show peers mode (count only || user names with complete % || full details) +$cfg_sp_mode = $bb_cfg['bt_show_peers_mode']; +$get_sp_mode = (isset($_GET['spmode'])) ? $_GET['spmode'] : ''; + +$s_mode = 'count'; + +if ($cfg_sp_mode == SHOW_PEERS_NAMES) +{ + $s_mode = 'names'; +} +else if ($cfg_sp_mode == SHOW_PEERS_FULL) +{ + $s_mode = 'full'; +} + +if ($bb_cfg['bt_allow_spmode_change']) +{ + if ($get_sp_mode == 'names') + { + $s_mode = 'names'; + } + else if ($get_sp_mode == 'full') + { + $s_mode = 'full'; + } +} + +$bt_topic_id = $t_data['topic_id']; +$bt_user_id = $userdata['user_id']; +$attach_id = $attachments['_'. $post_id][$i]['attach_id']; +$tracker_status = $attachments['_'. $post_id][$i]['tracker_status']; +$download_count = $attachments['_'. $post_id][$i]['download_count']; +$tor_file_size = humn_size($attachments['_'. $post_id][$i]['filesize']); +$tor_file_time = bb_date($attachments['_'. $post_id][$i]['filetime']); + +$tor_reged = (bool) $tracker_status; +$show_peers = (bool) $bb_cfg['bt_show_peers']; + +$locked = ($t_data['forum_status'] == FORUM_LOCKED || $t_data['topic_status'] == TOPIC_LOCKED); +$tor_auth = ($bt_user_id != ANONYMOUS && (($bt_user_id == $poster_id && !$locked) || $is_auth['auth_mod'])); + +$tor_auth_reg = ($tor_auth && $t_data['allow_reg_tracker'] && $post_id == $t_data['topic_first_post_id']); +$tor_auth_del = ($tor_auth && $tor_reged); + +$tracker_link = ($tor_reged) ? $lang['BT_REG_YES'] : $lang['BT_REG_NO']; + +$download_link = append_sid("download.php?id=$attach_id"); +$description = ($comment) ? $comment : preg_replace("#.torrent$#i", '', $display_name); + +if ($tor_auth_reg || $tor_auth_del) +{ + $reg_tor_url = ''. $lang['BT_REG_ON_TRACKER'] .''; + $unreg_tor_url = ''. $lang['BT_UNREG_FROM_TRACKER'] .''; + + $tracker_link = ($tor_reged) ? $unreg_tor_url : $reg_tor_url; +} + +if (!$tor_reged) +{ + $template->assign_block_vars('postrow.attach.tor_not_reged', array( + 'DOWNLOAD_NAME' => $display_name, + 'TRACKER_LINK' => $tracker_link, + 'ATTACH_ID' => $attach_id, + + 'S_UPLOAD_IMAGE' => $upload_image, + 'U_DOWNLOAD_LINK' => $download_link, + 'FILESIZE' => $tor_file_size, + + 'DOWNLOAD_COUNT' => sprintf($lang['DOWNLOAD_NUMBER'], $download_count), + 'POSTED_TIME' => $tor_file_time, + )); + + if ($comment) + { + $template->assign_block_vars('postrow.attach.tor_not_reged.comment', array('COMMENT' => $comment)); + } +} +else +{ + $sql = "SELECT * + FROM ". BB_BT_TORRENTS ." + WHERE attach_id = $attach_id + LIMIT 1"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain torrent information', '', __LINE__, __FILE__, $sql); + } + $tor_info = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); +} + +if ($tor_reged && !$tor_info) +{ + DB()->query("UPDATE ". BB_ATTACHMENTS_DESC ." SET tracker_status = 0 WHERE attach_id = $attach_id"); + + bb_die('Torrent status fixed'); +} + +if ($tor_auth) +{ + $template->assign_vars(array( + 'TOR_CONTROLS' => true, + 'TOR_ACTION' => "torrent.php", + + //torrent status mod + 'TOR_STATUS' => "torstatus.php", + //end torrent status mod + + 'TOR_ATTACH_ID' => $attach_id, + )); + + if ($t_data['self_moderated'] || $is_auth['auth_mod']) + { + $template->assign_vars(array('AUTH_MOVE' => true)); + } +} + +if ($tor_reged && $tor_info) +{ + $tor_size = ($tor_info['size']) ? $tor_info['size'] : 0; + $tor_id = $tor_info['topic_id']; + $tor_type = $tor_info['tor_type']; + + // Magnet link + $passkey = DB()->fetch_row("SELECT auth_key FROM ". BB_BT_USERS ." WHERE user_id = ". (int) $bt_user_id ." LIMIT 1"); + $tor_magnet = create_magnet($tor_info['info_hash'], $passkey['auth_key'], $userdata['session_logged_in']); + + // ratio limits + $min_ratio_dl = $bb_cfg['bt_min_ratio_allow_dl_tor']; + $min_ratio_warn = $bb_cfg['bt_min_ratio_warning']; + $dl_allowed = true; + $user_ratio = 0; + + if (($min_ratio_dl || $min_ratio_warn) && $bt_user_id != $poster_id) + { + $sql = "SELECT u.*, dl.user_status + FROM ". BB_BT_USERS ." u + LEFT JOIN ". BB_BT_DLSTATUS ." dl ON dl.user_id = $bt_user_id AND dl.topic_id = $bt_topic_id + WHERE u.user_id = $bt_user_id + LIMIT 1"; + } + else + { + $sql = "SELECT user_status + FROM ". BB_BT_DLSTATUS ." + WHERE user_id = $bt_user_id + AND topic_id = $bt_topic_id + LIMIT 1"; + } + + $bt_userdata = DB()->fetch_row($sql); + + $user_status = isset($bt_userdata['user_status']) ? $bt_userdata['user_status'] : null; + + if (($min_ratio_dl || $min_ratio_warn) && $user_status != DL_STATUS_COMPLETE && $bt_user_id != $poster_id && $tor_type != TOR_TYPE_GOLD) + { + if (($user_ratio = get_bt_ratio($bt_userdata)) !== null) + { + $dl_allowed = ($user_ratio > $min_ratio_dl); + } + + if (isset($user_ratio) && isset($min_ratio_warn) && $user_ratio < $min_ratio_warn && TR_RATING_LIMITS) + { + $template->assign_vars(array( + 'SHOW_RATIO_WARN' => true, + 'RATIO_WARN_MSG' => sprintf($lang['BT_RATIO_WARNING_MSG'], $min_ratio_warn, $bb_cfg['bt_ratio_warning_url_help']), + )); + } + } + + if (!$dl_allowed) + { + $template->assign_block_vars('postrow.attach.tor_reged', array()); + $template->assign_vars(array( + 'TOR_BLOCKED' => true, + 'TOR_BLOCKED_MSG' => sprintf($lang['BT_LOW_RATIO_FOR_DL'], round($user_ratio, 2), "search.php?dlu=$bt_user_id&dlc=1"), + )); + } + else + { + //torrent status mod + $cuid = $tor_info['checked_user_id']; + //end torrent status mod + $template->assign_block_vars('postrow.attach.tor_reged', array( + 'DOWNLOAD_NAME' => $display_name, + 'TRACKER_LINK' => $tracker_link, + 'ATTACH_ID' => $attach_id, + 'TOR_FROZEN' => ($tor_info['tor_status'] == TOR_STATUS_FROZEN || $tor_info['tor_status'] == 3 || $tor_info['tor_status'] == 4 || $tor_info['tor_status'] == 7), + 'TOR_SILVER_GOLD' => $tor_type, + + // torrent status mod + 'TOR_STATUS_TEXT' => $lang['tor_status'][$tor_info['tor_status']], + 'TOR_STATUS_ICON' => $bb_cfg['tor_icons'][$tor_info['tor_status']], + 'TOR_STATUS_BY' => $cuid ? (' ·  ' . get_username($cuid) . '  ·  '. delta_time($tor_info['checked_time']) .' назад') : '', + 'TOR_STATUS_SELECT' => build_select('', array_flip($bb_cfg['change_tor_status_select']), TOR_APPROVED), + //end torrent status mod + + 'S_UPLOAD_IMAGE' => $upload_image, + 'U_DOWNLOAD_LINK' => $download_link, + 'DL_LINK_CLASS' => (isset($bt_userdata['user_status'])) ? $dl_link_css[$bt_userdata['user_status']] : 'genmed', + 'DL_TITLE_CLASS' => (isset($bt_userdata['user_status'])) ? $dl_status_css[$bt_userdata['user_status']] : 'gen', + 'FILESIZE' => $tor_file_size, + + 'MAGNET' => $tor_magnet, + + 'DOWNLOAD_COUNT' => sprintf($lang['DOWNLOAD_NUMBER'], $download_count), + 'REGED_TIME' => bb_date($tor_info['reg_time']), + 'REGED_DELTA' => delta_time($tor_info['reg_time']), + + 'TORRENT_SIZE' => humn_size($tor_size), + 'COMPLETED' => sprintf($lang['DOWNLOAD_NUMBER'], $tor_info['complete_count']), + )); + + if ($comment) + { + $template->assign_block_vars('postrow.attach.tor_reged.comment', array('COMMENT' => $comment)); + } + } + + if ($bb_cfg['show_tor_info_in_dl_list']) + { + $template->assign_vars(array( + 'SHOW_DL_LIST' => true, + 'SHOW_DL_LIST_TOR_INFO' => true, + + 'TOR_SIZE' => humn_size($tor_size), + 'TOR_LONGEVITY' => delta_time($tor_info['reg_time']), + 'TOR_COMPLETED' => declension($tor_info['complete_count'], 'times'), + )); + } + + // Show peers + if ($show_peers) + { + // Sorting order in full mode + if ($s_mode == 'full') + { + $full_mode_order = 'tr.remain'; + $full_mode_sort_dir = 'ASC'; + + if (isset($_REQUEST['psortasc'])) + { + $full_mode_sort_dir = 'ASC'; + } + else if (isset($_REQUEST['psortdesc'])) + { + $full_mode_sort_dir = 'DESC'; + } + + if (isset($_REQUEST['porder'])) + { + $peer_orders = array( + 'name' => 'u.username', + 'ip' => 'tr.ip', + 'port' => 'tr.port', + 'compl' => 'tr.remain', + 'cup' => 'tr.uploaded', + 'cdown' => 'tr.downloaded', + 'sup' => 'tr.speed_up', + 'sdown' => 'tr.speed_down', + 'time' => 'tr.update_time', + ); + + foreach ($peer_orders as $get_key => $order_by_value) + { + if ($_REQUEST['porder'] == $get_key) + { + $full_mode_order = $order_by_value; + break; + } + } + } + } + // SQL for each mode + if ($s_mode == 'count') + { + $sql = "SELECT seeders, leechers, speed_up, speed_down + FROM ". BB_BT_TRACKER_SNAP ." + WHERE topic_id = $tor_id + LIMIT 1"; + } + else if ($s_mode == 'names') + { + $sql = "SELECT tr.user_id, tr.ip, tr.port, tr.remain, tr.seeder, u.username + FROM ". BB_BT_TRACKER ." tr, ". BB_USERS ." u + WHERE tr.topic_id = $tor_id + AND u.user_id = tr.user_id + GROUP BY tr.ip, tr.user_id, tr.port, tr.seeder + ORDER BY u.username + LIMIT $show_peers_limit"; + } + else + { + $sql = "SELECT + tr.user_id, tr.ip, tr.port, tr.uploaded, tr.downloaded, tr.remain, + tr.seeder, tr.releaser, tr.speed_up, tr.speed_down, tr.update_time, + u.username + FROM ". BB_BT_TRACKER ." tr + LEFT JOIN ". BB_USERS ." u ON u.user_id = tr.user_id + WHERE tr.topic_id = $tor_id + GROUP BY tr.ip, tr.user_id, tr.port, tr.seeder + ORDER BY $full_mode_order $full_mode_sort_dir + LIMIT $show_peers_limit"; + } + + // Build peers table + if ($peers = DB()->fetch_rowset($sql)) + { + $peers_cnt = count($peers); + + $cnt = $tr = $sp_up = $sp_down = $sp_up_tot = $sp_down_tot = array(); + $cnt['s'] = $tr['s'] = $sp_up['s'] = $sp_down['s'] = $sp_up_tot['s'] = $sp_down_tot['s'] = 0; + $cnt['l'] = $tr['l'] = $sp_up['l'] = $sp_down['l'] = $sp_up_tot['l'] = $sp_down_tot['l'] = 0; + + $max_up = $max_down = $max_sp_up = $max_sp_down = array(); + $max_up['s'] = $max_down['s'] = $max_sp_up['s'] = $max_sp_down['s'] = 0; + $max_up['l'] = $max_down['l'] = $max_sp_up['l'] = $max_sp_down['l'] = 0; + $max_up_id['s'] = $max_down_id['s'] = $max_sp_up_id['s'] = $max_sp_down_id['s'] = ($peers_cnt + 1); + $max_up_id['l'] = $max_down_id['l'] = $max_sp_up_id['l'] = $max_sp_down_id['l'] = ($peers_cnt + 1); + + if ($s_mode == 'full') + { + foreach ($peers as $pid => $peer) + { + $x = ($peer['seeder']) ? 's' : 'l'; + $cnt[$x]++; + $sp_up_tot[$x] += $peer['speed_up']; + $sp_down_tot[$x] += $peer['speed_down']; + + $guest = ($peer['user_id'] == ANONYMOUS || is_null($peer['username'])); + $p_max_up = $peer['uploaded']; + $p_max_down = $peer['downloaded']; + + if ($p_max_up > $max_up[$x]) + { + $max_up[$x] = $p_max_up; + $max_up_id[$x] = $pid; + } + if ($peer['speed_up'] > $max_sp_up[$x]) + { + $max_sp_up[$x] = $peer['speed_up']; + $max_sp_up_id[$x] = $pid; + } + if ($p_max_down > $max_down[$x]) + { + $max_down[$x] = $p_max_down; + $max_down_id[$x] = $pid; + } + if ($peer['speed_down'] > $max_sp_down[$x]) + { + $max_sp_down[$x] = $peer['speed_down']; + $max_sp_down_id[$x] = $pid; + } + } + $max_down_id['s'] = $max_sp_down_id['s'] = ($peers_cnt + 1); + + if ($cnt['s'] == 1) + { + $max_up_id['s'] = $max_sp_up_id['s'] = ($peers_cnt + 1); + } + if ($cnt['l'] == 1) + { + $max_up_id['l'] = $max_down_id['l'] = $max_sp_up_id['l'] = $max_sp_down_id['l'] = ($peers_cnt + 1); + } + } + + if ($s_mode == 'count') + { + $tmp = array(); + $tmp[0]['seeder'] = $tmp[0]['username'] = $tmp[1]['username'] = 0; + $tmp[1]['seeder'] = 1; + $tmp[0]['username'] = (int) @$peers[0]['leechers']; + $tmp[1]['username'] = (int) @$peers[0]['seeders']; + $tor_speed_up = (int) @$peers[0]['speed_up']; + $tor_speed_down = (int) @$peers[0]['speed_down']; + $peers = $tmp; + + $template->assign_vars(array( + 'TOR_SPEED_UP' => ($tor_speed_up) ? humn_size($tor_speed_up, 0, 'KB') .'/s' : '0 KB/s', + 'TOR_SPEED_DOWN' => ($tor_speed_down) ? humn_size($tor_speed_down, 0, 'KB') .'/s' : '0 KB/s', + )); + } + + foreach ($peers as $pid => $peer) + { + $u_prof_href = ($s_mode == 'count') ? '#' : append_sid("profile.php?mode=viewprofile&u=". $peer['user_id']) .'#torrent'; + + // Full details mode + if ($s_mode == 'full') + { + $ip = bt_show_ip($peer['ip']); + $port = bt_show_port($peer['port']); + $guest = ($peer['user_id'] == ANONYMOUS || is_null($peer['username'])); + + if (isset($peer['user_id']) && $guest) + { + $peer['username'] = 'Guest'; + } + // peer max/current up/down + $p_max_up = $peer['uploaded']; + $p_max_down = $peer['downloaded']; + $p_cur_up = $peer['uploaded']; + $p_cur_down = $peer['downloaded']; + + if ($peer['seeder']) + { + $x = 's'; + $x_row = 'srow'; + $x_full = 'sfull'; + $link_class = 'seedmed'; + + if (!defined('SEEDER_EXIST')) + { + define('SEEDER_EXIST', true); + $seed_order_action = append_sid("viewtopic.php?". POST_TOPIC_URL ."=$bt_topic_id&spmode=full") .'#seeders'; + + $template->assign_block_vars("$x_full", array( + 'SEED_ORD_ACT' => $seed_order_action, + 'SEEDERS_UP_TOT' => humn_size($sp_up_tot[$x], 0, 'KB') .'/s' + )); + + if ($ip) + { + $template->assign_block_vars("$x_full.iphead", array()); + } + if ($port !== false) + { + $template->assign_block_vars("$x_full.porthead", array()); + } + } + $compl_perc = ($tor_size) ? round(($p_max_up / $tor_size), 1) : 0; + } + else + { + $x = 'l'; + $x_row = 'lrow'; + $x_full = 'lfull'; + $link_class = 'leechmed'; + + if (!defined('LEECHER_EXIST')) + { + define('LEECHER_EXIST', true); + $leech_order_action = append_sid("viewtopic.php?". POST_TOPIC_URL ."=$bt_topic_id&spmode=full") .'#leechers'; + + $template->assign_block_vars("$x_full", array( + 'LEECH_ORD_ACT' => $leech_order_action, + 'LEECHERS_UP_TOT' => humn_size($sp_up_tot[$x], 0, 'KB') .'/s', + 'LEECHERS_DOWN_TOT' => humn_size($sp_down_tot[$x], 0, 'KB') .'/s' + )); + + if ($ip) + { + $template->assign_block_vars("$x_full.iphead", array()); + } + if ($port !== false) + { + $template->assign_block_vars("$x_full.porthead", array()); + } + } + $compl_size = ($peer['remain'] && $tor_size && $tor_size > $peer['remain']) ? ($tor_size - $peer['remain']) : 0; + $compl_perc = ($compl_size) ? floor($compl_size * 100 / $tor_size) : 0; + } + + $rel_sign = (!$guest && $peer['releaser']) ? ' ® ' : ''; + $name = ''. wbr($peer['username']) .''. $rel_sign; + $up_tot = ($p_max_up) ? humn_size($p_max_up) : '-'; + $down_tot = ($p_max_down) ? humn_size($p_max_down) : '-'; + $up_ratio = ($p_max_down) ? round(($p_max_up / $p_max_down), 2) : ''; + $sp_up = ($peer['speed_up']) ? humn_size($peer['speed_up'], 0, 'KB') .'/s' : '-'; + $sp_down = ($peer['speed_down']) ? humn_size($peer['speed_down'], 0, 'KB') .'/s' : '-'; + + $bgr_class = (!($tr[$x] % 2)) ? $bgr_class_1 : $bgr_class_2; + $row_bgr = ($change_peers_bgr_over) ? " class=\"$bgr_class\" onmouseover=\"this.className='$bgr_class_over';\" onmouseout=\"this.className='$bgr_class';\"" : ''; + $tr[$x]++; + + $template->assign_block_vars("$x_full.$x_row", array( + 'ROW_BGR' => $row_bgr, + 'NAME' => ($peer['update_time']) ? $name : "$name", + 'COMPL_PRC' => $compl_perc, + 'UP_TOTAL' => ($max_up_id[$x] == $pid) ? "$up_tot" : $up_tot, + 'DOWN_TOTAL' => ($max_down_id[$x] == $pid) ? "$down_tot" : $down_tot, + 'SPEED_UP' => ($max_sp_up_id[$x] == $pid) ? "$sp_up" : $sp_up, + 'SPEED_DOWN' => ($max_sp_down_id[$x] == $pid) ? "$sp_down" : $sp_down, + 'UPD_EXP_TIME' => ($peer['update_time']) ? "upd: ". bb_date($peer['update_time'], 'd-M-y H:i') : "stopped", + 'TOR_RATIO' => ($up_ratio) ? "UL/DL ratio: $up_ratio" : '', + )); + + if ($ip) + { + $template->assign_block_vars("$x_full.$x_row.ip", array('IP' => $ip)); + } + if ($port !== false) + { + $template->assign_block_vars("$x_full.$x_row.port", array('PORT' => $port)); + } + } + // Count only & only names modes + else + { + if ($peer['seeder']) + { + $seeders .= ''. $peer['username'] .', '; + $seed_count = $peer['username']; + } + else + { + $compl_size = (@$peer['remain'] && $tor_size && $tor_size > $peer['remain']) ? ($tor_size - $peer['remain']) : 0; + $compl_perc = ($compl_size) ? floor($compl_size * 100 / $tor_size) : 0; + + $leechers .= ''. $peer['username'] .''; + $leechers .= ($s_mode == 'names') ? ' ['. $compl_perc .'%]' : ''; + $leechers .= ', '; + $leech_count = $peer['username']; + } + } + } + + if ($s_mode != 'full' && $seeders) + { + $seeders[strlen($seeders)-9] = ' '; + $template->assign_vars(array( + 'SEED_LIST' => $seeders, + 'SEED_COUNT' => ($seed_count) ? $seed_count : 0, + )); + } + if ($s_mode != 'full' && $leechers) + { + $leechers[strlen($leechers)-9] = ' '; + $template->assign_vars(array( + 'LEECH_LIST' => $leechers, + 'LEECH_COUNT' => ($leech_count) ? $leech_count : 0, + )); + } + } + unset($peers); + + if ($s_mode == 'full' && (defined('SEEDER_EXIST') || defined('LEECHER_EXIST'))) + { + $name_opt = ''; + $seed_compl_opt = ''; + $leech_compl_opt = ''; + + $up_down_speed_opt = ' + + + + + '; + + $ip_opt = ($ip) ? '' : ''; + $port_opt = ($port !== false) ? '' : ''; + + if ($cnt['s'] > 2) + { + $seed_order_select = $name_opt . $seed_compl_opt . $up_down_speed_opt . $ip_opt . $port_opt; + $template->assign_block_vars('sfull.sorder', array('SEED_ORDER_SELECT' => '')); + } + if ($cnt['l'] > 2) + { + $leech_order_select = $name_opt . $leech_compl_opt . $up_down_speed_opt . $ip_opt . $port_opt; + $template->assign_block_vars('lfull.lorder', array('LEECH_ORDER_SELECT' => '')); + } + } + + // Show "seeder last seen info" + if (($s_mode == 'count' && !$seed_count) || (!$seeders && !defined('SEEDER_EXIST'))) + { + $last_seen_time = ($tor_info['seeder_last_seen']) ? delta_time($tor_info['seeder_last_seen']) : $lang['NEVER']; + + $template->assign_vars(array( + 'SEEDER_LAST_SEEN' => sprintf($lang['SEEDER_LAST_SEEN'], $last_seen_time), + )); + } + } + + $template->assign_block_vars('tor_title', array('U_DOWNLOAD_LINK' => $download_link)); + + if ($peers_cnt > $max_peers_before_overflow && $s_mode == 'full') + { + $template->assign_vars(array('PEERS_DIV_STYLE' => $peers_div_style_overflow)); + $template->assign_vars(array('PEERS_OVERFLOW' => true)); + } + else + { + $template->assign_vars(array('PEERS_DIV_STYLE' => $peers_div_style_normal)); + } +} + +if ($bb_cfg['bt_allow_spmode_change'] && $s_mode != 'full') +{ + $template->assign_vars(array( + 'PEERS_FULL_LINK' => true, + 'SPMODE_FULL_HREF' => append_sid("viewtopic.php?". POST_TOPIC_URL ."=$bt_topic_id&spmode=full") .'#seeders', + )); +} + +$template->assign_vars(array( + 'SHOW_DL_LIST_LINK' => (($bb_cfg['bt_show_dl_list'] || $bb_cfg['allow_dl_list_names_mode']) && $t_data['topic_dl_type'] == TOPIC_DL_TYPE_DL), + 'SHOW_TOR_ACT' => ($tor_reged && $show_peers), + 'S_MODE_COUNT' => ($s_mode == 'count'), + 'S_MODE_NAMES' => ($s_mode == 'names'), + 'S_MODE_FULL' => ($s_mode == 'full'), + 'PEER_EXIST' => ($seeders || $leechers || defined('SEEDER_EXIST') || defined('LEECHER_EXIST')), + 'SEED_EXIST' => ($seeders || defined('SEEDER_EXIST')), + 'LEECH_EXIST' => ($leechers || defined('LEECHER_EXIST')), + 'TOR_HELP_LINKS' => $bb_cfg['tor_help_links'], +)); \ No newline at end of file diff --git a/upload/attach_mod/includes/.htaccess b/upload/attach_mod/includes/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/attach_mod/includes/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_admin.php b/upload/attach_mod/includes/functions_admin.php new file mode 100644 index 000000000..63355c7e4 --- /dev/null +++ b/upload/attach_mod/includes/functions_admin.php @@ -0,0 +1,415 @@ +sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Entry', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) == 0) + { + $sql_ary = array( + 'user_id' => (int) $id, + 'group_id' => 0, + 'quota_type' => (int) $quota_type, + 'quota_limit_id'=> (int) $quota_limit_id + ); + + $sql = 'INSERT INTO ' . BB_QUOTA . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + } + else + { + $sql = 'UPDATE ' . BB_QUOTA . " + SET quota_limit_id = $quota_limit_id + WHERE user_id = $id + AND quota_type = $quota_type"; + } + DB()->sql_freeresult($result); + } + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to update quota Settings', '', __LINE__, __FILE__, $sql); + } + + } + else if ($mode == 'group') + { + if (!$quota_limit_id) + { + $sql = 'DELETE FROM ' . BB_QUOTA . " + WHERE group_id = $id + AND quota_type = $quota_type"; + + if( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Unable to delete quota Settings', '', __LINE__, __FILE__, $sql); + } + } + else + { + // Check if user is already entered + $sql = 'SELECT group_id + FROM ' . BB_QUOTA . " + WHERE group_id = $id + AND quota_type = $quota_type"; + + if( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Entry', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) == 0) + { + $sql = 'INSERT INTO ' . BB_QUOTA . " (user_id, group_id, quota_type, quota_limit_id) + VALUES (0, $id, $quota_type, $quota_limit_id)"; + } + else + { + $sql = 'UPDATE ' . BB_QUOTA . " SET quota_limit_id = $quota_limit_id + WHERE group_id = $id AND quota_type = $quota_type"; + } + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Unable to update quota Settings', '', __LINE__, __FILE__, $sql); + } + } + } +} + +/** +* sort multi-dimensional Array +*/ +function sort_multi_array ($sort_array, $key, $sort_order, $pre_string_sort = 0) +{ + $last_element = sizeof($sort_array) - 1; + + if (!$pre_string_sort) + { + $string_sort = (!is_numeric(@$sort_array[$last_element-1][$key]) ) ? true : false; + } + else + { + $string_sort = $pre_string_sort; + } + + for ($i = 0; $i < $last_element; $i++) + { + $num_iterations = $last_element - $i; + + for ($j = 0; $j < $num_iterations; $j++) + { + $next = 0; + + // do checks based on key + $switch = false; + if (!$string_sort) + { + if (($sort_order == 'DESC' && intval(@$sort_array[$j][$key]) < intval(@$sort_array[$j + 1][$key])) || ($sort_order == 'ASC' && intval(@$sort_array[$j][$key]) > intval(@$sort_array[$j + 1][$key]))) + { + $switch = true; + } + } + else + { + if (($sort_order == 'DESC' && strcasecmp(@$sort_array[$j][$key], @$sort_array[$j + 1][$key]) < 0) || ($sort_order == 'ASC' && strcasecmp(@$sort_array[$j][$key], @$sort_array[$j + 1][$key]) > 0)) + { + $switch = true; + } + } + + if ($switch) + { + $temp = $sort_array[$j]; + $sort_array[$j] = $sort_array[$j + 1]; + $sort_array[$j + 1] = $temp; + } + } + } + + return $sort_array; +} + +/** +* Returns the filesize of the upload directory in human readable format +*/ +function get_formatted_dirsize() +{ + global $attach_config, $upload_dir, $lang; + + $upload_dir_size = 0; + + if (!intval($attach_config['allow_ftp_upload'])) + { + if ($dirname = @opendir($upload_dir)) + { + while ($file = @readdir($dirname)) + { + if ($file != 'index.php' && $file != '.htaccess' && !is_dir($upload_dir . '/' . $file) && !is_link($upload_dir . '/' . $file)) + { + $upload_dir_size += @filesize($upload_dir . '/' . $file); + } + } + @closedir($dirname); + } + else + { + $upload_dir_size = $lang['NOT_AVAILABLE']; + return $upload_dir_size; + } + } + else + { + $conn_id = attach_init_ftp(); + + $file_listing = array(); + + $file_listing = @ftp_rawlist($conn_id, ''); + + if (!$file_listing) + { + $upload_dir_size = $lang['NOT_AVAILABLE']; + return $upload_dir_size; + } + + for ($i = 0; $i < count($file_listing); $i++) + { + if (preg_match("/([-d])[rwxst-]{9}.* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9]) ([0-9]{2}:[0-9]{2}) (.+)/", $file_listing[$i], $regs)) + { + if ($regs[1] == 'd') + { + $dirinfo[0] = 1; // Directory == 1 + } + $dirinfo[1] = $regs[2]; // Size + $dirinfo[2] = $regs[3]; // Date + $dirinfo[3] = $regs[4]; // Filename + $dirinfo[4] = $regs[5]; // Time + } + + if ($dirinfo[0] != 1 && $dirinfo[4] != 'index.php' && $dirinfo[4] != '.htaccess') + { + $upload_dir_size += $dirinfo[1]; + } + } + + @ftp_quit($conn_id); + } + + if ($upload_dir_size >= 1048576) + { + $upload_dir_size = round($upload_dir_size / 1048576 * 100) / 100 . ' ' . $lang['MB']; + } + else if ($upload_dir_size >= 1024) + { + $upload_dir_size = round($upload_dir_size / 1024 * 100) / 100 . ' ' . $lang['KB']; + } + else + { + $upload_dir_size = $upload_dir_size . ' ' . $lang['BYTES']; + } + + return $upload_dir_size; +} + +/* +* Build SQL-Statement for the search feature +*/ +function search_attachments($order_by, &$total_rows) +{ + global $lang; + + $where_sql = array(); + + // Get submitted Vars + $search_vars = array('search_keyword_fname', 'search_keyword_comment', 'search_author', 'search_size_smaller', 'search_size_greater', 'search_count_smaller', 'search_count_greater', 'search_days_greater', 'search_forum', 'search_cat'); + + for ($i = 0; $i < sizeof($search_vars); $i++) + { + $$search_vars[$i] = get_var($search_vars[$i], ''); + } + + // Author name search + if ($search_author != '') + { + // Bring in line with 2.0.x expected username + $search_author = addslashes(html_entity_decode($search_author)); + $search_author = stripslashes(clean_username($search_author)); + + // Prepare for directly going into sql query + $search_author = str_replace('*', '%', attach_mod_sql_escape($search_author)); + + // We need the post_id's, because we want to query the Attachment Table + $sql = 'SELECT user_id + FROM ' . BB_USERS . " + WHERE username LIKE '$search_author'"; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t obtain list of matching users (searching for: ' . $search_author . ')', '', __LINE__, __FILE__, $sql); + } + + $matching_userids = ''; + if ( $row = DB()->sql_fetchrow($result) ) + { + do + { + $matching_userids .= (($matching_userids != '') ? ', ' : '') . intval($row['user_id']); + } + while ($row = DB()->sql_fetchrow($result)); + + DB()->sql_freeresult($result); + } + else + { + message_die(GENERAL_MESSAGE, $lang['NO_ATTACH_SEARCH_MATCH']); + } + + $where_sql[] = ' (t.user_id_1 IN (' . $matching_userids . ')) '; + } + + // Search Keyword + if ($search_keyword_fname != '') + { + $match_word = str_replace('*', '%', $search_keyword_fname); + $where_sql[] = " (a.real_filename LIKE '" . attach_mod_sql_escape($match_word) . "') "; + } + + if ($search_keyword_comment != '') + { + $match_word = str_replace('*', '%', $search_keyword_comment); + $where_sql[] = " (a.comment LIKE '" . attach_mod_sql_escape($match_word) . "') "; + } + + // Search Download Count + if ($search_count_smaller != '' || $search_count_greater != '') + { + if ($search_count_smaller != '') + { + $where_sql[] = ' (a.download_count < ' . (int) $search_count_smaller . ') '; + } + else if ($search_count_greater != '') + { + $where_sql[] = ' (a.download_count > ' . (int) $search_count_greater . ') '; + } + } + + // Search Filesize + if ($search_size_smaller != '' || $search_size_greater != '') + { + if ($search_size_smaller != '') + { + $where_sql[] = ' (a.filesize < ' . (int) $search_size_smaller . ') '; + } + else if ($search_size_greater != '') + { + $where_sql[] = ' (a.filesize > ' . (int) $search_size_greater . ') '; + } + } + + // Search Attachment Time + if ($search_days_greater != '') + { + $where_sql[] = ' (a.filetime < ' . ( time() - ((int) $search_days_greater * 86400)) . ') '; + } + + // Search Forum + if ($search_forum) + { + $where_sql[] = ' (p.forum_id = ' . intval($search_forum) . ') '; + } + + // Search Cat... nope... sorry :( + + $sql = 'SELECT a.*, t.post_id, p.post_time, p.topic_id + FROM ' . BB_ATTACHMENTS . ' t, ' . BB_ATTACHMENTS_DESC . ' a, ' . BB_POSTS . ' p WHERE '; + + if (sizeof($where_sql) > 0) + { + $sql .= implode('AND', $where_sql) . ' AND '; + } + + $sql .= 't.post_id = p.post_id AND a.attach_id = t.attach_id '; + + $total_rows_sql = $sql; + + $sql .= $order_by; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $attachments = DB()->sql_fetchrowset($result); + $num_attach = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_attach == 0) + { + message_die(GENERAL_MESSAGE, $lang['NO_ATTACH_SEARCH_MATCH']); + } + + if (!($result = DB()->sql_query($total_rows_sql))) + { + message_die(GENERAL_ERROR, 'Could not query attachments', '', __LINE__, __FILE__, $sql); + } + + $total_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + return $attachments; +} + +/** +* perform LIMIT statement on arrays +*/ +function limit_array($array, $start, $pagelimit) +{ + // array from start - start+pagelimit + $limit = (sizeof($array) < ($start + $pagelimit)) ? sizeof($array) : $start + $pagelimit; + + $limit_array = array(); + + for ($i = $start; $i < $limit; $i++) + { + $limit_array[] = $array[$i]; + } + + return $limit_array; +} \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_attach.php b/upload/attach_mod/includes/functions_attach.php new file mode 100644 index 000000000..291816e30 --- /dev/null +++ b/upload/attach_mod/includes/functions_attach.php @@ -0,0 +1,892 @@ + 4096) + { + return; + } + else if ($number < $base) + { + return $chars[$number]; + } + + $hexval = ''; + + while ($number > 0) + { + $remainder = $number%$base; + + if ($remainder < $base) + { + $hexval = $chars[$remainder] . $hexval; + } + + $number = floor($number/$base); + } + + return $hexval; +} + +/** +* base64todec function +*/ +function base64_unpack($string) +{ + $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-'; + $base = strlen($chars); + + $length = strlen($string); + $number = 0; + + for($i = 1; $i <= $length; $i++) + { + $pos = $length - $i; + $operand = strpos($chars, substr($string,$pos,1)); + $exponent = pow($base, $i-1); + $decValue = $operand * $exponent; + $number += $decValue; + } + + return $number; +} + +/** +* Per Forum based Extension Group Permissions (Encode Number) -> Theoretically up to 158 Forums saveable. :) +* We are using a base of 64, but splitting it to one-char and two-char numbers. :) +*/ +function auth_pack($auth_array) +{ + $one_char_encoding = '#'; + $two_char_encoding = '.'; + $one_char = $two_char = false; + $auth_cache = ''; + + for ($i = 0; $i < sizeof($auth_array); $i++) + { + $val = base64_pack(intval($auth_array[$i])); + if (strlen($val) == 1 && !$one_char) + { + $auth_cache .= $one_char_encoding; + $one_char = true; + } + else if (strlen($val) == 2 && !$two_char) + { + $auth_cache .= $two_char_encoding; + $two_char = true; + } + + $auth_cache .= $val; + } + + return $auth_cache; +} + +/** +* Reverse the auth_pack process +*/ +function auth_unpack($auth_cache) +{ + $one_char_encoding = '#'; + $two_char_encoding = '.'; + + $auth = array(); + $auth_len = 1; + + for ($pos = 0; $pos < strlen($auth_cache); $pos += $auth_len) + { + $forum_auth = substr($auth_cache, $pos, 1); + if ($forum_auth == $one_char_encoding) + { + $auth_len = 1; + continue; + } + else if ($forum_auth == $two_char_encoding) + { + $auth_len = 2; + $pos--; + continue; + } + + $forum_auth = substr($auth_cache, $pos, $auth_len); + $forum_id = base64_unpack($forum_auth); + $auth[] = intval($forum_id); + } + return $auth; +} + +/** +* Used for determining if Forum ID is authed, please use this Function on all Posting Screens +*/ +function is_forum_authed($auth_cache, $check_forum_id) +{ + $one_char_encoding = '#'; + $two_char_encoding = '.'; + + if (trim($auth_cache) == '') + { + return true; + } + + $auth = array(); + $auth_len = 1; + + for ($pos = 0; $pos < strlen($auth_cache); $pos+=$auth_len) + { + $forum_auth = substr($auth_cache, $pos, 1); + if ($forum_auth == $one_char_encoding) + { + $auth_len = 1; + continue; + } + else if ($forum_auth == $two_char_encoding) + { + $auth_len = 2; + $pos--; + continue; + } + + $forum_auth = substr($auth_cache, $pos, $auth_len); + $forum_id = (int) base64_unpack($forum_auth); + if ($forum_id == $check_forum_id) + { + return true; + } + } + return false; +} + +/** +* Init FTP Session +*/ +function attach_init_ftp($mode = false) +{ + global $lang, $attach_config; + + $server = (trim($attach_config['ftp_server']) == '') ? 'localhost' : trim($attach_config['ftp_server']); + + $ftp_path = ($mode == MODE_THUMBNAIL) ? trim($attach_config['ftp_path']) . '/' . THUMB_DIR : trim($attach_config['ftp_path']); + + $conn_id = @ftp_connect($server); + + if (!$conn_id) + { + message_die(GENERAL_ERROR, sprintf($lang['FTP_ERROR_CONNECT'], $server)); + } + + $login_result = @ftp_login($conn_id, $attach_config['ftp_user'], $attach_config['ftp_pass']); + + if (!$login_result) + { + message_die(GENERAL_ERROR, sprintf($lang['FTP_ERROR_LOGIN'], $attach_config['ftp_user'])); + } + + if (!@ftp_pasv($conn_id, intval($attach_config['ftp_pasv_mode']))) + { + message_die(GENERAL_ERROR, $lang['FTP_ERROR_PASV_MODE']); + } + + $result = @ftp_chdir($conn_id, $ftp_path); + + if (!$result) + { + message_die(GENERAL_ERROR, sprintf($lang['FTP_ERROR_PATH'], $ftp_path)); + } + + return $conn_id; +} + +/** +* Deletes an Attachment +*/ +function unlink_attach($filename, $mode = false) +{ + global $upload_dir, $attach_config, $lang; + + $filename = basename($filename); + + if (!intval($attach_config['allow_ftp_upload'])) + { + if ($mode == MODE_THUMBNAIL) + { + $filename = $upload_dir . '/' . THUMB_DIR . '/t_' . $filename; + } + else + { + $filename = $upload_dir . '/' . $filename; + } + + $deleted = @unlink($filename); + + } + else + { + $conn_id = attach_init_ftp($mode); + + if ($mode == MODE_THUMBNAIL) + { + $filename = 't_' . $filename; + } + + $res = @ftp_delete($conn_id, $filename); + if (!$res) + { + return $deleted; + } + + @ftp_quit($conn_id); + + $deleted = true; + } + + return $deleted; +} + +/** +* FTP File to Location +*/ +function ftp_file($source_file, $dest_file, $mimetype, $disable_error_mode = false) +{ + global $attach_config, $lang, $error, $error_msg; + + $conn_id = attach_init_ftp(); + + // Binary or Ascii ? + $mode = FTP_BINARY; + if (preg_match("/text/i", $mimetype) || preg_match("/html/i", $mimetype)) + { + $mode = FTP_ASCII; + } + + $res = @ftp_put($conn_id, $dest_file, $source_file, $mode); + + if (!$res && !$disable_error_mode) + { + $error = true; + if (!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg = sprintf($lang['FTP_ERROR_UPLOAD'], $attach_config['ftp_path']) . '
'; + @ftp_quit($conn_id); + return false; + } + + if (!$res) + { + return false; + } + + @ftp_site($conn_id, 'CHMOD 0644 ' . $dest_file); + @ftp_quit($conn_id); + return true; +} + +/** +* Check if Attachment exist +*/ +function attachment_exists($filename) +{ + global $upload_dir, $attach_config; + + $filename = basename($filename); + + if (!intval($attach_config['allow_ftp_upload'])) + { + if (!@file_exists(@amod_realpath($upload_dir . '/' . $filename))) + { + return false; + } + else + { + return true; + } + } + else + { + $found = false; + + $conn_id = attach_init_ftp(); + + $file_listing = array(); + + $file_listing = @ftp_rawlist($conn_id, $filename); + + for ($i = 0, $size = sizeof($file_listing); $i < $size; $i++) + { + if (preg_match("/([-d])[rwxst-]{9}.* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9]) ([0-9]{2}:[0-9]{2}) (.+)/", $file_listing[$i], $regs)) + { + if ($regs[1] == 'd') + { + $dirinfo[0] = 1; // Directory == 1 + } + $dirinfo[1] = $regs[2]; // Size + $dirinfo[2] = $regs[3]; // Date + $dirinfo[3] = $regs[4]; // Filename + $dirinfo[4] = $regs[5]; // Time + } + + if ($dirinfo[0] != 1 && $dirinfo[4] == $filename) + { + $found = true; + } + } + + @ftp_quit($conn_id); + + return $found; + } +} + +/** +* Check if Thumbnail exist +*/ +function thumbnail_exists($filename) +{ + global $upload_dir, $attach_config; + + $filename = basename($filename); + + if (!intval($attach_config['allow_ftp_upload'])) + { + if (!@file_exists(@amod_realpath($upload_dir . '/' . THUMB_DIR . '/t_' . $filename))) + { + return false; + } + else + { + return true; + } + } + else + { + $found = false; + + $conn_id = attach_init_ftp(MODE_THUMBNAIL); + + $file_listing = array(); + + $filename = 't_' . $filename; + $file_listing = @ftp_rawlist($conn_id, $filename); + + for ($i = 0, $size = sizeof($file_listing); $i < $size; $i++) + { + if (preg_match("/([-d])[rwxst-]{9}.* ([0-9]*) ([a-zA-Z]+[0-9: ]*[0-9]) ([0-9]{2}:[0-9]{2}) (.+)/", $file_listing[$i], $regs)) + { + if ($regs[1] == 'd') + { + $dirinfo[0] = 1; // Directory == 1 + } + $dirinfo[1] = $regs[2]; // Size + $dirinfo[2] = $regs[3]; // Date + $dirinfo[3] = $regs[4]; // Filename + $dirinfo[4] = $regs[5]; // Time + } + + if ($dirinfo[0] != 1 && $dirinfo[4] == $filename) + { + $found = true; + } + } + + @ftp_quit($conn_id); + + return $found; + } +} + +/** +* Physical Filename stored already ? +*/ +function physical_filename_already_stored($filename) +{ + if ($filename == '') + { + return false; + } + + $filename = basename($filename); + + $sql = 'SELECT attach_id + FROM ' . BB_ATTACHMENTS_DESC . " + WHERE physical_filename = '" . attach_mod_sql_escape($filename) . "' + LIMIT 1"; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get attachment information for filename: ' . htmlspecialchars($filename), '', __LINE__, __FILE__, $sql); + } + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + return ($num_rows == 0) ? false : true; +} + +/** +* get all attachments from a post (could be an post array too) +*/ +function get_attachments_from_post($post_id_array) +{ + global $attach_config; + + $attachments = array(); + + if (!is_array($post_id_array)) + { + if (empty($post_id_array)) + { + return $attachments; + } + + $post_id = intval($post_id_array); + + $post_id_array = array(); + $post_id_array[] = $post_id; + } + + $post_id_array = implode(', ', array_map('intval', $post_id_array)); + + if ($post_id_array == '') + { + return $attachments; + } + + $display_order = (intval($attach_config['display_order']) == 0) ? 'DESC' : 'ASC'; + + $sql = 'SELECT a.post_id, d.* + FROM ' . BB_ATTACHMENTS . ' a, ' . BB_ATTACHMENTS_DESC . " d + WHERE a.post_id IN ($post_id_array) + AND a.attach_id = d.attach_id + ORDER BY d.filetime $display_order"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Attachment Informations for post number ' . $post_id_array, '', __LINE__, __FILE__, $sql); + } + + $num_rows = DB()->num_rows($result); + $attachments = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if ($num_rows == 0) + { + return array(); + } + + return $attachments; +} + +/** +* Count Filesize of Attachments in Database based on the attachment id +*/ +function get_total_attach_filesize($attach_ids) +{ + if (!is_array($attach_ids) || !sizeof($attach_ids)) + { + return 0; + } + + $attach_ids = implode(', ', array_map('intval', $attach_ids)); + + if (!$attach_ids) + { + return 0; + } + + $sql = 'SELECT filesize + FROM ' . BB_ATTACHMENTS_DESC . " + WHERE attach_id IN ($attach_ids)"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query Total Filesize', '', __LINE__, __FILE__, $sql); + } + + $total_filesize = 0; + + while ($row = DB()->sql_fetchrow($result)) + { + $total_filesize += (int) $row['filesize']; + } + DB()->sql_freeresult($result); + + return $total_filesize; +} + +/** +* Get allowed Extensions and their respective Values +*/ +function get_extension_informations() +{ + return $GLOBALS['datastore']->get('attach_extensions'); +} + +// +// Sync Topic +// +function attachment_sync_topic ($topics) +{ + if (is_array($topics)) + { + $topics = join(',', $topics); + } + $posts_without_attach = $topics_without_attach = array(); + + // Check orphan post_attachment markers + $sql = "SELECT p.post_id + FROM ". BB_POSTS ." p + LEFT JOIN ". BB_ATTACHMENTS ." a USING(post_id) + WHERE p.topic_id IN($topics) + AND p.post_attachment = 1 + AND a.post_id IS NULL"; + + if ($rowset = DB()->fetch_rowset($sql)) + { + foreach ($rowset as $row) + { + $posts_without_attach[] = $row['post_id']; + } + if ($posts_sql = join(',', $posts_without_attach)) + { + DB()->query("UPDATE ". BB_POSTS ." SET post_attachment = 0 WHERE post_id IN($posts_sql)"); + } + } + + // Update missing topic_attachment markers + DB()->query(" + UPDATE ". BB_TOPICS ." t, ". BB_POSTS ." p SET + t.topic_attachment = 1 + WHERE p.topic_id IN($topics) + AND p.post_attachment = 1 + AND p.topic_id = t.topic_id + "); + + // Fix orphan topic_attachment markers + $sql = "SELECT t.topic_id + FROM ". BB_POSTS ." p, ". BB_TOPICS ." t + WHERE t.topic_id = p.topic_id + AND t.topic_id IN($topics) + AND t.topic_attachment = 1 + GROUP BY p.topic_id + HAVING SUM(p.post_attachment) = 0"; + + if ($rowset = DB()->fetch_rowset($sql)) + { + foreach ($rowset as $row) + { + $topics_without_attach[] = $row['topic_id']; + } + if ($topics_sql = join(',', $topics_without_attach)) + { + DB()->query("UPDATE ". BB_TOPICS ." SET topic_attachment = 0 WHERE topic_id IN($topics_sql)"); + } + } +} + +/** +* Get Extension +*/ +function get_extension($filename) +{ + if (!stristr($filename, '.')) + { + return ''; + } + $extension = strrchr(strtolower($filename), '.'); + $extension[0] = ' '; + $extension = strtolower(trim($extension)); + if (is_array($extension)) + { + return ''; + } + else + { + return $extension; + } +} + +/** +* Delete Extension +*/ +function delete_extension($filename) +{ + return substr($filename, 0, strrpos(strtolower(trim($filename)), '.')); +} + +/** +* Check if a user is within Group +*/ +function user_in_group($user_id, $group_id) +{ + $user_id = (int) $user_id; + $group_id = (int) $group_id; + + if (!$user_id || !$group_id) + { + return false; + } + + $sql = 'SELECT u.group_id + FROM ' . BB_USER_GROUP . ' u, ' . BB_GROUPS . " g + WHERE g.group_single_user = 0 + AND u.group_id = g.group_id + AND u.user_id = $user_id + AND g.group_id = $group_id + LIMIT 1"; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get User Group', '', __LINE__, __FILE__, $sql); + } + + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_rows == 0) + { + return false; + } + + return true; +} + +/** +* Realpath replacement for attachment mod +*/ +function amod_realpath($path) +{ + return (function_exists('realpath')) ? realpath($path) : $path; +} + +/** +* _set_var +* +* Set variable, used by {@link get_var the get_var function} +* +* @private +*/ +function _set_var(&$result, $var, $type, $multibyte = false) +{ + settype($var, $type); + $result = $var; + + if ($type == 'string') + { + $result = trim(str_replace(array("\r\n", "\r", '\xFF'), array("\n", "\n", ' '), $result)); + // 2.0.x is doing addslashes on all variables + $result = stripslashes($result); + if ($multibyte) + { + $result = preg_replace('#&(\#[0-9]+;)#', '&\1', $result); + } + } +} + +/** +* get_var +* +* Used to get passed variable +*/ +function get_var($var_name, $default, $multibyte = false) +{ + $request_var = (isset($_POST[$var_name])) ? $_POST : $_GET; + + if (!isset($request_var[$var_name]) || (is_array($request_var[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($request_var[$var_name]))) + { + return (is_array($default)) ? array() : $default; + } + + $var = $request_var[$var_name]; + + if (!is_array($default)) + { + $type = gettype($default); + } + else + { + list($key_type, $type) = each($default); + $type = gettype($type); + $key_type = gettype($key_type); + } + + if (is_array($var)) + { + $_var = $var; + $var = array(); + + foreach ($_var as $k => $v) + { + if (is_array($v)) + { + foreach ($v as $_k => $_v) + { + _set_var($k, $k, $key_type); + _set_var($_k, $_k, $key_type); + _set_var($var[$k][$_k], $_v, $type, $multibyte); + } + } + else + { + _set_var($k, $k, $key_type); + _set_var($var[$k], $v, $type, $multibyte); + } + } + } + else + { + _set_var($var, $var, $type, $multibyte); + } + + return $var; +} + +/** +* Escaping SQL +*/ +function attach_mod_sql_escape($text) +{ + switch (SQL_LAYER) + { + case 'postgresql': + return pg_escape_string($text); + break; + + case 'mysql': + case 'mysql4': + if (function_exists('mysql_real_escape_string')) + { + return DB()->escape_string($text); + } + else + { + return str_replace("'", "''", str_replace('\\', '\\\\', $text)); + } + break; + + default: + return str_replace("'", "''", str_replace('\\', '\\\\', $text)); + break; + } +} + +/** +* Build sql statement from array for insert/update/select statements +* +* Idea for this from Ikonboard +* Possible query values: INSERT, INSERT_SELECT, MULTI_INSERT, UPDATE, SELECT +*/ +function attach_mod_sql_build_array($query, $assoc_ary = false) +{ + if (!is_array($assoc_ary)) + { + return false; + } + + $fields = array(); + $values = array(); + if ($query == 'INSERT' || $query == 'INSERT_SELECT') + { + foreach ($assoc_ary as $key => $var) + { + $fields[] = $key; + + if (is_null($var)) + { + $values[] = 'NULL'; + } + else if (is_string($var)) + { + $values[] = "'" . attach_mod_sql_escape($var) . "'"; + } + else if (is_array($var) && is_string($var[0])) + { + $values[] = $var[0]; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + + $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; + } + else if ($query == 'MULTI_INSERT') + { + $ary = array(); + foreach ($assoc_ary as $id => $sql_ary) + { + $values = array(); + foreach ($sql_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = 'NULL'; + } + elseif (is_string($var)) + { + $values[] = "'" . attach_mod_sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? intval($var) : $var; + } + } + $ary[] = '(' . implode(', ', $values) . ')'; + } + + $query = ' (' . implode(', ', array_keys($assoc_ary[0])) . ') VALUES ' . implode(', ', $ary); + } + else if ($query == 'UPDATE' || $query == 'SELECT') + { + $values = array(); + foreach ($assoc_ary as $key => $var) + { + if (is_null($var)) + { + $values[] = "$key = NULL"; + } + elseif (is_string($var)) + { + $values[] = "$key = '" . attach_mod_sql_escape($var) . "'"; + } + else + { + $values[] = (is_bool($var)) ? "$key = " . intval($var) : "$key = $var"; + } + } + $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); + } + + return $query; +} \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_delete.php b/upload/attach_mod/includes/functions_delete.php new file mode 100644 index 000000000..4a6d9e9a3 --- /dev/null +++ b/upload/attach_mod/includes/functions_delete.php @@ -0,0 +1,309 @@ +sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select ids', '', __LINE__, __FILE__, $sql); + } + + $num_post_list = DB()->num_rows($result); + + if ($num_post_list == 0) + { + DB()->sql_freeresult($result); + return; + } + + while ($row = DB()->sql_fetchrow($result)) + { + $post_id_array[] = intval($row[$p_id]); + } + DB()->sql_freeresult($result); + } + + if (!is_array($post_id_array)) + { + if (trim($post_id_array) == '') + { + return; + } + + if (strstr($post_id_array, ', ')) + { + $post_id_array = explode(', ', $post_id_array); + } + else if (strstr($post_id_array, ',')) + { + $post_id_array = explode(',', $post_id_array); + } + else + { + $post_id = intval($post_id_array); + + $post_id_array = array(); + $post_id_array[] = $post_id; + } + } + + if (!sizeof($post_id_array)) + { + return; + } + + // First of all, determine the post id and attach_id + if ($attach_id_array === 0) + { + $attach_id_array = array(); + + // Get the attach_ids to fill the array + $whereclause = 'WHERE post_id IN (' . implode(', ', $post_id_array) . ')'; + + $sql = 'SELECT attach_id + FROM ' . BB_ATTACHMENTS . " $whereclause + GROUP BY attach_id"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select Attachment Ids', '', __LINE__, __FILE__, $sql); + } + + $num_attach_list = DB()->num_rows($result); + + if ($num_attach_list == 0) + { + DB()->sql_freeresult($result); + return; + } + + while ($row = DB()->sql_fetchrow($result)) + { + $attach_id_array[] = (int) $row['attach_id']; + } + DB()->sql_freeresult($result); + } + + if (!is_array($attach_id_array)) + { + if (strstr($attach_id_array, ', ')) + { + $attach_id_array = explode(', ', $attach_id_array); + } + else if (strstr($attach_id_array, ',')) + { + $attach_id_array = explode(',', $attach_id_array); + } + else + { + $attach_id = intval($attach_id_array); + + $attach_id_array = array(); + $attach_id_array[] = $attach_id; + } + } + + if (!sizeof($attach_id_array)) + { + return; + } + + $sql_id = 'post_id'; + + if (sizeof($post_id_array) && sizeof($attach_id_array)) + { + $sql = 'DELETE FROM ' . BB_ATTACHMENTS . ' + WHERE attach_id IN (' . implode(', ', $attach_id_array) . ") + AND $sql_id IN (" . implode(', ', $post_id_array) . ')'; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, $lang['ERROR_DELETED_ATTACHMENTS'], '', __LINE__, __FILE__, $sql); + } + + //bt + if ($sql_id == 'post_id') + { + // XBTT + if($bb_cfg['announce_type'] == 'xbt') + { + $sql = "INSERT INTO ". BB_BT_TORRENTS ."_del (topic_id, info_hash) + SELECT topic_id, info_hash + FROM ". BB_BT_TORRENTS ." + WHERE attach_id IN(". implode(',', $attach_id_array) .") ON DUPLICATE KEY UPDATE is_del=1"; + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, $lang['Error_deleted_attachments'], '', __LINE__, __FILE__, $sql); + } + } + // XBTT END. + + $sql = "SELECT topic_id + FROM ". BB_BT_TORRENTS ." + WHERE attach_id IN(". implode(',', $attach_id_array) .")"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, $lang['ERROR_DELETED_ATTACHMENTS'], '', __LINE__, __FILE__, $sql); + } + + $torrents_sql = array(); + + while ($row = DB()->sql_fetchrow($result)) + { + $torrents_sql[] = $row['topic_id']; + } + + if ($torrents_sql = implode(',', $torrents_sql)) + { + // Remove peers from tracker + $sql = "DELETE FROM ". BB_BT_TRACKER ." + WHERE topic_id IN($torrents_sql)"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete peers', '', __LINE__, __FILE__, $sql); + } + } + // Delete torrents + $sql = "DELETE FROM ". BB_BT_TORRENTS ." + WHERE attach_id IN(". implode(',', $attach_id_array) .")"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, $lang['ERROR_DELETED_ATTACHMENTS'], '', __LINE__, __FILE__, $sql); + } + } + //bt end + + for ($i = 0; $i < sizeof($attach_id_array); $i++) + { + $sql = 'SELECT attach_id + FROM ' . BB_ATTACHMENTS . ' + WHERE attach_id = ' . (int) $attach_id_array[$i]; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select Attachment Ids', '', __LINE__, __FILE__, $sql); + } + + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_rows == 0) + { + $sql = 'SELECT attach_id, physical_filename, thumbnail + FROM ' . BB_ATTACHMENTS_DESC . ' + WHERE attach_id = ' . (int) $attach_id_array[$i]; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attach description table', '', __LINE__, __FILE__, $sql); + } + $num_rows = DB()->num_rows($result); + + if ($num_rows != 0) + { + $num_attach = $num_rows; + $attachments = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + // delete attachments + for ($j = 0; $j < $num_attach; $j++) + { + unlink_attach($attachments[$j]['physical_filename']); + + if (intval($attachments[$j]['thumbnail']) == 1) + { + unlink_attach($attachments[$j]['physical_filename'], MODE_THUMBNAIL); + } + + $sql = 'DELETE FROM ' . BB_ATTACHMENTS_DESC . ' + WHERE attach_id = ' . (int) $attachments[$j]['attach_id']; + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, $lang['ERROR_DELETED_ATTACHMENTS'], '', __LINE__, __FILE__, $sql); + } + } + } + else + { + DB()->sql_freeresult($result); + } + } + } + } + + // Now Sync the Topic/PM + if (sizeof($post_id_array)) + { + $sql = 'SELECT topic_id + FROM ' . BB_POSTS . ' + WHERE post_id IN (' . implode(', ', $post_id_array) . ') + GROUP BY topic_id'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t select Topic ID', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + attachment_sync_topic($row['topic_id']); + } + DB()->sql_freeresult($result); + } +} \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_filetypes.php b/upload/attach_mod/includes/functions_filetypes.php new file mode 100644 index 000000000..9c42cdd5f --- /dev/null +++ b/upload/attach_mod/includes/functions_filetypes.php @@ -0,0 +1,410 @@ += 4294967294) + { + $value -= 4294967296; + } + + return $value; +} + +/** +* Read Word (2 Bytes) from File - Note: It's an Intel Word +*/ +function read_word($fp) +{ + $data = fread($fp, 2); + + $value = ord($data[1]) * 256 + ord($data[0]); + + return $value; +} + +/** +* Read Byte +*/ +function read_byte($fp) +{ + $data = fread($fp, 1); + + $value = ord($data); + + return $value; +} + +/** +* Get Image Dimensions +*/ +function image_getdimension($file) +{ + + $size = @getimagesize($file); + + if ($size[0] != 0 || $size[1] != 0) + { + return $size; + } + + // Try to get the Dimension manually, depending on the mimetype + $fp = @fopen($file, 'rb'); + if (!$fp) + { + return $size; + } + + $error = FALSE; + + // BMP - IMAGE + + $tmp_str = fread($fp, 2); + if ($tmp_str == 'BM') + { + $length = read_longint($fp); + + if ($length <= 6) + { + $error = true; + } + + if (!$error) + { + $i = read_longint($fp); + if ( $i != 0) + { + $error = true; + } + } + + if (!$error) + { + $i = read_longint($fp); + + if ($i != 0x3E && $i != 0x76 && $i != 0x436 && $i != 0x36) + { + $error = true; + } + } + + if (!$error) + { + $tmp_str = fread($fp, 4); + $width = read_longint($fp); + $height = read_longint($fp); + + if ($width > 3000 || $height > 3000) + { + $error = true; + } + } + } + else + { + $error = true; + } + + if (!$error) + { + fclose($fp); + return array( + $width, + $height, + 6 + ); + } + + $error = false; + fclose($fp); + + // GIF - IMAGE + + $fp = @fopen($file, 'rb'); + + $tmp_str = fread($fp, 3); + + if ($tmp_str == 'GIF') + { + $tmp_str = fread($fp, 3); + $width = read_word($fp); + $height = read_word($fp); + + $info_byte = fread($fp, 1); + $info_byte = ord($info_byte); + if (($info_byte & 0x80) != 0x80 && ($info_byte & 0x80) != 0) + { + $error = true; + } + + if (!$error) + { + if (($info_byte & 8) != 0) + { + $error = true; + } + + } + } + else + { + $error = true; + } + + if (!$error) + { + fclose($fp); + return array( + $width, + $height, + 1 + ); + } + + $error = false; + fclose($fp); + + // JPG - IMAGE + $fp = @fopen($file, 'rb'); + + $tmp_str = fread($fp, 4); + $w1 = read_word($fp); + + if (intval($w1) < 16) + { + $error = true; + } + + if (!$error) + { + $tmp_str = fread($fp, 4); + if ($tmp_str == 'JFIF') + { + $o_byte = fread($fp, 1); + if (intval($o_byte) != 0) + { + $error = true; + } + + if (!$error) + { + $str = fread($fp, 2); + $b = read_byte($fp); + + if ($b != 0 && $b != 1 && $b != 2) + { + $error = true; + } + } + + if (!$error) + { + $width = read_word($fp); + $height = read_word($fp); + + if ($width <= 0 || $height <= 0) + { + $error = true; + } + } + } + } + else + { + $error = true; + } + + if (!$error) + { + fclose($fp); + return array( + $width, + $height, + 2 + ); + } + + $error = false; + fclose($fp); + + // PCX - IMAGE + + $fp = @fopen($file, 'rb'); + + $tmp_str = fread($fp, 3); + + if ((ord($tmp_str[0]) == 10) && (ord($tmp_str[1]) == 0 || ord($tmp_str[1]) == 2 || ord($tmp_str[1]) == 3 || ord($tmp_str[1]) == 4 || ord($tmp_str[1]) == 5) && (ord($tmp_str[2]) == 1)) + { + $b = fread($fp, 1); + + if (ord($b) != 1 && ord($b) != 2 && ord($b) != 4 && ord($b) != 8 && ord($b) != 24) + { + $error = true; + } + + if (!$error) + { + $xmin = read_word($fp); + $ymin = read_word($fp); + $xmax = read_word($fp); + $ymax = read_word($fp); + $tmp_str = fread($fp, 52); + + $b = fread($fp, 1); + if ($b != 0) + { + $error = true; + } + } + + if (!$error) + { + $width = $xmax - $xmin + 1; + $height = $ymax - $ymin + 1; + } + } + else + { + $error = true; + } + + if (!$error) + { + fclose($fp); + return array( + $width, + $height, + 7 + ); + } + + fclose($fp); + + return $size; +} + +/** +* Flash MX Support +* Routines and Methods are from PhpAdsNew (www.sourceforge.net/projects/phpadsnew) +*/ + +/** +*/ +define('swf_tag_compressed', chr(0x43).chr(0x57).chr(0x53)); +define('swf_tag_identify', chr(0x46).chr(0x57).chr(0x53)); + +/** +* Get flash bits +*/ +function swf_bits($buffer, $pos, $count) +{ + $result = 0; + + for ($loop = $pos; $loop < $pos + $count; $loop++) + { + $result = $result + ((((ord($buffer[(int)($loop / 8)])) >> (7 - ($loop % 8))) & 0x01) << ($count - ($loop - $pos) - 1)); + } + + return $result; +} + +/** +* decompress flash contents +*/ +function swf_decompress($buffer) +{ + if ((function_exists('gzuncompress')) && (substr($buffer, 0, 3) == swf_tag_compressed) && (ord(substr($buffer, 3, 1)) >= 6) ) + { + // Only decompress relevant Informations + $output = 'F'; + $output .= substr ($buffer, 1, 7); + $output .= gzuncompress (substr ($buffer, 8)); + + return $output; + } + else + { + return $buffer; + } +} + +/** +* Get flash dimension +*/ +function swf_getdimension($file) +{ + $size = @getimagesize($file); + + if ($size[0] != 0 || $size[1] != 0) + { + return $size; + } + + // Try to get the Dimension manually + $fp = @fopen($file, 'rb'); + if (!$fp) + { + return $size; + } + + $error = false; + + // SWF - FLASH FILE + $fp = @fopen($file, 'rb'); + + // Decompress if file is a Flash MX compressed file + $buffer = fread($fp, 1024); + + if (substr($buffer, 0, 3) == swf_tag_identify || substr($buffer, 0, 3) == swf_tag_compressed) + { + if (substr($buffer, 0, 3) == swf_tag_compressed) + { + fclose($fp); + $fp = @fopen($file, 'rb'); + $buffer = fread($fp, filesize($file)); + $buffer = swf_decompress($buffer); + } + + // Get size of rect structure + $bits = swf_bits ($buffer, 64, 5); + + // Get rect + $width = (int)(swf_bits ($buffer, 69 + $bits, $bits) - swf_bits ($buffer, 69, $bits)) / 20; + $height = (int)(swf_bits ($buffer, 69 + (3 * $bits), $bits) - swf_bits ($buffer, 69 + (2 * $bits), $bits)) / 20; + } + else + { + $error = true; + } + + if (!$error) + { + fclose($fp); + return array( + $width, + $height, + 2 + ); + } + + fclose($fp); + + return $size; +} \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_includes.php b/upload/attach_mod/includes/functions_includes.php new file mode 100644 index 000000000..c7fbde396 --- /dev/null +++ b/upload/attach_mod/includes/functions_includes.php @@ -0,0 +1,472 @@ +Rules)'; +// $s_auth_can .= ( ( $is_auth['auth_attachments'] ) ? $rules_link . ' ' . $lang['RULES_ATTACH_CAN'] : $lang['RULES_ATTACH_CANNOT'] ) . '
'; + $s_auth_can .= (($is_auth['auth_attachments']) ? $lang['RULES_ATTACH_CAN'] : $lang['RULES_ATTACH_CANNOT'] ) . '
'; + + $s_auth_can .= (($is_auth['auth_download']) ? $lang['RULES_DOWNLOAD_CAN'] : $lang['RULES_DOWNLOAD_CANNOT'] ) . '
'; +} + +/** +* Called from admin_users.php and admin_groups.php in order to process Quota Settings (admin/admin_users.php:admin/admin_groups.php) +*/ +function attachment_quota_settings($admin_mode, $submit = false, $mode) +{ + global $template, $lang, $attach_config; + + if (!intval($attach_config['allow_ftp_upload'])) + { + if ($attach_config['upload_dir'][0] == '/' || ($attach_config['upload_dir'][0] != '/' && $attach_config['upload_dir'][1] == ':')) + { + $upload_dir = $attach_config['upload_dir']; + } + else + { + $upload_dir = BB_ROOT . $attach_config['upload_dir']; + } + } + else + { + $upload_dir = $attach_config['download_path']; + } + + include(BB_ROOT .'attach_mod/includes/functions_selects.php'); + if (!function_exists("process_quota_settings")) + include(BB_ROOT . 'attach_mod/includes/functions_admin.php'); + + $user_id = 0; + + if ($admin_mode == 'user') + { + // We overwrite submit here... to be sure + $submit = (isset($_POST['submit'])) ? true : false; + + if (!$submit && $mode != 'save') + { + $user_id = get_var(POST_USERS_URL, 0); + $u_name = get_var('username', ''); + + if (!$user_id && !$u_name) + { + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED'] ); + } + + if ($user_id) + { + $this_userdata['user_id'] = $user_id; + } + else + { + // Get userdata is handling the sanitizing of username + $this_userdata = get_userdata($_POST['username'], true); + } + + $user_id = (int) $this_userdata['user_id']; + } + else + { + $user_id = get_var('id', 0); + + if (!$user_id) + { + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED'] ); + } + } + } + + if ($admin_mode == 'user' && !$submit && $mode != 'save') + { + // Show the contents + $sql = 'SELECT quota_limit_id, quota_type FROM ' . BB_QUOTA . ' + WHERE user_id = ' . (int) $user_id; + + if( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Unable to get Quota Settings', '', __LINE__, __FILE__, $sql); + } + + $pm_quota = $upload_quota = 0; + + if ($row = DB()->sql_fetchrow($result)) + { + do + { + if ($row['quota_type'] == QUOTA_UPLOAD_LIMIT) + { + $upload_quota = $row['quota_limit_id']; + } + else if ($row['quota_type'] == QUOTA_PM_LIMIT) + { + $pm_quota = $row['quota_limit_id']; + } + } + while ($row = DB()->sql_fetchrow($result)); + } + else + { + // Set Default Quota Limit + $upload_quota = $attach_config['default_upload_quota']; + $pm_quota = $attach_config['default_pm_quota']; + + } + DB()->sql_freeresult($result); + + $template->assign_vars(array( + 'S_SELECT_UPLOAD_QUOTA' => quota_limit_select('user_upload_quota', $upload_quota), + 'S_SELECT_PM_QUOTA' => quota_limit_select('user_pm_quota', $pm_quota), + )); + } + + if ($admin_mode == 'user' && $submit && @$_POST['deleteuser']) + { + process_quota_settings($admin_mode, $user_id, QUOTA_UPLOAD_LIMIT, 0); + process_quota_settings($admin_mode, $user_id, QUOTA_PM_LIMIT, 0); + } + else if ($admin_mode == 'user' && $submit && $mode == 'save') + { + // Get the contents + $upload_quota = get_var('user_upload_quota', 0); + $pm_quota = get_var('user_pm_quota', 0); + + process_quota_settings($admin_mode, $user_id, QUOTA_UPLOAD_LIMIT, $upload_quota); + process_quota_settings($admin_mode, $user_id, QUOTA_PM_LIMIT, $pm_quota); + } + + if ($admin_mode == 'group' && $mode == 'newgroup') + { + return; + } + + if ($admin_mode == 'group' && !$submit && isset($_POST['edit'])) + { + // Get group id again, we do not trust phpBB here, Mods may be installed ;) + $group_id = get_var(POST_GROUPS_URL, 0); + + // Show the contents + $sql = 'SELECT quota_limit_id, quota_type FROM ' . BB_QUOTA . ' + WHERE group_id = ' . (int) $group_id; + + if( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Unable to get Quota Settings', '', __LINE__, __FILE__, $sql); + } + + $pm_quota = $upload_quota = 0; + + if ($row = DB()->sql_fetchrow($result)) + { + do + { + if ($row['quota_type'] == QUOTA_UPLOAD_LIMIT) + { + $upload_quota = $row['quota_limit_id']; + } + else if ($row['quota_type'] == QUOTA_PM_LIMIT) + { + $pm_quota = $row['quota_limit_id']; + } + } + while ($row = DB()->sql_fetchrow($result)); + } + else + { + // Set Default Quota Limit + $upload_quota = $attach_config['default_upload_quota']; + $pm_quota = $attach_config['default_pm_quota']; + } + DB()->sql_freeresult($result); + + $template->assign_vars(array( + 'S_SELECT_UPLOAD_QUOTA' => quota_limit_select('group_upload_quota', $upload_quota), + 'S_SELECT_PM_QUOTA' => quota_limit_select('group_pm_quota', $pm_quota), + )); + } + + if ($admin_mode == 'group' && $submit && isset($_POST['group_delete'])) + { + $group_id = get_var(POST_GROUPS_URL, 0); + + process_quota_settings($admin_mode, $group_id, QUOTA_UPLOAD_LIMIT, 0); + process_quota_settings($admin_mode, $group_id, QUOTA_PM_LIMIT, 0); + } + else if ($admin_mode == 'group' && $submit) + { + $group_id = get_var(POST_GROUPS_URL, 0); + + // Get the contents + $upload_quota = get_var('group_upload_quota', 0); + $pm_quota = get_var('group_pm_quota', 0); + + process_quota_settings($admin_mode, $group_id, QUOTA_UPLOAD_LIMIT, $upload_quota); + process_quota_settings($admin_mode, $group_id, QUOTA_PM_LIMIT, $pm_quota); + } + +} + +/** +* Called from usercp_viewprofile, displays the User Upload Quota Box, Upload Stats and a Link to the User Attachment Control Panel +* Groups are able to be grabbed, but it's not used within the Attachment Mod. ;) +* (includes/usercp_viewprofile.php) +*/ +function display_upload_attach_box_limits($user_id, $group_id = 0) +{ + global $attach_config, $bb_cfg, $lang, $template, $userdata, $profiledata; + + if (intval($attach_config['disable_mod'])) + { + return; + } + + if (!IS_ADMIN && $userdata['user_id'] != $user_id) + { + return; + } + + if (!$user_id) + { + return; + } + + // Return if the user is not within the to be listed Group + if ($group_id) + { + if (!user_in_group($user_id, $group_id)) + { + return; + } + } + + $user_id = (int) $user_id; + $group_id = (int) $group_id; + + $attachments = new attach_posting(); + $attachments->page = 0; + + // Get the assigned Quota Limit. For Groups, we are directly getting the value, because this Quota can change from user to user. + if ($group_id) + { + $sql = 'SELECT l.quota_limit + FROM ' . BB_QUOTA . ' q, ' . BB_QUOTA_LIMITS . ' l + WHERE q.group_id = ' . (int) $group_id . ' + AND q.quota_type = ' . QUOTA_UPLOAD_LIMIT . ' + AND q.quota_limit_id = l.quota_limit_id + LIMIT 1'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Group Quota', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) > 0) + { + $row = DB()->sql_fetchrow($result); + $attach_config['upload_filesize_limit'] = intval($row['quota_limit']); + DB()->sql_freeresult($result); + } + else + { + DB()->sql_freeresult($result); + + // Set Default Quota Limit + $quota_id = intval($attach_config['default_upload_quota']); + + if ($quota_id == 0) + { + $attach_config['upload_filesize_limit'] = $attach_config['attachment_quota']; + } + else + { + $sql = 'SELECT quota_limit + FROM ' . BB_QUOTA_LIMITS . ' + WHERE quota_limit_id = ' . (int) $quota_id . ' + LIMIT 1'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get Quota Limit', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) > 0) + { + $row = DB()->sql_fetchrow($result); + $attach_config['upload_filesize_limit'] = $row['quota_limit']; + } + else + { + $attach_config['upload_filesize_limit'] = $attach_config['attachment_quota']; + } + DB()->sql_freeresult($result); + } + } + } + else + { + if (is_array($profiledata)) + { + $attachments->get_quota_limits($profiledata, $user_id); + } + else + { + $attachments->get_quota_limits($userdata, $user_id); + } + } + + if (!$attach_config['upload_filesize_limit']) + { + $upload_filesize_limit = $attach_config['attachment_quota']; + } + else + { + $upload_filesize_limit = $attach_config['upload_filesize_limit']; + } + + if ($upload_filesize_limit == 0) + { + $user_quota = $lang['UNLIMITED']; + } + else + { + $size_lang = ($upload_filesize_limit >= 1048576) ? $lang['MB'] : ( ($upload_filesize_limit >= 1024) ? $lang['KB'] : $lang['BYTES'] ); + + if ($upload_filesize_limit >= 1048576) + { + $user_quota = (round($upload_filesize_limit / 1048576 * 100) / 100) . ' ' . $size_lang; + } + else if ($upload_filesize_limit >= 1024) + { + $user_quota = (round($upload_filesize_limit / 1024 * 100) / 100) . ' ' . $size_lang; + } + else + { + $user_quota = ($upload_filesize_limit) . ' ' . $size_lang; + } + } + + // Get all attach_id's the specific user posted, but only uploads to the board and not Private Messages + $sql = 'SELECT attach_id + FROM ' . BB_ATTACHMENTS . ' + WHERE user_id_1 = ' . (int) $user_id . ' + GROUP BY attach_id'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $attach_ids = DB()->sql_fetchrowset($result); + $num_attach_ids = DB()->num_rows($result); + DB()->sql_freeresult($result); + $attach_id = array(); + + for ($j = 0; $j < $num_attach_ids; $j++) + { + $attach_id[] = intval($attach_ids[$j]['attach_id']); + } + + $upload_filesize = (sizeof($attach_id) > 0) ? get_total_attach_filesize($attach_id) : 0; + + $size_lang = ($upload_filesize >= 1048576) ? $lang['MB'] : ( ($upload_filesize >= 1024) ? $lang['KB'] : $lang['BYTES'] ); + + if ($upload_filesize >= 1048576) + { + $user_uploaded = (round($upload_filesize / 1048576 * 100) / 100) . ' ' . $size_lang; + } + else if ($upload_filesize >= 1024) + { + $user_uploaded = (round($upload_filesize / 1024 * 100) / 100) . ' ' . $size_lang; + } + else + { + $user_uploaded = ($upload_filesize) . ' ' . $size_lang; + } + + $upload_limit_pct = ( $upload_filesize_limit > 0 ) ? round(( $upload_filesize / $upload_filesize_limit ) * 100) : 0; + $upload_limit_img_length = ( $upload_filesize_limit > 0 ) ? round(( $upload_filesize / $upload_filesize_limit ) * $bb_cfg['privmsg_graphic_length']) : 0; + if ($upload_limit_pct > 100) + { + $upload_limit_img_length = $bb_cfg['privmsg_graphic_length']; + } + $upload_limit_remain = ( $upload_filesize_limit > 0 ) ? $upload_filesize_limit - $upload_filesize : 100; + + $l_box_size_status = sprintf($lang['UPLOAD_PERCENT_PROFILE'], $upload_limit_pct); + + $template->assign_block_vars('switch_upload_limits', array()); + + $template->assign_vars(array( + 'L_UACP' => $lang['UACP'], + 'U_UACP' => BB_ROOT ."profile.php?mode=attachcp&u=$user_id&sid={$userdata['session_id']}", + 'UPLOADED' => sprintf($lang['USER_UPLOADED_PROFILE'], $user_uploaded), + 'QUOTA' => sprintf($lang['USER_QUOTA_PROFILE'], $user_quota), + 'UPLOAD_LIMIT_IMG_WIDTH' => $upload_limit_img_length, + 'UPLOAD_LIMIT_PERCENT' => $upload_limit_pct, + 'PERCENT_FULL' => $l_box_size_status, + )); +} + +/** +* Prune Attachments (includes/prune.php) +*/ +function prune_attachments($sql_post) +{ + delete_attachment($sql_post); +} \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_selects.php b/upload/attach_mod/includes/functions_selects.php new file mode 100644 index 000000000..5e3d45783 --- /dev/null +++ b/upload/attach_mod/includes/functions_selects.php @@ -0,0 +1,266 @@ +sql_query($sql))) + { + message_die(GENERAL_ERROR, "Couldn't query Extension Groups Table", "", __LINE__, __FILE__, $sql); + } + + $group_select = ''; + + return $group_select; +} + +/** +* select download mode +*/ +function download_select($select_name, $group_id = 0) +{ + global $types_download, $modes_download; + + if ($group_id) + { + $sql = 'SELECT download_mode + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE group_id = ' . (int) $group_id; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, "Couldn't query Extension Groups Table", "", __LINE__, __FILE__, $sql); + } + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (!isset($row['download_mode'])) + { + return ''; + } + + $download_mode = $row['download_mode']; + } + + $group_select = ''; + + return $group_select; +} + +/** +* select category types +*/ +function category_select($select_name, $group_id = 0) +{ + global $types_category, $modes_category; + + $sql = 'SELECT group_id, cat_id + FROM ' . BB_EXTENSION_GROUPS; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Couldn't select Category", "", __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + $type_category = 0; + + if ($num_rows > 0) + { + for ($i = 0; $i < $num_rows; $i++) + { + if ($group_id == $rows[$i]['group_id']) + { + $category_type = $rows[$i]['cat_id']; + } + } + } + + $types = array(NONE_CAT); + $modes = array('none'); + + for ($i = 0; $i < sizeof($types_category); $i++) + { + $types[] = $types_category[$i]; + $modes[] = $modes_category[$i]; + } + + $group_select = ''; + + return $group_select; +} + +/** +* Select size mode +*/ +function size_select($select_name, $size_compare) +{ + global $lang; + + $size_types_text = array($lang['BYTES'], $lang['KB'], $lang['MB']); + $size_types = array('b', 'kb', 'mb'); + + $select_field = ''; + + return $select_field; +} + +/** +* select quota limit +*/ +function quota_limit_select($select_name, $default_quota = 0) +{ + global $lang; + + $sql = 'SELECT quota_limit_id, quota_desc + FROM ' . BB_QUOTA_LIMITS . ' + ORDER BY quota_limit ASC'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Couldn't query Quota Limits Table", "", __LINE__, __FILE__, $sql); + } + + $quota_select = ''; + + return $quota_select; +} + +/** +* select default quota limit +*/ +function default_quota_limit_select($select_name, $default_quota = 0) +{ + global $lang; + + $sql = 'SELECT quota_limit_id, quota_desc + FROM ' . BB_QUOTA_LIMITS . ' + ORDER BY quota_limit ASC'; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Couldn't query Quota Limits Table", "", __LINE__, __FILE__, $sql); + } + + $quota_select = ''; + + return $quota_select; +} \ No newline at end of file diff --git a/upload/attach_mod/includes/functions_thumbs.php b/upload/attach_mod/includes/functions_thumbs.php new file mode 100644 index 000000000..f8771741c --- /dev/null +++ b/upload/attach_mod/includes/functions_thumbs.php @@ -0,0 +1,247 @@ + $height) + { + return array( + round($width * ($max_width / $width)), + round($height * ($max_width / $width)) + ); + } + else + { + return array( + round($width * ($max_width / $height)), + round($height * ($max_width / $height)) + ); + } +} + +/** +* Check if imagick is present +*/ +function is_imagick() +{ + global $imagick, $attach_config; + + if ($attach_config['img_imagick'] != '') + { + $imagick = $attach_config['img_imagick']; + return true; + } + else + { + return false; + } +} + +/** +* Get supported image types +*/ +function get_supported_image_types($type) +{ + if (@extension_loaded('gd')) + { + $format = imagetypes(); + $new_type = 0; + + switch ($type) + { + case 1: + $new_type = ($format & IMG_GIF) ? IMG_GIF : 0; + break; + case 2: + case 9: + case 10: + case 11: + case 12: + $new_type = ($format & IMG_JPG) ? IMG_JPG : 0; + break; + case 3: + $new_type = ($format & IMG_PNG) ? IMG_PNG : 0; + break; + case 6: + case 15: + $new_type = ($format & IMG_WBMP) ? IMG_WBMP : 0; + break; + } + + return array( + 'gd' => ($new_type) ? true : false, + 'format' => $new_type, + 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1 + ); + } + + return array('gd' => false); +} + +/** +* Create thumbnail +*/ +function create_thumbnail($source, $new_file, $mimetype) +{ + global $attach_config, $imagick; + + $source = amod_realpath($source); + $min_filesize = (int) $attach_config['img_min_thumb_filesize']; + $img_filesize = (@file_exists($source)) ? @filesize($source) : false; + + if (!$img_filesize || $img_filesize <= $min_filesize) + { + return false; + } + + list($width, $height, $type, ) = getimagesize($source); + + if (!$width || !$height) + { + return false; + } + + list($new_width, $new_height) = get_img_size_format($width, $height); + + $tmp_path = $old_file = ''; + + if (intval($attach_config['allow_ftp_upload'])) + { + $old_file = $new_file; + + $tmp_path = explode('/', $source); + $tmp_path[count($tmp_path)-1] = ''; + $tmp_path = implode('/', $tmp_path); + + if ($tmp_path == '') + { + $tmp_path = '/tmp'; + } + + $value = trim($tmp_path); + + if ($value[strlen($value)-1] == '/') + { + $value[strlen($value)-1] = ' '; + } + + // + $new_file = tempnam(trim($value), 't00000'); + + // We remove it now because it gets created again later + @unlink($new_file); + } + + $used_imagick = false; + + if (is_imagick()) + { + passthru($imagick . ' -quality 85 -antialias -sample ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" +profile "*" "' . str_replace('\\', '/', $new_file) . '"'); + if (@file_exists($new_file)) + { + $used_imagick = true; + } + } + + if (!$used_imagick) + { + $type = get_supported_image_types($type); + + if ($type['gd']) + { + switch ($type['format']) + { + case IMG_GIF: + $image = imagecreatefromgif($source); + break; + case IMG_JPG: + $image = imagecreatefromjpeg($source); + break; + case IMG_PNG: + $image = imagecreatefrompng($source); + break; + case IMG_WBMP: + $image = imagecreatefromwbmp($source); + break; + } + + if ($type['version'] == 1 || !$attach_config['use_gd2']) + { + $new_image = imagecreate($new_width, $new_height); + imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); + } + else + { + $new_image = imagecreatetruecolor($new_width, $new_height); + imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); + } + + switch ($type['format']) + { + case IMG_GIF: + imagegif($new_image, $new_file); + break; + case IMG_JPG: + imagejpeg($new_image, $new_file, 90); + break; + case IMG_PNG: + imagepng($new_image, $new_file); + break; + case IMG_WBMP: + imagewbmp($new_image, $new_file); + break; + } + + imagedestroy($new_image); + } + } + + if (!@file_exists($new_file)) + { + return false; + } + + if (intval($attach_config['allow_ftp_upload'])) + { + $result = ftp_file($new_file, $old_file, $mimetype, true); // True for disable error-mode + @unlink($new_file); + + if (!$result) + { + return false; + } + } + else + { + @chmod($new_file, 0664); + } + + return true; +} \ No newline at end of file diff --git a/upload/attach_mod/posting_attachments.php b/upload/attach_mod/posting_attachments.php new file mode 100644 index 000000000..2320db08b --- /dev/null +++ b/upload/attach_mod/posting_attachments.php @@ -0,0 +1,1460 @@ +add_attachment_body = get_var('add_attachment_body', 0); + $this->posted_attachments_body = get_var('posted_attachments_body', 0); + + $this->file_comment = get_var('filecomment', ''); + $this->attachment_id_list = get_var('attach_id_list', array(0)); + $this->attachment_comment_list = get_var('comment_list', array('')); + $this->attachment_filesize_list = get_var('filesize_list', array(0)); + $this->attachment_filetime_list = get_var('filetime_list', array(0)); + $this->attachment_filename_list = get_var('filename_list', array('')); + $this->attachment_extension_list = get_var('extension_list', array('')); + $this->attachment_mimetype_list = get_var('mimetype_list', array('')); + + $this->filename = (isset($_FILES['fileupload']) && isset($_FILES['fileupload']['name']) && $_FILES['fileupload']['name'] != 'none') ? trim(stripslashes($_FILES['fileupload']['name'])) : ''; + + $this->attachment_list = get_var('attachment_list', array('')); + $this->attachment_thumbnail_list = get_var('attach_thumbnail_list', array(0)); + } + + /** + * Get Quota Limits + */ + function get_quota_limits($userdata_quota, $user_id = 0) + { + global $attach_config; + + // + // Define Filesize Limits (Prepare Quota Settings) + // Priority: User, Group, Management + // + // This method is somewhat query intensive, but i think because this one is only executed while attaching a file, + // it does not make much sense to come up with an new db-entry. + // Maybe i will change this in a future version, where you are able to disable the User Quota Feature at all (using + // Default Limits for all Users/Groups) + // + + // Change this to 'group;user' if you want to have first priority on group quota settings. +// $priority = 'group;user'; + $priority = 'user;group'; + + if (IS_ADMIN) + { + $attach_config['pm_filesize_limit'] = 0; // Unlimited + $attach_config['upload_filesize_limit'] = 0; // Unlimited + return; + } + + $quota_type = QUOTA_UPLOAD_LIMIT; + $limit_type = 'upload_filesize_limit'; + $default = 'attachment_quota'; + + if (!$user_id) + { + $user_id = intval($userdata_quota['user_id']); + } + + $priority = explode(';', $priority); + $found = false; + + for ($i = 0; $i < sizeof($priority); $i++) + { + if (($priority[$i] == 'group') && (!$found)) + { + // Get Group Quota, if we find one, we have our quota + $sql = 'SELECT u.group_id + FROM ' . BB_USER_GROUP . ' u, ' . BB_GROUPS . ' g + WHERE g.group_single_user = 0 + AND u.user_pending = 0 + AND u.group_id = g.group_id + AND u.user_id = ' . $user_id; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get User Group', '', __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + if ($num_rows > 0) + { + $group_id = array(); + + for ($j = 0; $j < $num_rows; $j++) + { + $group_id[] = (int) $rows[$j]['group_id']; + } + + $sql = 'SELECT l.quota_limit + FROM ' . BB_QUOTA . ' q, ' . BB_QUOTA_LIMITS . ' l + WHERE q.group_id IN (' . implode(', ', $group_id) . ') + AND q.group_id <> 0 + AND q.quota_type = ' . $quota_type . ' + AND q.quota_limit_id = l.quota_limit_id + ORDER BY l.quota_limit DESC + LIMIT 1'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get Group Quota', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) > 0) + { + $row = DB()->sql_fetchrow($result); + $attach_config[$limit_type] = $row['quota_limit']; + $found = TRUE; + } + DB()->sql_freeresult($result); + } + } + + if ($priority[$i] == 'user' && !$found) + { + // Get User Quota, if the user is not in a group or the group has no quotas + $sql = 'SELECT l.quota_limit + FROM ' . BB_QUOTA . ' q, ' . BB_QUOTA_LIMITS . ' l + WHERE q.user_id = ' . $user_id . ' + AND q.user_id <> 0 + AND q.quota_type = ' . $quota_type . ' + AND q.quota_limit_id = l.quota_limit_id + LIMIT 1'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get User Quota', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) > 0) + { + $row = DB()->sql_fetchrow($result); + $attach_config[$limit_type] = $row['quota_limit']; + $found = TRUE; + } + DB()->sql_freeresult($result); + } + } + + if (!$found) + { + // Set Default Quota Limit + $quota_id = ($quota_type == QUOTA_UPLOAD_LIMIT) ? $attach_config['default_upload_quota'] : $attach_config['default_pm_quota']; + + if ($quota_id == 0) + { + $attach_config[$limit_type] = $attach_config[$default]; + } + else + { + $sql = 'SELECT quota_limit + FROM ' . BB_QUOTA_LIMITS . ' + WHERE quota_limit_id = ' . (int) $quota_id . ' + LIMIT 1'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get Default Quota Limit', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) > 0) + { + $row = DB()->sql_fetchrow($result); + $attach_config[$limit_type] = $row['quota_limit']; + } + else + { + $attach_config[$limit_type] = $attach_config[$default]; + } + DB()->sql_freeresult($result); + } + } + + // Never exceed the complete Attachment Upload Quota + if ($quota_type == QUOTA_UPLOAD_LIMIT) + { + if ($attach_config[$limit_type] > $attach_config[$default]) + { + $attach_config[$limit_type] = $attach_config[$default]; + } + } + } + + /** + * Handle all modes... (intern) + * @private + */ + function handle_attachments($mode) + { + global $is_auth, $attach_config, $refresh, $post_id, $submit, $preview, $error, $error_msg, $lang, $template, $userdata; + + // + // ok, what shall we do ;) + // + + if (IS_ADMIN) + { + $max_attachments = ADMIN_MAX_ATTACHMENTS; + } + else + { + $max_attachments = intval($attach_config['max_attachments']); + } + + $sql_id = 'post_id'; + + // nothing, if the user is not authorized or attachment mod disabled + if (intval($attach_config['disable_mod']) || !$is_auth['auth_attachments']) + { + return false; + } + + // Init Vars + $attachments = array(); + + if (!$refresh) + { + $add = (isset($_POST['add_attachment'])) ? TRUE : FALSE; + $delete = (isset($_POST['del_attachment'])) ? TRUE : FALSE; + $edit = ( isset($_POST['edit_comment']) ) ? TRUE : FALSE; + $update_attachment = ( isset($_POST['update_attachment']) ) ? TRUE : FALSE; + $del_thumbnail = ( isset($_POST['del_thumbnail']) ) ? TRUE : FALSE; + + $add_attachment_box = (!empty($_POST['add_attachment_box'])) ? TRUE : FALSE; + $posted_attachments_box = (!empty($_POST['posted_attachments_box'])) ? TRUE : FALSE; + + $refresh = $add || $delete || $edit || $del_thumbnail || $update_attachment || $add_attachment_box || $posted_attachments_box; + } + + // Get Attachments + $attachments = get_attachments_from_post($post_id); + + $auth = ($is_auth['auth_edit'] || $is_auth['auth_mod']) ? TRUE : FALSE; + + if (!$submit && $mode == 'editpost' && $auth) + { + if (!$refresh && !$preview && !$error && !isset($_POST['del_poll_option'])) + { + for ($i = 0; $i < sizeof($attachments); $i++) + { + $this->attachment_list[] = $attachments[$i]['physical_filename']; + $this->attachment_comment_list[] = $attachments[$i]['comment']; + $this->attachment_filename_list[] = $attachments[$i]['real_filename']; + $this->attachment_extension_list[] = $attachments[$i]['extension']; + $this->attachment_mimetype_list[] = $attachments[$i]['mimetype']; + $this->attachment_filesize_list[] = $attachments[$i]['filesize']; + $this->attachment_filetime_list[] = $attachments[$i]['filetime']; + $this->attachment_id_list[] = $attachments[$i]['attach_id']; + $this->attachment_thumbnail_list[] = $attachments[$i]['thumbnail']; + } + } + } + + $this->num_attachments = sizeof($this->attachment_list); + + if ($submit && $mode != 'vote') + { + if ($mode == 'newtopic' || $mode == 'reply' || $mode == 'editpost') + { + if ($this->filename != '') + { + if ($this->num_attachments < intval($max_attachments)) + { + $this->upload_attachment($this->page); + + if (!$error && $this->post_attach) + { + array_unshift($this->attachment_list, $this->attach_filename); + array_unshift($this->attachment_comment_list, $this->file_comment); + array_unshift($this->attachment_filename_list, $this->filename); + array_unshift($this->attachment_extension_list, $this->extension); + array_unshift($this->attachment_mimetype_list, $this->type); + array_unshift($this->attachment_filesize_list, $this->filesize); + array_unshift($this->attachment_filetime_list, $this->filetime); + array_unshift($this->attachment_id_list, '0'); + array_unshift($this->attachment_thumbnail_list, $this->thumbnail); + + $this->file_comment = ''; + + // This Variable is set to FALSE here, because the Attachment Mod enter Attachments into the + // Database in two modes, one if the id_list is 0 and the second one if post_attach is true + // Since post_attach is automatically switched to true if an Attachment got added to the filesystem, + // but we are assigning an id of 0 here, we have to reset the post_attach variable to FALSE. + // + // This is very relevant, because it could happen that the post got not submitted, but we do not + // know this circumstance here. We could be at the posting page or we could be redirected to the entered + // post. :) + $this->post_attach = FALSE; + } + } + else + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['TOO_MANY_ATTACHMENTS'], intval($max_attachments)); + } + } + } + } + + if ($preview || $refresh || $error) + { + $delete_attachment = ( isset($_POST['del_attachment']) ) ? TRUE : FALSE; + $delete_thumbnail = (isset($_POST['del_thumbnail'])) ? TRUE : FALSE; + + $add_attachment = (isset($_POST['add_attachment'])) ? TRUE : FALSE; + $edit_attachment = (isset($_POST['edit_comment'])) ? TRUE : FALSE; + $update_attachment = (isset($_POST['update_attachment']) ) ? TRUE : FALSE; + + // Perform actions on temporary attachments + if ($delete_attachment || $delete_thumbnail) + { + // store old values + $actual_id_list = get_var('attach_id_list', array(0)); + $actual_comment_list = get_var('comment_list', array('')); + $actual_filename_list = get_var('filename_list', array('')); + $actual_extension_list = get_var('extension_list', array('')); + $actual_mimetype_list = get_var('mimetype_list', array('')); + $actual_filesize_list = get_var('filesize_list', array(0)); + $actual_filetime_list = get_var('filetime_list', array(0)); + + $actual_list = get_var('attachment_list', array('')); + $actual_thumbnail_list = get_var('attach_thumbnail_list', array(0)); + + // clean values + $this->attachment_list = array(); + $this->attachment_comment_list = array(); + $this->attachment_filename_list = array(); + $this->attachment_extension_list = array(); + $this->attachment_mimetype_list = array(); + $this->attachment_filesize_list = array(); + $this->attachment_filetime_list = array(); + $this->attachment_id_list = array(); + $this->attachment_thumbnail_list = array(); + + // restore values :) + if (isset($_POST['attachment_list'])) + { + for ($i = 0; $i < sizeof($actual_list); $i++) + { + $restore = FALSE; + $del_thumb = FALSE; + + if ($delete_thumbnail) + { + if ( !isset($_POST['del_thumbnail'][$actual_list[$i]]) ) + { + $restore = TRUE; + } + else + { + $del_thumb = TRUE; + } + } + if ( $delete_attachment ) + { + if ( !isset($_POST['del_attachment'][$actual_list[$i]]) ) + { + $restore = TRUE; + } + } + + if ( $restore ) + { + $this->attachment_list[] = $actual_list[$i]; + $this->attachment_comment_list[] = $actual_comment_list[$i]; + $this->attachment_filename_list[] = $actual_filename_list[$i]; + $this->attachment_extension_list[] = $actual_extension_list[$i]; + $this->attachment_mimetype_list[] = $actual_mimetype_list[$i]; + $this->attachment_filesize_list[] = $actual_filesize_list[$i]; + $this->attachment_filetime_list[] = $actual_filetime_list[$i]; + $this->attachment_id_list[] = $actual_id_list[$i]; + $this->attachment_thumbnail_list[] = $actual_thumbnail_list[$i]; + } + else if (!$del_thumb) + { + // delete selected attachment + if ($actual_id_list[$i] == '0' ) + { + unlink_attach($actual_list[$i]); + + if ($actual_thumbnail_list[$i] == 1) + { + unlink_attach($actual_list[$i], MODE_THUMBNAIL); + } + } + else + { + delete_attachment($post_id, $actual_id_list[$i], $this->page); + } + } + else if ($del_thumb) + { + // delete selected thumbnail + $this->attachment_list[] = $actual_list[$i]; + $this->attachment_comment_list[] = $actual_comment_list[$i]; + $this->attachment_filename_list[] = $actual_filename_list[$i]; + $this->attachment_extension_list[] = $actual_extension_list[$i]; + $this->attachment_mimetype_list[] = $actual_mimetype_list[$i]; + $this->attachment_filesize_list[] = $actual_filesize_list[$i]; + $this->attachment_filetime_list[] = $actual_filetime_list[$i]; + $this->attachment_id_list[] = $actual_id_list[$i]; + $this->attachment_thumbnail_list[] = 0; + + if ($actual_id_list[$i] == 0) + { + unlink_attach($actual_list[$i], MODE_THUMBNAIL); + } + else + { + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . ' + SET thumbnail = 0 + WHERE attach_id = ' . (int) $actual_id_list[$i]; + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to update ' . BB_ATTACHMENTS_DESC . ' Table.', '', __LINE__, __FILE__, $sql); + } + } + } + } + } + } + else if ($edit_attachment || $update_attachment || $add_attachment || $preview) + { + if ($edit_attachment) + { + $actual_comment_list = get_var('comment_list', array('')); + + $this->attachment_comment_list = array(); + + for ($i = 0; $i < sizeof($this->attachment_list); $i++) + { + $this->attachment_comment_list[$i] = $actual_comment_list[$i]; + } + } + + if ($update_attachment) + { + if ($this->filename == '') + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= $lang['ERROR_EMPTY_ADD_ATTACHBOX']; + } + + $this->upload_attachment($this->page); + + if (!$error) + { + $actual_list = get_var('attachment_list', array('')); + $actual_id_list = get_var('attach_id_list', array(0)); + + $attachment_id = 0; + $actual_element = 0; + + for ($i = 0; $i < sizeof($actual_id_list); $i++) + { + if (isset($_POST['update_attachment'][$actual_id_list[$i]])) + { + $attachment_id = intval($actual_id_list[$i]); + $actual_element = $i; + } + } + + // Get current informations to delete the Old Attachment + $sql = 'SELECT physical_filename, comment, thumbnail + FROM ' . BB_ATTACHMENTS_DESC . ' + WHERE attach_id = ' . (int) $attachment_id; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to select old Attachment Entry.', '', __LINE__, __FILE__, $sql); + } + + if (DB()->num_rows($result) != 1) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= $lang['ERROR_MISSING_OLD_ENTRY']; + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $comment = (trim($this->file_comment) == '') ? trim($row['comment']) : trim($this->file_comment); + + // Update Entry + $sql_ary = array( + 'physical_filename' => (string) basename($this->attach_filename), + 'real_filename' => (string) basename($this->filename), + 'comment' => (string) $comment, + 'extension' => (string) strtolower($this->extension), + 'mimetype' => (string) strtolower($this->type), + 'filesize' => (int) $this->filesize, + 'filetime' => (int) $this->filetime, + 'thumbnail' => (int) $this->thumbnail + ); + + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . ' SET ' . attach_mod_sql_build_array('UPDATE', $sql_ary) . ' + WHERE attach_id = ' . (int) $attachment_id; + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to update the Attachment.', '', __LINE__, __FILE__, $sql); + } + + // Delete the Old Attachment + unlink_attach($row['physical_filename']); + + if (intval($row['thumbnail']) == 1) + { + unlink_attach($row['physical_filename'], MODE_THUMBNAIL); + } + + //bt + if ($this->attachment_extension_list[$actual_element] === TORRENT_EXT && $attachments[$actual_element]['tracker_status']) + { + include(INC_DIR .'functions_torrent.php'); + tracker_unregister($attachment_id); + } + //bt end + + // Make sure it is displayed + $this->attachment_list[$actual_element] = $this->attach_filename; + $this->attachment_comment_list[$actual_element] = $comment; + $this->attachment_filename_list[$actual_element] = $this->filename; + $this->attachment_extension_list[$actual_element] = $this->extension; + $this->attachment_mimetype_list[$actual_element] = $this->type; + $this->attachment_filesize_list[$actual_element] = $this->filesize; + $this->attachment_filetime_list[$actual_element] = $this->filetime; + $this->attachment_id_list[$actual_element] = $actual_id_list[$actual_element]; + $this->attachment_thumbnail_list[$actual_element] = $this->thumbnail; + $this->file_comment = ''; + + } + } + + if (($add_attachment || $preview) && $this->filename != '') + { + if ($this->num_attachments < intval($max_attachments)) + { + $this->upload_attachment($this->page); + + if (!$error) + { + array_unshift($this->attachment_list, $this->attach_filename); + array_unshift($this->attachment_comment_list, $this->file_comment); + array_unshift($this->attachment_filename_list, $this->filename); + array_unshift($this->attachment_extension_list, $this->extension); + array_unshift($this->attachment_mimetype_list, $this->type); + array_unshift($this->attachment_filesize_list, $this->filesize); + array_unshift($this->attachment_filetime_list, $this->filetime); + array_unshift($this->attachment_id_list, '0'); + array_unshift($this->attachment_thumbnail_list, $this->thumbnail); + + $this->file_comment = ''; + } + } + else + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['TOO_MANY_ATTACHMENTS'], intval($max_attachments)); + } + } + } + } + + return TRUE; + } + + /** + * Basic Insert Attachment Handling for all Message Types + */ + function do_insert_attachment($mode, $message_type, $message_id) + { + global $upload_dir; + + if (intval($message_id) < 0) + { + return FALSE; + } + + global $post_info, $userdata; + + $post_id = (int) $message_id; + $user_id_1 = (isset($post_info['poster_id'])) ? (int) $post_info['poster_id'] : 0; + + if (!$user_id_1) + { + $user_id_1 = (int) $userdata['user_id']; + } + + if ($mode == 'attach_list') + { + for ($i = 0; $i < sizeof($this->attachment_list); $i++) + { + if ($this->attachment_id_list[$i]) + { + // update entry in db if attachment already stored in db and filespace + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . " + SET comment = '" . @attach_mod_sql_escape($this->attachment_comment_list[$i]) . "' + WHERE attach_id = " . $this->attachment_id_list[$i]; + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to update the File Comment.', '', __LINE__, __FILE__, $sql); + } + } + else + { + if (empty($this->attachment_mimetype_list[$i]) && $this->attachment_extension_list[$i] === TORRENT_EXT) + { + $this->attachment_mimetype_list[$i] = 'application/x-bittorrent'; + } + + // insert attachment into db + $sql_ary = array( + 'physical_filename' => (string) basename($this->attachment_list[$i]), + 'real_filename' => (string) basename($this->attachment_filename_list[$i]), + 'comment' => (string) @$this->attachment_comment_list[$i], + 'extension' => (string) strtolower($this->attachment_extension_list[$i]), + 'mimetype' => (string) strtolower($this->attachment_mimetype_list[$i]), + 'filesize' => (int) $this->attachment_filesize_list[$i], + 'filetime' => (int) $this->attachment_filetime_list[$i], + 'thumbnail' => (int) $this->attachment_thumbnail_list[$i] + ); + + $sql = 'INSERT INTO ' . BB_ATTACHMENTS_DESC . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t store Attachment.
Your ' . $message_type . ' has been stored.', '', __LINE__, __FILE__, $sql); + } + + $attach_id = DB()->sql_nextid(); + + //bt + if ($this->attachment_extension_list[$i] === TORRENT_EXT && !defined('TORRENT_ATTACH_ID')) + { + define('TORRENT_ATTACH_ID', $attach_id); + } + //bt end + + $sql_ary = array( + 'attach_id' => (int) $attach_id, + 'post_id' => (int) $post_id, + 'user_id_1' => (int) $user_id_1, + ); + + $sql = 'INSERT INTO ' . BB_ATTACHMENTS . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + + if ( !(DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t store Attachment.
Your ' . $message_type . ' has been stored.', '', __LINE__, __FILE__, $sql); + } + } + } + + return TRUE; + } + + if ($mode == 'last_attachment') + { + if ($this->post_attach && !isset($_POST['update_attachment'])) + { + // insert attachment into db, here the user submited it directly + $sql_ary = array( + 'physical_filename' => (string) basename($this->attach_filename), + 'real_filename' => (string) basename($this->filename), + 'comment' => (string) $this->file_comment, + 'extension' => (string) strtolower($this->extension), + 'mimetype' => (string) strtolower($this->type), + 'filesize' => (int) $this->filesize, + 'filetime' => (int) $this->filetime, + 'thumbnail' => (int) $this->thumbnail + ); + + $sql = 'INSERT INTO ' . BB_ATTACHMENTS_DESC . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + + // Inform the user that his post has been created, but nothing is attached + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t store Attachment.
Your ' . $message_type . ' has been stored.', '', __LINE__, __FILE__, $sql); + } + + $attach_id = DB()->sql_nextid(); + + $sql_ary = array( + 'attach_id' => (int) $attach_id, + 'post_id' => (int) $post_id, + 'user_id_1' => (int) $user_id_1, + ); + + $sql = 'INSERT INTO ' . BB_ATTACHMENTS . ' ' . attach_mod_sql_build_array('INSERT', $sql_ary); + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t store Attachment.
Your ' . $message_type . ' has been stored.', '', __LINE__, __FILE__, $sql); + } + } + } + } + + /** + * Attachment Mod entry switch/output (intern) + * @private + */ + function display_attachment_bodies() + { + global $attach_config, $is_auth, $lang, $mode, $template, $upload_dir, $userdata, $forum_id; + + // Choose what to display + $value_add = $value_posted = 0; + + $this->add_attachment_body = 1; + $this->posted_attachments_body = 1; + + $s_hidden = ''; + $s_hidden .= ''; + + $u_rules_id = $forum_id; + + $template->assign_vars(array( + 'L_ADD_ATTACHMENT_TITLE' => $lang['ADD_ATTACHMENT_TITLE'], + 'L_POSTED_ATTACHMENTS' => $lang['POSTED_ATTACHMENTS'], + 'L_FILE_NAME' => $lang['FILE_NAME'], + 'L_FILE_COMMENT' => $lang['FILE_COMMENT'], + 'RULES' => ''. $lang['ALLOWED_EXTENSIONS_AND_SIZES'] .'', + + 'ADD_ATTACH_HIDDEN_FIELDS' => $s_hidden, + )); + + $attachments = array(); + + if (sizeof($this->attachment_list) > 0) + { + $hidden = ''; + for ($i = 0; $i < sizeof($this->attachment_list); $i++) + { + $hidden .= ''; + $hidden .= ''; + $hidden .= ''; + $hidden .= ''; + $hidden .= ''; + $hidden .= ''; + $hidden .= ''; + $hidden .= ''; + + if (!$this->posted_attachments_body || sizeof($this->attachment_list) == 0) + { + $hidden .= ''; + } + } + $template->assign_var('POSTED_ATTACHMENTS_HIDDEN_FIELDS', $hidden); + } + + if ($this->add_attachment_body) + { + $template->assign_vars(array( + 'TPL_ADD_ATTACHMENT' => true, + 'L_ADD_ATTACH_TITLE' => $lang['ADD_ATTACHMENT_TITLE'], + 'L_ADD_ATTACH_EXPLAIN' => $lang['ADD_ATTACHMENT_EXPLAIN'], + 'L_ADD_ATTACHMENT' => $lang['ADD_ATTACHMENT'], + + 'FILE_COMMENT' => htmlspecialchars($this->file_comment), + 'FILESIZE' => $attach_config['max_filesize'], + 'FILENAME' => htmlspecialchars($this->filename), + + 'S_FORM_ENCTYPE' => 'enctype="multipart/form-data"', + )); + } + + if ($this->posted_attachments_body && sizeof($this->attachment_list) > 0) + { + $template->assign_vars(array( + 'TPL_POSTED_ATTACHMENTS' => true, + 'L_POSTED_ATTACHMENTS' => $lang['POSTED_ATTACHMENTS'], + 'L_UPDATE_COMMENT' => $lang['UPDATE_COMMENT'], + 'L_UPLOAD_NEW_VERSION' => $lang['UPLOAD_NEW_VERSION'], + 'L_DELETE_ATTACHMENT' => $lang['DELETE_ATTACHMENT'], + 'L_DELETE_THUMBNAIL' => $lang['DELETE_THUMBNAIL'], + )); + + for ($i = 0; $i < sizeof($this->attachment_list); $i++) + { + if (@$this->attachment_id_list[$i] == 0) + { + $download_link = $upload_dir . '/' . basename($this->attachment_list[$i]); + } + else + { + $download_link = append_sid(BB_ROOT . 'download.php?id=' . $this->attachment_id_list[$i]); + } + + $template->assign_block_vars('attach_row', array( + 'FILE_NAME' => @htmlspecialchars($this->attachment_filename_list[$i]), + 'ATTACH_FILENAME' => @$this->attachment_list[$i], + 'FILE_COMMENT' => @htmlspecialchars($this->attachment_comment_list[$i]), + 'ATTACH_ID' => @$this->attachment_id_list[$i], + + 'U_VIEW_ATTACHMENT' => $download_link) + ); + + // Thumbnail there ? And is the User Admin or Mod ? Then present the 'Delete Thumbnail' Button + if (@intval($this->attachment_thumbnail_list[$i]) == 1 && ((isset($is_auth['auth_mod']) && $is_auth['auth_mod']) || IS_ADMIN)) + { + $template->assign_block_vars('attach_row.switch_thumbnail', array()); + } + + if (@$this->attachment_id_list[$i]) + { + $template->assign_block_vars('attach_row.switch_update_attachment', array()); + } + } + } + + $template->assign_var('ATTACHBOX'); + } + + /** + * Upload an Attachment to Filespace (intern) + */ + function upload_attachment() + { + global $error, $error_msg, $lang, $attach_config, $userdata, $upload_dir, $forum_id; + + $this->post_attach = ($this->filename != '') ? TRUE : FALSE; + + if ($this->post_attach) + { +// $r_file = trim(basename(htmlspecialchars($this->filename))); + $r_file = trim(basename($this->filename)); + $file = $_FILES['fileupload']['tmp_name']; + $this->type = $_FILES['fileupload']['type']; + + if (isset($_FILES['fileupload']['size']) && $_FILES['fileupload']['size'] == 0) + { + message_die(GENERAL_ERROR, 'Tried to upload empty file'); + } + + // Opera add the name to the mime type + $this->type = (strstr($this->type, '; name')) ? str_replace(strstr($this->type, '; name'), '', $this->type) : $this->type; + $this->type = strtolower($this->type); + $this->extension = strtolower(get_extension($this->filename)); + + $this->filesize = @filesize($file); + $this->filesize = intval($this->filesize); + + $sql = 'SELECT g.allow_group, g.max_filesize, g.cat_id, g.forum_permissions + FROM ' . BB_EXTENSION_GROUPS . ' g, ' . BB_EXTENSIONS . " e + WHERE g.group_id = e.group_id + AND e.extension = '" . attach_mod_sql_escape($this->extension) . "' + LIMIT 1"; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query Extensions.', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $allowed_filesize = ($row['max_filesize']) ? $row['max_filesize'] : $attach_config['max_filesize']; + $cat_id = intval($row['cat_id']); + $auth_cache = trim($row['forum_permissions']); + + // check Filename + if (preg_match("#[\\/:*?\"<>|]#i", $this->filename)) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['INVALID_FILENAME'], htmlspecialchars($this->filename)); + } + + // check php upload-size + if (!$error && $file == 'none') + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $ini_val = ( phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var'; + + $max_size = @$ini_val('upload_max_filesize'); + + if ($max_size == '') + { + $error_msg .= $lang['ATTACHMENT_PHP_SIZE_NA']; + } + else + { + $error_msg .= sprintf($lang['ATTACHMENT_PHP_SIZE_OVERRUN'], $max_size); + } + } + + // Check Extension + if (!$error && intval($row['allow_group']) == 0) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['DISALLOWED_EXTENSION'], htmlspecialchars($this->extension)); + } + + // Check Forum Permissions + if (!$error && !IS_ADMIN && !is_forum_authed($auth_cache, $forum_id) && trim($auth_cache) != '') + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['DISALLOWED_EXTENSION_WITHIN_FORUM'], htmlspecialchars($this->extension)); + } + + //bt + // Check if user can post torrent + global $post_data; + + if (!$error && $this->extension === TORRENT_EXT && !$post_data['first_post']) + { + $error = TRUE; + if (!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= $lang['ALLOWED_ONLY_1ST_POST_ATTACH']; + } + //bt end + + // Upload File + + $this->thumbnail = 0; + + if (!$error) + { + // + // Prepare Values + $this->filetime = time(); + + $this->filename = $r_file; + + // physical filename + //$this->attach_filename = strtolower($this->filename); + $this->attach_filename = $this->filename; + + //bt + if (FILENAME_CRYPTIC) + { + $this->attach_filename = make_rand_str(FILENAME_CRYPTIC_LENGTH); + } + else if (FILENAME_TRANSLITERATE) + { + $this->attach_filename = transliterate($this->attach_filename); + } + else + { // original + $this->attach_filename = html_entity_decode(trim(stripslashes($this->attach_filename))); + $this->attach_filename = delete_extension($this->attach_filename); + $this->attach_filename = str_replace(array(' ','-'), array('_','_'), $this->attach_filename); + $this->attach_filename = str_replace('__', '_', $this->attach_filename); + $this->attach_filename = str_replace(array(',', '.', '!', '?', 'ь', 'Ь', 'ц', 'Ц', 'д', 'Д', ';', ':', '@', "'", '"', '&'), array('', '', '', '', 'ue', 'ue', 'oe', 'oe', 'ae', 'ae', '', '', '', '', '', 'and'), $this->attach_filename); + $this->attach_filename = str_replace(array('$', 'Я', '>','<','§','%','=','/','(',')','#','*','+',"\\",'{','}','[',']'), array('dollar', 'ss','greater','lower','paragraph','percent','equal','','','','','','','','','','',''), $this->attach_filename); + // Remove non-latin characters + $this->attach_filename = preg_replace("/([\xC2\xC3])([\x80-\xBF])/e", "chr(ord('\\1')<<6&0xC0|ord('\\2')&0x3F)", $this->attach_filename); + $this->attach_filename = rawurlencode($this->attach_filename); + $this->attach_filename = preg_replace("/(%[0-9A-F]{1,2})/i", '', $this->attach_filename); + $this->attach_filename = trim($this->attach_filename); + } + $this->attach_filename = str_replace(array('&','&',' '), '_', $this->attach_filename); + $this->attach_filename = str_replace('php', '_php_', $this->attach_filename); + $this->attach_filename = substr(trim($this->attach_filename), 0, FILENAME_MAX_LENGTH); + + for ($i=0, $max_try=5; $i <= $max_try; $i++) + { + $fn_prefix = make_rand_str(FILENAME_PREFIX_LENGTH) .'_'; + $new_physical_filename = clean_filename($fn_prefix . $this->attach_filename); + + if (!physical_filename_already_stored($new_physical_filename)) + { + break; + } + if ($i == $max_try) + { + message_die(GENERAL_ERROR, 'Could not create filename for attachment', '', __LINE__, __FILE__); + } + } + $this->attach_filename = $new_physical_filename; + + // Do we have to create a thumbnail ? + if ($cat_id == IMAGE_CAT && intval($attach_config['img_create_thumbnail'])) + { + $this->thumbnail = 1; + } + } + + if ($error) + { + $this->post_attach = FALSE; + return; + } + + // Upload Attachment + if (!$error) + { + if (!(intval($attach_config['allow_ftp_upload']))) + { + // Descide the Upload method + $ini_val = ( phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var'; + + $safe_mode = @$ini_val('safe_mode'); + + if (@$ini_val('open_basedir')) + { + if ( @phpversion() < '4.0.3' ) + { + $upload_mode = 'copy'; + } + else + { + $upload_mode = 'move'; + } + } + else if ( @$ini_val('safe_mode') ) + { + $upload_mode = 'move'; + } + else + { + $upload_mode = 'copy'; + } + } + else + { + $upload_mode = 'ftp'; + } + + // Ok, upload the Attachment + if (!$error) + { + $this->move_uploaded_attachment($upload_mode, $file); + } + } + + // Now, check filesize parameters + if (!$error) + { + if ($upload_mode != 'ftp' && !$this->filesize) + { + $this->filesize = intval(@filesize($upload_dir . '/' . $this->attach_filename)); + } + } + + // Check Image Size, if it's an image + if (!$error && !IS_ADMIN && $cat_id == IMAGE_CAT) + { + list($width, $height) = image_getdimension($upload_dir . '/' . $this->attach_filename); + + if ($width != 0 && $height != 0 && intval($attach_config['img_max_width']) != 0 && intval($attach_config['img_max_height']) != 0) + { + if ($width > intval($attach_config['img_max_width']) || $height > intval($attach_config['img_max_height'])) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['ERROR_IMAGESIZE'], intval($attach_config['img_max_width']), intval($attach_config['img_max_height'])); + } + } + } + + // check Filesize + if (!$error && $allowed_filesize != 0 && $this->filesize > $allowed_filesize && !(IS_ADMIN || IS_MOD || IS_GROUP_MEMBER)) + { + $size_lang = ($allowed_filesize >= 1048576) ? $lang['MB'] : ( ($allowed_filesize >= 1024) ? $lang['KB'] : $lang['BYTES'] ); + + if ($allowed_filesize >= 1048576) + { + $allowed_filesize = round($allowed_filesize / 1048576 * 100) / 100; + } + else if($allowed_filesize >= 1024) + { + $allowed_filesize = round($allowed_filesize / 1024 * 100) / 100; + } + + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['ATTACHMENT_TOO_BIG'], $allowed_filesize, $size_lang); + } + + // Check our complete quota + if ($attach_config['attachment_quota']) + { + $sql = 'SELECT sum(filesize) as total FROM ' . BB_ATTACHMENTS_DESC; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query total filesize', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $total_filesize = $row['total']; + + if (($total_filesize + $this->filesize) > $attach_config['attachment_quota']) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= $lang['ATTACH_QUOTA_REACHED']; + } + + } + + $this->get_quota_limits($userdata); + + // Check our user quota + if ($attach_config['upload_filesize_limit']) + { + $sql = 'SELECT attach_id + FROM ' . BB_ATTACHMENTS . ' + WHERE user_id_1 = ' . (int) $userdata['user_id'] . ' + GROUP BY attach_id'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $attach_ids = DB()->sql_fetchrowset($result); + $num_attach_ids = DB()->num_rows($result); + DB()->sql_freeresult($result); + + $attach_id = array(); + + for ($i = 0; $i < $num_attach_ids; $i++) + { + $attach_id[] = intval($attach_ids[$i]['attach_id']); + } + + if ($num_attach_ids > 0) + { + // Now get the total filesize + $sql = 'SELECT sum(filesize) as total + FROM ' . BB_ATTACHMENTS_DESC . ' + WHERE attach_id IN (' . implode(', ', $attach_id) . ')'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query total filesize', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + $total_filesize = $row['total']; + } + else + { + $total_filesize = 0; + } + + if (($total_filesize + $this->filesize) > $attach_config['upload_filesize_limit']) + { + $upload_filesize_limit = $attach_config['upload_filesize_limit']; + $size_lang = ($upload_filesize_limit >= 1048576) ? $lang['MB'] : ( ($upload_filesize_limit >= 1024) ? $lang['KB'] : $lang['BYTES'] ); + + if ($upload_filesize_limit >= 1048576) + { + $upload_filesize_limit = round($upload_filesize_limit / 1048576 * 100) / 100; + } + else if($upload_filesize_limit >= 1024) + { + $upload_filesize_limit = round($upload_filesize_limit / 1024 * 100) / 100; + } + + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['USER_UPLOAD_QUOTA_REACHED'], $upload_filesize_limit, $size_lang); + } + } + + if ($error) + { + unlink_attach($this->attach_filename); + unlink_attach($this->attach_filename, MODE_THUMBNAIL); + $this->post_attach = FALSE; + } + } + } + + // Copy the temporary attachment to the right location (copy, move_uploaded_file or ftp) + function move_uploaded_attachment($upload_mode, $file) + { + global $error, $error_msg, $lang, $upload_dir; + + if (!is_uploaded_file($file)) + { + message_die(GENERAL_ERROR, 'Unable to upload file. The given source has not been uploaded.', __LINE__, __FILE__); + } + + switch ($upload_mode) + { + case 'copy': + + if (!@copy($file, $upload_dir . '/' . basename($this->attach_filename))) + { + if (!@move_uploaded_file($file, $upload_dir . '/' . basename($this->attach_filename))) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['GENERAL_UPLOAD_ERROR'], './' . $upload_dir . '/' . $this->attach_filename); + return; + } + } + @chmod($upload_dir . '/' . basename($this->attach_filename), 0666); + + break; + + case 'move': + + if (!@move_uploaded_file($file, $upload_dir . '/' . basename($this->attach_filename))) + { + if (!@copy($file, $upload_dir . '/' . basename($this->attach_filename))) + { + $error = TRUE; + if(!empty($error_msg)) + { + $error_msg .= '
'; + } + $error_msg .= sprintf($lang['GENERAL_UPLOAD_ERROR'], './' . $upload_dir . '/' . $this->attach_filename); + return; + } + } + @chmod($upload_dir . '/' . $this->attach_filename, 0666); + + break; + + case 'ftp': + ftp_file($file, basename($this->attach_filename), $this->type); + break; + } + + if (!$error && $this->thumbnail == 1) + { + if ($upload_mode == 'ftp') + { + $source = $file; + $dest_file = THUMB_DIR . '/t_' . basename($this->attach_filename); + } + else + { + $source = $upload_dir . '/' . basename($this->attach_filename); + $dest_file = amod_realpath($upload_dir); + $dest_file .= '/' . THUMB_DIR . '/t_' . basename($this->attach_filename); + } + + if (!create_thumbnail($source, $dest_file, $this->type)) + { + if (!$file || !create_thumbnail($file, $dest_file, $this->type)) + { + $this->thumbnail = 0; + } + } + } + } +} + +/** +* @package attachment_mod +* Attachment posting +*/ +class attach_posting extends attach_parent +{ + /** + * Constructor + */ + function attach_posting() + { + $this->attach_parent(); + $this->page = 0; + } + + /** + * Insert an Attachment into a Post (this is the second function called from posting.php) + */ + function insert_attachment($post_id) + { + global $is_auth, $mode, $userdata, $error, $error_msg; + + // Insert Attachment ? + if (!empty($post_id) && ($mode == 'newtopic' || $mode == 'reply' || $mode == 'editpost') && $is_auth['auth_attachments']) + { + $this->do_insert_attachment('attach_list', 'post', $post_id); + $this->do_insert_attachment('last_attachment', 'post', $post_id); + + if ((sizeof($this->attachment_list) > 0 || $this->post_attach) && !isset($_POST['update_attachment'])) + { + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_attachment = 1 + WHERE post_id = ' . (int) $post_id; + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to update Posts Table.', '', __LINE__, __FILE__, $sql); + } + + $sql = 'SELECT topic_id + FROM ' . BB_POSTS . ' + WHERE post_id = ' . (int) $post_id; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to select Posts Table.', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_attachment = 1 + WHERE topic_id = ' . (int) $row['topic_id']; + + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Unable to update Topics Table.', '', __LINE__, __FILE__, $sql); + } + } + } + } + + /** + * Handle Attachments (Add/Delete/Edit/Show) - This is the first function called from every message handler + */ + function posting_attachment_mod() + { + global $mode, $confirm, $is_auth, $post_id, $delete, $refresh; + + if (!$refresh) + { + $add_attachment_box = (!empty($_POST['add_attachment_box'])) ? TRUE : FALSE; + $posted_attachments_box = (!empty($_POST['posted_attachments_box'])) ? TRUE : FALSE; + + $refresh = $add_attachment_box || $posted_attachments_box; + } + + // Choose what to display + $result = $this->handle_attachments($mode); + + if ($result === false) + { + return; + } + + if ($confirm && ($delete || $mode == 'delete' || $mode == 'editpost') && ($is_auth['auth_delete'] || $is_auth['auth_mod'])) + { + if ($post_id) + { + delete_attachment($post_id); + } + } + + $this->display_attachment_bodies(); + } + +} + +/** +* Entry Point +*/ +function execute_posting_attachment_handling() +{ + global $attachment_mod; + + $attachment_mod['posting'] = new attach_posting(); + $attachment_mod['posting']->posting_attachment_mod(); +} \ No newline at end of file diff --git a/upload/bt/announce.php b/upload/bt/announce.php new file mode 100644 index 000000000..25b949875 --- /dev/null +++ b/upload/bt/announce.php @@ -0,0 +1,194 @@ + 0xFFFF) +{ + msg_die('Invalid port'); +} +if (!isset($uploaded) || $uploaded < 0 || $uploaded > $max_up_down_val || $uploaded == 1844674407370) +{ + msg_die('Invalid uploaded value'); +} +if (!isset($downloaded) || $downloaded < 0 || $downloaded > $max_up_down_val || $downloaded == 1844674407370) +{ + msg_die('Invalid downloaded value'); +} +if (!isset($left) || $left < 0 || $left > $max_left_val) +{ + msg_die('Invalid left value'); +} +if (!verify_id($passkey, BT_AUTH_KEY_LENGTH)) +{ + msg_die('Invalid passkey'); +} + +// IP +$ip = $_SERVER['REMOTE_ADDR']; + +if (!$bb_cfg['ignore_reported_ip'] && isset($_GET['ip']) && $ip !== $_GET['ip']) +{ + if (!$bb_cfg['verify_reported_ip']) + { + $ip = $_GET['ip']; + } + else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) + { + foreach ($matches[0] as $x_ip) + { + if ($x_ip === $_GET['ip']) + { + if (!$bb_cfg['allow_internal_ip'] && preg_match("#^(10|172\.16|192\.168)\.#", $x_ip)) + { + break; + } + $ip = $x_ip; + break; + } + } + } +} +// Check that IP format is valid +if (!verify_ip($ip)) +{ + msg_die("Invalid IP: $ip"); +} +// Convert IP to HEX format +$ip_sql = encode_ip($ip); + +// Peer unique id +$peer_hash = md5( + rtrim($info_hash, ' ') . $passkey . $ip . $port +); + +// Get cached peer info from previous announce (last peer info) +$lp_info = CACHE('tr_cache')->get(PEER_HASH_PREFIX . $peer_hash); + +if (DBG_LOG) dbg_log(' ', '$lp_info-get_from-CACHE-'. ($lp_info ? 'hit' : 'miss')); + +// Drop fast announce +if ($lp_info && (!isset($event) || $event !== 'stopped')) +{ + drop_fast_announce($lp_info); +} + +// Functions +function drop_fast_announce ($lp_info) +{ + global $announce_interval; + + if ($lp_info['update_time'] < (TIMENOW - $announce_interval + 60)) + { + return; // if announce interval correct + } + + if (DBG_LOG) dbg_log(' ', 'drop_fast_announce-'. (!empty(DB()) ? 'DB' : 'CACHE')); + + $new_ann_intrv = $lp_info['update_time'] + $announce_interval - TIMENOW; + + dummy_exit($new_ann_intrv); +} + +function msg_die ($msg) +{ + if (DBG_LOG) dbg_log(' ', '!die-'. clean_filename($msg)); + + $output = bencode(array( +# 'interval' => (int) 1800, + 'min interval' => (int) 1800, +# 'peers' => (string) DUMMY_PEER, + 'failure reason' => (string) $msg, + 'warning message' => (string) $msg, + )); + + die($output); +} + +# $agent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '-'; +# bb_log("$agent | ". str_compact($peer_id) ."\n", 'agent'); + +// Start announcer +define('TR_ROOT', './'); +require(TR_ROOT .'includes/init_tr.php'); +require(TR_ROOT .'includes/tr_announcer.php'); +exit; \ No newline at end of file diff --git a/upload/bt/includes/.htaccess b/upload/bt/includes/.htaccess new file mode 100644 index 000000000..a42f56b15 --- /dev/null +++ b/upload/bt/includes/.htaccess @@ -0,0 +1,3 @@ +Order Deny,Allow +Deny from all +Allow from local. \ No newline at end of file diff --git a/upload/bt/includes/init_tr.php b/upload/bt/includes/init_tr.php new file mode 100644 index 000000000..394872a12 --- /dev/null +++ b/upload/bt/includes/init_tr.php @@ -0,0 +1,559 @@ +num_queries : '-'; + $sql_inittime = !empty($DBS) ? DB()->sql_inittime : ' -- '; + $sql_timetotal = !empty($DBS) ? DB()->sql_timetotal : ' -- '; + $sql_init_perc = !empty($DBS) ? round($sql_inittime*100/$gen_time) : ' - '; + $sql_total_perc = !empty($DBS) ? round($sql_timetotal*100/$gen_time) : ' - '; + + $str = array(); + $str[] = substr(time(), -4, 4); + $str[] = sprintf('%.4f', $gen_time); + $str[] = sprintf('%.4f'. LOG_SEPR .'%02d%%', $sql_inittime, $sql_init_perc); + $str[] = sprintf('%.4f'. LOG_SEPR .'%02d%%', $sql_timetotal, $sql_total_perc); + $str[] = $num_queries; + $str[] = sprintf('%.1f', LOADAVG); + $str = join(LOG_SEPR, $str) . LOG_LF; + dbg_log($str, '!!gentime'); + } +/**!/ + bb_log("##\n". ob_get_contents() ."\n##", 'tr_output_'. date('m-d_H')); +#*/ + + exit; +} + +function silent_exit () +{ + while (@ob_end_clean()); + + tracker_exit(); +} + +function error_exit ($msg = '') +{ + if (DBG_LOG) dbg_log(' ', '!err-'. clean_filename($msg)); + + if (!DEBUG) + { + silent_exit(); + } + + echo bencode(array('failure reason' => str_compact($msg))); + + tracker_exit(); +} + +function browser_redirect () +{ + if (empty($_SERVER['HTTP_USER_AGENT'])) return; + + $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); + + $browser_ids = array( + 'amaya', + 'crawler', + 'dillo', + 'elinks', + 'gecko', + 'googlebot', + 'ibrowse', + 'icab', + 'konqueror', + 'lynx', + 'mozilla', + 'msie', + 'msnbot', + 'netpositive', + 'omniweb', + 'opera', + 'safari', + 'slurp', + 'w3m', + 'wget', + ); + + foreach ($browser_ids as $browser) + { + if (strpos($user_agent, $browser) !== false) + { + if (DBG_LOG) + { + dbg_log(' ', "redirect/$browser"); + + dbg_log( + TIMENOW . LOG_SEPR . + encode_ip($_SERVER['REMOTE_ADDR']) . LOG_SEPR . + $_SERVER['REMOTE_ADDR'] . LOG_SEPR . + $_SERVER['QUERY_STRING'] . LOG_SEPR . + $_SERVER['HTTP_USER_AGENT'] . LOG_SEPR . + LOG_LF, + "redirect/$browser.q.log" + ); + } + + header('Location: '. $GLOBALS['tr_cfg']['browser_redirect_url']); + tracker_exit(); + } + } +} + +// Database +class sql_db +{ + var $link = null; + var $result = null; + var $selected_db = null; + + var $pconnect = false; + var $locked = false; + + var $num_queries = 0; + var $sql_starttime = 0; + var $sql_inittime = 0; + var $sql_timetotal = 0; + + var $dbg = array(); + var $dbg_id = 0; + var $dbg_user = false; + var $cur_query = null; + + /** + * Constructor + */ + function sql_db ($cfg) + { + $this->dbg_user = (SQL_DEBUG && $cfg['dbg_user']); + $this->pconnect = $cfg['persist']; + + // Connect to server + $this->link = @$this->connect($cfg); + + // Select database + $this->selected_db = @$this->select_db($cfg); + + // Set charset + if ($cfg['charset'] && !@$this->sql_query("SET NAMES {$cfg['charset']}")) + { + error_exit("Could not set MySQL charset '{$cfg['charset']}'"); + } + + $this->num_queries = 0; + $this->sql_inittime = $this->sql_timetotal; + } + + /** + * Open connection + */ + function connect ($cfg) + { + $this->cur_query = 'connect'; + $this->debug('start'); + + $connect_type = ($this->pconnect) ? 'mysql_pconnect' : 'mysql_connect'; + + if (!$link = $connect_type($cfg['dbhost'], $cfg['dbuser'], $cfg['dbpasswd'])) + { + $this->log_error(); + } + + register_shutdown_function(array(&$this, 'sql_close')); + + $this->debug('end'); + $this->cur_query = null; + + if (DBG_LOG) dbg_log(' ', 'DB-connect'. ($link ? '' : '-FAIL')); + + if (!$link) + { + dummy_exit(1200); + } + + return $link; + } + + /** + * Select database + */ + function select_db ($cfg) + { + $this->cur_query = 'select db'; + $this->debug('start'); + + if (!mysql_select_db($cfg['dbname'], $this->link)) + { + $this->log_error(); + error_exit("Could not select database '{$cfg['dbname']}'"); + } + + $this->debug('end'); + $this->cur_query = null; + + return $cfg['dbname']; + } + + /** + * Base query method + */ + function sql_query ($query, $type = 'buffered') + { + $this->cur_query = $query; + $this->debug('start'); + + $query_function = ($type === 'unbuffered') ? 'mysql_unbuffered_query' : 'mysql_query'; + + if (!$this->result = $query_function($query, $this->link)) + { + $this->log_error(); + } + + $this->debug('end'); + $this->cur_query = null; + + $this->num_queries++; + + return $this->result; + } + + /** + * Execute query WRAPPER (with error handling) + */ + function query ($query, $err_msg = '') + { + if (!$result = $this->sql_query($query)) + { + $this->trigger_error($err_msg); + } + + return $result; + } + + /** + * Return number of rows + */ + function num_rows ($result = false) + { + $num_rows = false; + + if ($result OR $result = $this->result) + { + $num_rows = is_resource($result) ? mysql_num_rows($result) : false; + } + + return $num_rows; + } + + /** + * Return number of affected rows + */ + function affected_rows () + { + return (is_resource($this->link)) ? mysql_affected_rows($this->link) : -1; + } + + /** + * Fetch current row + */ + function sql_fetchrow ($result, $result_type = MYSQL_ASSOC) + { + return (is_resource($result)) ? mysql_fetch_array($result, $result_type) : false; + } + + /** + * Alias of sql_fetchrow() + */ + function fetch_next ($result, $result_type = MYSQL_ASSOC) + { + return $this->sql_fetchrow($result, $result_type); + } + + /** + * Fetch row WRAPPER (with error handling) + */ + function fetch_row ($query, $err_msg = '') + { + if (!$result = $this->sql_query($query)) + { + $this->trigger_error($err_msg); + } + + return $this->sql_fetchrow($result); + } + + /** + * Fetch all rows + */ + function sql_fetchrowset ($result, $result_type = MYSQL_ASSOC) + { + $rowset = array(); + + while ($row = mysql_fetch_array($result, $result_type)) + { + $rowset[] = $row; + } + + return $rowset; + } + + /** + * Fetch all rows WRAPPER (with error handling) + */ + function fetch_rowset ($query, $err_msg = '') + { + if (!$result = $this->sql_query($query, 'buffered')) + { + $this->trigger_error($err_msg); + } + + return $this->sql_fetchrowset($result); + } + + /** + * Escape string used in sql query + */ + function escape ($v, $check_type = false) + { + if (!$check_type) + { + return mysql_real_escape_string($v); + } + + switch (true) + { + case is_string ($v): return "'". mysql_real_escape_string($v) ."'"; + case is_int ($v): return "$v"; + case is_bool ($v): return ($v) ? '1' : '0'; + case is_float ($v): return "'$v'"; + case is_null ($v): return 'NULL'; + } + // if $v has unsuitable type + $this->trigger_error(__FUNCTION__ .' - wrong params'); + } + + /** + * Return sql error array + */ + function sql_error () + { + $return_ary = array( + 'code' => '', + 'message' => 'not connected', + ); + + if (is_resource($this->link)) + { + $return_ary = array( + 'code' => mysql_errno($this->link), + 'message' => mysql_error($this->link), + ); + } + + return $return_ary; + } + + /** + * Close sql connection + */ + function sql_close () + { + if (is_resource($this->link)) + { + mysql_close($this->link); + } + + $this->link = $this->selected_db = null; + + if (DBG_LOG) dbg_log(str_repeat(' ', $this->num_queries), 'DB-num_queries'); + } + + /** + * Get info about last query + */ + function query_info () + { + $info = array(); + + if ($num = $this->num_rows($this->result)) + { + $info[] = "$num rows"; + } + + if (is_resource($this->link) AND $ext = mysql_info($this->link)) + { + $info[] = "$ext"; + } + else if (!$num && ($aff = $this->affected_rows($this->result) AND $aff != -1)) + { + $info[] = "$aff rows"; + } + + return join(', ', $info); + } + + /** + * Store debug info + */ + function debug ($mode) + { + if (!SQL_DEBUG) return; + + if ($mode == 'start') + { + if (SQL_CALC_QUERY_TIME || DBG_LOG || SQL_LOG_SLOW_QUERIES) + { + $this->sql_starttime = utime(); + } + } + else if ($mode == 'end') + { + if (SQL_CALC_QUERY_TIME || DBG_LOG || SQL_LOG_SLOW_QUERIES) + { + $cur_query_time = utime() - $this->sql_starttime; + $this->sql_timetotal += $cur_query_time; + + if (SQL_LOG_SLOW_QUERIES && $cur_query_time > SQL_SLOW_QUERY_TIME) + { + $msg = date('m-d H:i:s') . LOG_SEPR; + $msg .= sprintf('%03d', round($cur_query_time)); + $msg .= defined('LOADAVG') ? LOG_SEPR . sprintf('%.1f', LOADAVG) : ''; + $msg .= LOG_SEPR . str_compact($this->cur_query); + $msg .= LOG_SEPR .' # '. $this->query_info(); + $msg .= LOG_SEPR . $this->debug_find_source(); + bb_log($msg . LOG_LF, 'sql_slow_tr'); + } + } + } + return; + } + + /** + * Trigger error + */ + function trigger_error ($msg = '') + { + if (error_reporting()) + { + if (!$msg) $msg = 'DB Error'; + + if (DEBUG === true) + { + $err = $this->sql_error(); + $msg .= trim(sprintf(' #%06d %s', $err['code'], $err['message'])); + } + else + { + $msg .= " [". $this->debug_find_source() ."]"; + } + + error_exit($msg); + } + } + + /** + * Find caller source + */ + function debug_find_source () + { + $source = ''; + $backtrace = debug_backtrace(); + + foreach ($backtrace as $trace) + { + if ($trace['file'] !== __FILE__) + { + $source = str_replace(BB_PATH . DIR_SEPR, '', $trace['file']) .'('. $trace['line'] .')'; + break; + } + } + + return $source; + } + + /** + * Log error + */ + function log_error () + { + if (!SQL_LOG_ERRORS) return; + if (!error_reporting()) return; + + $msg = array(); + $err = $this->sql_error(); + $msg[] = str_compact(sprintf('#%06d %s', $err['code'], $err['message'])); + $msg[] = ''; + $msg[] = str_compact($this->cur_query); + $msg[] = ''; + $msg[] = 'Source : '. $this->debug_find_source(); + $msg[] = 'IP : '. @$_SERVER['REMOTE_ADDR']; + $msg[] = 'Date : '. date('Y-m-d H:i:s'); + $msg[] = 'Agent : '. @$_SERVER['HTTP_USER_AGENT']; + $msg[] = 'Req_URI : '. @$_SERVER['REQUEST_URI']; + $msg[] = 'Referer : '. @$_SERVER['HTTP_REFERER']; + $msg[] = 'Method : '. @$_SERVER['REQUEST_METHOD']; + $msg[] = 'Request : '. trim(print_r($_REQUEST, true)) . str_repeat('_', 78) . LOG_LF; + $msg[] = ''; + bb_log($msg, 'sql_error_tr'); + } +} + +// Make the database connection +function db_init () +{ + if (defined('SQL_LAYER')) + { + return; + } + define('SQL_LAYER', 'mysql'); + + DB() = new sql_db(array( + 'dbms' => DBMS, + 'dbhost' => DBHOST, + 'dbname' => DBNAME, + 'dbuser' => DBUSER, + 'dbpasswd' => DBPASSWD, + 'charset' => DBCHARSET, + 'collation' => DBCOLLATION, + 'persist' => PCONNECT, + 'dbg_user' => false, + )); +} + +##### LOG ##### // User req (by passkey) +if ($log_passkey && isset($log_passkey[$_GET[$passkey_key]])) +{ + bb_log( + md5($_GET['info_hash']) . LOG_SEPR . + date('His') . LOG_SEPR . + TIMENOW . LOG_SEPR . + $_SERVER['QUERY_STRING'] . LOG_SEPR . + $_SERVER['REMOTE_ADDR'] . LOG_SEPR . + @$_SERVER['HTTP_X_FORWARDED_FOR'] . LOG_SEPR . + @$_SERVER['HTTP_USER_AGENT'] . LOG_SEPR . + LOG_LF, + 'passkey_'. $log_passkey[$_GET[$passkey_key]] + ); +} +### LOG END ### \ No newline at end of file diff --git a/upload/bt/includes/tr_announcer.php b/upload/bt/includes/tr_announcer.php new file mode 100644 index 000000000..f55607c18 --- /dev/null +++ b/upload/bt/includes/tr_announcer.php @@ -0,0 +1,248 @@ +rm(PEER_HASH_PREFIX . $peer_hash); + if (DBG_LOG) dbg_log(' ', 'stopped'); +} + +// Get last peer info from DB +if (!CACHE('tr_cache')->used && !$lp_info) +{ + $lp_info = DB()->fetch_row(" + SELECT * FROM ". BB_BT_TRACKER ." WHERE peer_hash = '$peer_hash' LIMIT 1 + "); + + if (DBG_LOG) dbg_log(' ', '$lp_info-get_from-DB-'. ($lp_info ? 'hit' : 'miss')); +} + +if ($lp_info) +{ + if (!$stopped) + { + drop_fast_announce($lp_info); + } + + $user_id = $lp_info['user_id']; + $topic_id = $lp_info['topic_id']; + $releaser = $lp_info['releaser']; + $tor_type = $lp_info['tor_type']; +} +else +{ + // Verify if torrent registered on tracker and user authorized + $info_hash_sql = rtrim(DB()->escape($info_hash), ' '); + $passkey_sql = DB()->escape($passkey); + + $sql = " + SELECT tor.topic_id, tor.poster_id, tor.tor_type, u.* + FROM ". BB_BT_TORRENTS ." tor + LEFT JOIN ". BB_BT_USERS ." u ON u.auth_key = '$passkey_sql' + WHERE tor.info_hash = '$info_hash_sql' + LIMIT 1 + "; + + $row = DB()->fetch_row($sql); + + if (empty($row['topic_id'])) + { + msg_die('Torrent not registered, info_hash = ' . bin2hex($info_hash_sql)); + } + if (empty($row['user_id'])) + { + msg_die('Please LOG IN and REDOWNLOAD this torrent (user not found)'); + } + + $user_id = $row['user_id']; + $topic_id = $row['topic_id']; + $releaser = (int) ($user_id == $row['poster_id']); + $tor_type = $row['tor_type']; + + // Ratio limits + if ((TR_RATING_LIMITS || $tr_cfg['limit_concurrent_ips']) && !$stopped) + { + $user_ratio = ($row['u_down_total'] && $row['u_down_total'] > MIN_DL_FOR_RATIO) ? ($row['u_up_total'] + $row['u_up_release'] + $row['u_up_bonus']) / $row['u_down_total'] : 1; + require(TR_ROOT .'includes/tr_ratio.php'); + } +} + +// Up/Down speed +$speed_up = $speed_down = 0; + +if ($lp_info && $lp_info['update_time'] < TIMENOW) +{ + if ($uploaded > $lp_info['uploaded']) + { + $speed_up = ceil(($uploaded - $lp_info['uploaded']) / (TIMENOW - $lp_info['update_time'])); + } + if ($downloaded > $lp_info['downloaded']) + { + $speed_down = ceil(($downloaded - $lp_info['downloaded']) / (TIMENOW - $lp_info['update_time'])); + } +} + +// Up/Down addition +$up_add = ($lp_info && $uploaded > $lp_info['uploaded']) ? $uploaded - $lp_info['uploaded'] : 0; +$down_add = ($lp_info && $downloaded > $lp_info['downloaded']) ? $downloaded - $lp_info['downloaded'] : 0; + +// Gold/Silver releases +if ($bb_cfg['gold_silver_enabled'] && $down_add) +{ + if ($tor_type == TOR_TYPE_GOLD) + { + $down_add = 0; + } + // Silver releases + else if ($tor_type == TOR_TYPE_SILVER) + { + $down_add = ceil($down_add/2); + } +} + +// Insert/update peer info +$peer_info_updated = false; +$update_time = ($stopped) ? 0 : TIMENOW; + +if ($lp_info) +{ + $sql = "UPDATE ". BB_BT_TRACKER ." SET update_time = $update_time"; + + $sql .= ", seeder = $seeder"; + $sql .= ($releaser != $lp_info['releaser']) ? ", releaser = $releaser" : ''; + + $sql .= ($tor_type != $lp_info['tor_type']) ? ", tor_type = $tor_type" : ''; + + $sql .= ($uploaded != $lp_info['uploaded']) ? ", uploaded = $uploaded" : ''; + $sql .= ($downloaded != $lp_info['downloaded']) ? ", downloaded = $downloaded" : ''; + $sql .= ", remain = $left"; + + $sql .= ($up_add) ? ", up_add = up_add + $up_add" : ''; + $sql .= ($down_add) ? ", down_add = down_add + $down_add" : ''; + + $sql .= ", speed_up = $speed_up"; + $sql .= ", speed_down = $speed_down"; + + $sql .= " WHERE peer_hash = '$peer_hash'"; + $sql .= " LIMIT 1"; + + DB()->query($sql); + + $peer_info_updated = DB()->affected_rows(); + + if (DBG_LOG) dbg_log(' ', 'this_peer-update'. ($peer_info_updated ? '' : '-FAIL')); +} + +if (!$lp_info || !$peer_info_updated) +{ + $columns = 'peer_hash, topic_id, user_id, ip, port, seeder, releaser, tor_type, uploaded, downloaded, remain, speed_up, speed_down, up_add, down_add, update_time'; + $values = "'$peer_hash', $topic_id, $user_id, '$ip_sql', $port, $seeder, $releaser, $tor_type, $uploaded, $downloaded, $left, $speed_up, $speed_down, $up_add, $down_add, $update_time"; + + DB()->query("REPLACE INTO ". BB_BT_TRACKER ." ($columns) VALUES ($values)"); + + if (DBG_LOG) dbg_log(' ', 'this_peer-insert'); +} + +// Exit if stopped +if ($stopped) +{ + silent_exit(); +} + +// Store peer info in cache +$lp_info = array( + 'downloaded' => (float) $downloaded, + 'releaser' => (int) $releaser, + 'seeder' => (int) $seeder, + 'topic_id' => (int) $topic_id, + 'update_time' => (int) TIMENOW, + 'uploaded' => (float) $uploaded, + 'user_id' => (int) $user_id, + 'tor_type' => (int) $tor_type, +); + +$lp_info_cached = CACHE('tr_cache')->set(PEER_HASH_PREFIX . $peer_hash, $lp_info, PEER_HASH_EXPIRE); + +if (DBG_LOG && !$lp_info_cached) dbg_log(' ', '$lp_info-caching-FAIL'); + +// Get cached output +$output = CACHE('tr_cache')->get(PEERS_LIST_PREFIX . $topic_id); + +if (DBG_LOG) dbg_log(' ', '$output-get_from-CACHE-'. ($output !== false ? 'hit' : 'miss')); + +if (!$output) +{ + // Retrieve peers + $numwant = (int) $tr_cfg['numwant']; + $compact_mode = ($tr_cfg['compact_mode'] || !empty($compact)); + + $rowset = DB()->fetch_rowset(" + SELECT ip, port + FROM ". BB_BT_TRACKER ." + WHERE topic_id = $topic_id + ORDER BY RAND() + LIMIT $numwant + "); + + if ($compact_mode) + { + $peers = ''; + + foreach ($rowset as $peer) + { + $peers .= pack('Nn', ip2long(decode_ip($peer['ip'])), $peer['port']); + } + } + else + { + $peers = array(); + + foreach ($rowset as $peer) + { + $peers[] = array( + 'ip' => decode_ip($peer['ip']), + 'port' => intval($peer['port']), + ); + } + } + + $seeders = 0; + $leechers = 0; + + if ($tr_cfg['scrape']) + { + $row = DB()->fetch_row(" + SELECT seeders, leechers + FROM ". BB_BT_TRACKER_SNAP ." + WHERE topic_id = $topic_id + LIMIT 1 + "); + + $seeders = $row['seeders']; + $leechers = $row['leechers']; + } + + $output = array( + 'interval' => (int) $announce_interval, + 'min interval' => (int) $announce_interval, + 'peers' => $peers, + 'complete' => (int) $seeders, + 'incomplete' => (int) $leechers, + ); + + $peers_list_cached = CACHE('tr_cache')->set(PEERS_LIST_PREFIX . $topic_id, $output, PEERS_LIST_EXPIRE); + + if (DBG_LOG && !$peers_list_cached) dbg_log(' ', '$output-caching-FAIL'); +} + +// Return data to client +echo bencode($output); + +tracker_exit(); diff --git a/upload/bt/includes/tr_ratio.php b/upload/bt/includes/tr_ratio.php new file mode 100644 index 000000000..4cc148f54 --- /dev/null +++ b/upload/bt/includes/tr_ratio.php @@ -0,0 +1,76 @@ + $limit) + { + if ($user_ratio < $ratio) + { + $tr_cfg['limit_active_tor'] = 1; + $tr_cfg['limit_leech_count'] = $limit; + $rating_msg = " (ratio < $ratio)"; + break; + } + } +} + +// Limit active torrents +if (!isset($bb_cfg['unlimited_users'][$user_id]) && $tr_cfg['limit_active_tor'] && (($tr_cfg['limit_seed_count'] && $seeder) || ($tr_cfg['limit_leech_count'] && !$seeder))) +{ + $sql = "SELECT COUNT(DISTINCT topic_id) AS active_torrents + FROM ". BB_BT_TRACKER ." + WHERE user_id = $user_id + AND seeder = $seeder + AND topic_id != $topic_id"; + + if (!$seeder && $tr_cfg['leech_expire_factor'] && $user_ratio < 0.5) + { + $sql .= " AND update_time > ". (TIMENOW - 60*$tr_cfg['leech_expire_factor']); + } + $sql .= " GROUP BY user_id"; + + if ($row = DB()->fetch_row($sql)) + { + if ($seeder && $tr_cfg['limit_seed_count'] && $row['active_torrents'] >= $tr_cfg['limit_seed_count']) + { + msg_die('Only '. $tr_cfg['limit_seed_count'] .' torrent(s) allowed for seeding'); + } + else if (!$seeder && $tr_cfg['limit_leech_count'] && $row['active_torrents'] >= $tr_cfg['limit_leech_count']) + { + msg_die('Only '. $tr_cfg['limit_leech_count'] .' torrent(s) allowed for leeching'. $rating_msg); + } + } +} + +// Limit concurrent IPs +if ($tr_cfg['limit_concurrent_ips'] && (($tr_cfg['limit_seed_ips'] && $seeder) || ($tr_cfg['limit_leech_ips'] && !$seeder))) +{ + $sql = "SELECT COUNT(DISTINCT ip) AS ips + FROM ". BB_BT_TRACKER ." + WHERE topic_id = $topic_id + AND user_id = $user_id + AND seeder = $seeder + AND ip != '$ip_sql'"; + + if (!$seeder && $tr_cfg['leech_expire_factor']) + { + $sql .= " AND update_time > ". (TIMENOW - 60*$tr_cfg['leech_expire_factor']); + } + $sql .= " GROUP BY topic_id"; + + if ($row = DB()->fetch_row($sql)) + { + if ($seeder && $tr_cfg['limit_seed_ips'] && $row['ips'] >= $tr_cfg['limit_seed_ips']) + { + msg_die('You can seed only from '. $tr_cfg['limit_seed_ips'] ." IP's"); + } + else if (!$seeder && $tr_cfg['limit_leech_ips'] && $row['ips'] >= $tr_cfg['limit_leech_ips']) + { + msg_die('You can leech only from '. $tr_cfg['limit_leech_ips'] ." IP's"); + } + } +} \ No newline at end of file diff --git a/upload/bt/includes/tr_scraper.php b/upload/bt/includes/tr_scraper.php new file mode 100644 index 000000000..bc8776e67 --- /dev/null +++ b/upload/bt/includes/tr_scraper.php @@ -0,0 +1,25 @@ +escape($info_hash), ' '); + +$row = DB()->fetch_row(" + SELECT tor.complete_count, snap.seeders, snap.leechers + FROM ". BB_BT_TORRENTS ." tor + LEFT JOIN ". BB_BT_TRACKER_SNAP ." snap ON (snap.topic_id = tor.topic_id) + WHERE tor.info_hash = '$info_hash_sql' + LIMIT 1 +"); + +$output['files'][$info_hash] = array( + 'complete' => (int) $row['seeders'], + 'downloaded' => (int) $row['complete_count'], + 'incomplete' => (int) $row['leechers'], +); + +echo bencode($output); + +tracker_exit(); \ No newline at end of file diff --git a/upload/bt/index.php b/upload/bt/index.php new file mode 100644 index 000000000..7e44c5d1d --- /dev/null +++ b/upload/bt/index.php @@ -0,0 +1,3 @@ + (int) 1800, + 'failure reason' => (string) $msg, + 'warning message' => (string) $msg, + )); + + die($output); +} + +define('TR_ROOT', './'); +require(TR_ROOT .'includes/init_tr.php'); +require(TR_ROOT .'includes/tr_scraper.php'); +exit; \ No newline at end of file diff --git a/upload/callseed.php b/upload/callseed.php new file mode 100644 index 000000000..ea492b690 --- /dev/null +++ b/upload/callseed.php @@ -0,0 +1,182 @@ +session_start(); + +require(INC_DIR .'bbcode.php'); +require(LANG_DIR .'lang_callseed.php'); + +function topic_info($topic_id) +{ + $sql = " SELECT tor.poster_id, tor.forum_id, tor.attach_id, t.topic_title, f.forum_name + FROM ". BB_BT_TORRENTS ." tor , ". BB_TOPICS ." t, ". BB_FORUMS ." f + WHERE tor.topic_id = $topic_id + AND t.topic_id = tor.topic_id + AND f.forum_id = tor.forum_id + LIMIT 1"; + $row = DB()->fetch_row($sql); + + $t = array( + "topic_title" => $row['topic_title'], + "forum_title" => $row['forum_name'], + "attach_id" => $row['attach_id'], + "topic_poster" => $row['poster_id'] + ); + + return $t; +} + +function send_pm($topic_id, $t_info, $to_user_id) +{ + global $userdata, $lang, $msg_error; + + $sql = "UPDATE ". BB_BT_TORRENTS ." SET call_seed_time=". TIMENOW ." WHERE topic_id = $topic_id"; + if (!DB()->sql_query($sql)) { + $msg_error = "TIME"; + return; + } + + $subj = sprintf ($lang['CALLSEED_SUBJ'], $t_info['topic_title']); + $text = sprintf ($lang['CALLSEED_TEXT'], $topic_id, $t_info['forum_title'], $t_info['topic_title'], $t_info['attach_id']); + $subj = DB()->escape($subj); + $text = DB()->escape($text); + + $sql = "INSERT INTO ". BB_PRIVMSGS ." (privmsgs_type, privmsgs_subject, privmsgs_from_userid, privmsgs_to_userid, privmsgs_date, privmsgs_ip) + VALUES (". PRIVMSGS_NEW_MAIL .",'$subj',{$userdata['user_id']},$to_user_id,". TIMENOW .",'". USER_IP ."')"; + if (!DB()->sql_query($sql)) { + $msg_error = "MSG"; + return; + } + + $id = DB()->sql_nextid(); + + $sql = "INSERT INTO ". BB_PRIVMSGS_TEXT ." VALUES($id, '". make_bbcode_uid() ."', '$text')"; + if (!DB()->sql_query($sql)) { + $msg_error = "MSG_TEXT"; + return; + } + + $sql = "UPDATE ". BB_USERS ." SET + user_new_privmsg = user_new_privmsg + 1, + user_last_privmsg = ". TIMENOW .", + user_newest_pm_id = $id + WHERE user_id = $to_user_id"; + if (!DB()->sql_query($sql)) { + $msg_error = "POPUP"; + return; + } +} + + $u_id = array(); + $topic_id = request_var('t', 0); + $t_info = topic_info($topic_id); + $msg_error = "OK"; + + $sql = "SELECT call_seed_time FROM ". BB_BT_TORRENTS ." WHERE topic_id = $topic_id LIMIT 1"; + if($row = DB()->fetch_row($sql)) + { + $pr_time = $row['call_seed_time']; + $pause = 86400; //1 day + $cp = TIMENOW - $pr_time; + $pcp = $pause - $cp; + if($cp <= $pause) + { + $cur_pause_hour = floor($pcp/3600); + $cur_pause_min = floor($pcp/60)/*-($cur_pause_hour*60)*/; + $msg_error = "SPAM"; + } + } + else + { + message_die(GENERAL_ERROR, 'Topic does not callseed time', '', __LINE__, __FILE__); + } + + // check have_seed + if ($msg_error == "OK") + { + $sql = "SELECT seeders, leechers FROM ". BB_BT_TRACKER_SNAP ." WHERE topic_id = $topic_id LIMIT 1"; + $row = DB()->fetch_row($sql); + if ($row['seeders'] > 2) + #if ( !in_array($userdata['user_level'], array(ADMIN, MOD)) ) + { + $seeders = $row['seeders']; + $leechers = $row['leechers']; + $msg_error = "HAVE_SEED"; + } + } + + $sql = "SELECT user_id FROM ". BB_BT_DLSTATUS ." WHERE topic_id = $topic_id"; + /*$row = DB()->fetch_rowset($sql);*/ + foreach(DB()->fetch_rowset($sql) as $row) + { + $u_id[] = $row['user_id']; + } + if (!in_array($t_info['topic_poster'], $u_id)) + { + $u_id[] = $t_info['topic_poster']; + } + array_unique($u_id); + + foreach($u_id as $i=>$user_id) + { + if ($msg_error != "OK") break; + + send_pm($topic_id, $t_info, $user_id); + } + + $msg = ''; + meta_refresh("viewtopic.php?t=$topic_id", 8); + $return_to = sprintf ($lang['CALLSEED_RETURN'], $topic_id); + + switch($msg_error) { + case "OK": + $msg .= $lang['CALLSEED_MSG_OK']; + break; + case "SPAM": + $msg .= sprintf ($lang['CALLSEED_MSG_SPAM'], $cur_pause_hour, $cur_pause_min); + break; + case "MSG": + $msg .= $lang['CALLSEED_MSG_MSG']; + break; + case "MSG_TEXT": + $msg .= $lang['CALLSEED_MSG_MSG_TEXT']; + break; + case "POPUP": + $msg .= $lang['CALLSEED_MSG_POPUP']; + break; + case "TIME": + $msg .= $lang['CALLSEED_MSG_TIME']; + break; + case "HAVE_SEED": + $msg .= sprintf ($lang['CALLSEED_HAVE_SEED'], $seeders, $leechers); + break; + } + +$msg .= $return_to; +message_die(GENERAL_MESSAGE, $msg); \ No newline at end of file diff --git a/upload/common.php b/upload/common.php new file mode 100644 index 000000000..91891eed7 --- /dev/null +++ b/upload/common.php @@ -0,0 +1,1277 @@ + $srv_cfg + var $srv = array(); // $srv_name => $db_obj + var $alias = array(); // $srv_alias => $srv_name + + var $log_file = 'sql_queries'; + var $log_counter = 0; + var $num_queries = 0; + var $sql_inittime = 0; + var $sql_timetotal = 0; + + function DBS ($cfg) + { + $this->cfg = $cfg['db']; + $this->alias = $cfg['db_alias']; + + foreach ($this->cfg as $srv_name => $srv_cfg) + { + $this->srv[$srv_name] = null; + } + } + + // / $srv_name + function get_db_obj ($srv_name_or_alias = 'db1') + { + $srv_name = $this->get_srv_name($srv_name_or_alias); + + if (!is_object($this->srv[$srv_name])) + { + $this->srv[$srv_name] = new sql_db($this->cfg[$srv_name]); + $this->srv[$srv_name]->db_server = $srv_name; + } + return $this->srv[$srv_name]; + } + + // + function get_srv_name ($name) + { + if (isset($this->alias[$name])) + { + $srv_name = $this->alias[$name]; + } + else if (isset($this->cfg[$name])) + { + $srv_name = $name; + } + else + { + $srv_name = 'db1'; + } + return $srv_name; + } +} + +$DBS = new DBS($bb_cfg); + +function DB ($db_alias = 'db1') +{ + global $DBS; + return $DBS->get_db_obj($db_alias); +} + +// Cache +define('PEER_HASH_PREFIX', 'peer_'); +define('PEERS_LIST_PREFIX', 'peers_list_'); + +define('PEER_HASH_EXPIRE', round($bb_cfg['announce_interval'] * (0.85*$tr_cfg['expire_factor']))); // sec +define('PEERS_LIST_EXPIRE', round($bb_cfg['announce_interval'] * 0.7)); // sec + +class CACHES +{ + var $cfg = array(); // + var $obj = array(); // - + var $ref = array(); // $obj (_ => _) + + function CACHES ($cfg) + { + $this->cfg = $cfg['cache']; + $this->obj['__stub'] = new cache_common(); + } + + function get_cache_obj ($cache_name) + { + if (!isset($this->ref[$cache_name])) + { + if (!$engine_cfg =& $this->cfg['engines'][$cache_name]) + { + $this->ref[$cache_name] =& $this->obj['__stub']; + } + else + { + $cache_type =& $engine_cfg[0]; + $cache_cfg =& $engine_cfg[1]; + + switch ($cache_type) + { + case 'cache_memcache': + if (!$mc_name =& $cache_cfg[0]) + { + trigger_error("empty mc_name for $cache_name cache", E_USER_ERROR); + } + if (!$mc_cfg =& $this->cfg['memcache'][$mc_name]) + { + trigger_error("mc_cfg for $cache_name not found", E_USER_ERROR); + } + if (!isset($this->obj[$mc_name])) + { + $servers = (array) $mc_cfg[0]; + $pconnect = $mc_cfg[1]; + $con_required = $mc_cfg[2]; + + $this->obj[$mc_name] = new cache_memcache(array( + 'mc_name' => $mc_name, + 'mc_class' => $this->cfg['mc_class'], // $bb_cfg['cache']['mc_class'] + 'servers' => $servers, + 'pconnect' => $pconnect, // $bb_cfg['cache']['pconnect'] + 'con_required' => $con_required, + )); + } + $this->ref[$cache_name] =& $this->obj[$mc_name]; + break; + + case 'cache_sqlite': + if (!isset($this->obj[$cache_name])) + { + $cache_cfg['pconnect'] = $this->cfg['pconnect']; + $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '_cache.sqlite.db'); + + $this->obj[$cache_name] = new cache_sqlite($cache_cfg); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'db_sqlite': + if (!isset($this->obj[$cache_name])) + { + $cache_cfg['pconnect'] = $this->cfg['pconnect']; + $cache_cfg['db_file_path'] = $this->get_db_path($cache_name, $cache_cfg, '.sqlite.db'); + $cache_cfg['table_name'] = $cache_name; + $cache_cfg['table_schema'] = $this->get_table_schema($cache_cfg); + + $this->obj[$cache_name] = new sqlite_common($cache_cfg); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + case 'filecache': + if (!isset($this->obj[$cache_name])) + { + $this->obj[$cache_name] = new cache_file($this->cfg['db_dir'] . $cache_name .'/'); + } + $this->ref[$cache_name] =& $this->obj[$cache_name]; + break; + + default: + trigger_error("invalid cache_type: $cache_type", E_USER_ERROR); + } + } + } + + return $this->ref[$cache_name]; + } + + function get_db_path ($name, $cfg, $ext) + { + if (!empty($cfg['shard_type']) && $cfg['shard_type'] != 'none') + { + return $this->cfg['db_dir'] . $name .'_*'. $ext; + } + else + { + return $this->cfg['db_dir'] . $name . $ext; + } + } + + function get_table_schema ($cfg) + { + return "CREATE TABLE {$cfg['table_name']} ( {$cfg['columns']} )"; + } +} + +$CACHES = new CACHES($bb_cfg); + +function CACHE ($cache_name) +{ + global $CACHES; + return $CACHES->get_cache_obj($cache_name); +} + +class cache_common +{ + var $used = false; + /** + * Returns value of variable + */ + function get ($key, $get_miss_key_callback = '', $prefix = '', $ttl = 604800) + { + if ($get_miss_key_callback) return $get_miss_key_callback($key); + return is_array($key) ? array() : false; + } + /** + * Store value of variable + */ + function set ($key, $value, $ttl = 604800, $prefix = '') + { + return false; + } + /** + * Remove variable + */ + function rm ($key, $prefix = '') + { + return false; + } +} + +class cache_memcache extends cache_common +{ + var $cfg = array( + 'mc_class' => 'class_name', // $bb_cfg['cache']['mc_class'] + ); + var $used = true; + var $db = null; + + function cache_memcache ($cfg) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->db = new $this->cfg['mc_class']($this->cfg); + } + + function get ($key, $get_miss_key_callback = '', $prefix = '', $ttl = 604800) + { + if (empty($key)) + { + return is_array($key) ? array() : false; + } + $cached_items = array(); + $prefix_len = strlen($prefix); + $key_ary = (array) $key; + $key_get = array(); + + foreach ($key_ary as $k) + { + $key_get[] = $prefix . $k; + } + + // get available items + foreach ($this->db->get($key_get) as $k => $v) + { + $cached_items[substr($k, $prefix_len)] = $v; + } + + // get miss items + if ($get_miss_key_callback AND $miss_key = array_diff($key_ary, array_keys($cached_items))) + { + foreach ($get_miss_key_callback($miss_key) as $k => $v) + { + $this->set($prefix.$k, $v, $ttl); + $cached_items[$k] = $v; + } + } + // return + if (is_array($key)) + { + return $cached_items; + } + else + { + return isset($cached_items[$key]) ? $cached_items[$key] : false; + } + } + + function set ($key, $value, $ttl = 604800, $prefix = '') + { + return $this->db->set($prefix.$key, $value, $ttl); + } + + function rm ($key, $prefix = '') + { + return $this->db->rm($prefix.$key); + } +} + +class memcache_common extends cache_dbg_common +{ + var $cfg = array( + 'mc_name' => null, // $bb_cfg['cache']['memcache'][ key ] + 'servers' => array('host:port'), // $bb_cfg['cache']['memcache'][ val ] + 'pconnect' => false, // $bb_cfg['cache']['pconnect'] + 'con_required' => false, + 'log_name' => 'memcache', + ); + var $engine = 'Memcache'; + var $mc = null; + + function memcache_common ($cfg = array()) + { + $this->mc = new Memcache(); + + $this->cfg = array_merge($this->cfg, $cfg); + $this->dbg_enabled = sql_dbg_enabled(); + + $this->init(); + } + + function init () + { + $this->cur_query = ($this->dbg_enabled) ? "addServer(". join(", ", (array)$this->cfg['servers']) .", ". (int) $this->cfg['pconnect'] .", ". (int) $this->cfg['con_required'] .")" : ''; + $this->debug('start'); + + foreach ($this->cfg['servers'] as $srv) + { + list($host, $port) = explode(':', $srv); + $this->mc->addServer($host, $port, $this->cfg['pconnect']); + } + $this->mc->setCompressThreshold(5000); + + $this->debug('stop'); + } + + function get ($key) + { + $this->cur_query = ($this->dbg_enabled) ? "get(". join(", ", (array)$key) .")" : ''; + $this->debug('start'); + + $result = $this->mc->get($key); + + if (!is_array($result)) + { + // + $result = array(); + } + + $this->debug('stop'); + return $result; + } + + function set ($key, $value, $ttl = 604800, $flag = 0) + { + $this->cur_query = ($this->dbg_enabled) ? "set($key, ". str_compact(print_r($value, true)) .")" : ''; + $this->debug('start'); + + $result = $this->mc->set($key, $value, $flag, $ttl); + + $this->debug('stop'); + return $result; + } + + function rm ($key) + { + $this->cur_query = ($this->dbg_enabled) ? "rm('$key')" : ''; + $this->debug('start'); + + $result = $this->mc->delete($key, 0); + + $this->debug('stop'); + return $result; + } +} + +class memcached_common extends cache_dbg_common +{ + var $cfg = array( + 'mc_name' => null, // $bb_cfg['cache']['memcache'][ key ] + 'servers' => array('host:port'), // $bb_cfg['cache']['memcache'][ val ] + 'pconnect' => false, // $bb_cfg['cache']['pconnect'] + 'con_required' => false, + 'log_name' => 'memcached', + ); + var $engine = 'Memcached'; + var $mc = null; + + function memcached_common ($cfg = array()) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->dbg_enabled = sql_dbg_enabled(); + + $persistent_id = ($this->cfg['pconnect']) ? $this->cfg['mc_name'] : ''; + + if ($this->dbg_enabled) + { + $pconnect = ($this->cfg['pconnect']) ? 'pcon' : 'not_pcon'; + $con_req = ($this->cfg['con_required']) ? 'req' : 'not_req'; + $this->engine .= "($persistent_id), $pconnect, $con_req"; + } + + $this->mc = new Memcached($persistent_id); + + $this->init(); + } + + function init () + { + if (!count($this->mc->getServerList())) + { + $this->cur_query = ($this->dbg_enabled) ? "addServer(". join(", ", (array)$this->cfg['servers']) .")" : ''; + $this->debug('start'); + + foreach ($this->cfg['servers'] as $srv) + { + list($host, $port) = explode(':', $srv); + $this->mc->addServer($host, $port); + } + + $this->debug('stop'); + } + } + + function get ($key) + { + $this->cur_query = ($this->dbg_enabled) ? "get(". join(", ", (array)$key) .")" : ''; + $this->debug('start'); + + $result = $this->mc->getMulti((array)$key); + + if (!is_array($result)) + { + $res_code = $this->mc->getResultCode(); + $res_msg = $this->mc->getResultMessage(); + $err_txt = "Memcached({$this->cfg['mc_name']})::get failed [$res_code, $res_msg]"; + + if ($this->cfg['con_required']) + { + trigger_error($err_txt, E_USER_ERROR); + } + else + { + bb_log(join(" ", array(date('d-m H:i:s'), $err_txt))."\n", 'mc_err'); + } + $result = array(); + } + + $this->debug('stop'); + return $result; + } + + function set ($key, $value, $ttl = 604800, $flag = 0) + { + $this->cur_query = ($this->dbg_enabled) ? "set($key, ". str_compact(print_r($value, true)) .")" : ''; + $this->debug('start'); + + $result = $this->mc->set($key, $value, $ttl); + + $this->debug('stop'); + return $result; + } + + function rm ($key) + { + $this->cur_query = ($this->dbg_enabled) ? "rm('$key')" : ''; + $this->debug('start'); + + $result = $this->mc->delete($key, 0); + + $this->debug('stop'); + return $result; + } +} + +class cache_sqlite extends cache_common +{ + var $used = true; + var $db = null; + var $cfg = array( + 'db_file_path' => '/path/to/cache.db.sqlite', + 'table_name' => 'cache', + 'table_schema' => 'CREATE TABLE cache ( + cache_name VARCHAR(255), + cache_expire_time INT, + cache_value TEXT, + PRIMARY KEY (cache_name) + )', + 'pconnect' => true, + 'con_required' => true, + 'log_name' => 'CACHE', + ); + + function cache_sqlite ($cfg) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->db = new sqlite_common($this->cfg); + } + + function get ($key, $get_miss_key_callback = '', $prefix = '', $ttl = 604800) + { + if (empty($key)) + { + return is_array($key) ? array() : false; + } + $this->db->shard($prefix.$key); + $cached_items = array(); + $prefix_len = strlen($prefix); + $prefix_sql = sqlite_escape_string($prefix); + + $key_ary = $key_sql = (array) $key; + array_deep($key_sql, 'sqlite_escape_string'); + + // get available items + $rowset = $this->db->fetch_rowset(" + SELECT cache_name, cache_value + FROM ". $this->cfg['table_name'] ." + WHERE cache_name IN('$prefix_sql". join("','$prefix_sql", $key_sql) ."') AND cache_expire_time > ". TIMENOW ." + LIMIT ". count($key) ." + "); + + $this->db->debug('start', 'unserialize()'); + foreach ($rowset as $row) + { + $cached_items[substr($row['cache_name'], $prefix_len)] = unserialize($row['cache_value']); + } + $this->db->debug('stop'); + + // get miss items + if ($get_miss_key_callback AND $miss_key = array_diff($key_ary, array_keys($cached_items))) + { + foreach ($get_miss_key_callback($miss_key) as $k => $v) + { + $this->set($prefix.$k, $v, $ttl); + $cached_items[$k] = $v; + } + } + // return + if (is_array($key)) + { + return $cached_items; + } + else + { + return isset($cached_items[$key]) ? $cached_items[$key] : false; + } + } + + function set ($key, $value, $ttl = 604800, $prefix = '') + { + $this->db->shard($prefix.$key); + $key_sql = sqlite_escape_string($prefix.$key); + $expire = TIMENOW + $ttl; + $value_sql = sqlite_escape_string(serialize($value)); + + $result = $this->db->query("REPLACE INTO ". $this->cfg['table_name'] ." (cache_name, cache_expire_time, cache_value) VALUES ('$key_sql', $expire, '$value_sql')"); + return (bool) $result; + } + + function rm ($key, $prefix = '') + { + $this->db->shard($prefix.$key); + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($prefix.$key) ."'"); + return (bool) $result; + } + + function gc ($expire_time = TIMENOW) + { + $result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time"); + return ($result) ? sqlite_changes($this->db->dbh) : 0; + } +} + +class sqlite_common extends cache_dbg_common +{ + var $cfg = array( + 'db_file_path' => 'sqlite.db', + 'table_name' => 'table_name', + 'table_schema' => 'CREATE TABLE table_name (...)', + 'pconnect' => true, + 'con_required' => true, + 'log_name' => 'SQLite', + 'shard_type' => 'none', # none, string, int ( ) + 'shard_val' => 0, # string - . , int - ( ) + ); + var $engine = 'SQLite DB'; + var $dbh = null; + var $connected = false; + var $shard_val = false; + + var $table_create_attempts = 0; + + function sqlite_common ($cfg) + { + $this->cfg = array_merge($this->cfg, $cfg); + $this->dbg_enabled = sql_dbg_enabled(); + } + + function connect () + { + $this->cur_query = ($this->dbg_enabled) ? ($this->cfg['pconnect'] ? 'p' : '') .'connect to: '. $this->cfg['db_file_path'] : 'connect'; + $this->debug('start'); + + $connect_type = ($this->cfg['pconnect']) ? 'sqlite_popen' : 'sqlite_open'; + + if ($this->cfg['shard_type'] != 'none' && $this->shard_val === false) + { + trigger_error("cannot shard: shard_val not defined for {$this->cfg['db_file_path']}", E_USER_ERROR); + } + + if (@$this->dbh = $connect_type($this->cfg['db_file_path'], 0666, $sqlite_error)) + { + $this->connected = true; + } + + if (!$this->connected && $this->cfg['con_required']) + { + trigger_error($sqlite_error, E_USER_ERROR); + } + + $this->debug('stop'); + $this->cur_query = null; + } + + function create_table () + { + $this->table_create_attempts++; + return sqlite_query($this->dbh, $this->cfg['table_schema']); + } + + function shard ($key) + { + $type = $this->cfg['shard_type']; + + if ($type == 'none') return; + if (is_array($key)) trigger_error('cannot shard: $key is array', E_USER_ERROR); + + // define shard_val + if ($type == 'string') + { + $shard_val = substr($key, 0, $this->cfg['shard_val']); + } + else + { + $shard_val = $key % $this->cfg['shard_val']; + } + // + if ($this->shard_val !== false) + { + if ($shard_val != $this->shard_val) + { + trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $key]", E_USER_ERROR); + } + else + { + return; + } + } + $this->shard_val = $shard_val; + $this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']); + } + + function query ($query) + { + if (!$this->connected) $this->connect(); + + $this->cur_query = $query; + $this->debug('start'); + + if (!$result = @sqlite_unbuffered_query($this->dbh, $query, SQLITE_ASSOC)) + { + if (!$this->table_create_attempts && !sqlite_num_rows(sqlite_query($this->dbh, "PRAGMA table_info({$this->cfg['table_name']})"))) + { + if ($this->create_table()) + { + $result = sqlite_unbuffered_query($this->dbh, $query, SQLITE_ASSOC); + } + } + if (!$result) + { + $this->trigger_error($this->get_error_msg()); + } + } + + $this->debug('stop'); + $this->cur_query = null; + + $this->num_queries++; + + return $result; + } + + function fetch_row ($query) + { + $result = $this->query($query); + return is_resource($result) ? sqlite_fetch_array($result, SQLITE_ASSOC) : false; + } + + function fetch_rowset ($query) + { + $result = $this->query($query); + return is_resource($result) ? sqlite_fetch_all($result, SQLITE_ASSOC) : array(); + } + + function changes () + { + return is_resource($this->dbh) ? sqlite_changes($this->dbh) : 0; + } + + function escape ($str) + { + return sqlite_escape_string($str); + } + + function get_error_msg () + { + return 'SQLite error #'. ($err_code = sqlite_last_error($this->dbh)) .': '. sqlite_error_string($err_code); + } + + function trigger_error ($msg = 'DB Error') + { + if (error_reporting()) trigger_error($msg, E_USER_ERROR); + } +} + +class cache_dbg_common +{ + var $num_queries = 0; + var $sql_starttime = 0; + var $sql_inittime = 0; + var $sql_timetotal = 0; + var $cur_query_time = 0; + + var $dbg = array(); + var $dbg_id = 0; + var $dbg_enabled = false; + var $cur_query = null; + + function debug ($mode, $cur_query = null) + { + if (!$this->dbg_enabled) return; + + $id =& $this->dbg_id; + $dbg =& $this->dbg[$id]; + + if ($mode == 'start') + { + $this->sql_starttime = utime(); + + $dbg['sql'] = isset($cur_query) ? short_query($cur_query) : short_query($this->cur_query); + $dbg['src'] = $this->debug_find_source(); + $dbg['file'] = $this->debug_find_source('file'); + $dbg['line'] = $this->debug_find_source('line'); + $dbg['time'] = ''; + } + else if ($mode == 'stop') + { + $this->cur_query_time = utime() - $this->sql_starttime; + $this->sql_timetotal += $this->cur_query_time; + $dbg['time'] = $this->cur_query_time; + $id++; + } + } + + function debug_find_source ($mode = '') + { + foreach (debug_backtrace() as $trace) + { + if ($trace['file'] !== __FILE__) + { + switch ($mode) + { + case 'file': return $trace['file']; + case 'line': return $trace['line']; + default: return hide_bb_path($trace['file']) .'('. $trace['line'] .')'; + } + } + } + return 'src not found'; + } +} + +function sql_dbg_enabled () +{ + return (SQL_DEBUG && DBG_USER && !empty($_COOKIE['sql_log'])); +} + +function short_query ($sql, $esc_html = false) +{ + $max_len = 2500; + $sql = str_compact($sql); + + if (empty($_COOKIE['sql_log_full'])) + { + if (strlen($sql) > $max_len) + { + $sql = substr($sql, 0, $max_len-500) .' [...cut...] '. substr($sql, -480); + } + } + + return ($esc_html) ? htmlCHR($sql, true) : $sql; +} + +class cache_file extends cache_common +{ + var $used = true; + + var $dir = null; + + function cache_file ($dir) + { + $this->dir = $dir; + } + + function get ($name) + { + $filename = $this->dir . clean_filename($name) . '.php'; + + if(file_exists($filename)) + { + require($filename); + } + + return (!empty($filecache['value'])) ? $filecache['value'] : false; + } + + function set ($name, $value, $ttl = 86400) + { + if (!function_exists('var_export')) + { + return false; + } + + $filename = $this->dir . clean_filename($name) . '.php'; + $expire = TIMENOW + $ttl; + $cache_data = array( + 'expire' => $expire, + 'value' => $value, + ); + + $filecache = "'; + + return (bool) file_write($filecache, $filename, false, true, true); + } + + function rm ($name) + { + $filename = $this->dir . clean_filename($name) . '.php'; + if (file_exists($filename)) + { + return (bool) unlink($filename); + } + return false; + } + + function gc ($expire_time = TIMENOW) + { + $dir = $this->dir; + + if (is_dir($dir)) + { + if ($dh = opendir($dir)) + { + while (($file = readdir($dh)) !== false) + { + if ($file != "." && $file != "..") + { + $filename = $dir . $file; + + require($filename); + + if(!empty($filecache['expire']) && ($filecache['expire'] < $expire_time)) + { + unlink($filename); + } + } + } + closedir($dh); + } + } + + return; + } +} + +// Functions +function utime () +{ + return array_sum(explode(' ', microtime())); +} + +function bb_log ($msg, $file_name) +{ + if (is_array($msg)) + { + $msg = join(LOG_LF, $msg); + } + $file_name .= (LOG_EXT) ? '.'. LOG_EXT : ''; + return file_write($msg, LOG_DIR . $file_name); +} + +function file_write ($str, $file, $max_size = LOG_MAX_SIZE, $lock = true, $replace_content = false) +{ + $bytes_written = false; + + if ($max_size && @filesize($file) >= $max_size) + { + $old_name = $file; $ext = ''; + if (preg_match('#^(.+)(\.[^\\/]+)$#', $file, $matches)) + { + $old_name = $matches[1]; $ext = $matches[2]; + } + $new_name = $old_name .'_[old]_'. date('Y-m-d_H-i-s_') . getmypid() . $ext; + clearstatcache(); + if (@file_exists($file) && @filesize($file) >= $max_size && !@file_exists($new_name)) + { + @rename($file, $new_name); + } + } + if (!$fp = @fopen($file, 'ab')) + { + if ($dir_created = bb_mkdir(dirname($file))) + { + $fp = @fopen($file, 'ab'); + } + } + if ($fp) + { + if ($lock) + { + @flock($fp, LOCK_EX); + } + if ($replace_content) + { + @ftruncate($fp, 0); + @fseek($fp, 0, SEEK_SET); + } + $bytes_written = @fwrite($fp, $str); + @fclose($fp); + } + + return $bytes_written; +} + +function bb_mkdir ($path, $mode = 0777) +{ + $old_um = umask(0); + $dir = mkdir_rec($path, $mode); + umask($old_um); + return $dir; +} + +function mkdir_rec ($path, $mode) +{ + if (is_dir($path)) + { + return ($path !== '.' && $path !== '..') ? is_writable($path) : false; + } + else + { + return (mkdir_rec(dirname($path), $mode)) ? @mkdir($path, $mode) : false; + } +} + +function verify_id ($id, $length) +{ + return (preg_match('#^[a-zA-Z0-9]{'. $length .'}$#', $id) && is_string($id)); +} + +function clean_filename ($fname) +{ + static $s = array('\\', '/', ':', '*', '?', '"', '<', '>', '|', ' '); + return str_replace($s, '_', str_compact($fname)); +} + +function encode_ip ($dotquad_ip) +{ + $ip_sep = explode('.', $dotquad_ip); + if (count($ip_sep) == 4) + { + return sprintf('%02x%02x%02x%02x', $ip_sep[0], $ip_sep[1], $ip_sep[2], $ip_sep[3]); + } + + $ip_sep = explode(':', preg_replace('/(^:)|(:$)/', '', $dotquad_ip)); + $res = ''; + foreach ($ip_sep as $x) + { + $res .= sprintf('%0'. ($x == '' ? (9 - count($ip_sep)) * 4 : 4) .'s', $x); + } + return $res; +} + +function decode_ip ($int_ip) +{ + $int_ip = trim($int_ip); + + if (strlen($int_ip) == 32) + { + $int_ip = substr(chunk_split($int_ip, 4, ':'), 0, 39); + $int_ip = ':'. implode(':', array_map("hexhex", explode(':',$int_ip))) .':'; + preg_match_all("/(:0)+/", $int_ip, $zeros); + if (count($zeros[0]) > 0) + { + $match = ''; + foreach($zeros[0] as $zero) + if (strlen($zero) > strlen($match)) + $match = $zero; + $int_ip = preg_replace('/'. $match .'/', ':', $int_ip, 1); + } + return preg_replace('/(^:([^:]))|(([^:]):$)/', '$2$4', $int_ip); + } + if (strlen($int_ip) !== 8) $int_ip = '00000000'; + $hexipbang = explode('.', chunk_split($int_ip, 2, '.')); + return hexdec($hexipbang[0]). '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]); +} + +function hexhex ($value) +{ + return dechex(hexdec($value)); +} + +function verify_ip ($ip) +{ + return preg_match('#^(\d{1,3}\.){3}\d{1,3}$#', $ip); +} + +function str_compact ($str) +{ + return preg_replace('#\s+#', ' ', trim($str)); +} + +function make_rand_str ($len = 10) +{ + $str = ''; + while (strlen($str) < $len) + { + $str .= str_shuffle(preg_replace('#[^0-9a-zA-Z]#', '', crypt(uniqid(mt_rand(), true)))); + } + return substr($str, 0, $len); +} + +// bencode: based on OpenTracker [http://whitsoftdev.com/opentracker] +function bencode ($var) +{ + if (is_string($var)) + { + return strlen($var) .':'. $var; + } + else if (is_int($var)) + { + return 'i'. $var .'e'; + } + else if (is_float($var)) + { + return 'i'. sprintf('%.0f', $var) .'e'; + } + else if (is_array($var)) + { + if (count($var) == 0) + { + return 'de'; + } + else + { + $assoc = false; + + foreach ($var as $key => $val) + { + if (!is_int($key)) + { + $assoc = true; + break; + } + } + + if ($assoc) + { + ksort($var, SORT_REGULAR); + $ret = 'd'; + + foreach ($var as $key => $val) + { + $ret .= bencode($key) . bencode($val); + } + return $ret .'e'; + } + else + { + $ret = 'l'; + + foreach ($var as $val) + { + $ret .= bencode($val); + } + return $ret .'e'; + } + } + } + else + { + trigger_error('bencode error: wrong data type', E_USER_ERROR); + } +} + +function array_deep (&$var, $fn, $one_dimensional = false, $array_only = false) +{ + if (is_array($var)) + { + foreach ($var as $k => $v) + { + if (is_array($v)) + { + if ($one_dimensional) + { + unset($var[$k]); + } + else if ($array_only) + { + $var[$k] = $fn($v); + } + else + { + array_deep($var[$k], $fn); + } + } + else if (!$array_only) + { + $var[$k] = $fn($v); + } + } + } + else if (!$array_only) + { + $var = $fn($var); + } +} + +function hide_bb_path ($path) +{ + return ltrim(str_replace(BB_PATH, '', $path), '/\\'); +} + +function tr_drop_request ($drop_type) +{ + if (DBG_LOG) dbg_log(' ', "request-dropped-$drop_type"); + dummy_exit(mt_rand(300, 900)); +} + +function get_loadavg () +{ + if (is_callable('sys_getloadavg')) + { + $loadavg = join(' ', sys_getloadavg()); + } + else if (strpos(PHP_OS, 'Linux') !== false) + { + $loadavg = @file_get_contents('/proc/loadavg'); + } + + return !empty($loadavg) ? $loadavg : 0; +} + +function sys ($param) +{ + switch ($param) + { + case 'la': + return function_exists('sys_getloadavg') ? join(' ', sys_getloadavg()) : 0; + break; + case 'mem': + return function_exists('memory_get_usage') ? memory_get_usage() : 0; + break; + case 'mem_peak': + return function_exists('memory_get_peak_usage') ? memory_get_peak_usage() : 0; + break; + default: + trigger_error("invalid param: $param", E_USER_ERROR); + } +} + +function ver_compare ($version1, $operator, $version2) +{ + return version_compare($version1, $version2, $operator); +} + +// Board init +if (defined('IN_PHPBB')) +{ + require(INC_DIR .'init_bb.php'); +} +// Tracker init +else if (defined('IN_TRACKER')) +{ + define('DUMMY_PEER', pack('Nn', ip2long($_SERVER['REMOTE_ADDR']), !empty($_GET['port']) ? intval($_GET['port']) : mt_rand(1000, 65000))); + + function dummy_exit ($interval = 1800) + { + $output = bencode(array( + 'interval' => (int) $interval, + 'min interval' => (int) $interval, + 'peers' => (string) DUMMY_PEER, + )); + + die($output); + } + + header('Content-Type: text/plain'); + header('Pragma: no-cache'); + + if (STRIP_SLASHES) + { + array_deep($_GET, 'stripslashes'); + array_deep($_POST, 'stripslashes'); + } + + if (!defined('IN_ADMIN')) + { + // Exit if tracker is disabled via ON/OFF trigger + if (file_exists(BB_DISABLED)) + { + dummy_exit(mt_rand(1200, 2400)); # die('d14:failure reason20:temporarily disablede'); + } + + // Limit server load + if ($bb_cfg['max_srv_load'] || $bb_cfg['tr_working_second']) + { + if ((!empty($_GET['uploaded']) || !empty($_GET['downloaded'])) && (!isset($_GET['event']) || $_GET['event'] === 'started')) + { + if ($bb_cfg['tr_working_second'] && (TIMENOW % $bb_cfg['tr_working_second'])) + { + tr_drop_request('wrk_sec'); + } + else if ($bb_cfg['max_srv_load'] && LOADAVG) + { + if (LOADAVG > $bb_cfg['max_srv_load']) + { + tr_drop_request('load'); + } + } + } + } + } +} diff --git a/upload/config.php b/upload/config.php new file mode 100644 index 000000000..3e53f7ad9 --- /dev/null +++ b/upload/config.php @@ -0,0 +1,547 @@ + 'srv_name' +); + +// http://www.php.net/manual/en/mysql.constants.php#mysql.client-flags +define('DBFLAGS', NULL); // Flags: MYSQL_CLIENT_COMPRESS - Compress MySQL +define('DBMS', 'mysql'); +define('DBCOLLATION', ''); +define('PCONNECT', false); + +// Cache +$bb_cfg['cache']['pconnect'] = false; +$bb_cfg['cache']['db_dir'] = realpath(BB_ROOT) .'/cache/filecache/'; + +$bb_cfg['cache']['memcache'] = array( + // cache + 'mc_bb_core' => array('localhost:11211', false, false), + // datastore + 'ds_bb_core' => array('localhost:11211', false, false), +); + +$bb_cfg['cache']['mc_class'] = 'memcache_common'; // memcache_common, memcached_common + +# name => array( (string) type, (array) cfg ) + +$bb_cfg['cache']['engines'] = array( + 'bb_cache' => array('filecache', array()), + 'tr_cache' => array('filecache', array()), + 'session_cache' => array('filecache', array()), + + 'bb_cap_sid' => array('cache_sqlite', array()), + 'bb_login_err' => array('cache_sqlite', array()), +); + +// Datastore +$bb_cfg['datastore_type'] = 'filecache'; // Available datastore types: mysql, sqlite, memcache, filecache + +$bb_cfg['datastore']['sqlite'] = array( + 'db_file_path' => $bb_cfg['cache']['db_dir'] . '/bb_datastore.sqlite.db', + 'pconnect' => false, +); +$bb_cfg['datastore']['mc']['srv_all'] = array( + 'ds_bb_core', +); +$bb_cfg['datastore']['mc']['srv_loc'] = 'undefined'; // должен быть определен в node_config.php +// создание конфига кешей +foreach ($bb_cfg['datastore']['mc']['srv_all'] as $ds_srv) +{ + $bb_cfg['cache']['engines'][$ds_srv] = array('cache_memcache', array($ds_srv)); +} + +// Tracker +$bb_cfg['announce_type'] = 'xbt'; // Тип анонсера, xbt или php +$bb_cfg['announce_interval'] = 2400; // Announce interval (default: 1800) +$bb_cfg['passkey_key'] = 'uk'; // Passkey key name in GET request +$bb_cfg['ignore_reported_ip'] = false; // Ignore IP reported by client +$bb_cfg['verify_reported_ip'] = true; // Verify IP reported by client against $_SERVER['HTTP_X_FORWARDED_FOR'] +$bb_cfg['allow_internal_ip'] = false; // Allow internal IP (10.xx.. etc.) + +$bb_cfg['how_to_download_url_help'] = 'viewtopic.php?t=1'; // URL help link for "How to Download?" +$bb_cfg['what_is_torrent_url_help'] = 'viewtopic.php?t=2'; // URL help link for "What is Bittorrent?" +$bb_cfg['ratio_url_help'] = 'viewtopic.php?t=3'; // URL help link for Ratio. + +//$bb_cfg['bt_ratio_warning_msg'] = '$bb_cfg[\'bt_ratio_warning_msg\']'; /* Перемещено в "attach_mod\displaying_torrent.php" */ + +$bb_cfg['bt_min_ratio_allow_dl_tor'] = 0; // 0 - disable +$bb_cfg['bt_min_ratio_warning'] = 0; // 0 - disable +$bb_cfg['bt_ratio_warning_url_help'] = $bb_cfg['ratio_url_help']; // URL help link, for limit end. +$bb_cfg['bt_min_ratio_dl_button'] = 0; // 0 - disable + +$tr_cfg = array( + 'autoclean' => true, + 'off' => false, + 'off_reason' => 'temporarily disabled', + 'numwant' => 50, + 'update_dlstat' => true, + 'expire_factor' => 2.5, + 'compact_mode' => true, + 'upd_user_up_down_stat' => true, + 'browser_redirect_url' => '', + 'scrape' => true, + 'limit_active_tor' => true, + 'limit_seed_count' => 0, + 'limit_leech_count' => 8, + 'leech_expire_factor' => 60, + 'limit_concurrent_ips' => false, + 'limit_seed_ips' => 0, + 'limit_leech_ips' => 2, +); + +$bb_cfg['show_dl_status_in_search'] = true; +$bb_cfg['show_dl_status_in_forum'] = true; + +$bb_cfg['show_tor_info_in_dl_list'] = true; // http://trac.torrentpier.com/trac/changeset/377 +$bb_cfg['allow_dl_list_names_mode'] = true; + +// Torrents +$bb_cfg['torrent_sign'] = ''; // e.g. "[yoursite.com]" +$bb_cfg['tor_help_links'] = ''; + +// Days to keep torrent registered, if: +$bb_cfg['seeder_last_seen_days_keep'] = 20; +$bb_cfg['seeder_never_seen_days_keep'] = 5; + +// Ratio limits +define('TR_RATING_LIMITS', true); // ON/OFF +define('MIN_DL_FOR_RATIO', 5368709120); // in bytes, 0 - disable + +// Don't change the order of ratios (from 0 to 1) +// rating < 0.4 -- allow only 1 torrent for leeching +// rating < 0.5 -- only 2 +// rating < 0.6 -- only 3 +// rating > 0.6 -- depend on your tracker config limits (in "ACP - Tracker Config - Limits") +$rating_limits = array( + '0.4' => 1, + '0.5' => 2, + '0.6' => 3, +); + +// Seeding torrents limit +$bb_cfg['max_seeding_torrents'] = 0; // 0 - unlimited +$bb_cfg['min_up_speed_per_torrent'] = 500; // bytes +$bb_cfg['too_many_seeding_redirect_url'] = 'viewtopic.php?t=TOPIC_ID'; + +// DL-Status +$bb_cfg['dl_will_days_keep'] = 60; // days to keep user's dlstatus records +$bb_cfg['dl_down_days_keep'] = 30; +$bb_cfg['dl_complete_days_keep'] = 180; +$bb_cfg['dl_cancel_days_keep'] = 30; + +// Tor-Stats +$bb_cfg['torstat_days_keep'] = 60; // days to keep user's per-torrent stats + +// Tor-Help +$bb_cfg['torhelp_enabled'] = true; // find dead torrents (without seeder) that user might help seeding + +$page_cfg['show_torhelp'] = array( +# BB_SCRIPT => true + 'index' => true, + 'tracker' => true, +); + +// Path (trailing slash '/' at the end: XX_PATH - without, XX_DIR - with) +define('DIR_SEPR', DIRECTORY_SEPARATOR); + +define('BB_PATH', realpath(BB_ROOT) ); // absolute pathname to the forum root +define('ADMIN_DIR', BB_PATH .'/admin/' ); +define('CACHE_DIR', BB_PATH .'/cache/' ); +define('CFG_DIR', BB_PATH .'/config/' ); +define('DEV_DIR', BB_PATH .'/develop/' ); +define('INC_DIR', BB_PATH .'/includes/' ); +define('LANG_ROOT_DIR', BB_PATH .'/language/' ); +define('LOG_DIR', BB_PATH .'/log/' ); +define('TEMPLATES_DIR', BB_PATH .'/templates/'); +define('TRIGGERS_DIR', BB_PATH .'/triggers/' ); + +// Language +setlocale(LC_ALL, 'ru_RU.UTF-8'); +setlocale(LC_NUMERIC, 'C'); +$bb_cfg['default_lang_dir'] = LANG_ROOT_DIR .'lang_russian/'; + +// Templates +define('ADMIN_TPL_DIR', TEMPLATES_DIR .'/admin/'); + +$bb_cfg['tpl_name'] = 'default'; +$bb_cfg['stylesheet'] = 'main.css'; +$bb_cfg['theme_css'] = 'theme_default.css'; + +$bb_cfg['show_sidebar1_on_every_page'] = false; +$bb_cfg['show_sidebar2_on_every_page'] = false; + +$bb_cfg['sidebar1_static_content_path'] = BB_PATH .'/misc/html/sidebar1.html'; # +$bb_cfg['sidebar2_static_content_path'] = ''; + +$page_cfg['show_sidebar1'] = array( +# BB_SCRIPT => true + 'index' => true, +); +$page_cfg['show_sidebar2'] = array( +# BB_SCRIPT => true + 'index' => false, +); + +$bb_cfg['topic_tpl']['overall_header'] = TEMPLATES_DIR .'topic_tpl_overall_header.html'; +$bb_cfg['topic_tpl']['rules_video'] = TEMPLATES_DIR .'topic_tpl_rules_video.html'; + +// Cookie +$bb_cfg['cookie_domain'] = ''; # '.yourdomain.com' +$bb_cfg['cookie_path'] = '/forum/'; # '/forum/' +$bb_cfg['cookie_secure'] = (!empty($_SERVER['HTTPS']) ? 1 : 0); # 0 +$bb_cfg['cookie_prefix'] = 'bb_'; # 'bb_' + +define('COOKIE_DBG', 'bb_dbg'); // debug cookie name + +// Server +$bb_cfg['server_name'] = $_SERVER['SERVER_NAME']; // The domain name from which this board runs +$bb_cfg['server_port'] = $_SERVER['SERVER_PORT']; // The port your server is running on +$bb_cfg['script_path'] = '/forum/'; // The path where FORUM is located relative to the domain name +$bb_cfg['sitename'] = 'TorrentPier II - Torrent Tracker'; // Name of your site + +// Server load +$bb_cfg['max_srv_load'] = 0; // 0 - disable +$bb_cfg['tr_working_second'] = 0; // 0 - disable + +// Backup +$bb_cfg['db_backup_shell_cmd'] = ''; // '/path/to/db_backup.sh 2>&1' +$bb_cfg['site_backup_shell_cmd'] = ''; + +// GZip +$bb_cfg['gzip_compress'] = false; // compress output +$bb_cfg['gzip_force'] = false; // always compress (don't check client compatibility) + +// Sessions +$bb_cfg['session_update_intrv'] = 180; // sec + +$bb_cfg['user_session_duration'] = 1800; // sec +$bb_cfg['admin_session_duration'] = 6*3600; // sec +$bb_cfg['user_session_gc_ttl'] = 1800; // number of seconds that a staled session entry may remain in sessions table +$bb_cfg['session_cache_gc_ttl'] = 1200; // sec +$bb_cfg['max_reg_users_online'] = 0; // 0 - unlimited +$bb_cfg['max_last_visit_days'] = 14; // days +$bb_cfg['last_visit_update_intrv'] = 3600; // sec + +// Registration +$bb_cfg['new_user_reg_disabled'] = false; // Disable new user registrations +$bb_cfg['unique_ip'] = false; // Deny registration of several accounts by one ip +$bb_cfg['new_user_reg_restricted'] = false; +$bb_cfg['reg_email_activation'] = false; + + +// Email +$bb_cfg['emailer_disabled'] = false; + +$bb_cfg['topic_notify_enabled'] = true; +$bb_cfg['pm_notify_enabled'] = true; +$bb_cfg['groupcp_send_email'] = true; +$bb_cfg['email_change_disabled'] = false; // disable changing email by user + +$bb_cfg['tech_admin_email'] = 'admin@' . $bb_cfg['server_name']; // email for sending error reports +$bb_cfg['abuse_email'] = 'abuse@' . $bb_cfg['server_name']; +$bb_cfg['email_default_charset'] = 'UTF-8'; + +// AJAX +define('AJAX_HTML_DIR', BB_ROOT .'ajax/html/'); +define('AJAX_DIR', BB_ROOT .'ajax/'); + +// Debug +define('DEBUG', false); // !!! "DEBUG" should be ALWAYS DISABLED on production environment !!! +define('DBG_LOG', false); +define('DBG_TIME', true); // false, true или рабочая секудна (при 3 - запись в лог будет только если текущее время кратно 3) +define('DBG_LOG_GENTIME', true); +define('DBG_LOG_ERRORS', true); +define('PROFILER', false); // Profiler extension name, or FALSE to disable (supported: 'dbg') + +define('SQL_DEBUG', true); +define('SQL_LOG_ERRORS', true); // all SQL_xxx options enabled only if SQL_DEBUG == TRUE +define('SQL_CALC_QUERY_TIME', true); // for stats +define('SQL_LOG_SLOW_QUERIES', true); +define('SQL_SLOW_QUERY_TIME', 10); // sec +define('SQL_PREPEND_SRC_COMM', false); // prepend source file(line) comment to sql query + + +// Special users +$bb_cfg['dbg_users'] = array( +# user_id => 'name', + 2 => 'admin', +); + +$bb_cfg['unlimited_users'] = array( +# user_id => 'name', + 2 => 'admin', +); + +$bb_cfg['super_admins'] = array( +# user_id => 'name', + 2 => 'admin', +); + +$bb_cfg['no_form_token_users'] = array( +# user_id => 'name', + 2 => 'admin', +); + +// Log options +define('LOG_EXT', 'log'); +define('LOG_SEPR', ' | '); +define('LOG_LF', "\n"); +define('LOG_MAX_SIZE', 1048576); // bytes + +// Log request +$log_ip_req = array( +# '127.0.0.1' => 'user1', // CLIENT_IP => 'name' +# '7f000001' => 'user2', // USER_IP => 'name' +); + +$log_passkey = array( +# 'passkey' => 'log_filename', +); + +// Log response +$log_ip_resp = array( +# '127.0.0.1' => 'user1', // CLIENT_IP => 'name' +# '7f000001' => 'user2', // USER_IP => 'name' +); + +// Error reporting +if (DEBUG) +{ + error_reporting(E_ALL); + ini_set('display_errors', 1); + ini_set('log_errors', 0); +} +else +{ + error_reporting(E_ALL); # E_ALL & ~E_NOTICE + ini_set('display_errors', 0); + ini_set('log_errors', 1); +} +ini_set('error_log', LOG_DIR .'php_err.log'); + +// Disable magic_quotes_runtime +@set_magic_quotes_runtime(0); +ini_set("magic_quotes_runtime", 0); +define('STRIP_SLASHES', get_magic_quotes_gpc()); +if (STRIP_SLASHES) die('set magic_quotes off'); + +// Triggers +define('BB_ENABLED', TRIGGERS_DIR .'$on'); +define('BB_DISABLED', TRIGGERS_DIR .'$off'); +define('CRON_ALLOWED', TRIGGERS_DIR .'cron_allowed'); +define('CRON_RUNNING', TRIGGERS_DIR .'cron_running'); + +// Cron +// старт производится из cron.php +$bb_cfg['cron_check_interval'] = 45; // sec + +// News +$bb_cfg['show_latest_news'] = true; +$bb_cfg['latest_news_count'] = 5; +$bb_cfg['latest_news_forum_id'] = '1'; // (string) 1,2,3... + +// Subforums +$bb_cfg['sf_on_first_page_only'] = true; +$bb_cfg['sf_check_view_permissions'] = false; + +// Forums +$bb_cfg['allowed_topics_per_page'] = array(50, 100, 150, 200, 250, 300); + +// Topics +$bb_cfg['show_quick_reply'] = true; +$bb_cfg['show_rank_text'] = false; +$bb_cfg['show_rank_image'] = true; +$bb_cfg['show_poster_joined'] = true; +$bb_cfg['show_poster_posts'] = true; +$bb_cfg['show_poster_from'] = true; +$bb_cfg['show_poster_flag'] = true; +$bb_cfg['show_bot_nick'] = false; +$bb_cfg['text_buttons'] = true; // replace EDIT, QUOTE... images with text links +$bb_cfg['parse_ed2k_links'] = true; // make ed2k links clickable +$bb_cfg['post_date_format'] = 'd-M-Y H:i'; +$bb_cfg['ext_link_new_win'] = true; // open external links in new window + +$bb_cfg['topic_moved_days_keep'] = 7; // remove topic moved links after xx days (or FALSE to disable) + +$bb_cfg['allowed_posts_per_page'] = array(15, 30, 50, 100); + +// Posts +$bb_cfg['use_posts_cache'] = true; // if you switch from ON to OFF, you need to TRUNCATE `bb_posts_html` table +$bb_cfg['posts_cache_days_keep'] = 14; +$bb_cfg['max_post_length'] = 120000; // bytes + +// Search +$bb_cfg['search_engine_type'] = 'sphinx'; // none, mysql, sphinx +$bb_cfg['sphinx_topic_titles_host'] = '127.0.0.1'; +$bb_cfg['sphinx_topic_titles_port'] = 3312; +$bb_cfg['disable_ft_search_in_posts'] = false; // disable searching in post bodies +$bb_cfg['disable_search_for_guest'] = true; +$bb_cfg['allow_search_in_bool_mode'] = true; +$bb_cfg['max_search_words_per_post'] = 200; +$bb_cfg['search_min_word_len'] = 3; +$bb_cfg['search_max_word_len'] = 35; +$bb_cfg['limit_max_search_results'] = false; +$bb_cfg['search_help_url'] = ''; +$bb_cfg['search_match_help_topic_id'] = 0; +$bb_cfg['tidy_cfg'] = array( +# 'hide-comments' => false, +# 'indent' => true, +# 'indent-spaces' => 1, +); +$bb_cfg['spam_filter_file_path'] = ''; //BB_PATH .'/misc/spam_filter_words.txt'; + +// Posting +$bb_cfg['show_virtual_keyboard'] = true; +$bb_cfg['prevent_multiposting'] = true; // replace "reply" with "edit last msg" if user (not admin or mod) is last topic poster +$bb_cfg['max_smilies'] = 10; // Максимальное число смайлов в посте (0 - без ограничения) + +// Actions log +$bb_cfg['log_days_keep'] = 90; + +// Users +$bb_cfg['user_not_activated_days_keep'] = 7; // "not activated" == "not finished registration" +$bb_cfg['user_not_active_days_keep'] = 180; // inactive users but only with no posts + +// GroupCP +$bb_cfg['groupcp_members_per_page'] = 300; + +// Ads +$bb_cfg['show_ads'] = false; +$bb_cfg['show_ads_users'] = array( +# user_id => 'name', + 2 => 'admin', +); + +// block_type => [block_id => block_desc] +$bb_cfg['ad_blocks'] = array( + 'trans' => array( + 100 => 'сквозная сверху', + ), + 'index' => array( + 200 => 'главная, под новостями', + ), +); + +// Misc +define('BOT_UID', -746); + +define('LOADAVG', function_exists('get_loadavg') ? get_loadavg() : 0); +define('MEM_USAGE', function_exists('memory_get_usage')); + +$bb_cfg['mem_on_start'] = (MEM_USAGE) ? memory_get_usage() : 0; + +$bb_cfg['translate_dates'] = true; // in displaying time +$bb_cfg['use_word_censor'] = true; + +$bb_cfg['last_visit_date_format'] = 'd-M H:i'; +$bb_cfg['last_post_date_format'] = 'd-M-y H:i'; + +$bb_cfg['allow_change'] = array( + 'language' => true, + 'dateformat' => true, +); + +define('GZIP_OUTPUT_ALLOWED', (extension_loaded('zlib') && !ini_get('zlib.output_compression'))); + +$banned_user_agents = array( +// Download Master +# 'download', +# 'master', +// Others +# 'wget', +); + +$bb_cfg['porno_forums'] = ''; // (string) 1,2,3.. +$bb_cfg['porno_forums_screenshots_topic_id'] = 52267; +$bb_cfg['trash_forum_id'] = 0; // (int) 27 + +$bb_cfg['first_logon_redirect_url'] = 'index.php'; +$bb_cfg['faq_url'] = 'faq.php'; +$bb_cfg['terms_and_conditions_url'] = 'index.php'; + +$bb_cfg['user_agreement_url'] = "misc.php?do=info&show=user_agreement"; +$bb_cfg['copyright_holders_url'] = "misc.php?do=info&show=copyright_holders"; +$bb_cfg['advert_url'] = "misc.php?do=info&show=advert"; + +$bb_cfg['html_path'] = BB_PATH .'/misc/html/'; # +$bb_cfg['user_agreement_html_path'] = $bb_cfg['html_path'] .'user_agreement.html'; # +$bb_cfg['copyright_holders_html_path'] = $bb_cfg['html_path'] .'copyright_holders.html'; # +$bb_cfg['advert_html_path'] = $bb_cfg['html_path'] .'advert.html'; # + + +// Captcha +$bb_cfg['captcha']['name'] = 'torrentpier.me'; +$bb_cfg['captcha']['disabled'] = false; +$bb_cfg['captcha']['secret_key'] = 'secret_key'; +$bb_cfg['captcha']['img_path'] = "./images/captcha/"; # without '/' diff --git a/upload/config/.htaccess b/upload/config/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/config/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/config/cron_cfg.php b/upload/config/cron_cfg.php new file mode 100644 index 000000000..582714f73 --- /dev/null +++ b/upload/config/cron_cfg.php @@ -0,0 +1,12 @@ +. | +// +------------------------------------------------------------------------+ +// | This source file is subject to the New BSD license, That is bundled | +// | with this package in the file LICENSE, and is available through | +// | the world-wide-web at | +// | http://www.opensource.org/licenses/bsd-license.php | +// | If you did not receive a copy of the new BSDlicense and are unable | +// | to obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: Timer.php,v 1.16 2006/03/01 13:41:39 matthias Exp $ +// + +/** + * Provides timing and profiling information. + * + * Example 1: Automatic profiling start, stop, and output. + * + * + * setMarker('Marker 1'); + * ?> + * + * + * Example 2: Manual profiling start, stop, and output. + * + * + * start(); + * $timer->setMarker('Marker 1'); + * $timer->stop(); + * + * $timer->display(); // to output html formated + * // AND/OR : + * $profiling = $timer->getProfiling(); // get the profiler info as an associative array + * ?> + * + * + * @author Sebastian Bergmann + * @author Ludovico Magnocavallo + * @copyright Copyright © 2002-2005 Sebastian Bergmann + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Benchmarking + * @package Benchmark + */ +class Benchmark_Timer { + /** + * Contains the markers. + * + * @var array + * @access private + */ + var $markers = array(); + var $memory = array(); + + var $name_counter = array(); + + /** + * Auto-start and stop timer. + * + * @var boolean + * @access private + */ + var $auto = FALSE; + + /** + * Max marker name length for non-html output. + * + * @var integer + * @access private + */ + var $maxStringLength = 0; + + var $startTime = 0; + + /** + * Constructor. + * + * @param boolean $auto + * @access public + */ + function Benchmark_Timer($auto = FALSE) { + $this->auto = $auto; + $this->startTime = $this->_getMicrotime(); + + if ($this->auto) { + $this->start(); + } + } + + /** + * Destructor. + * + * @access private + */ + function _Benchmark_Timer() { + if ($this->auto) { + $this->stop(); + $this->display(); + } + } + + /** + * Set "Start" marker. + * + * @see setMarker(), stop() + * @access public + */ + function start() { + $this->setMarker('Start'); + } + + /** + * Set "Stop" marker. + * + * @see setMarker(), start() + * @access public + */ + function stop() { + $this->setMarker('Stop'); + } + + /** + * Set marker. + * + * @param string $name Name of the marker to be set. + * @see start(), stop() + * @access public + */ + function setMarker($name = '') { + if (!$name) { + $trace = debug_backtrace(); + $name = $GLOBALS['timer_markers'] .': '. hide_bb_path($trace[0]['file']) .'('. $trace[0]['line'] .')'; + } + if ($name != 'Start' && $name != 'Stop') { + $GLOBALS['timer_markers']++; + } + if (isset($this->markers[$name])) { + $name .= ' ['. @++$this->name_counter[$name] .']'; + } + $this->markers[$name] = $this->_getMicrotime(); + $this->memory[$name] = sys('mem'); + } + + /** + * Returns the time elapsed betweens two markers. + * + * @param string $start start marker, defaults to "Start" + * @param string $end end marker, defaults to "Stop" + * @return double $time_elapsed time elapsed between $start and $end + * @access public + */ + function timeElapsed($start = 'Start', $end = 'Stop') { + if ($end == 'Stop' && !isset($this->markers['Stop'])) { + $this->markers['Stop'] = $this->_getMicrotime(); + } + + if (extension_loaded('bcmath')) { + return bcsub($this->markers[$end], $this->markers[$start], 6); + } else { + return $this->markers[$end] - $this->markers[$start]; + } + } + + /** + * Returns profiling information. + * + * $profiling[x]['name'] = name of marker x + * $profiling[x]['time'] = time index of marker x + * $profiling[x]['diff'] = execution time from marker x-1 to this marker x + * $profiling[x]['total'] = total execution time up to marker x + * + * @return array + * @access public + */ + function getProfiling() { + $i = $total = 0; + $result = array(); + $temp = reset($this->markers); + $mem_before = 0; + $this->maxStringLength = 0; + + foreach ($this->markers as $marker => $time) { + if (extension_loaded('bcmath')) { + $diff = bcsub($time, $temp, 6); + $total = bcadd($total, $diff, 6); + } else { + $diff = $time - $temp; + $total = $total + $diff; + } + + $result[$i]['name'] = $marker; + $result[$i]['time'] = $time; + $result[$i]['diff'] = $diff; + $result[$i]['total'] = $total; + $result[$i]['mem'] = $this->memory[$marker]; + $result[$i]['mem_diff'] = $this->memory[$marker] - $mem_before; + + $this->maxStringLength = (strlen($marker) > $this->maxStringLength ? strlen($marker) + 1 : $this->maxStringLength); + + $temp = $time; + $mem_before = $this->memory[$marker]; + $i++; + } + + $result[0]['diff'] = '-'; + $result[0]['total'] = '-'; + $this->maxStringLength = (strlen('total') > $this->maxStringLength ? strlen('total') : $this->maxStringLength); + $this->maxStringLength += 2; + + return $result; + } + + /** + * Return formatted profiling information. + * + * @param boolean $showTotal Optionnaly includes total in output, default no + * @param string $format output format (auto, plain or html), default auto + * @return string + * @see getProfiling() + * @access public + */ + function getOutput($showTotal = FALSE, $format = 'auto') { + if ($format == 'auto') { + $format = isset($_SERVER['SERVER_PROTOCOL']) ? 'html' : 'plain'; + } + + $total = $this->TimeElapsed(); + $result = $this->getProfiling(); + $dashes = ''; + + if ($format == 'html') { + $out = ' +

+ + + '."\n"; + $out .= ' + + + + + + + + '. ($showTotal ? ' + + + ' : '') + ."\n"; + } else { + $dashes = $out = str_pad("\n", + $this->maxStringLength + ($showTotal ? 70 : 45), '-', STR_PAD_LEFT); + $out .= str_pad('marker', $this->maxStringLength) . + str_pad("time index", 22) . + str_pad("ex time", 16) . + str_pad("perct ", 8) . + ($showTotal ? ' '.str_pad("elapsed", 16)."perct" : '')."\n" . + $dashes; + } + + foreach ($result as $k => $v) { + $perc = (($v['diff'] * 100) / $total); + $tperc = (($v['total'] * 100) / $total); + + if ($format == 'html') { + $out .= ' + + + + + + + + '. ($showTotal ? ' + + + ' : '') + ."\n"; + } else { + $out .= str_pad($v['name'], $this->maxStringLength, ' ') . + str_pad($v['time'], 22) . + str_pad($v['diff'], 14) . + str_pad(number_format($perc, 2, '.', '')."%",8, ' ', STR_PAD_LEFT) . + ($showTotal ? ' '. + str_pad($v['total'], 14) . + str_pad(number_format($tperc, 2, '.', '')."%", + 8, ' ', STR_PAD_LEFT) : ''). + "\n"; + } + + $out .= $dashes; + } + + if ($format == 'html') { + $out .= " + + + + + + + + ". ($showTotal ? " + + + " : '') + ." + \n"; + $out .= "
 time idxex time%memmem +-elapsed%
'. $v['name'] .''. number_format($v['time'] - $this->startTime, 6) .''. number_format($v['diff'], 6) .''. number_format($perc, 2) .'%'. humn_size($v['mem'], 2, '', ' ') .''. (($v['mem_diff'] > 0) ? '+' : '-') . humn_size(abs($v['mem_diff']), 2, '', ' ') .''. number_format($v['total'], 6) .''. number_format($tperc, 2, '.', '') .'%
total-". number_format($total, 6) ."100.00%". humn_size(sys('mem_peak'), 2, '', ' ') ."---


\n"; + } else { + $out .= str_pad('total', $this->maxStringLength); + $out .= str_pad('-', 22); + $out .= str_pad($total, 15); + $out .= "100.00%\n"; + $out .= $dashes; + } + + return $out; + } + + /** + * Prints the information returned by getOutput(). + * + * @param boolean $showTotal Optionnaly includes total in output, default no + * @param string $format output format (auto, plain or html), default auto + * @see getOutput() + * @access public + */ + function display($showTotal = FALSE, $format = 'html') { + print $this->getOutput($showTotal, $format); + } + + /** + * Wrapper for microtime(). + * + * @return float + * @access private + * @since 1.3.0 + */ + function _getMicrotime() { + $microtime = explode(' ', microtime()); + return $microtime[1] . substr($microtime[0], 1); + } +} diff --git a/upload/develop/dbg_config.php b/upload/develop/dbg_config.php new file mode 100644 index 000000000..ef3be8899 --- /dev/null +++ b/upload/develop/dbg_config.php @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/upload/develop/error_handler.php b/upload/develop/error_handler.php new file mode 100644 index 000000000..e25fd5033 --- /dev/null +++ b/upload/develop/error_handler.php @@ -0,0 +1,107 @@ + 'Notice', + E_RECOVERABLE_ERROR => 'Recoverable Error', + E_STRICT => 'Strict', + E_USER_ERROR => 'Error', + E_USER_NOTICE => 'Notice', + E_USER_WARNING => 'Warning', + E_WARNING => 'Warning', + ); + + var $err_Stack = array(); + var $err_HtmlOut = ''; + + function bb_error_handler ($errNo = null, $errMsg = null, $file = null, $line = null, $context = null) + { + if (!($errNo & error_reporting())) return; + + $critical_error = ($errNo & E_USER_ERROR); +# $critical_error = true; + + if ($critical_error) + { + $info = array(); + if (is_array($arr = @unserialize($errMsg))) + { + foreach ($arr as $k => $v) + { + $info[$k] = $v; + } + } + $trace = $full_trace = debug_backtrace(); + array_shift($trace); + + if (isset($trace[1]['function']) && $trace[1]['function'] === 'sql_trigger_error') + { + array_shift($trace); + array_shift($trace); + } + $file = $trace[0]['file']; + $line = $trace[0]['line']; + } + + $id = md5($file . $errNo . $errMsg); + if (!isset($this->errStack[$id])) + { + $this->errStack[$id] = array( + 'file' => $file, + 'line' => $line, + 'errNo' => $errNo, + 'errMsg' => $errMsg, + ); + if (preg_match('#(.*)\((\d+)\).*eval.*#', $file, $m)) + { + $src_file = $m[1]; + $src_line = $m[2]; + } + else + { + $src_file = $file; + $src_line = $line; + } + $this->err_HtmlOut .= '' + ."\n" + .'' + . $this->errType[$errNo] .':' + ."\n" + .'' + . htmlCHR($errMsg) + . (($critical_error) ? "
\n\n" : "
\n") + . str_replace(BB_PATH . DIRECTORY_SEPARATOR, '', $file) ."($line)" + ."\n" + ."\n"; + } + + if ($critical_error) + { + require(DEV_DIR .'error_report.php'); + exit; + } + } + + function get_errors () + { + if ($this->err_HtmlOut) + { + return "\n". $this->err_HtmlOut ."
doubleClick the filename to open in Editor
\n"; + } + return ''; + } + + function get_clean_errors () + { + $ret = $this->get_errors(); + $this->err_HtmlOut = ''; + return $ret; + } +} + +$errHandler = new bb_error_handler; +set_error_handler(array(&$errHandler, 'bb_error_handler')); + diff --git a/upload/develop/error_report.php b/upload/develop/error_report.php new file mode 100644 index 000000000..c4a329a63 --- /dev/null +++ b/upload/develop/error_report.php @@ -0,0 +1,234 @@ +get_clean_errors(); + +$showSourceUri = BB_ROOT .'develop/show_source.php'; +$showSourcePrev = 15; +$showSourceNext = 15; +?> + + + +
+
+ +errType[$errNo]; ?>: '; + } + function fontEnd() + { + return ''; + } + + if (count($info)) + { + foreach ($info as $k => $v) + { + echo "$k: $v
\n"; + } + } + else + { + echo "$errMsg
\n"; + } + echo "
\n"; + + if (count($trace)) + { + echo 'Trace: ' . count($trace) . " "; + echo '[show details] '; + echo '[hide details]'; + + echo "
\n"; + echo "
\n"; + + echo '
    '; + $currentParam = -1; + + foreach ($trace as $k => $v) + { + $currentParam++; + + echo '
  • '; + + if (isset($v['class'])) + { + echo ''; + echo $v['class']; + echo "."; + } + else + { + echo ''; + } + + echo $v['function']; + echo ''; + echo " ("; + + $sep = ''; + $v['args'] = (array) @$v['args']; + foreach ($v['args'] as $arg) { + + $currentParam++; + + echo $sep; + $sep = ', '; + $color = '#404040'; + + switch (true) { + + case is_bool($arg): + $param = 'TRUE'; + $string = $param; + break; + + case is_int($arg): + case is_float($arg): + $param = $arg; + $string = $arg; + $color = $c['number']; + break; + + case is_null($arg): + $param = 'NULL'; + $string = $param; + break; + + case is_string($arg): + $param = $arg; + $string = 'string[' . strlen($arg) . ']'; + break; + + case is_array($arg): + ob_start(); + print_r($arg); + $param = ob_get_contents(); + ob_end_clean(); + $string = 'array[' . count($arg) . ']'; + break; + + case is_object($arg): + ob_start(); + print_r($arg); + $param = ob_get_contents(); + ob_end_clean(); + $string = 'object: ' . get_class($arg); + break; + + case is_resource($arg): + $param = 'resource: ' . get_resource_type($arg); + $string = 'resource'; + break; + + default: + $param = 'unknown'; + $string = $param; + break; + } + + echo ''; + echo $string; + echo ''; + echo ''; + } + + echo ")"; + echo "
    \n"; + + if (!isset($v['file'])) { + $v['file'] = 'unknown'; + } + if (!isset($v['line'])) { + $v['line'] = 'unknown'; + } + + $v['line'] = @$v['line']; + echo ''; + + echo '
  • '; + } + + echo '
'; + + } else { + echo 'File: '; + echo basename($file); + echo ' (' . $line . ') '; + echo dirname($file); + } + +?> + +[hide param]'; ?> +
+ +Trick: click on a function's argument to see it fully
+Trick: click on a function to see the file & line
+Trick: click on the file name to see the source code
+ +
\ No newline at end of file diff --git a/upload/develop/functions_debug.php b/upload/develop/functions_debug.php new file mode 100644 index 000000000..69422fe36 --- /dev/null +++ b/upload/develop/functions_debug.php @@ -0,0 +1,102 @@ +', $data); + $count = count($data); + + //count which lines to display + $start = $line - $prev; + if ($start < 1) + { + $start = 0; + } + $end = $line + $next; + if ($end > $count) + { + $end = $count + 1; + } + + //color for numbering lines + $highlight_default = ini_get('highlight.default'); + + echo '
'; + echo ''; + echo '
'; + + for ($x = $start+1; $x <= $end+1; $x++) + { + $class = ($line == $x) ? 'lineNum lineErr' : 'lineNum'; + echo "
 "; + echo ''; + echo ($x); + echo ' '; + echo "
\n"; + } + echo '
'; + + while ($start <= $end) + { + if ($line == $start+1) + { + echo '
 '; + } + else + { + echo '
 '; + } + echo @$data[$start]; + echo "
\n"; + $start++; + } + echo '
'; + + if ($add_view_full_link && ($prev != 10000 || $next != 10000)) + { + echo '
'; + echo 'View Full Source'; + } + return ob_get_clean(); +} diff --git a/upload/develop/init_debug.php b/upload/develop/init_debug.php new file mode 100644 index 000000000..56c55c9d9 --- /dev/null +++ b/upload/develop/init_debug.php @@ -0,0 +1,41 @@ +start(); +# $GLOBALS['timer']->setMarker(); // empty setMarker() will point to "source(line)" +# $GLOBALS['timer']->setMarker('Marker 1'); +# $GLOBALS['timer']->setMarker('Marker 1 End'); +# $GLOBALS['timer']->stop(); +# $GLOBALS['timer']->display(); die; + +// +// Error handler +// +require(DEV_DIR .'error_handler.php'); + +// +// OB conveyer +// +function prepend_debug_info ($contents) +{ + global $errHandler; + + if ($errors = $errHandler->get_clean_errors()) + { + $contents = file_get_contents(DEV_DIR .'dbg_header.php') . $errors . $contents; + } + + return $contents; +} + +ob_start('prepend_debug_info'); diff --git a/upload/develop/memcached_stub.php b/upload/develop/memcached_stub.php new file mode 100644 index 000000000..1909dfc70 --- /dev/null +++ b/upload/develop/memcached_stub.php @@ -0,0 +1,154 @@ +
'. basename(__FILE__)); + +require('./dbg_config.php'); + +$interpreter = $bb_cfg['dbg']['interpreter']; +$prog_path = $_GET['prog']; +$prog_args = $_GET['args']; + +$command = "$interpreter $prog_path $prog_args"; +exec($command); +echo ''; +exit; + diff --git a/upload/develop/profiler/example.txt b/upload/develop/profiler/example.txt new file mode 100644 index 000000000..9ffbcaf07 --- /dev/null +++ b/upload/develop/profiler/example.txt @@ -0,0 +1,9 @@ +print_profile_data($min_time); +?> + +$min_time - ("0.01" - , "0.01%" - ) + diff --git a/upload/develop/profiler/profiler.css b/upload/develop/profiler/profiler.css new file mode 100644 index 000000000..cb690d1a4 --- /dev/null +++ b/upload/develop/profiler/profiler.css @@ -0,0 +1,119 @@ +#profContainer { + background-color: #F5F5F5; +} +.profTable { + background: #D3D3D3; + width: 100%; + margin-bottom: 6px; +} +.profHead { + color: #000000; + background: #F5F5F5; + font-size: 11px; + text-align: center; +} +.profFile { + color: #F5F5F5; + background: #71869F; + font-size: 13px; + text-align: left; + letter-spacing: 1px; + padding: 3px 4px 4px 12px; +} +.profFunc { + color: #2C2C2C; + font-size: 13px; + background: #ECECEA; + padding: 1px 4px 1px 3px; + white-space: nowrap; + font-family: "Courier New", Courier, monospace; +} +.funcTime { + padding: 1px 3px 1px 3px; + text-align: center; +} +.funcName { + padding: 1px 4px 1px 6px; + font-size: 14px; + font-weight: bold; +} +.profFoot { + color: #000000; + background: #D1D7DC; + font-size: 11px; + text-align: left; +} +.profTD { + font-size: 11px; +} +.profRow1 { + background: #F4F4F4; +} +.profRow2 { + background: #F4F4F4; +} +.perc { + padding: 2px 4px 2px 6px; + text-align: right; + color: #000000; +} +.high1 { + color: #BB0000; +} +.high3 { + font-size: 11px; + color: #EA0000; + font-weight: bold; +} +.high5 { + font-size: 11px; + color: #FF0000; + font-weight: bold; +} +.time { + padding: 2px 4px 2px 4px; + text-align: center; + color: #285C30; + font-weight: bold; +} +.avg { + padding: 2px 2px 2px 4px; + font-size: 10px; + font-style: normal; + text-align: center; + letter-spacing: -1px; + color: #336633; +} +.hits { + font-size: 10px; + padding: 2px 4px 2px 4px; + text-align: center; + font-style: normal; +} +.line { + font-size: 10px; + padding: 2px 4px 2px 6px; + text-align: right; +} +.scr { + padding: 2px 4px 2px 4px; + font-size: 11px; + text-align: left; + width: 100%; +} +.srcOpen .srcOpen:link, .srcOpen:visited { + color: #000099; +} +font { + font-size: 11px; +} +.warningBox1 { + color: darkred; + border: 1px solid #B22222; + padding: 12px; +} +.files { + font-size: 12px; + background: #FBFBFB; + font-family: Courier, monospace; +} diff --git a/upload/develop/profiler/profiler.php b/upload/develop/profiler/profiler.php new file mode 100644 index 000000000..a594399c1 --- /dev/null +++ b/upload/develop/profiler/profiler.php @@ -0,0 +1,35 @@ + + '. file_get_contents(dirname(__FILE__) .'/profiler.css') .' + + '."\n"; + + if (!extension_loaded($extension_name)) + { + echo ' +
+ Cannot load '. $extension_name .' extension. Please check your PHP configuration. +
+ '; + } + + $profiler_module_name = dirname(__FILE__) .'/profiler_'. basename($extension_name) .'.php'; + + if (include($profiler_module_name)) + { + $profiler_class_name = "profiler_{$extension_name}"; + $profiler_obj = new $profiler_class_name(); + return $profiler_obj; + } + else + { + trigger_error("Unsupported profiler extension: $extension_name", E_USER_ERROR); + } + } +} diff --git a/upload/develop/profiler/profiler_dbg.php b/upload/develop/profiler/profiler_dbg.php new file mode 100644 index 000000000..898051eb0 --- /dev/null +++ b/upload/develop/profiler/profiler_dbg.php @@ -0,0 +1,377 @@ + array(), + 'line_no' => array(), + 'hit_count' => array(), + 'tm_max' => array(), + 'tm_min' => array(), + 'tm_sum' => array(), + ); + + + --------------------------------------------------- + get all modules name + --------------------------------------------------- + int dbg_get_all_module_names(array &$results); + + return int: count of $results + + $results = array( + 'mod_no' => array(), + 'mod_name' => array(), + ); + + + --------------------------------------------------- + get module name + --------------------------------------------------- + int dbg_get_module_name(int $mod_no, string &$results); + + return int: 0 - error + 1 - success + + $results = module name + + + --------------------------------------------------- + get all context (function name) for given module + --------------------------------------------------- + int dbg_get_all_contexts(int $mod_no, array &$results); + + if $mod_no = 0 it returns all contexts + + return int: count of $results + + $results = array( + 'ctx_no' => array(), + 'mod_no' => array(), + 'ctx_name' => array(), + ); + + + --------------------------------------------------- + get context name + --------------------------------------------------- + int dbg_get_context_name(int $ctx_no, string &$function_name); + + return int: 0 - error + 1 - success + + $function_name = function name + + + --------------------------------------------------- + get all source lines for given module + --------------------------------------------------- + int dbg_get_all_source_lines(int $mod_no, array &$results); + + if $mod_no = 0 it returns all source lines for all contexts + + return int: count of $results + + $results = array( + 'ctx_no' => array(), + 'mod_no' => array(), + 'line_no' => array(), + ); + + + --------------------------------------------------- + get context id for given module and line + --------------------------------------------------- + int dbg_get_source_context(int $mod_no, int $line_no, int &$ctx_no); + + return int: 0 - error + 1 - success + + $ctx_no = function name + +*/ + +############################################################################## + +class profiler_dbg extends profiler +{ + var $min_time = 0; + var $total_time = 0; + + // $min_time - ( %) + // + function print_profile_data ($min_time = 0) + { + // Get all profiling data + dbg_get_profiler_results (&$results); # prn($results); + dbg_get_all_module_names (&$modules); + dbg_get_all_contexts (0, &$context); + dbg_get_all_source_lines (0, &$lines); + + $this->total_time = array_sum($results['tm_sum']); + $this->min_time = strpos($min_time, '%') ? $this->total_time * floatval($min_time)/100 : floatval($min_time); + $percent = ($this->total_time) ? 100/$this->total_time : 0; + + $module_names = $context_names = $context_lines = $profile = array(); + + // Module names + foreach ($modules['mod_no'] as $id => $module_no) + { + $module_names[$module_no] = $modules['mod_name'][$id]; + + $profile[$module_no]['time'] = 0; + $profile[$module_no]['.'] = array(); + } + + // Context names + foreach ($context['mod_no'] as $id => $context_no) + { + $module_no = $context['ctx_no'][$id]; + $ctx_name = $context['ctx_name'][$id]; + + $context_names[$context_no] = ($ctx_name) ? "$ctx_name()" : 'GLOBAL'; + + $profile[$module_no]['.'][$context_no]['time'] = 0; + $profile[$module_no]['.'][$context_no]['.'] = array(); + } + + // Context lines + foreach ($lines['line_no'] as $id => $line_no) + { + $module_no = $lines['mod_no'][$id]; + + $context_lines[$module_no][$line_no] = $lines['ctx_no'][$id]; + } + + // Build profiling data + foreach ($results['line_no'] as $id => $line_no) + { + $module_no = $results['mod_no'][$id]; + $context_no = $context_lines[$module_no][$line_no]; + + $profile[$module_no]['time'] += $results['tm_sum'][$id]; + $profile[$module_no]['.'][$context_no]['time'] += $results['tm_sum'][$id]; + + if ($results['tm_sum'][$id] < $this->min_time) + { + continue; + } + + $profile[$module_no]['.'][$context_no]['.'][$line_no] = array( + 'time' => $results['tm_sum'][$id], + 'hits' => $results['hit_count'][$id], + ); + } + + // Sort profiling data: modules, contexts and lines + uasort($profile, array(__CLASS__, 'sort_by_time_desc')); + + foreach ($profile as $module_no => $context) + { + uasort($profile[$module_no]['.'], array(__CLASS__, 'sort_by_time_desc')); + + foreach ($context['.'] as $context_no => $lines) + { + uasort($profile[$module_no]['.'][$context_no]['.'], array(__CLASS__, 'sort_by_time_desc')); + } + } + + // Display profiling data + $colspan = 6; + $row_class = 'profRow1'; + + // Replacements for cleaning highlighted code + $highlight_replacements = array( + '' => '', + '' => '', + ' ' => ' ', + '><?php' => '>', + '?><' => '<', + '><?<' => '><', + '>php ' => '>', + ); + + echo ' +
+ + + '; + // Modules + foreach ($profile as $module_no => $context) + { + $module_path = $module_names[$module_no]; + $module_name = basename($module_path); + $module_src = is_file($module_path) ? file($module_path) : array(); + $module_time = sprintf('%.4f', $context['time']); + $module_perc = sprintf('%.1f', $context['time']*$percent); + + if ($module_time < $this->min_time) + { + continue; + } + + echo ' + +
+ + + + + + + + + + + + + + + + '."\n"; + + // Context + foreach ($context['.'] as $context_no => $lines) + { + $context_name = $context_names[$context_no]; + $context_time = $this->get_ms($lines['time']); + $context_perc = sprintf('%.2f', $lines['time']*$percent); + $row_class = ($row_class == 'profRow1') ? 'profRow2' : 'profRow1'; + + if ($lines['time'] < $this->min_time) + { + continue; + } + + echo ' + + + + + + '; + + // Lines + foreach ($lines['.'] as $line_no => $data) + { + $line_perc = $data['time']*$percent; + $line_perc = ($line_perc > 0.05) ? sprintf('%.1f', $line_perc) : ''; + $line_hits = ($data['hits'] != 1) ? $data['hits'] : ''; + $line_link = '". $line_no .''; + $line_time_sum = $this->get_ms($data['time']); + $line_time_avg = ($line_hits) ? $this->get_ms($data['time']/$line_hits, 3) : ''; + + $perc_class = 'perc'; + if ($line_perc > 5) $perc_class .= ' high5'; + else if ($line_perc > 3) $perc_class .= ' high3'; + else if ($line_perc > 1) $perc_class .= ' high1'; + + if ($line_src =& $module_src[$line_no-1]) + { + $line_src = preg_replace('#\s+#', ' ', trim($line_src)); + $line_src = highlight_string(" + + + + + + + + '."\n"; + } // Lines + } // Context + } // Modules + + echo ' +
' . "[ $module_perc%, $module_time sec. ] :: $module_name " . '
  %   time   avg   hits  line  source
'. "$context_perc%" .''. "$context_time ms" .''. $context_name .'
'. $line_perc .''. $line_time_sum .''. $line_time_avg .''. $line_hits .''. $line_link .''. $line_src .'
+ + + + +
+
[ '. count($modules['mod_name']) .' files, '. sprintf('%.3f', $this->total_time) .' sec. ]
+
'. join('
', $modules['mod_name']) .'
+
+
+
+ '; + } + + function get_ms ($time, $precision = 2) + { + return ($time < 0.001) ? round($time*1000, $precision) : round($time*1000, 0); + } + + static function sort_by_time_desc ($a, $b) + { + if ($a['time'] == $b['time']) return 0; + return ($a['time'] > $b['time']) ? -1 : 1; + } +} + + + + diff --git a/upload/develop/show_source.php b/upload/develop/show_source.php new file mode 100644 index 000000000..498bd4c9f --- /dev/null +++ b/upload/develop/show_source.php @@ -0,0 +1,19 @@ +
'. basename(__FILE__)); + +define('IN_PHPBB', true); +define('BB_ROOT', './../'); + +require('./dbg_config.php'); +require('./functions_debug.php'); + +$file = @$_GET['file']; +$line = @$_GET['line']; +$prev = @$_GET['prev'] ? $_GET['prev'] : 15; +$next = @$_GET['next'] ? $_GET['next'] : 15; + +require('./dbg_header.php'); +echo showSource($file, $line, $prev, $next); + diff --git a/upload/develop/source/Date_DeltaRussian.rar b/upload/develop/source/Date_DeltaRussian.rar new file mode 100644 index 000000000..8ebac0b3e Binary files /dev/null and b/upload/develop/source/Date_DeltaRussian.rar differ diff --git a/upload/develop/source/Globals.zip b/upload/develop/source/Globals.zip new file mode 100644 index 000000000..ff39836d4 Binary files /dev/null and b/upload/develop/source/Globals.zip differ diff --git a/upload/develop/source/benchmark.rar b/upload/develop/source/benchmark.rar new file mode 100644 index 000000000..b146ada7a Binary files /dev/null and b/upload/develop/source/benchmark.rar differ diff --git a/upload/develop/source/javascript_browser_detection_basic.rar b/upload/develop/source/javascript_browser_detection_basic.rar new file mode 100644 index 000000000..95e14d17b Binary files /dev/null and b/upload/develop/source/javascript_browser_detection_basic.rar differ diff --git a/upload/develop/source/js-sprintf.rar b/upload/develop/source/js-sprintf.rar new file mode 100644 index 000000000..f7f86f3ed Binary files /dev/null and b/upload/develop/source/js-sprintf.rar differ diff --git a/upload/develop/source/profiler.zip b/upload/develop/source/profiler.zip new file mode 100644 index 000000000..a18bdbf7b Binary files /dev/null and b/upload/develop/source/profiler.zip differ diff --git a/upload/dl_list.php b/upload/dl_list.php new file mode 100644 index 000000000..94df2bea4 --- /dev/null +++ b/upload/dl_list.php @@ -0,0 +1,210 @@ +session_start(); + +// Check if user logged in +if (!$userdata['session_logged_in']) +{ + redirect("login.php?redirect=$redirect_type&$redirect"); +} + +if ($bb_cfg['bt_min_ratio_dl_button'] && $btu = get_bt_userdata($user->id)) +{ + if (($user_ratio = get_bt_ratio($btu)) < $bb_cfg['bt_min_ratio_dl_button']) + { + bb_die($lang['BT_LOW_RATIO_FUNC']); + } +} + +// Check if user did not confirm +if (@$_POST['cancel']) +{ + redirect("$redirect_type?$redirect"); +} + +// +// Delete DL-list +// +if ($mode == 'dl_delete' && $topic_id) +{ + if (!IS_ADMIN) + { + $sql = "SELECT forum_id + FROM ". BB_TOPICS ." + WHERE topic_id = $topic_id + LIMIT 1"; + + if (!$row = DB()->sql_fetchrow(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not obtain forum_id for this topic', '', __LINE__, __FILE__, $sql); + } + + $is_auth = auth(AUTH_ALL, $row['forum_id'], $userdata); + + if (!$is_auth['auth_mod']) + { + message_die(GENERAL_MESSAGE, $lang['NOT_MODERATOR'], $lang['NOT_AUTHORISED']); + } + } + + if (!$confirmed) + { + $hidden_fields = array( + 't' => $topic_id, + 'mode' => 'dl_delete', + ); + + print_confirmation(array( + 'QUESTION' => $lang['DL_LIST_DEL_CONFIRM'], + 'FORM_ACTION' => "dl_list.php", + 'HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + )); + } + + clear_dl_list($topic_id); + redirect("$redirect_type?$redirect"); +} + +// +// Update DL status +// + +$req_topics_ary = $topics_ary = array(); + +// Get topics selected by user +if ($mode == 'set_topics_dl_status') +{ + if (!isset($_POST['dl_topics_id_list']) || !is_array($_POST['dl_topics_id_list'])) + { + message_die(GENERAL_MESSAGE, $lang['NONE_SELECTED']); + } + + foreach ($_POST['dl_topics_id_list'] as $topic_id) + { + $req_topics_ary[] = (int) $topic_id; + } +} +else if ($mode == 'set_dl_status') +{ + $req_topics_ary[] = (int) $topic_id; +} + +// Get existing topics +if ($req_topics_sql = join(',', $req_topics_ary)) +{ + $sql = "SELECT topic_id FROM ". BB_TOPICS ." WHERE topic_id IN($req_topics_sql)"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $topics_ary[] = $row['topic_id']; + } +} + +if ($topics_ary && ($mode == 'set_dl_status' || $mode == 'set_topics_dl_status')) +{ + $new_dlstatus_ary = array(); + + foreach ($topics_ary as $topic_id) + { + $new_dlstatus_ary[] = array( + 'user_id' => (int) $user->id, + 'topic_id' => (int) $topic_id, + 'user_status' => (int) $new_dl_status, + ); + } + $new_dlstatus_sql = DB()->build_array('MULTI_INSERT', $new_dlstatus_ary); + + if($bb_cfg['announce_type'] == 'xbt') + { + DB()->query("REPLACE INTO ". BB_BT_DLSTATUS_MAIN ." $new_dlstatus_sql"); + } + else + { + DB()->query("REPLACE INTO ". BB_BT_DLSTATUS_NEW ." $new_dlstatus_sql"); + } + + DB()->query(" + DELETE FROM ". BB_BT_DLSTATUS_MAIN ." + WHERE user_id = {$user->id} + AND topic_id IN(". join(',', $topics_ary) .") + "); + + redirect("$redirect_type?$redirect"); +} + +redirect("index.php"); \ No newline at end of file diff --git a/upload/download.php b/upload/download.php new file mode 100644 index 000000000..75a5079ad --- /dev/null +++ b/upload/download.php @@ -0,0 +1,377 @@ +enqueue(array( + 'attach_extensions', +)); + +$download_id = request_var('id', 0); +$thumbnail = request_var('thumb', 0); + +// Send file to browser +function send_file_to_browser($attachment, $upload_dir) +{ + global $lang, $attach_config; + + $filename = ($upload_dir == '') ? $attachment['physical_filename'] : $upload_dir . '/' . $attachment['physical_filename']; + + $gotit = false; + + if (!intval($attach_config['allow_ftp_upload'])) + { + if (@!file_exists(@amod_realpath($filename))) + { + message_die(GENERAL_ERROR, $lang['ERROR_NO_ATTACHMENT'] . "

404 File Not Found: The File " . $filename . " does not exist."); + } + else + { + $gotit = true; + } + } + + // + // Determine the Browser the User is using, because of some nasty incompatibilities. + // Most of the methods used in this function are from phpMyAdmin. :) + // + if (!empty($_SERVER['HTTP_USER_AGENT'])) + { + $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT']; + } + else if (!isset($HTTP_USER_AGENT)) + { + $HTTP_USER_AGENT = ''; + } + + if (preg_match('/Opera(\/| )([0-9].[0-9]{1,2})/', $HTTP_USER_AGENT, $log_version)) + { + $browser_version = $log_version[2]; + $browser_agent = 'opera'; + } + else if (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $HTTP_USER_AGENT, $log_version)) + { + $browser_version = $log_version[1]; + $browser_agent = 'ie'; + } + else if (preg_match('/OmniWeb\/([0-9].[0-9]{1,2})/', $HTTP_USER_AGENT, $log_version)) + { + $browser_version = $log_version[1]; + $browser_agent = 'omniweb'; + } + else if (preg_match('/Netscape([0-9]{1})/', $HTTP_USER_AGENT, $log_version)) + { + $browser_version = $log_version[1]; + $browser_agent = 'netscape'; + } + else if (preg_match('/Mozilla\/([0-9].[0-9]{1,2})/', $HTTP_USER_AGENT, $log_version)) + { + $browser_version = $log_version[1]; + $browser_agent = 'mozilla'; + } + else if (preg_match('/Konqueror\/([0-9].[0-9]{1,2})/', $HTTP_USER_AGENT, $log_version)) + { + $browser_version = $log_version[1]; + $browser_agent = 'konqueror'; + } + else + { + $browser_version = 0; + $browser_agent = 'other'; + } + + // Correct the mime type - we force application/octetstream for all files, except images + // Please do not change this, it is a security precaution + if (!strstr($attachment['mimetype'], 'image')) + { + $attachment['mimetype'] = ($browser_agent == 'ie' || $browser_agent == 'opera') ? 'application/octetstream' : 'application/octet-stream'; + } + + //bt + global $userdata; + + if (!(isset($_GET['original']) && !IS_USER)) + { + include(INC_DIR .'functions_torrent.php'); + send_torrent_with_passkey($filename); + } + //bt end + + // Now the tricky part... let's dance +// @ob_end_clean(); +// @ini_set('zlib.output_compression', 'Off'); + header('Pragma: public'); +// header('Content-Transfer-Encoding: none'); + +//$real_filename = html_entity_decode(basename($attachment['real_filename'])); + $real_filename = clean_filename(basename($attachment['real_filename'])); + $mimetype = "{$attachment['mimetype']};"; + $charset = (@$lang['CONTENT_ENCODING']) ? "charset={$lang['CONTENT_ENCODING']};" : ''; + + // Send out the Headers + header("Content-Type: $mimetype $charset name=\"$real_filename\""); + header("Content-Disposition: inline; filename=\"$real_filename\""); + + unset($real_filename); + // + // Now send the File Contents to the Browser + // + if ($gotit) + { + $size = @filesize($filename); + if ($size) + { + header("Content-length: $size"); + } + readfile($filename); + } + else if (!$gotit && intval($attach_config['allow_ftp_upload'])) + { + $conn_id = attach_init_ftp(); + + $ini_val = ( @phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var'; + + $tmp_path = ( !@$ini_val('safe_mode') ) ? '/tmp' : $upload_dir; + $tmp_filename = @tempnam($tmp_path, 't0000'); + + @unlink($tmp_filename); + + $mode = FTP_BINARY; + if ( (preg_match("/text/i", $attachment['mimetype'])) || (preg_match("/html/i", $attachment['mimetype'])) ) + { + $mode = FTP_ASCII; + } + + $result = @ftp_get($conn_id, $tmp_filename, $filename, $mode); + + if (!$result) + { + message_die(GENERAL_ERROR, $lang['ERROR_NO_ATTACHMENT'] . "

404 File Not Found: The File " . $filename . " does not exist."); + } + + @ftp_quit($conn_id); + + $size = @filesize($tmp_filename); + if ($size) + { + header("Content-length: $size"); + } + readfile($tmp_filename); + @unlink($tmp_filename); + } + else + { + message_die(GENERAL_ERROR, $lang['ERROR_NO_ATTACHMENT'] . "

404 File Not Found: The File " . $filename . " does not exist."); + } + + exit; +} +// +// End Functions +// + +// +// Start Session Management +// +$user->session_start(); + +if (!$download_id) +{ + message_die(GENERAL_ERROR, $lang['NO_ATTACHMENT_SELECTED']); +} + +if ($attach_config['disable_mod'] && !IS_ADMIN) +{ + message_die(GENERAL_MESSAGE, $lang['ATTACHMENT_FEATURE_DISABLED']); +} + +$sql = 'SELECT * + FROM ' . BB_ATTACHMENTS_DESC . ' + WHERE attach_id = ' . (int) $download_id; + +if (!($result = DB()->sql_query($sql))) +{ + message_die(GENERAL_ERROR, 'Could not query attachment informations', '', __LINE__, __FILE__, $sql); +} + +if (!($attachment = DB()->sql_fetchrow($result))) +{ + message_die(GENERAL_MESSAGE, $lang['ERROR_NO_ATTACHMENT']); +} + +$attachment['physical_filename'] = basename($attachment['physical_filename']); + +DB()->sql_freeresult($result); + +// get forum_id for attachment authorization or private message authorization +$authorised = false; + +$sql = 'SELECT * + FROM ' . BB_ATTACHMENTS . ' + WHERE attach_id = ' . (int) $attachment['attach_id']; + +if (!($result = DB()->sql_query($sql))) +{ + message_die(GENERAL_ERROR, 'Could not query attachment informations', '', __LINE__, __FILE__, $sql); +} + +$auth_pages = DB()->sql_fetchrowset($result); +$num_auth_pages = DB()->num_rows($result); + +for ($i = 0; $i < $num_auth_pages && $authorised == false; $i++) +{ + $auth_pages[$i]['post_id'] = intval($auth_pages[$i]['post_id']); + + if ($auth_pages[$i]['post_id'] != 0) + { + $sql = 'SELECT forum_id + FROM ' . BB_POSTS . ' + WHERE post_id = ' . (int) $auth_pages[$i]['post_id']; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query post information', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + + $forum_id = $row['forum_id']; + + $is_auth = array(); + $is_auth = auth(AUTH_ALL, $forum_id, $userdata); + + if ($is_auth['auth_download']) + { + $authorised = TRUE; + } + } +} + + +if (!$authorised) +{ + message_die(GENERAL_MESSAGE, $lang['SORRY_AUTH_VIEW_ATTACH']); +} + +$datastore->rm('cat_forums'); + +// +// Get Information on currently allowed Extensions +// +$rows = get_extension_informations(); +$num_rows = count($rows); + +for ($i = 0; $i < $num_rows; $i++) +{ + $extension = strtolower(trim($rows[$i]['extension'])); + $allowed_extensions[] = $extension; + $download_mode[$extension] = $rows[$i]['download_mode']; +} + +// disallowed ? +if (!in_array($attachment['extension'], $allowed_extensions) && !IS_ADMIN) +{ + message_die(GENERAL_MESSAGE, sprintf($lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension'])); +} + +$download_mode = intval($download_mode[$attachment['extension']]); + +if ($thumbnail) +{ + $attachment['physical_filename'] = THUMB_DIR . '/t_' . $attachment['physical_filename']; +} + +// Update download count +if (!$thumbnail) +{ + $sql = 'UPDATE ' . BB_ATTACHMENTS_DESC . ' + SET download_count = download_count + 1 + WHERE attach_id = ' . (int) $attachment['attach_id']; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Couldn\'t update attachment download count', '', __LINE__, __FILE__, $sql); + } +} + +// Determine the 'presenting'-method +if ($download_mode == PHYSICAL_LINK) +{ + $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; + $server_name = preg_replace('/^\/?(.*?)\/?$/', '\1', trim($bb_cfg['server_name'])); + $server_port = ($bb_cfg['server_port'] <> 80) ? ':' . trim($bb_cfg['server_port']) : ''; + $script_name = preg_replace('/^\/?(.*?)\/?$/', '/\1', trim($bb_cfg['script_path'])); + + if ($script_name[strlen($script_name)] != '/') + { + $script_name .= '/'; + } + + if (intval($attach_config['allow_ftp_upload'])) + { + if (trim($attach_config['download_path']) == '') + { + message_die(GENERAL_ERROR, 'Physical Download not possible with the current Attachment Setting'); + } + + $url = trim($attach_config['download_path']) . '/' . $attachment['physical_filename']; + $redirect_path = $url; + } + else + { + $url = $upload_dir . '/' . $attachment['physical_filename']; +// $url = preg_replace('/^\/?(.*?\/)?$/', '\1', trim($url)); + $redirect_path = $server_protocol . $server_name . $server_port . $script_name . $url; + } + + // Redirect via an HTML form for PITA webservers + if (@preg_match('/Microsoft|WebSTAR|Xitami/', getenv('SERVER_SOFTWARE'))) + { + header('Refresh: 0; URL=' . $redirect_path); + echo 'Redirect
If your browser does not support meta redirection please click HERE to be redirected
'; + exit; + } + + // Behave as per HTTP/1.1 spec for others + header('Location: ' . $redirect_path); + exit; +} +else +{ + if (intval($attach_config['allow_ftp_upload'])) + { + // We do not need a download path, we are not downloading physically + send_file_to_browser($attachment, ''); + exit; + } + else + { + send_file_to_browser($attachment, $upload_dir); + exit; + } +} \ No newline at end of file diff --git a/upload/faq.php b/upload/faq.php new file mode 100644 index 000000000..5f91d932e --- /dev/null +++ b/upload/faq.php @@ -0,0 +1,110 @@ +session_start(); + +// Set vars to prevent naughtiness +$faq = array(); +// +// Load the appropriate faq file +// +$mode = request_var('mode', ''); +if(!empty($mode)) +{ + switch($mode) + { + case 'bbcode': + $lang_file = 'lang_bbcode'; + $l_title = $lang['BBCODE_GUIDE']; + break; + default: + $lang_file = 'lang_faq'; + $l_title = $lang['FAQ']; + break; + } +} +else +{ + $lang_file = 'lang_faq'; + $l_title = $lang['FAQ']; +} +include(LANG_ROOT_DIR ."lang_{$bb_cfg['default_lang']}/$lang_file.php"); +include(LANG_ROOT_DIR ."lang_{$bb_cfg['default_lang']}/lang_faq_attach.php"); + +// +// Pull the array data from the lang pack +// +$j = 0; +$counter = 0; +$counter_2 = 0; +$faq_block = array(); +$faq_block_titles = array(); + +for($i = 0; $i < count($faq); $i++) +{ + if( $faq[$i][0] != '--' ) + { + $faq_block[$j][$counter]['id'] = $counter_2; + $faq_block[$j][$counter]['question'] = $faq[$i][0]; + $faq_block[$j][$counter]['answer'] = $faq[$i][1]; + + $counter++; + $counter_2++; + } + else + { + $j = ( $counter != 0 ) ? $j + 1 : 0; + + $faq_block_titles[$j] = $faq[$i][1]; + + $counter = 0; + } +} + +// +// Lets build a page ... +// +$template->assign_vars(array( + 'PAGE_TITLE' => $l_title, + 'L_FAQ_TITLE' => $l_title, +)); + +for($i = 0; $i < count($faq_block); $i++) +{ + if( count($faq_block[$i]) ) + { + $template->assign_block_vars('faq_block', array( + 'BLOCK_TITLE' => $faq_block_titles[$i]) + ); + $template->assign_block_vars('faq_block_link', array( + 'BLOCK_TITLE' => $faq_block_titles[$i]) + ); + + for($j = 0; $j < count($faq_block[$i]); $j++) + { + $row_class = !($j % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars('faq_block.faq_row', array( + 'ROW_CLASS' => $row_class, + 'FAQ_QUESTION' => $faq_block[$i][$j]['question'], + 'FAQ_ANSWER' => $faq_block[$i][$j]['answer'], + + 'U_FAQ_ID' => $faq_block[$i][$j]['id']) + ); + + $template->assign_block_vars('faq_block_link.faq_row_link', array( + 'ROW_CLASS' => $row_class, + 'FAQ_LINK' => $faq_block[$i][$j]['question'], + + 'U_FAQ_LINK' => '#' . $faq_block[$i][$j]['id']) + ); + } + } +} + +print_page('faq.tpl'); \ No newline at end of file diff --git a/upload/favicon.ico b/upload/favicon.ico new file mode 100644 index 000000000..73131f1b9 Binary files /dev/null and b/upload/favicon.ico differ diff --git a/upload/files/.htaccess b/upload/files/.htaccess new file mode 100644 index 000000000..34ed2a11e --- /dev/null +++ b/upload/files/.htaccess @@ -0,0 +1,3 @@ +php_flag engine off +RemoveHandler .php .php5 .php4 .php3 .phtml .pl .asp +AddType text/plain .php .php .htm .html .phtml .pl .asp \ No newline at end of file diff --git a/upload/files/thumbs/.htaccess b/upload/files/thumbs/.htaccess new file mode 100644 index 000000000..34ed2a11e --- /dev/null +++ b/upload/files/thumbs/.htaccess @@ -0,0 +1,3 @@ +php_flag engine off +RemoveHandler .php .php5 .php4 .php3 .phtml .pl .asp +AddType text/plain .php .php .htm .html .phtml .pl .asp \ No newline at end of file diff --git a/upload/gallery.php b/upload/gallery.php new file mode 100644 index 000000000..5a2dc415c --- /dev/null +++ b/upload/gallery.php @@ -0,0 +1,216 @@ +session_start(array('req_login' => true)); + +require(LANG_DIR ."lang_gallery.php"); + +$go = isset($_GET['go']) ? $_GET['go'] : ''; +$max_size = $bb_cfg['pic_max_size']; +$dir = $bb_cfg['pic_dir']; +$url = make_url('/'); + +$msg = ''; +$links_all = $thumbs_all = array(); + +// DON'T CHANGE THIS FILE TYPEs +$allowed_ext = array('jpeg', 'jpg', 'png', 'gif'); + +function create_thumb ($dir, $name, $att) +{ + $infile = $dir . $name . $att; + if ($att == ".jpg" || $att == ".jpeg") + $im = imagecreatefromjpeg($infile); + elseif ($att == ".png") + $im = imagecreatefrompng($infile); + elseif ($att == ".gif") + $im = imagecreatefromgif($infile); + + $oh = imagesy($im); + $ow = imagesx($im); + $r = $oh/$ow; + $newh = 200; + $neww = $newh/$r; + $outfile = $dir ."thumb_". $name . $att; + $im1 = imagecreatetruecolor($neww,$newh); + imagecopyresampled($im1, $im, 0, 0, 0, 0, $neww, $newh, imagesx($im), imagesy($im)); + imagejpeg($im1, $outfile, 75); + imagedestroy($im); + imagedestroy($im1); +} + +function paste_links($links, $thumbs = '') +{ + global $links_all, $thumbs_all, $lang; + + if (is_array($links)) + { + $link = implode(' ', $links); + $img = '[img]'. implode('[/img] [img]', $links) .'[/img]'; + + if ($thumbs) + { + $thumb = ''; + for ($i = 0; $i < count($links); $i++) + { + $thumb .= '[url='.$links[$i].'][img]'. $thumbs[$i] .'[/img][/url]'; + } + } + } + else + { + $link = trim($links); + $img = '[img]'. $links .'[/img]'; + + $thumb = '[url='.$link.'][img]'. $thumbs .'[/img][/url]'; + } + $spoiler = '[spoiler="'. $lang['GALLERY_SCREENSHOTS'] .'"]' . $img . '[/spoiler]'; + + $text = (!is_array($links)) ? '
'. $link .'
' : ''; + $text .= (!is_array($links)) ? '
'. $lang['GALLERY_YOUR_IMAGE'] .'' : ''; + $text .= '

'. $lang['GALLERY_LINK_URL'] .':

'; + $text .= '

'. $lang['GALLERY_TAG_SCREEN'] .':

'; + if ($thumbs) + { + $text .='

'. $lang['GALLERY_TAG_SCREEN_THUMB'] .':

'; + } + $text .= (!is_array($links)) ? '

'. $lang['GALLERY_TAG_POSTER_RIGHT'] .':

' : ''; + $text .= '

'. $lang['GALLERY_TAG_SPOILER'] .':

'; + + $links_all[] = $links; + $thumbs ? ($thumbs_all[] = $thumbs) : null; + + return $text; +} + +function upload_file ($files_ary, $idx) +{ + global $max_size, $allowed_ext, $create_thumb, $dir, $url, $lang; + + if (empty($files_ary)) + message_die(GENERAL_ERROR, "

". $lang['GALLERY_FILE_NOT_UPLOADED'] ."



". $lang['GALLERY_BACK'] ."


"); + if ($files_ary['size'][$idx] > $max_size) + message_die(GENERAL_ERROR, "

". $lang['GALLERY_IMAGE_OVERLOAD'] ."



". $lang['GALLERY_BACK'] ."


"); + + $name = strtolower($files_ary['name'][$idx]); + $ext = substr(strrchr($name, '.'), 1); + + $allow = in_array($ext, $allowed_ext); + $att = '.'. $ext; + + $thumb = false; + + if ($allow) + { + $name = md5_file($files_ary['tmp_name'][$idx]); + + if (file_exists($dir . $name . $att)) + { + if ($create_thumb && !file_exists($dir .'thumb_'. $name . $att)) + { + create_thumb($dir, $name, $att); + $thumb = $url . $dir ."thumb_". $name . $att; + } + $msg = '
'. $lang['GALLERY_FILE_EXIST'] . paste_links($url . $dir . $name . $att, $thumb) .''; + } + else + { + if (copy($files_ary['tmp_name'][$idx], $dir.$name.$att)) + { + if ($create_thumb) + { + create_thumb($dir, $name, $att); + $thumb = $url . $dir ."thumb_". $name . $att; + } + $msg = '
'. $lang['GALLERY_UPLOAD_SUCCESSFUL'] . paste_links($url . $dir . $name . $att, $thumb) .''; + } + else $msg = "
". $lang['GALLERY_UPLOAD_FAILED'] .""; + } + if (IS_ADMIN) + { + $msg .= "

"; + $msg .= "". $lang['GALLERY_DEL_LINK'] .":    "; + $msg .= "".$url."gallery.php?go=delete&fn=".$name.$att.""; + } + } + else $msg = "
". $lang['GALLERY_INVALID_TYPE'] .""; + + return $msg; +} + +if ($go == 'upload') +{ + @ini_set("memory_limit", "512M"); + + $create_thumb = (isset($_POST['create_thumb'])) ? true : false; + + for ($i = 0; $i < count($_FILES['imgfile']['name']); $i++) + { + $msg .= upload_file ($_FILES['imgfile'], $i); + } + + if (count($_FILES['imgfile']['name']) > 1) + { + $msg .= '
'. paste_links ($links_all, $thumbs_all); + } +} + +if ($go == 'delete' && IS_ADMIN && !empty($_GET['fn'])) +{ + global $lang; + + $fn = clean_filename($_GET['fn']); + + $pic = $dir . $fn; + $prev = $dir ."thumb_". $fn; + if (!is_file($pic)) message_die(GENERAL_ERROR, $lang['GALLERY_FILE_NOT_EXIST']); + + if (unlink($pic)) + { + @unlink($prev); + message_die(GENERAL_MESSAGE, "

". $lang['GALLERY_FILE_DELETE'] ."


". $lang['GALLERY_BACK'] ."
"); + } + else + message_die(GENERAL_ERROR, "

". $lang['GALLERY_FAILURE'] ."


". $lang['GALLERY_BACK'] ."
"); +} + +$template->assign_vars(array( + 'MSG' => $msg, + 'MAX_SIZE' => humn_size($max_size), + 'MAX_SIZE_HINT' => $lang['GALLERY_MAX_FILE_SIZE'], + 'CREATE_THUMB' => $lang['GALLERY_CREATE_THUMB'], + 'UPLOAD' => $lang['GALLERY_UPLOAD_IMAGE'], + 'MORE' => $lang['GALLERY_MORE_LINK'], +)); + +print_page('gallery.tpl'); \ No newline at end of file diff --git a/upload/groupcp.php b/upload/groupcp.php new file mode 100644 index 000000000..e7b5ed511 --- /dev/null +++ b/upload/groupcp.php @@ -0,0 +1,719 @@ +' : ''; + break; + case USER_AVATAR_REMOTE: + $poster_avatar = ( $bb_cfg['allow_avatar_remote'] ) ? '' : ''; + break; + case USER_AVATAR_GALLERY: + $poster_avatar = ( $bb_cfg['allow_avatar_local'] ) ? '' : ''; + break; + } + } + + if ( bf($row['user_opt'], 'user_opt', 'viewemail') || $group_mod ) + { + $email_uri = ( $bb_cfg['board_email_form'] ) ? "profile.php?mode=email&u={$row['user_id']}" : 'mailto:' . $row['user_email']; + + $email_img = '' . $lang['SEND_EMAIL'] . ''; + $email = '' . $lang['SEND_EMAIL'] . ''; + } + else + { + $email_img = ' '; + $email = ' '; + } + + $temp_url = "profile.php?mode=viewprofile&" . POST_USERS_URL . "=" . $row['user_id']; + $profile_img = '' . $lang['READ_PROFILE'] . ''; + $profile = '' . $lang['READ_PROFILE'] . ''; + + $temp_url = "privmsg.php?mode=post&" . POST_USERS_URL . "=" . $row['user_id']; + $pm_img = '' . $lang['SEND_PRIVATE_MESSAGE'] . ''; + $pm = '' . $lang['SEND_PRIVATE_MESSAGE'] . ''; + + $www_img = ( $row['user_website'] ) ? '' . $lang['VISIT_WEBSITE'] . '' : ''; + $www = ( $row['user_website'] ) ? '' . $lang['VISIT_WEBSITE'] . '' : ''; + + if ( !empty($row['user_icq']) ) + { + $icq_status_img = ''; + $icq_img = '' . $lang['ICQ'] . ''; + $icq = '' . $lang['ICQ'] . ''; + } + else + { + $icq_status_img = ''; + $icq_img = ''; + $icq = ''; + } + + $temp_url = "search.php?search_author=1&uid={$row['user_id']}"; + $search_img = '' . sprintf($lang['SEARCH_USER_POSTS'], $row['username']) . ''; + $search = '' . sprintf($lang['SEARCH_USER_POSTS'], $row['username']) . ''; + + return; +} +// +// -------------------------- + +$user->session_start(array('req_login' => true)); + +$group_id = isset($_REQUEST[POST_GROUPS_URL]) ? intval($_REQUEST[POST_GROUPS_URL]) : null; +$start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; +$per_page = $bb_cfg['groupcp_members_per_page']; + +$group_info = array(); +$is_moderator = false; + +if ($group_id) +{ + if (!$group_info = get_group_data($group_id)) + { + bb_die($lang['GROUP_NOT_EXIST']); + } + if (!$group_info['group_id'] || !$group_info['group_moderator'] || !$group_info['moderator_name']) + { + bb_die("Invalid group data [group_id: $group_id]"); + } + $is_moderator = ($userdata['user_id'] == $group_info['group_moderator'] || IS_ADMIN); +} + +if (!$group_id) +{ + // Show the main screen where the user can select a group. + $groups = array(); + $pending = 10; + $member = 20; + + $sql = " + SELECT + g.group_name, g.group_description, g.group_id, g.group_type, + IF(ug.user_id IS NOT NULL, IF(ug.user_pending = 1, $pending, $member), 0) AS membership, + g.group_moderator, u.username AS moderator_name, + IF(g.group_moderator = ug.user_id, 1, 0) AS is_group_mod + FROM + ". BB_GROUPS ." g + LEFT JOIN + ". BB_USER_GROUP ." ug ON + ug.group_id = g.group_id + AND ug.user_id = ". $userdata['user_id'] ." + LEFT JOIN + ". BB_USERS ." u ON g.group_moderator = u.user_id + WHERE + g.group_single_user = 0 + ORDER BY + is_group_mod DESC, + membership DESC, + g.group_type ASC, + g.group_name ASC + "; + + foreach (DB()->fetch_rowset($sql) as $row) + { + if ($row['is_group_mod']) + { + $type = 'mod'; + } + else if ($row['membership'] == $member) + { + $type = 'member'; + } + else if ($row['membership'] == $pending) + { + $type = 'pending'; + } + else if ($row['group_type'] == GROUP_OPEN) + { + $type = 'open'; + } + else if ($row['group_type'] == GROUP_CLOSED) + { + $type = 'closed'; + } + else if ($row['group_type'] == GROUP_HIDDEN && IS_ADMIN) + { + $type = 'hidden'; + } + else + { + continue; + } + $groups[$type][$row['group_name']] = $row['group_id']; + } + + if ($groups) + { + $s_hidden_fields = ''; + + foreach ($groups as $type => $grp) + { + $template->assign_block_vars('groups', array( + 'MEMBERSHIP' => $lang['GROUP_MEMBER_' . strtoupper($type)], + 'GROUP_SELECT' => build_select(POST_GROUPS_URL, $grp), + )); + } + + $template->assign_vars(array( + 'SELECT_GROUP' => true, + 'PAGE_TITLE' => $lang['GROUP_CONTROL_PANEL'], + 'S_USERGROUP_ACTION' => "groupcp.php", + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); + } + else + { + bb_die($lang['NO_GROUPS_EXIST']); + } +} +else if (!empty($_POST['groupstatus'])) +{ + if (!$is_moderator) + { + bb_die($lang['NOT_GROUP_MODERATOR']); + } + + $new_group_type = (int) $_POST['group_type']; + + if (!in_array($new_group_type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN), true)) + { + bb_die("Invalid group type: $new_group_type"); + } + + DB()->query(" + UPDATE ". BB_GROUPS ." SET + group_type = $new_group_type + WHERE group_id = $group_id + AND group_single_user = 0 + LIMIT 1 + "); + + $message = $lang['GROUP_TYPE_UPDATED'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_GROUP'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + + bb_die($message); +} +else if (@$_POST['joingroup']) +{ + if ($group_info['group_type'] != GROUP_OPEN) + { + bb_die($lang['THIS_CLOSED_GROUP']); + } + + $sql = "SELECT g.group_id, g.group_name, ug.user_id, u.user_email, u.username, u.user_lang + FROM ". BB_GROUPS ." g + LEFT JOIN ". BB_USERS ." u ON(u.user_id = g.group_moderator) + LEFT JOIN ". BB_USER_GROUP ." ug ON(ug.group_id = g.group_id AND ug.user_id = {$userdata['user_id']}) + WHERE g.group_id = $group_id + AND group_single_user = 0 + AND g.group_type = ". GROUP_OPEN ." + LIMIT 1"; + + $row = $moderator = DB()->fetch_row($sql); + + if (!$row['group_id']) + { + bb_die($lang['NO_GROUPS_EXIST']); + } + if ($row['user_id']) + { + bb_die($lang['ALREADY_MEMBER_GROUP']); + } + + add_user_into_group($group_id, $userdata['user_id'], 1); + + if ($bb_cfg['groupcp_send_email']) + { + include(BB_ROOT .'includes/emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('group_request', $moderator['user_lang']); + $emailer->email_address($moderator['user_email']); + $emailer->set_subject($lang['GROUP_REQUEST']); + + $emailer->assign_vars(array( + 'USER' => $userdata['username'], + 'SITENAME' => $bb_cfg['sitename'], + 'GROUP_MODERATOR' => $moderator['username'], + 'EMAIL_SIG' => ($bb_cfg['board_email_sig']) ? str_replace('
', "\n", "-- \n" . $bb_cfg['board_email_sig']) : '', + 'U_GROUPCP' => make_url(GROUP_URL . $group_id), + )); + $emailer->send(); + $emailer->reset(); + } + + $message = $lang['GROUP_JOINED'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_GROUP'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + + bb_die($message); +} +else if (!empty($_POST['unsub']) || !empty($_POST['unsubpending'])) +{ + delete_user_group($group_id, $userdata['user_id']); + + $message = $lang['UNSUB_SUCCESS'] .'

'; + $message .= sprintf($lang['CLICK_RETURN_GROUP'], '', '') .'

'; + $message .= sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + + bb_die($message); +} +else +{ + // Handle Additions, removals, approvals and denials + $group_moderator = $group_info['group_moderator']; + + if (!empty($_POST['add']) || !empty($_POST['remove']) || !empty($_POST['approve']) || !empty($_POST['deny'])) + { + if (!$is_moderator) + { + bb_die($lang['NOT_GROUP_MODERATOR']); + } + + if (!empty($_POST['add'])) + { + if (!$row = get_userdata(@$_POST['username'], true)) + { + bb_die($lang['COULD_NOT_ADD_USER']); + } + + add_user_into_group($group_id, $row['user_id']); + + if ($bb_cfg['groupcp_send_email']) + { + require(BB_ROOT .'includes/emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('group_added', $row['user_lang']); + $emailer->email_address($row['user_email']); + $emailer->set_subject($lang['GROUP_ADDED']); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'GROUP_NAME' => $group_info['group_name'], + 'EMAIL_SIG' => ($bb_cfg['board_email_sig']) ? str_replace('
', "\n", "-- \n". $bb_cfg['board_email_sig']) : '', + 'U_GROUPCP' => make_url(GROUP_URL . $group_id), + )); + $emailer->send(); + $emailer->reset(); + } + } + else + { + if (((!empty($_POST['approve']) || !empty($_POST['deny'])) && !empty($_POST['pending_members'])) || (!empty($_POST['remove']) && !empty($_POST['members']))) + { + $members = (!empty($_POST['approve']) || !empty($_POST['deny'])) ? $_POST['pending_members'] : $_POST['members']; + + $sql_in = array(); + foreach ($members as $members_id) + { + $sql_in[] = (int) $members_id; + } + if (!$sql_in = join(',', $sql_in)) + { + bb_die($lang['NONE_SELECTED']); + } + + if (!empty($_POST['approve'])) + { + DB()->query(" + UPDATE ". BB_USER_GROUP ." SET + user_pending = 0 + WHERE user_id IN($sql_in) + AND group_id = $group_id + "); + + update_user_level($sql_in); + } + else if (!empty($_POST['deny']) || !empty($_POST['remove'])) + { + DB()->query(" + DELETE FROM ". BB_USER_GROUP ." + WHERE user_id IN($sql_in) + AND group_id = $group_id + "); + + if (!empty($_POST['remove'])) + { + update_user_level($sql_in); + } + } + // Email users when they are approved + if (!empty($_POST['approve']) && $bb_cfg['groupcp_send_email']) + { + $sql_select = "SELECT user_email + FROM ". BB_USERS ." + WHERE user_id IN($sql_in)"; + + if (!$result = DB()->sql_query($sql_select)) + { + message_die(GENERAL_ERROR, 'Could not get user email information', '', __LINE__, __FILE__, $sql); + } + + $bcc_list = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $bcc_list[] = $row['user_email']; + } + + $group_name = $group_info['group_name']; + + require(INC_DIR .'emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + for ($i=0, $cnt=count($bcc_list); $i < $cnt; $i++) + { + $emailer->bcc($bcc_list[$i]); + } + + $emailer->use_template('group_approved'); + $emailer->set_subject($lang['GROUP_APPROVED']); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'GROUP_NAME' => $group_name, + 'EMAIL_SIG' => ($bb_cfg['board_email_sig']) ? str_replace('
', "\n", "-- \n". $bb_cfg['board_email_sig']) : '', + 'U_GROUPCP' => make_url(GROUP_URL . $group_id), + )); + $emailer->send(); + $emailer->reset(); + } + } + } + } + // END approve or deny + + // Get moderator details for this group + $group_moderator = DB()->fetch_row(" + SELECT * + FROM ". BB_USERS ." + WHERE user_id = ". $group_info['group_moderator'] ." + "); + + // Get user information for this group + $members_count = $modgroup_pending_count = 0; + + // Members + $group_members = DB()->fetch_rowset(" + SELECT u.username, u.user_id, u.user_opt, u.user_posts, u.user_regdate, u.user_from, u.user_website, u.user_email, u.user_icq, ug.user_pending + FROM ". BB_USER_GROUP ." ug, ". BB_USERS ." u + WHERE ug.group_id = $group_id + AND ug.user_pending = 0 + AND ug.user_id <> ". $group_moderator['user_id'] ." + AND u.user_id = ug.user_id + ORDER BY u.username + LIMIT $start, ". ($per_page + 1) ." + "); + $members_count = count($group_members); + + if ($members_count == $per_page + 1) + { + array_pop($group_members); + } + + if ($members_count > $per_page) + { + $items_count = $start + ($per_page * 2); + $pages = '?'; + } + else + { + $items_count = $start + $members_count; + $pages = (!$members_count) ? 1 : ceil($items_count / $per_page); + } + + $template->assign_vars(array( + 'PAGINATION' => generate_pagination(GROUP_URL . $group_id, $items_count, $per_page, $start), + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], floor($start / $per_page) + 1, $pages), + )); + + // Pending + if ($is_moderator) + { + $modgroup_pending_list = DB()->fetch_rowset(" + SELECT u.username, u.user_id, u.user_opt, u.user_posts, u.user_regdate, u.user_from, u.user_website, u.user_email, u.user_icq + FROM ". BB_USER_GROUP ." ug, ". BB_USERS ." u + WHERE ug.group_id = $group_id + AND ug.user_pending = 1 + AND u.user_id = ug.user_id + ORDER BY u.username + LIMIT 200 + "); + $modgroup_pending_count = count($modgroup_pending_list); + } + + // Current user membership + $is_group_member = $is_group_pending_member = false; + + $sql = "SELECT user_pending + FROM ". BB_USER_GROUP ." + WHERE group_id = $group_id + AND user_id = ". $userdata['user_id'] ." + LIMIT 1"; + + if ($row = DB()->fetch_row($sql)) + { + if ($row['user_pending'] == 0) + { + $is_group_member = true; + } + else + { + $is_group_pending_member = true; + } + } + + if ($userdata['user_id'] == $group_moderator['user_id']) + { + $group_details = $lang['ARE_GROUP_MODERATOR']; + $s_hidden_fields = ''; + } + else if ($is_group_member || $is_group_pending_member) + { + $template->assign_vars(array( + 'SHOW_UNSUBSCRIBE_CONTROLS' => true, + 'CONTROL_NAME' => ($is_group_member) ? 'unsub' : 'unsubpending', + )); + $group_details = ($is_group_pending_member) ? $lang['PENDING_THIS_GROUP'] : $lang['MEMBER_THIS_GROUP']; + $s_hidden_fields = ''; + } + else if (IS_GUEST) + { + $group_details = $lang['LOGIN_TO_JOIN']; + $s_hidden_fields = ''; + } + else + { + if ($group_info['group_type'] == GROUP_OPEN) + { + $template->assign_var('SHOW_SUBSCRIBE_CONTROLS'); + + $group_details = $lang['THIS_OPEN_GROUP']; + $s_hidden_fields = ''; + } + else if ($group_info['group_type'] == GROUP_CLOSED) + { + $group_details = $lang['THIS_CLOSED_GROUP']; + $s_hidden_fields = ''; + } + else if ($group_info['group_type'] == GROUP_HIDDEN) + { + $group_details = $lang['THIS_HIDDEN_GROUP']; + $s_hidden_fields = ''; + } + } + + // Add the moderator + $username = $group_moderator['username']; + $user_id = $group_moderator['user_id']; + + generate_user_info($group_moderator, $bb_cfg['default_dateformat'], $is_moderator, $from, $posts, $joined, $poster_avatar, $profile_img, $profile, $search_img, $search, $pm_img, $pm, $email_img, $email, $www_img, $www, $icq_status_img, $icq_img, $icq); + + $template->assign_vars(array( + 'GROUP_INFO' => true, + 'PAGE_TITLE' => $lang['GROUP_CONTROL_PANEL'], + + 'GROUP_NAME' => htmlCHR($group_info['group_name']), + 'GROUP_DESCRIPTION' => $group_info['group_description'], + 'GROUP_DETAILS' => $group_details, + 'MOD_USERNAME' => $username, + 'MOD_FROM' => $from, + 'MOD_JOINED' => $joined, + 'MOD_POSTS' => $posts, + 'MOD_AVATAR_IMG' => $poster_avatar, + 'MOD_PROFILE_IMG' => $profile_img, + 'MOD_PROFILE' => $profile, + 'MOD_SEARCH_IMG' => $search_img, + 'MOD_SEARCH' => $search, + 'MOD_PM_IMG' => $pm_img, + 'MOD_PM' => $pm, + 'MOD_EMAIL_IMG' => $email_img, + 'MOD_EMAIL' => $email, + 'MOD_WWW_IMG' => $www_img, + 'MOD_WWW' => $www, + 'MOD_ICQ_STATUS_IMG' => $icq_status_img, + 'MOD_ICQ_IMG' => $icq_img, + 'MOD_ICQ' => $icq, + + 'U_MOD_VIEWPROFILE' => "profile.php?mode=viewprofile&" . POST_USERS_URL . "=$user_id", + 'U_SEARCH_USER' => "search.php?mode=searchuser", + + 'S_GROUP_OPEN_TYPE' => GROUP_OPEN, + 'S_GROUP_CLOSED_TYPE' => GROUP_CLOSED, + 'S_GROUP_HIDDEN_TYPE' => GROUP_HIDDEN, + 'S_GROUP_OPEN_CHECKED' => ($group_info['group_type'] == GROUP_OPEN) ? ' checked="checked"' : '', + 'S_GROUP_CLOSED_CHECKED' => ($group_info['group_type'] == GROUP_CLOSED) ? ' checked="checked"' : '', + 'S_GROUP_HIDDEN_CHECKED' => ($group_info['group_type'] == GROUP_HIDDEN) ? ' checked="checked"' : '', + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_MODE_SELECT' => $select_sort_mode, + 'S_ORDER_SELECT' => $select_sort_order, + 'S_GROUPCP_ACTION' => "groupcp.php?" . POST_GROUPS_URL . "=$group_id", + )); + + // Dump out the remaining users + foreach ($group_members as $i => $member) + { + $username = $member['username']; + $user_id = $member['user_id']; + + generate_user_info($member, $bb_cfg['default_dateformat'], $is_moderator, $from, $posts, $joined, $poster_avatar, $profile_img, $profile, $search_img, $search, $pm_img, $pm, $email_img, $email, $www_img, $www, $icq_status_img, $icq_img, $icq); + + if ($group_info['group_type'] != GROUP_HIDDEN || $is_group_member || $is_moderator) + { + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars('member', array( + 'ROW_CLASS' => $row_class, + 'USERNAME' => $username, + 'FROM' => $from, + 'JOINED' => $joined, + 'POSTS' => $posts, + 'USER_ID' => $user_id, + 'AVATAR_IMG' => $poster_avatar, + 'PROFILE_IMG' => $profile_img, + 'PROFILE' => $profile, + 'SEARCH_IMG' => $search_img, + 'SEARCH' => $search, + 'PM_IMG' => $pm_img, + 'PM' => $pm, + 'EMAIL_IMG' => $email_img, + 'EMAIL' => $email, + 'WWW_IMG' => $www_img, + 'WWW' => $www, + 'ICQ_STATUS_IMG' => $icq_status_img, + 'ICQ_IMG' => $icq_img, + 'ICQ' => $icq, + + 'U_VIEWPROFILE' => "profile.php?mode=viewprofile&" . POST_USERS_URL . "=$user_id", + )); + + if ($is_moderator) + { + $template->assign_block_vars('member.switch_mod_option', array()); + } + } + } + + // No group members + if (!$members_count) + { + $template->assign_block_vars('switch_no_members', array()); + } + + // No group members + if ($group_info['group_type'] == GROUP_HIDDEN && !$is_group_member && !$is_moderator) + { + $template->assign_block_vars('switch_hidden_group', array()); + } + + // + // We've displayed the members who belong to the group, now we + // do that pending memebers... + // + if ($is_moderator && $modgroup_pending_list) + { + foreach ($modgroup_pending_list as $i => $member) + { + $username = $member['username']; + $user_id = $member['user_id']; + + generate_user_info($member, $bb_cfg['default_dateformat'], $is_moderator, $from, $posts, $joined, $poster_avatar, $profile_img, $profile, $search_img, $search, $pm_img, $pm, $email_img, $email, $www_img, $www, $icq_status_img, $icq_img, $icq); + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $user_select = ''; + + $template->assign_block_vars('pending', array( + 'ROW_CLASS' => $row_class, + 'USERNAME' => $username, + 'FROM' => $from, + 'JOINED' => $joined, + 'POSTS' => $posts, + 'USER_ID' => $user_id, + 'AVATAR_IMG' => $poster_avatar, + 'PROFILE_IMG' => $profile_img, + 'PROFILE' => $profile, + 'SEARCH_IMG' => $search_img, + 'SEARCH' => $search, + 'PM_IMG' => $pm_img, + 'PM' => $pm, + 'EMAIL_IMG' => $email_img, + 'EMAIL' => $email, + 'WWW_IMG' => $www_img, + 'WWW' => $www, + 'ICQ_STATUS_IMG' => $icq_status_img, + 'ICQ_IMG' => $icq_img, + 'ICQ' => $icq, + + 'U_VIEWPROFILE' => "profile.php?mode=viewprofile&". POST_USERS_URL ."=$user_id", + )); + } + + $template->assign_vars(array( + 'PENDING_USERS' => true, + )); + } + + if ($is_moderator) + { + $template->assign_block_vars('switch_mod_option', array()); + $template->assign_block_vars('switch_add_member', array()); + } +} + +print_page('groupcp.tpl'); \ No newline at end of file diff --git a/upload/images/Thumbs.db b/upload/images/Thumbs.db new file mode 100644 index 000000000..7f6da5c79 Binary files /dev/null and b/upload/images/Thumbs.db differ diff --git a/upload/images/avatars/bot.gif b/upload/images/avatars/bot.gif new file mode 100644 index 000000000..948c02ecb Binary files /dev/null and b/upload/images/avatars/bot.gif differ diff --git a/upload/images/avatars/gallery/noavatar.png b/upload/images/avatars/gallery/noavatar.png new file mode 100644 index 000000000..e6025d259 Binary files /dev/null and b/upload/images/avatars/gallery/noavatar.png differ diff --git a/upload/images/icon_clip.gif b/upload/images/icon_clip.gif new file mode 100644 index 000000000..4e9129790 Binary files /dev/null and b/upload/images/icon_clip.gif differ diff --git a/upload/images/icon_disk.gif b/upload/images/icon_disk.gif new file mode 100644 index 000000000..add08e92d Binary files /dev/null and b/upload/images/icon_disk.gif differ diff --git a/upload/images/icon_disk_gray.gif b/upload/images/icon_disk_gray.gif new file mode 100644 index 000000000..10fec33d3 Binary files /dev/null and b/upload/images/icon_disk_gray.gif differ diff --git a/upload/images/icon_dn.gif b/upload/images/icon_dn.gif new file mode 100644 index 000000000..957bfaaf1 Binary files /dev/null and b/upload/images/icon_dn.gif differ diff --git a/upload/images/logo/Thumbs.db b/upload/images/logo/Thumbs.db new file mode 100644 index 000000000..67c874b50 Binary files /dev/null and b/upload/images/logo/Thumbs.db differ diff --git a/upload/images/logo/logo.gif b/upload/images/logo/logo.gif new file mode 100644 index 000000000..8811a0d88 Binary files /dev/null and b/upload/images/logo/logo.gif differ diff --git a/upload/images/logo/logo.png b/upload/images/logo/logo.png new file mode 100644 index 000000000..3ff577a82 Binary files /dev/null and b/upload/images/logo/logo.png differ diff --git a/upload/images/magnet.png b/upload/images/magnet.png new file mode 100644 index 000000000..a667d4da0 Binary files /dev/null and b/upload/images/magnet.png differ diff --git a/upload/images/menu_open_1.gif b/upload/images/menu_open_1.gif new file mode 100644 index 000000000..839d8ac9a Binary files /dev/null and b/upload/images/menu_open_1.gif differ diff --git a/upload/images/pic_loading.gif b/upload/images/pic_loading.gif new file mode 100644 index 000000000..01e61866d Binary files /dev/null and b/upload/images/pic_loading.gif differ diff --git a/upload/images/smiles/aa.gif b/upload/images/smiles/aa.gif new file mode 100644 index 000000000..48c3c88ce Binary files /dev/null and b/upload/images/smiles/aa.gif differ diff --git a/upload/images/smiles/ab.gif b/upload/images/smiles/ab.gif new file mode 100644 index 000000000..48c861154 Binary files /dev/null and b/upload/images/smiles/ab.gif differ diff --git a/upload/images/smiles/ac.gif b/upload/images/smiles/ac.gif new file mode 100644 index 000000000..7442ceab4 Binary files /dev/null and b/upload/images/smiles/ac.gif differ diff --git a/upload/images/smiles/ad.gif b/upload/images/smiles/ad.gif new file mode 100644 index 000000000..ea194fefb Binary files /dev/null and b/upload/images/smiles/ad.gif differ diff --git a/upload/images/smiles/ae.gif b/upload/images/smiles/ae.gif new file mode 100644 index 000000000..b2ae75a1c Binary files /dev/null and b/upload/images/smiles/ae.gif differ diff --git a/upload/images/smiles/af.gif b/upload/images/smiles/af.gif new file mode 100644 index 000000000..6218414ce Binary files /dev/null and b/upload/images/smiles/af.gif differ diff --git a/upload/images/smiles/ag.gif b/upload/images/smiles/ag.gif new file mode 100644 index 000000000..08fd2f991 Binary files /dev/null and b/upload/images/smiles/ag.gif differ diff --git a/upload/images/smiles/ah.gif b/upload/images/smiles/ah.gif new file mode 100644 index 000000000..caf8d5b38 Binary files /dev/null and b/upload/images/smiles/ah.gif differ diff --git a/upload/images/smiles/ai.gif b/upload/images/smiles/ai.gif new file mode 100644 index 000000000..d47a4c361 Binary files /dev/null and b/upload/images/smiles/ai.gif differ diff --git a/upload/images/smiles/aj.gif b/upload/images/smiles/aj.gif new file mode 100644 index 000000000..323565efe Binary files /dev/null and b/upload/images/smiles/aj.gif differ diff --git a/upload/images/smiles/ak.gif b/upload/images/smiles/ak.gif new file mode 100644 index 000000000..ad50e3626 Binary files /dev/null and b/upload/images/smiles/ak.gif differ diff --git a/upload/images/smiles/al.gif b/upload/images/smiles/al.gif new file mode 100644 index 000000000..8ed13acb1 Binary files /dev/null and b/upload/images/smiles/al.gif differ diff --git a/upload/images/smiles/am.gif b/upload/images/smiles/am.gif new file mode 100644 index 000000000..ddd745af7 Binary files /dev/null and b/upload/images/smiles/am.gif differ diff --git a/upload/images/smiles/an.gif b/upload/images/smiles/an.gif new file mode 100644 index 000000000..6a425a43d Binary files /dev/null and b/upload/images/smiles/an.gif differ diff --git a/upload/images/smiles/ao.gif b/upload/images/smiles/ao.gif new file mode 100644 index 000000000..6c0e3e145 Binary files /dev/null and b/upload/images/smiles/ao.gif differ diff --git a/upload/images/smiles/ap.gif b/upload/images/smiles/ap.gif new file mode 100644 index 000000000..635b3272b Binary files /dev/null and b/upload/images/smiles/ap.gif differ diff --git a/upload/images/smiles/aq.gif b/upload/images/smiles/aq.gif new file mode 100644 index 000000000..93109f2fd Binary files /dev/null and b/upload/images/smiles/aq.gif differ diff --git a/upload/images/smiles/ar.gif b/upload/images/smiles/ar.gif new file mode 100644 index 000000000..c7bd8e03a Binary files /dev/null and b/upload/images/smiles/ar.gif differ diff --git a/upload/images/smiles/as.gif b/upload/images/smiles/as.gif new file mode 100644 index 000000000..b4a46bd85 Binary files /dev/null and b/upload/images/smiles/as.gif differ diff --git a/upload/images/smiles/at.gif b/upload/images/smiles/at.gif new file mode 100644 index 000000000..ebb95fc45 Binary files /dev/null and b/upload/images/smiles/at.gif differ diff --git a/upload/images/smiles/au.gif b/upload/images/smiles/au.gif new file mode 100644 index 000000000..869fc834d Binary files /dev/null and b/upload/images/smiles/au.gif differ diff --git a/upload/images/smiles/av.gif b/upload/images/smiles/av.gif new file mode 100644 index 000000000..38a9afd8c Binary files /dev/null and b/upload/images/smiles/av.gif differ diff --git a/upload/images/smiles/aw.gif b/upload/images/smiles/aw.gif new file mode 100644 index 000000000..c86e2aaa6 Binary files /dev/null and b/upload/images/smiles/aw.gif differ diff --git a/upload/images/smiles/ax.gif b/upload/images/smiles/ax.gif new file mode 100644 index 000000000..8130923fc Binary files /dev/null and b/upload/images/smiles/ax.gif differ diff --git a/upload/images/smiles/ay.gif b/upload/images/smiles/ay.gif new file mode 100644 index 000000000..0c45cc24f Binary files /dev/null and b/upload/images/smiles/ay.gif differ diff --git a/upload/images/smiles/az.gif b/upload/images/smiles/az.gif new file mode 100644 index 000000000..311829e15 Binary files /dev/null and b/upload/images/smiles/az.gif differ diff --git a/upload/images/smiles/ba.gif b/upload/images/smiles/ba.gif new file mode 100644 index 000000000..a06637883 Binary files /dev/null and b/upload/images/smiles/ba.gif differ diff --git a/upload/images/smiles/bb.gif b/upload/images/smiles/bb.gif new file mode 100644 index 000000000..ad656611f Binary files /dev/null and b/upload/images/smiles/bb.gif differ diff --git a/upload/images/smiles/bc.gif b/upload/images/smiles/bc.gif new file mode 100644 index 000000000..083af3f68 Binary files /dev/null and b/upload/images/smiles/bc.gif differ diff --git a/upload/images/smiles/bd.gif b/upload/images/smiles/bd.gif new file mode 100644 index 000000000..381f5cde0 Binary files /dev/null and b/upload/images/smiles/bd.gif differ diff --git a/upload/images/smiles/be.gif b/upload/images/smiles/be.gif new file mode 100644 index 000000000..4835b1598 Binary files /dev/null and b/upload/images/smiles/be.gif differ diff --git a/upload/images/smiles/bf.gif b/upload/images/smiles/bf.gif new file mode 100644 index 000000000..f7faaf727 Binary files /dev/null and b/upload/images/smiles/bf.gif differ diff --git a/upload/images/smiles/bg.gif b/upload/images/smiles/bg.gif new file mode 100644 index 000000000..59153be71 Binary files /dev/null and b/upload/images/smiles/bg.gif differ diff --git a/upload/images/smiles/bh.gif b/upload/images/smiles/bh.gif new file mode 100644 index 000000000..4d679573a Binary files /dev/null and b/upload/images/smiles/bh.gif differ diff --git a/upload/images/smiles/bi.gif b/upload/images/smiles/bi.gif new file mode 100644 index 000000000..7b887f00c Binary files /dev/null and b/upload/images/smiles/bi.gif differ diff --git a/upload/images/smiles/bj.gif b/upload/images/smiles/bj.gif new file mode 100644 index 000000000..b06ae18bb Binary files /dev/null and b/upload/images/smiles/bj.gif differ diff --git a/upload/images/smiles/bk.gif b/upload/images/smiles/bk.gif new file mode 100644 index 000000000..16fbe8e1e Binary files /dev/null and b/upload/images/smiles/bk.gif differ diff --git a/upload/images/smiles/bl.gif b/upload/images/smiles/bl.gif new file mode 100644 index 000000000..a55908452 Binary files /dev/null and b/upload/images/smiles/bl.gif differ diff --git a/upload/images/smiles/bm.gif b/upload/images/smiles/bm.gif new file mode 100644 index 000000000..0586ca939 Binary files /dev/null and b/upload/images/smiles/bm.gif differ diff --git a/upload/images/smiles/bn.gif b/upload/images/smiles/bn.gif new file mode 100644 index 000000000..8014a3fc6 Binary files /dev/null and b/upload/images/smiles/bn.gif differ diff --git a/upload/images/smiles/bo.gif b/upload/images/smiles/bo.gif new file mode 100644 index 000000000..ef20b4087 Binary files /dev/null and b/upload/images/smiles/bo.gif differ diff --git a/upload/images/smiles/bp.gif b/upload/images/smiles/bp.gif new file mode 100644 index 000000000..b938e7e2e Binary files /dev/null and b/upload/images/smiles/bp.gif differ diff --git a/upload/images/smiles/bq.gif b/upload/images/smiles/bq.gif new file mode 100644 index 000000000..40b9ce651 Binary files /dev/null and b/upload/images/smiles/bq.gif differ diff --git a/upload/images/smiles/br.gif b/upload/images/smiles/br.gif new file mode 100644 index 000000000..3618ebeb3 Binary files /dev/null and b/upload/images/smiles/br.gif differ diff --git a/upload/images/smiles/bs.gif b/upload/images/smiles/bs.gif new file mode 100644 index 000000000..bc05134e3 Binary files /dev/null and b/upload/images/smiles/bs.gif differ diff --git a/upload/images/smiles/bt.gif b/upload/images/smiles/bt.gif new file mode 100644 index 000000000..4cba890fa Binary files /dev/null and b/upload/images/smiles/bt.gif differ diff --git a/upload/images/smiles/bu.gif b/upload/images/smiles/bu.gif new file mode 100644 index 000000000..831019e6d Binary files /dev/null and b/upload/images/smiles/bu.gif differ diff --git a/upload/images/smiles/bv.gif b/upload/images/smiles/bv.gif new file mode 100644 index 000000000..93b62618b Binary files /dev/null and b/upload/images/smiles/bv.gif differ diff --git a/upload/images/smiles/bw.gif b/upload/images/smiles/bw.gif new file mode 100644 index 000000000..c565a9b68 Binary files /dev/null and b/upload/images/smiles/bw.gif differ diff --git a/upload/images/smiles/smileys.pak b/upload/images/smiles/smileys.pak new file mode 100644 index 000000000..7b5d676af --- /dev/null +++ b/upload/images/smiles/smileys.pak @@ -0,0 +1,49 @@ +aa.gif=+:aa=+::aa: +ab.gif=+:ab=+::ab: +ac.gif=+:ac=+::ac: +ad.gif=+:ad=+::ad: +ae.gif=+:ae=+::ae: +af.gif=+:af=+::af: +ag.gif=+:ag=+::ag: +ah.gif=+:ah=+::ah: +ai.gif=+:ai=+::ai: +aj.gif=+:aj=+::aj: +ak.gif=+:ak=+::ak: +al.gif=+:al=+::al: +am.gif=+:am=+::am: +an.gif=+:an=+::an: +ao.gif=+:ao=+::ao: +ap.gif=+:ap=+::ap: +aq.gif=+:aq=+::aq: +ar.gif=+:ar=+::ar: +as.gif=+:as=+::as: +at.gif=+:at=+::at: +au.gif=+:au=+::au: +av.gif=+:av=+::av: +aw.gif=+:aw=+::aw: +ax.gif=+:ax=+::ax: +ay.gif=+:ay=+::ay: +az.gif=+:az=+::az: +ba.gif=+:ba=+::ba: +bb.gif=+:bb=+::bb: +bc.gif=+:bc=+::bc: +bd.gif=+:bd=+::bd: +be.gif=+:be=+::be: +bf.gif=+:bf=+::bf: +bg.gif=+:bg=+::bg: +bh.gif=+:bh=+::bh: +bi.gif=+:bi=+::bi: +bj.gif=+:bj=+::bj: +bk.gif=+:bk=+::bk: +bl.gif=+:bl=+::bl: +bm.gif=+:bm=+::bm: +bn.gif=+:bn=+::bn: +bo.gif=+:bo=+::bo: +bp.gif=+:bp=+::bp: +bq.gif=+:bq=+::bq: +br.gif=+:br=+::br: +bs.gif=+:bs=+::bs: +bt.gif=+:bt=+::bt: +bu.gif=+:bu=+::bu: +bv.gif=+:bv=+::bv: +bw.gif=+:bw=+::bw: diff --git a/upload/images/spacer.gif b/upload/images/spacer.gif new file mode 100644 index 000000000..5bfd67a2d Binary files /dev/null and b/upload/images/spacer.gif differ diff --git a/upload/images/tor_gold.gif b/upload/images/tor_gold.gif new file mode 100644 index 000000000..c735646e0 Binary files /dev/null and b/upload/images/tor_gold.gif differ diff --git a/upload/images/tor_silver.gif b/upload/images/tor_silver.gif new file mode 100644 index 000000000..b7c9d4f7c Binary files /dev/null and b/upload/images/tor_silver.gif differ diff --git a/upload/images/user_offline.gif b/upload/images/user_offline.gif new file mode 100644 index 000000000..d3cd05b2d Binary files /dev/null and b/upload/images/user_offline.gif differ diff --git a/upload/images/user_online.gif b/upload/images/user_online.gif new file mode 100644 index 000000000..606eab7cf Binary files /dev/null and b/upload/images/user_online.gif differ diff --git a/upload/includes/.htaccess b/upload/includes/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/FastJSON.class.php b/upload/includes/FastJSON.class.php new file mode 100644 index 000000000..896b66877 --- /dev/null +++ b/upload/includes/FastJSON.class.php @@ -0,0 +1,372 @@ +values), new GenericClass):new Instance of GenericClass + * + * With a decoded JSON object You could convert them + * into a new instance of your Generic Class. + * Example: + * class MyClass { + * var $param = "somevalue"; + * function MyClass($somevar) { + * $this->somevar = $somevar; + * }; + * function getVar = function(){ + * return $this->somevar; + * }; + * }; + * + * $instance = new MyClass("example"); + * $encoded = FastJSON::encode($instance); + * // {"param":"somevalue"} + * + * $decoded = FastJSON::decode($encoded); + * // $decoded instanceof Object => true + * // $decoded instanceof MyClass => false + * + * $decoded = FastJSON::convert($decoded, new MyClass("example")); + * // $decoded instanceof Object => true + * // $decoded instanceof MyClass => true + * + * $decoded->getVar(); // example + * + * --------------------------------------- + * + * @author Andrea Giammarchi + * @site http://www.devpro.it/ + * @version 0.4 [fixed string convertion problems, add stdClass optional convertion instead of associative array (used by default)] + * @requires anything + * @compatibility PHP >= 4 + * @license + * --------------------------------------- + * + * Copyright (c) 2006 - 2007 Andrea Giammarchi + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated + * documentation files (the "Software"), + * to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * _______________________________________ + */ +class FastJSON { + + // public methods + + /** + * public static method + * + * FastJSON::convert(params:* [, result:Instance]):* + * + * @param * String or Object + * @param Instance optional new generic class instance if first + * parameter is an object. + * @return * time() value or new Instance with object parameters. + * + * @note please read Special FastJSON::convert method Informations + */ + function convert($params, $result = null){ + switch(gettype($params)){ + case 'array': + $tmp = array(); + foreach($params as $key => $value) { + if(($value = FastJSON::encode($value)) !== '') + array_push($tmp, FastJSON::encode(strval($key)).':'.$value); + }; + $result = '{'.implode(',', $tmp).'}'; + break; + case 'boolean': + $result = $params ? 'true' : 'false'; + break; + case 'double': + case 'float': + case 'integer': + $result = $result !== null ? strftime('%Y-%m-%dT%H:%M:%S', $params) : strval($params); + break; + case 'NULL': + $result = 'null'; + break; + case 'string': + $i = create_function('&$e, $p, $l', 'return intval(substr($e, $p, $l));'); + if(preg_match('/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $params)) + $result = mktime($i($params, 11, 2), $i($params, 14, 2), $i($params, 17, 2), $i($params, 5, 2), $i($params, 9, 2), $i($params, 0, 4)); + break; + case 'object': + $tmp = array(); + if(is_object($result)) { + foreach($params as $key => $value) + $result->$key = $value; + } else { + $result = get_object_vars($params); + foreach($result as $key => $value) { + if(($value = FastJSON::encode($value)) !== '') + array_push($tmp, FastJSON::encode($key).':'.$value); + }; + $result = '{'.implode(',', $tmp).'}'; + } + break; + } + return $result; + } + + /** + * public method + * + * FastJSON::decode(params:String[, useStdClass:Boolean]):* + * + * @param String valid JSON encoded string + * @param Bolean uses stdClass instead of associative array if params contains objects (default false) + * @return * converted variable or null + * is params is not a JSON compatible string. + * @note This method works in an optimist way. If JSON string is not valid + * the code execution will die using exit. + * This is probably not so good but JSON is often used combined with + * XMLHttpRequest then I suppose that's better more protection than + * just some WARNING. + * With every kind of valid JSON string the old error_reporting level + * and the old error_handler will be restored. + * + * @example + * FastJSON::decode('{"param":"value"}'); // associative array + * FastJSON::decode('{"param":"value"}', true); // stdClass + * FastJSON::decode('["one",two,true,false,null,{},[1,2]]'); // array + */ + function decode($encode, $stdClass = false){ + $pos = 0; + $slen = is_string($encode) ? strlen($encode) : null; + if($slen !== null) { + $error = error_reporting(0); + set_error_handler(array('FastJSON', '__exit')); + $result = FastJSON::__decode($encode, $pos, $slen, $stdClass); + error_reporting($error); + restore_error_handler(); + } + else + $result = null; + return $result; + } + + /** + * public method + * + * FastJSON::encode(params:*):String + * + * @param * Array, Boolean, Float, Int, Object, String or NULL variable. + * @return String JSON genric object rappresentation + * or empty string if param is not compatible. + * + * @example + * FastJSON::encode(array(1,"two")); // '[1,"two"]' + * + * $obj = new MyClass(); + * obj->param = "value"; + * obj->param2 = "value2"; + * FastJSON::encode(obj); // '{"param":"value","param2":"value2"}' + */ + function encode($decode){ + $result = ''; + switch(gettype($decode)){ + case 'array': + if(!count($decode) || array_keys($decode) === range(0, count($decode) - 1)) { + $keys = array(); + foreach($decode as $value) { + if(($value = FastJSON::encode($value)) !== '') + array_push($keys, $value); + } + $result = '['.implode(',', $keys).']'; + } + else + $result = FastJSON::convert($decode); + break; + case 'string': + $replacement = FastJSON::__getStaticReplacement(); + $result = '"'.str_replace($replacement['find'], $replacement['replace'], $decode).'"'; + break; + default: + if(!is_callable($decode)) + $result = FastJSON::convert($decode); + break; + } + return $result; + } + + // private methods, uncommented, sorry + function __getStaticReplacement(){ + static $replacement = array('find'=>array(), 'replace'=>array()); + if($replacement['find'] == array()) { + foreach(array_merge(range(0, 7), array(11), range(14, 31)) as $v) { + $replacement['find'][] = chr($v); + $replacement['replace'][] = "\\u00".sprintf("%02x", $v); + } + $replacement['find'] = array_merge(array(chr(0x5c), chr(0x2F), chr(0x22), chr(0x0d), chr(0x0c), chr(0x0a), chr(0x09), chr(0x08)), $replacement['find']); + $replacement['replace'] = array_merge(array('\\\\', '\\/', '\\"', '\r', '\f', '\n', '\t', '\b'), $replacement['replace']); + } + return $replacement; + } + function __decode(&$encode, &$pos, &$slen, &$stdClass){ + switch($encode{$pos}) { + case 't': + $result = true; + $pos += 4; + break; + case 'f': + $result = false; + $pos += 5; + break; + case 'n': + $result = null; + $pos += 4; + break; + case '[': + $result = array(); + ++$pos; + while($encode{$pos} !== ']') { + array_push($result, FastJSON::__decode($encode, $pos, $slen, $stdClass)); + if($encode{$pos} === ',') + ++$pos; + } + ++$pos; + break; + case '{': + $result = $stdClass ? new stdClass : array(); + ++$pos; + while($encode{$pos} !== '}') { + $tmp = FastJSON::__decodeString($encode, $pos); + ++$pos; + if($stdClass) + $result->$tmp = FastJSON::__decode($encode, $pos, $slen, $stdClass); + else + $result[$tmp] = FastJSON::__decode($encode, $pos, $slen, $stdClass); + if($encode{$pos} === ',') + ++$pos; + } + ++$pos; + break; + case '"': + switch($encode{++$pos}) { + case '"': + $result = ""; + break; + default: + $result = FastJSON::__decodeString($encode, $pos); + break; + } + ++$pos; + break; + default: + $tmp = ''; + preg_replace('/^(\-)?([0-9]+)(\.[0-9]+)?([eE]\+[0-9]+)?/e', '$tmp = "\\1\\2\\3\\4"', substr($encode, $pos)); + if($tmp !== '') { + $pos += strlen($tmp); + $nint = intval($tmp); + $nfloat = floatval($tmp); + $result = $nfloat == $nint ? $nint : $nfloat; + } + break; + } + return $result; + } + function __decodeString(&$encode, &$pos) { + $replacement = FastJSON::__getStaticReplacement(); + $endString = FastJSON::__endString($encode, $pos, $pos); + $result = str_replace($replacement['replace'], $replacement['find'], substr($encode, $pos, $endString)); + $pos += $endString; + return $result; + } + function __endString(&$encode, $position, &$pos) { + do { + $position = strpos($encode, '"', $position + 1); + }while($position !== false && FastJSON::__slashedChar($encode, $position - 1)); + if($position === false) + trigger_error('', E_USER_WARNING); + return $position - $pos; + } + function __exit($str, $a, $b) { + exit($a.'FATAL: FastJSON decode method failure [malicious or incorrect JSON string]'); + } + function __slashedChar(&$encode, $position) { + $pos = 0; + while($encode{$position--} === '\\') + $pos++; + return $pos % 2; + } +} + +?> diff --git a/upload/includes/bbcode.php b/upload/includes/bbcode.php new file mode 100644 index 000000000..a9876d348 --- /dev/null +++ b/upload/includes/bbcode.php @@ -0,0 +1,1014 @@ +enqueue(array( + 'smile_replacements', +)); + +$page_cfg['include_bbcode_js'] = true; + +// +// BBCode templates +// +function get_bbcode_tpl () +{ +$bbcode_tpl = array(); +// Quote +/* +
+
Цитата:
+
+*/ +$bbcode_tpl['quote_open'] = << +
+HTML; + +/* +
+
\\1 писал(а):
+
+*/ +$bbcode_tpl['quote_username_open'] = << +
+HTML; + +$bbcode_tpl['quote_close'] = << +
+HTML; + +// Code +$bbcode_tpl['code_open'] = << +
Код:
+
+HTML; + +$bbcode_tpl['code_close'] = << +
+HTML; + +// Spoiler +/* +
+
скрытый текст
+
+*/ +$bbcode_tpl['spoiler_open'] = << +
+HTML; + +/* +
+
\\1
+
+*/ +$bbcode_tpl['spoiler_title_open'] = << +
+

\\1

+HTML; + +$bbcode_tpl['spoiler_close'] = << +
+HTML; + +// Image +$bbcode_tpl['img'] = ' '; + +$bbcode_tpl['img_aligned'] = << +HTML; + +// HR +$bbcode_tpl['hr'] = <<- +HTML; + +array_deep($bbcode_tpl, 'bbcode_tpl_compact'); +return $bbcode_tpl; +} + +function bbcode_tpl_compact ($text) +{ + $text = str_compact($text); + $text = str_replace('> <', '><', $text); + return $text; +} + +// prepare a posted message for entry into the database +function prepare_message ($message) +{ + $message = bbcode::clean_up($message); + $message = htmlCHR($message, false, ENT_NOQUOTES); + return $message; +} + +// +// post_html_cache +// +function update_post_html_cache ($post_id, $post_text) +{ + if (CACHE('bb_post_html')->used) + { + $post_html = bbcode2html($post_text); + CACHE('bb_post_html')->set($post_id, $post_html, 86400, 'p_html_'); + } +} + +function rm_post_html_cache ($post_id) +{ + CACHE('bb_post_html')->rm("p_html_{$post_id}"); +} + +// $post_ids - array or int +function get_posts_html ($post_ids) +{ + if (!$post_ids_csv = get_id_csv($post_ids)) + { + return is_array($post_ids) ? array() : ''; + } + + return CACHE('bb_post_html')->get($post_ids, 'get_posts_html_items', 'p_html_', 86400); +} + +// $post_ids - array +function get_posts_html_items ($post_ids) +{ + if (!$post_ids_csv = get_id_csv($post_ids)) return array(); + + $items = array_fill_keys( (array)$post_ids, null ); + + $sql = "SELECT post_id, post_text FROM ". BB_POSTS_TEXT ." WHERE post_id IN($post_ids_csv) ORDER BY NULL"; + + foreach (DB('pt')->fetch_rowset($sql) as $row) + { + $items[$row['post_id']] = bbcode2html($row['post_text']); + } + + return is_array($post_ids) ? $items : $items[$post_ids]; +} + +// $post_ids - array or int +function get_posts_text ($post_ids) +{ + global $bb_cfg; + + if (!$post_ids_csv = get_id_csv($post_ids)) + { + return is_array($post_ids) ? array() : ''; + } + + $posts_text = array(); + + $sql = "SELECT post_id, post_text FROM ". BB_POSTS_TEXT ." WHERE post_id IN($post_ids_csv) ORDER BY NULL"; + + foreach (DB('pt')->fetch_rowset($sql) as $row) + { + $posts_text[$row['post_id']] = $row['post_text']; + } + + return is_array($post_ids) ? $posts_text : $posts_text[$post_ids]; +} + +// Fill smiley templates (or just the variables) with smileys +// Either in a window or inline +function generate_smilies($mode) +{ + global $bb_cfg, $template, $lang, $images; + global $user; + + $inline_columns = 4; + $inline_rows = 7; + $window_columns = 8; + + if ($mode == 'window') + { + $user->session_start(); + } + + if (!$sql = CACHE('bb_cache')->get('smilies')) + { + $sql = DB()->fetch_rowset("SELECT emoticon, code, smile_url FROM ". BB_SMILIES ." ORDER BY smilies_id"); + CACHE('bb_cache')->set('smilies', $sql); + } + if ($sql) + { + $num_smilies = 0; + $rowset = array(); + foreach ($sql as $row) + { + if (empty($rowset[$row['smile_url']])) + { + $rowset[$row['smile_url']]['code'] = str_replace("'", "\\'", str_replace('\\', '\\\\', $row['code'])); + $rowset[$row['smile_url']]['emoticon'] = $row['emoticon']; + $num_smilies++; + } + } + + if ($num_smilies) + { + $smilies_count = ($mode == 'inline') ? min(19, $num_smilies) : $num_smilies; + $smilies_split_row = ($mode == 'inline') ? $inline_columns - 1 : $window_columns - 1; + + $s_colspan = 0; + $row = 0; + $col = 0; + + while (list($smile_url, $data) = @each($rowset)) + { + if (!$col) + { + $template->assign_block_vars('smilies_row', array()); + } + + $template->assign_block_vars('smilies_row.smilies_col', array( + 'SMILEY_CODE' => $data['code'], + 'SMILEY_IMG' => $bb_cfg['smilies_path'] . '/' . $smile_url, + 'SMILEY_DESC' => $data['emoticon']) + ); + + $s_colspan = max($s_colspan, $col + 1); + + if ($col == $smilies_split_row) + { + if ($mode == 'inline' && $row == $inline_rows - 1) + { + break; + } + $col = 0; + $row++; + } + else + { + $col++; + } + } + + if ($mode == 'inline' && $num_smilies > $inline_rows * $inline_columns) + { + $template->assign_block_vars('switch_smilies_extra', array()); + + $template->assign_vars(array( + 'L_MORE_SMILIES' => $lang['MORE_EMOTICONS'], + 'U_MORE_SMILIES' => append_sid("posting.php?mode=smilies")) + ); + } + + $template->assign_vars(array( + 'PAGE_TITLE' => $lang['EMOTICONS'], + 'L_EMOTICONS' => $lang['EMOTICONS'], + 'S_SMILIES_COLSPAN' => $s_colspan, + )); + } + } + + if ($mode == 'window') + { + print_page('posting_smilies.tpl', 'simple'); + } +} + +// some functions from vB +// ############################################################################# +/** +* Strips away [quote] tags and their contents from the specified string +* +* @param string Text to be stripped of quote tags +* +* @return string +*/ +function strip_quotes ($text) +{ + $lowertext = strtolower($text); + + // find all [quote tags + $start_pos = array(); + $curpos = 0; + do + { + $pos = strpos($lowertext, '[quote', $curpos); + if ($pos !== false) + { + $start_pos["$pos"] = 'start'; + $curpos = $pos + 6; + } + } + while ($pos !== false); + + if (sizeof($start_pos) == 0) + { + return $text; + } + + // find all [/quote] tags + $end_pos = array(); + $curpos = 0; + do + { + $pos = strpos($lowertext, '[/quote', $curpos); + if ($pos !== false) + { + $end_pos["$pos"] = 'end'; + $curpos = $pos + 8; + } + } + while ($pos !== false); + + if (sizeof($end_pos) == 0) + { + return $text; + } + + // merge them together and sort based on position in string + $pos_list = $start_pos + $end_pos; + ksort($pos_list); + + do + { + // build a stack that represents when a quote tag is opened + // and add non-quote text to the new string + $stack = array(); + $newtext = '[...] '; + $substr_pos = 0; + foreach ($pos_list AS $pos => $type) + { + $stacksize = sizeof($stack); + if ($type == 'start') + { + // empty stack, so add from the last close tag or the beginning of the string + if ($stacksize == 0) + { + $newtext .= substr($text, $substr_pos, $pos - $substr_pos); + } + array_push($stack, $pos); + } + else + { + // pop off the latest opened tag + if ($stacksize) + { + array_pop($stack); + $substr_pos = $pos + 8; + } + } + } + + // add any trailing text + $newtext .= substr($text, $substr_pos); + + // check to see if there's a stack remaining, remove those points + // as key points, and repeat. Allows emulation of a non-greedy-type + // recursion. + if ($stack) + { + foreach ($stack AS $pos) + { + unset($pos_list["$pos"]); + } + } + } + while ($stack); + + return $newtext; +} + +// ############################################################################# +/** +* Strips away bbcode from a given string, leaving plain text +* +* @param string Text to be stripped of bbcode tags +* @param boolean If true, strip away quote tags AND their contents +* @param boolean If true, use the fast-and-dirty method rather than the shiny and nice method +* +* @return string +*/ +function strip_bbcode ($message, $stripquotes = true, $fast_and_dirty = false, $showlinks = true) +{ + $find = array(); + $replace = array(); + + if ($stripquotes) + { + // [quote=username] and [quote] + $message = strip_quotes($message); + } + + // a really quick and rather nasty way of removing bbcode + if ($fast_and_dirty) + { + // any old thing in square brackets + $find[] = '#\[.*/?\]#siU'; + $replace = ''; + + $message = preg_replace($find, $replace, $message); + } + // the preferable way to remove bbcode + else + { + // simple links + $find[] = '#\[(email|url)=("??)(.+)\\2\]\\3\[/\\1\]#siU'; + $replace[] = '\3'; + + // named links + $find[] = '#\[(email|url)=("??)(.+)\\2\](.+)\[/\\1\]#siU'; + $replace[] = ($showlinks ? '\4 (\3)' : '\4'); + + // smilies + $find[] = '#(?<=^|\W)(:\w+?:)(?=$|\W)#'; + $replace[] = ''; + + // replace + $message = preg_replace($find, $replace, $message); + + // strip out all other instances of [x]...[/x] + while (preg_match('#\[([a-z]+)\s*?(?:[^\]]*?)\](.*?)(\[/\1\])#is', $message, $m)) + { + $message = str_replace($m[0], $m[2], $message); + } + + $replace = array('[*]', '[hr]', '[br]'); + $message = str_replace($replace, ' ', $message); + } + + return $message; +} + +function extract_search_words ($text) +{ + global $bb_cfg; + + $max_words_count = $bb_cfg['max_search_words_per_post']; + $min_word_len = max(2, $bb_cfg['search_min_word_len'] - 1); + $max_word_len = $bb_cfg['search_max_word_len']; + + $text = ' ' . str_compact(strip_tags(strtolower($text))) . ' '; + $text = str_replace(array('[', ']'), array('[', ']'), $text); + + // HTML entities like   + $text = preg_replace('/(\w*?)&#?[0-9a-z]+;(\w*?)/i', '', $text); + // Remove URL's + $text = preg_replace('#\b[a-z0-9]+://[0-9a-z\.\-]+(/[0-9a-z\?\.%_\-\+=&/]+)?#', ' ', $text); + + $text = strip_bbcode($text); + + // Filter out characters like ^, $, &, change "it's" to "its" + $text = preg_replace('#\W#', ' ', $text); + + // short & long words + $text = preg_replace('#(?<=^|\s)(\S{1,'.$min_word_len.'}|\S{'.$max_word_len.',}|\W*)(?=$|\s)#', ' ', $text); + + $text = remove_stopwords($text); +# $text = replace_synonyms($text); + + // Trim 1+ spaces to one space and split this string into unique words + $text = array_unique(explode(' ', str_compact($text))); + + if (sizeof($text) > $max_words_count) + { +# shuffle($text); + $text = array_splice($text, 0, $max_words_count); + } + + return $text; +} + +function replace_synonyms ($text) +{ + static $syn_match = null, $syn_replace = null; + + if (is_null($syn_match)) + { + preg_match_all("#(\w+) (\w+)(\r?\n|$)#", @file_get_contents(LANG_DIR .'search_synonyms.txt'), $m); + + $syn_match = $m[2]; + $syn_replace = $m[1]; + + array_deep($syn_match, 'pad_with_space'); + array_deep($syn_replace, 'pad_with_space'); + } + + return ($syn_match && $syn_replace) ? str_replace($syn_match, $syn_replace, $text) : $text; +} + +function add_search_words ($post_id, $post_message, $post_title = '', $bbcode_uid = '', $only_return_words = false) +{ + $text = $post_title .' '. $post_message; + $text = strip_bbcode_uid($text, $bbcode_uid); + $words = ($text) ? extract_search_words($text) : array(); + + if ($only_return_words) + { + return join("\n", $words); + } + else + { + DB()->query("DELETE FROM ". BB_POSTS_SEARCH ." WHERE post_id = $post_id"); + + if ($words_sql = DB()->escape(join("\n", $words))) + { + DB()->query("REPLACE INTO ". BB_POSTS_SEARCH ." (post_id, search_words) VALUES ($post_id, '$words_sql')"); + } + } +} + +class bbcode +{ + var $tpl = array(); // шаблоны для замены тегов + var $smilies = null; + var $found_spam = null; // найденные спам "слова" + var $del_words = array(); // см. get_words_rate() + var $tidy_cfg = array( + 'drop-empty-paras' => false, + 'fix-uri' => false, + 'force-output' => true, + 'hide-comments' => true, + 'join-classes' => false, + 'join-styles' => false, + 'merge-divs' => false, +# 'merge-spans' => false, // нужно будет включить после обновления версии tidy + 'newline' => 'LF', + 'output-xhtml' => true, + 'preserve-entities' => true, + 'quiet' => true, + 'quote-ampersand' => false, + 'show-body-only' => true, + 'show-errors' => false, + 'show-warnings' => false, + 'wrap' => 0, + ); + var $block_tags = array( + 'align', + 'br', + 'clear', + 'hr', + 'list', + 'pre', + 'quote', + 'spoiler', + ); + var $preg = array(); + var $str = array(); + var $preg_search = array(); + var $preg_repl = array(); + var $str_search = array(); + var $str_repl = array(); + + /** + * Constructor + */ + function bbcode () + { + global $bb_cfg; + + $this->tpl = get_bbcode_tpl(); + + $this->init_replacements(); + + if ($bb_cfg['tidy_cfg']) + { + $this->tidy_cfg = array_merge($this->tidy_cfg, $bb_cfg['tidy_cfg']); + } + } + + /** + * init_replacements + */ + function init_replacements () + { + $tpl = $this->tpl; + $url_exp = '[\w\#$%&~/.\-;:=?@\[\]+]+?'; + $img_url_exp = 'http://[^\s\?&;:=\#\"<>]+?\.(jpg|jpeg|gif|png)'; + $email_exp = '[a-z0-9&\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+'; + + $this->preg = array( + '#\[quote="(.+?)"\]#' => $tpl['quote_username_open'], + '#\[spoiler="(.+?)"\]#' => $tpl['spoiler_title_open'], + '#\[list=(a|A|i|I|1)\]#' => '
    ', + '#\[\*=(\d+)\]#' => '
  • ', + '#\[pre\](.*?)\[/pre\]#s' => '
    $1
    ', + '#\[name=([a-zA-Z0-9_]+?)\]#' => '', + '#\[url=\#([a-zA-Z0-9_]+?)\](.*?)\[/url\]#' => '$2', + '#\[color=([\#0-9a-zA-Z]+)\]#' => '', + '#\[size=([1-2]?[0-9])\]#' => '', + '#\[align=(left|right|center|justify)\]#' => '', + '#\[font="([\w\- \']+)"\]#' => '', + "#\[img\]($img_url_exp)\[/img\]#i" => $tpl['img'], + "#\[img=(left|right)\]($img_url_exp)\[/img\]\s*#i" => $tpl['img_aligned'], + "#\[email\]($email_exp)\[/email\]#i" => '$1', + "#\[url\](https?://$url_exp)\[/url\]#i" => '$1', + "#\[url\](www\.$url_exp)\[/url\]#i" => '$1', + "#\[url=(https?://$url_exp)\]([^?\n\t].*?)\[/url\]#i" => '$2', + "#\[url=(www\.$url_exp)\]([^?\n\t].*?)\[/url\]#i" => '$2', + ); + + $this->str = array( + '[quote]' => $tpl['quote_open'], + '[/quote]' => $tpl['quote_close'], + '[spoiler]' => $tpl['spoiler_open'], + '[/spoiler]' => $tpl['spoiler_close'], + '[list]' => '
      ', + '[*]' => '
    • ', + '[/list]' => '
    ', + '[/color]' => '
    ', + '[/size]' => '
    ', + '[/align]' => '
    ', + '[/font]' => '
    ', + '[tab]' => ' ', + '[br]' => "\n\n", + '[hr]' => $tpl['hr'], # $('.post-hr').html('
    '); + '[b]' => '', + '[/b]' => '', + '[u]' => '', + '[/u]' => '', + '[i]' => '', + '[/i]' => '', + '[s]' => '', + '[/s]' => '', + '[del]' => '', + '[/del]' => '', + '[clear]' => '
     
    ', + ); + + $this->preg_search = array_keys($this->preg); + $this->preg_repl = array_values($this->preg); + $this->str_search = array_keys($this->str); + $this->str_repl = array_values($this->str); + } + + /** + * bbcode2html + * $text должен быть уже обработан htmlCHR($text, false, ENT_NOQUOTES); + */ + function bbcode2html ($text, $do_tidy = true) + { + $text = " $text "; + $text = $this->clean_up($text); + $text = $this->spam_filter($text); + + // парсинг тегов + if (strpos($text, '[') !== false) + { + // [CODE] + $text = preg_replace_callback('#(\s*)\[code\](.+?)\[/code\](\s*)#s', array(&$this, 'code_callback'), $text); + + // Escape tags inside tiltes in [quote="tilte"] + $text = preg_replace_callback('#(\[(quote|spoiler)=")(.+?)("\])#', array(&$this, 'escape_tiltes_callback'), $text); + + // Normalize block level tags wrapped with new lines + $block_tags = join('|', $this->block_tags); + $text = str_replace("\n\n[hr]\n\n", '[br][hr][br]', $text); + $text = preg_replace("#(\s*)(\[/?($block_tags)(.*?)\])(\s*)#", '$2', $text); + + // Tag replacements + $text = preg_replace($this->preg_search, $this->preg_repl, $text); + $text = str_replace($this->str_search, $this->str_repl, $text); + } + + $text = $this->make_clickable($text); + $text = $this->smilies_pass($text); + $text = $this->new_line2html($text); + $text = trim($text); + + if ($do_tidy) + { + $text = $this->tidy($text); + } + + return trim($text); + } + + /** + * Clean up + */ + static function clean_up ($text) + { + $text = trim($text); + $text = str_replace("\r", '', $text); + $text = preg_replace('#[ \t]+$#m', '', $text); // trailing spaces + $text = preg_replace('#\n{3,}#', "\n\n", $text); + return $text; + } + + /** + * Spam filter + */ + static function spam_filter ($text) + { + global $bb_cfg; + static $spam_words = null; + static $spam_replace = ' СПАМ'; + + if (isset($this)) + { + $found_spam =& $this->found_spam; + } + + // set $spam_words and $spam_replace + if (!$bb_cfg['spam_filter_file_path']) + { + return $text; + } + if (is_null($spam_words)) + { + $spam_words = file_get_contents($bb_cfg['spam_filter_file_path']); + $spam_words = strtolower($spam_words); + $spam_words = explode("\n", $spam_words); + } + + $found_spam = array(); + + $tm_start = utime(); + + $msg_decoded = $text; + $msg_decoded = html_entity_decode($msg_decoded); + $msg_decoded = urldecode($msg_decoded); + $msg_decoded = str_replace('&', ' &', $msg_decoded); + + $msg_search = strtolower($msg_decoded); + + foreach ($spam_words as $spam_str) + { + if (!$spam_str = trim($spam_str)) + { + continue; + } + if (strpos($msg_search, $spam_str) !== false) + { + $found_spam[] = $spam_str; + } + } + if ($found_spam) + { + $spam_exp = array(); + foreach ($found_spam as $keyword) + { + $spam_exp[] = preg_quote($keyword, '/'); + } + $spam_exp = join('|', $spam_exp); + + $text = preg_replace("/($spam_exp)(\S*)/i", $spam_replace, $msg_decoded); + $text = htmlCHR($text, false, ENT_NOQUOTES); +# bb_log(date("H:i:s") ." | ". sprintf('%.4f', (utime() - $tm_start)) ." | ". sprintf('%-6s', strlen($text)) ." | ". join(' ** ', $found_spam) ."\n", 'spam_filter'); + } + + return $text; + } + + /** + * [code] callback + */ + function code_callback ($m) + { + $code = trim($m[2]); + $code = str_replace(' ', '  ', $code); + $code = str_replace(' ', '  ', $code); + $code = str_replace("\t", '  ', $code); + $code = str_replace(array('[', ']', ':', ')'), array('[', ']', ':', ')'), $code); + return $this->tpl['code_open'] . $code . $this->tpl['code_close']; + } + + /** + * Escape tags inside tiltes in [quote="tilte"] + */ + function escape_tiltes_callback ($m) + { + $tilte = substr($m[3], 0, 250); + $tilte = str_replace(array('[', ']', ':', ')', '"'), array('[', ']', ':', ')', '"'), $tilte); + // еще раз htmlspecialchars, т.к. при извлечении из title происходит обратное преобразование + $tilte = htmlspecialchars($tilte, ENT_QUOTES); + return $m[1] . $tilte . $m[4]; + } + + /** + * make_clickable + */ + function make_clickable ($text) + { + global $bb_cfg; + + $url_regexp = "# + (? $max_len) ? substr($href, 0, $max_len - 19) .'...'. substr($href, -16) : $href; + + return "$name"; + } + + /** + * smilies_pass + */ + function smilies_pass ($text) + { + global $datastore; + + if (is_null($this->smilies)) + { + $this->smilies = $datastore->get('smile_replacements'); + } + if ($this->smilies) + { + $parsed_text = preg_replace($this->smilies['orig'], $this->smilies['repl'], $text, 101, $smilies_cnt); + $text = ($smilies_cnt <= 100) ? $parsed_text : $text; + } + + return $text; + } + + /** + * new_line2html + */ + function new_line2html ($text) + { + $text = preg_replace('#\n{2,}#', '
    ', $text); + $text = str_replace("\n", '
    ', $text); + return $text; + } + + /** + * tidy + */ + function tidy ($text) + { + $text = tidy_repair_string($text, $this->tidy_cfg, 'raw'); + return $text; + } +} + +function bbcode2html ($text) +{ + global $bbcode; + + if (!isset($bbcode)) + { + $bbcode = new bbcode(); + } + return $bbcode->bbcode2html($text); +} + +function strip_bbcode_uid ($text, $bbcode_uid) +{ + $text = str_replace('[tab]', ' ', $text); + $text = str_replace('"', '"', $text); + $text = str_replace('code:1:', 'code:', $text); + $text = str_replace('list:u:', 'list:', $text); + $text = str_replace('list:o:', 'list:', $text); + $text = str_replace(":$bbcode_uid", '', $text); + return $text; +} + +class words_rate +{ + var $dbg_mode = false; + var $words_rate = 0; + var $deleted_words = array(); + var $del_text_hl = ''; + var $words_del_exp = ''; + var $words_cnt_exp = '#[a-zA-Zа-яА-ЯёЁ]{4,}#'; + + function words_rate () + { + // слова начинающиеся на.. + $del_list = file_get_contents(BB_ROOT .'/misc/words_rate_del_list.txt'); + $del_list = str_compact($del_list); + $del_list = str_replace(' ', '|', preg_quote($del_list, '/')); + $del_exp = '/\b('.$del_list.')[\w\-]*/i'; + + $this->words_del_exp = $del_exp; + } + + /** + * возвращает "показатель полезности" сообщения используемый для автоудаления коротких сообщений типа "спасибо", "круто" и т.д. + */ + function get_words_rate ($text) + { + $this->words_rate = 127; // максимальное значение по умолчанию + $this->deleted_words = array(); + $this->del_text_hl = $text; + + // длинное сообщение + if (strlen($text) > 600) + { + return $this->words_rate; + } + // вырезаем цитаты если содержит +1 + if (preg_match('#\+\d+#', $text)) + { + $text = strip_quotes($text); + } + // содержит ссылку + if (strpos($text, '://')) + { + return $this->words_rate; + } + // вопрос + if ($questions = preg_match_all('#\w\?+#', $text, $m)) + { + if ($questions >= 1) + { + return $this->words_rate; + } + } + + if ($this->dbg_mode) + { + preg_match_all($this->words_del_exp, $text, $this->deleted_words); + $text_dbg = preg_replace($this->words_del_exp, '$0', $text); + $this->del_text_hl = '
    '. $text_dbg . '
    '; + } + $text = preg_replace($this->words_del_exp, '', $text); + + // удаление смайлов + $text = preg_replace('#:\w+:#', '', $text); + // удаление bbcode тегов + $text = preg_replace('#\[\S+\]#', '', $text); + + $words_count = preg_match_all($this->words_cnt_exp, $text, $m); + + if ($words_count !== false && $words_count < 127) + { + $this->words_rate = ($words_count == 0) ? 1 : $words_count; + } + + return $this->words_rate; + } +} + +function get_words_rate ($text) +{ + static $wr = null; + if (!isset($wr)) + { + $wr = new words_rate(); + } + return $wr->get_words_rate($text); +} + +function hide_passkey ($str) +{ + global $bb_cfg; + return preg_replace("#\?{$bb_cfg['passkey_key']}=[a-zA-Z0-9]{". BT_AUTH_KEY_LENGTH ."}#", "?{$bb_cfg['passkey_key']}=passkey", $str); +} + +function get_parsed_post ($postrow, $mode = 'full', $return_chars = 600) +{ + global $bb_cfg; + + if ($bb_cfg['use_posts_cache'] && !empty($postrow['post_html'])) + { + return $postrow['post_html']; + } + + $message = bbcode2html($postrow['post_text']); + + // Posts cache + if ($bb_cfg['use_posts_cache']) + { + DB()->shutdown['post_html'][] = array( + 'post_id' => (int) $postrow['post_id'], + 'post_html' => (string) $message, + ); + } + + return $message; +} + +function update_post_html ($postrow) +{ + DB()->query("DELETE FROM ". BB_POSTS_HTML ." WHERE post_id = ". (int) $postrow['post_id'] ." LIMIT 1"); +} diff --git a/upload/includes/captcha/captcha.php b/upload/includes/captcha/captcha.php new file mode 100644 index 000000000..41f6b68c2 --- /dev/null +++ b/upload/includes/captcha/captcha.php @@ -0,0 +1,394 @@ +cfg = $cfg; + $this->can_bypass = !empty($_POST[$this->cfg['secret_key']]); + $this->curr_code_key = $this->get_key_name(TIMENOW); + $this->prev_code_key = $this->get_key_name(TIMENOW - $this->key_ttl); + } + + function verify_code () + { + // + if ($this->can_bypass || $this->cfg['disabled']) + { + if (!empty($_POST[$this->cfg['secret_key']])) log_get('cap/off', @$_POST['login_username']); + return true; + } + // cap_sid + if (isset($_POST[$this->cap_sid_key]) && verify_id($_POST[$this->cap_sid_key], $this->cap_sid_len)) + { + $this->cap_sid_val = $_POST[$this->cap_sid_key]; + } + else + { + return false; + } + // code + $entered_code = ''; + if (isset($_POST[$this->curr_code_key])) + { + $entered_code = (string) $_POST[$this->curr_code_key]; + } + else if (isset($_POST[$this->prev_code_key])) + { + $entered_code = (string) $_POST[$this->prev_code_key]; + } + + $entered_code = strtolower(trim($entered_code)); + + $valid_code = $this->get_code(); + + if ($entered_code === $valid_code) + { + $this->del_sid(); + return true; + } + else + { + $this->del_sid(); + return false; + } + } + + function get_html () + { + if ($this->cfg['disabled']) return ''; + + $this->gen_cap_sid(); + $this->new_img_path = $this->get_img_path($this->new_cap_id); + $this->new_code_key = $this->get_key_name(TIMENOW); + + return ' +
    pic
    +
    + + +
    + '; + } + + function get_code () + { + if ($this->cap_sid_val AND $code = CACHE('bb_cap_sid')->get('c_sid_'. $this->cap_sid_val)) + { + return strtolower(trim($code)); + } + else + { + return null; + } + } + + function del_sid () + { + if ($this->cap_sid_val) + { + CACHE('bb_cap_sid')->rm('c_sid_'. $this->cap_sid_val); + } + } + + function gen_cap_sid () + { + $row = DB()->fetch_row("SELECT MIN(cap_id) AS min_id, MAX(cap_id) AS max_id FROM ". BB_CAPTCHA ." WHERE cap_id > 0"); + + $min_id = intval($row['min_id']) + $this->new_per_minute; + $max_id = intval($row['max_id']); + + $this->new_cap_id = ($min_id < $max_id) ? mt_rand($min_id, $max_id) : $max_id; + + $this->new_cap_code = (string) DB()->fetch_row("SELECT cap_code FROM ". BB_CAPTCHA ." WHERE cap_id = {$this->new_cap_id}", 'cap_code'); + + $this->new_cap_sid = make_rand_str($this->cap_sid_len); + + CACHE('bb_cap_sid')->set('c_sid_'. $this->new_cap_sid, $this->new_cap_code, $this->key_ttl*2); + } + + function get_img_path ($id) + { + return $this->get_path($id, $this->cfg['img_path']); + } + + function get_path ($id, $base) + { + $path = $base . ($id % 50) .'/'. $id .'.'. $this->img_ext; + return preg_replace("#/($id)(\.{$this->img_ext})\$#", '/'. md5($this->cfg['secret_key'] . md5($id)) .'$2', $path); + } + + /** + * $_POST + */ + function get_key_name ($tm) + { + return 'cap_code_'. md5($this->cfg['secret_key'] . md5($tm - ($tm % $this->key_ttl))); + } +} + +class captcha_kcaptcha extends captcha_common +{ + // generates keystring and image + function gen_img ($cap_id) + { + // do not change without changing font files! + $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"; + + # symbols used to draw CAPTCHA - alphabet without similar symbols (o=0, 1=l, i=j, t=f) + $allowed_symbols = "23456789abcdeghkmnpqsuvxyz"; + + # folder with fonts + $fontsdir = INC_DIR .'captcha/kcaptcha/fonts/'; + + $fonts = array( + 'antiqua.png', + 'baskerville.png', + 'batang.png', + 'bookman.png', + 'calisto.png', + 'cambria.png', + 'centaur.png', + 'century.png', + 'chaparral.png', + 'constantia.png', + 'footlight.png', + 'garamond.png', + 'georgia.png', + 'goudy_old.png', + 'kozuka.png', + 'lucida.png', + 'minion.png', + 'palatino.png', + 'perpetua.png', + 'rockwell.png', + 'times.png', + 'warnock.png', + ); + + # CAPTCHA string length + $length = mt_rand($this->cap_min_chars, $this->cap_max_chars); + + # CAPTCHA image size (you do not need to change it, whis parameters is optimal) + $width = 120; + $height = 60; + + # symbol's vertical fluctuation amplitude divided by 2 + $fluctuation_amplitude = 5; + + # increase safety by prevention of spaces between symbols + $no_spaces = true; + + # show credits + $show_credits = true; # set to false to remove credits line. Credits adds 12 pixels to image height + $credits = $this->cfg['name']; # if empty, HTTP_HOST will be shown + + # CAPTCHA image colors (RGB, 0-255) + //$foreground_color = array(0, 0, 0); + //$background_color = array(220, 230, 255); + $foreground_color = array(mt_rand(0,100), mt_rand(0,100), mt_rand(0,100)); + $background_color = array(mt_rand(200,255), mt_rand(200,255), mt_rand(200,255)); + + # JPEG quality of CAPTCHA image (bigger is better quality, but larger file size) + $jpeg_quality = 90; + + $alphabet_length=strlen($alphabet); + + do{ + // generating random keystring + while(true){ + $this->keystring=''; + for($i=0;$i<$length;$i++){ + $this->keystring.=$allowed_symbols[mt_rand(0,strlen($allowed_symbols)-1)]; + } + if(!preg_match('/cp|cb|ck|c6|c9|rn|rm|mm|co|do|cl|db|qp|qb|dp|ww/', $this->keystring)) break; + } + + $font_file = $fontsdir . $fonts[mt_rand(0, count($fonts)-1)]; + $font=imagecreatefrompng($font_file); + imagealphablending($font, true); + $fontfile_width=imagesx($font); + $fontfile_height=imagesy($font)-1; + $font_metrics=array(); + $symbol=0; + $reading_symbol=false; + + // loading font + for($i=0;$i<$fontfile_width && $symbol<$alphabet_length;$i++){ + $transparent = (imagecolorat($font, $i, 0) >> 24) == 127; + + if(!$reading_symbol && !$transparent){ + $font_metrics[$alphabet[$symbol]]=array('start'=>$i); + $reading_symbol=true; + continue; + } + + if($reading_symbol && $transparent){ + $font_metrics[$alphabet[$symbol]]['end']=$i; + $reading_symbol=false; + $symbol++; + continue; + } + } + + $img=imagecreatetruecolor($width, $height); + imagealphablending($img, true); + $white=imagecolorallocate($img, 255, 255, 255); + $black=imagecolorallocate($img, 0, 0, 0); + + imagefilledrectangle($img, 0, 0, $width-1, $height-1, $white); + + // draw text + $x=1; + for($i=0;$i<$length;$i++){ + $m=$font_metrics[$this->keystring[$i]]; + + $y=mt_rand(-$fluctuation_amplitude, $fluctuation_amplitude)+($height-$fontfile_height)/2+2; + + if($no_spaces){ + $shift=0; + if($i>0){ + $shift=10000; + for($sy=7;$sy<$fontfile_height-20;$sy+=1){ + for($sx=$m['start']-1;$sx<$m['end'];$sx+=1){ + $rgb=imagecolorat($font, $sx, $sy); + $opacity=$rgb>>24; + if($opacity<127){ + $left=$sx-$m['start']+$x; + $py=$sy+$y; + if($py>$height) break; + for($px=min($left,$width-1);$px>$left-12 && $px>=0;$px-=1){ + $color=imagecolorat($img, $px, $py) & 0xff; + if($color+$opacity<190){ + if($shift>$left-$px){ + $shift=$left-$px; + } + break; + } + } + break; + } + } + } + if($shift==10000){ + $shift=mt_rand(4,6); + } + + } + }else{ + $shift=1; + } + imagecopy($img, $font, $x-$shift, $y, $m['start'], 1, $m['end']-$m['start'], $fontfile_height); + $x+=$m['end']-$m['start']-$shift; + } + }while($x>=$width-10); // while not fit in canvas + + $center=$x/2; + + // credits. To remove, see configuration file + $img2=imagecreatetruecolor($width, $height+($show_credits?12:0)); + $foreground=imagecolorallocate($img2, $foreground_color[0], $foreground_color[1], $foreground_color[2]); + $background=imagecolorallocate($img2, $background_color[0], $background_color[1], $background_color[2]); + imagefilledrectangle($img2, 0, 0, $width-1, $height-1, $background); + imagefilledrectangle($img2, 0, $height, $width-1, $height+12, $foreground); + $credits=empty($credits)?$this->cfg['name']:$credits; + imagestring($img2, 2, $width/2-imagefontwidth(2)*strlen($credits)/2, $height-2, $credits, $background); + + // periods + $rand1=mt_rand(750000,1200000)/10000000; + $rand2=mt_rand(750000,1200000)/10000000; + $rand3=mt_rand(750000,1200000)/10000000; + $rand4=mt_rand(750000,1200000)/10000000; + // phases + $rand5=mt_rand(0,31415926)/10000000; + $rand6=mt_rand(0,31415926)/10000000; + $rand7=mt_rand(0,31415926)/10000000; + $rand8=mt_rand(0,31415926)/10000000; + // amplitudes + $rand9=mt_rand(330,420)/110; + $rand10=mt_rand(330,450)/110; + + //wave distortion + + for($x=0;$x<$width;$x++){ + for($y=0;$y<$height;$y++){ + $sx=$x+(sin($x*$rand1+$rand5)+sin($y*$rand3+$rand6))*$rand9-$width/2+$center+1; + $sy=$y+(sin($x*$rand2+$rand7)+sin($y*$rand4+$rand8))*$rand10; + + if($sx<0 || $sy<0 || $sx>=$width-1 || $sy>=$height-1){ + continue; + }else{ + $color=imagecolorat($img, $sx, $sy) & 0xFF; + $color_x=imagecolorat($img, $sx+1, $sy) & 0xFF; + $color_y=imagecolorat($img, $sx, $sy+1) & 0xFF; + $color_xy=imagecolorat($img, $sx+1, $sy+1) & 0xFF; + } + + if($color==255 && $color_x==255 && $color_y==255 && $color_xy==255){ + continue; + }else if($color==0 && $color_x==0 && $color_y==0 && $color_xy==0){ + $newred=$foreground_color[0]; + $newgreen=$foreground_color[1]; + $newblue=$foreground_color[2]; + }else{ + $frsx=$sx-floor($sx); + $frsy=$sy-floor($sy); + $frsx1=1-$frsx; + $frsy1=1-$frsy; + + $newcolor=( + $color*$frsx1*$frsy1+ + $color_x*$frsx*$frsy1+ + $color_y*$frsx1*$frsy+ + $color_xy*$frsx*$frsy); + + if($newcolor>255) $newcolor=255; + $newcolor=$newcolor/255; + $newcolor0=1-$newcolor; + + $newred=$newcolor0*$foreground_color[0]+$newcolor*$background_color[0]; + $newgreen=$newcolor0*$foreground_color[1]+$newcolor*$background_color[1]; + $newblue=$newcolor0*$foreground_color[2]+$newcolor*$background_color[2]; + } + + imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newred, $newgreen, $newblue)); + } + } + + $img_path = $this->get_img_path($cap_id); + file_write('', $img_path, null, true, true); + + imagejpeg($img2, $img_path, $jpeg_quality); +# imagegif($img2, $img_path); +# imagepng($img2, $img_path); + + imagedestroy($img2); + + return $this->keystring; + } +} diff --git a/upload/includes/captcha/kcaptcha/fonts/Thumbs.db b/upload/includes/captcha/kcaptcha/fonts/Thumbs.db new file mode 100644 index 000000000..b182afbe2 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/Thumbs.db differ diff --git a/upload/includes/captcha/kcaptcha/fonts/antiqua.png b/upload/includes/captcha/kcaptcha/fonts/antiqua.png new file mode 100644 index 000000000..78d93d597 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/antiqua.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/baskerville.png b/upload/includes/captcha/kcaptcha/fonts/baskerville.png new file mode 100644 index 000000000..5a635287d Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/baskerville.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/batang.png b/upload/includes/captcha/kcaptcha/fonts/batang.png new file mode 100644 index 000000000..ba0075634 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/batang.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/bookman.png b/upload/includes/captcha/kcaptcha/fonts/bookman.png new file mode 100644 index 000000000..1132a122a Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/bookman.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/calisto.png b/upload/includes/captcha/kcaptcha/fonts/calisto.png new file mode 100644 index 000000000..b3b0dd560 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/calisto.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/cambria.png b/upload/includes/captcha/kcaptcha/fonts/cambria.png new file mode 100644 index 000000000..76ad92107 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/cambria.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/centaur.png b/upload/includes/captcha/kcaptcha/fonts/centaur.png new file mode 100644 index 000000000..30a46cadd Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/centaur.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/century.png b/upload/includes/captcha/kcaptcha/fonts/century.png new file mode 100644 index 000000000..abf89d7e2 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/century.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/chaparral.png b/upload/includes/captcha/kcaptcha/fonts/chaparral.png new file mode 100644 index 000000000..7395bacdb Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/chaparral.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/constantia.png b/upload/includes/captcha/kcaptcha/fonts/constantia.png new file mode 100644 index 000000000..d3abc6464 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/constantia.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/footlight.png b/upload/includes/captcha/kcaptcha/fonts/footlight.png new file mode 100644 index 000000000..cb2a634ec Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/footlight.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/garamond.png b/upload/includes/captcha/kcaptcha/fonts/garamond.png new file mode 100644 index 000000000..eb7222123 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/garamond.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/georgia.png b/upload/includes/captcha/kcaptcha/fonts/georgia.png new file mode 100644 index 000000000..d00bb75e4 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/georgia.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/goudy_old.png b/upload/includes/captcha/kcaptcha/fonts/goudy_old.png new file mode 100644 index 000000000..b4d236d9a Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/goudy_old.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/kozuka.png b/upload/includes/captcha/kcaptcha/fonts/kozuka.png new file mode 100644 index 000000000..ececa1104 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/kozuka.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/lucida.png b/upload/includes/captcha/kcaptcha/fonts/lucida.png new file mode 100644 index 000000000..050732aa7 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/lucida.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/minion.png b/upload/includes/captcha/kcaptcha/fonts/minion.png new file mode 100644 index 000000000..34384e51a Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/minion.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/palatino.png b/upload/includes/captcha/kcaptcha/fonts/palatino.png new file mode 100644 index 000000000..3a9d37b24 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/palatino.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/perpetua.png b/upload/includes/captcha/kcaptcha/fonts/perpetua.png new file mode 100644 index 000000000..8b4c0871a Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/perpetua.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/rockwell.png b/upload/includes/captcha/kcaptcha/fonts/rockwell.png new file mode 100644 index 000000000..da19566d1 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/rockwell.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/times.png b/upload/includes/captcha/kcaptcha/fonts/times.png new file mode 100644 index 000000000..656e99d97 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/times.png differ diff --git a/upload/includes/captcha/kcaptcha/fonts/warnock.png b/upload/includes/captcha/kcaptcha/fonts/warnock.png new file mode 100644 index 000000000..c114dbcb9 Binary files /dev/null and b/upload/includes/captcha/kcaptcha/fonts/warnock.png differ diff --git a/upload/includes/cron/.htaccess b/upload/includes/cron/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/cron/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/cron/cron_check.php b/upload/includes/cron/cron_check.php new file mode 100644 index 000000000..012a0b30f --- /dev/null +++ b/upload/includes/cron/cron_check.php @@ -0,0 +1,38 @@ +fetch_rowset(" + SELECT * FROM ". BB_CRON ." + WHERE cron_active = 1 + AND next_run <= NOW() + ORDER BY run_order +"); + +// Run cron jobs +if ($cron_jobs) +{ + bb_log(date('H:i:s - ') . getmypid() .' --x- RUN jobs'. LOG_LF, CRON_LOG_DIR .'cron_check'); + + foreach ($cron_jobs as $job) + { + if ($job['disable_board']) + { + cron_disable_board(); + sleep(10); + break; + } + } + + require(CRON_DIR .'cron_run.php'); + + // Update cron_last_check + bb_update_config(array('cron_last_check' => (time() + 10))); +} +else +{ + bb_log(date('H:i:s - ') . getmypid() .' --x- no active jobs found ----------------------------------------------'. LOG_LF, CRON_LOG_DIR .'cron_check'); +} \ No newline at end of file diff --git a/upload/includes/cron/cron_init.php b/upload/includes/cron/cron_init.php new file mode 100644 index 000000000..330b6e227 --- /dev/null +++ b/upload/includes/cron/cron_init.php @@ -0,0 +1,62 @@ +query(" + SET SESSION + myisam_sort_buffer_size = 16*1024*1024 + , bulk_insert_buffer_size = 8*1024*1024 + , join_buffer_size = 4*1024*1024 + , read_buffer_size = 4*1024*1024 + , read_rnd_buffer_size = 8*1024*1024 + , sort_buffer_size = 4*1024*1024 + , tmp_table_size = 80*1024*1024 + , group_concat_max_len = 1*1024*1024 +"); + +// Restore vars at shutdown +DB()->add_shutdown_query(" + SET SESSION + myisam_sort_buffer_size = DEFAULT + , bulk_insert_buffer_size = DEFAULT + , join_buffer_size = DEFAULT + , read_buffer_size = DEFAULT + , read_rnd_buffer_size = DEFAULT + , sort_buffer_size = DEFAULT + , tmp_table_size = DEFAULT + , group_concat_max_len = DEFAULT +"); + +// $cron_jobs obtained in cron_check.php +foreach ($cron_jobs as $job) +{ + $job_script = CRON_JOB_DIR . basename($job['cron_script']); + + if (file_exists($job_script)) + { + $cron_start_time = utime(); + $cron_runtime_log = ''; + $cron_write_log = (CRON_LOG_ENABLED && (CRON_FORCE_LOG || $job['log_enabled'] >= 1)); + $cron_sql_log_file = CRON_LOG_DIR .'SQL-'. basename($job['cron_script']); + + if ($cron_write_log) + { + $msg = array(); + $msg[] = 'start'; + $msg[] = date('m-d'); + $msg[] = date('H:i:s'); + $msg[] = sprintf('%-4s', round(get_loadavg(), 1)); + $msg[] = sprintf('%05d', getmypid()); + $msg[] = $job['cron_title']; + $msg = join(LOG_SEPR, $msg); + bb_log($msg . LOG_LF, CRON_LOG_DIR . CRON_LOG_FILE); + } + + if ($job['log_sql_queries']) + { + DB()->log_next_query(100000, $cron_sql_log_file); + } + + @set_time_limit(600); + require($job_script); + + if ($job['log_sql_queries']) + { + DB()->log_next_query(0); + bb_log(LOG_LF, $cron_sql_log_file); + } + + if ($cron_write_log) + { + $msg = array(); + $msg[] = ' end'; + $msg[] = date('m-d'); + $msg[] = date('H:i:s'); + $msg[] = sprintf('%-4s', round(get_loadavg(), 1)); + $msg[] = sprintf('%05d', getmypid()); + $msg[] = round(utime() - $cron_start_time) .'/'. round(utime() - TIMESTART) . ' sec'; + $msg = join(LOG_SEPR, $msg); + $msg .= LOG_LF .'------=-------=----------=------=-------=----------'; + bb_log($msg . LOG_LF, CRON_LOG_DIR . CRON_LOG_FILE); + + if ($cron_runtime_log) + { + $runtime_log_file = ($job['log_file']) ? $job['log_file'] : $job['cron_script']; + bb_log($cron_runtime_log . LOG_LF, CRON_LOG_DIR . basename($runtime_log_file)); + } + } + + DB()->query(" + UPDATE ". BB_CRON ." SET + last_run = NOW(), + run_counter = run_counter + 1, + next_run = + CASE + WHEN schedule = 'hourly' THEN + DATE_ADD(NOW(), INTERVAL 1 HOUR) + WHEN schedule = 'daily' THEN + DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 1 DAY), INTERVAL TIME_TO_SEC(run_time) SECOND) + WHEN schedule = 'weekly' THEN + DATE_ADD( + DATE_ADD(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(NOW()) DAY), INTERVAL 7 DAY), + INTERVAL CONCAT(ROUND(run_day-1), ' ', run_time) DAY_SECOND) + WHEN schedule = 'monthly' THEN + DATE_ADD( + DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFMONTH(NOW())-1 DAY), INTERVAL 1 MONTH), + INTERVAL CONCAT(ROUND(run_day-1), ' ', run_time) DAY_SECOND) + ELSE + DATE_ADD(NOW(), INTERVAL TIME_TO_SEC(run_interval) SECOND) + END + WHERE cron_id = {$job['cron_id']} + LIMIT 1 + "); + + sleep(3); + } + else + { + $cron_err_msg = "Can't run \"{$job['cron_title']}\" : file \"$job_script\" not found". LOG_LF; + bb_log($cron_err_msg, 'cron_error'); + } +} \ No newline at end of file diff --git a/upload/includes/cron/jobs/.htaccess b/upload/includes/cron/jobs/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/cron/jobs/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/cron/jobs/avatars_cleanup.php b/upload/includes/cron/jobs/avatars_cleanup.php new file mode 100644 index 000000000..7739196dc --- /dev/null +++ b/upload/includes/cron/jobs/avatars_cleanup.php @@ -0,0 +1,117 @@ +query(" + CREATE TEMPORARY TABLE $tmp_tbl ( + user_avatar VARCHAR(255) NOT NULL default '', + KEY user_avatar (user_avatar(20)) + ) ENGINE = MyISAM DEFAULT CHARSET=".DBCHARSET." +"); + +DB()->query("ALTER TABLE ". BB_USERS ." ADD INDEX user_avatar(user_avatar(10))"); + +$avatars_dir = BB_ROOT . $bb_cfg['avatar_path']; + +// Get all names of existed avatars and insert them into $tmp_tbl +if ($dir = @opendir($avatars_dir)) +{ + $check_avatars = true; + $files = array(); + $f_len = 0; + + while (false !== ($f = readdir($dir))) + { + if ($f == 'index.php' || $f == '.htaccess' || is_dir("$avatars_dir/$f") || is_link("$avatars_dir/$f")) + { + continue; + } + $f = DB()->escape($f); + $files[] = "('$f')"; + $f_len += strlen($f) + 5; + + if ($f_len > $db_max_packet) + { + $files = join(',', $files); + DB()->query("INSERT INTO $tmp_tbl VALUES $files"); + $files = array(); + $f_len = 0; + } + } + if ($files = join(',', $files)) + { + DB()->query("INSERT INTO $tmp_tbl VALUES $files"); + } + closedir($dir); +} + +if ($check_avatars) +{ + // Delete avatars that exist in file system but not exist in DB + $sql = "SELECT f.user_avatar + FROM $tmp_tbl f + LEFT JOIN ". BB_USERS ." u USING(user_avatar) + WHERE u.user_avatar IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + if ($filename = basename($row['user_avatar'])) + { + if ($fix_errors) + { + @unlink("$avatars_dir/$filename"); + } + if ($debug_mode) + { + $orphan_files[] = "$avatars_dir/$filename"; + } + } + } + // Find DB records for avatars that exist in DB but not exist in file system + $sql = "SELECT u.user_id + FROM ". BB_USERS ." u + LEFT JOIN $tmp_tbl f USING(user_avatar) + WHERE u.user_avatar_type = ". USER_AVATAR_UPLOAD ." + AND f.user_avatar IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $orphan_db_avatars[] = $row['user_id']; + } + // Delete all orphan avatars from DB + if ($orphans_sql = join(',', $orphan_db_avatars)) + { + if ($fix_errors) + { + DB()->query(" + UPDATE ". BB_USERS ." SET + user_avatar = '', + user_avatar_type = ". USER_AVATAR_NONE ." + WHERE user_id IN($orphans_sql) + "); + } + } +} + +if ($debug_mode) +{ + prn_r($orphan_files, '$orphan_files'); + prn_r($orphan_db_avatars, '$orphan_db_avatars'); +} + +DB()->query("DROP TEMPORARY TABLE $tmp_tbl"); +DB()->query("ALTER TABLE ". BB_USERS ." DROP INDEX user_avatar"); + +unset($fix_errors, $debug_mode); \ No newline at end of file diff --git a/upload/includes/cron/jobs/bb_maintenance.php b/upload/includes/cron/jobs/bb_maintenance.php new file mode 100644 index 000000000..e53a8dd31 --- /dev/null +++ b/upload/includes/cron/jobs/bb_maintenance.php @@ -0,0 +1,261 @@ +query(" + CREATE TEMPORARY TABLE $tmp_attach_tbl ( + physical_filename VARCHAR(255) NOT NULL default '', + KEY physical_filename (physical_filename(20)) + ) ENGINE = MyISAM DEFAULT CHARSET=".DBCHARSET." +"); + +// Get attach_mod config +$attach_dir = get_attachments_dir(); + +// Get all names of existed attachments and insert them into $tmp_attach_tbl +if ($dir = @opendir($attach_dir)) +{ + $check_attachments = true; + $files = array(); + $f_len = 0; + + while (false !== ($f = readdir($dir))) + { + if ($f == 'index.php' || $f == '.htaccess' || is_dir("$attach_dir/$f") || is_link("$attach_dir/$f")) + { + continue; + } + $f = DB()->escape($f); + $files[] = "('$f')"; + $f_len += strlen($f) + 5; + + if ($f_len > $db_max_packet) + { + $files = join(',', $files); + DB()->query("INSERT INTO $tmp_attach_tbl VALUES $files"); + $files = array(); + $f_len = 0; + } + } + if ($files = join(',', $files)) + { + DB()->query("INSERT INTO $tmp_attach_tbl VALUES $files"); + } + closedir($dir); +} + +// Lock tables +# $lock = DB()->lock($lock_tables); + +if ($check_attachments) +{ + // Delete bad records + DB()->query(" + DELETE a, d + FROM ". BB_ATTACHMENTS_DESC ." d + LEFT JOIN ". BB_ATTACHMENTS ." a USING(attach_id) + WHERE ( + d.physical_filename = '' + OR d.real_filename = '' + OR d.extension = '' + OR d.mimetype = '' + OR d.filesize = 0 + OR d.filetime = 0 + OR a.post_id = 0 + ) + "); + + // Delete attachments that exist in file system but not exist in DB + $sql = "SELECT f.physical_filename + FROM $tmp_attach_tbl f + LEFT JOIN ". BB_ATTACHMENTS_DESC ." d USING(physical_filename) + WHERE d.physical_filename IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + if ($filename = basename($row['physical_filename'])) + { + if ($fix_errors) + { + @unlink("$attach_dir/$filename"); + @unlink("$attach_dir/". THUMB_DIR .'/t_'. $filename); + } + if ($debug_mode) + { + $orphan_files[] = "$attach_dir/$filename"; + } + } + } + // Find DB records for attachments that exist in DB but not exist in file system + $sql = "SELECT d.attach_id + FROM ". BB_ATTACHMENTS_DESC ." d + LEFT JOIN $tmp_attach_tbl f USING(physical_filename) + WHERE f.physical_filename IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $orphan_db_attach[] = $row['attach_id']; + } + // Attachment exist in DESC_TABLE but not exist in ATTACH_TABLE + $sql = "SELECT d.attach_id + FROM ". BB_ATTACHMENTS_DESC ." d + LEFT JOIN ". BB_ATTACHMENTS ." a USING(attach_id) + WHERE a.attach_id IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $orphan_db_attach[] = $row['attach_id']; + } + // Attachment exist in ATTACH_TABLE but not exist in DESC_TABLE + $sql = "SELECT a.attach_id + FROM ". BB_ATTACHMENTS ." a + LEFT JOIN ". BB_ATTACHMENTS_DESC ." d USING(attach_id) + WHERE d.attach_id IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $orphan_db_attach[] = $row['attach_id']; + } + // Attachments without post + $sql = "SELECT a.attach_id + FROM ". BB_ATTACHMENTS ." a + LEFT JOIN ". BB_POSTS ." p USING(post_id) + WHERE p.post_id IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $orphan_db_attach[] = $row['attach_id']; + } + // Delete all orphan attachments + if ($orphans_sql = join(',', $orphan_db_attach)) + { + if ($fix_errors) + { + DB()->query("DELETE FROM ". BB_ATTACHMENTS_DESC ." WHERE attach_id IN($orphans_sql)"); + DB()->query("DELETE FROM ". BB_ATTACHMENTS ." WHERE attach_id IN($orphans_sql)"); + } + } + + // Torrents without attachments + $sql = "SELECT tor.topic_id + FROM ". BB_BT_TORRENTS ." tor + LEFT JOIN ". BB_ATTACHMENTS_DESC ." d USING(attach_id) + WHERE d.attach_id IS NULL + LIMIT $sql_limit"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $orphan_tor[] = $row['topic_id']; + } + // Delete all orphan torrents + if ($orphans_sql = join(',', $orphan_tor)) + { + if ($fix_errors) + { + DB()->query("DELETE FROM ". BB_BT_TORRENTS ." WHERE topic_id IN($orphans_sql)"); + } + } + + // Check post_attachment markers + $sql = "SELECT p.post_id + FROM ". BB_POSTS ." p + LEFT JOIN ". BB_ATTACHMENTS ." a USING(post_id) + WHERE p.post_attachment = 1 + AND a.post_id IS NULL"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $posts_without_attach[] = $row['post_id']; + } + if ($posts_sql = join(',', $posts_without_attach)) + { + if ($fix_errors) + { + DB()->query("UPDATE ". BB_POSTS ." SET post_attachment = 0 WHERE post_id IN($posts_sql)"); + } + } + // Check topic_attachment markers + $sql = "SELECT t.topic_id + FROM ". BB_POSTS ." p, ". BB_TOPICS ." t + WHERE t.topic_id = p.topic_id + AND t.topic_attachment = 1 + GROUP BY p.topic_id + HAVING SUM(p.post_attachment) = 0"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $topics_without_attach[] = $row['topic_id']; + } + if ($topics_sql = join(',', $topics_without_attach)) + { + if ($fix_errors) + { + DB()->query("UPDATE ". BB_TOPICS ." SET topic_attachment = 0 WHERE topic_id IN($topics_sql)"); + } + } +} +if ($debug_mode) +{ + prn_r($orphan_files, '$orphan_files'); + prn_r($orphan_db_attach, '$orphan_db_attach'); + prn_r($orphan_tor, '$orphan_tor'); + prn_r($posts_without_attach, '$posts_without_attach'); + prn_r($topics_without_attach, '$topics_without_attach'); +} + +// Unlock tables +# $unlock = DB()->unlock(); + +DB()->query("DROP TEMPORARY TABLE $tmp_attach_tbl"); + +unset($fix_errors, $debug_mode); + +// Sync +require_once(INC_DIR .'functions_admin.php'); +sync('topic', 'all'); +sync('forum', 'all'); +sync('user_posts', 'all'); + +// Clean "user_newpasswd" +DB()->query(" + UPDATE ". BB_USERS ." SET + user_newpasswd = '' + WHERE user_lastvisit < ". (TIMENOW - 7*86400) ." +"); + +// Clean posts cache +if ($posts_days = intval($bb_cfg['posts_cache_days_keep'])) +{ + DB()->query("DELETE FROM ". BB_POSTS_HTML ." WHERE post_html_time < DATE_SUB(NOW(), INTERVAL $posts_days DAY)"); +} diff --git a/upload/includes/cron/jobs/bb_manage_untrusted.php b/upload/includes/cron/jobs/bb_manage_untrusted.php new file mode 100644 index 000000000..98d16e7e2 --- /dev/null +++ b/upload/includes/cron/jobs/bb_manage_untrusted.php @@ -0,0 +1,3 @@ +gc(); + $cron_runtime_log .= date('Y-m-d H:i:s') ." -- tr -- $changes rows deleted\n"; +} +if (method_exists(CACHE('bb_cache'), 'gc')) +{ + $changes = CACHE('bb_cache')->gc(); + $cron_runtime_log .= date('Y-m-d H:i:s') ." -- bb -- $changes rows deleted\n"; +} +if (method_exists(CACHE('session_cache'), 'gc')) +{ + $changes = CACHE('session_cache')->gc(TIMENOW + $bb_cfg['session_cache_gc_ttl']); + $cron_runtime_log .= date('Y-m-d H:i:s') ." -- ss -- $changes rows deleted\n"; +} +if (method_exists(CACHE('bb_login_err'), 'gc')) +{ + $changes = CACHE('bb_login_err')->gc(); + $cron_runtime_log .= date('Y-m-d H:i:s') ." -- ss -- $changes rows deleted\n"; +} diff --git a/upload/includes/cron/jobs/captcha_gen_gc.php b/upload/includes/cron/jobs/captcha_gen_gc.php new file mode 100644 index 000000000..f67abe274 --- /dev/null +++ b/upload/includes/cron/jobs/captcha_gen_gc.php @@ -0,0 +1,60 @@ +cap_img_total; // (cap_id > 0) +$new_per_minute = CAPTCHA()->new_per_minute; // +$cap_expire_time = TIMENOW + CAPTCHA()->key_ttl*2; + +$gen_new_img_count = $new_per_minute; // +$expire_img_count = $new_per_minute; // + +$row = DB()->fetch_row("SELECT COUNT(*) AS cnt, MAX(cap_id) AS max_id FROM ". BB_CAPTCHA ." WHERE cap_id > 0"); + +$cur_total_count = (int) $row['cnt']; +$cur_max_id = (int) $row['max_id']; + +if ($cur_total_count < $cap_img_total) +{ + $gen_new_img_count += ($cap_img_total - $cur_total_count); +} + +$start_id = $cur_max_id + 1; +$cur_id = $start_id; +$finish_id = $start_id + $gen_new_img_count - 1; + +while ($cur_id <= $finish_id) +{ + $code = CAPTCHA()->gen_img($cur_id); + DB()->query("INSERT INTO ". BB_CAPTCHA ." (cap_id, cap_code) VALUES ($cur_id, '$code')"); + $cur_id++; +} + +// +// +// +DB()->query(" + UPDATE ". BB_CAPTCHA ." SET + cap_id = -cap_id, + cap_expire = $cap_expire_time + WHERE cap_id > 0 + ORDER BY cap_id + LIMIT $expire_img_count +"); + +// +// +// +$del_ids = DB()->fetch_rowset("SELECT cap_id FROM ". BB_CAPTCHA ." WHERE cap_id < 0 AND cap_expire < ". TIMENOW, 'cap_id'); + +foreach ($del_ids as $del_id) +{ + $cap_img_path = CAPTCHA()->get_img_path(abs($del_id)); + unlink($cap_img_path); + + DB()->query("DELETE FROM ". BB_CAPTCHA ." WHERE cap_id = $del_id LIMIT 1"); +} + diff --git a/upload/includes/cron/jobs/clean_dlstat.php b/upload/includes/cron/jobs/clean_dlstat.php new file mode 100644 index 000000000..8f7d7419d --- /dev/null +++ b/upload/includes/cron/jobs/clean_dlstat.php @@ -0,0 +1,100 @@ +query(" + CREATE TEMPORARY TABLE ". BUF_DLSTATUS_TABLE ." ( + user_id mediumint(9) NOT NULL default '0', + topic_id mediumint(8) unsigned NOT NULL default '0', + user_status tinyint(1) NOT NULL default '0', + PRIMARY KEY (user_id, topic_id) + ) ENGINE = MyISAM + "); + + DB()->query(" + INSERT INTO ". BUF_DLSTATUS_TABLE ." + (user_id, topic_id, user_status) + SELECT + user_id, topic_id, user_status + FROM + ". BB_BT_DLSTATUS_NEW ." + WHERE + last_modified_dlstatus < DATE_SUB(NOW(), INTERVAL 1 DAY) + "); + + DB()->query(" + REPLACE INTO ". BB_BT_DLSTATUS_MAIN ." + (user_id, topic_id, user_status) + SELECT + user_id, topic_id, user_status + FROM ". BUF_DLSTATUS_TABLE ." + "); + + DB()->query(" + DELETE new + FROM ". BUF_DLSTATUS_TABLE ." buf + INNER JOIN ". BB_BT_DLSTATUS_NEW ." new USING(user_id, topic_id) + "); + + DB()->query("DROP TEMPORARY TABLE ". BUF_DLSTATUS_TABLE); +} + +// Delete staled dl-status records +$keeping_dlstat = array( + DL_STATUS_WILL => (int) $bb_cfg['dl_will_days_keep'], + DL_STATUS_DOWN => (int) $bb_cfg['dl_down_days_keep'], + DL_STATUS_COMPLETE => (int) $bb_cfg['dl_complete_days_keep'], + DL_STATUS_CANCEL => (int) $bb_cfg['dl_cancel_days_keep'], +); + +$delete_dlstat_sql = array(); + +foreach ($keeping_dlstat as $dl_status => $days_to_keep) +{ + if ($days_to_keep) + { + $delete_dlstat_sql[] = " + user_status = $dl_status + AND + last_modified_dlstatus < DATE_SUB(NOW(), INTERVAL $days_to_keep DAY) + "; + } +} + +if ($delete_dlstat_sql = join(') OR (', $delete_dlstat_sql)) +{ + DB()->query("DELETE QUICK FROM ". BB_BT_DLSTATUS ." WHERE ($delete_dlstat_sql)"); +} + +// Delete orphans +DB()->query(" + DELETE QUICK dl + FROM ". BB_BT_DLSTATUS ." dl + LEFT JOIN ". BB_USERS ." u USING(user_id) + WHERE u.user_id IS NULL +"); + +DB()->query(" + DELETE QUICK dl + FROM ". BB_BT_DLSTATUS ." dl + LEFT JOIN ". BB_TOPICS ." t USING(topic_id) + WHERE t.topic_id IS NULL +"); + +// Tor-Stats cleanup +if ($torstat_days_keep = intval($bb_cfg['torstat_days_keep'])) +{ + DB()->query("DELETE QUICK FROM ". BB_BT_TORSTAT ." WHERE last_modified_torstat < DATE_SUB(NOW(), INTERVAL $torstat_days_keep DAY)"); +} + +DB()->query(" + DELETE QUICK tst + FROM ". BB_BT_TORSTAT ." tst + LEFT JOIN ". BB_BT_TORRENTS ." tor USING(topic_id) + WHERE tor.topic_id IS NULL +"); \ No newline at end of file diff --git a/upload/includes/cron/jobs/clean_log.php b/upload/includes/cron/jobs/clean_log.php new file mode 100644 index 000000000..9fb3455e0 --- /dev/null +++ b/upload/includes/cron/jobs/clean_log.php @@ -0,0 +1,10 @@ +query(" + DELETE FROM ". BB_LOG ." + WHERE log_time < ". (TIMENOW - 86400*$log_days_keep) ." +"); \ No newline at end of file diff --git a/upload/includes/cron/jobs/clean_search_results.php b/upload/includes/cron/jobs/clean_search_results.php new file mode 100644 index 000000000..b9957e145 --- /dev/null +++ b/upload/includes/cron/jobs/clean_search_results.php @@ -0,0 +1,10 @@ +query(" + DELETE FROM ". BB_SEARCH ." + WHERE search_time < $search_results_expire +"); \ No newline at end of file diff --git a/upload/includes/cron/jobs/db_backup.php b/upload/includes/cron/jobs/db_backup.php new file mode 100644 index 000000000..d9abb1da4 --- /dev/null +++ b/upload/includes/cron/jobs/db_backup.php @@ -0,0 +1,37 @@ +from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('blank'); + $emailer->email_address($bb_cfg['tech_admin_email']); + $emailer->set_subject("DB Backup failed [{$bb_cfg['server_name']}]"); + + $emailer->assign_vars(array( + 'MESSAGE' => $cron_runtime_log, + )); + $emailer->send(); + $emailer->reset(); +} + +sleep(10); + +DB()->expect_slow_query(16*60, 100); diff --git a/upload/includes/cron/jobs/ds_update_cat_forums.php b/upload/includes/cron/jobs/ds_update_cat_forums.php new file mode 100644 index 000000000..094ffea2b --- /dev/null +++ b/upload/includes/cron/jobs/ds_update_cat_forums.php @@ -0,0 +1,5 @@ +update('cat_forums'); \ No newline at end of file diff --git a/upload/includes/cron/jobs/ds_update_stats.php b/upload/includes/cron/jobs/ds_update_stats.php new file mode 100644 index 000000000..52bd760e4 --- /dev/null +++ b/upload/includes/cron/jobs/ds_update_stats.php @@ -0,0 +1,5 @@ +update('stats'); \ No newline at end of file diff --git a/upload/includes/cron/jobs/flash_topic_view.php b/upload/includes/cron/jobs/flash_topic_view.php new file mode 100644 index 000000000..d06fdb252 --- /dev/null +++ b/upload/includes/cron/jobs/flash_topic_view.php @@ -0,0 +1,26 @@ +lock(array( + BB_TOPICS .' t', + BUF_TOPIC_VIEW .' buf', +)); + +// Flash buffered records +DB()->query(" + UPDATE + ". BB_TOPICS ." t, + ". BUF_TOPIC_VIEW ." buf + SET + t.topic_views = t.topic_views + buf.topic_views + WHERE + t.topic_id = buf.topic_id +"); + +// Delete buffered records +DB()->query("DELETE buf FROM ". BUF_TOPIC_VIEW ." buf"); + +// Unlock tables +DB()->unlock(); \ No newline at end of file diff --git a/upload/includes/cron/jobs/prune_forums.php b/upload/includes/cron/jobs/prune_forums.php new file mode 100644 index 000000000..303b7ff4a --- /dev/null +++ b/upload/includes/cron/jobs/prune_forums.php @@ -0,0 +1,15 @@ +fetch_rowset($sql) as $row) + { + topic_delete('prune', $row['forum_id'], (TIMENOW - 86400*$row['prune_days'])); + } +} \ No newline at end of file diff --git a/upload/includes/cron/jobs/prune_inactive_users.php b/upload/includes/cron/jobs/prune_inactive_users.php new file mode 100644 index 000000000..774e0abed --- /dev/null +++ b/upload/includes/cron/jobs/prune_inactive_users.php @@ -0,0 +1,66 @@ +fetch_rowset($sql) as $row) + { + $not_activated_users[] = $row['user_id']; + } + } + if ($not_active_days = intval($bb_cfg['user_not_active_days_keep'])) + { + $sql = " + SELECT user_id + FROM ". BB_USERS ." + WHERE user_active = 1 + AND user_posts = 0 + AND user_lastvisit < ". (TIMENOW - 86400*$not_active_days) ." + AND user_id NOT IN($excluded_users) + LIMIT $users_per_cycle + "; + foreach (DB()->fetch_rowset($sql) as $row) + { + $not_active_users[] = $row['user_id']; + } + } + + if ($prune_users = $not_activated_users + $not_active_users) + { + user_delete($prune_users); + } + + if (count($prune_users) < $users_per_cycle) + { + break; + } + + sleep(3); +} + +unset($prune_users, $not_activated_users, $not_active_users); diff --git a/upload/includes/cron/jobs/prune_topic_moved.php b/upload/includes/cron/jobs/prune_topic_moved.php new file mode 100644 index 000000000..4624718a2 --- /dev/null +++ b/upload/includes/cron/jobs/prune_topic_moved.php @@ -0,0 +1,14 @@ +query(" + DELETE FROM ". BB_TOPICS ." + WHERE topic_status = ". TOPIC_MOVED ." + AND topic_time < $prune_time + "); +} \ No newline at end of file diff --git a/upload/includes/cron/jobs/sessions_cleanup.php b/upload/includes/cron/jobs/sessions_cleanup.php new file mode 100644 index 000000000..987aa83c2 --- /dev/null +++ b/upload/includes/cron/jobs/sessions_cleanup.php @@ -0,0 +1,47 @@ +lock(array( + BB_USERS .' u', + BB_SESSIONS .' s', +)); + +// Update user's session time +DB()->query(" + UPDATE + ". BB_USERS ." u, + ". BB_SESSIONS ." s + SET + u.user_session_time = IF(u.user_session_time < s.session_time, s.session_time, u.user_session_time) + WHERE + u.user_id = s.session_user_id + AND s.session_user_id != ". ANONYMOUS ." + AND ( + (s.session_time < $user_session_expire_time AND s.session_admin = 0) + OR + (s.session_time < $admin_session_expire_time AND s.session_admin != 0) + ) +"); + +DB()->unlock(); +// ############################ Tables UNLOCKED ############################## + +sleep(5); + +// Delete staled sessions +DB()->query(" + DELETE s + FROM ". BB_SESSIONS ." s + WHERE + (s.session_time < $user_session_gc_time AND s.session_admin = 0) + OR + (s.session_time < $admin_session_gc_time AND s.session_admin != 0) +"); \ No newline at end of file diff --git a/upload/includes/cron/jobs/site_backup.php b/upload/includes/cron/jobs/site_backup.php new file mode 100644 index 000000000..54da83fad --- /dev/null +++ b/upload/includes/cron/jobs/site_backup.php @@ -0,0 +1,33 @@ +from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('blank'); + $emailer->email_address($bb_cfg['tech_admin_email']); + $emailer->set_subject("Site Backup failed [{$bb_cfg['server_name']}]"); + + $emailer->assign_vars(array( + 'MESSAGE' => $cron_runtime_log, + )); + $emailer->send(); + $emailer->reset(); +} + +sleep(10); \ No newline at end of file diff --git a/upload/includes/cron/jobs/tr_cleanup_and_dlstat.php b/upload/includes/cron/jobs/tr_cleanup_and_dlstat.php new file mode 100644 index 000000000..b0fe5cd20 --- /dev/null +++ b/upload/includes/cron/jobs/tr_cleanup_and_dlstat.php @@ -0,0 +1,183 @@ +query("DROP TABLE IF EXISTS ". NEW_BB_BT_LAST_TORSTAT .", ". NEW_BB_BT_LAST_USERSTAT); + DB()->query("DROP TABLE IF EXISTS ". OLD_BB_BT_LAST_TORSTAT .", ". OLD_BB_BT_LAST_USERSTAT); + + DB()->query("CREATE TABLE ". NEW_BB_BT_LAST_TORSTAT ." LIKE ". BB_BT_LAST_TORSTAT); + DB()->query("CREATE TABLE ". NEW_BB_BT_LAST_USERSTAT ." LIKE ". BB_BT_LAST_USERSTAT); + + DB()->expect_slow_query(600); + + // Update dlstat (part 1) + if ($tr_cfg['update_dlstat']) + { + // ############################ Tables LOCKED ################################ + DB()->lock(array( + BB_BT_TRACKER, + NEW_BB_BT_LAST_TORSTAT, + )); + + // Get PER TORRENT user's dlstat from tracker + DB()->query(" + INSERT INTO ". NEW_BB_BT_LAST_TORSTAT ." + (topic_id, user_id, dl_status, up_add, down_add, release_add, speed_up, speed_down) + SELECT + topic_id, user_id, IF(releaser, $releaser, seeder), SUM(up_add), SUM(down_add), IF(releaser, SUM(up_add), 0), SUM(speed_up), SUM(speed_down) + FROM ". BB_BT_TRACKER ." + WHERE (up_add != 0 OR down_add != 0) + GROUP BY topic_id, user_id + "); + + // Reset up/down additions in tracker + DB()->query("UPDATE ". BB_BT_TRACKER ." SET up_add = 0, down_add = 0"); + + DB()->unlock(); + // ############################ Tables UNLOCKED ############################## + } + +} +// Update last seeder info in BUF +DB()->query(" + REPLACE INTO ". BUF_LAST_SEEDER ." + (topic_id, seeder_last_seen) + SELECT + topic_id, ". TIMENOW ." + FROM ". BB_BT_TRACKER ." + WHERE seeder = 1 + GROUP BY topic_id +"); + +// Clean peers table +if ($tr_cfg['autoclean']) +{ + $announce_interval = max(intval($bb_cfg['announce_interval']), 60); + $expire_factor = max(floatval($tr_cfg['expire_factor']), 1); + $peer_expire_time = TIMENOW - floor($announce_interval * $expire_factor); + + DB()->query("DELETE FROM ". BB_BT_TRACKER ." WHERE update_time < $peer_expire_time"); +} + +if($bb_cfg['announce_type'] == 'xbt') +{ + DB()->query(" + INSERT IGNORE INTO ". BB_BT_TORSTAT ." + (topic_id, user_id) + SELECT + topic_id, user_id + FROM ". BB_BT_TRACKER ." + WHERE IF(releaser, $releaser, seeder) = ". DL_STATUS_COMPLETE ." AND (up_add != 0 OR down_add != 0) + "); + // Reset up/down additions in tracker + DB()->query("UPDATE ". BB_BT_TRACKER ." SET up_add = 0, down_add = 0"); +} +// Delete not registered torrents from tracker +/* +DB()->query(" + DELETE tr + FROM ". BB_BT_TRACKER ." tr + LEFT JOIN ". BB_BT_TORRENTS ." tor USING(topic_id) + WHERE tor.topic_id IS NULL +"); +*/ + +if($bb_cfg['announce_type'] != 'xbt') +{ + // Update dlstat (part 2) + if ($tr_cfg['update_dlstat']) + { + // Set "only 1 seeder" bonus + DB()->query(" + UPDATE + ". NEW_BB_BT_LAST_TORSTAT ." tb, + ". BB_BT_TRACKER_SNAP ." sn + SET + tb.bonus_add = tb.up_add + WHERE + tb.topic_id = sn.topic_id + AND sn.seeders = 1 + AND tb.up_add != 0 + AND tb.dl_status = ". DL_STATUS_COMPLETE ." + "); + + // Get SUMMARIZED user's dlstat + DB()->query(" + INSERT INTO ". NEW_BB_BT_LAST_USERSTAT ." + (user_id, up_add, down_add, release_add, bonus_add, speed_up, speed_down) + SELECT + user_id, SUM(up_add), SUM(down_add), SUM(release_add), SUM(bonus_add), SUM(speed_up), SUM(speed_down) + FROM ". NEW_BB_BT_LAST_TORSTAT ." + GROUP BY user_id + "); + + // Update TOTAL user's dlstat + DB()->query(" + UPDATE + ". BB_BT_USERS ." u, + ". NEW_BB_BT_LAST_USERSTAT ." ub + SET + u.u_up_total = u.u_up_total + ub.up_add, + u.u_down_total = u.u_down_total + ub.down_add, + u.u_up_release = u.u_up_release + ub.release_add, + u.u_up_bonus = u.u_up_bonus + ub.bonus_add + WHERE u.user_id = ub.user_id + "); + + // Delete from MAIN what exists in BUF but not exsits in NEW + DB()->query(" + DELETE main + FROM ". BB_BT_DLSTATUS_MAIN ." main + INNER JOIN ( + ". NEW_BB_BT_LAST_TORSTAT ." buf + LEFT JOIN ". BB_BT_DLSTATUS_NEW ." new USING(user_id, topic_id) + ) USING(user_id, topic_id) + WHERE new.user_id IS NULL + AND new.topic_id IS NULL + "); + + // Update DL-Status + DB()->query(" + REPLACE INTO ". BB_BT_DLSTATUS_NEW ." + (user_id, topic_id, user_status) + SELECT + user_id, topic_id, dl_status + FROM ". NEW_BB_BT_LAST_TORSTAT ." + "); + + // Update PER TORRENT DL-Status (for "completed" counter) + DB()->query(" + INSERT IGNORE INTO ". BB_BT_TORSTAT ." + (topic_id, user_id) + SELECT + topic_id, user_id + FROM ". NEW_BB_BT_LAST_TORSTAT ." + WHERE dl_status = ". DL_STATUS_COMPLETE ." + "); + } + + DB()->query(" + RENAME TABLE + ". BB_BT_LAST_TORSTAT ." TO ". OLD_BB_BT_LAST_TORSTAT .", + ". NEW_BB_BT_LAST_TORSTAT ." TO ". BB_BT_LAST_TORSTAT ." + "); + DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_LAST_TORSTAT .", ". OLD_BB_BT_LAST_TORSTAT); + + DB()->query(" + RENAME TABLE + ". BB_BT_LAST_USERSTAT ." TO ". OLD_BB_BT_LAST_USERSTAT .", + ". NEW_BB_BT_LAST_USERSTAT ." TO ". BB_BT_LAST_USERSTAT ." + "); + DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_LAST_USERSTAT .", ". OLD_BB_BT_LAST_USERSTAT); + + DB()->expect_slow_query(10); +} \ No newline at end of file diff --git a/upload/includes/cron/jobs/tr_complete_count.php b/upload/includes/cron/jobs/tr_complete_count.php new file mode 100644 index 000000000..8a816b8f3 --- /dev/null +++ b/upload/includes/cron/jobs/tr_complete_count.php @@ -0,0 +1,30 @@ +query(" + CREATE TEMPORARY TABLE tmp_complete_count + SELECT + topic_id, COUNT(*) AS compl_cnt + FROM ". BB_BT_TORSTAT ." + WHERE completed = 0 + GROUP BY topic_id +"); + +// Update USER "completed" counters +DB()->query("UPDATE ". BB_BT_TORSTAT ." SET completed = 1"); + +// Update TORRENT "completed" counters +DB()->query(" + UPDATE + ". BB_BT_TORRENTS ." tor, + tmp_complete_count tmp + SET + tor.complete_count = tor.complete_count + tmp.compl_cnt + WHERE + tor.topic_id = tmp.topic_id +"); + +// Drop tmp table +DB()->query("DROP TEMPORARY TABLE tmp_complete_count"); diff --git a/upload/includes/cron/jobs/tr_maintenance.php b/upload/includes/cron/jobs/tr_maintenance.php new file mode 100644 index 000000000..e0889b0bd --- /dev/null +++ b/upload/includes/cron/jobs/tr_maintenance.php @@ -0,0 +1,64 @@ +fetch_rowset($sql) as $row) +{ + $topics_sql[] = $row['topic_id']; + $attach_sql[] = $row['attach_id']; +} +$dead_tor_sql = join(',', $topics_sql); +$attach_sql = join(',', $attach_sql); + +if ($dead_tor_sql && $attach_sql) +{ +/* + // Update topic type + DB()->query(" + UPDATE ". BB_TOPICS ." SET + topic_dl_type = ". TOPIC_DL_TYPE_NORMAL ." + WHERE topic_id IN($dead_tor_sql) + "); +*/ + // Delete torstat + DB()->query(" + DELETE FROM ". BB_BT_TORSTAT ." + WHERE topic_id IN($dead_tor_sql) + "); + + // Update attach + DB()->query(" + UPDATE + ". ATTACHMENTS_DESC_TABLE ." a, + ". BB_BT_TORRENTS ." tor + SET + a.tracker_status = 0, + a.download_count = tor.complete_count + WHERE + a.attach_id = tor.attach_id + AND tor.attach_id IN($attach_sql) + "); + + // Remove torrents + DB()->query(" + DELETE FROM ". BB_BT_TORRENTS ." + WHERE topic_id IN($dead_tor_sql) + "); +} diff --git a/upload/includes/cron/jobs/tr_make_snapshot.php b/upload/includes/cron/jobs/tr_make_snapshot.php new file mode 100644 index 000000000..6aed55f4e --- /dev/null +++ b/upload/includes/cron/jobs/tr_make_snapshot.php @@ -0,0 +1,169 @@ +expect_slow_query(600); + +// +// Make tracker snapshot +// +define('NEW_BB_BT_TRACKER_SNAP', 'new_tracker_snap'); +define('OLD_BB_BT_TRACKER_SNAP', 'old_tracker_snap'); + +DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_TRACKER_SNAP .", ". OLD_BB_BT_TRACKER_SNAP); + +DB()->query("CREATE TABLE ". NEW_BB_BT_TRACKER_SNAP ." LIKE ". BB_BT_TRACKER_SNAP); + +$per_cycle = 50000; +$row = DB()->fetch_row("SELECT MIN(topic_id) AS start_id, MAX(topic_id) AS finish_id FROM ". BB_BT_TRACKER); +$start_id = (int) $row['start_id']; +$finish_id = (int) $row['finish_id']; + +while (true) +{ + set_time_limit(600); + $end_id = $start_id + $per_cycle - 1; + + $val = array(); + $sql = " + SELECT + topic_id, SUM(seeder) AS seeders, (COUNT(*) - SUM(seeder)) AS leechers, + SUM(speed_up) AS speed_up, SUM(speed_down) AS speed_down + FROM ". BB_BT_TRACKER ." + WHERE topic_id BETWEEN $start_id AND $end_id + GROUP BY topic_id + "; + foreach (DB()->fetch_rowset($sql) as $row) + { + $val[] = join(',', $row); + } + if ($val) + { + DB()->query(" + REPLACE INTO ". NEW_BB_BT_TRACKER_SNAP ." + (topic_id, seeders, leechers, speed_up, speed_down) + VALUES(". join('),(', $val) .") + "); + } + if ($end_id > $finish_id) + { + break; + } + if (!($start_id % ($per_cycle*10))) + { + sleep(1); + } + $start_id += $per_cycle; +} + +DB()->query(" + RENAME TABLE + ". BB_BT_TRACKER_SNAP ." TO ". OLD_BB_BT_TRACKER_SNAP .", + ". NEW_BB_BT_TRACKER_SNAP ." TO ". BB_BT_TRACKER_SNAP ." +"); + +DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_TRACKER_SNAP .", ". OLD_BB_BT_TRACKER_SNAP); + +if($bb_cfg['announce_type'] != 'xbt') +{ + // + // Make dl-list snapshot + // + define('NEW_BB_BT_DLSTATUS_SNAP', 'new_dlstatus_snap'); + define('OLD_BB_BT_DLSTATUS_SNAP', 'old_dlstatus_snap'); + + DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_DLSTATUS_SNAP .", ". OLD_BB_BT_DLSTATUS_SNAP); + + DB()->query("CREATE TABLE ". NEW_BB_BT_DLSTATUS_SNAP ." LIKE ". BB_BT_DLSTATUS_SNAP); + + if ($bb_cfg['bt_show_dl_list'] && $bb_cfg['bt_dl_list_only_count']) + { + DB()->query(" + INSERT INTO ". NEW_BB_BT_DLSTATUS_SNAP ." + (topic_id, dl_status, users_count) + SELECT + topic_id, user_status, COUNT(*) + FROM ". BB_BT_DLSTATUS ." + WHERE user_status != ". DL_STATUS_RELEASER ." + GROUP BY topic_id, user_status + "); + } + + DB()->query(" + RENAME TABLE + ". BB_BT_DLSTATUS_SNAP ." TO ". OLD_BB_BT_DLSTATUS_SNAP .", + ". NEW_BB_BT_DLSTATUS_SNAP ." TO ". BB_BT_DLSTATUS_SNAP ." + "); + + DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_DLSTATUS_SNAP .", ". OLD_BB_BT_DLSTATUS_SNAP); +} +// +// TORHELP +// +if ($bb_cfg['torhelp_enabled']) +{ + $tor_min_seeders = 0; // "<=" + $tor_min_leechers = 2; // ">=" + $tor_min_completed = 10; // ">=" + $tor_seed_last_seen_days = 3; // "<=" + $tor_downloaded_days_ago = 60; // ">=" + $user_last_seen_online = 15; // minutes + $users_limit = 3000; + $dl_status_ary = array(DL_STATUS_COMPLETE); + + define('NEW_BB_BT_TORHELP', 'new_torhelp'); + define('OLD_BB_BT_TORHELP', 'old_torhelp'); + + DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_TORHELP .", ". OLD_BB_BT_TORHELP); + + DB()->query("CREATE TABLE ". NEW_BB_BT_TORHELP ." LIKE ". BB_BT_TORHELP); + + // Select users + $sql = " + SELECT DISTINCT session_user_id AS uid + FROM ". BB_SESSIONS ." + WHERE session_time > (UNIX_TIMESTAMP() - $user_last_seen_online*60) + AND session_user_id != ". ANONYMOUS ." + ORDER BY session_time DESC + LIMIT $users_limit + "; + $online_users_ary = array(); + + foreach (DB()->fetch_rowset($sql) as $row) + { + $online_users_ary[] = $row['uid']; + } + + if ($online_users_csv = join(',', $online_users_ary)) + { + DB()->query(" + INSERT INTO ". NEW_BB_BT_TORHELP ." (user_id, topic_id_csv) + SELECT + dl.user_id, GROUP_CONCAT(dl.topic_id) + FROM ". BB_BT_TRACKER_SNAP ." trsn + INNER JOIN ". BB_BT_TORRENTS ." tor ON (tor.topic_id = trsn.topic_id) + INNER JOIN ". BB_BT_DLSTATUS_MAIN ." dl ON (dl.topic_id = tor.topic_id) + WHERE + trsn.seeders <= $tor_min_seeders + AND trsn.leechers >= $tor_min_leechers + AND tor.forum_id != ". (int) $bb_cfg['trash_forum_id'] ." + AND tor.complete_count >= $tor_min_completed + AND tor.seeder_last_seen <= (UNIX_TIMESTAMP() - $tor_seed_last_seen_days*86400) + AND dl.user_id IN($online_users_csv) + AND dl.user_status IN(". get_id_csv($dl_status_ary) .") + AND dl.last_modified_dlstatus > DATE_SUB(NOW(), INTERVAL $tor_downloaded_days_ago DAY) + GROUP BY dl.user_id + LIMIT 10000 + "); + } + + DB()->query(" + RENAME TABLE + ". BB_BT_TORHELP ." TO ". OLD_BB_BT_TORHELP .", + ". NEW_BB_BT_TORHELP ." TO ". BB_BT_TORHELP ." + "); + + DB()->query("DROP TABLE IF EXISTS ". NEW_BB_BT_TORHELP .", ". OLD_BB_BT_TORHELP); +} + +DB()->expect_slow_query(10); diff --git a/upload/includes/cron/jobs/tr_update_seeder_last_seen.php b/upload/includes/cron/jobs/tr_update_seeder_last_seen.php new file mode 100644 index 000000000..75025a25b --- /dev/null +++ b/upload/includes/cron/jobs/tr_update_seeder_last_seen.php @@ -0,0 +1,15 @@ +query(" + UPDATE + ". BUF_LAST_SEEDER ." b, + ". BB_BT_TORRENTS ." tor + SET + tor.seeder_last_seen = b.seeder_last_seen + WHERE + tor.topic_id = b.topic_id +"); + +DB()->query("TRUNCATE TABLE ". BUF_LAST_SEEDER); diff --git a/upload/includes/datastore/.htaccess b/upload/includes/datastore/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/datastore/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/datastore/build_attach_extensions.php b/upload/includes/datastore/build_attach_extensions.php new file mode 100644 index 000000000..ee543eb8b --- /dev/null +++ b/upload/includes/datastore/build_attach_extensions.php @@ -0,0 +1,17 @@ +fetch_rowset(" + SELECT + e.extension, g.cat_id, g.download_mode, g.upload_icon + FROM + ". BB_EXTENSIONS ." e, + ". BB_EXTENSION_GROUPS ." g + WHERE + e.group_id = g.group_id + AND g.allow_group = 1 +"); + +$this->store('attach_extensions', $extensions); diff --git a/upload/includes/datastore/build_cat_forums.php b/upload/includes/datastore/build_cat_forums.php new file mode 100644 index 000000000..ff4cb7964 --- /dev/null +++ b/upload/includes/datastore/build_cat_forums.php @@ -0,0 +1,174 @@ + array( + 'guest_view' => array(), + 'guest_read' => array(), + 'user_view' => array(), + 'user_read' => array(), + ), + 'tracker_forums' => array(), + 'cat_title_html' => array(), + 'forum_name_html' => array(), + 'c' => array(), // also has $data['c']['cat_id']['forums'] key + 'f' => array(), // also has $data['f']['forum_id']['subforums'] key +); + +// Store only these fields from BB_FORUMS in $data['f'] +$forum_store_fields = array_flip(array_keys($bf['forum_perm'])); +$forum_store_fields += array_flip(array( + 'forum_id', + 'cat_id', + 'forum_name', + 'forum_desc', + 'forum_status', + 'forum_posts', + 'forum_topics', + 'forum_parent', +)); + +// Categories +$sql = "SELECT * FROM ". BB_CATEGORIES ." ORDER BY cat_order"; + +foreach(DB()->fetch_rowset($sql) as $row) +{ + $data['c'][$row['cat_id']] = $row; + $data['cat_title_html'][$row['cat_id']] = htmlCHR($row['cat_title']); +} + +$sql = " + SELECT f.* + FROM ". BB_FORUMS ." f, ". BB_CATEGORIES ." c + WHERE f.cat_id = c.cat_id + ORDER BY c.cat_order, f.forum_order +"; + +foreach (DB()->fetch_rowset($sql) as $row) +{ + $fid = $row['forum_id']; + $not_auth =& $data['not_auth_forums']; + + // Find not auth forums + if ($row['auth_view'] != AUTH_ALL) + { + $not_auth['guest_view'][] = $fid; + } + if ($row['auth_view'] != AUTH_ALL && $row['auth_view'] != AUTH_REG) + { + $not_auth['user_view'][] = $fid; + } + if ($row['auth_read'] != AUTH_ALL) + { + $not_auth['guest_read'][] = $fid; + } + if ($row['auth_read'] != AUTH_ALL && $row['auth_read'] != AUTH_REG) + { + $not_auth['user_read'][] = $fid; + } + + // Store forums data + if ($parent_id = $row['forum_parent']) + { + $parent =& $data['f'][$parent_id]; + + $parent['subforums'][] = $fid; + $parent['forum_posts'] += $row['forum_posts']; + $parent['forum_topics'] += $row['forum_topics']; + } + if ($row['allow_reg_tracker']) + { + $data['tracker_forums'][] = $fid; + } + + $data['f'][$fid] = array_intersect_key($row, $forum_store_fields); + $data['forum_name_html'][$fid] = htmlCHR($row['forum_name']); + + // Forum ids in cat + $data['c'][$row['cat_id']]['forums'][] = $fid; +} +foreach ($data['not_auth_forums'] as $key => $val) +{ + $data['not_auth_forums'][$key] = join(',', $val); +} +$data['tracker_forums'] = join(',', $data['tracker_forums']); + +$this->store('cat_forums', $data); + +// +// jumpbox +// +$data = array( + 'guest' => get_forum_select('guest', 'f', null, null, null, 'id="jumpbox" onchange="window.location.href=\'viewforum.php?f=\'+this.value;"'), + 'user' => get_forum_select('user', 'f', null, null, null, 'id="jumpbox" onchange="window.location.href=\'viewforum.php?f=\'+this.value;"'), +); + +$this->store('jumpbox', $data); + +file_write($data['guest'], AJAX_HTML_DIR .'jumpbox_guest.html', false, true, true); +file_write($data['user'], AJAX_HTML_DIR .'jumpbox_user.html', false, true, true); + +// +// viewtopic_forum_select +// +$data = array( + 'viewtopic_forum_select' => get_forum_select('admin', 'new_forum_id'), +); + +$this->store('viewtopic_forum_select', $data); + +// +// latest_news +// +if ($bb_cfg['show_latest_news'] AND $news_forum_ids = $bb_cfg['latest_news_forum_id']) +{ + $news_count = max($bb_cfg['latest_news_count'], 1); + + $data = DB()->fetch_rowset(" + SELECT topic_id, topic_time, topic_title + FROM ". BB_TOPICS ." + WHERE forum_id IN ($news_forum_ids) + ORDER BY topic_time DESC + LIMIT $news_count + "); + + $this->store('latest_news', $data); +} + +// +// Ads +// +$ad_html = $ad_block_assignment = array(); + +if ($bb_cfg['show_ads']) +{ + $active_ads = DB()->fetch_rowset(" + SELECT * + FROM ". BB_ADS ." + WHERE ad_status = 1 + AND ad_start_time < NOW() + AND DATE_ADD(ad_start_time, INTERVAL ad_active_days DAY) > NOW() + "); + + foreach ($active_ads as $ad) + { + if ($ad['ad_block_ids']) + { + foreach(explode(',', $ad['ad_block_ids']) as $block_id) + { + $ad_block_assignment[$block_id][] = $ad['ad_id']; + } + } + + $ad_html[$ad['ad_id']] = $ad['ad_html']; + } +} + +$this->store('ads', $ad_html); +bb_update_config(array('active_ads' => serialize($ad_block_assignment))); diff --git a/upload/includes/datastore/build_moderators.php b/upload/includes/datastore/build_moderators.php new file mode 100644 index 000000000..76d2f8b1d --- /dev/null +++ b/upload/includes/datastore/build_moderators.php @@ -0,0 +1,107 @@ + array(), // only by personal permissions + 'name_groups' => array(), // only visible to all users + 'mod_users' => array(), // only by personal permissions + 'mod_groups' => array(), // only visible to all users + 'moderators' => array(), // all moderators + 'admins' => array(), // all admins +); + +// name_users +// mod_users +$sql = " + SELECT + aa.forum_id, u.user_id, u.username + FROM + ". BB_AUTH_ACCESS ." aa, + ". BB_USER_GROUP ." ug, + ". BB_GROUPS ." g, + ". BB_USERS ." u + WHERE + aa.forum_perm & ". BF_AUTH_MOD ." + AND ug.group_id = aa.group_id + AND ug.user_pending = 0 + AND g.group_id = ug.group_id + AND g.group_single_user = 1 + AND u.user_id = ug.user_id + GROUP BY + aa.forum_id, u.user_id + ORDER BY + u.username +"; + +foreach (DB()->fetch_rowset($sql) as $row) +{ + $data['name_users'][$row['user_id']] = $row['username']; + $data['mod_users'][$row['forum_id']][] = $row['user_id']; +} + +// name_groups +// mod_groups +$sql = " + SELECT + aa.forum_id, g.group_id, g.group_name + FROM + ". BB_AUTH_ACCESS ." aa, + ". BB_GROUPS ." g + WHERE + aa.forum_perm & ". BF_AUTH_MOD ." + AND g.group_id = aa.group_id + AND g.group_single_user = 0 + AND g.group_type != ". GROUP_HIDDEN ." + GROUP BY + aa.forum_id, g.group_id + ORDER BY + g.group_name +"; + +foreach (DB()->fetch_rowset($sql) as $row) +{ + $data['name_groups'][$row['group_id']] = $row['group_name']; + $data['mod_groups'][$row['forum_id']][] = $row['group_id']; +} + +// moderators +$sql = " + SELECT + u.user_id, u.username + FROM + ". BB_AUTH_ACCESS ." aa, + ". BB_USER_GROUP ." ug, + ". BB_GROUPS ." g, + ". BB_USERS ." u + WHERE + aa.forum_perm & ". BF_AUTH_MOD ." + AND ug.group_id = aa.group_id + AND ug.user_pending = 0 + AND g.group_id = ug.group_id + AND u.user_id = ug.user_id + GROUP BY + u.user_id + ORDER BY + u.username +"; + +foreach (DB()->fetch_rowset($sql) as $row) +{ + $data['moderators'][$row['user_id']] = $row['username']; +} + +// admins +$sql = " + SELECT user_id, username + FROM ". BB_USERS ." + WHERE user_level = ". ADMIN ." + ORDER BY username +"; + +foreach (DB()->fetch_rowset($sql) as $row) +{ + $data['admins'][$row['user_id']] = $row['username']; +} + +$this->store('moderators', $data); \ No newline at end of file diff --git a/upload/includes/datastore/build_ranks.php b/upload/includes/datastore/build_ranks.php new file mode 100644 index 000000000..7e09b93c9 --- /dev/null +++ b/upload/includes/datastore/build_ranks.php @@ -0,0 +1,14 @@ +fetch_rowset($sql) as $row) +{ + $ranks[$row['rank_id']] = $row; +} + +$this->store('ranks', $ranks); diff --git a/upload/includes/datastore/build_smilies.php b/upload/includes/datastore/build_smilies.php new file mode 100644 index 000000000..8f1dfce9e --- /dev/null +++ b/upload/includes/datastore/build_smilies.php @@ -0,0 +1,18 @@ +fetch_rowset("SELECT * FROM ". BB_SMILIES); +usort($rowset, 'smiley_sort'); + +foreach ($rowset as $smile) +{ + $smilies['orig'][] = '#(?<=^|\W)'. preg_quote($smile['code'], '#') .'(?=$|\W)#'; + $smilies['repl'][] = ' '. $smile['emoticon'] .''; +} + +$this->store('smile_replacements', $smilies); diff --git a/upload/includes/datastore/build_stats.php b/upload/includes/datastore/build_stats.php new file mode 100644 index 000000000..e0c0e16da --- /dev/null +++ b/upload/includes/datastore/build_stats.php @@ -0,0 +1,32 @@ +fetch_row("SELECT COUNT(*) AS usercount FROM ". BB_USERS ." WHERE user_id NOT IN(". EXCLUDED_USERS_CSV .")"); +$data['usercount'] = number_format($row['usercount']); + +// newestuser +$row = DB()->fetch_row("SELECT user_id, username FROM ". BB_USERS ." ORDER BY user_id DESC LIMIT 1"); +$data['newestuser'] = $row; + +// post/topic count +$row = DB()->fetch_row("SELECT SUM(forum_topics) AS topiccount, SUM(forum_posts) AS postcount FROM ". BB_FORUMS); +$data['postcount'] = number_format($row['postcount']); +$data['topiccount'] = number_format($row['topiccount']); + +// torrents stat +$row = DB()->fetch_row("SELECT COUNT(topic_id) AS torrentcount, SUM(size) AS size FROM ". BB_BT_TORRENTS); +$data['torrentcount'] = number_format($row['torrentcount']); +$data['size'] = $row['size']; + +// peers stat +$row = DB()->fetch_row("SELECT SUM(seeders) AS seeders, SUM(leechers) AS leechers, ((SUM(speed_up) + SUM(speed_down))/2) AS speed FROM ". BB_BT_TRACKER_SNAP); +$data['seeders'] = number_format($row['seeders']); +$data['leechers'] = number_format($row['leechers']); +$data['peers'] = number_format($row['seeders'] + $row['leechers']); +$data['speed'] = $row['speed']; + +$this->store('stats', $data); diff --git a/upload/includes/db/.htaccess b/upload/includes/db/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/db/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/db/mysql.php b/upload/includes/db/mysql.php new file mode 100644 index 000000000..b35175c21 --- /dev/null +++ b/upload/includes/db/mysql.php @@ -0,0 +1,987 @@ +cfg = array_combine($this->cfg_keys, $cfg_values); + $this->dbg_enabled = (sql_dbg_enabled() || !empty($_COOKIE['explain'])); + $this->do_explain = ($this->dbg_enabled && !empty($_COOKIE['explain'])); + $this->slow_time = SQL_SLOW_QUERY_TIME; + + // ссылки на глобальные переменные (для включения логов сразу на всех серверах, подсчета общего количества запросов и т.д.) + $this->DBS['log_file'] =& $DBS->log_file; + $this->DBS['log_counter'] =& $DBS->log_counter; + $this->DBS['num_queries'] =& $DBS->num_queries; + $this->DBS['sql_inittime'] =& $DBS->sql_inittime; + $this->DBS['sql_timetotal'] =& $DBS->sql_timetotal; + } + + /** + * Initialize connection + */ + function init () + { + // Connect to server + $this->link = $this->connect(); + + // Select database + $this->selected_db = $this->select_db(); + + // Set charset + if ($this->cfg['charset'] && !@mysql_set_charset($this->cfg['charset'], $this->link)) + { + if (!$this->sql_query("SET NAMES {$this->cfg['charset']}")) + { + die("Could not set charset {$this->cfg['charset']}"); + } + } + + $this->inited = true; + $this->num_queries = 0; + $this->sql_inittime = $this->sql_timetotal; + $this->DBS['sql_inittime'] += $this->sql_inittime; + } + + /** + * Open connection + */ + function connect () + { + $this->cur_query = ($this->dbg_enabled) ? ($this->cfg['persist'] ? 'p' : '') . "connect to: {$this->cfg['dbhost']}" : 'connect'; + $this->debug('start'); + + $connect_type = ($this->cfg['persist']) ? 'mysql_pconnect' : 'mysql_connect'; + + if (!$link = @$connect_type($this->cfg['dbhost'], $this->cfg['dbuser'], $this->cfg['dbpasswd'])) + { + $server = (DBG_USER) ? $this->cfg['dbhost'] : ''; + header("HTTP/1.0 503 Service Unavailable"); + bb_log(' ', "db_err/connect_failed_{$this->cfg['dbhost']}"); + die("Could not connect to the server $server"); + } + + register_shutdown_function(array(&$this, 'close')); + + $this->debug('stop'); + $this->cur_query = null; + + return $link; + } + + /** + * Select database + */ + function select_db () + { + $this->cur_query = ($this->dbg_enabled) ? "select db: {$this->cfg['dbname']}" : 'select db'; + $this->debug('start'); + + if (!@mysql_select_db($this->cfg['dbname'], $this->link)) + { + $database = (DBG_USER) ? $this->cfg['dbhost'] : ''; + die("Could not select database $database"); + } + + $this->debug('stop'); + $this->cur_query = null; + + return $this->cfg['dbname']; + } + + /** + * Base query method + */ + function sql_query ($query) + { + if (!is_resource($this->link)) + { + $this->init(); + } + if (is_array($query)) + { + $query = $this->build_sql($query); + } + if (SQL_PREPEND_SRC_COMM) + { + $query = '/* '. $this->debug_find_source() .' */ '. $query; + } + $this->cur_query = $query; + $this->debug('start'); + + if (!$this->result = mysql_query($query, $this->link)) + { + $this->log_error(); + } + + $this->debug('stop'); + $this->cur_query = null; + + if ($this->inited) + { + $this->num_queries++; + $this->DBS['num_queries']++; + } + + return $this->result; + } + + /** + * Execute query WRAPPER (with error handling) + */ + function query ($query) + { + if (!$result = $this->sql_query($query)) + { + $this->trigger_error(); + } + + return $result; + } + + /** + * Return number of rows + */ + function num_rows ($result = false) + { + $num_rows = false; + + if ($result OR $result = $this->result) + { + $num_rows = is_resource($result) ? mysql_num_rows($result) : false; + } + + return $num_rows; + } + + /** + * Return number of affected rows + */ + function affected_rows () + { + return is_resource($this->link) ? mysql_affected_rows($this->link) : -1; + } + + /** + * Fetch current field + */ + function sql_fetchfield($field, $rownum = -1, $query_id = 0) + { + if(!$query_id) + { + $query_id = $this->query_result; + } + if($query_id) + { + if($rownum > -1) + { + $result = @mysql_result($query_id, $rownum, $field); + } + else + { + if(empty($this->row[$query_id]) && empty($this->rowset[$query_id])) + { + if($this->sql_fetchrow()) + { + $result = $this->row[$query_id][$field]; + } + } + else + { + if($this->rowset[$query_id]) + { + $result = $this->rowset[$query_id][0][$field]; + } + else if($this->row[$query_id]) + { + $result = $this->row[$query_id][$field]; + } + } + } + return $result; + } + else + { + return false; + } + } + + /** + * Fetch current row + */ + function sql_fetchrow ($result, $field_name = '') + { + $row = mysql_fetch_assoc($result); + + if ($field_name) + { + return isset($row[$field_name]) ? $row[$field_name] : false; + } + else + { + return $row; + } + } + + /** + * Alias of sql_fetchrow() + */ + function fetch_next ($result) + { + return $this->sql_fetchrow($result); + } + + /** + * Fetch row WRAPPER (with error handling) + */ + function fetch_row ($query, $field_name = '') + { + if (!$result = $this->sql_query($query)) + { + $this->trigger_error(); + } + + return $this->sql_fetchrow($result, $field_name); + } + + /** + * Fetch all rows + */ + function sql_fetchrowset ($result, $field_name = '') + { + $rowset = array(); + + while ($row = mysql_fetch_assoc($result)) + { + $rowset[] = ($field_name) ? $row[$field_name] : $row; + } + + return $rowset; + } + + /** + * Fetch all rows WRAPPER (with error handling) + */ + function fetch_rowset ($query, $field_name = '') + { + if (!$result = $this->sql_query($query)) + { + $this->trigger_error(); + } + + return $this->sql_fetchrowset($result, $field_name); + } + + /** + * Fetch all rows WRAPPER (with error handling) + */ + function fetch_all ($query, $field_name = '') + { + if (!$result = $this->sql_query($query)) + { + $this->trigger_error(); + } + + return $this->sql_fetchrowset($result, $field_name); + } + + /** + * Get last inserted id after insert statement + */ + function sql_nextid () + { + return mysql_insert_id($this->link); + } + + /** + * Free sql result + */ + function sql_freeresult ($result = false) + { + if ($result OR $result = $this->result) + { + $return_value = is_resource($result) ? mysql_free_result($result) : false; + } + + $this->result = null; + } + + /** + * Escape data used in sql query + */ + function escape ($v, $check_type = false, $dont_escape = false) + { + if ($dont_escape) return $v; + if (!$check_type) return $this->escape_string($v); + + switch (true) + { + case is_string ($v): return "'". $this->escape_string($v) ."'"; + case is_int ($v): return "$v"; + case is_bool ($v): return ($v) ? '1' : '0'; + case is_float ($v): return "'$v'"; + case is_null ($v): return 'NULL'; + } + // if $v has unsuitable type + $this->trigger_error(__FUNCTION__ .' - wrong params'); + } + + /** + * Escape string + */ + function escape_string ($str) + { + if (!is_resource($this->link)) + { + $this->init(); + } + + return mysql_real_escape_string($str, $this->link); + } + + /** + * Build SQL statement from array (based on same method from phpBB3, idea from Ikonboard) + * + * Possible $query_type values: INSERT, INSERT_SELECT, MULTI_INSERT, UPDATE, SELECT + */ + function build_array ($query_type, $input_ary, $data_already_escaped = false, $check_data_type_in_escape = true) + { + $fields = $values = $ary = $query = array(); + $dont_escape = $data_already_escaped; + $check_type = $check_data_type_in_escape; + + if (empty($input_ary) || !is_array($input_ary)) + { + $this->trigger_error(__FUNCTION__ .' - wrong params: $input_ary'); + } + + if ($query_type == 'INSERT') + { + foreach ($input_ary as $field => $val) + { + $fields[] = $field; + $values[] = $this->escape($val, $check_type, $dont_escape); + } + $fields = join(', ', $fields); + $values = join(', ', $values); + $query = "($fields)\nVALUES\n($values)"; + } + else if ($query_type == 'INSERT_SELECT') + { + foreach ($input_ary as $field => $val) + { + $fields[] = $field; + $values[] = $this->escape($val, $check_type, $dont_escape); + } + $fields = join(', ', $fields); + $values = join(', ', $values); + $query = "($fields)\nSELECT\n$values"; + } + else if ($query_type == 'MULTI_INSERT') + { + foreach ($input_ary as $id => $sql_ary) + { + foreach ($sql_ary as $field => $val) + { + $values[] = $this->escape($val, $check_type, $dont_escape); + } + $ary[] = '('. join(', ', $values) .')'; + $values = array(); + } + $fields = join(', ', array_keys($input_ary[0])); + $values = join(",\n", $ary); + $query = "($fields)\nVALUES\n$values"; + } + else if ($query_type == 'SELECT' || $query_type == 'UPDATE') + { + foreach ($input_ary as $field => $val) + { + $ary[] = "$field = ". $this->escape($val, $check_type, $dont_escape); + } + $glue = ($query_type == 'SELECT') ? "\nAND " : ",\n"; + $query = join($glue, $ary); + } + + if (!$query) + { + bb_die('
    '. __FUNCTION__ .": Wrong params for $query_type query type\n\n\$input_ary:\n\n". htmlCHR(print_r($input_ary, true)) .'
    '); + } + + return "\n". $query ."\n"; + } + + function get_empty_sql_array () + { + return array( + 'SELECT' => array(), + 'select_options' => array(), + 'FROM' => array(), + 'INNER JOIN' => array(), + 'LEFT JOIN' => array(), + 'WHERE' => array(), + 'GROUP BY' => array(), + 'HAVING' => array(), + 'ORDER BY' => array(), + 'LIMIT' => array(), + ); + } + + function build_sql ($sql_ary) + { + $sql = ''; + array_deep($sql_ary, 'array_unique', false, true); + + foreach ($sql_ary as $clause => $ary) + { + switch ($clause) + { + case 'SELECT': + $sql .= ($ary) ? ' SELECT '. join(' ', $sql_ary['select_options']) .' '. join(', ', $ary) : ''; + break; + case 'FROM': + $sql .= ($ary) ? ' FROM '. join(', ', $ary) : ''; + break; + case 'INNER JOIN': + $sql .= ($ary) ? ' INNER JOIN '. join(' INNER JOIN ', $ary) : ''; + break; + case 'LEFT JOIN': + $sql .= ($ary) ? ' LEFT JOIN '. join(' LEFT JOIN ', $ary) : ''; + break; + case 'WHERE': + $sql .= ($ary) ? ' WHERE '. join(' AND ', $ary) : ''; + break; + case 'GROUP BY': + $sql .= ($ary) ? ' GROUP BY '. join(', ', $ary) : ''; + break; + case 'HAVING': + $sql .= ($ary) ? ' HAVING '. join(' AND ', $ary) : ''; + break; + case 'ORDER BY': + $sql .= ($ary) ? ' ORDER BY '. join(', ', $ary) : ''; + break; + case 'LIMIT': + $sql .= ($ary) ? ' LIMIT '. join(', ', $ary) : ''; + break; + } + } + + return trim($sql); + } + + /** + * Return sql error array + */ + function sql_error () + { + if (is_resource($this->link)) + { + return array('code' => mysql_errno($this->link), 'message' => mysql_error($this->link)); + } + else + { + return array('code' => '', 'message' => 'not connected'); + } + } + + /** + * Close sql connection + */ + function close () + { + if (is_resource($this->link)) + { + $this->unlock(); + + if (!empty($this->locks)) + { + foreach ($this->locks as $name => $void) + { + $this->release_lock($name); + } + } + + $this->exec_shutdown_queries(); + + mysql_close($this->link); + } + + $this->link = $this->selected_db = null; + } + + /** + * Add shutdown query + */ + function add_shutdown_query ($sql) + { + $this->shutdown['__sql'][] = $sql; + } + + /** + * Exec shutdown queries + */ + function exec_shutdown_queries () + { + if (empty($this->shutdown)) return; + + if (!empty($this->shutdown['post_html'])) + { + $post_html_sql = $this->build_array('MULTI_INSERT', $this->shutdown['post_html']); + $this->query("REPLACE INTO ". BB_POSTS_HTML ." $post_html_sql"); + } + + if (!empty($this->shutdown['__sql'])) + { + foreach ($this->shutdown['__sql'] as $sql) + { + $this->query($sql); + } + } + } + + /** + * Lock tables + */ + function lock ($tables, $lock_type = 'WRITE') + { + if ($this->cfg['persist']) + { +# return true; + } + + $tables_sql = array(); + + foreach ((array) $tables as $table_name) + { + $tables_sql[] = "$table_name $lock_type"; + } + if ($tables_sql = join(', ', $tables_sql)) + { + $this->locked = $this->sql_query("LOCK TABLES $tables_sql"); + } + + return $this->locked; + } + + /** + * Unlock tables + */ + function unlock () + { + if ($this->locked && $this->sql_query("UNLOCK TABLES")) + { + $this->locked = false; + } + + return !$this->locked; + } + + /** + * Obtain user level lock + */ + function get_lock ($name, $timeout = 0) + { + $lock_name = $this->get_lock_name($name); + $timeout = (int) $timeout; + $row = $this->fetch_row("SELECT GET_LOCK('$lock_name', $timeout) AS lock_result"); + + if ($row['lock_result']) + { + $this->locks[$name] = true; + } + + return $row['lock_result']; + } + + /** + * Obtain user level lock status + */ + function release_lock ($name) + { + $lock_name = $this->get_lock_name($name); + $row = $this->fetch_row("SELECT RELEASE_LOCK('$lock_name') AS lock_result"); + + if ($row['lock_result']) + { + unset($this->locks[$name]); + } + + return $row['lock_result']; + } + + /** + * Release user level lock + */ + function is_free_lock ($name) + { + $lock_name = $this->get_lock_name($name); + $row = $this->fetch_row("SELECT IS_FREE_LOCK('$lock_name') AS lock_result"); + return $row['lock_result']; + } + + /** + * Make per db unique lock name + */ + function get_lock_name ($name) + { + if (!$this->selected_db) + { + $this->init(); + } + + return "{$this->selected_db}_{$name}"; + } + + /** + * Get info about last query + */ + function query_info () + { + $info = array(); + + if ($num = $this->num_rows($this->result)) + { + $info[] = "$num rows"; + } + + if (is_resource($this->link) AND $ext = mysql_info($this->link)) + { + $info[] = "$ext"; + } + else if (!$num && ($aff = $this->affected_rows($this->result) AND $aff != -1)) + { + $info[] = "$aff rows"; + } + + return str_compact(join(', ', $info)); + } + + /** + * Get server version + */ + function server_version () + { + preg_match('#^(\d+\.\d+\.\d+).*#', mysql_get_server_info(), $m); + return $m[1]; + } + + /** + * Set slow query marker for xx seconds + * This will disable counting other queries as "slow" during this time + */ + function expect_slow_query ($ignoring_time = 60, $new_priority = 10) + { + if ($old_priority = CACHE('bb_cache')->get('dont_log_slow_query')) + { + if ($old_priority > $new_priority) + { + return; + } + } + + @define('IN_FIRST_SLOW_QUERY', true); + CACHE('bb_cache')->set('dont_log_slow_query', $new_priority, $ignoring_time); + } + + /** + * Store debug info + */ + function debug ($mode) + { + if (!SQL_DEBUG) return; + + $id =& $this->dbg_id; + $dbg =& $this->dbg[$id]; + + if ($mode == 'start') + { + if (SQL_CALC_QUERY_TIME || DBG_LOG || SQL_LOG_SLOW_QUERIES) + { + $this->sql_starttime = utime(); + } + if ($this->dbg_enabled) + { + $dbg['sql'] = preg_replace('#^(\s*)(/\*)(.*)(\*/)(\s*)#', '', $this->cur_query); + $dbg['src'] = $this->debug_find_source(); + $dbg['file'] = $this->debug_find_source('file'); + $dbg['line'] = $this->debug_find_source('line'); + $dbg['time'] = ''; + $dbg['info'] = ''; + $dbg['mem_before'] = sys('mem'); + } + if ($this->do_explain) + { + $this->explain('start'); + } + } + else if ($mode == 'stop') + { + if (SQL_CALC_QUERY_TIME || DBG_LOG || SQL_LOG_SLOW_QUERIES) + { + $this->cur_query_time = utime() - $this->sql_starttime; + $this->sql_timetotal += $this->cur_query_time; + $this->DBS['sql_timetotal'] += $this->cur_query_time; + + if (SQL_LOG_SLOW_QUERIES && $this->cur_query_time > $this->slow_time) + { + $this->log_slow_query(); + } + } + if ($this->dbg_enabled) + { + $dbg['time'] = utime() - $this->sql_starttime; + $dbg['info'] = $this->query_info(); + $dbg['mem_after'] = sys('mem'); + $id++; + } + if ($this->do_explain) + { + $this->explain('stop'); + } + // проверка установки $this->inited - для пропуска инициализационных запросов + if ($this->DBS['log_counter'] && $this->inited) + { + $this->log_query($this->DBS['log_file']); + $this->DBS['log_counter']--; + } + } + } + + /** + * Trigger error + */ + function trigger_error ($msg = 'DB Error') + { + if (error_reporting()) + { + if (DEBUG === true) + { + $err = $this->sql_error(); + $msg .= "\n". trim(sprintf('#%06d %s', $err['code'], $err['message'])); + } + else + { + $msg .= " [". $this->debug_find_source() ."]"; + } + + trigger_error($msg, E_USER_ERROR); + } + } + + /** + * Find caller source + */ + function debug_find_source ($mode = '') + { + foreach (debug_backtrace() as $trace) + { + if (!empty($trace['file']) && $trace['file'] !== __FILE__) + { + switch ($mode) + { + case 'file': return $trace['file']; + case 'line': return $trace['line']; + default: return hide_bb_path($trace['file']) .'('. $trace['line'] .')'; + } + } + } + return ''; + } + + /** + * Prepare for logging + */ + function log_next_query ($queries_count = 1, $log_file = 'sql_queries') + { + $this->DBS['log_file'] = $log_file; + $this->DBS['log_counter'] = $queries_count; + } + + /** + * Log query + */ + function log_query ($log_file = 'sql_queries') + { + $q_time = ($this->cur_query_time >= 10) ? round($this->cur_query_time, 0) : sprintf('%.4f', $this->cur_query_time); + $msg = array(); + $msg[] = round($this->sql_starttime); + $msg[] = date('m-d H:i:s', $this->sql_starttime); + $msg[] = sprintf('%-6s', $q_time); + $msg[] = sprintf('%-4s', round(sys('la'), 1)); + $msg[] = sprintf('%05d', getmypid()); + $msg[] = $this->db_server; + $msg[] = short_query($this->cur_query); + $msg = join(LOG_SEPR, $msg); + $msg .= ($info = $this->query_info()) ? ' # '. $info : ''; + $msg .= ' # '. $this->debug_find_source() .' '; + $msg .= defined('IN_CRON') ? 'cron' : basename($_SERVER['REQUEST_URI']); + bb_log($msg . LOG_LF, $log_file); + } + + /** + * Log slow query + */ + function log_slow_query ($log_file = 'sql_slow_bb') + { + if (!defined('IN_FIRST_SLOW_QUERY') && CACHE('bb_cache')->get('dont_log_slow_query')) + { + return; + } + $this->log_query($log_file); + } + + /** + * Log error + */ + function log_error () + { + if (!SQL_LOG_ERRORS) return; + + $msg = array(); + $err = $this->sql_error(); + $msg[] = str_compact(sprintf('#%06d %s', $err['code'], $err['message'])); + $msg[] = ''; + $msg[] = str_compact($this->cur_query); + $msg[] = ''; + $msg[] = 'Source : '. $this->debug_find_source() ." :: $this->db_server.$this->selected_db"; + $msg[] = 'IP : '. @$_SERVER['REMOTE_ADDR']; + $msg[] = 'Date : '. date('Y-m-d H:i:s'); + $msg[] = 'Agent : '. @$_SERVER['HTTP_USER_AGENT']; + $msg[] = 'Req_URI : '. @$_SERVER['REQUEST_URI']; + $msg[] = 'Referer : '. @$_SERVER['HTTP_REFERER']; + $msg[] = 'Method : '. @$_SERVER['REQUEST_METHOD']; + $msg[] = 'PID : '. sprintf('%05d', getmypid()); + $msg[] = 'Request : '. trim(print_r($_REQUEST, true)) . str_repeat('_', 78) . LOG_LF; + $msg[] = ''; + bb_log($msg, 'sql_error_bb'); + } + + /** + * Explain queries (based on code from phpBB3) + */ + function explain ($mode, $html_table = '', $row = '') + { + $query = str_compact($this->cur_query); + // remove comments + $query = preg_replace('#(\s*)(/\*)(.*)(\*/)(\s*)#', '', $query); + + switch ($mode) + { + case 'start': + $this->explain_hold = ''; + // TODO: добавить поддержку многотабличных запросов + if (preg_match('#UPDATE ([a-z0-9_]+).*?WHERE(.*)/#', $query, $m)) + { + $query = "SELECT * FROM $m[1] WHERE $m[2]"; + } + else if (preg_match('#DELETE FROM ([a-z0-9_]+).*?WHERE(.*)#s', $query, $m)) + { + $query = "SELECT * FROM $m[1] WHERE $m[2]"; + } + + if (preg_match('#^SELECT#', $query)) + { + $html_table = false; + + if ($result = @mysql_query("EXPLAIN $query", $this->link)) + { + while ($row = @mysql_fetch_assoc($result)) + { + $html_table = $this->explain('add_explain_row', $html_table, $row); + } + } + if ($html_table) + { + $this->explain_hold .= ''; + } + } + break; + + case 'stop': + if (!$this->explain_hold) break; + + $id = $this->dbg_id-1; + $htid = 'expl-'. intval($this->link) .'-'. $id; + $dbg = $this->dbg[$id]; + $file = addslashes($dbg['file']); + $line = $dbg['line']; + $edit = (DEBUG === true) ? "OpenInEditor('$file', $line);" : ''; + + $this->explain_out .= ' + + + + + + +
     '. $dbg['src'] .'  ['. sprintf('%.4f', $dbg['time']) .' s]  '. $dbg['info'] .''. "$this->db_server.$this->selected_db" .' :: Query #'. ($this->num_queries+1) .' 
    '. $this->explain_hold .'
    +
    '. short_query($dbg['sql'], true) .'  '. (UA_IE ? '

    ' : '') .'
    +
    '; + break; + + case 'add_explain_row': + if (!$html_table && $row) + { + $html_table = true; + $this->explain_hold .= ''; + foreach (array_keys($row) as $val) + { + $this->explain_hold .= ''; + } + $this->explain_hold .= ''; + } + $this->explain_hold .= ''; + foreach (array_values($row) as $i => $val) + { + $class = !($i % 2) ? 'row1' : 'row2'; + $this->explain_hold .= ''; + } + $this->explain_hold .= ''; + + return $html_table; + + break; + + case 'display': + echo '
    '. $this->explain_out .'
    '; + break; + } + } +} \ No newline at end of file diff --git a/upload/includes/emailer.class.php b/upload/includes/emailer.class.php new file mode 100644 index 000000000..bdbeab6e1 --- /dev/null +++ b/upload/includes/emailer.class.php @@ -0,0 +1,345 @@ +reset(); + $this->use_smtp = $use_smtp; + $this->reply_to = $this->from = ''; + } + + // Resets all the data (address, template file, etc etc to default + function reset() + { + $this->addresses = array(); + $this->vars = $this->msg = $this->extra_headers = ''; + } + + // Sets an email address to send to + function email_address($address) + { + $this->addresses['to'] = trim($address); + } + + function cc($address) + { + $this->addresses['cc'][] = trim($address); + } + + function bcc($address) + { + $this->addresses['bcc'][] = trim($address); + } + + function replyto($address) + { + $this->reply_to = trim($address); + } + + function from($address) + { + $this->from = trim($address); + } + + // set up subject for mail + function set_subject($subject = '') + { + $this->subject = trim(preg_replace('#[\n\r]+#s', '', $subject)); + } + + // set up extra mail headers + function extra_headers($headers) + { + $this->extra_headers .= trim($headers) . "\n"; + } + + function use_template($template_file, $template_lang = '') + { + global $bb_cfg; + + if (trim($template_file) == '') + { + message_die(GENERAL_ERROR, 'No template file set', '', __LINE__, __FILE__); + } + + if (trim($template_lang) == '') + { + $template_lang = $bb_cfg['default_lang']; + } + + if (empty($this->tpl_msg[$template_lang . $template_file])) + { + $tpl_file = LANG_ROOT_DIR ."lang_$template_lang/email/$template_file.tpl"; + + if (!@file_exists(@phpbb_realpath($tpl_file))) + { + $tpl_file = LANG_ROOT_DIR ."lang_{$bb_cfg['default_lang']}/email/$template_file.tpl"; + + if (!@file_exists(@phpbb_realpath($tpl_file))) + { + message_die(GENERAL_ERROR, 'Could not find email template file :: ' . $template_file, '', __LINE__, __FILE__); + } + } + + if (!($fd = @fopen($tpl_file, 'r'))) + { + message_die(GENERAL_ERROR, 'Failed opening template file :: ' . $tpl_file, '', __LINE__, __FILE__); + } + + $this->tpl_msg[$template_lang . $template_file] = fread($fd, filesize($tpl_file)); + fclose($fd); + } + + $this->msg = $this->tpl_msg[$template_lang . $template_file]; + + return true; + } + + // assign variables + function assign_vars($vars) + { + $this->vars = (empty($this->vars)) ? $vars : $this->vars . $vars; + } + + // Send the mail out to the recipients set previously in var $this->address + function send() + { + global $bb_cfg, $lang; + + if ($bb_cfg['emailer_disabled']) + { + return; + } + + // Escape all quotes, else the eval will fail. + $this->msg = str_replace ("'", "\'", $this->msg); + $this->msg = preg_replace('#\{([a-z0-9\-_]*?)\}#is', "' . $\\1 . '", $this->msg); + + // Set vars + reset ($this->vars); + while (list($key, $val) = each($this->vars)) + { + $$key = $val; + } + + eval("\$this->msg = '$this->msg';"); + + // Clear vars + reset ($this->vars); + while (list($key, $val) = each($this->vars)) + { + unset($$key); + } + + // We now try and pull a subject from the email body ... if it exists, + // do this here because the subject may contain a variable + $drop_header = ''; + $match = array(); + if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match)) + { + $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : 'No Subject'); + $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); + } + else + { + $this->subject = (($this->subject != '') ? $this->subject : 'No Subject'); + } + + if (preg_match('#^(Charset:(.*?))$#m', $this->msg, $match)) + { + $this->encoding = (trim($match[2]) != '') ? trim($match[2]) : trim($lang['CONTENT_ENCODING']); + $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); + } + else + { + $this->encoding = !empty($lang['CONTENT_ENCODING']) ? trim($lang['CONTENT_ENCODING']) : $bb_cfg['email_default_charset']; + } + $this->subject = $this->encode($this->subject); + + if ($drop_header != '') + { + $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg)); + } + + $to = @$this->addresses['to']; + + $cc = (@count($this->addresses['cc'])) ? implode(', ', $this->addresses['cc']) : ''; + $bcc = (@count($this->addresses['bcc'])) ? implode(', ', $this->addresses['bcc']) : ''; + + // Build header + //$this->extra_headers = (($this->reply_to != '') ? "Reply-to: $this->reply_to\n" : '') . (($this->from != '') ? "From: $this->from\n" : "From: " . $bb_cfg['board_email'] . "\n") . "Return-Path: " . $bb_cfg['board_email'] . "\nMessage-ID: <" . md5(uniqid(time())) . "@" . $bb_cfg['server_name'] . ">\nMIME-Version: 1.0\nContent-type: text/plain; charset=" . $this->encoding . "\nContent-transfer-encoding: 8bit\nDate: " . date('r', time()) . "\nX-Priority: 3\nX-MSMail-Priority: Normal\nX-Mailer: PHP\nX-MimeOLE: Produced By phpBB2\n" . $this->extra_headers . (($cc != '') ? "Cc: $cc\n" : '') . (($bcc != '') ? "Bcc: $bcc\n" : ''); + $this->extra_headers = (($this->reply_to != '') ? "Reply-to: $this->reply_to\n" : '') . (($this->from != '') ? "From: $this->from\n" : "From: " . $bb_cfg['board_email'] . "\n") . "Return-Path: " . $bb_cfg['board_email'] . "\nMessage-ID: <" . md5(uniqid(time())) . "@" . $bb_cfg['server_name'] . ">\nMIME-Version: 1.0\nContent-type: text/plain; charset=" . $this->encoding . "\nContent-transfer-encoding: 8bit\nDate: " . date('r', time()) . "\nX-Priority: 0\nX-MSMail-Priority: Normal\nX-Mailer: Microsoft Office Outlook, Build 11.0.5510\nX-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1441\nX-Sender: " . $bb_cfg['board_email'] . "\n" . $this->extra_headers . (($cc != '') ? "Cc: $cc\n" : '') . (($bcc != '') ? "Bcc: $bcc\n" : ''); + + // Send message ... removed $this->encode() from subject for time being + if ( $this->use_smtp ) + { + if ( !defined('SMTP_INCLUDED') ) + { + include(INC_DIR .'smtp.php'); + } + + $result = smtpmail($to, $this->subject, $this->msg, $this->extra_headers); + } + else + { + $empty_to_header = ($to == '') ? TRUE : FALSE; + $to = ($to == '') ? (($bb_cfg['sendmail_fix']) ? ' ' : 'Undisclosed-recipients:;') : $to; + + $result = @mail($to, $this->subject, preg_replace("#(?msg), $this->extra_headers); + + if (!$result && !$bb_cfg['sendmail_fix'] && $empty_to_header) + { + $to = ' '; + + bb_update_config(array('sendmail_fix' => 1)); + + $bb_cfg['sendmail_fix'] = 1; + $result = @mail($to, $this->subject, preg_replace("#(?msg), $this->extra_headers); + } + } + + // Did it work? + if (!$result) + { + message_die(GENERAL_ERROR, 'Failed sending email :: ' . (($this->use_smtp) ? 'SMTP' : 'PHP') . ' :: ' . $result, '', __LINE__, __FILE__); + } + + return true; + } + + // Encodes the given string for proper display for this encoding ... nabbed + // from php.net and modified. There is an alternative encoding method which + // may produce lesd output but it's questionable as to its worth in this + // scenario IMO + function encode($str) + { + if ($this->encoding == '') + { + return $str; + } + + // define start delimimter, end delimiter and spacer + $start = "=?$this->encoding?B?"; + $end = "?="; + + // encode the string and split it into chunks with spacers after each chunk + $str = base64_encode($str); + + return $start . $str . $end; + } + + // + // Attach files via MIME. + // + function attachFile($filename, $mimetype = "application/octet-stream", $szFromAddress, $szFilenameToDisplay) + { + global $lang; + $mime_boundary = "--==================_846811060==_"; + + $this->msg = '--' . $mime_boundary . "\nContent-Type: text/plain;\n\tcharset=\"" . $lang['CONTENT_ENCODING'] . "\"\n\n" . $this->msg; + + if ($mime_filename) + { + $filename = $mime_filename; + $encoded = $this->encode_file($filename); + } + + $fd = fopen($filename, "r"); + $contents = fread($fd, filesize($filename)); + + $this->mimeOut = "--" . $mime_boundary . "\n"; + $this->mimeOut .= "Content-Type: " . $mimetype . ";\n\tname=\"$szFilenameToDisplay\"\n"; + $this->mimeOut .= "Content-Transfer-Encoding: quoted-printable\n"; + $this->mimeOut .= "Content-Disposition: attachment;\n\tfilename=\"$szFilenameToDisplay\"\n\n"; + + if ( $mimetype == "message/rfc822" ) + { + $this->mimeOut .= "From: ".$szFromAddress."\n"; + $this->mimeOut .= "To: ".$this->emailAddress."\n"; + $this->mimeOut .= "Date: ".date("D, d M Y H:i:s") . " UT\n"; + $this->mimeOut .= "Reply-To:".$szFromAddress."\n"; + $this->mimeOut .= "Subject: ".$this->mailSubject."\n"; + // $this->mimeOut .= "X-Mailer: PHP/".phpversion()."\n"; + $this->mimeOut .= "X-Priority: 0\n"; + $this->mimeOut .= "X-Mailer: Microsoft Office Outlook, Build 11.0.5510\n"; + $this->mimeOut .= "X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1441\n"; + $this->mimeOut .= "X-Sender: " . $bb_cfg['board_email'] . " \n"; + $this->mimeOut .= "MIME-Version: 1.0\n"; + } + + $this->mimeOut .= $contents."\n"; + $this->mimeOut .= "--" . $mime_boundary . "--" . "\n"; + + return $out; + // added -- to notify email client attachment is done + } + + function getMimeHeaders($filename, $mime_filename="") + { + $mime_boundary = "--==================_846811060==_"; + + if ($mime_filename) + { + $filename = $mime_filename; + } + + $out = "MIME-Version: 1.0\n"; + $out .= "Content-Type: multipart/mixed;\n\tboundary=\"$mime_boundary\"\n\n"; + $out .= "This message is in MIME format. Since your mail reader does not understand\n"; + $out .= "this format, some or all of this message may not be legible."; + + return $out; + } + + // + // Split string by RFC 2045 semantics (76 chars per line, end with \r\n). + // + function myChunkSplit($str) + { + $stmp = $str; + $len = strlen($stmp); + $out = ""; + + while ($len > 0) + { + if ($len >= 76) + { + $out .= substr($stmp, 0, 76) . "\r\n"; + $stmp = substr($stmp, 76); + $len = $len - 76; + } + else + { + $out .= $stmp . "\r\n"; + $stmp = ""; + $len = 0; + } + } + return $out; + } + + // + // Split the specified file up into a string and return it + // + function encode_file($sourcefile) + { + if (is_readable(phpbb_realpath($sourcefile))) + { + $fd = fopen($sourcefile, "r"); + $contents = fread($fd, filesize($sourcefile)); + $encoded = $this->myChunkSplit(base64_encode($contents)); + fclose($fd); + } + + return $encoded; + } +} \ No newline at end of file diff --git a/upload/includes/functions.php b/upload/includes/functions.php new file mode 100644 index 000000000..0145ba91e --- /dev/null +++ b/upload/includes/functions.php @@ -0,0 +1,2978 @@ + $val); + } + foreach ($tracks as $key => $val) + { + $key = (int) $key; + $val++; + $curr_track_val = !empty($tracking_ary[$key]) ? $tracking_ary[$key] : 0; + + if ($val > max($curr_track_val, $user->data['user_lastvisit'])) + { + $tracking_ary[$key] = $val; + } + else + { + if ($curr_track_val < $user->data['user_lastvisit']) + { + unset($tracking_ary[$key]); + } + } + } + } + + $overflow = count($tracking_topics) + count($tracking_forums) - COOKIE_MAX_TRACKS; + + if ($overflow > 0) + { + arsort($tracking_ary); + for ($i=0; $i < $overflow; $i++) + { + array_pop($tracking_ary); + } + } + + if (array_diff($tracking_ary, $prev_tracking_ary)) + { + bb_setcookie($cookie_name, serialize($tracking_ary)); + } +} + +function get_last_read ($topic_id = 0, $forum_id = 0) +{ + global $tracking_topics, $tracking_forums, $user; + + $t = isset($tracking_topics[$topic_id]) ? $tracking_topics[$topic_id] : 0; + $f = isset($tracking_forums[$forum_id]) ? $tracking_forums[$forum_id] : 0; + return max($t, $f, $user->data['user_lastvisit']); +} + +function is_unread ($ref, $topic_id = 0, $forum_id = 0) +{ + return (!IS_GUEST && $ref > get_last_read($topic_id, $forum_id)); +} + +/** +* Datastore +*/ +class datastore_common +{ + /** + * Директория с builder-скриптами (внутри INC_DIR) + */ + var $ds_dir = 'datastore/'; + /** + * Готовая к употреблению data + * array('title' => data) + */ + var $data = array(); + /** + * Список элементов, которые будут извлечены из хранилища при первом же запросе get() + * до этого момента они ставятся в очередь $queued_items для дальнейшего извлечения _fetch()'ем + * всех элементов одним запросом + * array('title1', 'title2'...) + */ + var $queued_items = array(); + + /** + * 'title' => 'builder script name' inside "includes/datastore" dir + */ + var $known_items = array( + 'cat_forums' => 'build_cat_forums.php', + 'jumpbox' => 'build_cat_forums.php', + 'viewtopic_forum_select' => 'build_cat_forums.php', + 'latest_news' => 'build_cat_forums.php', + 'ads' => 'build_cat_forums.php', + 'moderators' => 'build_moderators.php', + 'stats' => 'build_stats.php', + 'ranks' => 'build_ranks.php', + 'attach_extensions' => 'build_attach_extensions.php', + 'smile_replacements' => 'build_smilies.php', + ); + + /** + * Constructor + */ + function datastore_common () {} + + /** + * @param array(item1_title, item2_title...) or single item's title + */ + function enqueue ($items) + { + foreach ((array) $items as $item) + { + // игнор уже поставленного в очередь либо уже извлеченного + if (!in_array($item, $this->queued_items) && !isset($this->data[$item])) + { + $this->queued_items[] = $item; + } + } + } + + function &get ($title) + { +# if (in_array(BB_SCRIPT, array('forum', 'topic', 'ajax'))) bb_log(' ', "ds/". BB_SCRIPT ."/$title"); + + if (!isset($this->data[$title])) + { + $this->enqueue($title); + $this->_fetch(); + } + return $this->data[$title]; + } + + function store ($item_name, $item_data) {} + + function rm ($items) + { + foreach ((array) $items as $item) + { + unset($this->data[$item]); + } + } + + function update ($items) + { + if ($items == 'all') + { + $items = array_keys(array_unique($this->known_items)); + } + foreach ((array) $items as $item) + { + $this->_build_item($item); + } + } + + function _fetch () + { + $this->_fetch_from_store(); + + foreach ($this->queued_items as $title) + { + if (!isset($this->data[$title]) || $this->data[$title] === false) + { + $this->_build_item($title); + } + } + + $this->queued_items = array(); + } + + function _fetch_from_store () {} + + function _build_item ($title) + { + if (!empty($this->known_items[$title])) + { + require(INC_DIR . $this->ds_dir . $this->known_items[$title]); + } + else + { + trigger_error("Unknown datastore item: $title", E_USER_ERROR); + } + } +} + +class datastore_mysql extends datastore_common +{ + var $engine = 'MySQL'; + + function store ($item_name, $item_data) + { + $this->data[$item_name] = $item_data; + + $args = DB()->build_array('INSERT', array( + 'ds_title' => (string) $item_name, + 'ds_data' => (string) serialize($item_data), + )); + DB()->query("REPLACE INTO ". BB_DATASTORE . $args); + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) return; + + array_deep($items, 'mysql_escape_string'); + $items_list = join("','", $items); + + $sql = "SELECT ds_title, ds_data FROM ". BB_DATASTORE ." WHERE ds_title IN('$items_list')"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $this->data[$row['ds_title']] = unserialize($row['ds_data']); + } + } +} + +class datastore_memcache extends datastore_common +{ + var $engine = 'memcache'; + var $cfg = array(); + + function datastore_memcache ($cfg) + { + $this->cfg = $cfg; + } + + function store ($item_name, $item_data) + { + $this->data[$item_name] = $item_data; +# bb_log(join("\t", array(date('H:i:s'), $item_name, @basename($_SERVER['REQUEST_URI'])))."\n", 'ds_store'); + + foreach ($this->cfg['srv_all'] as $ds_srv) + { + CACHE($ds_srv)->set($item_name, $item_data, 604800, 'ds_'); + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) return; + + foreach (CACHE($this->cfg['srv_loc'])->get($items, '', 'ds_') as $item_name => $item_val) + { + $this->data[$item_name] = $item_val; + } + } +} + +class datastore_sqlite extends datastore_common +{ + var $engine = 'SQLite'; + var $db = null; + var $cfg = array(); + + function datastore_sqlite ($cfg) + { + $this->cfg = $cfg; + $this->db = new sqlite_common($cfg); + } + + function store ($item_name, $item_data) + { + $this->data[$item_name] = $item_data; +# bb_log(join("\t", array(date('H:i:s'), $item_name, @basename($_SERVER['REQUEST_URI'])))."\n", 'ds_store'); + + $ds_title = sqlite_escape_string($item_name); + $ds_data = sqlite_escape_string(serialize($item_data)); + + $result = $this->db->query("REPLACE INTO ". $this->cfg['table_name'] ." (ds_title, ds_data) VALUES ('$ds_title', '$ds_data')"); + + return (bool) $result; + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) return; + + array_deep($items, 'sqlite_escape_string'); + $items_list = join("','", $items); + + $rowset = $this->db->fetch_rowset("SELECT ds_title, ds_data FROM ". $this->cfg['table_name'] ." WHERE ds_title IN('$items_list')"); + + $this->db->debug('start', "unserialize()"); + foreach ($rowset as $row) + { + $this->data[$row['ds_title']] = unserialize($row['ds_data']); + } + $this->db->debug('stop'); + } +} + +class datastore_file extends datastore_common +{ + var $dir = null; + + function datastore_file ($dir) + { + $this->dir = $dir; + } + + function store ($title, $var) + { + $this->data[$title] = $var; + + $filename = $this->dir . clean_filename($title) . '.php'; + + $filecache = "'; + + return (bool) file_write($filecache, $filename, false, true, true); + } + + function clean () + { + $dir = $this->dir; + + if (is_dir($dir)) + { + if ($dh = opendir($dir)) + { + while (($file = readdir($dh)) !== false) + { + if ($file != "." && $file != "..") + { + $filename = $dir . $file; + + unlink($filename); + } + } + closedir($dh); + } + } + } + + function _fetch_from_store () + { + if (!$items = $this->queued_items) + { + $src = $this->_debug_find_caller('enqueue'); + trigger_error("Datastore: item '$item' already enqueued [$src]", E_USER_ERROR); + } + + foreach($items as $item) + { + $filename = $this->dir . $item . '.php'; + + if(file_exists($filename)) + { + require($filename); + + $this->data[$item] = $filestore; + } + } + } +} + +// +// Ads +// +class ads_common +{ + var $ad_blocks = array(); + var $active_ads = array(); + + /** + * Constructor + */ + function ads_common () + { + global $bb_cfg; + + $this->ad_blocks =& $bb_cfg['ad_blocks']; + $this->active_ads = !empty($bb_cfg['active_ads']) ? unserialize($bb_cfg['active_ads']) : array(); + } + + /** + * Get ads to show for each block + */ + function get ($block_types) + { + $ads = array(); + + if ($this->active_ads) + { + $block_ids = $this->get_block_ids($block_types); + + if ($ad_ids = $this->get_ad_ids($block_ids)) + { + $ad_html = $this->get_ads_html(); + + foreach ($ad_ids as $block_id => $ad_id) + { + $ads[$block_id] =& $ad_html[$ad_id]; + } + } + } + + return $ads; + } + + /** + * Get ads html + */ + function get_ads_html () + { + global $datastore; + if (!$ads_html = $datastore->get('ads')) + { + $datastore->update('ads'); + $ads_html = $datastore->get('ads'); + } + + return $ads_html; + } + + /** + * Get block_ids for specified block_types + */ + function get_block_ids ($block_types) + { + $block_ids = array(); + + foreach ($block_types as $block_type) + { + if ($blocks =& $this->ad_blocks[$block_type]) + { + $block_ids = array_merge($block_ids, array_keys($blocks)); + } + } + + return $block_ids; + } + + /** + * Get ad_ids for specified blocks + */ + function get_ad_ids ($block_ids) + { + $ad_ids = array(); + + foreach ($block_ids as $block_id) + { + if ($ads =& $this->active_ads[$block_id]) + { + shuffle($ads); + $ad_ids[$block_id] = $ads[0]; + } + } + + return $ad_ids; + } +} + +// +// Auth +// +define('AUTH_LIST_ALL', 0); + +// forum's ACL types (phpbb_forums: auth_view, auth_read... values) +# 'AUTH_ALL' 0 +define('AUTH_REG', 1); +define('AUTH_ACL', 2); +# 'AUTH_MOD' 3 +define('AUTH_ADMIN', 5); + +// forum_perm bitfields - backward compatible with auth($type) +define('AUTH_ALL', 0); +define('AUTH_VIEW', 1); +define('AUTH_READ', 2); +define('AUTH_MOD', 3); +define('AUTH_POST', 4); +define('AUTH_REPLY', 5); +define('AUTH_EDIT', 6); +define('AUTH_DELETE', 7); +define('AUTH_STICKY', 8); +define('AUTH_ANNOUNCE', 9); +define('AUTH_VOTE', 10); +define('AUTH_POLLCREATE', 11); +define('AUTH_ATTACH', 12); +define('AUTH_DOWNLOAD', 13); + +define('BF_AUTH_MOD', bit2dec(AUTH_MOD)); + +// When defining user permissions, take into account: +define('UG_PERM_BOTH', 1); // both user and group +define('UG_PERM_USER_ONLY', 2); // only personal user permissions +define('UG_PERM_GROUP_ONLY', 3); // only group permissions + +$bf['forum_perm'] = array( + 'auth_view' => AUTH_VIEW, + 'auth_read' => AUTH_READ, + 'auth_mod' => AUTH_MOD, + 'auth_post' => AUTH_POST, + 'auth_reply' => AUTH_REPLY, + 'auth_edit' => AUTH_EDIT, + 'auth_delete' => AUTH_DELETE, + 'auth_sticky' => AUTH_STICKY, + 'auth_announce' => AUTH_ANNOUNCE, + 'auth_vote' => AUTH_VOTE, + 'auth_pollcreate' => AUTH_POLLCREATE, + 'auth_attachments' => AUTH_ATTACH, + 'auth_download' => AUTH_DOWNLOAD, +); + +$bf['user_opt'] = array( + 'viewemail' => 0, + 'attachsig' => 1, + 'allowavatar' => 2, + 'allow_pm' => 3, + 'allow_viewonline' => 4, + 'notify' => 5, + 'notify_pm' => 6, + 'allow_passkey' => 7, + 'hide_porn_forums' => 8, + 'can_hide_ads' => 9, + 'hide_ads' => 10, +); + +function bit2dec ($bit_num) +{ + if (is_array($bit_num)) + { + $dec = 0; + foreach ($bit_num as $bit) + { + $dec |= (1 << $bit); + } + return $dec; + } + return (1 << $bit_num); +} + +function bf_bit2dec ($bf_array_name, $key) +{ + if (!isset($GLOBALS['bf'][$bf_array_name][$key])) + { + trigger_error(__FUNCTION__ .": bitfield '$key' not found", E_USER_ERROR); + } + return (1 << $GLOBALS['bf'][$bf_array_name][$key]); +} + +function bf ($int, $bf_array_name, $key) +{ + return (bf_bit2dec($bf_array_name, $key) & (int) $int); +} + +function setbit (&$int, $bit_num, $on) +{ + return ($on) ? $int |= (1 << $bit_num) : $int &= ~(1 << $bit_num); +} + +/* + $type's accepted (pre-pend with AUTH_): + VIEW, READ, POST, REPLY, EDIT, DELETE, STICKY, ANNOUNCE, VOTE, POLLCREATE + + Possible options ($type/forum_id combinations): + + * If you include a type and forum_id then a specific lookup will be done and + the single result returned + + * If you set type to AUTH_ALL and specify a forum_id an array of all auth types + will be returned + + * If you provide a forum_id a specific lookup on that forum will be done + + * If you set forum_id to AUTH_LIST_ALL and specify a type an array listing the + results for all forums will be returned + + * If you set forum_id to AUTH_LIST_ALL and type to AUTH_ALL a multidimensional + array containing the auth permissions for all types and all forums for that + user is returned + + All results are returned as associative arrays, even when a single auth type is + specified. + + If available you can send an array (either one or two dimensional) containing the + forum auth levels, this will prevent the auth function having to do its own + lookup +*/ +function auth ($type, $forum_id, $ug_data, $f_access = array(), $group_perm = UG_PERM_BOTH) +{ + global $lang, $bf, $datastore; + + $is_guest = true; + $is_admin = false; + $auth = $auth_fields = $u_access = array(); + $add_auth_type_desc = ($forum_id != AUTH_LIST_ALL); + + // + // Get $auth_fields + // + if ($type == AUTH_ALL) + { + $auth_fields = array_keys($bf['forum_perm']); + } + else if ($auth_type = array_search($type, $bf['forum_perm'])) + { + $auth_fields = array($auth_type); + } + + if (empty($auth_fields)) + { + trigger_error(__FUNCTION__ .'(): empty $auth_fields', E_USER_ERROR); + } + + // + // Get $f_access + // + // If f_access has been passed, or auth is needed to return an array of forums + // then we need to pull the auth information on the given forum (or all forums) + if (empty($f_access)) + { + if (!$forums = $datastore->get('cat_forums')) + { + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); + } + + if ($forum_id == AUTH_LIST_ALL) + { + $f_access = $forums['f']; + } + else if (isset($forums['f'][$forum_id])) + { + $f_access[$forum_id] = $forums['f'][$forum_id]; + } + } + else if (isset($f_access['forum_id'])) + { + // Change passed $f_access format for later using in foreach() + $f_access = array($f_access['forum_id'] => $f_access); + } + + if (empty($f_access)) + { + trigger_error(__FUNCTION__ .'(): empty $f_access', E_USER_ERROR); + } + + // + // Get user or group permissions + // + $forum_match_sql = ($forum_id != AUTH_LIST_ALL) ? "AND aa.forum_id = ". (int) $forum_id : ''; + + // GROUP mode + if (!empty($ug_data['group_id'])) + { + $is_guest = false; + $is_admin = false; + + $sql = "SELECT aa.forum_id, aa.forum_perm + FROM ". BB_AUTH_ACCESS ." aa + WHERE aa.group_id = ". (int) $ug_data['group_id'] ." + $forum_match_sql"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $u_access[$row['forum_id']] = $row['forum_perm']; + } + } + // USER mode + else if (!empty($ug_data['user_id'])) + { + $is_guest = empty($ug_data['session_logged_in']); + $is_admin = (!$is_guest && $ug_data['user_level'] == ADMIN); + + if ($group_perm != UG_PERM_BOTH) + { + $group_single_user = ($group_perm == UG_PERM_USER_ONLY) ? 1 : 0; + + $sql = " + SELECT + aa.forum_id, BIT_OR(aa.forum_perm) AS forum_perm + FROM + ". BB_USER_GROUP ." ug, + ". BB_GROUPS ." g, + ". BB_AUTH_ACCESS ." aa + WHERE + ug.user_id = ". (int) $ug_data['user_id'] ." + AND ug.user_pending = 0 + AND g.group_id = ug.group_id + AND g.group_single_user = $group_single_user + AND aa.group_id = g.group_id + $forum_match_sql + GROUP BY aa.forum_id + "; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $u_access[$row['forum_id']] = $row['forum_perm']; + } + } + else + { + if (!$is_guest && !$is_admin) + { + $sql = "SELECT SQL_CACHE aa.forum_id, aa.forum_perm + FROM ". BB_AUTH_ACCESS_SNAP ." aa + WHERE aa.user_id = ". (int) $ug_data['user_id'] ." + $forum_match_sql"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $u_access[$row['forum_id']] = $row['forum_perm']; + } + } + } + } + + // 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 + // + foreach ($f_access as $f_id => $f_data) + { + $auth[$f_id]['auth_mod'] = auth_check('forum_perm', 'auth_mod', $u_access, $f_id, $is_admin); + + foreach ($auth_fields as $auth_type) + { + if (!isset($f_data[$auth_type])) + { + continue; + } + switch ($f_data[$auth_type]) + { + case AUTH_ALL: + $auth[$f_id][$auth_type] = true; + break; + + case AUTH_REG: + $auth[$f_id][$auth_type] = !$is_guest; + break; + + case AUTH_ACL: + $auth[$f_id][$auth_type] = (auth_check('forum_perm', $auth_type, $u_access, $f_id, $is_admin) || $auth[$f_id]['auth_mod']); + break; + + case AUTH_MOD: + $auth[$f_id][$auth_type] = $auth[$f_id]['auth_mod']; + break; + + case AUTH_ADMIN: + $auth[$f_id][$auth_type] = $is_admin; + break; + + default: + $auth[$f_id][$auth_type] = false; + } + if ($add_auth_type_desc) + { + $auth[$f_id][$auth_type .'_type'] =& $lang['AUTH_TYPES'][$f_data[$auth_type]]; + } + } + } + + return ($forum_id == AUTH_LIST_ALL) ? $auth : $auth[$forum_id]; +} + +function auth_check ($bf_ary, $bf_key, $perm_ary, $perm_key, $is_admin = false) +{ + if ($is_admin) return true; + if (!isset($perm_ary[$perm_key])) return false; + + return bf($perm_ary[$perm_key], $bf_ary, $bf_key); +} + +class Date_Delta +{ + var $auto_granularity = array( + 60 => 'seconds', // set granularity to "seconds" if delta less then 1 minute + 10800 => 'minutes', // 3 hours + 259200 => 'hours', // 3 days + 15681600 => 'mday', // 6 months + 1d+12h + 311040000 => 'mon', // 10 years + ); + var $intervals = array(); + var $format = ''; + + // Creates new object. + function Date_Delta() + { + global $lang; + + $this->intervals = $lang['DELTA_TIME']['INTERVALS']; + $this->format = $lang['DELTA_TIME']['FORMAT']; + } + + // Makes the spellable phrase. + function spellDelta($first, $last, $from = 'auto') + { + if ($last < $first) + { + $old_first = $first; + $first = $last; + $last = $old_first; + } + + if ($from == 'auto') + { + $from = 'year'; + $diff = $last - $first; + foreach ($this->auto_granularity as $seconds_count => $granule) + { + if ($diff < $seconds_count) + { + $from = $granule; + break; + } + } + } + + // Solve data delta. + $delta = $this->getDelta($first, $last); + if (!$delta) return false; + + // Make spellable phrase. + $parts = array(); + $intervals = $GLOBALS['lang']['DELTA_TIME']['INTERVALS']; + + foreach (array_reverse($delta) as $k => $n) + { + if (!$n) + { + if ($k == $from) + { + if (!$parts) + { + $parts[] = declension($n, $this->intervals[$k], $this->format); + } + break; + } + continue; + } + $parts[] = declension($n, $this->intervals[$k], $this->format); + if ($k == $from) break; + } + return join(' ', $parts); + } + + // returns the associative array with date deltas. + function getDelta($first, $last) + { + if ($last < $first) return false; + + // Solve H:M:S part. + $hms = ($last - $first) % (3600 * 24); + $delta['seconds'] = $hms % 60; + $delta['minutes'] = floor($hms/60) % 60; + $delta['hours'] = floor($hms/3600) % 60; + + // Now work only with date, delta time = 0. + $last -= $hms; + $f = getdate($first); + $l = getdate($last); // the same daytime as $first! + + $dYear = $dMon = $dDay = 0; + + // Delta day. Is negative, month overlapping. + $dDay += $l['mday'] - $f['mday']; + if ($dDay < 0) { + $monlen = $this->monthLength(date('Y', $first), date('m', $first)); + $dDay += $monlen; + $dMon--; + } + $delta['mday'] = $dDay; + + // Delta month. If negative, year overlapping. + $dMon += $l['mon'] - $f['mon']; + if ($dMon < 0) { + $dMon += 12; + $dYear --; + } + $delta['mon'] = $dMon; + + // Delta year. + $dYear += $l['year'] - $f['year']; + $delta['year'] = $dYear; + + return $delta; + } + + // Returns the length (in days) of the specified month. + function monthLength($year, $mon) + { + $l = 28; + while (checkdate($mon, $l+1, $year)) $l++; + return $l; + } +} + +function delta_time ($timestamp_1, $timestamp_2 = TIMENOW, $granularity = 'auto') +{ + return $GLOBALS['DeltaTime']->spellDelta($timestamp_1, $timestamp_2, $granularity); +} + +function get_select ($type) +{ + $select_ary = array(); + + switch ($type) + { + case 'groups': + + $sql = "SELECT group_id, group_name + FROM ". BB_GROUPS ." + WHERE group_single_user = 0 + ORDER BY group_name"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + if (isset($select_ary[$row['group_name']])) + { + $cnt = md5($row['group_name']) .'_cnt'; + $$cnt = @$$cnt + 1; + $row['group_name'] = $row['group_name'] . ' ['. (int) $$cnt .']'; + } + $select_ary[$row['group_name']] = $row['group_id']; + } + $select_name = POST_GROUPS_URL; + break; + } + return ($select_ary) ? build_select($select_name, $select_ary) : ''; +} + +class html_common +{ + var $options = ''; + var $attr = array(); + var $cur_attr = null; + var $max_length = HTML_SELECT_MAX_LENGTH; + var $selected = array(); + + function build_select ($name, $params, $selected = null, $max_length = HTML_SELECT_MAX_LENGTH, $multiple_size = null, $js = '') + { + if (empty($params)) return ''; + + $this->options = ''; + $this->selected = array_flip((array) $selected); + $this->max_length = $max_length; + + $this->attr = array(); + $this->cur_attr =& $this->attr; + + if (isset($params['__attributes'])) + { + $this->attr = $params['__attributes']; + unset($params['__attributes']); + } + + $this->_build_select_rec($params); + + $select_params = ($js) ? " $js" : ''; + $select_params .= ($multiple_size) ? ' multiple="multiple" size="'. $multiple_size .'"' : ''; + $select_params .= ' name="'. htmlCHR($name) .'"'; + $select_params .= ' id="'. htmlCHR($name) .'"'; + + return "\n\n"; + } + + function _build_select_rec ($params) + { + foreach ($params as $opt_name => $opt_val) + { + $opt_name = rtrim($opt_name); + + if (is_array($opt_val)) + { + $this->cur_attr =& $this->cur_attr[$opt_name]; + + $label = htmlCHR(str_short($opt_name, $this->max_length)); + + $this->options .= "\t\n"; + $this->_build_select_rec($opt_val); + $this->options .= "\t\n"; + + $this->cur_attr =& $this->attr; + } + else + { + $text = htmlCHR(str_short($opt_name, $this->max_length)); + $value = ' value="'. htmlCHR($opt_val) .'"'; + + $class = isset($this->cur_attr[$opt_name]['class']) ? ' class="'. $this->cur_attr[$opt_name]['class'] .'"' : ''; + $style = isset($this->cur_attr[$opt_name]['style']) ? ' style="'. $this->cur_attr[$opt_name]['style'] .'"' : ''; + + $selected = isset($this->selected[$opt_val]) ? HTML_SELECTED : ''; + $disabled = isset($this->cur_attr[$opt_name]['disabled']) ? HTML_DISABLED : ''; + + $this->options .= "\t\t '. $text ." \n"; + } + } + } + + function array2html ($array, $ul = 'ul', $li = 'li') + { + $this->out = ''; + $this->_array2html_rec($array, $ul, $li); + return "<$ul class=\"tree-root\">{$this->out}"; + } + + function _array2html_rec ($array, $ul, $li) + { + foreach ($array as $k => $v) + { + if (is_array($v)) + { + $this->out .= "<$li>$k<$ul>"; + $this->_array2html_rec($v, $ul, $li); + $this->out .= ""; + } + else + { + $this->out .= "<$li>$v"; + } + } + } + + // all arguments should be already htmlspecialchar()d (if needed) + function build_checkbox ($name, $title, $checked = false, $disabled = false, $class = null, $id = null, $value = 1) + { + $name = ' name="'. $name .'" '; + $value = ' value="'. $value .'" '; + $title = ($class) ? ''. $title .'' : $title; + $id = ($id) ? " id=\"$id\" " : ''; + $checked = ($checked) ? HTML_CHECKED : ''; + $disabled = ($disabled) ? HTML_DISABLED : ''; + + return ''; + } + +# function build_option ($opt_name, $opt_val, $selected = null, $max_length = false) +# { +# return "\t\t\n"; +# } + +# function build_optgroup ($label, $contents, $max_length = false) +# { +# return "\t\n". $contents ."\t\n"; +# } +} + +function build_select ($name, $params, $selected = null, $max_length = HTML_SELECT_MAX_LENGTH, $multiple_size = null, $js = '') +{ + return $GLOBALS['html']->build_select($name, $params, $selected, $max_length, $multiple_size, $js); +} + +function build_checkbox ($name, $title, $checked = false, $disabled = false, $class = null, $id = null, $value = 1) +{ + return $GLOBALS['html']->build_checkbox($name, $title, $checked, $disabled, $class, $id, $value); +} + +function replace_quote ($str, $double = true, $single = true) +{ + if ($double) $str = str_replace('"', '"', $str); + if ($single) $str = str_replace("'", ''', $str); + return $str; +} + +/** +* Build simple hidden fields from array +*/ +function build_hidden_fields ($fields_ary) +{ + $out = "\n"; + + foreach ($fields_ary as $name => $val) + { + if (is_array($val)) + { + foreach ($val as $ary_key => $ary_val) + { + $out .= '\n"; + } + } + else + { + $out .= '\n"; + } + } + + return $out; +} + +/** + * Choost russian word declension based on numeric [from dklab.ru] + * Example for $expressions: array("ответ", "ответа", "ответов") + */ +function declension ($int, $expressions, $format = '%1$s %2$s') +{ + if (!is_array($expressions)) + { + $expressions = $GLOBALS['lang']['DECLENSION'][strtoupper($expressions)]; + } + + if (count($expressions) < 3) + { + $expressions[2] = $expressions[1]; + } + $count = intval($int) % 100; + + if ($count >= 5 && $count <= 20) + { + $result = $expressions['2']; + } + else + { + $count = $count % 10; + if ($count == 1) + { + $result = $expressions['0']; + } + elseif ($count >= 2 && $count <= 4) + { + $result = $expressions['1']; + } + else + { + $result = $expressions['2']; + } + } + + return ($format) ? sprintf($format, $int, $result) : $result; +} + +// http://forum.dklab.ru/php/advises/UrlreplaceargChangesValueOfParameterInUrl.html +function url_arg ($url, $arg, $value, $amp = '&') +{ + $arg = preg_quote($arg, '/'); + + // разделяем URL и ANCHOR + $anchor = ''; + if (preg_match('/(.*)(#.*)/s', $url, $m)) + { + $url = $m[1]; + $anchor = $m[2]; + } + // заменяем параметр, если он существует + if (preg_match("/((\?|&|&)$arg=)[^&]*/s", $url, $m)) + { + $cur = $m[0]; + $new = is_null($value) ? '' : $m[1] . urlencode($value); + $url = str_replace($cur, $new, $url); + } + // добавляем параметр + else if (!is_null($value)) + { + $div = (strpos($url, '?') !== false) ? $amp : '?'; + $url = $url . $div . $arg .'='. urlencode($value); + } + return $url . $anchor; +} + +/** + * Adds commas between every group of thousands + */ +function commify ($number) +{ + return number_format($number); +} + +/** + * Returns a size formatted in a more human-friendly format, rounded to the nearest GB, MB, KB.. + */ +function humn_size ($size, $rounder = null, $min = null, $space = ' ') +{ + static $sizes = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + static $rounders = array(0, 0, 0, 2, 3, 3, 3, 3, 3); + + $size = (float) $size; + $ext = $sizes[0]; + $rnd = $rounders[0]; + + if ($min == 'KB' && $size < 1024) + { + $size = $size / 1024; + $ext = 'KB'; + $rounder = 1; + } + else + { + for ($i=1, $cnt=count($sizes); ($i < $cnt && $size >= 1024); $i++) + { + $size = $size / 1024; + $ext = $sizes[$i]; + $rnd = $rounders[$i]; + } + } + if (!$rounder) + { + $rounder = $rnd; + } + + return round($size, $rounder) . $space . $ext; +} + +function bt_show_ip ($ip, $port = '') +{ + global $bb_cfg; + + if (IS_MOD || IS_ADMIN) + { + $ip = decode_ip($ip); + $ip .= ($port) ? ":$port" : ''; + return $ip; + } + else + { + return ($bb_cfg['bt_show_ip_only_moder']) ? false : decode_ip_xx($ip); + } +} + +function bt_show_port ($port) +{ + global $bb_cfg; + + if (IS_MOD || IS_ADMIN) + { + return $port; + } + else + { + return ($bb_cfg['bt_show_port_only_moder']) ? false : $port; + } +} + +function decode_ip_xx ($ip) +{ + $h = explode('.', chunk_split($ip, 2, '.')); + return hexdec($h[0]) .'.'. hexdec($h[1]) .'.'. hexdec($h[2]) .'.xx'; +} + +function checkbox_get_val (&$key, &$val, $default = 1, $on = 1, $off = 0) +{ + global $previous_settings, $search_id; + + if (isset($_REQUEST[$key])) + { + $val = (int) $_REQUEST[$key]; + } + else if (!isset($_REQUEST[$key]) && isset($_REQUEST['prev_'. $key])) + { + $val = $off; + } + else if (isset($previous_settings[$key]) && (!IS_GUEST || !empty($search_id))) + { + $val = ($previous_settings[$key]) ? $on : $off; + } + else + { + $val = $default; + } +} + +function select_get_val ($key, &$val, $options_ary, $default, $num = true) +{ + global $previous_settings; + + if (isset($_REQUEST[$key])) + { + if (isset($options_ary[$_REQUEST[$key]])) + { + $val = ($num) ? intval($_REQUEST[$key]) : $_REQUEST[$key]; + } + } + else if (isset($previous_settings[$key])) + { + $val = $previous_settings[$key]; + } + else + { + $val = $default; + } +} + +/** +* set_var +* +* Set variable, used by {@link request_var the request_var function} +* +* @access private +*/ +function set_var(&$result, $var, $type, $multibyte = false, $strip = true) +{ + settype($var, $type); + $result = $var; + + if ($type == 'string') + { + $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r"), array("\n", "\n"), $result))); + + if (!empty($result)) + { + // Make sure multibyte characters are wellformed + if ($multibyte) + { + if (!preg_match('/^./u', $result)) + { + $result = ''; + } + } + } + + $result = ($strip) ? stripslashes($result) : $result; + } +} +/** +* request_var +* +* Used to get passed variable +*/ +function request_var($var_name, $default, $multibyte = false, $cookie = false) +{ + if (!$cookie && isset($_COOKIE[$var_name])) + { + if (!isset($_GET[$var_name]) && !isset($_POST[$var_name])) + { + return (is_array($default)) ? array() : $default; + } + $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name]; + } + + if (!isset($_REQUEST[$var_name]) || (is_array($_REQUEST[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($_REQUEST[$var_name]))) + { + return (is_array($default)) ? array() : $default; + } + + $var = $_REQUEST[$var_name]; + if (!is_array($default)) + { + $type = gettype($default); + } + else + { + list($key_type, $type) = each($default); + $type = gettype($type); + $key_type = gettype($key_type); + if ($type == 'array') + { + reset($default); + $default = current($default); + list($sub_key_type, $sub_type) = each($default); + $sub_type = gettype($sub_type); + $sub_type = ($sub_type == 'array') ? 'NULL' : $sub_type; + $sub_key_type = gettype($sub_key_type); + } + } + + if (is_array($var)) + { + $_var = $var; + $var = array(); + + foreach ($_var as $k => $v) + { + set_var($k, $k, $key_type); + if ($type == 'array' && is_array($v)) + { + foreach ($v as $_k => $_v) + { + if (is_array($_v)) + { + $_v = null; + } + set_var($_k, $_k, $sub_key_type); + set_var($var[$k][$_k], $_v, $sub_type, $multibyte); + } + } + else + { + if ($type == 'array' || is_array($v)) + { + $v = null; + } + set_var($var[$k], $v, $type, $multibyte); + } + } + } + else + { + set_var($var, $var, $type, $multibyte); + } + + return $var; +} + +function get_username ($user_id) +{ + if (empty($user_id)) return false; + $row = DB()->fetch_row("SELECT username FROM ". BB_USERS ." WHERE user_id = $user_id LIMIT 1"); + return $row['username']; +} + +function get_user_id ($username) +{ + if (empty($username)) return false; + $row = DB()->fetch_row("SELECT user_id FROM ". BB_USERS ." WHERE username = '$username' LIMIT 1"); + return $row['user_id']; +} + +function str_short ($text, $max_length, $space = ' ') +{ + if ($max_length && strlen($text) > $max_length) + { + $text = mb_substr($text, 0, $max_length); + + if ($last_space_pos = $max_length - intval(strpos(strrev($text), $space))) + { + if ($last_space_pos > round($max_length * 3/4)) + { + $last_space_pos--; + $text = mb_substr($text, 0, $last_space_pos); + } + } + $text .= '...'; + $text = preg_replace('!&#?(\w+)?;?(\w{1,5})?\.\.\.$!', '...', $text); + } + + return $text; +} + +function wbr ($text, $max_word_length = HTML_WBR_LENGTH) +{ + return preg_replace("/([\w\->;:.,~!?(){}@#$%^*\/\\\\]{". $max_word_length ."})/ui", '$1', $text); +} + +function get_bt_userdata ($user_id) +{ + return DB()->fetch_row("SELECT * FROM ". BB_BT_USERS ." WHERE user_id = ". (int) $user_id ." LIMIT 1"); +} + +function get_bt_ratio ($btu) +{ + return + (!empty($btu['u_down_total']) && $btu['u_down_total'] > MIN_DL_FOR_RATIO) + ? round((($btu['u_up_total'] + $btu['u_up_release'] + $btu['u_up_bonus']) / $btu['u_down_total']), 2) + : null + ; +} + +function show_bt_userdata ($user_id) +{ + $btu = get_bt_userdata($user_id); + + $GLOBALS['template']->assign_vars(array( + 'SHOW_BT_USERDATA' => true, + 'UP_TOTAL' => humn_size($btu['u_up_total']), + 'UP_BONUS' => humn_size($btu['u_up_bonus']), + 'RELEASED' => humn_size($btu['u_up_release']), + 'DOWN_TOTAL' => humn_size($btu['u_down_total']), + 'DOWN_TOTAL_BYTES' => $btu['u_down_total'], + 'USER_RATIO' => get_bt_ratio($btu), + 'MIN_DL_FOR_RATIO' => humn_size(MIN_DL_FOR_RATIO), + 'MIN_DL_BYTES' => MIN_DL_FOR_RATIO, + 'AUTH_KEY' => $btu['auth_key'], + )); +} + +function get_attachments_dir ($cfg = null) +{ + if (!$cfg AND !$cfg = $GLOBALS['attach_config']) + { + $cfg = bb_get_config(BB_ATTACH_CONFIG, true, false); + } + + if (!$cfg['allow_ftp_upload']) + { + if ($cfg['upload_dir'][0] == '/' || ($cfg['upload_dir'][0] != '/' && $cfg['upload_dir'][1] == ':')) + { + return $cfg['upload_dir']; + } + else + { + return BB_ROOT . $cfg['upload_dir']; + } + } + else + { + return $cfg['download_path']; + } +} + +function bb_get_config ($table, $from_db = false, $update_cache = true) +{ + if ($from_db OR !$cfg = CACHE('bb_cache')->get("config_{$table}")) + { + $cfg = array(); + foreach (DB()->fetch_rowset("SELECT * FROM $table") as $row) + { + $cfg[$row['config_name']] = $row['config_value']; + } + if ($update_cache) + { + CACHE('bb_cache')->set("config_{$table}", $cfg); + } + } + return $cfg; +} + +function bb_update_config ($params, $table = BB_CONFIG) +{ + $updates = array(); + foreach ($params as $name => $val) + { + $updates[] = array( + 'config_name' => $name, + 'config_value' => $val, + ); + } + $updates = DB()->build_array('MULTI_INSERT', $updates); + + DB()->query("REPLACE INTO $table $updates"); + // Update cache + bb_get_config($table, true, true); +} + +function get_db_stat($mode) +{ + switch( $mode ) + { + case 'usercount': + $sql = "SELECT COUNT(user_id) AS total + FROM " . BB_USERS; + break; + + case 'newestuser': + $sql = "SELECT user_id, username + FROM " . BB_USERS . " + WHERE user_id <> " . ANONYMOUS . " + ORDER BY user_id DESC + LIMIT 1"; + break; + + case 'postcount': + case 'topiccount': + $sql = "SELECT SUM(forum_topics) AS topic_total, SUM(forum_posts) AS post_total + FROM " . BB_FORUMS; + break; + } + + if ( !($result = DB()->sql_query($sql)) ) + { + return false; + } + + $row = DB()->sql_fetchrow($result); + + switch ( $mode ) + { + case 'usercount': + return $row['total']; + break; + case 'newestuser': + return $row; + break; + case 'postcount': + return $row['post_total']; + break; + case 'topiccount': + return $row['topic_total']; + break; + } + + return false; +} + +// added at phpBB 2.0.11 to properly format the username +function clean_username($username) +{ + $username = mb_substr(htmlspecialchars(str_replace("\'", "'", trim($username))), 0, 25, 'UTF-8'); + $username = phpbb_rtrim($username, "\\"); + $username = str_replace("'", "\'", $username); + + return $username; +} + +/** +* This function is a wrapper for ltrim, as charlist is only supported in php >= 4.1.0 +* Added in phpBB 2.0.18 +*/ +function phpbb_ltrim($str, $charlist = false) +{ + if ($charlist === false) + { + return ltrim($str); + } + + $php_version = explode('.', PHP_VERSION); + + // php version < 4.1.0 + if ((int) $php_version[0] < 4 || ((int) $php_version[0] == 4 && (int) $php_version[1] < 1)) + { + while ($str{0} == $charlist) + { + $str = substr($str, 1); + } + } + else + { + $str = ltrim($str, $charlist); + } + + return $str; +} + +// added at phpBB 2.0.12 to fix a bug in PHP 4.3.10 (only supporting charlist in php >= 4.1.0) +function phpbb_rtrim($str, $charlist = false) +{ + if ($charlist === false) + { + return rtrim($str); + } + + $php_version = explode('.', PHP_VERSION); + + // php version < 4.1.0 + if ((int) $php_version[0] < 4 || ((int) $php_version[0] == 4 && (int) $php_version[1] < 1)) + { + while ($str{strlen($str)-1} == $charlist) + { + $str = substr($str, 0, strlen($str)-1); + } + } + else + { + $str = rtrim($str, $charlist); + } + + return $str; +} + +// +// Get Userdata, $u can be username or user_id. If force_str is true, the username will be forced. +// +function get_userdata ($u, $force_name = false, $allow_anon = false) +{ + if (!$u) return false; + + if (intval($u) == ANONYMOUS && $allow_anon) + { + if ($userdata = CACHE('bb_cache')->get('anonymous_userdata')) + { + return $userdata; + } + } + + $userdata = array(); + $name_search = false; + $anon_sql = (!$allow_anon) ? "AND user_id != ". ANONYMOUS : ''; + + if ($force_name || !is_numeric($u)) + { + $name_search = true; + $where_sql = "WHERE username = '". clean_username($u) ."'"; + } + else + { + $where_sql = "WHERE user_id = ". (int) $u; + } + + $sql = "SELECT * FROM ". BB_USERS ." $where_sql $anon_sql LIMIT 1"; + + if (!$userdata = DB()->fetch_row($sql)) + { + if (!is_int($u) && !$name_search) + { + $where_sql = "WHERE username = '". clean_username($u) ."'"; + $sql = "SELECT * FROM ". BB_USERS ." $where_sql $anon_sql LIMIT 1"; + $userdata = DB()->fetch_row($sql); + } + } + + if ($userdata['user_id'] == ANONYMOUS) + { + CACHE('bb_cache')->set('anonymous_userdata', $userdata); + } + + return $userdata; +} + +function make_jumpbox ($selected = 0) +{ + global $datastore, $template; + + if (!$jumpbox = $datastore->get('jumpbox')) + { + $datastore->update('jumpbox'); + $jumpbox = $datastore->get('jumpbox'); + } + + $template->assign_vars(array( + 'JUMPBOX' => (IS_GUEST) ? $jumpbox['guest'] : $jumpbox['user'], + )); +} + +function make_user_flag($country_code) +{ + global $lang; + + if(!defined('COUNTRIES_LANG')) + { + include(LANG_DIR . "lang_countries.php"); + } + + $title = $lang['COUNTRIES'][$country_code]; + return "\"{$title}\"
    "; +} + +// $mode: array(not_auth_forum1,not_auth_forum2,..) or (string) 'mode' +function get_forum_select ($mode = 'guest', $name = POST_FORUM_URL, $selected = null, $max_length = HTML_SELECT_MAX_LENGTH, $multiple_size = null, $js = '', $all_forums_option = null) +{ + global $lang, $datastore; + + if (is_array($mode)) + { + $not_auth_forums_fary = array_flip($mode); + $mode = 'not_auth_forums'; + } + if (is_null($max_length)) + { + $max_length = HTML_SELECT_MAX_LENGTH; + } + $select = is_null($all_forums_option) ? array() : array($lang['ALL_AVAILABLE'] => $all_forums_option); + if (!$forums = $datastore->get('cat_forums')) + { + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); + } + + foreach ($forums['f'] as $fid => $f) + { + switch ($mode) + { + case 'guest': + if ($f['auth_view'] != AUTH_ALL) continue 2; + break; + + case 'user': + if ($f['auth_view'] != AUTH_ALL && $f['auth_view'] != AUTH_REG) continue 2; + break; + + case 'not_auth_forums': + if (isset($not_auth_forums_fary[$f['forum_id']])) continue 2; + break; + + case 'admin': + break; + + default: + trigger_error(__FUNCTION__ .": invalid mode '$mode'", E_USER_ERROR); + } + $cat_title = $forums['c'][$f['cat_id']]['cat_title']; + $f_name = ($f['forum_parent']) ? ' |- ' : ''; + $f_name .= $f['forum_name']; + + while (isset($select[$cat_title][$f_name])) + { + $f_name .= ' '; + } + + $select[$cat_title][$f_name] = $fid; + + if (!$f['forum_parent']) + { + $class = 'root_forum'; + $class .= isset($f['subforums']) ? ' has_sf' : ''; + $select['__attributes'][$cat_title][$f_name]['class'] = $class; + } + } + + return build_select($name, $select, $selected, $max_length, $multiple_size, $js); +} + +function setup_style () +{ + global $bb_cfg, $template; + + // AdminCP works only with default template + $tpl_dir_name = defined('IN_ADMIN') ? 'default' : basename($bb_cfg['tpl_name']); + $stylesheet = defined('IN_ADMIN') ? 'main.css' : basename($bb_cfg['stylesheet']); + $theme_css = defined('IN_ADMIN') ? 'admin.css' : basename($bb_cfg['theme_css']); + + $template = new Template(TEMPLATES_DIR . $tpl_dir_name); + $css_dir = BB_ROOT . basename(TEMPLATES_DIR) ."/$tpl_dir_name/css/"; + + $template->assign_vars(array( + 'BB_ROOT' => BB_ROOT, + 'SPACER' => BB_ROOT .'images/spacer.gif', + 'STYLESHEET' => $css_dir . $stylesheet, + 'THEME_CSS' => ($theme_css) ? $css_dir . $theme_css : '', + 'DBG_CSS' => $css_dir . 'dbg.css', + 'EXT_LINK_NEW_WIN' => $bb_cfg['ext_link_new_win'], + )); + + require(TEMPLATES_DIR . $tpl_dir_name .'/tpl_config.php'); + + $theme = array('template_name' => $tpl_dir_name); + + return $theme; +} + +// Create date/time from format and timezone +function bb_date ($gmepoch, $format = false, $tz = null) +{ + global $bb_cfg, $lang; + + if (is_null($tz)) + { + $tz = $bb_cfg['board_timezone']; + } + if (!$format) + { + $format = $bb_cfg['default_dateformat']; + } + $date = gmdate($format, $gmepoch + (3600 * $tz)); + + return ($bb_cfg['translate_dates']) ? strtr(strtoupper($date), $lang['DATETIME']) : $date; +} + +// +// Pagination routine, generates +// page number sequence +// +function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = TRUE) +{ + global $lang; + +// Pagination Mod + $begin_end = 3; + $from_middle = 1; +/* + By default, $begin_end is 3, and $from_middle is 1, so on page 6 in a 12 page view, it will look like this: + + a, d = $begin_end = 3 + b, c = $from_middle = 1 + + "begin" "middle" "end" + | | | + | a b | c d | + | | | | | | | + v v v v v v v + 1, 2, 3 ... 5, 6, 7 ... 10, 11, 12 + + Change $begin_end and $from_middle to suit your needs appropriately +*/ + + $total_pages = ceil($num_items/$per_page); + + if ( $total_pages == 1 ) + { + return ''; + } + + $on_page = floor($start_item / $per_page) + 1; + + $page_string = ''; + if ( $total_pages > ((2*($begin_end + $from_middle)) + 2) ) + { + $init_page_max = ( $total_pages > $begin_end ) ? $begin_end : $total_pages; + for($i = 1; $i < $init_page_max + 1; $i++) + { + $page_string .= ( $i == $on_page ) ? '' . $i . '' : '' . $i . ''; + if ( $i < $init_page_max ) + { + $page_string .= ", "; + } + } + if ( $total_pages > $begin_end ) + { + if ( $on_page > 1 && $on_page < $total_pages ) + { + $page_string .= ( $on_page > ($begin_end + $from_middle + 1) ) ? ' ... ' : ', '; + + $init_page_min = ( $on_page > ($begin_end + $from_middle) ) ? $on_page : ($begin_end + $from_middle + 1); + + $init_page_max = ( $on_page < $total_pages - ($begin_end + $from_middle) ) ? $on_page : $total_pages - ($begin_end + $from_middle); + + for($i = $init_page_min - $from_middle; $i < $init_page_max + ($from_middle + 1); $i++) + { + $page_string .= ($i == $on_page) ? '' . $i . '' : '' . $i . ''; + if ( $i < $init_page_max + $from_middle ) + { + $page_string .= ', '; + } + } + $page_string .= ( $on_page < $total_pages - ($begin_end + $from_middle) ) ? ' ... ' : ', '; + } + else + { + $page_string .= ' ... '; + } + for($i = $total_pages - ($begin_end - 1); $i < $total_pages + 1; $i++) + { + $page_string .= ( $i == $on_page ) ? '' . $i . '' : '' . $i . ''; + if( $i < $total_pages ) + { + $page_string .= ", "; + } + } + } + } + else + { + for($i = 1; $i < $total_pages + 1; $i++) + { + $page_string .= ( $i == $on_page ) ? '' . $i . '' : '' . $i . ''; + if ( $i < $total_pages ) + { + $page_string .= ', '; + } + } + } + + if ( $add_prevnext_text ) + { + if ( $on_page > 1 ) + { + $page_string = ' ' . $lang['PREVIOUS'] . '  ' . $page_string; + } + + if ( $on_page < $total_pages ) + { + $page_string .= '  ' . $lang['NEXT'] . ''; + } + + } + + $return = ($page_string) ? $lang['GOTO_PAGE'] .':  '. $page_string : ''; + + return str_replace('&start=0', '', $return); +} + +// +// This does exactly what preg_quote() does in PHP 4-ish +// If you just need the 1-parameter preg_quote call, then don't bother using this. +// +function phpbb_preg_quote($str, $delimiter) +{ + $text = preg_quote($str); + $text = str_replace($delimiter, '\\' . $delimiter, $text); + + return $text; +} + +// +// Obtain list of naughty words and build preg style replacement arrays for use by the +// calling script, note that the vars are passed as references this just makes it easier +// to return both sets of arrays +// +function obtain_word_list(&$orig_word, &$replacement_word) +{ + global $bb_cfg; + + if (!$bb_cfg['use_word_censor']) return; + + if (!$sql = CACHE('bb_cache')->get('censored')) + { + $sql = DB()->fetch_rowset("SELECT word, replacement FROM ". BB_WORDS); + CACHE('bb_cache')->set('censored', $sql, 7200); + } + foreach($sql as $row) + { + //$orig_word[] = '#(? strlen($b['code'])) ? -1 : 1; +} + +// +// This is general replacement for die(), allows templated +// output in users (or default) language, etc. +// +// $msg_code can be one of these constants: +// +// GENERAL_MESSAGE : Use for any simple text message, eg. results +// of an operation, authorisation failures, etc. +// +// GENERAL ERROR : Use for any error which occurs _AFTER_ the +// common.php include and session code, ie. most errors in +// pages/functions +// +// CRITICAL_MESSAGE : Used when basic config data is available but +// a session may not exist, eg. banned users +// +// CRITICAL_ERROR : Used when config data cannot be obtained, eg +// no database connection. Should _not_ be used in 99.5% of cases +// +function bb_die ($msg_text, $msg_code = GENERAL_MESSAGE, $msg_title = '') +{ + if (defined('IN_AJAX')) + { + ajax_die($msg_text, $msg_code); + } + message_die($msg_code, $msg_text, $msg_title); +} + +function ajax_die ($msg_text, $msg_code = E_AJAX_GENERAL_ERROR) +{ + $GLOBALS['ajax']->ajax_die($msg_text, $msg_code); +} + +function message_die ($msg_code, $msg_text = '', $msg_title = '', $err_line = '', $err_file = '', $sql = '') +{ + global $DBS, $template, $bb_cfg, $theme, $lang, $nav_links, $gen_simple_header, $images; + global $userdata; + + if (defined('HAS_DIED')) + { + trigger_error(__FUNCTION__ .' was called multiple times', E_USER_ERROR); + } + define('HAS_DIED', 1); + define('DISABLE_CACHING_OUTPUT', true); + $sql_store = $sql; + $debug_text = ''; + + // Get SQL error if we are debugging. Do this as soon as possible to prevent + // subsequent queries from overwriting the status of sql_error() + if (DEBUG && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR)) + { + if (!empty($DBS) && $sql_store) + { + $sql_error = DB()->sql_error(); + $debug_text .= "

    SQL Error : {$sql_error['code']}

    {$sql_error['message']}"; + } + if ($sql_store) + { + $debug_text .= "

    $sql_store"; + } + if ($sql_store && $err_line && $err_file) + { + $debug_text .= "

    Line : {$err_line}
    File : ". basename($err_file); + } + } + + if (empty($lang)) + { + require($bb_cfg['default_lang_dir'] .'lang_main.php'); + } + if (empty($userdata) && ($msg_code == GENERAL_MESSAGE || $msg_code == GENERAL_ERROR)) + { + $userdata = session_pagestart(); + } + // If the header hasn't been output then do it + if (!defined('PAGE_HEADER_SENT') && $msg_code != CRITICAL_ERROR) + { + if (empty($template)) + { + $template = new Template(BB_ROOT ."templates/{$bb_cfg['tpl_name']}"); + } + if (empty($theme)) + { + $theme = setup_style(); + } + require(PAGE_HEADER); + } + + switch ($msg_code) + { + case GENERAL_MESSAGE: + if (!$msg_title) $msg_title = $lang['INFORMATION']; + break; + + case CRITICAL_MESSAGE: + if (!$msg_title) $msg_title = $lang['CRITICAL_INFORMATION']; + break; + + case GENERAL_ERROR: + if (!$msg_text) $msg_text = $lang['AN_ERROR_OCCURED']; + if (!$msg_title) $msg_title = $lang['GENERAL_ERROR']; + break; + + case CRITICAL_ERROR: + // Critical errors mean we cannot rely on _ANY_ DB information being + // available so we're going to dump out a simple echo'd statement + if (!$msg_text) $msg_text = $lang['A_CRITICAL_ERROR']; + if (!$msg_title) $msg_title = 'phpBB : Critical Error'; + break; + } + // Add on DEBUG info if we've enabled debug mode and this is an error. This + // prevents debug info being output for general messages should DEBUG be + // set TRUE by accident (preventing confusion for the end user!) + if (DEBUG && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR)) + { + if ($debug_text) + { + $msg_text .= '

    DEBUG MODE'. $debug_text; + } + } + + if ($msg_code != CRITICAL_ERROR) + { + if (!empty($lang[$msg_text])) + { + $msg_text = $lang[$msg_text]; + } + + $template->assign_vars(array( + 'TPL_GENERAL_MESSAGE' => true, + + 'MESSAGE_TITLE' => $msg_title, + 'MESSAGE_TEXT' => $msg_text, + )); + + $template->set_filenames(array('message_die' => 'common.tpl')); + $template->pparse('message_die'); + + require(PAGE_FOOTER); + } + else + { +# while (@ob_end_clean()); + echo "\n\n". $msg_title ."\n

    \n". $msg_text ."\n"; + } + exit; +} + +// +// This function is for compatibility with PHP 4.x's realpath() +// function. In later versions of PHP, it needs to be called +// to do checks with some functions. Older versions of PHP don't +// seem to need this, so we'll just return the original value. +// dougk_ff7 +function phpbb_realpath($path) +{ + return (!@function_exists('realpath') || !@realpath(INC_DIR . 'functions.php')) ? $path : @realpath($path); +} + +function login_redirect ($url = '') +{ + redirect('login.php' .'?redirect='. (($url) ? $url : $_SERVER['REQUEST_URI'])); +} + +function meta_refresh($url, $time = 5) +{ + global $template; + + $template->assign_var( + 'META' , '' + ); +} + +function redirect ($url) +{ + global $bb_cfg; + + if (headers_sent($filename, $linenum)) + { + trigger_error("Headers already sent in $filename($linenum)", E_USER_ERROR); + } + + if (strstr(urldecode($url), "\n") || strstr(urldecode($url), "\r") || strstr(urldecode($url), ';url')) + { + message_die(CRITICAL_ERROR, 'Tried to redirect to potentially insecure url.'); + } + + if (!empty($_COOKIE['explain'])) + { + message_die(GENERAL_MESSAGE, "redirect($url)"); + } + + $url = trim($url); + $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; + + $server_name = preg_replace('#^\/?(.*?)\/?$#', '\1', trim($bb_cfg['server_name'])); + $server_port = ($bb_cfg['server_port'] <> 80) ? ':' . trim($bb_cfg['server_port']) : ''; + $script_name = preg_replace('#^\/?(.*?)\/?$#', '\1', trim($bb_cfg['script_path'])); + + if ($script_name) + { + $script_name = "/$script_name"; + $url = preg_replace("#^$script_name#", '', $url); + } + + $redirect_url = $server_protocol . $server_name . $server_port . $script_name . preg_replace('#^\/?(.*?)\/?$#', '/\1', $url); + + // Redirect via an HTML form for PITA webservers + if (@preg_match('/Microsoft|WebSTAR|Xitami/', getenv('SERVER_SOFTWARE'))) + { + header('Refresh: 0; URL='. $redirect_url); + echo 'Redirect
    If your browser does not support meta redirection please click HERE to be redirected
    '; + exit; + } + + // Behave as per HTTP/1.1 spec for others + header('Location: '. $redirect_url); + exit; +} + +//-- mod : topic display order --------------------------------------------------------------------- +//-- add +// build a list of the sortable fields or return field name +function get_forum_display_sort_option($selected_row=0, $action='list', $list='sort') +{ + global $lang; + + $forum_display_sort = array( + 'lang_key' => array('LASTPOST', 'SORT_TOPIC_TITLE', 'SORT_TIME'), + 'fields' => array('t.topic_last_post_time', 't.topic_title', 't.topic_time'), + ); + $forum_display_order = array( + 'lang_key' => array('DESC', 'ASC'), + 'fields' => array('DESC', 'ASC'), + ); + + // get the good list + $list_name = 'forum_display_' . $list; + $listrow = $$list_name; + + // init the result + $res = ''; + if ( $selected_row > count($listrow['lang_key']) ) + { + $selected_row = 0; + } + + // build list + if ($action == 'list') + { + for ($i=0; $i < count($listrow['lang_key']); $i++) + { + $selected = ($i==$selected_row) ? ' selected="selected"' : ''; + $l_value = (isset($lang[$listrow['lang_key'][$i]])) ? $lang[$listrow['lang_key'][$i]] : $listrow['lang_key'][$i]; + $res .= ''; + } + } + else + { + // field + $res = $listrow['fields'][$selected_row]; + } + return $res; +} +//-- fin mod : topic display order ----------------------------------------------------------------- + +function topic_attachment_image($switch_attachment) +{ + global $is_auth; + + if (!$switch_attachment || !($is_auth['auth_download'] && $is_auth['auth_view'])) + { + return ''; + } + return ' '; +} + +function transliterate ($str) +{ + static $translit_table; + + if (!isset($translit_table)) + { + require(DEFAULT_LANG_DIR .'translit_table.php'); + } + return strtr($str, $translit_table); +} + +/** + * array_combine() + * + * @package PHP_Compat + * @link http://php.net/function.array_combine + * @author Aidan Lister + * @version $Revision: 1.21 $ + * @since PHP 5 + */ +if (!function_exists('array_combine')) +{ + function array_combine($keys, $values) + { + if (!is_array($keys)) { + user_error('array_combine() expects parameter 1 to be array, ' . + gettype($keys) . ' given', E_USER_WARNING); + return; + } + + if (!is_array($values)) { + user_error('array_combine() expects parameter 2 to be array, ' . + gettype($values) . ' given', E_USER_WARNING); + return; + } + + $key_count = count($keys); + $value_count = count($values); + if ($key_count !== $value_count) { + user_error('array_combine() Both parameters should have equal number of elements', E_USER_WARNING); + return false; + } + + if ($key_count === 0 || $value_count === 0) { + user_error('array_combine() Both parameters should have number of elements at least 0', E_USER_WARNING); + return false; + } + + $keys = array_values($keys); + $values = array_values($values); + + $combined = array(); + for ($i = 0; $i < $key_count; $i++) { + $combined[$keys[$i]] = $values[$i]; + } + + return $combined; + } +} + +/** + * array_intersect_key() + * + * @package PHP_Compat + * @link http://php.net/function.array_intersect_key + * @author Tom Buskens + * @version $Revision: 1.4 $ + * @since PHP 5.0.2 + */ +if (!function_exists('array_intersect_key')) { + function array_intersect_key() + { + $args = func_get_args(); + if (count($args) < 2) { + user_error('Wrong parameter count for array_intersect_key()', E_USER_WARNING); + return; + } + + // Check arrays + $array_count = count($args); + for ($i = 0; $i !== $array_count; $i++) { + if (!is_array($args[$i])) { + user_error('array_intersect_key() Argument #' . + ($i + 1) . ' is not an array', E_USER_WARNING); + return; + } + } + + // Compare entries + $result = array(); + foreach ($args[0] as $key1 => $value1) { + for ($i = 1; $i !== $array_count; $i++) { + foreach ($args[$i] as $key2 => $value2) { + if ((string) $key1 === (string) $key2) { + $result[$key1] = $value1; + } + } + } + } + + return $result; + } +} + +function clear_dl_list ($topics_csv) +{ + DB()->query("DELETE FROM ". BB_BT_DLSTATUS ." WHERE topic_id IN($topics_csv)"); + DB()->query("DELETE FROM ". BB_BT_DLSTATUS_SNAP ." WHERE topic_id IN($topics_csv)"); +} + +// $ids - array(id1,id2,..) or (string) id +function get_id_csv ($ids) +{ + $ids = array_values((array) $ids); + array_deep($ids, 'intval', 'one-dimensional'); + return (string) join(',', $ids); +} + +// $ids - array(id1,id2,..) or (string) id1,id2,.. +function get_id_ary ($ids) +{ + $ids = is_string($ids) ? explode(',', $ids) : array_values((array) $ids); + array_deep($ids, 'intval', 'one-dimensional'); + return (array) $ids; +} + +function get_topic_title ($topic_id) +{ + $row = DB()->fetch_row(" + SELECT topic_title FROM ". BB_TOPICS ." WHERE topic_id = ". (int) $topic_id ." + "); + return $row['topic_title']; +} + +function forum_exists ($forum_id) +{ + return DB()->fetch_row("SELECT forum_id FROM ". BB_FORUMS ." WHERE forum_id = $forum_id LIMIT 1"); +} + +function cat_exists ($cat_id) +{ + return DB()->fetch_row("SELECT cat_id FROM ". BB_CATEGORIES ." WHERE cat_id = $cat_id LIMIT 1"); +} + +// +// Action Log +// +class log_action +{ + var $log_type = array( + # LOG_TYPE_NAME LOG_TYPE_ID + 'mod_topic_delete' => 1, + 'mod_topic_move' => 2, + 'mod_topic_lock' => 3, + 'mod_topic_unlock' => 4, + 'mod_post_delete' => 5, + 'mod_topic_split' => 6, + 'adm_user_delete' => 7, + 'adm_user_ban' => 8, + 'adm_user_unban' => 9, + ); + var $log_type_select = array(); + var $log_disabled = false; + + function init () + { + global $lang, $bb_cfg; + + if (empty($lang['LOG_ACTION'])) + { + require($bb_cfg['default_lang_dir'] .'lang_log_action.php'); + } + + foreach ($lang['LOG_ACTION']['LOG_TYPE'] as $log_type => $log_desc) + { + $this->log_type_select[strip_tags($log_desc)] = $this->log_type[$log_type]; + } + } + + function mod ($type_name, $args = array()) + { + global $userdata; + + if (empty($this->log_type)) $this->init(); + if ($this->log_disabled) return; + + $forum_id =& $args['forum_id']; + $forum_id_new =& $args['forum_id_new']; + $topic_id =& $args['topic_id']; + $topic_id_new =& $args['topic_id_new']; + $topic_title =& $args['topic_title']; + $topic_title_new =& $args['topic_title_new']; + $log_msg =& $args['log_msg']; + + if (!empty($userdata)) + { + $user_id = $userdata['user_id']; + $username = $userdata['username']; + $session_ip = $userdata['session_ip']; + } + else + { + $user_id = ''; + $username = defined('IN_CRON') ? 'cron' : CLIENT_IP; + $session_ip = ''; + } + + $sql_ary = array( + 'log_type_id' => (int) $this->log_type["$type_name"], + 'log_user_id' => (int) $user_id, + 'log_username' => (string) $username, + 'log_user_ip' => (string) $session_ip, + 'log_forum_id' => (int) $forum_id, + 'log_forum_id_new' => (int) $forum_id_new, + 'log_topic_id' => (int) $topic_id, + 'log_topic_id_new' => (int) $topic_id_new, + 'log_topic_title' => (string) $topic_title, + 'log_topic_title_new' => (string) $topic_title_new, + 'log_time' => (int) TIMENOW, + 'log_msg' => (string) $log_msg, + ); + $sql_args = DB()->build_array('INSERT', $sql_ary); + + DB()->query("INSERT INTO ". BB_LOG ." $sql_args"); + } + + function admin ($type_name, $args = array()) + { + $this->mod($type_name, $args); + } +} + +function get_topic_icon ($topic, $is_unread = null) +{ + global $bb_cfg, $lang, $images; + + $t_hot = ($topic['topic_replies'] >= $bb_cfg['hot_threshold']); + $is_unread = is_null($is_unread) ? is_unread($topic['topic_last_post_time'], $topic['topic_id'], $topic['forum_id']) : $is_unread; + + if ($topic['topic_status'] == TOPIC_MOVED) + { + $folder_image = $images['folder']; + } + else + { + $folder = ($t_hot) ? $images['folder_hot'] : $images['folder']; + $folder_new = ($t_hot) ? $images['folder_hot_new'] : $images['folder_new']; + + if ($topic['topic_type'] == POST_ANNOUNCE) + { + $folder = $images['folder_announce']; + $folder_new = $images['folder_announce_new']; + } + else if ($topic['topic_type'] == POST_STICKY) + { + $folder = $images['folder_sticky']; + $folder_new = $images['folder_sticky_new']; + } + else if ($topic['topic_status'] == TOPIC_LOCKED) + { + $folder = $images['folder_locked']; + $folder_new = $images['folder_locked_new']; + } + else if ($topic['topic_dl_type'] == TOPIC_DL_TYPE_DL) + { + $folder = ($t_hot) ? $images['folder_dl_hot'] : $images['folder_dl']; + $folder_new = ($t_hot) ? $images['folder_dl_hot_new'] : $images['folder_dl_new']; + } + + $folder_image = ($is_unread) ? $folder_new : $folder; + } + + return $folder_image; +} + +function build_topic_pagination ($url, $replies, $per_page) +{ + $pg = ''; + + if (++$replies > $per_page) + { + $total_pages = ceil($replies / $per_page); + + for ($j=0, $page=1; $j < $replies; $j += $per_page, $page++) + { + $href = ($j) ? "$url&start=$j" : $url; + $pg .= ''. $page .''; + + if ($page == 1 && $total_pages > 3) + { + $pg .= ' .. '; + $page = $total_pages - 2; + $j += ($total_pages - 3) * $per_page; + } + else if ($page < $total_pages) + { + $pg .= ', '; + } + } + } + + return $pg; +} + +function print_confirmation ($tpl_vars) +{ + global $template, $lang; + + $template->assign_vars(array( + 'TPL_CONFIRM' => true, + 'CONFIRM_TITLE' => $lang['CONFIRM'], + 'FORM_METHOD' => 'post', + )); + $template->assign_vars($tpl_vars); + + print_page('common.tpl'); +} + +/** + * $args = array( + * 'tpl' => 'template file name', + * 'simple' => $gen_simple_header, + * ); + * OR (string) 'template_file_name' + * + * $type = '' (common forum page) + * 'admin' (adminCP page) + * 'simple' (simple page without common header) + * + * $mode = 'no_header' + * 'no_footer' + */ +function print_page ($args, $type = '', $mode = '') +{ + global $template, $gen_simple_header; + + $tpl = (is_array($args) && !empty($args['tpl'])) ? $args['tpl'] : $args; + $tpl = ($type === 'admin') ? ADMIN_TPL_DIR . $tpl : $tpl; + + $gen_simple_header = (is_array($args) && !empty($args['simple']) OR $type === 'simple') ? true : $gen_simple_header; + + if ($mode !== 'no_header') + { + require(PAGE_HEADER); + } + + $template->set_filenames(array('body' => $tpl)); + $template->pparse('body'); + + if ($mode !== 'no_footer') + { + require(PAGE_FOOTER); + } +} + +function caching_output ($enabled, $mode, $cache_var_name, $ttl = 300) +{ + if (!$enabled || !CACHE('tr_cache')->used) + { + return; + } + + if ($mode == 'send') + { + if ($cached_contents = CACHE('bb_cache')->get($cache_var_name)) + { + bb_exit($cached_contents); + } + } + else if ($mode == 'store') + { + if ($output = ob_get_contents()) + { + CACHE('bb_cache')->set($cache_var_name, $output, $ttl); + } + } +} + +// +// Ajax +// +/** + * Encode PHP var to JSON (PHP -> JS) + */ +function bb_json_encode ($data) +{ + if (!function_exists('json_encode')) { + require_once( INC_DIR . 'FastJSON.class.php' ); + $json = new FastJSON(); + return $json->encode(utf8_encode($data)); + } + return json_encode($data); +} + +/** + * Decode JSON to PHP (JS -> PHP) + */ +function bb_json_decode ($data) +{ + if (!is_string($data)) trigger_error('invalid argument for '. __FUNCTION__, E_USER_ERROR); + + if (!function_exists('json_decode')) { + require_once( INC_DIR . 'FastJSON.class.php' ); + $json = new FastJSON(); + return utf8_decode($json->decode($data)); + } + return json_decode($data, true); +} + +function clean_topic_title ($str, $replace_underscore = false) +{ + $str = ($replace_underscore) ? str_replace('_', ' ', $str) : $str; + $str = htmlCHR(str_compact($str)); + return $str; +} + +function clean_text_match ($text, $ltrim_star = true, $remove_stopwords = false, $die_if_empty = false) +{ + global $bb_cfg, $lang; + + $text = str_compact($text); + $ltrim_chars = ($ltrim_star) ? ' *-!' : ' '; + $wrap_with_quotes = preg_match('#^"[^"]+"$#', $text); + +# $min_word_len = max(2, $bb_cfg['search_min_word_len'] - 1); +# $max_word_len = $bb_cfg['search_max_word_len']; + +# $text = preg_replace('#\b\w{1,'. $min_word_len .'}\b#', '', $text); +# $text = preg_replace('#\b\w{'. $max_word_len .',}\b#', '', $text); + + $text = ' '. str_compact(ltrim($text, $ltrim_chars)) .' '; + + if ($remove_stopwords) + { + $text = remove_stopwords($text); + } + + if ($bb_cfg['search_engine_type'] == 'sphinx') + { + $text = preg_replace('#(?<=\S)\-#u', ' ', $text); // "1-2-3" -> "1 2 3" + $text = preg_replace('#[^0-9a-zA-Zа-яА-ЯёЁ\-_*|]#u', ' ', $text); // допустимые символы (кроме " которые отдельно) + $text = str_replace('-', ' -', $text); // - только в начале слова + $text = str_replace('*', '* ', $text); // * только в конце слова + $text = preg_replace('#\s*\|\s*#u', '|', $text); // "| " -> "|" + $text = preg_replace('#\|+#u', ' | ', $text); // "||" -> "|" + $text = preg_replace('#(?<=\s)[\-*]+\s#u', ' ', $text); // одиночные " - ", " * " + $text = trim($text, ' -|'); + $text = str_compact($text); + $text_match_sql = ($wrap_with_quotes && $text != '') ? '"'. $text .'"' : $text; + } + else + { +# if ($all_words) +# { +# $text = preg_replace('#\s(\b\w)#', ' +$1', $text); +# } + $text_match_sql = DB()->escape(trim($text)); + } + + if (!$text_match_sql && $die_if_empty) + { + bb_die($lang['No_search_match']); + } + return $text_match_sql; +} + +function init_sphinx () +{ + global $sphinx; + + if (!isset($sphinx)) + { + require(INC_DIR .'sphinxapi.php'); + $sphinx = new SphinxClient(); + + $sphinx->SetConnectTimeout(5); +# $sphinx->SetMaxQueryTime(2); + $sphinx->SetRankingMode(SPH_RANK_NONE); + $sphinx->SetMatchMode(SPH_MATCH_BOOLEAN); +# $sphinx->SetSortMode($mode, $sortby=""); + } +} + +function log_sphinx_error ($err_type, $err_msg, $query = '') +{ + $ignore_err_txt = array( + 'negation on top level', + 'Query word length is less than min prefix length', + ); + if (!count($ignore_err_txt) || !preg_match('#'. join('|', $ignore_err_txt) .'#i', $err_msg)) + { + $orig_query = strtr($_REQUEST['nm'], array("\n" => '\n')); + bb_log(date('m-d H:i:s') ." | $err_type | $err_msg | $orig_query | $query". LOG_LF, 'sphinx_error'); + } +} + +function get_title_match_topics ($title_match_sql, $limit = 500, $forum_ids = array()) +{ + global $bb_cfg, $sphinx, $userdata; + + $topic_ids = array(); + $limit = (int) $limit; + $forum_ids = (array) $forum_ids; + $title_match_sql = encode_text_match($title_match_sql); + + if ($bb_cfg['search_engine_type'] == 'sphinx') + { + global $user; + + init_sphinx(); + + $sphinx->SetServer($bb_cfg['sphinx_topic_titles_host'], $bb_cfg['sphinx_topic_titles_port']); + $sphinx->SetLimits(0, $limit, $limit, $limit); + if ($forum_ids) + { + $sphinx->SetFilter('forum_id', $forum_ids, false); + } + if (preg_match('#^"[^"]+"$#u', $title_match_sql)) + { + $sphinx->SetMatchMode(SPH_MATCH_PHRASE); + } + if ($result = $sphinx->Query($title_match_sql, 'topics', $userdata['username'] .' ('. USER_IP .')')) + { + if (!empty($result['matches'])) + { + $topic_ids = array_keys($result['matches']); + } + } + else if ($error = $sphinx->GetLastError()) + { + if (strpos($error, 'errno=110')) + { + bb_log(' ', 'misc/sphinx_conn_err_110'); + bb_die('В данный момент поисковик недоступен

    Попробуйте повторить запрос через несколько секунд'); + } + log_sphinx_error('ERR', $error, $title_match_sql); + } + if ($warning = $sphinx->GetLastWarning()) + { + log_sphinx_error('wrn', $warning, $title_match_sql); + } + } + else if ($bb_cfg['search_engine_type'] == 'mysql') + { + $bool_mode = (true) ? " IN BOOLEAN MODE" : ''; + $in_forums = ($forum_ids) ? "AND forum_id IN(". join(',', $forum_ids) .")" : ''; + $sql = " + SELECT topic_id + FROM ". BB_TOPICS ." + WHERE topic_title LIKE '%$title_match_sql%' + $in_forums + ORDER BY NULL + LIMIT $limit + "; + foreach (DB()->fetch_rowset($sql) as $row) + { + $topic_ids[] = $row['topic_id']; + } + } + else + { + bb_die('Поиск временно отключен'); + } + + return $topic_ids; +} + +// для более корректного поиска по словам содержащим одиночную кавычку +function encode_text_match ($txt) +{ + return str_replace("'", ''', $txt); +} + +function decode_text_match ($txt) +{ + return str_replace(''', "'", $txt); +} + +function remove_stopwords ($text) +{ + static $stopwords = null; + + if (is_null($stopwords)) + { + $stopwords = explode(' ', str_compact(@file_get_contents(LANG_DIR .'search_stopwords.txt'))); + array_deep($stopwords, 'pad_with_space'); + } + + return ($stopwords) ? str_replace($stopwords, ' ', $text) : $text; +} + +function pad_with_space ($str) +{ + return ($str) ? " $str " : $str; +} + +function create_magnet($infohash, $auth_key, $logged_in) +{ + global $bb_cfg, $userdata, $_GET; + $passkey_url = (!$logged_in || isset($_GET['no_passkey'])) ? '' : "?{$bb_cfg['passkey_key']}=$auth_key&"; + return ''; +} + +function get_avatar ($avatar, $type, $allowavatar = true) +{ + global $bb_cfg, $lang; + + $user_avatar = ''; + + if ($allowavatar) + { + switch($type) + { + case USER_AVATAR_UPLOAD: + $user_avatar = ( $bb_cfg['allow_avatar_upload'] ) ? '' : ''; + break; + case USER_AVATAR_REMOTE: + $user_avatar = ( $bb_cfg['allow_avatar_remote'] ) ? '' : ''; + break; + case USER_AVATAR_GALLERY: + $user_avatar = ( $bb_cfg['allow_avatar_local'] ) ? '' : ''; + break; + } + } + return $user_avatar; +} + +function set_die_append_msg ($forum_id = null, $topic_id = null) +{ + global $template; + $msg = ''; + $msg .= ($topic_id) ? '

    Вернуться в тему

    ' : ''; + $msg .= ($forum_id) ? '

    Вернуться в форум

    ' : ''; + $msg .= '

    Вернуться на главную

    '; + $template->assign_var('BB_DIE_APPEND_MSG', $msg); +} + +function CAPTCHA () +{ + static $captcha_obj = null; + + if ($captcha_obj === null) + { + global $bb_cfg; + require(INC_DIR .'captcha/captcha.php'); + $captcha_obj = new captcha_kcaptcha($bb_cfg['captcha']); + } + + return $captcha_obj; +} + +function get_path_from_id ($id, $ext_id, $base_path, $first_div, $sec_div) +{ + global $bb_cfg; + $ext = isset($bb_cfg['file_id_ext'][$ext_id]) ? $bb_cfg['file_id_ext'][$ext_id] : ''; + return ($base_path ? "$base_path/" : '') . ($id % $sec_div) .'/'. $id . ($ext ? ".$ext" : ''); +} \ No newline at end of file diff --git a/upload/includes/functions_admin.php b/upload/includes/functions_admin.php new file mode 100644 index 000000000..4423344a6 --- /dev/null +++ b/upload/includes/functions_admin.php @@ -0,0 +1,938 @@ +query(" + CREATE TEMPORARY TABLE $tmp_sync_forums ( + forum_id SMALLINT UNSIGNED NOT NULL DEFAULT '0', + forum_last_post_id MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + forum_posts MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + forum_topics MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (forum_id) + ) ENGINE = MEMORY + "); + + $where_sql = (!$all_forums) ? "WHERE f.forum_id IN($forum_csv)" : ''; + + DB()->query(" + INSERT INTO $tmp_sync_forums + SELECT + f.forum_id, + MAX(p.post_id), + COUNT(p.post_id), + COUNT(DISTINCT p.topic_id) + FROM ". BB_FORUMS ." f + LEFT JOIN ". BB_POSTS ." p USING(forum_id) + $where_sql + GROUP BY f.forum_id + "); + + DB()->query(" + UPDATE + $tmp_sync_forums tmp, ". BB_FORUMS ." f + SET + f.forum_last_post_id = tmp.forum_last_post_id, + f.forum_posts = tmp.forum_posts, + f.forum_topics = tmp.forum_topics + WHERE + f.forum_id = tmp.forum_id + "); + + DB()->query("DROP TEMPORARY TABLE $tmp_sync_forums"); + + break; + + case 'topic': + + $all_topics = ($id === 'all'); + + if (!$all_topics AND !$topic_csv = get_id_csv($id)) + { + break; + } + + $tmp_sync_topics = 'tmp_sync_topics'; + + DB()->query(" + CREATE TEMPORARY TABLE $tmp_sync_topics ( + topic_id MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + total_posts MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + topic_first_post_id MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + topic_last_post_id MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + topic_last_post_time INT UNSIGNED NOT NULL DEFAULT '0', + topic_attachment TINYINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (topic_id) + ) ENGINE = MEMORY + "); + + $where_sql = (!$all_topics) ? "AND t.topic_id IN($topic_csv)" : ''; + + DB()->query(" + INSERT INTO $tmp_sync_topics + SELECT + t.topic_id, + COUNT(p.post_id) AS total_posts, + MIN(p.post_id) AS topic_first_post_id, + MAX(p.post_id) AS topic_last_post_id, + MAX(p.post_time) AS topic_last_post_time, + IF(MAX(a.attach_id), 1, 0) AS topic_attachment + FROM ". BB_TOPICS ." t + LEFT JOIN ". BB_POSTS ." p ON(p.topic_id = t.topic_id) + LEFT JOIN ". BB_ATTACHMENTS ." a ON(a.post_id = p.post_id) + WHERE t.topic_status != ". TOPIC_MOVED ." + $where_sql + GROUP BY t.topic_id + "); + + DB()->query(" + UPDATE + $tmp_sync_topics tmp, ". BB_TOPICS ." t + SET + t.topic_replies = tmp.total_posts - 1, + t.topic_first_post_id = tmp.topic_first_post_id, + t.topic_last_post_id = tmp.topic_last_post_id, + t.topic_last_post_time = tmp.topic_last_post_time, + t.topic_attachment = tmp.topic_attachment + WHERE + t.topic_id = tmp.topic_id + "); + + $sql = "SELECT topic_id FROM ". $tmp_sync_topics ." WHERE total_posts = 0"; + + if ($rowset = DB()->fetch_rowset($sql)) + { + $topics = array(); + foreach ($rowset as $row) + { + $topics[] = $row['topic_id']; + } + topic_delete($topics); + } + + DB()->query("DROP TEMPORARY TABLE $tmp_sync_topics"); + + break; + + case 'user_posts': + + $all_users = ($id === 'all'); + + if (!$all_users AND !$user_csv = get_id_csv($id)) + { + break; + } + + $tmp_user_posts = 'tmp_sync_user_posts'; + + DB()->query(" + CREATE TEMPORARY TABLE $tmp_user_posts ( + user_id MEDIUMINT NOT NULL DEFAULT '0', + user_posts MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (user_id) + ) ENGINE = MEMORY + "); + + // Set posts count = 0 and then update to real count + $where_user_sql = (!$all_users) ? "AND user_id IN($user_csv)" : "AND user_posts != 0"; + $where_post_sql = (!$all_users) ? "AND poster_id IN($user_csv)" : ''; + + DB()->query(" + REPLACE INTO $tmp_user_posts + SELECT user_id, 0 + FROM ". BB_USERS ." + WHERE user_id != ". ANONYMOUS ." + $where_user_sql + UNION + SELECT poster_id, COUNT(*) + FROM ". BB_POSTS ." + WHERE poster_id != ". ANONYMOUS ." + $where_post_sql + GROUP BY poster_id + "); + + DB()->query(" + UPDATE + $tmp_user_posts tmp, ". BB_USERS ." u + SET + u.user_posts = tmp.user_posts + WHERE + u.user_id = tmp.user_id + "); + + DB()->query("DROP TEMPORARY TABLE $tmp_user_posts"); + + break; + } +} + +function topic_delete ($mode_or_topic_id, $forum_id = null, $prune_time = 0, $prune_all = false) +{ + global $lang, $bb_cfg, $log_action; + + $prune = ($mode_or_topic_id === 'prune'); + + if (!$prune AND !$topic_csv = get_id_csv($mode_or_topic_id)) + { + return false; + } + + $log_topics = $sync_forums = array(); + + if ($prune) + { + $sync_forums[$forum_id] = true; + } + else + { + $where_sql = ($forum_csv = get_id_csv($forum_id)) ? "AND forum_id IN($forum_csv)" : ''; + + $sql = " + SELECT topic_id, forum_id, topic_title, topic_status + FROM ". BB_TOPICS ." + WHERE topic_id IN($topic_csv) + $where_sql + "; + + $topic_csv = array(); + + foreach (DB()->fetch_rowset($sql) as $row) + { + $topic_csv[] = $row['topic_id']; + $log_topics[] = $row; + $sync_forums[$row['forum_id']] = true; + } + + if (!$topic_csv = get_id_csv($topic_csv)) + { + return false; + } + } + + // Get topics to delete + $tmp_delete_topics = 'tmp_delete_topics'; + + DB()->query(" + CREATE TEMPORARY TABLE $tmp_delete_topics ( + topic_id MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (topic_id) + ) ENGINE = MEMORY + "); + + $where_sql = ($prune) ? "forum_id = $forum_id" : "topic_id IN($topic_csv)"; + $where_sql .= ($prune && $prune_time) ? " AND topic_last_post_time < $prune_time" : ''; + $where_sql .= ($prune && !$prune_all) ? " AND topic_type NOT IN(". POST_ANNOUNCE .",". POST_STICKY .")": ''; + + DB()->query(" + INSERT INTO $tmp_delete_topics + SELECT topic_id + FROM ". BB_TOPICS ." + WHERE $where_sql + "); + + // Get topics count + $row = DB()->fetch_row("SELECT COUNT(*) AS topics_count FROM $tmp_delete_topics"); + + if (!$deleted_topics_count = $row['topics_count']) + { + DB()->query("DROP TEMPORARY TABLE $tmp_delete_topics"); + return 0; + } + + // Update user posts count + $tmp_user_posts = 'tmp_user_posts'; + + DB()->query(" + CREATE TEMPORARY TABLE $tmp_user_posts ( + user_id MEDIUMINT NOT NULL DEFAULT '0', + user_posts MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (user_id) + ) ENGINE = MEMORY + "); + + DB()->query(" + INSERT INTO $tmp_user_posts + SELECT p.poster_id, COUNT(p.post_id) + FROM ". $tmp_delete_topics ." del, ". BB_POSTS ." p + WHERE p.topic_id = del.topic_id + AND p.poster_id != ". ANONYMOUS ." + GROUP BY p.poster_id + "); + + DB()->query(" + UPDATE + $tmp_user_posts tmp, ". BB_USERS ." u + SET + u.user_posts = u.user_posts - tmp.user_posts + WHERE + u.user_id = tmp.user_id + "); + + DB()->query("DROP TEMPORARY TABLE $tmp_user_posts"); + + // Delete votes + DB()->query(" + DELETE vd, vr, vu + FROM ". $tmp_delete_topics ." del + LEFT JOIN ". BB_VOTE_DESC ." vd USING(topic_id) + LEFT JOIN ". BB_VOTE_RESULTS ." vr USING(vote_id) + LEFT JOIN ". BB_VOTE_USERS ." vu USING(vote_id) + "); + + if ($bb_cfg['auto_delete_posted_pics']) + { + $result = DB()->sql_query(" + SELECT ph.post_id, ph.post_html + FROM $tmp_delete_topics tmp + LEFT JOIN ". BB_POSTS ." p USING(topic_id) + LEFT JOIN ". BB_POSTS_HTML ." ph ON(p.post_id = ph.post_id) + "); + + while ( $post = DB()->sql_fetchrow($result) ) + { + preg_match_all('#fetch_row(" + SELECT post_id + FROM ". BB_POSTS_HTML ." + WHERE post_html LIKE '%". DB()->escape($match[1]). "%' + AND post_id != {$post['post_id']} + "); + + if(empty($have)) + { + @unlink(BB_ROOT . $bb_cfg['pic_dir'] . end(explode('/', $match[1]))); + } + } + } + } + + // Delete attachments (from disk) + $attach_dir = get_attachments_dir(); + + $result = DB()->query(" + SELECT + d.physical_filename + FROM + ". $tmp_delete_topics ." del, + ". BB_POSTS ." p, + ". BB_ATTACHMENTS ." a, + ". BB_ATTACHMENTS_DESC ." d + WHERE + p.topic_id = del.topic_id + AND a.post_id = p.post_id + AND d.attach_id = a.attach_id + "); + + while ($row = DB()->fetch_next($result)) + { + if ($filename = basename($row['physical_filename'])) + { + @unlink("$attach_dir/". $filename); + @unlink("$attach_dir/". THUMB_DIR .'/t_'. $filename); + } + } + unset($row, $result); + + // Delete posts, posts_text, attachments (from DB) + DB()->query(" + DELETE p, pt, ps, a, d + FROM ". $tmp_delete_topics ." del + LEFT JOIN ". BB_POSTS ." p ON(p.topic_id = del.topic_id) + LEFT JOIN ". BB_POSTS_TEXT ." pt ON(pt.post_id = p.post_id) + LEFT JOIN ". BB_POSTS_SEARCH ." ps ON(ps.post_id = p.post_id) + LEFT JOIN ". BB_ATTACHMENTS ." a ON(a.post_id = p.post_id) + LEFT JOIN ". BB_ATTACHMENTS_DESC ." d ON(d.attach_id = a.attach_id) + "); + + // Delete topics, topics watch + DB()->query(" + DELETE t, tw + FROM ". $tmp_delete_topics ." del + LEFT JOIN ". BB_TOPICS ." t USING(topic_id) + LEFT JOIN ". BB_TOPICS_WATCH ." tw USING(topic_id) + "); + + // Delete topic moved stubs + DB()->query(" + DELETE t + FROM ". $tmp_delete_topics ." del, ". BB_TOPICS ." t + WHERE t.topic_moved_id = del.topic_id + "); + + // Delete torrents + DB()->query(" + DELETE tor, tr + FROM ". $tmp_delete_topics ." del + LEFT JOIN ". BB_BT_TORRENTS ." tor USING(topic_id) + LEFT JOIN ". BB_BT_TRACKER ." tr USING(topic_id) + "); +/* + // Delete dlstat + DB()->query(" + DELETE dl + FROM ". $tmp_delete_topics ." del + LEFT JOIN ". BB_BT_DLSTATUS ." dl USING(topic_id) + "); +*/ + // Log action + if ($prune) + { + // TODO + } + else + { + foreach ($log_topics as $row) + { + if ($row['topic_status'] == TOPIC_MOVED) + { + $row['topic_title'] = ''. $lang['TOPIC_MOVED'] .' '. $row['topic_title']; + } + + $log_action->mod('mod_topic_delete', array( + 'forum_id' => $row['forum_id'], + 'topic_id' => $row['topic_id'], + 'topic_title' => $row['topic_title'], + )); + } + } + + // Sync + sync('forum', array_keys($sync_forums)); + + DB()->query("DROP TEMPORARY TABLE $tmp_delete_topics"); + + return $deleted_topics_count; +} + +function topic_move ($topic_id, $to_forum_id, $from_forum_id = null, $leave_shadow = false, $insert_bot_msg = false) +{ + global $log_action; + + $to_forum_id = (int) $to_forum_id; + + // Verify input params + if (!$topic_csv = get_id_csv($topic_id)) + { + return false; + } + if (!forum_exists($to_forum_id)) + { + return false; + } + if ($from_forum_id && (!forum_exists($from_forum_id) || $to_forum_id == $from_forum_id)) + { + return false; + } + + // Get topics info + $where_sql = ($forum_csv = get_id_csv($from_forum_id)) ? "AND forum_id IN($forum_csv)" : ''; + + $sql = " + SELECT * + FROM ". BB_TOPICS ." + WHERE topic_id IN($topic_csv) + AND topic_status != ". TOPIC_MOVED ." + $where_sql + "; + + $topics = array(); + $sync_forums = array($to_forum_id => true); + + foreach (DB()->fetch_rowset($sql) as $row) + { + if ($row['forum_id'] != $to_forum_id) + { + $topics[$row['topic_id']] = $row; + $sync_forums[$row['forum_id']] = true; + } + } + + if (!$topics OR !$topic_csv = get_id_csv(array_keys($topics))) + { + return false; + } + + // Insert topic in the old forum that indicates that the topic has moved + if ($leave_shadow) + { + $shadows = array(); + + foreach ($topics as $topic_id => $row) + { + $shadows[] = array( + 'forum_id' => $row['forum_id'], + 'topic_title' => $row['topic_title'], + 'topic_poster' => $row['topic_poster'], + 'topic_time' => TIMENOW, + 'topic_status' => TOPIC_MOVED, + 'topic_type' => POST_NORMAL, + 'topic_vote' => $row['topic_vote'], + 'topic_views' => $row['topic_views'], + 'topic_replies' => $row['topic_replies'], + 'topic_first_post_id' => $row['topic_first_post_id'], + 'topic_last_post_id' => $row['topic_last_post_id'], + 'topic_moved_id' => $topic_id, + 'topic_last_post_time' => $row['topic_last_post_time'], + ); + } + if ($sql_args = DB()->build_array('MULTI_INSERT', $shadows)) + { + DB()->query("INSERT INTO ". BB_TOPICS . $sql_args); + } + } + + // Update topics + DB()->query(" + UPDATE ". BB_TOPICS ." SET + forum_id = $to_forum_id + WHERE topic_id IN($topic_csv) + "); + + // Update posts + DB()->query(" + UPDATE ". BB_POSTS ." SET + forum_id = $to_forum_id + WHERE topic_id IN($topic_csv) + "); + + // Update torrents + DB()->query(" + UPDATE ". BB_BT_TORRENTS ." SET + forum_id = $to_forum_id + WHERE topic_id IN($topic_csv) + "); + + // Bot + if ($insert_bot_msg) + { + foreach ($topics as $topic_id => $row) + { + insert_post('after_move', $topic_id, $to_forum_id, $row['forum_id']); + } + sync('topic', array_keys($topics)); + } + + // Sync + sync('forum', array_keys($sync_forums)); + + // Log action + foreach ($topics as $topic_id => $row) + { + $log_action->mod('mod_topic_move', array( + 'forum_id' => $row['forum_id'], + 'forum_id_new' => $to_forum_id, + 'topic_id' => $topic_id, + 'topic_title' => $row['topic_title'], + )); + } + + return true; +} + +function post_delete ($mode_or_post_id, $user_id = null, $exclude_first = true) +{ + global $bb_cfg, $log_action; + + $del_user_posts = ($mode_or_post_id === 'user'); // Delete all user posts + + // Get required params + if ($del_user_posts) + { + if (!$user_csv = get_id_csv($user_id)) return false; + } + else + { + if (!$post_csv = get_id_csv($mode_or_post_id)) return false; + + // exclude first post of topic + if ($exclude_first) + { + $sql = "SELECT topic_first_post_id FROM ". BB_TOPICS ." WHERE topic_first_post_id IN($post_csv)"; + + if ($first_posts = DB()->fetch_rowset($sql, 'topic_first_post_id')) + { + $posts_without_first = array_diff(explode(',', $post_csv), $first_posts); + + if (!$post_csv = get_id_csv($posts_without_first)) + { + return false; + } + } + } + } + + // Collect data for logs, sync.. + $log_topics = $sync_forums = $sync_topics = $sync_users = array(); + + if ($del_user_posts) + { + $sql = "SELECT DISTINCT topic_id FROM ". BB_POSTS ." WHERE poster_id IN($user_csv)"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $sync_topics[] = $row['topic_id']; + } + + if ($topic_csv = get_id_csv($sync_topics)) + { + $sql = "SELECT DISTINCT forum_id FROM ". BB_TOPICS ." WHERE topic_id IN($topic_csv)"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $sync_forums[$row['forum_id']] = true; + } + } + + $sync_users = explode(',', $user_csv); + } + else + { + $sql = " + SELECT p.topic_id, p.forum_id, t.topic_title + FROM ". BB_POSTS ." p, ". BB_TOPICS ." t + WHERE p.post_id IN($post_csv) + AND t.topic_id = p.topic_id + GROUP BY t.topic_id + "; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $log_topics[] = $row; + $sync_topics[] = $row['topic_id']; + $sync_forums[$row['forum_id']] = true; + } + + $sql = "SELECT DISTINCT poster_id FROM ". BB_POSTS ." WHERE post_id IN($post_csv)"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $sync_users[] = $row['poster_id']; + } + } + + // Get all post_id for deleting + $tmp_delete_posts = 'tmp_delete_posts'; + + DB()->query(" + CREATE TEMPORARY TABLE $tmp_delete_posts ( + post_id MEDIUMINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (post_id) + ) ENGINE = MEMORY + "); + DB()->add_shutdown_query("DROP TEMPORARY TABLE IF EXISTS $tmp_delete_posts"); + + if ($del_user_posts) + { + $where_sql = "poster_id IN($user_csv)"; + + $exclude_posts_ary = array(); + foreach (DB()->fetch_rowset("SELECT topic_first_post_id FROM ". BB_TOPICS ." WHERE topic_poster IN($user_csv)") as $row) + { + $exclude_posts_ary[] = $row['topic_first_post_id']; + } + if ($exclude_posts_csv = get_id_csv($exclude_posts_ary)) + { + $where_sql .= " AND post_id NOT IN($exclude_posts_csv)"; + } + } + else + { + $where_sql = "post_id IN($post_csv)"; + } + + DB()->query(" + INSERT INTO $tmp_delete_posts + SELECT post_id + FROM ". BB_POSTS ." + WHERE $where_sql + "); + + // Deleted posts count + $row = DB()->fetch_row("SELECT COUNT(*) AS posts_count FROM $tmp_delete_posts"); + + if (!$deleted_posts_count = $row['posts_count']) + { + DB()->query("DROP TEMPORARY TABLE $tmp_delete_posts"); + return 0; + } + + if ($bb_cfg['auto_delete_posted_pics']) + { + $result = DB()->sql_query(" + SELECT ph.post_id, ph.post_html + FROM $tmp_delete_posts tmp + LEFT JOIN ". BB_POSTS_HTML ." ph USING(post_id) + "); + + while ( $post = DB()->sql_fetchrow($result) ) + { + preg_match_all('#fetch_row(" + SELECT post_id + FROM ". BB_POSTS_HTML ." + WHERE post_html LIKE '%". DB()->escape($match[1]). "%' + AND post_id != {$post['post_id']} + "); + + if(empty($have)) + { + @unlink(BB_ROOT . $bb_cfg['pic_dir']. end(explode('/', $match[1]))); + } + } + } + } + + // Delete attachments (from disk) + $attach_dir = get_attachments_dir(); + + $result = DB()->query(" + SELECT + d.physical_filename + FROM + ". $tmp_delete_posts ." del, + ". BB_ATTACHMENTS ." a, + ". BB_ATTACHMENTS_DESC ." d + WHERE + a.post_id = del.post_id + AND d.attach_id = a.attach_id + "); + + while ($row = DB()->fetch_next($result)) + { + if ($filename = basename($row['physical_filename'])) + { + @unlink("$attach_dir/". $filename); + @unlink("$attach_dir/". THUMB_DIR .'/t_'. $filename); + } + } + unset($row, $result); + + // Delete posts, posts_text, attachments (from DB) + DB()->query(" + DELETE p, pt, ps, tor, a, d + FROM ". $tmp_delete_posts ." del + LEFT JOIN ". BB_POSTS ." p ON(p.post_id = del.post_id) + LEFT JOIN ". BB_POSTS_TEXT ." pt ON(pt.post_id = del.post_id) + LEFT JOIN ". BB_POSTS_SEARCH ." ps ON(ps.post_id = del.post_id) + LEFT JOIN ". BB_BT_TORRENTS ." tor ON(tor.post_id = del.post_id) + LEFT JOIN ". BB_ATTACHMENTS ." a ON(a.post_id = del.post_id) + LEFT JOIN ". BB_ATTACHMENTS_DESC ." d ON(d.attach_id = a.attach_id) + "); + + // Log action + if ($del_user_posts) + { + $log_action->admin('mod_post_delete', array( + 'log_msg' => 'user: '. get_usernames_for_log($user_id) ."
    posts: $deleted_posts_count", + )); + } + else if (!defined('IN_CRON')) + { + foreach ($log_topics as $row) + { + $log_action->mod('mod_post_delete', array( + 'forum_id' => $row['forum_id'], + 'topic_id' => $row['topic_id'], + 'topic_title' => $row['topic_title'], + )); + } + } + + // Sync + sync('topic', $sync_topics); + sync('forum', array_keys($sync_forums)); + sync('user_posts', $sync_users); + + DB()->query("DROP TEMPORARY TABLE $tmp_delete_posts"); + + return $deleted_posts_count; +} + +function poll_delete ($topic_id) +{ + if (!$topic_csv = get_id_csv($topic_id)) + { + return false; + } + + DB()->query(" + DELETE vd, vr, vu + FROM ". BB_VOTE_DESC ." vd + LEFT JOIN ". BB_VOTE_RESULTS ." vr USING(vote_id) + LEFT JOIN ". BB_VOTE_USERS ." vu USING(vote_id) + WHERE vd.topic_id IN($topic_csv) + "); + + DB()->query(" + UPDATE ". BB_TOPICS ." SET topic_vote = 0 WHERE topic_id IN($topic_csv) + "); +} + +function user_delete ($user_id, $delete_posts = false) +{ + global $bb_cfg, $log_action; + + $default_group_moderator_id = 2; + + if (!$user_csv = get_id_csv($user_id)) + { + return false; + } + + // LOG + $log_action->admin('adm_user_delete', array( + 'log_msg' => get_usernames_for_log($user_id), + )); + + // Avatar + $result = DB()->query(" + SELECT user_avatar + FROM ". BB_USERS ." + WHERE user_avatar_type = ". USER_AVATAR_UPLOAD ." + AND user_avatar != '' + AND user_id IN($user_csv) + "); + + while ($row = DB()->fetch_next($result)) + { + if ($filename = basename($row['user_avatar'])) + { + @unlink(BB_ROOT . $bb_cfg['avatar_path'] .'/'. $filename); + } + } + unset($row, $result); + + // Group + DB()->query(" + UPDATE ". BB_GROUPS ." SET + group_moderator = $default_group_moderator_id + WHERE group_single_user = 0 + AND group_moderator IN($user_csv) + "); + + if ($delete_posts) + { + post_delete('user', $user_id); + } + else + { + DB()->query(" + UPDATE ". BB_POSTS ." p, ". BB_USERS ." u SET + p.post_username = u.username, + p.poster_id = ". DELETED ." + WHERE u.user_id IN($user_csv) + AND p.poster_id = u.user_id + "); + } + + DB()->query(" + UPDATE ". BB_TOPICS ." SET + topic_poster = ". DELETED ." + WHERE topic_poster IN($user_csv) + "); + + DB()->query(" + UPDATE ". BB_VOTE_USERS ." SET + vote_user_id = ". DELETED ." + WHERE vote_user_id IN($user_csv) + "); + + DB()->query(" + UPDATE ". BB_BT_TORRENTS ." SET + poster_id = ". DELETED ." + WHERE poster_id IN($user_csv) + "); + + DB()->query(" + DELETE ug, g, a, qt1, qt2 + FROM ". BB_USER_GROUP ." ug + LEFT JOIN ". BB_GROUPS ." g ON(g.group_id = ug.group_id AND g.group_single_user = 1) + LEFT JOIN ". BB_AUTH_ACCESS ." a ON(a.group_id = g.group_id) + LEFT JOIN ". BB_QUOTA ." qt1 ON(qt1.user_id = ug.user_id) + LEFT JOIN ". BB_QUOTA ." qt2 ON(qt2.group_id = g.group_id) + WHERE ug.user_id IN($user_csv) + "); + + DB()->query(" + DELETE u, ban, s, tw, asn + FROM ". BB_USERS ." u + LEFT JOIN ". BB_BANLIST ." ban ON(ban.ban_userid = u.user_id) + LEFT JOIN ". BB_SESSIONS ." s ON(s.session_user_id = u.user_id) + LEFT JOIN ". BB_TOPICS_WATCH ." tw ON(tw.user_id = u.user_id) + LEFT JOIN ". BB_AUTH_ACCESS_SNAP ." asn ON(asn.user_id = u.user_id) + WHERE u.user_id IN($user_csv) + "); + + DB()->query(" + DELETE btu, tr + FROM ". BB_BT_USERS ." btu + LEFT JOIN ". BB_BT_TRACKER ." tr ON(tr.user_id = btu.user_id) + WHERE btu.user_id IN($user_csv) + "); + + // PM + DB()->query(" + DELETE pm, pmt + FROM ". BB_PRIVMSGS ." pm + LEFT JOIN ". BB_PRIVMSGS_TEXT ." pmt ON(pmt.privmsgs_text_id = pm.privmsgs_id) + WHERE pm.privmsgs_from_userid IN($user_csv) + AND pm.privmsgs_type IN(". PRIVMSGS_SENT_MAIL .','. PRIVMSGS_SAVED_OUT_MAIL .") + "); + + DB()->query(" + DELETE pm, pmt + FROM ". BB_PRIVMSGS ." pm + LEFT JOIN ". BB_PRIVMSGS_TEXT ." pmt ON(pmt.privmsgs_text_id = pm.privmsgs_id) + WHERE pm.privmsgs_to_userid IN($user_csv) + AND pm.privmsgs_type IN(". PRIVMSGS_READ_MAIL .','. PRIVMSGS_SAVED_IN_MAIL .") + "); + + DB()->query(" + UPDATE ". BB_PRIVMSGS ." SET + privmsgs_from_userid = ". DELETED ." + WHERE privmsgs_from_userid IN($user_csv) + "); + + DB()->query(" + UPDATE ". BB_PRIVMSGS ." SET + privmsgs_to_userid = ". DELETED ." + WHERE privmsgs_to_userid IN($user_csv) + "); +} + +function get_usernames_for_log ($user_id) +{ + $users_log_msg = array(); + + if ($user_csv = get_id_csv($user_id)) + { + $sql = "SELECT user_id, username FROM ". BB_USERS ." WHERE user_id IN($user_csv)"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $users_log_msg[] = "$row[username] [$row[user_id]]"; + } + } + + return join(', ', $users_log_msg); +} \ No newline at end of file diff --git a/upload/includes/functions_admin_cron.php b/upload/includes/functions_admin_cron.php new file mode 100644 index 000000000..26e0833d4 --- /dev/null +++ b/upload/includes/functions_admin_cron.php @@ -0,0 +1,160 @@ +sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain cron script', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + $job = $row['cron_script']; + $job_script = BB_ROOT . 'includes/cron/jobs/' . $job; + require($job_script); + } + DB()->query(" + UPDATE ". BB_CRON ." SET + last_run = NOW(), + run_counter = run_counter + 1, + next_run = + CASE + WHEN schedule = 'hourly' THEN + DATE_ADD(NOW(), INTERVAL 1 HOUR) + WHEN schedule = 'daily' THEN + DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 1 DAY), INTERVAL TIME_TO_SEC(run_time) SECOND) + WHEN schedule = 'weekly' THEN + DATE_ADD( + DATE_ADD(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(NOW()) DAY), INTERVAL 7 DAY), + INTERVAL CONCAT(ROUND(run_day-1), ' ', run_time) DAY_SECOND) + WHEN schedule = 'monthly' THEN + DATE_ADD( + DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFMONTH(NOW())-1 DAY), INTERVAL 1 MONTH), + INTERVAL CONCAT(ROUND(run_day-1), ' ', run_time) DAY_SECOND) + ELSE + DATE_ADD(NOW(), INTERVAL TIME_TO_SEC(run_interval) SECOND) + END + WHERE cron_id IN ($jobs) + "); + sleep(3); + return; +} + +function delete_jobs($jobs) +{ + DB()->query("DELETE FROM " . BB_CRON . " WHERE cron_id IN ($jobs)"); + return; +} + +function toggle_active($jobs, $cron_action) +{ + $active = ($cron_action == 'disable') ? 0 : 1; + DB()->query("UPDATE " . BB_CRON . " SET cron_active = $active WHERE cron_id IN ($jobs)"); + return; +} + +function validate_cron_post($cron_arr) { + $errors = 'Errors in: '; + $errnum = 0; + if (!$cron_arr['cron_title']){ + $errors .= 'cron title (empty value), '; + $errnum++; + } + if (!$cron_arr['cron_script']){ + $errors .= 'cron script (empty value), '; + $errnum++; + } + if ($errnum > 0){ + $result = $errors . ' total ' . $errnum . ' errors
    Back'; + } + else { + $result = 1; + } + return $result; +} + +function insert_cron_job($cron_arr) +{ + $cron_active = $cron_arr['cron_active']; + $cron_title = $cron_arr['cron_title']; + $cron_script = $cron_arr['cron_script']; + $schedule = $cron_arr['schedule']; + $run_day = $cron_arr['run_day']; + $run_time = $cron_arr['run_time']; + $run_order = $cron_arr['run_order']; + $last_run = $cron_arr['last_run']; + $next_run = $cron_arr['next_run']; + $run_interval = $cron_arr['run_interval']; + $log_enabled = $cron_arr['log_enabled']; + $log_file = $cron_arr['log_file']; + $log_sql_queries = $cron_arr['log_sql_queries']; + $disable_board = $cron_arr['disable_board']; + $run_counter = $cron_arr['run_counter']; + DB()->query("INSERT INTO ".BB_CRON." (cron_active, cron_title, cron_script, schedule, run_day, run_time, run_order, last_run, next_run, run_interval, log_enabled, log_file, log_sql_queries, disable_board, run_counter) VALUES ( + $cron_active, '$cron_title', '$cron_script', '$schedule', '$run_day', '$run_time', '$run_order', '$last_run', '$next_run', '$run_interval', $log_enabled, '$log_file', $log_sql_queries, $disable_board, '$run_counter')"); +} + +function update_cron_job($cron_arr) +{ + $cron_id = $cron_arr['cron_id']; + $cron_active = $cron_arr['cron_active']; + $cron_title = DB()->escape($cron_arr['cron_title']); + $cron_script = DB()->escape($cron_arr['cron_script']); + $schedule = $cron_arr['schedule']; + $run_day = $cron_arr['run_day']; + $run_time = $cron_arr['run_time']; + $run_order = $cron_arr['run_order']; + $last_run = $cron_arr['last_run']; + $next_run = $cron_arr['next_run']; + $run_interval = $cron_arr['run_interval']; + $log_enabled = $cron_arr['log_enabled']; + $log_file = DB()->escape($cron_arr['log_file']); + $log_sql_queries = $cron_arr['log_sql_queries']; + $disable_board = $cron_arr['disable_board']; + $run_counter = $cron_arr['run_counter']; + + DB()->query("UPDATE " . BB_CRON . " SET + cron_active = '$cron_active', + cron_title = '$cron_title', + cron_script = '$cron_script', + schedule = '$schedule', + run_day = '$run_day', + run_time = '$run_time', + run_order = '$run_order', + last_run = '$last_run', + next_run = '$next_run', + run_interval = '$run_interval', + log_enabled = '$log_enabled', + log_file = '$log_file', + log_sql_queries = '$log_sql_queries', + disable_board = '$disable_board', + run_counter = '$run_counter' + WHERE cron_id = $cron_id + "); +} + +function update_config_php($config_option_name, $new_value) { + $file = file(BB_ROOT.'config.php'); + $i = 0; + $count = count($file); + while ($i<$count) { + if (preg_match("/$config_option_name/i", $file[$i])) { + $line = explode(';', $file[$i]); //explode comments + $line[0] = '$bb_cfg[\''.$config_option_name.'\'] = '.$new_value.''; //assign a new value + $file[$i] = implode(';', $line); //build a new line + + $fp = fopen(BB_ROOT."config.php","w"); + fputs($fp,implode("",$file)); + fclose($fp); + } + $i++; + } + return; +} \ No newline at end of file diff --git a/upload/includes/functions_admin_torrent.php b/upload/includes/functions_admin_torrent.php new file mode 100644 index 000000000..a6ac181fd --- /dev/null +++ b/upload/includes/functions_admin_torrent.php @@ -0,0 +1,117 @@ +sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not update $table_name", '', __LINE__, __FILE__, $sql); + } + + if (isset($_POST[$field_name])) + { + // Get new status + $in_sql = array(); + + foreach ($_POST[$field_name] as $i => $val) + { + $in_sql[] = intval($val); + } + + // Update status + if ($in_sql = join(',', $in_sql)) + { + $sql = "UPDATE $table_name + SET $field_name = 1 + WHERE $key IN($in_sql)"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not update $table_name", '', __LINE__, __FILE__, $sql); + } + } + } + return; +} + +function set_tpl_vars ($default_cfg, $cfg) +{ + global $template; + + foreach ($default_cfg as $config_name => $config_value) + { + $template->assign_vars(array(strtoupper($config_name) => htmlspecialchars($cfg[$config_name]))); + } +} + +function set_tpl_vars_bool ($default_cfg, $cfg) +{ + global $template, $lang; + + foreach ($default_cfg as $config_name => $config_value) + { + // YES/NO 'checked="checked"' + $template->assign_vars(array( + strtoupper($config_name) .'_YES' => ($cfg[$config_name]) ? HTML_CHECKED : '', + strtoupper($config_name) .'_NO' => (!$cfg[$config_name]) ? HTML_CHECKED : '', + )); + // YES/NO lang vars + $template->assign_vars(array( + 'L_'. strtoupper($config_name) .'_YES' => ($cfg[$config_name]) ? "$lang[YES]" : $lang['YES'], + 'L_'. strtoupper($config_name) .'_NO' => (!$cfg[$config_name]) ? "$lang[NO]" : $lang['NO'], + )); + } +} + +function set_tpl_vars_lang ($default_cfg) +{ + global $template, $lang; + + foreach ($default_cfg as $config_name => $config_value) + { + $template->assign_vars(array( + 'L_'. strtoupper($config_name) => isset($lang[$config_name]) ? $lang[$config_name] : '', + 'L_'. strtoupper($config_name) .'_EXPL' => isset($lang[$config_name .'_expl']) ? $lang[$config_name .'_expl'] : '', + 'L_'. strtoupper($config_name) .'_HEAD' => isset($lang[$config_name .'_head']) ? $lang[$config_name .'_head'] : '', + )); + + } +} + +function update_config_table ($table_name, $default_cfg, $cfg, $type) +{ + global $db; + + foreach ($default_cfg as $config_name => $config_value) + { + if (isset($_POST[$config_name]) && $_POST[$config_name] != $cfg[$config_name]) + { + if ($type == 'str') + { + $config_value = $_POST[$config_name]; + } + else if ($type == 'bool') + { + $config_value = ($_POST[$config_name]) ? 1 : 0; + } + else if ($type == 'num') + { + $config_value = abs(intval($_POST[$config_name])); + } + else + { + return; + } + + bb_update_config(array($config_name => $config_value), $table_name); + } + } +} \ No newline at end of file diff --git a/upload/includes/functions_dev.php b/upload/includes/functions_dev.php new file mode 100644 index 000000000..f31920512 --- /dev/null +++ b/upload/includes/functions_dev.php @@ -0,0 +1,55 @@ +srv as $srv_name => $db_obj) + { + $log .= !empty($db_obj) ? get_sql_log_html($db_obj, "$srv_name [MySQL]") : ''; + } + foreach ($CACHES->obj as $cache_name => $cache_obj) + { + $log .= !empty($cache_obj->db) ? get_sql_log_html($cache_obj->db, "cache: $cache_name [{$cache_obj->db->engine}]") : ''; + } + + $log .= !empty($sphinx) ? get_sql_log_html($sphinx, '$sphinx') : ''; + $log .= !empty($datastore->db) ? get_sql_log_html($datastore->db, '$datastore ['.$datastore->engine.']') : ''; + + return $log; +} + +function get_sql_log_html ($db_obj, $log_name) +{ + if (empty($db_obj->dbg)) return ''; + + $log = ''; + + foreach ($db_obj->dbg as $i => $dbg) + { + $id = "sql_{$i}_". mt_rand(); + $sql = short_query($dbg['sql'], true); + $time = sprintf('%.4f', $dbg['time']); + $perc = sprintf('[%2d]', $dbg['time']*100/$db_obj->sql_timetotal); + $info = !empty($dbg['info']) ? $dbg['info'] .' ['. $dbg['src'] .']' : $dbg['src']; + $file = addslashes($dbg['file']); + $line = $dbg['line']; + $edit = (DEBUG === true) ? "OpenInEditor('$file', $line);" : ''; + + $log .= '' + . '
    ' + . ''. $time .' ' + . ''. $perc .'' + . ' ' + . ''. $sql .'' + . ' # '. $info .' ' + . '
    ' + . "\n"; + } + return ' +
    '. $log_name .'
    + '. $log .' + '; +} diff --git a/upload/includes/functions_group.php b/upload/includes/functions_group.php new file mode 100644 index 000000000..c25025814 --- /dev/null +++ b/upload/includes/functions_group.php @@ -0,0 +1,229 @@ +query(" + CREATE TEMPORARY TABLE $tmp_table ( + user_id MEDIUMINT NOT NULL DEFAULT '0', + user_level TINYINT NOT NULL DEFAULT '0', + PRIMARY KEY (user_id) + ) ENGINE = MEMORY + "); + + DB()->query(" + REPLACE INTO $tmp_table (user_id, user_level) + SELECT u.user_id, ". USER ." + FROM ". BB_USERS ." u + WHERE user_level NOT IN(". USER .",". ADMIN .") + $users_in + UNION + SELECT DISTINCT ug.user_id, ". GROUP_MEMBER ." + FROM ". BB_GROUPS ." g, ". BB_USER_GROUP ." ug + WHERE g.group_single_user = 0 + AND ug.group_id = g.group_id + AND ug.user_pending = 0 + $user_groups_in + UNION + SELECT DISTINCT ug.user_id, ". MOD ." + FROM ". BB_AUTH_ACCESS ." aa, ". BB_USER_GROUP ." ug + WHERE aa.forum_perm & ". BF_AUTH_MOD ." + AND ug.group_id = aa.group_id + AND ug.user_pending = 0 + $user_groups_in + "); + + DB()->query(" + UPDATE ". BB_USERS ." u, $tmp_table lev SET + u.user_level = lev.user_level + WHERE lev.user_id = u.user_id + AND u.user_level NOT IN(". ADMIN .") + $users_in + "); + + DB()->query("DROP TEMPORARY TABLE $tmp_table"); + + update_user_permissions($user_id); + delete_orphan_usergroups(); + $datastore->update('moderators'); +} + +function delete_group ($group_id) +{ + $group_id = (int) $group_id; + + DB()->query(" + DELETE ug, g, aa + FROM ". BB_USER_GROUP ." ug + LEFT JOIN ". BB_GROUPS ." g ON(g.group_id = $group_id) + LEFT JOIN ". BB_AUTH_ACCESS ." aa ON(aa.group_id = $group_id) + WHERE ug.group_id = $group_id + "); + + update_user_level('all'); +} + +function add_user_into_group ($group_id, $user_id, $user_pending = 0) +{ + $args = DB()->build_array('INSERT', array( + 'group_id' => (int) $group_id, + 'user_id' => (int) $user_id, + 'user_pending' => (int) $user_pending, + )); + DB()->query("REPLACE INTO ". BB_USER_GROUP . $args); + + if (!$user_pending) + { + update_user_level($user_id); + } +} + +function delete_user_group ($group_id, $user_id) +{ + DB()->query(" + DELETE FROM ". BB_USER_GROUP ." + WHERE user_id = ". (int) $user_id ." + AND group_id = ". (int) $group_id ." + "); + + update_user_level($user_id); +} + +function create_user_group ($user_id) +{ + DB()->query("INSERT INTO ". BB_GROUPS ." (group_single_user) VALUES (1)"); + + $group_id = (int) DB()->sql_nextid(); + $user_id = (int) $user_id; + + DB()->query("INSERT INTO ". BB_USER_GROUP ." (user_id, group_id) VALUES ($user_id, $group_id)"); + + return $group_id; +} + +function get_group_data ($group_id) +{ + if ($group_id === 'all') + { + $sql = "SELECT g.*, u.username AS moderator_name, aa.group_id AS auth_mod + FROM ". BB_GROUPS ." g + LEFT JOIN ". BB_USERS ." u ON(g.group_moderator = u.user_id) + LEFT JOIN ". BB_AUTH_ACCESS ." aa ON(aa.group_id = g.group_id AND aa.forum_perm & ". BF_AUTH_MOD .") + WHERE g.group_single_user = 0 + GROUP BY g.group_id + ORDER BY g.group_name"; + } + else + { + $sql = "SELECT g.*, u.username AS moderator_name, aa.group_id AS auth_mod + FROM ". BB_GROUPS ." g + LEFT JOIN ". BB_USERS ." u ON(g.group_moderator = u.user_id) + LEFT JOIN ". BB_AUTH_ACCESS ." aa ON(aa.group_id = g.group_id AND aa.forum_perm & ". BF_AUTH_MOD .") + WHERE g.group_id = ". (int) $group_id ." + AND g.group_single_user = 0 + LIMIT 1"; + } + $method = ($group_id === 'all') ? 'fetch_rowset' : 'fetch_row'; + return DB()->$method($sql); +} + +function delete_permissions ($group_id = null, $user_id = null, $cat_id = null) +{ + $group_id = get_id_csv($group_id); + $user_id = get_id_csv($user_id); + $cat_id = get_id_csv($cat_id); + + $forums_join_sql = ($cat_id) ? " + INNER JOIN ". BB_FORUMS ." f ON(a.forum_id = f.forum_id AND f.cat_id IN($cat_id)) + " : ''; + + if ($group_id) + { + DB()->query("DELETE a FROM ". BB_AUTH_ACCESS ." a $forums_join_sql WHERE a.group_id IN($group_id)"); + } + if ($user_id) + { + DB()->query("DELETE a FROM ". BB_AUTH_ACCESS_SNAP ." a $forums_join_sql WHERE a.user_id IN($user_id)"); + } +} + +function store_permissions ($group_id, $auth_ary) +{ + if (empty($auth_ary) || !is_array($auth_ary)) return; + + $values = array(); + + foreach ($auth_ary as $forum_id => $permission) + { + $values[] = array( + 'group_id' => (int) $group_id, + 'forum_id' => (int) $forum_id, + 'forum_perm' => (int) $permission, + ); + } + $values = DB()->build_array('MULTI_INSERT', $values); + + DB()->query("INSERT INTO ". BB_AUTH_ACCESS . $values); +} + +function update_user_permissions ($user_id = 'all') +{ + if (is_array($user_id)) + { + $user_id = join(',', $user_id); + } + $delete_in = ($user_id !== 'all') ? " WHERE user_id IN($user_id)" : ''; + $users_in = ($user_id !== 'all') ? "AND ug.user_id IN($user_id)" : ''; + + DB()->query("DELETE FROM ". BB_AUTH_ACCESS_SNAP . $delete_in); + + DB()->query(" + INSERT INTO ". BB_AUTH_ACCESS_SNAP ." + (user_id, forum_id, forum_perm) + SELECT + ug.user_id, aa.forum_id, BIT_OR(aa.forum_perm) + FROM + ". BB_USER_GROUP ." ug, + ". BB_GROUPS ." g, + ". BB_AUTH_ACCESS ." aa + WHERE + ug.user_pending = 0 + $users_in + AND g.group_id = ug.group_id + AND aa.group_id = g.group_id + GROUP BY + ug.user_id, aa.forum_id + "); +} + +function delete_orphan_usergroups () +{ + // GROUP_SINGLE_USER without AUTH_ACCESS + DB()->query(" + DELETE g + FROM ". BB_GROUPS ." g + LEFT JOIN ". BB_AUTH_ACCESS ." aa USING(group_id) + WHERE g.group_single_user = 1 + AND aa.group_id IS NULL + "); + + // orphan USER_GROUP (against GROUP table) + DB()->query(" + DELETE ug + FROM ". BB_USER_GROUP ." ug + LEFT JOIN ". BB_GROUPS ." g USING(group_id) + WHERE g.group_id IS NULL + "); +} \ No newline at end of file diff --git a/upload/includes/functions_post.php b/upload/includes/functions_post.php new file mode 100644 index 000000000..1bcd36b32 --- /dev/null +++ b/upload/includes/functions_post.php @@ -0,0 +1,786 @@ +#', '#"#'); +$html_entities_replace = array('&', '<', '>', '"'); + +$unhtml_specialchars_match = array('#>#', '#<#', '#"#', '#&#'); +$unhtml_specialchars_replace = array('>', '<', '"', '&'); + +// +// This function will prepare a posted message for +// entry into the database. +// + +function unprepare_message($message) +{ + global $unhtml_specialchars_match, $unhtml_specialchars_replace; + + return preg_replace($unhtml_specialchars_match, $unhtml_specialchars_replace, $message); +} + +// +// Prepare a message for posting +// +function prepare_post(&$mode, &$post_data, &$bbcode_on, &$smilies_on, &$error_msg, &$username, &$bbcode_uid, &$subject, &$message, &$poll_title, &$poll_options, &$poll_length) +{ + global $bb_cfg, $userdata, $lang; + + // Check username + if (!empty($username)) + { + $username = clean_username($username); + + if (!$userdata['session_logged_in'] || ($userdata['session_logged_in'] && $username != $userdata['username'])) + { + require(INC_DIR .'functions_validate.php'); + + if ($err = validate_username($username)) + { + $error_msg .= $err; + } + } + else + { + $username = ''; + } + } + + // Check subject + if (!empty($subject)) + { + $subject = preg_replace('#&#', '&', htmlspecialchars(trim($subject))); + } + else if ($mode == 'newtopic' || ($mode == 'editpost' && $post_data['first_post'])) + { + $error_msg .= (!empty($error_msg)) ? '
    ' . $lang['EMPTY_SUBJECT'] : $lang['EMPTY_SUBJECT']; + } + + // Check message + if (!empty($message)) + { + + } + else if ($mode != 'delete' && $mode != 'poll_delete') + { + $error_msg .= (!empty($error_msg)) ? '
    ' . $lang['EMPTY_MESSAGE'] : $lang['EMPTY_MESSAGE']; + } + + // + // Handle poll stuff + // + if ($mode == 'newtopic' || ($mode == 'editpost' && $post_data['first_post'])) + { + $poll_length = (isset($poll_length)) ? max(0, intval($poll_length)) : 0; + + if (!empty($poll_title)) + { + $poll_title = htmlspecialchars(trim($poll_title)); + } + + if(!empty($poll_options)) + { + $temp_option_text = array(); + while(list($option_id, $option_text) = @each($poll_options)) + { + $option_text = trim($option_text); + if (!empty($option_text)) + { + $temp_option_text[$option_id] = htmlspecialchars($option_text); + } + } + $option_text = $temp_option_text; + + if (count($poll_options) < 2) + { + $error_msg .= (!empty($error_msg)) ? '
    ' . $lang['TO_FEW_POLL_OPTIONS'] : $lang['TO_FEW_POLL_OPTIONS']; + } + else if (count($poll_options) > $bb_cfg['max_poll_options']) + { + $error_msg .= (!empty($error_msg)) ? '
    ' . $lang['TO_MANY_POLL_OPTIONS'] : $lang['TO_MANY_POLL_OPTIONS']; + } + else if ($poll_title == '') + { + $error_msg .= (!empty($error_msg)) ? '
    ' . $lang['EMPTY_POLL_TITLE'] : $lang['EMPTY_POLL_TITLE']; + } + } + } + + // Check smilies limit + if($bb_cfg['max_smilies']) + { + $count_smilies = substr_count(bbcode2html($message), 'fetch_row($sql) AND $row['last_post_time']) + { + if ($userdata['user_level'] == USER) + { + if (TIMENOW - $row['last_post_time'] < $bb_cfg['flood_interval']) + { + message_die(GENERAL_MESSAGE, $lang['FLOOD_ERROR']); + } + } + } + } + + // Double Post Control + if ($mode != 'editpost' && !empty($row['last_post_time']) && !IS_AM) + { + $sql = " + SELECT pt.post_text, pt.bbcode_uid + FROM ". BB_POSTS ." p, ". BB_POSTS_TEXT ." pt + WHERE + $where_sql + AND p.post_time = ". (int) $row['last_post_time'] ." + AND pt.post_id = p.post_id + LIMIT 1 + "; + + if ($row = DB()->fetch_row($sql)) + { + $last_msg = addslashes(str_replace($row['bbcode_uid'], $bbcode_uid, $row['post_text'])); + $last_msg = str_replace("\'", "''", $last_msg); + + if ($last_msg == $post_message) + { + message_die(GENERAL_MESSAGE, $lang['DOUBLE_POST_ERROR']); + } + } + } + + if ($mode == 'newtopic' || ($mode == 'editpost' && $post_data['first_post'])) + { + $topic_vote = (!empty($poll_title) && count($poll_options) >= 2) ? 1 : 0; + + $topic_dl_type = (isset($_POST['topic_dl_type']) && ($post_info['allow_reg_tracker'] || $post_info['allow_dl_topic'] || $is_auth['auth_mod'])) ? TOPIC_DL_TYPE_DL : TOPIC_DL_TYPE_NORMAL; + + $sql = ($mode != "editpost") ? "INSERT INTO " . BB_TOPICS . " (topic_title, topic_poster, topic_time, forum_id, topic_status, topic_type, topic_dl_type, topic_vote) VALUES ('$post_subject', " . $userdata['user_id'] . ", $current_time, $forum_id, " . TOPIC_UNLOCKED . ", $topic_type, $topic_dl_type, $topic_vote)" : "UPDATE " . BB_TOPICS . " SET topic_title = '$post_subject', topic_type = $topic_type, topic_dl_type = $topic_dl_type " . ((@$post_data['edit_vote'] || !empty($poll_title)) ? ", topic_vote = " . $topic_vote : "") . " WHERE topic_id = $topic_id"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + + if ($mode == 'newtopic') + { + $topic_id = DB()->sql_nextid(); + } + } + + $edited_sql = ($mode == 'editpost' && !$post_data['last_post'] && $post_data['poster_post']) ? ", post_edit_time = $current_time, post_edit_count = post_edit_count + 1 " : ""; + + if ($update_post_time && $mode == 'editpost' && $post_data['last_post'] && !$post_data['first_post']) + { + $edited_sql .= ", post_time = $current_time "; + //lpt + $result = DB()->sql_query(" + UPDATE ". BB_TOPICS ." SET + topic_last_post_time = $current_time + WHERE topic_id = $topic_id + LIMIT 1 + "); + } + + $sql = ($mode != "editpost") ? "INSERT INTO " . BB_POSTS . " (topic_id, forum_id, poster_id, post_username, post_time, poster_ip, enable_bbcode, enable_smilies, enable_sig) VALUES ($topic_id, $forum_id, " . $userdata['user_id'] . ", '$post_username', $current_time, '". USER_IP ."', $bbcode_on, $smilies_on, $attach_sig)" : "UPDATE " . BB_POSTS . " SET post_username = '$post_username', enable_bbcode = $bbcode_on, enable_smilies = $smilies_on, enable_sig = $attach_sig" . $edited_sql . " WHERE post_id = $post_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + + if ($mode != 'editpost') + { + $post_id = DB()->sql_nextid(); + } + + $sql = ($mode != 'editpost') ? "INSERT INTO " . BB_POSTS_TEXT . " (post_id, post_subject, bbcode_uid, post_text) VALUES ($post_id, '$post_subject', '$bbcode_uid', '$post_message')" : "UPDATE " . BB_POSTS_TEXT . " SET post_text = '$post_message', bbcode_uid = '$bbcode_uid', post_subject = '$post_subject' WHERE post_id = $post_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + + if ($userdata['user_id'] != BOT_UID) + { + add_search_words($post_id, stripslashes($post_message), stripslashes($post_subject), $bbcode_uid); + } + + update_post_html(array( + 'post_id' => $post_id, + 'post_text' => $post_message, + 'bbcode_uid' => $bbcode_uid, + 'enable_smilies' => $smilies_on, + )); + + // + // Add poll + // + if (($mode == 'newtopic' || ($mode == 'editpost' && $post_data['edit_poll'])) && !empty($poll_title) && count($poll_options) >= 2) + { + $sql = (!$post_data['has_poll']) ? "INSERT INTO " . BB_VOTE_DESC . " (topic_id, vote_text, vote_start, vote_length) VALUES ($topic_id, '$poll_title', $current_time, " . ($poll_length * 86400) . ")" : "UPDATE " . BB_VOTE_DESC . " SET vote_text = '$poll_title', vote_length = " . ($poll_length * 86400) . " WHERE topic_id = $topic_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + + $delete_option_sql = ''; + $old_poll_result = array(); + if ($mode == 'editpost' && $post_data['has_poll']) + { + $sql = "SELECT vote_option_id, vote_result + FROM " . BB_VOTE_RESULTS . " + WHERE vote_id = $poll_id + ORDER BY vote_option_id ASC"; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not obtain vote data results for this topic', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + $old_poll_result[$row['vote_option_id']] = $row['vote_result']; + + if (!isset($poll_options[$row['vote_option_id']])) + { + $delete_option_sql .= ($delete_option_sql != '') ? ', ' . $row['vote_option_id'] : $row['vote_option_id']; + } + } + } + else + { + $poll_id = DB()->sql_nextid(); + } + + @reset($poll_options); + + $poll_option_id = 1; + while (list($option_id, $option_text) = each($poll_options)) + { + if (!empty($option_text)) + { + $option_text = str_replace("\'", "''", htmlspecialchars($option_text)); + $poll_result = ($mode == "editpost" && isset($old_poll_result[$option_id])) ? $old_poll_result[$option_id] : 0; + + $sql = ($mode != "editpost" || !isset($old_poll_result[$option_id])) ? "INSERT INTO " . BB_VOTE_RESULTS . " (vote_id, vote_option_id, vote_option_text, vote_result) VALUES ($poll_id, $poll_option_id, '$option_text', $poll_result)" : "UPDATE " . BB_VOTE_RESULTS . " SET vote_option_text = '$option_text', vote_result = $poll_result WHERE vote_option_id = $option_id AND vote_id = $poll_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + $poll_option_id++; + } + } + + if ($delete_option_sql != '') + { + $sql = "DELETE FROM " . BB_VOTE_RESULTS . " + WHERE vote_option_id IN ($delete_option_sql) + AND vote_id = $poll_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error deleting pruned poll options', '', __LINE__, __FILE__, $sql); + } + } + } + + meta_refresh(append_sid("viewtopic.php?" . POST_POST_URL . "=" . $post_id) . '#' . $post_id); + $message = $lang['STORED'] . '

    ' . sprintf($lang['CLICK_VIEW_MESSAGE'], '', '') . '

    ' . sprintf($lang['CLICK_RETURN_FORUM'], '', ''); + + return $mode; +} + +// +// Update post stats and details +// +function update_post_stats($mode, $post_data, $forum_id, $topic_id, $post_id, $user_id) +{ + $sign = ($mode == 'delete') ? '- 1' : '+ 1'; + $forum_update_sql = "forum_posts = forum_posts $sign"; + $topic_update_sql = ''; + + if ($mode == 'delete') + { + if ($post_data['last_post']) + { + if ($post_data['first_post']) + { + $forum_update_sql .= ', forum_topics = forum_topics - 1'; + } + else + { + $topic_update_sql .= 'topic_replies = topic_replies - 1'; + + $sql = "SELECT MAX(post_id) AS last_post_id, MAX(post_time) AS topic_last_post_time + FROM " . BB_POSTS . " + WHERE topic_id = $topic_id"; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Error in deleting post', '', __LINE__, __FILE__, $sql); + } + + if ($row = DB()->sql_fetchrow($result)) + { + $topic_update_sql .= ", topic_last_post_id = {$row['last_post_id']}, topic_last_post_time = {$row['topic_last_post_time']}"; + } + } + + if ($post_data['last_topic']) + { + $sql = "SELECT MAX(post_id) AS last_post_id + FROM " . BB_POSTS . " + WHERE forum_id = $forum_id"; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Error in deleting post', '', __LINE__, __FILE__, $sql); + } + + if ($row = DB()->sql_fetchrow($result)) + { + $forum_update_sql .= ($row['last_post_id']) ? ', forum_last_post_id = ' . $row['last_post_id'] : ', forum_last_post_id = 0'; + } + } + } + else if ($post_data['first_post']) + { + $sql = "SELECT MIN(post_id) AS first_post_id + FROM " . BB_POSTS . " + WHERE topic_id = $topic_id"; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Error in deleting post', '', __LINE__, __FILE__, $sql); + } + + if ($row = DB()->sql_fetchrow($result)) + { + $topic_update_sql .= 'topic_replies = topic_replies - 1, topic_first_post_id = ' . $row['first_post_id']; + } + } + else + { + $topic_update_sql .= 'topic_replies = topic_replies - 1'; + } + } + else if ($mode != 'poll_delete') + { + $forum_update_sql .= ", forum_last_post_id = $post_id" . (($mode == 'newtopic') ? ", forum_topics = forum_topics $sign" : ""); + $topic_update_sql = "topic_last_post_id = $post_id, topic_last_post_time = ". TIMENOW . (($mode == 'reply') ? ", topic_replies = topic_replies $sign" : ", topic_first_post_id = $post_id"); + } + else + { + $topic_update_sql .= 'topic_vote = 0'; + } + + $sql = "UPDATE " . BB_FORUMS . " SET + $forum_update_sql + WHERE forum_id = $forum_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + + if ($topic_update_sql != '') + { + $sql = "UPDATE " . BB_TOPICS . " SET + $topic_update_sql + WHERE topic_id = $topic_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + } + + if ($mode != 'poll_delete') + { + $sql = "UPDATE " . BB_USERS . " + SET user_posts = user_posts $sign + WHERE user_id = $user_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error in posting', '', __LINE__, __FILE__, $sql); + } + } +} + +// +// Delete a post/poll +// +function delete_post($mode, $post_data, &$message, &$meta, $forum_id, $topic_id, $post_id, $poll_id) +{ + global $lang; + + if ($mode == 'poll_delete') + { + $message = $lang['POLL_DELETE']; + poll_delete($topic_id); + } + else + { + $message = $lang['DELETED']; + post_delete($post_id); + } + + if (!($mode == 'delete' && $post_data['first_post'] && $post_data['last_post'])) + { + $message .= '

    '; + $message .= sprintf($lang['CLICK_RETURN_TOPIC'], '', ''); + } + + $message .= '

    '; + $message .= sprintf($lang['CLICK_RETURN_FORUM'], '', ''); +} + +// +// Handle user notification on new post +// +function user_notification($mode, &$post_data, &$topic_title, &$forum_id, &$topic_id, &$post_id, &$notify_user) +{ + global $bb_cfg, $lang; + global $userdata; + + if (!$bb_cfg['topic_notify_enabled']) + { + return; + } + + $current_time = time(); + + if ($mode != 'delete') + { + if ($mode == 'reply') + { + $sql = "SELECT ban_userid + FROM " . BB_BANLIST; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not obtain banlist', '', __LINE__, __FILE__, $sql); + } + + $user_id_sql = ''; + while ($row = DB()->sql_fetchrow($result)) + { + if (isset($row['ban_userid']) && !empty($row['ban_userid'])) + { + $user_id_sql .= ', ' . $row['ban_userid']; + } + } + + $sql = "SELECT u.user_id, u.user_email, u.user_lang + FROM " . BB_TOPICS_WATCH . " tw, " . BB_USERS . " u + WHERE tw.topic_id = $topic_id + AND tw.user_id NOT IN (" . $userdata['user_id'] . ", " . BOT_UID . ", " . ANONYMOUS . $user_id_sql . ") + AND tw.notify_status = " . TOPIC_WATCH_UN_NOTIFIED . " + AND u.user_id = tw.user_id"; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not obtain list of topic watchers', '', __LINE__, __FILE__, $sql); + } + + $update_watched_sql = ''; + $bcc_list_ary = array(); + + if ($row = DB()->sql_fetchrow($result)) + { + // Sixty second limit + @set_time_limit(60); + + do + { + if ($row['user_email'] != '') + { + $bcc_list_ary[$row['user_lang']][] = $row['user_email']; + } + $update_watched_sql .= ($update_watched_sql != '') ? ', ' . $row['user_id'] : $row['user_id']; + } + while ($row = DB()->sql_fetchrow($result)); + + // + // Let's do some checking to make sure that mass mail functions + // are working in win32 versions of php. + // + if (preg_match('/[c-z]:\\\.*/i', getenv('PATH')) && !$bb_cfg['smtp_delivery']) + { + $ini_val = (@phpversion() >= '4.0.0') ? 'ini_get' : 'get_cfg_var'; + + // We are running on windows, force delivery to use our smtp functions + // since php's are broken by default + if (!@$ini_val('sendmail_path')) + { + $bb_cfg['smtp_delivery'] = 1; + $bb_cfg['smtp_host'] = @$ini_val('SMTP'); + } + } + + if (sizeof($bcc_list_ary)) + { + include(INC_DIR .'emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $script_name = preg_replace('/^\/?(.*?)\/?$/', '\1', trim($bb_cfg['script_path'])); + $script_name = ($script_name != '') ? $script_name . '/viewtopic.php' : 'viewtopic.php'; + $server_name = trim($bb_cfg['server_name']); + $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; + $server_port = ($bb_cfg['server_port'] <> 80) ? ':' . trim($bb_cfg['server_port']) . '/' : '/'; + + $orig_word = array(); + $replacement_word = array(); + obtain_word_list($orig_word, $replacement_word); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $topic_title = (count($orig_word)) ? preg_replace($orig_word, $replacement_word, unprepare_message($topic_title)) : unprepare_message($topic_title); + + @reset($bcc_list_ary); + while (list($user_lang, $bcc_list) = each($bcc_list_ary)) + { + $emailer->use_template('topic_notify', $user_lang); + + for ($i = 0; $i < count($bcc_list); $i++) + { + $emailer->bcc($bcc_list[$i]); + } + + // The Topic_reply_notification lang string below will be used + // if for some reason the mail template subject cannot be read + // ... note it will not necessarily be in the posters own language! + $emailer->set_subject($lang['TOPIC_REPLY_NOTIFICATION']); + + // This is a nasty kludge to remove the username var ... till (if?) + // translators update their templates + $emailer->msg = preg_replace('#[ ]?{USERNAME}#', '', $emailer->msg); + + $emailer->assign_vars(array( + 'TOPIC_TITLE' => $topic_title, + 'SITENAME' => $bb_cfg['sitename'], + 'USERNAME' => $userdata['username'], + 'EMAIL_SIG' => (!empty($bb_cfg['board_email_sig'])) ? str_replace('
    ', "\n", "-- \n" . $bb_cfg['board_email_sig']) : '', + + 'U_TOPIC' => $server_protocol . $server_name . $server_port . $script_name . '?' . POST_POST_URL . "=$post_id#$post_id", + 'U_STOP_WATCHING_TOPIC' => $server_protocol . $server_name . $server_port . $script_name . '?' . POST_TOPIC_URL . "=$topic_id&unwatch=topic") + ); + + $emailer->send(); + $emailer->reset(); + } + } + } + DB()->sql_freeresult($result); + + if ($update_watched_sql != '') + { + $sql = "UPDATE " . BB_TOPICS_WATCH . " + SET notify_status = " . TOPIC_WATCH_NOTIFIED . " + WHERE topic_id = $topic_id + AND user_id IN ($update_watched_sql)"; + DB()->sql_query($sql); + } + } + + $sql = "SELECT topic_id + FROM " . BB_TOPICS_WATCH . " + WHERE topic_id = $topic_id + AND user_id = " . $userdata['user_id']; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not obtain topic watch information', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + + if (!$notify_user && !empty($row['topic_id'])) + { + $sql = "DELETE FROM " . BB_TOPICS_WATCH . " + WHERE topic_id = $topic_id + AND user_id = " . $userdata['user_id']; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete topic watch information', '', __LINE__, __FILE__, $sql); + } + } + else if ($notify_user && empty($row['topic_id'])) + { + $sql = "INSERT INTO " . BB_TOPICS_WATCH . " (user_id, topic_id, notify_status) + VALUES (" . $userdata['user_id'] . ", $topic_id, 0)"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not insert topic watch information', '', __LINE__, __FILE__, $sql); + } + } + } +} + +function insert_post ($mode, $topic_id, $forum_id = '', $old_forum_id = '', $new_topic_id = '', $new_topic_title = '', $old_topic_id = '', $message = '', $poster_id = '') +{ + global $bb_cfg, $lang; + global $userdata, $is_auth; + + require(DEFAULT_LANG_DIR .'lang_bot.php'); + + if (!$topic_id) return; + + $post_username = $post_subject = $post_text = $poster_ip = $bbcode_uid = ''; + + $enable_bbcode = $enable_smilies = 0; + $enable_sig = 1; + + $post_time = $current_time = time(); + $username = $userdata['username']; + $user_id = $userdata['user_id']; + + if ($mode == 'after_move') + { + if (!$forum_id || !$old_forum_id) return; + + $sql = "SELECT forum_id, forum_name + FROM ". BB_FORUMS ." + WHERE forum_id IN($forum_id, $old_forum_id)"; + + $forum_names = array(); + foreach (DB()->fetch_rowset($sql) as $row) + { + $forum_names[$row['forum_id']] = htmlCHR($row['forum_name']); + } + if (!$forum_names) return; + + $post_text = sprintf($lang['BOT_TOPIC_MOVED_FROM_TO'], "$forum_names[$old_forum_id]", "$forum_names[$forum_id]", "$username"); + + $poster_id = BOT_UID; + $poster_ip = '7f000001'; + } + else if ($mode == 'after_split_to_old') + { + $post_text = sprintf($lang['BOT_MESS_SPLITS'], "". htmlCHR($new_topic_title) ."", "$username"); + + $poster_id = BOT_UID; + $poster_ip = '7f000001'; + } + else if ($mode == 'after_split_to_new') + { + $sql = "SELECT t.topic_title, p.post_time + FROM ". BB_TOPICS ." t, ". BB_POSTS ." p + WHERE t.topic_id = $old_topic_id + AND p.post_id = t.topic_first_post_id"; + + if ($row = DB()->fetch_row($sql)) + { + $old_topic_title = $row['topic_title']; + $post_time = $row['post_time'] - 1; + + $post_text = sprintf($lang['BOT_TOPIC_SPLITS'], "$old_topic_title", "$username"); + + $poster_id = BOT_UID; + $poster_ip = '7f000001'; + } + else + { + return; + } + } + else + { + return; + } + + $post_columns = 'topic_id, forum_id, poster_id, post_username, post_time, poster_ip, enable_bbcode, enable_smilies, enable_sig'; + $post_values = "$topic_id, $forum_id, $poster_id, '$post_username', $post_time, '$poster_ip', $enable_bbcode, $enable_smilies, $enable_sig"; + + DB()->query("INSERT INTO ". BB_POSTS ." ($post_columns) VALUES ($post_values)"); + + $post_id = DB()->sql_nextid(); + $post_text = DB()->escape($post_text); + + $post_text_columns = 'post_id, post_subject, bbcode_uid, post_text'; + $post_text_values = "$post_id, '$post_subject', '$bbcode_uid', '$post_text'"; + + DB()->query("INSERT INTO ". BB_POSTS_TEXT ." ($post_text_columns) VALUES ($post_text_values)"); +} + +function topic_review ($topic_id) +{ + global $bb_cfg, $lang, $template; + + // Fetch posts data + $review_posts = DB()->fetch_rowset(" + SELECT + p.*, + pt.post_text, pt.bbcode_uid, + IF(p.poster_id = ". ANONYMOUS .", p.post_username, u.username) AS username, u.user_id + FROM + ". BB_POSTS ." p, + ". BB_POSTS_TEXT ." pt, + ". BB_USERS ." u + WHERE + p.topic_id = ". (int) $topic_id ." + AND pt.post_id = p.post_id + AND u.user_id = p.poster_id + ORDER BY p.post_time DESC + LIMIT ". $bb_cfg['posts_per_page'] ." + "); + + // Topic posts block + foreach ($review_posts as $i => $post) + { + $poster_name = ($post['username']) ? wbr($post['username']) : $lang['GUEST']; + + $template->assign_block_vars('review', array( + 'ROW_CLASS' => !($i % 2) ? 'row1' : 'row2', + 'POSTER_NAME' => $poster_name, + 'POSTER_NAME_JS' => addslashes($poster_name), + 'POST_DATE' => bb_date($post['post_time'], $bb_cfg['post_date_format']), + 'MESSAGE' => get_parsed_post($post), + )); + } + + $template->assign_vars(array( + 'TPL_TOPIC_REVIEW' => (bool) $review_posts, + 'L_TOPIC_REVIEW' => $lang['TOPIC_REVIEW'], + )); +} \ No newline at end of file diff --git a/upload/includes/functions_report.php b/upload/includes/functions_report.php new file mode 100644 index 000000000..e1d430ef0 --- /dev/null +++ b/upload/includes/functions_report.php @@ -0,0 +1,1404 @@ + $report_subject) + { + $temp[(int) $report_id] = (int) $report_subject[0]; + } + } + else + { + foreach ($subjects as $report_id => $report_subject) + { + $temp[(int) $report_id] = array( + (int) $report_subject[0], + $report_subject[1]); + } + } + + $subjects = $temp; +} + +// +// Reads modules from cache file +// +function report_modules_cache_read() +{ + return CACHE('bb_cache')->get('report_modules'); +} + +// +// Writes modules to cache file +// +function report_modules_cache_write($modules) +{ + return (bool) CACHE('bb_cache')->set('report_modules', $modules, 86400); +} + +// +// Deletes modules cache file +// +function report_modules_cache_clean() +{ + CACHE('bb_cache')->rm('report_modules'); +} + +// +// Obtains modules from the database +// +function report_modules_obtain() +{ + $sql = 'SELECT report_module_id, report_module_order, report_module_notify, report_module_prune, report_module_last_prune, + report_module_name, auth_write, auth_view, auth_notify, auth_delete + FROM ' . BB_REPORTS_MODULES . ' + ORDER BY report_module_order'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report modules', '', __LINE__, __FILE__, $sql); + } + + $modules = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($modules)) + { + return array(); + } + + return $modules; +} + +// +// Obtains report modules from the database or the cache, includes modules and +// stores module objects +// +function report_modules($mode = 'all', $module = null) +{ + global $bb_cfg; + static $modules; + static $module_names; + + if (!isset($modules)) + { + include(INC_DIR . "report_module.php"); + + if (!$bb_cfg['report_modules_cache'] || !$rows = report_modules_cache_read()) + { + $rows = report_modules_obtain(); + + if ($bb_cfg['report_modules_cache']) + { + report_modules_cache_write($rows); + } + } + + $modules = $module_names = array(); + foreach ($rows as $row) + { + // Include module file + $row['report_module_name'] = basename($row['report_module_name']); + include(INC_DIR .'report_hack/' . $row['report_module_name'] . ".php"); + + // Include language file + $lang = array(); + $lang_file = LANG_ROOT_DIR ."lang_{$bb_cfg['default_lang']}/report_hack/lang_{$row['report_module_name']}.php"; + if (file_exists($lang_file)) + { + include($lang_file); + } + + // Create module object + $modules[$row['report_module_id']] = new $row['report_module_name']($row['report_module_id'], $row, $lang); + + // Add module name to convert array + $module_names[$row['report_module_name']] = $row['report_module_id']; + + // Delete old reports + if ($row['report_module_prune'] && $row['report_module_last_prune'] + ($row['report_module_prune'] * 3600) < time()) + { + report_prune($row['report_module_id'], $row['report_module_prune'] * 86400); + + if ($bb_cfg['report_modules_cache']) + { + report_modules_cache_clean(); + } + } + } + } + + switch ($mode) + { + case 'all': + return $modules; + break; + + case 'names': + return $module_names; + break; + + case 'name': + case 'id': + if (!isset($module)) + { + return false; + } + + $key = ($mode == 'name') ? $module_names[$module] : $module; + return (isset($modules[$key])) ? $modules[$key] : false; + break; + + default: + return false; + break; + } +} + +// +// Checks the authorisation for multiple reports, returns array with report ids +// +function reports_auth_check(&$reports, $auth_names = 'auth_view', $subject_auth = true) +{ + global $bb_cfg; + + if (!is_array($reports)) + { + return array(); + } + + $auth_check_array = $reports_data = array(); + foreach ($reports as $report) + { + if (!isset($auth_check_array[$report['report_module_id']])) + { + $auth_check_array[$report['report_module_id']] = array(); + } + + $auth_check_array[$report['report_module_id']][$report['report_id']] = array($report['report_subject'], $report['report_subject_data']); + + $reports_data[$report['report_id']] = $report; + } + + $reports = $report_ids = array(); + + $report_modules = report_modules(); + foreach ($auth_check_array as $report_module_id => $report_subjects) + { + $report_module =& $report_modules[$report_module_id]; + + // + // Check module authorisation + // + if (!$report_module->auth_check($auth_names)) + { + continue; + } + + // + // Check subject authorisation + // + if ($subject_auth && $bb_cfg['report_subject_auth']) + { + $report_module->subjects_auth_check($report_subjects); + if (empty($report_subjects)) + { + continue; + } + } + + foreach (array_keys($report_subjects) as $report_id) + { + $reports[] = $reports_data[$report_id]; + $report_ids[] = $report_id; + } + } + + return $report_ids; +} + +// +// Executes a module action +// +function reports_module_action($reports, $action_name, $action_params = array()) +{ + if (!is_array($reports)) + { + return; + } + + if (!is_array($action_params)) + { + $action_params = array(null, $action_params); + } + else + { + array_unshift($action_params, null); + } + + $report_modules_subjects = array(); + foreach ($reports as $report) + { + if (!isset($report_modules_subjects[$report['report_module_id']])) + { + $report_modules_subjects[$report['report_module_id']] = array(); + } + + $report_modules_subjects[$report['report_module_id']][$report['report_id']] = array($report['report_subject'], $report['report_subject_data']); + } + + $report_modules = report_modules(); + foreach ($report_modules_subjects as $report_module_id => $report_subjects) + { + $report_module =& $report_modules[$report_module_id]; + + if (method_exists($report_module, "action_$action_name")) + { + $action_params[0] = $report_subjects; + call_user_func_array(array($report_module, "action_$action_name"), $action_params); + } + } +} + +// +// Handles email notifications, note that this function has variable parameters +// Includes authorisation check +// +function report_notify($mode) +{ + global $userdata, $bb_cfg; + + $num_args = func_num_args(); + $notify_users = $reports = array(); + + switch ($mode) + { + case 'new': + if ($num_args < 2) + { + return false; + } + + $report = func_get_arg(1); + $reports[$report['report_id']] =& $report; + + // get module object + $report_module = report_modules('id', $report['report_module_id']); + + // + // Check if notifications are enabled + // + if (!$report_module->data['report_module_notify']) + { + break; + } + + // + // Obtain report reason description + // + if ($report['report_reason_id']) + { + $sql = 'SELECT report_reason_desc + FROM ' . BB_REPORTS_REASONS . ' + WHERE report_reason_id = ' . $report['report_reason_id']; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report reason desc', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $report['report_reason_desc'] = ($row) ? $row['report_reason_desc'] : ''; + } + else + { + $report['report_reason_desc'] = ''; + } + + // + // Obtain notification users + // + $user_level_sql = ($bb_cfg['report_list_admin']) ? '= ' . ADMIN : 'IN(' . ADMIN . ', ' . MOD . ')'; + $sql = 'SELECT user_id, user_level, user_email, user_lang, user_timezone, user_dateformat + FROM ' . BB_USERS . ' + WHERE user_active = 1 + AND user_level ' . $user_level_sql . ' + AND user_id <> ' . $userdata['user_id']; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain administrators and moderators', '', __LINE__, __FILE__, $sql); + } + + $notify_users[$report['report_id']] = array(); + while ($row = DB()->sql_fetchrow($result)) + { + // + // Check module authorisation + // + if (!$report_module->auth_check(array('auth_view', 'auth_notify'), $row)) + { + continue; + } + + // + // Check subject authorisation + // + if ($bb_cfg['report_subject_auth']) + { + $report_subject = array($report['report_id'] => array($report['report_subject'], $report['report_subject_data'])); + if (!$report_module->subjects_auth_check($report_subject, $row)) + { + continue; + } + } + + $notify_users[$report['report_id']][] = $row; + } + DB()->sql_freeresult($result); + + // specify email template + $email_template = 'report_new'; + break; + + case 'change': + if ($num_args < 3) + { + return false; + } + + $status = func_get_arg(1); + + $report_ids = func_get_arg(2); + report_prepare_ids($report_ids); + + // + // Obtain report information + // + $sql = 'SELECT r.report_id, r.report_module_id, r.report_subject, r.report_subject_data, r.report_title, r.report_desc, + rc.report_change_time, rc.report_change_comment, u.username + FROM ' . BB_REPORTS . ' r + INNER JOIN ' . BB_REPORTS_CHANGES . ' rc + ON rc.report_change_id = r.report_last_change + INNER JOIN ' . BB_USERS . ' u + ON u.user_id = rc.user_id + WHERE r.report_id IN(' . implode(', ', $report_ids) . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report information', '', __LINE__, __FILE__, $sql); + } + + $auth_check_array = array(); + while ($row = DB()->sql_fetchrow($result)) + { + if (isset($row['report_subject_data'])) + { + $row['report_subject_data'] = unserialize($row['report_subject_data']); + } + + if (!isset($auth_check_array[$row['report_module_id']])) + { + $auth_check_array[$row['report_module_id']] = array(); + } + + $auth_check_array[$row['report_module_id']][$row['report_id']] = array($row['report_subject'], $row['report_subject_data']); + + $reports[$row['report_id']] = $row; + } + DB()->sql_freeresult($result); + + // + // Obtain notification users + // + $user_level_sql = ($bb_cfg['report_list_admin']) ? '= ' . ADMIN : 'IN(' . ADMIN . ', ' . MOD . ')'; + $sql = 'SELECT user_id, user_level, user_email, user_lang, user_dateformat, user_timezone + FROM ' . BB_USERS . ' + WHERE user_active = 1 + AND user_level ' . $user_level_sql . ' + AND user_id <> ' . $userdata['user_id']; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain administrators and moderators', '', __LINE__, __FILE__, $sql); + } + + $auth_options = array('auth_view', 'auth_notify'); + if ($status == REPORT_DELETE) + { + $auth_options[] = 'auth_delete'; + } + + $report_modules = report_modules(); + + while ($row = DB()->sql_fetchrow($result)) + { + foreach ($auth_check_array as $report_module_id => $report_subjects) + { + $report_module =& $report_modules[$report_module_id]; + + // + // Check if notifications are enabled + // + if (!$report_module->data['report_module_notify']) + { + continue; + } + + // + // Check module authorisation + // + if (!$report_module->auth_check($auth_options, $row)) + { + continue; + } + + // + // Check subject authorisation + // + if ($bb_cfg['report_subject_auth']) + { + $report_module->subjects_auth_check($report_subjects, $row); + } + + // + // Add users + // + foreach (array_keys($report_subjects) as $report_id) + { + if (!isset($notify_users[$report_id])) + { + $notify_users[$report_id] = array(); + } + + $notify_users[$report_id][] = $row; + } + } + } + DB()->sql_freeresult($result); + + // specify email template + $email_template = 'report_change'; + break; + + default: + return false; + break; + } + + if (empty($notify_users)) + { + return true; + } + + // Sixty second limit + @set_time_limit(60); + + // + // Let's do some checking to make sure that mass mail functions + // are working in win32 versions of php. + // + if (preg_match('/[c-z]:\\\.*/i', getenv('PATH')) && !$bb_cfg['smtp_delivery']) + { + $ini_val = (@phpversion() >= '4.0.0') ? 'ini_get' : 'get_cfg_var'; + + // We are running on windows, force delivery to use our smtp functions + // since php's are broken by default + $bb_cfg['smtp_delivery'] = 1; + $bb_cfg['smtp_host'] = @$ini_val('SMTP'); + } + + include(INC_DIR . "emailer.class.php"); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $server_name = trim($bb_cfg['server_name']); + $server_protocol = ($bb_cfg['cookie_secure']) ? 'https://' : 'http://'; + $server_port = ($bb_cfg['server_port'] <> 80) ? ':' . trim($bb_cfg['server_port']) . '/' : '/'; + $script_path = preg_replace('#^/?(.*?)/?$#', '$1', trim($bb_cfg['script_path'])); + $script_path .= ($script_path != '') ? '/' : ''; + $server_full = $server_protocol . $server_name . $server_port . $script_path; + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + // + // Send emails + // + foreach ($notify_users as $report_id => $report_notify_users) + { + $report =& $reports[$report_id]; + foreach ($report_notify_users as $user_info) + { + $emailer->use_template($email_template, $user_info['user_lang']); + $emailer->email_address($user_info['user_email']); + + // Get language variables + $lang =& report_notify_lang($user_info['user_lang']); + + // + // Set email variables + // we use $vars here because of an emailer bug + // + $vars = array( + 'EMAIL_SIG' => (!empty($bb_cfg['board_email_sig'])) ? str_replace('
    ', "\n", "-- \n" . $bb_cfg['board_email_sig']) : '', + 'SITENAME' => $bb_cfg['sitename'], + + 'REPORT_TITLE' => $report['report_title'], + 'REPORT_TEXT' => $report['report_desc'], + + 'U_REPORT_VIEW' => $server_full . "report.php?" . POST_REPORT_URL . "=$report_id"); + + switch ($mode) + { + case 'new': + if ($report['report_reason_desc']) + { + $report_reason = (isset($lang[$report['report_reason_desc']])) ? $lang[$report['report_reason_desc']] : $report['report_reason_desc']; + } + else + { + $report_reason = '-'; + } + + $vars = array_merge($vars, array( + 'REPORT_AUTHOR' => $userdata['username'], + 'REPORT_TIME' => bb_date($report['report_time'], $user_info['user_dateformat'], $user_info['user_timezone']), + 'REPORT_REASON' => $report_reason) + ); + break; + + case 'change': + $vars = array_merge($vars, array( + 'REPORT_CHANGE_AUTHOR' => $report['username'], + 'REPORT_CHANGE_TIME' => bb_date($report['report_change_time'], $user_info['user_dateformat'], $user_info['user_timezone']), + 'REPORT_CHANGE_STATUS' => $lang['REPORT_STATUS'][$status], + 'REPORT_CHANGE_COMMENT' => str_replace(array("\r\n", "\r", "\n"), ' ', $report['report_change_comment'])) + ); + break; + } + + $emailer->assign_vars($vars); + + $emailer->send(); + $emailer->reset(); + } + } + + return true; +} + +// +// Helper function for report_notify(), returns general language variable for the specified +// language +// +function &report_notify_lang($language) +{ + global $bb_cfg; + static $languages = array(); + $language = $bb_cfg['default_lang']; + + if (!isset($languages[$language])) + { + if ($bb_cfg['default_lang'] == $language) + { + global $lang; + } + else + { + $lang = array(); + include(LANG_ROOT_DIR ."lang_$language/lang_main.php"); + } + + $languages[$language] = $lang; + } + + return $languages[$language]; +} + +// +// Obtains count of new and open reports +// Includes authorisation check +// +function report_count_obtain() +{ + global $userdata, $bb_cfg; + static $report_count; + + if (isset($report_count)) + { + return $report_count; + } + + if ($userdata['user_level'] == ADMIN) + { + $sql = 'SELECT COUNT(report_id) AS report_count + FROM ' . BB_REPORTS . ' + WHERE report_status IN(' . REPORT_NEW . ', ' . REPORT_OPEN . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report count', '', __LINE__, __FILE__, $sql); + } + + $report_count = DB()->sql_fetchfield('report_count', 0, $result); + DB()->sql_freeresult($result); + } + else if ($userdata['user_level'] != MOD) + { + $report_count = 0; + } + else if (!$bb_cfg['report_subject_auth']) + { + $sql = 'SELECT COUNT(r.report_id) AS report_count + FROM ' . BB_REPORTS . ' r + INNER JOIN ' . BB_REPORTS_MODULES . ' rm + ON rm.report_module_id = r.report_module_id + WHERE report_status IN(' . REPORT_NEW . ', ' . REPORT_OPEN . ') + AND rm.auth_view <= ' . REPORT_AUTH_MOD; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report count', '', __LINE__, __FILE__, $sql); + } + + $report_count = DB()->sql_fetchfield('report_count', 0, $result); + DB()->sql_freeresult($result); + } + else + { + $sql = 'SELECT report_id, report_module_id, report_subject, report_subject_data + FROM ' . BB_REPORTS . ' + WHERE report_status IN(' . REPORT_NEW . ', ' . REPORT_OPEN . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not check report auth', '', __LINE__, __FILE__, $sql); + } + + $reports = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (!empty($reports)) + { + for ($i = 0, $count = count($reports); $i < $count; $i++) + { + if (isset($reports[$i]['report_subject_data'])) + { + $reports[$i]['report_subject_data'] = unserialize($reports[$i]['report_subject_data']); + } + } + + reports_auth_check($reports); + $report_count = count($reports); + } + else + { + $report_count = 0; + } + } + + return $report_count; +} + + +// +// Obtains reports (for a specific report module if $module_id is defined) +// Includes authorisation check if $auth_check is set to true. +// +function reports_obtain($module_id = null, $auth_check = true) +{ + $where_sql = (isset($module_id)) ? 'AND r.report_module_id = ' . (int) $module_id : ''; + $sql = 'SELECT r.report_id, r.user_id, r.report_time, r.report_module_id, r.report_status, r.report_subject, + r.report_subject_data, r.report_title, u.username + FROM ' . BB_REPORTS . ' r + LEFT JOIN ' . BB_USERS . ' u + ON u.user_id = r.user_id + WHERE r.report_status <> ' . REPORT_DELETE . " + $where_sql + ORDER BY r.report_status ASC, r.report_time DESC"; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain reports', '', __LINE__, __FILE__, $sql); + } + + $rows = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($rows)) + { + return array(); + } + + for ($i = 0, $count = count($rows); $i < $count; $i++) + { + if (isset($rows[$i]['report_subject_data'])) + { + $rows[$i]['report_subject_data'] = unserialize($rows[$i]['report_subject_data']); + } + } + + // + // Check authorisation + // + if ($auth_check) + { + reports_auth_check($rows); + } + + // + // Prepare reports array + // + $reports = array(); + foreach ($rows as $row) + { + if (!isset($reports[$row['report_module_id']])) + { + $reports[$row['report_module_id']] = array(); + } + + $reports[$row['report_module_id']][] = $row; + } + + return $reports; +} + +// +// Obtains open reports +// Includes authorisation check if $auth_check is set to true. +// +function reports_open_obtain($module_id, $report_subject, $auth_check = true) +{ + $sql = 'SELECT r.report_id, r.user_id, r.report_time, r.report_module_id, r.report_status, r.report_subject, + r.report_subject_data, r.report_title, u.username + FROM ' . BB_REPORTS . ' r + LEFT JOIN ' . BB_USERS . ' u + ON u.user_id = r.user_id + WHERE r.report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + AND r.report_module_id = ' . (int) $module_id . ' + AND r.report_subject = ' . (int) $report_subject . ' + ORDER BY r.report_status ASC, r.report_time DESC'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain open reports', '', __LINE__, __FILE__, $sql); + } + + $reports = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($reports)) + { + return array(); + } + + for ($i = 0, $count = count($reports); $i < $count; $i++) + { + if (isset($reports[$i]['report_subject_data'])) + { + $reports[$i]['report_subject_data'] = unserialize($reports[$i]['report_subject_data']); + } + } + + // + // Check authorisation + // + if ($auth_check) + { + reports_auth_check($reports); + } + + return $reports; +} + +// +// Obtains reports suggested for deletion +// Includes authorisation check if $auth_check is set to true. +// +function reports_deleted_obtain($auth_check = true) +{ + $sql = 'SELECT r.report_id, r.user_id, r.report_time, r.report_module_id, r.report_subject, + r.report_subject_data, r.report_title, u.username + FROM ' . BB_REPORTS . ' r + LEFT JOIN ' . BB_USERS . ' u + ON u.user_id = r.user_id + WHERE r.report_status = ' . REPORT_DELETE . ' + ORDER BY r.report_time DESC'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain deleted reports', '', __LINE__, __FILE__, $sql); + } + + $reports = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($reports)) + { + return array(); + } + + for ($i = 0, $count = count($reports); $i < $count; $i++) + { + if (isset($reports[$i]['report_subject_data'])) + { + $reports[$i]['report_subject_data'] = unserialize($reports[$i]['report_subject_data']); + } + } + + // + // Check authorisation + // + if ($auth_check) + { + reports_auth_check($reports, array('auth_view', 'auth_delete')); + } + + return $reports; +} + +// +// Obtains report information for the specified report. +// Includes authorisation check if $auth_check is set to true. +// +function report_obtain($report_id, $auth_check = true) +{ + global $bb_cfg, $lang; + + $sql = 'SELECT r.report_id, r.user_id, r.report_time, r.report_module_id, r.report_status, r.report_subject, + r.report_subject_data, r.report_title, r.report_desc, rr.report_reason_desc, u.username + FROM ' . BB_REPORTS . ' r + LEFT JOIN ' . BB_REPORTS_REASONS . ' rr + ON rr.report_reason_id = r.report_reason_id + LEFT JOIN ' . BB_USERS . ' u + ON u.user_id = r.user_id + WHERE r.report_id = ' . (int) $report_id; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report', '', __LINE__, __FILE__, $sql); + } + + $report = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (!$report) + { + return false; + } + + if (isset($report['report_subject_data'])) + { + $report['report_subject_data'] = unserialize($report['report_subject_data']); + } + + if (isset($report['report_reason_desc']) && isset($lang[$report['report_reason_desc']])) + { + $report['report_reason_desc'] = $lang[$report['report_reason_desc']]; + } + + // + // Check authorisation + // + if ($auth_check) + { + $auth_names = ($report['report_status'] == REPORT_DELETE) ? array('auth_view', 'auth_delete') : 'auth_view'; + $reports = array($report); + + reports_auth_check($reports, $auth_names); + + return (!empty($reports)) ? $reports[0] : false; + } + else + { + return $report; + } +} + +// +// Returns report changes for the specified report. +// Doesn't include authorisation check +// +function report_changes_obtain($report_id) +{ + $sql = 'SELECT rc.user_id, rc.report_change_time, rc.report_status, rc.report_change_comment, u.username + FROM ' . BB_REPORTS_CHANGES . ' rc + LEFT JOIN ' . BB_USERS . ' u + ON u.user_id = rc.user_id + WHERE rc.report_id = ' . (int) $report_id . ' + ORDER BY rc.report_change_time'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report changes', '', __LINE__, __FILE__, $sql); + } + + $report_changes = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($report_changes)) + { + return array(); + } + + return $report_changes; +} + +// +// Checks if there is a duplicate report +// +function report_duplicate_check($module_id, $report_subject) +{ + $sql = 'SELECT COUNT(report_id) AS count + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . (int) $module_id . ' + AND report_subject = ' . (int) $report_subject . ' + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not check for duplicate reports', '', __LINE__, __FILE__, $sql); + } + + $count = DB()->sql_fetchfield('count', 0, $result); + DB()->sql_freeresult($result); + + return ($count > 0); +} + +// +// Deletes old reports +// +function report_prune($module_id, $prune_time) +{ + // + // Obtain old reports + // + $sql = 'SELECT r.report_id, r.report_module_id, r.report_subject, r.report_subject_data + FROM ' . BB_REPORTS . ' r + INNER JOIN ' . BB_REPORTS_CHANGES . ' rc + ON rc.report_change_id = r.report_last_change + WHERE r.report_module_id = ' . (int) $module_id . ' + AND r.report_status IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + AND rc.report_change_time < ' . (time() - (int) $prune_time); + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain old reports', '', __LINE__, __FILE__, $sql); + } + + $reports = $report_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $reports[] = $row; + $report_ids[] = $row['report_id']; + } + DB()->sql_freeresult($result); + + // Execute module action + reports_module_action($reports, 'delete'); + + // Delete reports + reports_delete($report_ids, false, false); + + // + // Set last prune date + // + $sql = 'UPDATE ' . BB_REPORTS_MODULES . ' + SET report_module_last_prune = ' . time() . ' + WHERE report_module_id = ' . (int) $module_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete old reports', '', __LINE__, __FILE__, $sql); + } +} + +// +// Inserts a new report +// Includes authorisation check if $auth_check is set to true. +// +function report_insert($module_id, $report_subject, $report_reason, $report_title, $report_desc, $auth_check = true, $module_action = true, $notify = true) +{ + global $userdata, $bb_cfg; + + $report_module = report_modules('id', $module_id); + + // + // Check authorisation + // + if ($auth_check && !$report_module->auth_check('auth_write')) + { + return false; + } + + if (method_exists($report_module, 'subject_data_obtain')) + { + $report_subject_data = $report_module->subject_data_obtain($report_subject); + + if (is_array($report_subject_data)) + { + $report_subject_data_sql = "'" . str_replace("\'", "''", addslashes(serialize($report_subject_data))) . "'"; + } + else + { + $report_subject_data_sql = 'NULL'; + } + } + else + { + $report_subject_data = null; + $report_subject_data_sql = 'NULL'; + } + + // + // Insert report + // + $sql = 'INSERT INTO ' . BB_REPORTS . ' (user_id, report_time, report_module_id, report_status, report_reason_id, + report_subject, report_subject_data, report_title, report_desc) + VALUES (' . $userdata['user_id'] . ', ' . time() . ', ' . (int) $module_id . ', ' . REPORT_NEW . ', ' . (int) $report_reason . ', + ' . (int) $report_subject . ", $report_subject_data_sql, '" . str_replace("'", "''", $report_title) . "', + '" . str_replace("'", "''", $report_desc) . "')"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not insert report', '', __LINE__, __FILE__, $sql); + } + + $report_id = DB()->sql_nextid(); + + $report = array( + 'report_id' => $report_id, + 'report_time' => time(), + 'report_module_id' => $module_id, + 'report_reason_id' => $report_reason, + 'report_subject' => $report_subject, + 'report_subject_data' => $report_subject_data, + 'report_title' => $report_title, + 'report_desc' => $report_desc); + + // + // Execute module action + // + if ($module_action) + { + $report_module = report_modules('id', $module_id); + if (method_exists($report_module, 'action_insert')) + { + $report_module->action_insert($report_subject, $report_id, $report_subject_data); + } + } + + /*DB()->sql_query('');*/ + + // + // Send report notifications + // + if ($notify && ($bb_cfg['report_notify'] == REPORT_NOTIFY_NEW || $bb_cfg['report_notify'] == REPORT_NOTIFY_CHANGE)) + { + report_notify('new', $report); + } + + // + // Increase report counter + // + if (isset($bb_cfg['report_hack_count'])) + { + $sql = 'UPDATE ' . BB_CONFIG . " + SET config_value = config_value + 1 + WHERE config_name = 'report_hack_count'"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update report hack count', '', __LINE__, __FILE__, $sql); + } + } + + return $report_id; +} + +// +// Updates the status of the specified reports to $report_status, also inserts report status changes (with $comment) +// Includes authorisation check if $auth_check is set to true. +// +function reports_update_status($report_ids, $report_status, $comment = '', $auth_check = true, $module_action = true, $notify = true) +{ + global $userdata, $bb_cfg; + + report_prepare_ids($report_ids); + $report_status = (int) $report_status; + + if (empty($report_ids)) + { + return; + } + + if ($auth_check || $module_action) + { + $sql = 'SELECT report_id, report_module_id, report_subject, report_subject_data + FROM ' . BB_REPORTS . ' + WHERE report_id IN(' . implode(', ', $report_ids) . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain reports', '', __LINE__, __FILE__, $sql); + } + + $reports = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($reports)) + { + return; + } + } + + // + // Check authorisation + // + if ($auth_check) + { + $report_ids = reports_auth_check($reports); + } + + if (empty($report_ids)) + { + return; + } + + // Sorry, but we can't use transactions here because the DBAL doesn't allow BEGIN_TRANSACTION with an + // empty query + // DB()->sql_query(''); + + // + // Insert report status changes and update reports + // + $comment = str_replace("'", "''", $comment); + foreach ($report_ids as $report_id) + { + $sql = 'INSERT INTO ' . BB_REPORTS_CHANGES . " (report_id, user_id, report_change_time, report_status, report_change_comment) + VALUES($report_id, " . $userdata['user_id'] . ', ' . time() . ", $report_status, '$comment')"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not insert report change', __LINE__, __FILE__, $sql); + } + + $change_id = DB()->sql_nextid(); + + // + // Update reports + // + $sql = 'UPDATE ' . BB_REPORTS . " + SET + report_status = $report_status, + report_last_change = " . (int) $change_id . " + WHERE report_id = $report_id"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update reports status', '', __LINE__, __FILE__, $sql); + } + } + + // + // Execute module action + // + if ($module_action) + { + reports_module_action($reports, 'update_status', $report_status); + } + + /*DB()->sql_query('');*/ + + // + // Send report notifications + // + if ($notify && $bb_cfg['report_notify'] == REPORT_NOTIFY_CHANGE) + { + report_notify('change', $report_status, $report_ids); + } +} + +// +// Deletes the specified reports, also deletes report status changes +// Includes authorisation check if $auth_check is set to true. +// +function reports_delete($report_ids, $auth_check = true, $module_action = true) +{ + report_prepare_ids($report_ids); + + if (empty($report_ids)) + { + return; + } + + if ($auth_check || $module_action) + { + $sql = 'SELECT report_id, report_status, report_module_id, report_subject, report_subject_data + FROM ' . BB_REPORTS . ' + WHERE report_id IN(' . implode(', ', $report_ids) . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain reports', '', __LINE__, __FILE__, $sql); + } + + $reports = DB()->sql_fetchrowset($result); + DB()->sql_freeresult($result); + + if (empty($reports)) + { + return; + } + } + + // + // Check authorisation + // + if ($auth_check) + { + // general authorisation check + $update_ids = reports_auth_check($reports, array('auth_view', 'auth_delete_view')); + + // check for auth_delete + $report_ids = reports_auth_check($reports, 'auth_delete', false); + + // + // Update reports without auth_delete + // + for ($i = 0, $count = count($update_ids); $i < $count; $i++) + { + if (in_array($update_ids[$i], $report_ids)) + { + unset($update_ids[$i]); + } + } + + if (!empty($update_ids)) + { + reports_update_status($update_ids, REPORT_DELETE, false, false); + } + } + + $reports_sql = implode(', ', $report_ids); + if ($reports_sql == '') + { + return; + } + + // + // Delete reports + // + $sql = 'DELETE FROM ' . BB_REPORTS . " + WHERE report_id IN($reports_sql)"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete reports', '', __LINE__, __FILE__, $sql); + } + + // + // Delete report status changes + // + $sql = 'DELETE FROM ' . BB_REPORTS_CHANGES . " + WHERE report_id IN($reports_sql)"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete reports changes', '', __LINE__, __FILE__, $sql); + } + + // + // Execute module action + // + if ($module_action) + { + reports_module_action($reports, 'delete'); + } + + /*DB()->sql_query('');*/ +} + +// +// Returns report statistics +// +function report_statistics($mode) +{ + global $bb_cfg, $lang; + + switch ($mode) + { + case 'report_hack_count': + return $bb_cfg[$mode]; + break; + + case 'report_count': + $sql = 'SELECT COUNT(report_id) AS report_count + FROM ' . BB_REPORTS; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report statistics', '', __LINE__, __FILE__, $sql); + } + + $report_count = DB()->sql_fetchfield('report_count', 0, $result); + DB()->sql_freeresult($result); + + if ($report_count > $bb_cfg['report_hack_count']) + { + $sql = 'UPDATE ' . BB_CONFIG . " + SET config_value = '" . $report_count . "' + WHERE config_name = 'report_hack_count'"; + DB()->sql_query($sql); + } + + return $report_count; + break; + + case 'modules_count': + $report_modules = report_modules(); + + return count($report_modules); + break; + } + + return $mode; +} + +// +// Obtains all forums moderated by the specified user +// +function user_moderated_forums($user_id) +{ + static $moderators = array(); + + if (!isset($moderators[$user_id])) + { + // all auth_mod of user + $sql = 'SELECT aa.forum_id + FROM ' . BB_USER_GROUP . ' ug + INNER JOIN ' . BB_AUTH_ACCESS . ' aa + ON aa.group_id = ug.group_id + WHERE ug.user_id = ' . (int) $user_id . ' + AND aa.forum_perm = 8 + GROUP BY aa.forum_id'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain moderated forums', '', __LINE__, __FILE__, $sql); + } + + $moderators[$user_id] = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $moderators[$user_id][] = $row['forum_id']; + } + DB()->sql_freeresult($result); + } + + return $moderators[$user_id]; +} \ No newline at end of file diff --git a/upload/includes/functions_report_admin.php b/upload/includes/functions_report_admin.php new file mode 100644 index 000000000..c70b0ee21 --- /dev/null +++ b/upload/includes/functions_report_admin.php @@ -0,0 +1,571 @@ +sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report counts', '', __LINE__, __FILE__, $sql); + } + + $report_counts = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $report_counts[$row['report_module_id']] = $row['report_count']; + } + DB()->sql_freeresult($result); + + return $report_counts; +} + +// +// Obtains report reason count for each report module +// +function report_reason_counts_obtain() +{ + $sql = 'SELECT rm.report_module_id, COUNT(rr.report_reason_id) AS reason_count + FROM ' . BB_REPORTS_MODULES . ' rm + LEFT JOIN ' . BB_REPORTS_REASONS . ' rr + ON rr.report_module_id = rm.report_module_id + GROUP BY rm.report_module_id'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report reason counts', '', __LINE__, __FILE__, $sql); + } + + $report_reason_counts = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $report_reason_counts[$row['report_module_id']] = $row['reason_count']; + } + DB()->sql_freeresult($result); + + return $report_reason_counts; +} + +// +// Obtains inactive report modules, includes modules and stores module objects +// +function report_modules_inactive($mode = 'all', $module = null) +{ + global $bb_cfg; + static $modules; + + if (!isset($modules)) + { + if (!class_exists("report_module")) + include(INC_DIR . "report_module.php"); + + $installed_modules = report_modules('names'); + + $deny_modes = array('open', 'process', 'clear', 'delete', 'reported'); + + $dir = @opendir(INC_DIR .'report_hack'); + + $modules = array(); + $i = 0; + while ($file = @readdir($dir)) + { + if (!preg_match('#(.*)\.' . phpbb_preg_quote('php', '#') . '$#', $file, $matches)) + { + continue; + } + + // exclude installed modules + $module_name = $matches[1]; + if (isset($installed_modules[$module_name])) + { + continue; + } + + // include module file + include(INC_DIR . "report_hack/$file"); + + // Include language file + $lang = array(); + + $lang_file = LANG_ROOT_DIR ."lang_{$bb_cfg['default_lang']}/report_hack/lang_$module_name.php"; + if (file_exists($lang_file)) + { + include($lang_file); + } + + // Create module object + $modules[$module_name] = new $module_name(0, array('module_name' => $module_name), $lang); + + // + // Check validity of the module + // + if (!empty($modules[$module_name]->mode) && in_array($modules[$module_name]->mode, $deny_modes)) + { + unset($modules[$module_name]); + } + if (!isset($modules[$module_name]->id) || !isset($modules[$module_name]->data) || !isset($modules[$module_name]->lang) || !isset($modules[$module_name]->duplicates)) + { + unset($modules[$module_name]); + } + } + + @closedir($dir); + } + + switch ($mode) + { + case 'all': + return $modules; + break; + + case 'name': + if (!isset($module)) + { + return false; + } + + return (isset($modules[$module])) ? $modules[$module] : false; + break; + + default: + return false; + break; + } +} + +// +// Generates the auth select box +// +function report_auth_select($block_name, $default, $select_items = array(REPORT_AUTH_MOD, REPORT_AUTH_ADMIN)) +{ + global $lang, $template; + + foreach ($select_items as $value) + { + $template->assign_block_vars($block_name, array( + 'VALUE' => $value, + 'TITLE' => $lang['REPORT_AUTH'][$value], + 'SELECTED' => ($value == $default) ? ' selected="selected"' : '') + ); + } +} + +// +// Installs a report module +// +function report_module_install($module_notify, $module_prune, $module_name, $auth_write, $auth_view, $auth_notify, $auth_delete, $check = true) +{ + global $bb_cfg; + + // + // Check module + // + if ($check) + { + if (!$report_module = report_modules_inactive('name', $module_name)) + { + return false; + } + } + + // + // Get module order + // + $sql = 'SELECT MAX(report_module_order) AS max_order + FROM ' . BB_REPORTS_MODULES; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain max order', '', __LINE__, __FILE__, $sql); + } + + $max_order = DB()->sql_fetchfield('max_order', 0, $result); + DB()->sql_freeresult($result); + + // + // Insert module + // + $sql = 'INSERT INTO ' . BB_REPORTS_MODULES . ' (report_module_order, report_module_notify, report_module_prune, + report_module_name, auth_write, auth_view, auth_notify, auth_delete) + VALUES(' . ($max_order + 1) . ', ' . (int) $module_notify . ', ' . (int) $module_prune . ", + '" . str_replace("'", "''", $module_name) . "', " . (int) $auth_write . ', ' . (int) $auth_view . ', + ' . (int) $auth_notify . ', ' . (int) $auth_delete . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not install report module', '', __LINE__, __FILE__, $sql); + } + + $module_id = DB()->sql_nextid(); + + // + // Clean modules cache + // + if ($bb_cfg['report_modules_cache']) + { + report_modules_cache_clean(); + } + + return $module_id; +} + +// +// Edits a module +// +function report_module_edit($module_id, $module_notify, $module_prune, $auth_write, $auth_view, $auth_notify, $auth_delete) +{ + global $bb_cfg; + + $sql = 'UPDATE ' . BB_REPORTS_MODULES . ' + SET + report_module_notify = ' . (int) $module_notify . ', + report_module_prune = ' . (int) $module_prune . ', + auth_write = ' . (int) $auth_write . ', + auth_view = ' . (int) $auth_view . ', + auth_notify = ' . (int) $auth_notify . ', + auth_delete = ' . (int) $auth_delete . ' + WHERE report_module_id = ' . (int) $module_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not edit report module', '', __LINE__, __FILE__, $sql); + } + + // + // Clean modules cache + // + if ($bb_cfg['report_modules_cache']) + { + report_modules_cache_clean(); + } +} + +// +// Moves a module to another position (up or down), reorders other modules +// +function report_module_move($mode, $module_id, $steps = 1) +{ + global $bb_cfg; + + if (!$report_module = report_modules('id', $module_id)) + { + return false; + } + + switch ($mode) + { + case 'up': + $sql = 'UPDATE ' . BB_REPORTS_MODULES . " + SET report_module_order = report_module_order + 1 + WHERE report_module_order >= " . ($report_module->data['report_module_order'] - (int) $steps) . ' + AND report_module_order < ' . $report_module->data['report_module_order']; + break; + + case 'down': + $sql = 'UPDATE ' . BB_REPORTS_MODULES . " + SET report_module_order = report_module_order - 1 + WHERE report_module_order <= " . ($report_module->data['report_module_order'] + (int) $steps) . ' + AND report_module_order > ' . $report_module->data['report_module_order']; + break; + + default: + return false; + break; + } + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update module order', '', __LINE__, __FILE__, $sql); + } + + if (DB()->affected_rows()) + { + $op = ($mode == 'up') ? '-' : '+'; + $sql = 'UPDATE ' . BB_REPORTS_MODULES . " + SET report_module_order = report_module_order $op 1 + WHERE report_module_id = " . (int) $module_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update module order', '', __LINE__, __FILE__, $sql); + } + } + + DB()->sql_query(''); + + // + // Clean modules cache + // + if ($bb_cfg['report_modules_cache']) + { + report_modules_cache_clean(); + } + + return true; +} + +// +// Uninstalls a report module +// +function report_module_uninstall($module_id) +{ + global $bb_cfg; + + // + // Obtain reports in this module + // + $sql = 'SELECT report_id + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . (int) $module_id; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report ids', '', __LINE__, __FILE__, $sql); + } + + $report_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $report_ids = $row['report_id']; + } + DB()->sql_freeresult($result); + + // delete reports + reports_delete($report_ids, false, false); + + // + // Sync module + // + $report_module = report_modules('id', $module_id); + if (method_exists($report_module, 'sync')) + { + $report_module->sync(true); + } + + // + // Update module order + // + $sql = 'UPDATE ' . BB_REPORTS_MODULES . ' + SET report_module_order = report_module_order - 1 + WHERE report_module_order > ' . $report_module->data['report_module_order']; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update module order', '', __LINE__, __FILE__, $sql); + } + + // + // Delete report reasons + // + $sql = 'DELETE FROM ' . BB_REPORTS_REASONS . ' + WHERE report_module_id = ' . (int) $module_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete report reasons', '', __LINE__, __FILE__, $sql); + } + + // + // Delete module + // + $sql = 'DELETE FROM ' . BB_REPORTS_MODULES . ' + WHERE report_module_id = ' . (int) $module_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete report module', '', __LINE__, __FILE__, $sql); + } + + // + // Clean modules cache + // + if ($bb_cfg['report_modules_cache']) + { + report_modules_cache_clean(); + } +} + +// +// Obtains a report reason +// +function report_reason_obtain($reason_id) +{ + $sql = 'SELECT report_reason_desc + FROM ' . BB_REPORTS_REASONS . ' + WHERE report_reason_id = ' . (int) $reason_id; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report reason', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + return $row; +} + +// +// Inserts a report reason +// +function report_reason_insert($module_id, $reason_desc) +{ + // + // Get reason order + // + $sql = 'SELECT MAX(report_reason_order) AS max_order + FROM ' . BB_REPORTS_REASONS; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain max order', '', __LINE__, __FILE__, $sql); + } + + $max_order = DB()->sql_fetchfield('max_order', 0, $result); + DB()->sql_freeresult($result); + + // + // Insert reason + // + $sql = 'INSERT INTO ' . BB_REPORTS_REASONS . ' (report_module_id, report_reason_order, report_reason_desc) + VALUES(' . (int) $module_id . ', ' . ($max_order + 1) . ", '" . str_replace("'", "''", $reason_desc) . "')"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not insert report reason', '', __LINE__, __FILE__, $sql); + } + + return DB()->sql_nextid(); +} + +// +// Edits a report reason +// +function report_reason_edit($reason_id, $module_id, $reason_desc) +{ + $sql = 'UPDATE ' . BB_REPORTS_REASONS . ' + SET + report_module_id = ' . (int) $module_id . ", + report_reason_desc = '" . str_replace("'", "''", $reason_desc) . "' + WHERE report_reason_id = " . (int) $reason_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update report reason', '', __LINE__, __FILE__, $sql); + } +} + +// +// Moves a report reason to another position (up or down), reorders other report reasons +// +function report_reason_move($mode, $reason_id, $steps = 1) +{ + global $bb_cfg; + + // + // Obtain report reason information + // + $sql = 'SELECT report_module_id, report_reason_order + FROM ' . BB_REPORTS_REASONS . ' + WHERE report_reason_id = ' . (int) $reason_id; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report reason order', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (!$row) + { + return false; + } + + switch ($mode) + { + case 'up': + $sql = 'UPDATE ' . BB_REPORTS_REASONS . ' + SET report_reason_order = report_reason_order + 1 + WHERE report_module_id = ' . $row['report_module_id'] . ' + AND report_reason_order >= ' . ($row['report_reason_order'] - (int) $steps) . ' + AND report_reason_order < ' . $row['report_reason_order']; + break; + + case 'down': + $sql = 'UPDATE ' . BB_REPORTS_REASONS . ' + SET report_reason_order = report_reason_order - 1 + WHERE report_module_id = ' . $row['report_module_id'] . ' + AND report_reason_order <= ' . ($row['report_reason_order'] + (int) $steps) . ' + AND report_reason_order > ' . $row['report_reason_order']; + break; + + default: + return false; + break; + } + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update report reason order', '', __LINE__, __FILE__, $sql); + } + + if (DB()->affected_rows()) + { + $op = ($mode == 'up') ? '-' : '+'; + $sql = 'UPDATE ' . BB_REPORTS_REASONS . " + SET report_reason_order = report_reason_order $op 1 + WHERE report_reason_id = " . (int) $reason_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update report reason order', '', __LINE__, __FILE__, $sql); + } + } + + DB()->sql_query(''); + + return true; +} + +// +// Deletes a report reason +// +function report_reason_delete($reason_id) +{ + // + // Obtain report reason information + // + $sql = 'SELECT report_module_id, report_reason_order + FROM ' . BB_REPORTS_REASONS . ' + WHERE report_reason_id = ' . (int) $reason_id; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report reason', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (!$row) + { + return; + } + + // + // Update report reason order + // + $sql = 'UPDATE ' . BB_REPORTS_REASONS . ' + SET report_reason_order = report_reason_order - 1 + WHERE report_module_id = ' . $row['report_module_id'] . ' + AND report_reason_order > ' . $row['report_reason_order']; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update report reason order', '', __LINE__, __FILE__, $sql); + } + + // + // Delete report reason + // + $sql = 'DELETE FROM ' . BB_REPORTS_REASONS . ' + WHERE report_reason_id = ' . (int) $reason_id; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete report reason', '', __LINE__, __FILE__, $sql); + } +} \ No newline at end of file diff --git a/upload/includes/functions_selects.php b/upload/includes/functions_selects.php new file mode 100644 index 000000000..f982d6652 --- /dev/null +++ b/upload/includes/functions_selects.php @@ -0,0 +1,82 @@ +'; + while ( list($displayname, $filename) = @each($lang) ) + { + $selected = ( strtolower($default) == strtolower($filename) ) ? ' selected="selected"' : ''; + $lang_select .= ''; + } + $lang_select .= ''; + + return $lang_select; +} + +// +// Pick a timezone +// +function tz_select($default, $select_name = 'timezone') +{ + global $sys_timezone, $lang; + + if ( !isset($default) ) + { + $default == $sys_timezone; + } + $tz_select = ''; + + return $tz_select; +} \ No newline at end of file diff --git a/upload/includes/functions_torrent.php b/upload/includes/functions_torrent.php new file mode 100644 index 000000000..5accada57 --- /dev/null +++ b/upload/includes/functions_torrent.php @@ -0,0 +1,907 @@ +fetch_row($sql)) + { + message_die(GENERAL_ERROR, 'Invalid attach_id'); + } + + return $torrent; +} + +function torrent_auth_check ($forum_id, $poster_id) +{ + global $userdata, $lang, $attach_config; + + if (IS_ADMIN) return true; + + $is_auth = auth(AUTH_ALL, $forum_id, $userdata); + + if ($poster_id != $userdata['user_id'] && !$is_auth['auth_mod']) + { + message_die(GENERAL_MESSAGE, $lang['NOT_MODERATOR'], $lang['NOT_AUTHORISED']); + } + else if (!$is_auth['auth_view'] || !$is_auth['auth_attachments'] || $attach_config['disable_mod']) + { + $message = sprintf($lang['SORRY_AUTH_READ'], $is_auth['auth_read_type']); + message_die(GENERAL_MESSAGE, $message); + } + return $is_auth; +} + +function tracker_unregister ($attach_id, $mode = '') +{ + global $lang, $bb_cfg; + + $attach_id = (int) $attach_id; + $post_id = $topic_id = $forum_id = null; + + // Get torrent info + if ($torrent = get_torrent_info($attach_id)) + { + $post_id = $torrent['post_id']; + $topic_id = $torrent['topic_id']; + $forum_id = $torrent['forum_id']; + } + + if ($mode == 'request') + { + if (!$torrent) + { + message_die(GENERAL_ERROR, 'Torrent not found'); + } + if (!$torrent['tracker_status']) + { + message_die(GENERAL_ERROR, 'Torrent already unregistered'); + } + torrent_auth_check($forum_id, $torrent['poster_id']); + } + + if (!$topic_id) + { + $sql = "SELECT topic_id + FROM ". BB_BT_TORRENTS ." + WHERE attach_id = $attach_id"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not query torrent information', '', __LINE__, __FILE__, $sql); + } + if ($row = DB()->sql_fetchrow($result)) + { + $topic_id = $row['topic_id']; + } + } + + // Unset DL-Type for topic + if ($bb_cfg['bt_unset_dltype_on_tor_unreg'] && $topic_id) + { + $sql = "UPDATE ". BB_TOPICS ." SET + topic_dl_type = ". TOPIC_DL_TYPE_NORMAL ." + WHERE topic_id = $topic_id + LIMIT 1"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topics table', '', __LINE__, __FILE__, $sql); + } + } + + // XBTT + if($bb_cfg['announce_type'] == 'xbt') + { + $sql = 'INSERT INTO '. BB_BT_TORRENTS ."_del(topic_id, info_hash) + SELECT topic_id, info_hash + FROM ". BB_BT_TORRENTS ." + WHERE attach_id = $attach_id ON DUPLICATE KEY UPDATE is_del=1"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete torrent from torrents table', '', __LINE__, __FILE__, $sql); + } + } + // XBTT end. + + // Remove peers from tracker + $sql = "DELETE FROM ". BB_BT_TRACKER ." + WHERE topic_id = $topic_id"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete peers', '', __LINE__, __FILE__, $sql); + } + + // Delete torrent + $sql = "DELETE FROM ". BB_BT_TORRENTS ." + WHERE attach_id = $attach_id"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not delete torrent from torrents table', '', __LINE__, __FILE__, $sql); + } + + // Update tracker_status + $sql = "UPDATE ". BB_ATTACHMENTS_DESC ." SET + tracker_status = 0 + WHERE attach_id = $attach_id + LIMIT 1"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update torrent status', '', __LINE__, __FILE__, $sql); + } + + if ($mode == 'request') + { + exit_redirect($lang['BT_UNREGISTERED'], $post_id, $forum_id); + } +} + +function delete_torrent ($attach_id, $mode = '') +{ + global $lang, $userdata; + global $reg_mode, $topic_id; + + $attach_id = intval($attach_id); + $reg_mode = $mode; + + if (!$torrent = get_torrent_info($attach_id)) + { + message_die(GENERAL_ERROR, 'Torrent not found'); + } + + $post_id = $torrent['post_id']; + $topic_id = $torrent['topic_id']; + $forum_id = $torrent['forum_id']; + $poster_id = $torrent['poster_id']; + + if ($torrent['extension'] !== TORRENT_EXT) + { + message_die(GENERAL_ERROR, $lang['NOT_TORRENT']); + } + + torrent_auth_check($forum_id, $torrent['poster_id']); + tracker_unregister($attach_id); + delete_attachment(0, $attach_id); + + return; +} + +function change_tor_status ($attach_id, $new_tor_status) +{ + global $topic_id, $userdata; + + $attach_id = (int) $attach_id; + $new_tor_status = (int) $new_tor_status; + + if (!$torrent = get_torrent_info($attach_id)) + { + bb_die('Torrent not found'); + } + + $topic_id = $torrent['topic_id']; + + torrent_auth_check($torrent['forum_id'], $torrent['poster_id']); + + DB()->query(" + UPDATE ". BB_BT_TORRENTS ." SET + tor_status = $new_tor_status, + checked_user_id = {$userdata['user_id']}, + checked_time = '". TIMENOW ."' + WHERE attach_id = $attach_id + LIMIT 1 + "); +} + +// Set gold/silver type for torrent +function change_tor_type ($attach_id, $tor_status_gold) +{ + global $topic_id, $lang, $bb_cfg; + + if (!$torrent = get_torrent_info($attach_id)) + { + bb_die('Torrent not found'); + } + + if (!(IS_MOD || IS_ADMIN)) + { + bb_die($lang['ONLY_FOR_MOD']); + } + + $topic_id = $torrent['topic_id']; + $tor_status_gold = intval($tor_status_gold); + DB()->query("UPDATE ". BB_BT_TORRENTS ." SET tor_type = $tor_status_gold WHERE topic_id = $topic_id LIMIT 1"); + + // XBTT + if($bb_cfg['announce_type'] == 'xbt') + { + $sql = "SELECT CASE tor_type WHEN 1 THEN 0 WHEN 2 THEN 50 ELSE 100 END AS dl_percent, topic_id, info_hash FROM ". BB_BT_TORRENTS ." WHERE topic_id = $topic_id"; + $result = DB()->query($sql); + $row = DB()->sql_fetchrow($result); + $sql = "INSERT INTO ". BB_BT_TORRENTS ."_del(is_del, topic_id,info_hash, dl_percent) + VALUES (0, " .$row['topic_id'] .", '". $row['info_hash'] ."', ". $row['dl_percent'] .") ON DUPLICATE KEY UPDATE dl_percent = values(dl_percent)"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Error delete_torrents", '', __LINE__, __FILE__, $sql); + } + } +} + +function tracker_register ($attach_id, $mode = '') +{ + global $template, $attach_config, $bb_cfg, $lang, $return_message; + global $reg_mode; + + $attach_id = intval($attach_id); + $reg_mode = $mode; + + if (!$torrent = get_torrent_info($attach_id)) + { + message_die(GENERAL_ERROR, 'Torrent not found'); + } + + $post_id = $torrent['post_id']; + $topic_id = $torrent['topic_id']; + $forum_id = $torrent['forum_id']; + $poster_id = $torrent['poster_id']; + + if ($torrent['extension'] !== TORRENT_EXT) + { + torrent_error_exit($lang['NOT_TORRENT']); + } + + if (!$torrent['allow_reg_tracker']) + { + torrent_error_exit($lang['REG_NOT_ALLOWED_IN_THIS_FORUM']); + } + + if ($post_id != $torrent['topic_first_post_id']) + { + torrent_error_exit($lang['ALLOWED_ONLY_1ST_POST_REG']); + } + + if ($torrent['tracker_status']) + { + torrent_error_exit($lang['ALREADY_REG']); + } + + if ($this_topic_torrents = get_registered_torrents($topic_id, 'topic')) + { + torrent_error_exit($lang['ONLY_1_TOR_PER_TOPIC']); + } + + torrent_auth_check($forum_id, $torrent['poster_id']); + + $filename = get_attachments_dir() .'/'. $torrent['physical_filename']; + + if (!is_file($filename)) + { + torrent_error_exit('File name error'); + } + + if (!file_exists($filename)) + { + torrent_error_exit('File not exists'); + } + + if (!$tor = bdecode_file($filename)) + { + torrent_error_exit('This is not a bencoded file'); + } + + if ($bb_cfg['bt_disable_dht']) + { + $tor['info']['private'] = (int) 1; + //$tor['info']['source'] = (string) make_url('index.php'); + + $fp = fopen($filename, 'w+'); + fwrite ($fp, bencode($tor)); + fclose ($fp); + } + + if ($bb_cfg['bt_check_announce_url']) + { + include(INC_DIR .'torrent_announce_urls.php'); + + $ann = (@$tor['announce']) ? $tor['announce'] : ''; + $announce_urls['main_url'] = $bb_cfg['bt_announce_url']; + + if (!$ann || !in_array($ann, $announce_urls)) + { + $msg = sprintf($lang['INVALID_ANN_URL'], htmlspecialchars($ann), $announce_urls['main_url']); + torrent_error_exit($msg); + } + } + + $info = (@$tor['info']) ? $tor['info'] : array(); + + if (!@$info['name'] || !@$info['piece length'] || !@$info['pieces'] || strlen($info['pieces']) % 20 != 0) + { + torrent_error_exit('Invalid torrent file'); + } + + $info_hash = pack('H*', sha1(bencode($info))); + $info_hash_sql = rtrim(DB()->escape($info_hash), ' '); + $info_hash_md5 = md5($info_hash); + + $sql = "SELECT topic_id + FROM ". BB_BT_TORRENTS ." + WHERE info_hash = '$info_hash_sql' + LIMIT 1"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain torrent info', '', __LINE__, __FILE__, $sql); + } + if ($row = DB()->sql_fetchrow($result)) + { + $msg = sprintf($lang['BT_REG_FAIL_SAME_HASH'], append_sid(TOPIC_URL . $row['topic_id'])); + torrent_error_exit($msg); + } + + $totallen = 0; + + if (@$info['length']) + { + $totallen = (float) $info['length']; + } + else if (@$info['files'] && is_array($info['files'])) + { + foreach ($info['files'] as $fn => $f) + { + $totallen += (float) $f['length']; + } + } + else + { + torrent_error_exit('Invalid torrent file'); + } + + $reg_time = TIMENOW; + $size = sprintf('%.0f', (float) $totallen); + + $columns = ' info_hash, post_id, poster_id, topic_id, forum_id, attach_id, size, reg_time'; + $values = "'$info_hash_sql', $post_id, $poster_id, $topic_id, $forum_id, $attach_id, '$size', $reg_time"; + + $sql = "INSERT INTO ". BB_BT_TORRENTS ." ($columns) VALUES ($values)"; + + if (!DB()->sql_query($sql)) + { + $sql_error = DB()->sql_error(); + + if ($sql_error['code'] == 1062) // Duplicate entry + { + torrent_error_exit($lang['BT_REG_FAIL_SAME_HASH']); + } + message_die(GENERAL_ERROR, 'Could not register torrent on tracker', '', __LINE__, __FILE__, $sql); + } + + // update tracker status for this attachment + $sql = 'UPDATE '. BB_ATTACHMENTS_DESC ." SET + tracker_status = 1 + WHERE attach_id = $attach_id + LIMIT 1"; + + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update torrent status', '', __LINE__, __FILE__, $sql); + } + + // set DL-Type for topic + if ($bb_cfg['bt_set_dltype_on_tor_reg']) + { + $sql = 'UPDATE '. BB_TOPICS .' SET + topic_dl_type = '. TOPIC_DL_TYPE_DL ." + WHERE topic_id = $topic_id + LIMIT 1"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topics table', '', __LINE__, __FILE__, $sql); + } + } + + if ($reg_mode == 'request' || $reg_mode == 'newtopic') + { + $mess = sprintf($lang['BT_REGISTERED'], append_sid("download.php?id=$attach_id")); + exit_redirect($mess, $post_id, $forum_id); + } + + return; +} + +function send_torrent_with_passkey ($filename) +{ + global $attachment, $auth_pages, $userdata, $bb_cfg, $lang; + + if (!$bb_cfg['bt_add_auth_key'] || $attachment['extension'] !== TORRENT_EXT || !$size = @filesize($filename)) + { + return; + } + + $post_id = $poster_id = $passkey_val = ''; + $user_id = $userdata['user_id']; + $attach_id = $attachment['attach_id']; + + if (!$passkey_key = $bb_cfg['passkey_key']) + { + message_die(GENERAL_ERROR, 'Could not add passkey (wrong config $bb_cfg[\'passkey_key\'])'); + } + + // Get $post_id & $poster_id + foreach ($auth_pages as $rid => $row) + { + if ($row['attach_id'] == $attach_id) + { + $post_id = $row['post_id']; + $poster_id = $row['user_id_1']; + break; + } + } + + // Redirect guests to login page + if (IS_GUEST) + { + $redirect_url = ($post_id) ? POST_URL . $post_id : 'index.php'; + redirect(LOGIN_URL . $redirect_url); + } + + if (!$attachment['tracker_status']) + { + message_die(GENERAL_ERROR, $lang['PASSKEY_ERR_TOR_NOT_REG']); + } + + if ($userdata['session_logged_in'] && !$userdata['user_allow_passkey']) + { + message_die(GENERAL_ERROR, 'Could not add passkey

    You are not authorized to use passkey'); + } + + if ($bt_userdata = get_bt_userdata($user_id)) + { + $passkey_val = $bt_userdata['auth_key']; + } + + if (!$passkey_val && $userdata['session_logged_in']) + { + if ($bb_cfg['bt_gen_passkey_on_reg']) + { + if (!$passkey_val = generate_passkey($user_id)) + { + message_die(GENERAL_ERROR, 'Could not insert passkey', '', __LINE__, __FILE__, $sql); + } + } + else + { + $mess = sprintf($lang['PASSKEY_ERR_EMPTY'], append_sid("profile.php?mode=editprofile#bittorrent")); + message_die(GENERAL_ERROR, $mess); + } + } + + // Ratio limits + $min_ratio = $bb_cfg['bt_min_ratio_allow_dl_tor']; + + if ($min_ratio && $user_id != $poster_id && ($user_ratio = get_bt_ratio($bt_userdata)) !== null) + { + if ($user_ratio < $min_ratio && $post_id) + { + $dl = DB()->fetch_row(" + SELECT dl.user_status + FROM ". BB_POSTS ." p + LEFT JOIN ". BB_BT_DLSTATUS ." dl ON dl.topic_id = p.topic_id AND dl.user_id = $user_id + WHERE p.post_id = $post_id + LIMIT 1 + "); + + if (!isset($dl['user_status']) || $dl['user_status'] != DL_STATUS_COMPLETE) + { + $mess = sprintf($lang['BT_LOW_RATIO_FOR_DL'], round($user_ratio, 2), "search.php?dlu=$user_id&dlc=1"); + message_die(GENERAL_ERROR, $mess); + } + } + } + + // Seeding torrents limit + if ($bb_cfg['max_seeding_torrents'] && IS_USER) + { + $seeding = DB()->fetch_row(" + SELECT COUNT(DISTINCT topic_id) AS torrents, SUM(speed_up) AS sum_up + FROM ". BB_BT_TRACKER ." + WHERE user_id = $user_id + AND seeder = 1 + "); + + if ($seeding && $seeding['torrents'] > $bb_cfg['max_seeding_torrents'] && $bt_userdata['u_up_total'] < 200*1024*1024*1024) + { + if ($seeding['sum_up'] < ($seeding['torrents'] * $bb_cfg['min_up_speed_per_torrent'])) + { + $msg = array(); + $msg[] = date('m-d H:i:s'); + $msg[] = sprintf('%-30s', html_entity_decode($userdata['username'])." ($user_id)"); + $msg[] = sprintf('%-3s', $seeding['torrents']); + $msg[] = sprintf('%.2f', @$user_ratio); + $msg[] = sprintf('%-9s', humn_size($bt_userdata['u_up_total'], '', '', ' ')); + $msg[] = humn_size($seeding['sum_up'], '', '', ' '); + $msg = join(LOG_SEPR, $msg) . LOG_LF; + bb_log($msg, 'overseed/current'); + + redirect($bb_cfg['too_many_seeding_redirect_url']); + } + } + } + + // Announce URL + $ann_url = $bb_cfg['bt_announce_url']; + + if (!$tor = bdecode_file($filename)) + { + message_die(GENERAL_ERROR, 'This is not a bencoded file'); + } + + $passkey_url = (!$userdata['session_logged_in'] || isset($_GET['no_passkey'])) ? '' : "?$passkey_key=$passkey_val&"; + if ($passkey_url) + { + // XBTT unique passkey + if($bb_cfg['announce_type'] == 'xbt') + { + $info_hash = pack('H*', sha1(bencode($tor['info']))); + $passkey = substr('00000000'. dechex($userdata['user_id']), -8) . substr(sha1($bb_cfg['torrent_pass_private_key'] .' '. $passkey_val .' '. $userdata['user_id'] .' '. $info_hash), 0, 24); + $announce = preg_replace('@/a[^/]*$@i', "/$passkey$0", $ann_url); + } + else + { + $announce = strval($ann_url . $passkey_url); + } + } + + // Replace original announce url with tracker default + if ($bb_cfg['bt_replace_ann_url'] || !@$tor['announce']) + { + $tor['announce'] = $announce; + } + + // Delete all additional urls + if ($bb_cfg['bt_del_addit_ann_urls'] || $bb_cfg['bt_disable_dht']) + { + unset($tor['announce-list']); + } + elseif(@$tor['announce-list']) + { + $tor['announce-list'] = array_merge($tor['announce-list'], array(array($announce))); + } + + // Add publisher & topic url + $publisher = $bb_cfg['bt_add_publisher']; + $publisher_url = ($post_id) ? make_url(POST_URL . $post_id) : ''; + + if ($publisher) + { + $tor['publisher'] = strval($publisher); + unset($tor['publisher.utf-8']); + + if ($publisher_url) + { + $tor['publisher-url'] = strval($publisher_url); + unset($tor['publisher-url.utf-8']); + } + } + + // Add comment + $comment = ''; + + $orig_com = (@$tor['comment']) ? $tor['comment'] : ''; + + if ($bb_cfg['bt_add_comment']) + { + $comment = $bb_cfg['bt_add_comment']; + } + else + { + $comment = ($publisher_url) ? $publisher_url : ''; + } + + if ($comment = trim($comment)) + { + $tor['comment'] = strval($comment); + unset($tor['comment.utf-8']); + } + + //Azureus DHT disable + $tor['azureus_properties'] = array('dht_backup_enable' => intval(0)); + + // Send torrent + $output = bencode($tor); + $filename = clean_filename(basename($attachment['real_filename'])); + $mimetype = 'application/x-bittorrent;'; + $charset = (strpos(USER_AGENT, 'pera') && @$lang['CONTENT_ENCODING']) ? "charset={$lang['CONTENT_ENCODING']};" : ''; + +# header("Content-length: ". strlen($output)); + header("Content-Type: $mimetype $charset name=\"$filename\""); + header("Content-Disposition: attachment; filename=\"$filename\""); + + ##### LOG ##### + global $log_ip_resp; + + if (isset($log_ip_resp[USER_IP]) || isset($log_ip_resp[CLIENT_IP])) + { + $str = date('H:i:s') . LOG_SEPR . str_compact(ob_get_contents()) . LOG_LF; + $file = 'sessions/'. date('m-d') .'_{'. USER_IP .'}_'. CLIENT_IP .'_resp'; + bb_log($str, $file); + } + ### LOG END ### + + bb_exit($output); +} + +function generate_passkey ($user_id, $force_generate = false) +{ + global $lang, $sql; + + $user_id = (int) $user_id; + + // Check if user can change passkey + if (!$force_generate) + { + $sql = "SELECT user_allow_passkey + FROM ". BB_USERS ." + WHERE user_id = $user_id + LIMIT 1"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not query userdata for passkey', '', __LINE__, __FILE__, $sql); + } + if ($row = DB()->sql_fetchrow($result)) + { + if (!$row['user_allow_passkey']) + { + message_die(GENERAL_MESSAGE, $lang['NOT_AUTHORISED']); + } + } + } + + for ($i=0; $i < 20; $i++) + { + $passkey_val = make_rand_str(BT_AUTH_KEY_LENGTH); + + // Insert new row + $sql = "INSERT IGNORE INTO ". BB_BT_USERS ." (user_id, auth_key) VALUES ($user_id, '$passkey_val')"; + + if (DB()->sql_query($sql) && DB()->affected_rows() == 1) + { + return $passkey_val; + } + // Update + $sql = "UPDATE IGNORE ". BB_BT_USERS ." SET + auth_key = '$passkey_val' + WHERE user_id = $user_id + LIMIT 1"; + + if (DB()->sql_query($sql) && DB()->affected_rows() == 1) + { + return $passkey_val; + } + } + return false; +} + +function tracker_rm_torrent ($topic_id) +{ + return DB()->sql_query("DELETE FROM ". BB_BT_TRACKER ." WHERE topic_id = ". (int) $topic_id); +} + +function tracker_rm_user ($user_id) +{ + return DB()->sql_query("DELETE FROM ". BB_BT_TRACKER ." WHERE user_id = ". (int) $user_id); +} + +function get_registered_torrents ($id, $mode) +{ + $field = ($mode == 'topic') ? 'topic_id' : 'post_id'; + + $sql = "SELECT topic_id + FROM ". BB_BT_TORRENTS ." + WHERE $field = $id + LIMIT 1"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not query torrent id', '', __LINE__, __FILE__, $sql); + } + + if ($rowset = @DB()->sql_fetchrowset($result)) + { + return $rowset; + } + else + { + return false; + } +} + +function exit_redirect ($message, $post_id, $forum_id) +{ + global $template, $lang; + + $exit_message = $message .'

    '. sprintf($lang['CLICK_RETURN_TOPIC'], '', '') .'

    '. sprintf($lang['CLICK_RETURN_FORUM'], '', ''); + message_die(GENERAL_MESSAGE, $exit_message); +} + +function torrent_error_exit ($message) +{ + global $reg_mode, $return_message, $lang; + + $err_code = GENERAL_ERROR; + $msg = ''; + + if (isset($reg_mode) && ($reg_mode == 'request' || $reg_mode == 'newtopic')) + { + if (isset($return_message)) + { + $msg .= $return_message .'



    '; + } + $msg .= ''. $lang['BT_REG_FAIL'] .'

    '; + + $err_code = GENERAL_MESSAGE; + } + + $msg .= $message; + message_die($err_code, $msg); +} + +// bdecode: based on OpenTracker [http://whitsoftdev.com/opentracker] +function bdecode_file ($filename) +{ + $file_contents = file_get_contents($filename); + return bdecode($file_contents); +} + +function bdecode ($str) +{ + $pos = 0; + return bdecode_r($str, $pos); +} + +function bdecode_r ($str, &$pos) +{ + $strlen = strlen($str); + + if (($pos < 0) || ($pos >= $strlen)) + { + return null; + } + else if ($str[$pos] == 'i') + { + $pos++; + $numlen = strspn($str, '-0123456789', $pos); + $spos = $pos; + $pos += $numlen; + + if (($pos >= $strlen) || ($str[$pos] != 'e')) + { + return null; + } + else + { + $pos++; + return floatval(substr($str, $spos, $numlen)); + } + } + else if ($str[$pos] == 'd') + { + $pos++; + $ret = array(); + + while ($pos < $strlen) + { + if ($str[$pos] == 'e') + { + $pos++; + return $ret; + } + else + { + $key = bdecode_r($str, $pos); + + if ($key === null) + { + return null; + } + else + { + $val = bdecode_r($str, $pos); + + if ($val === null) + { + return null; + } + else if (!is_array($key)) + { + $ret[$key] = $val; + } + } + } + } + return null; + } + else if ($str[$pos] == 'l') + { + $pos++; + $ret = array(); + + while ($pos < $strlen) + { + if ($str[$pos] == 'e') + { + $pos++; + return $ret; + } + else + { + $val = bdecode_r($str, $pos); + + if ($val === null) + { + return null; + } + else + { + $ret[] = $val; + } + } + } + return null; + } + else + { + $numlen = strspn($str, '0123456789', $pos); + $spos = $pos; + $pos += $numlen; + + if (($pos >= $strlen) || ($str[$pos] != ':')) + { + return null; + } + else + { + $vallen = intval(substr($str, $spos, $numlen)); + $pos++; + $val = substr($str, $pos, $vallen); + + if (strlen($val) != $vallen) + { + return null; + } + else + { + $pos += $vallen; + return $val; + } + } + } +} \ No newline at end of file diff --git a/upload/includes/functions_validate.php b/upload/includes/functions_validate.php new file mode 100644 index 000000000..c9f7dca7a --- /dev/null +++ b/upload/includes/functions_validate.php @@ -0,0 +1,145 @@ + USERNAME_MAX_LENGTH) + { + return 'Слишком длинное имя пользователя'; + } + // Allowed symbols + if (!preg_match('#^['.$name_chars.']+$#iu', $username, $m)) + { + $invalid_chars = preg_replace('#['.$name_chars.']#iu', '', $username); + return "Имя $username содержит неподходящие символы: ". htmlCHR($invalid_chars) .''; + } + // HTML Entities + if (preg_match_all('/&(#[0-9]+|[a-z]+);/iu', $username, $m)) + { + foreach ($m[0] as $ent) + { + if (!preg_match('/^(&|<|>)$/iu', $ent)) + { + return 'Это имя содержит неподходящие символы'; + } + } + } + if ($check_ban_and_taken) + { + // Занято + $username_sql = DB()->escape($username); + + if ($row = DB()->fetch_row("SELECT username FROM ". BB_USERS ." WHERE username = '$username_sql' LIMIT 1")) + { + if ((!IS_GUEST && $row['username'] != $userdata['username']) || IS_GUEST) + { + return 'Пользователь с таким именем уже существует'; + } + } + // Запрещено + $banned_names = array(); + + foreach (DB()->fetch_rowset("SELECT disallow_username FROM ". BB_DISALLOW ." ORDER BY NULL") as $row) + { + $banned_names[] = str_replace('\*', '.*?', preg_quote($row['disallow_username'], '#u')); + } + if ($banned_names_exp = join('|', $banned_names)) + { + if (preg_match("#^($banned_names_exp)$#iu", $username)) + { + return 'Это имя было запрещено к использованию'; + } + } + } + + return false; +} + +// Check to see if email address is banned or already present in the DB +function validate_email ($email, $check_ban_and_taken = true) +{ + if (!$email || !preg_match('#^([_a-z\d])[a-z\d\.\-_]+@[a-z\d\-]+\.([a-z\d\-]+\.)*?[a-z]{2,4}$#i', $email)) + { + return 'Этот адрес email неправилен'; + } + if (strlen($email) > USEREMAIL_MAX_LENGTH) + { + return 'Слишком длинный email [максимум: '. USEREMAIL_MAX_LENGTH .' символов]'; + } + + if ($check_ban_and_taken) + { + $banned_emails = array(); + + foreach (DB()->fetch_rowset("SELECT ban_email FROM ". BB_BANLIST ." ORDER BY NULL") as $row) + { + $banned_emails[] = str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')); + } + if ($banned_emails_exp = join('|', $banned_emails)) + { + if (preg_match("#^($banned_emails_exp)$#i", $email)) + { + return 'Этот адрес email находится в чёрном списке'; + } + } + + $email_sql = DB()->escape($email); + + if (DB()->fetch_row("SELECT 1 FROM ". BB_USERS ." WHERE user_email = '$email_sql' LIMIT 1")) + { + return 'Этот адрес e-mail уже занят другим пользователем'; + } + } + + return false; +} + +// +// Does supplementary validation of optional profile fields. This expects common stuff like trim() and strip_tags() +// to have already been run. Params are passed by-ref, so we can set them to the empty string if they fail. +// +function validate_optional_fields(&$icq, &$website, &$location, &$occupation, &$interests, &$sig) +{ + $check_var_length = array('location', 'occupation', 'interests', 'sig'); + + for($i = 0; $i < count($check_var_length); $i++) + { + if (strlen($$check_var_length[$i]) < 2) + { + $$check_var_length[$i] = ''; + } + } + + // ICQ number has to be only numbers. + if (!preg_match('/^[0-9]+$/', $icq)) + { + $icq = ''; + } + + // website has to start with http://, followed by something with length at least 3 that + // contains at least one dot. + if ($website != "") + { + if (!preg_match('#^http[s]?:\/\/#i', $website)) + { + $website = 'http://' . $website; + } + + if (!preg_match('#^http[s]?\\:\\/\\/[a-z0-9\-]+\.([a-z0-9\-]+\.)?[a-z]+#i', $website)) + { + $website = ''; + } + } + + return; +} diff --git a/upload/includes/init_bb.php b/upload/includes/init_bb.php new file mode 100644 index 000000000..0d8010ec1 --- /dev/null +++ b/upload/includes/init_bb.php @@ -0,0 +1,663 @@ + 2400) + { + cron_enable_board(); + cron_release_file_lock(); + } + } +} + +function cron_release_file_lock () +{ + $lock_released = @rename(CRON_RUNNING, CRON_ALLOWED); + cron_touch_lock_file(CRON_ALLOWED); +} + +function cron_touch_lock_file ($lock_file) +{ + file_write(make_rand_str(20), $lock_file, 0, true, true); +} + +function cron_enable_board () +{ + @rename(BB_DISABLED, BB_ENABLED); +# bb_update_config(array('board_disable' => 0)); +} + +function cron_disable_board () +{ + @rename(BB_ENABLED, BB_DISABLED); +# bb_update_config(array('board_disable' => 1)); +} + +// Define some basic configuration arrays +unset($stopwords, $synonyms_match, $synonyms_replace); +$userdata = $theme = $images = $lang = $nav_links = $bf = $attach_config = array(); +$gen_simple_header = false; +$user = null; + +// Obtain and encode user IP +$client_ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1'; +$user_ip = encode_ip($client_ip); +define('CLIENT_IP', $client_ip); +define('USER_IP', $user_ip); + +function send_page ($contents) +{ + return compress_output($contents); +} + +define('UA_GZIP_SUPPORTED', (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false)); + +function compress_output ($contents) +{ + global $bb_cfg; + + if ($bb_cfg['gzip_compress'] && GZIP_OUTPUT_ALLOWED && !defined('NO_GZIP')) + { + if ((UA_GZIP_SUPPORTED || $bb_cfg['gzip_force']) && strlen($contents) > 2000) + { + header('Content-Encoding: gzip'); + $contents = gzencode($contents, 1); + } + } + + return $contents; +} + +// Start output buffering +if (!defined('IN_AJAX')) +{ + ob_start('send_page'); +} + +if (DEBUG === true) +{ + require(DEV_DIR .'init_debug.php'); +# if ($a); +# trigger_error("error handler test", E_USER_ERROR); +} + +// Config options +define('TPL_LIMIT_LOAD_EXIT', TEMPLATES_DIR .'limit_load_exit.php'); + +// Cookie params +$c = $bb_cfg['cookie_prefix']; +define('COOKIE_DATA', $c .'data'); +define('COOKIE_FORUM', $c .'f'); +define('COOKIE_LOAD', $c .'isl'); +define('COOKIE_MARK', $c .'mark_read'); +define('COOKIE_TEST', $c .'test'); +define('COOKIE_TOPIC', $c .'t'); +unset($c); + +define('COOKIE_SESSION', 0); +define('COOKIE_EXPIRED', TIMENOW - 31536000); +define('COOKIE_PERSIST', TIMENOW + 31536000); + +define('COOKIE_MAX_TRACKS', 90); + +function bb_setcookie ($name, $val, $lifetime = COOKIE_PERSIST, $httponly = false) +{ + global $bb_cfg; + + $domain = $bb_cfg['cookie_domain']; + + if (PHP_VERSION < 5.2) + { + // HttpOnly hack by Matt Mecham [http://blog.mattmecham.com/archives/2006/09/http_only_cookies_without_php.html] + $domain .= ($httponly) ? '; HttpOnly' : ''; + return setcookie($name, $val, $lifetime, $bb_cfg['cookie_path'], $domain, $bb_cfg['cookie_secure']); + } + else + { + return setcookie($name, $val, $lifetime, $bb_cfg['cookie_path'], $domain, $bb_cfg['cookie_secure'], $httponly); + } +} + +// Debug options +if (DBG_USER) +{ + error_reporting(E_ALL); + ini_set('display_errors', 1); +} + +define('DELETED', -1); + +// User Levels <- Do not change the values of USER or ADMIN +define('USER', 0); +define('ADMIN', 1); +define('MOD', 2); +define('GROUP_MEMBER', 20); + +$excluded_users = array( + ANONYMOUS, + BOT_UID, +); +define('EXCLUDED_USERS_CSV', implode(',', $excluded_users)); + +// User related +define('USER_ACTIVATION_NONE', 0); +define('USER_ACTIVATION_SELF', 1); +define('USER_ACTIVATION_ADMIN', 2); + +define('USER_AVATAR_NONE', 0); +define('USER_AVATAR_UPLOAD', 1); +define('USER_AVATAR_REMOTE', 2); +define('USER_AVATAR_GALLERY', 3); + +// Group settings +define('GROUP_OPEN', 0); +define('GROUP_CLOSED', 1); +define('GROUP_HIDDEN', 2); + +// Forum state +define('FORUM_UNLOCKED', 0); +define('FORUM_LOCKED', 1); + +// Topic status +define('TOPIC_UNLOCKED', 0); +define('TOPIC_LOCKED', 1); +define('TOPIC_MOVED', 2); + +define('TOPIC_WATCH_NOTIFIED', 1); +define('TOPIC_WATCH_UN_NOTIFIED', 0); + +// Topic types +define('POST_NORMAL', 0); +define('POST_STICKY', 1); +define('POST_ANNOUNCE', 2); +define('POST_GLOBAL_ANNOUNCE', 3); + +// Search types +define('SEARCH_TYPE_POST', 0); +define('SEARCH_TYPE_TRACKER', 1); + +// Error codes +define('GENERAL_MESSAGE', 200); +define('GENERAL_ERROR', 202); +define('CRITICAL_MESSAGE', 203); +define('CRITICAL_ERROR', 204); + +define('E_AJAX_GENERAL_ERROR', 1000); +define('E_AJAX_NEED_LOGIN', 1001); + +// Private messaging +define('PRIVMSGS_READ_MAIL', 0); +define('PRIVMSGS_NEW_MAIL', 1); +define('PRIVMSGS_SENT_MAIL', 2); +define('PRIVMSGS_SAVED_IN_MAIL', 3); +define('PRIVMSGS_SAVED_OUT_MAIL', 4); +define('PRIVMSGS_UNREAD_MAIL', 5); + +// URL PARAMETERS (hardcoding allowed) +define('POST_CAT_URL', 'c'); +define('POST_FORUM_URL', 'f'); +define('POST_GROUPS_URL', 'g'); +define('POST_POST_URL', 'p'); +define('POST_TOPIC_URL', 't'); +define('POST_USERS_URL', 'u'); + +// Download Modes +define('INLINE_LINK', 1); +define('PHYSICAL_LINK', 2); + +// Categories +define('NONE_CAT', 0); +define('IMAGE_CAT', 1); +define('STREAM_CAT', 2); +define('SWF_CAT', 3); + +// Misc +define('MEGABYTE', 1024); +define('ADMIN_MAX_ATTACHMENTS', 50); +define('THUMB_DIR', 'thumbs'); +define('MODE_THUMBNAIL', 1); + +// Forum Extension Group Permissions +define('GPERM_ALL', 0); // ALL FORUMS + +// Quota Types +define('QUOTA_UPLOAD_LIMIT', 1); +define('QUOTA_PM_LIMIT', 2); + +// Torrents +define('TOR_STATUS_NORMAL', 0); +define('TOR_STATUS_FROZEN', 1); + +// Report +// Report status constants +define('REPORT_NEW', 0); +define('REPORT_OPEN', 1); +define('REPORT_IN_PROCESS', 2); +define('REPORT_CLEARED', 3); +define('REPORT_DELETE', 4); +// Report authorisation constants +define('REPORT_AUTH_USER', 0); +define('REPORT_AUTH_MOD', 1); +define('REPORT_AUTH_CONFIRM', 2); +define('REPORT_AUTH_ADMIN', 3); +// Report notification constants +define('REPORT_NOTIFY_NEW', 1); +define('REPORT_NOTIFY_CHANGE', 2); +// Other report constants +define('POST_REPORT_URL', 'r'); +define('POST_REPORT_REASON_URL', 'r'); +// Report [END] + +// Torrents (reserved: -1) +define('TOR_NOT_APPROVED', 0); // не проверено +define('TOR_CLOSED', 1); // закрыто +define('TOR_APPROVED', 2); // проверено +define('TOR_NEED_EDIT', 3); // недооформлено +define('TOR_NO_DESC', 4); // неоформлено +define('TOR_DUP', 5); // повтор +define('TOR_CLOSED_CPHOLD', 6); // закрыто правообладателем +define('TOR_CONSUMED', 7); // поглощено +define('TOR_DOUBTFUL', 8); // сомнительно +define('TOR_CHECKING', 9); // проверяется +define('TOR_TMP', 10); // временная + +// Названия +$lang['tor_status'] = array( + TOR_TMP => 'временная', + TOR_CLOSED_CPHOLD => 'закрыто правообладателем', + TOR_CLOSED => 'закрыто', + TOR_NOT_APPROVED => 'не проверено', + TOR_NEED_EDIT => 'недооформлено', + TOR_NO_DESC => 'неоформлено', + TOR_DUP => 'повтор', + TOR_CONSUMED => 'поглощено', + TOR_APPROVED => 'проверено', + TOR_CHECKING => 'проверяется', + TOR_DOUBTFUL => 'сомнительно', +); + +// Список доступных модераторам статусов +$bb_cfg['change_tor_status_select'] = array( + TOR_CLOSED => 'закрыто', + TOR_NOT_APPROVED => 'не проверено', + TOR_NEED_EDIT => 'недооформлено', + TOR_NO_DESC => 'неоформлено', + TOR_DUP => 'повтор', + TOR_CONSUMED => 'поглощено', + TOR_TMP => 'временная', + TOR_APPROVED => 'проверено', + TOR_CHECKING => 'проверяется', + TOR_DOUBTFUL => 'сомнительно', +); + +$bb_cfg['tor_icons'] = array( + TOR_APPROVED => '', + TOR_CHECKING => '%', + TOR_CLOSED => 'x', + TOR_CLOSED_CPHOLD => '©', + TOR_CONSUMED => '', + TOR_DOUBTFUL => '#', + TOR_DUP => 'D', + TOR_NEED_EDIT => '?', + TOR_NO_DESC => '!', + TOR_NOT_APPROVED => '*', + TOR_TMP => 'T', +); + +// Запрет на скачивание +$bb_cfg['tor_frozen'] = array( + TOR_CHECKING => true, + TOR_CLOSED => true, + TOR_CLOSED_CPHOLD => true, + TOR_CONSUMED => true, + TOR_DUP => true, + TOR_NO_DESC => true, +); +// Запрет на редактирование головного сообщения +$bb_cfg['tor_cannot_edit'] = array( + TOR_CHECKING => true, + TOR_CLOSED => true, + TOR_CONSUMED => true, + TOR_DUP => true, +); + +// Table names +define('BUF_TOPIC_VIEW', 'buf_topic_view'); +define('BUF_LAST_SEEDER', 'buf_last_seeder'); +define('BB_ADS', 'bb_ads'); +define('BB_ATTACH_CONFIG', 'bb_attachments_config'); +define('BB_ATTACHMENTS_DESC', 'bb_attachments_desc'); +define('BB_ATTACHMENTS', 'bb_attachments'); +define('BB_AUTH_ACCESS_SNAP', 'bb_auth_access_snap'); +define('BB_AUTH_ACCESS', 'bb_auth_access'); +define('BB_BANLIST', 'bb_banlist'); +define('BB_BT_DLSTATUS_MAIN', 'bb_bt_dlstatus_main'); +define('BB_BT_DLSTATUS_NEW', 'bb_bt_dlstatus_new'); +define('BB_BT_DLSTATUS_SNAP', 'bb_bt_dlstatus_snap'); +define('BB_BT_DLSTATUS', 'bb_bt_dlstatus_mrg'); // main + new +define('BB_BT_LAST_TORSTAT', 'bb_bt_last_torstat'); +define('BB_BT_LAST_USERSTAT', 'bb_bt_last_userstat'); +define('BB_BT_TORHELP', 'bb_bt_torhelp'); +define('BB_BT_TORSTAT', 'bb_bt_torstat'); +define('BB_CATEGORIES', 'bb_categories'); +define('BB_CAPTCHA', 'bb_captcha'); +define('BB_CONFIG', 'bb_config'); +define('BB_COUNTRIES', 'bb_countries'); +define('BB_CRON', 'bb_cron'); +define('BB_DATASTORE', 'bb_datastore'); +define('BB_DISALLOW', 'bb_disallow'); +define('BB_EXTENSION_GROUPS', 'bb_extension_groups'); +define('BB_EXTENSIONS', 'bb_extensions'); +define('BB_FORUMS', 'bb_forums'); +define('BB_GROUPS', 'bb_groups'); +define('BB_LOG', 'bb_log'); +define('BB_POSTS_SEARCH', 'bb_posts_search'); +define('BB_POSTS', 'bb_posts'); +define('BB_POSTS_TEXT', 'bb_posts_text'); +define('BB_POSTS_HTML', 'bb_posts_html'); +define('BB_PRIVMSGS', 'bb_privmsgs'); +define('BB_PRIVMSGS_TEXT', 'bb_privmsgs_text'); +define('BB_QUOTA_LIMITS', 'bb_quota_limits'); +define('BB_QUOTA', 'bb_attach_quota'); +define('BB_RANKS', 'bb_ranks'); +define('BB_REPORTS', 'bb_reports'); // Report +define('BB_REPORTS_CHANGES', 'bb_reports_changes'); // Report Change's +define('BB_REPORTS_MODULES', 'bb_reports_modules'); // Report Module Table +define('BB_REPORTS_REASONS', 'bb_reports_reasons'); // Report Reasons +define('BB_SEARCH_REBUILD', 'bb_search_rebuild'); +define('BB_SEARCH', 'bb_search_results'); +define('BB_SESSIONS', 'bb_sessions'); +define('BB_SMILIES', 'bb_smilies'); +define('BB_TOPIC_TPL', 'bb_topic_templates'); +define('BB_TOPICS', 'bb_topics'); +define('BB_TOPICS_WATCH', 'bb_topics_watch'); +define('BB_USER_GROUP', 'bb_user_group'); +define('BB_USERS', 'bb_users'); +define('BB_VOTE_DESC', 'bb_vote_desc'); +define('BB_VOTE_RESULTS', 'bb_vote_results'); +define('BB_VOTE_USERS', 'bb_vote_voters'); +define('BB_WORDS', 'bb_words'); + +define('TORRENT_EXT', 'torrent'); + +define('TOPIC_DL_TYPE_NORMAL', 0); +define('TOPIC_DL_TYPE_DL', 1); + +define('SHOW_PEERS_COUNT', 1); +define('SHOW_PEERS_NAMES', 2); +define('SHOW_PEERS_FULL', 3); + +define('SEARCH_ID_LENGTH', 12); +define('SID_LENGTH', 20); +define('LOGIN_KEY_LENGTH', 12); +define('USERNAME_MAX_LENGTH', 25); +define('USEREMAIL_MAX_LENGTH', 40); + +define('PAGE_HEADER', INC_DIR .'page_header.php'); +define('PAGE_FOOTER', INC_DIR .'page_footer.php'); + +define('CAT_URL', "index.php?" .'c='); +define('DOWNLOAD_URL', "download.php?" .'id='); +define('FORUM_URL', "viewforum.php?" .'f='); +define('GROUP_URL', "groupcp.php?" .'g='); +define('LOGIN_URL', "login.php?" .'redirect='); +define('MODCP_URL', "modcp.php?" .'f='); +define('PM_URL', "privmsg.php?" .'mode=post&u='); +define('POST_URL', "viewtopic.php?" .'p='); +define('PROFILE_URL', "profile.php?" .'mode=viewprofile&u='); +define('TOPIC_URL', "viewtopic.php?" .'t='); + +define('USER_AGENT', @strtolower($_SERVER['HTTP_USER_AGENT'])); +define('UA_OPERA', strpos(USER_AGENT, 'pera')); +define('UA_IE', strpos(USER_AGENT, 'msie')); + +define('HTML_SELECT_MAX_LENGTH', 60); +define('HTML_WBR_LENGTH', 12); + +define('HTML_CHECKED', ' checked="checked" '); +define('HTML_DISABLED', ' disabled="disabled" '); +define('HTML_READONLY', ' readonly="readonly" '); +define('HTML_SELECTED', ' selected="selected" '); + +define('HTML_SF_SPACER', ' |- '); + +// $GPC +define('KEY_NAME', 0); // position in $GPC['xxx'] +define('DEF_VAL', 1); +define('GPC_TYPE', 2); + +define('GET', 1); +define('POST', 2); +define('COOKIE', 3); +define('REQUEST', 4); +define('CHBOX', 5); +define('SELECT', 6); + +if (!empty($banned_user_agents)) +{ + foreach ($banned_user_agents as $agent) + { + if (strstr(USER_AGENT, $agent)) + { +/*##### LOG ##### +$file = 'ban/user_agents_'. date('m-d'); +$str = array(); +$str[] = date('H:i:s'); +$str[] = @$_SERVER['HTTP_USER_AGENT']; +$str[] = @$_SERVER['REMOTE_ADDR']; +$str[] = @$_SERVER['REQUEST_URI']; +$str[] = @$_SERVER['HTTP_REFERER']; +bb_log($str, $file); +### LOG END ###*/ + + $filename = 'Skachivajte fajly brauzerom (скачивайте файлы браузером)'; + $output = '@'; + + header('Content-Type: text/plain'); + header('Content-Disposition: attachment; filename="'. $filename .'"'); + + die($output); + } + } +} + +// Functions +function send_no_cache_headers () +{ + header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); + header('Last-Modified: '. gmdate('D, d M Y H:i:s'). ' GMT'); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Cache-Control: post-check=0, pre-check=0', false); + header('Pragma: no-cache'); +} + +function bb_exit ($output = '') +{ + if ($output) + { + echo $output; + } + exit; +} + +// Exit if server overloaded +if (!(defined('IN_PROFILE') || defined('IN_LOGIN') || defined('IN_ADMIN') || defined('IN_AJAX') || defined('IN_SERVICE')) && BB_ROOT == './') +{ + if ($bb_cfg['max_srv_load'] && empty($_POST['message']) && !empty($_COOKIE[COOKIE_LOAD]) && LOADAVG) + { + if (LOADAVG > $bb_cfg['max_srv_load'] && (TIMENOW - $_COOKIE[COOKIE_LOAD]) > $bb_cfg['user_session_duration']) + { + require(TPL_LIMIT_LOAD_EXIT); + } + } +} + +function prn_r ($var, $title = '', $print = true) +{ + $r = '
    '. (($title) ? "$title\n\n" : '') . htmlspecialchars(print_r($var, true)) .'
    '; + if ($print) echo $r; + return $r; +} + +function prn () +{ + if (!DBG_USER) return; + foreach (func_get_args() as $var) prn_r($var); +} + +function vdump ($var, $title = '') +{ + echo '
    '. (($title) ? "$title\n\n" : '');
    +	var_dump($var);
    +	echo '
    '; +} + +function htmlCHR ($txt, $replace_space = false) +{ + return ($replace_space) ? str_replace(' ', ' ', htmlspecialchars($txt, ENT_QUOTES)) : htmlspecialchars($txt, ENT_QUOTES); +} + +function make_url ($path) +{ + return FULL_URL . preg_replace('#^\/?(.*?)\/?$#', '\1', $path); +} + +if (STRIP_SLASHES) +{ + array_deep($_GET, 'stripslashes'); + array_deep($_POST, 'stripslashes'); + array_deep($_COOKIE, 'stripslashes'); + array_deep($_REQUEST, 'stripslashes'); + array_deep($_SERVER, 'stripslashes'); + array_deep($_ENV, 'stripslashes'); + array_deep($_FILES, 'stripslashes'); +} +elseif (!defined('IN_AJAX')) +{ + array_deep($_GET, 'addslashes'); + array_deep($_POST, 'addslashes'); +} + +require(INC_DIR .'functions.php'); +require(INC_DIR .'sessions.php'); +require(INC_DIR .'template.php'); +require(INC_DIR .'db/mysql.php'); + +define('SQL_LAYER', 'mysql'); + +$bb_cfg = array_merge(bb_get_config(BB_CONFIG), $bb_cfg); + +$bb_cfg['cookie_name'] = $bb_cfg['cookie_prefix']; +$bb_cfg['board_dateformat'] = $bb_cfg['default_dateformat']; +$bb_cfg['board_lang'] = $bb_cfg['default_lang']; + +$user = new user_common(); +$userdata =& $user->data; + +if (DBG_USER) require(INC_DIR .'functions_dev.php'); + +$html = new html_common(); +$log_action = new log_action(); + +$ads = new ads_common(); + +// Initialize Datastore +switch ($bb_cfg['datastore_type']) +{ + case 'sqlite': + $default_cfg = array( + 'db_file_path' => '/dev/shm/bb.datastore.sqlite', + 'table_name' => 'datastore', + 'table_schema' => 'CREATE TABLE datastore ( + ds_title VARCHAR(255), + ds_data TEXT, + PRIMARY KEY (ds_title) + )', + 'pconnect' => true, + 'con_required' => true, + 'log_name' => 'DATASTORE', + ); + $datastore = new datastore_sqlite(array_merge($default_cfg, $bb_cfg['datastore']['sqlite'])); + break; + + case 'memcache': + $datastore = new datastore_memcache($bb_cfg['datastore']['mc']); + break; + + case 'filecache': + $datastore = new datastore_file($bb_cfg['cache']['db_dir'] . 'datastore/'); + break; + + default: + $datastore = new datastore_mysql(); +} +// Cron +if ((empty($_POST) && !defined('IN_ADMIN') && !defined('IN_AJAX') && !defined('IN_SERVICE') && !file_exists(CRON_RUNNING) && defined('START_CRON')) || defined('FORCE_CRON') /* && !empty($_GET['cron_test_9gndjk']) */) +{ + if (TIMENOW - $bb_cfg['cron_last_check'] > $bb_cfg['cron_check_interval']) + { + // Update cron_last_check + bb_update_config(array('cron_last_check' => (time() + 10))); + + require(CFG_DIR .'cron_cfg.php'); + + bb_log(date('H:i:s - ') . getmypid() .' -x-- DB-LOCK try'. LOG_LF, CRON_LOG_DIR .'cron_check'); + + if (DB()->get_lock('cron', 1)) + { + bb_log(date('H:i:s - ') . getmypid() .' --x- DB-LOCK OBTAINED !!!!!!!!!!!!!!!!!'. LOG_LF, CRON_LOG_DIR .'cron_check'); + + sleep(2); + require(CRON_DIR .'cron_init.php'); + + DB()->release_lock('cron'); + } + } +} + +$dl_link_css = array( + DL_STATUS_RELEASER => 'genmed', + DL_STATUS_WILL => 'dlWill', + DL_STATUS_DOWN => 'leechmed', + DL_STATUS_COMPLETE => 'seedmed', + DL_STATUS_CANCEL => 'dlCancel', +); + +$dl_status_css = array( + DL_STATUS_RELEASER => 'genmed', + DL_STATUS_WILL => 'dlWill', + DL_STATUS_DOWN => 'dlDown', + DL_STATUS_COMPLETE => 'dlComplete', + DL_STATUS_CANCEL => 'dlCancel', +); + + +// Show 'Board is disabled' message if needed. +if ($bb_cfg['board_disable'] && !defined('IN_ADMIN') && !defined('IN_LOGIN')) +{ + message_die(GENERAL_MESSAGE, 'BOARD_DISABLE', 'Information'); +} diff --git a/upload/includes/online_userlist.php b/upload/includes/online_userlist.php new file mode 100644 index 000000000..26755c619 --- /dev/null +++ b/upload/includes/online_userlist.php @@ -0,0 +1,167 @@ + array(), + MOD => array(), + GROUP_MEMBER => array(), + USER => array(), +); +$users_cnt = array( + 'admin' => 0, + 'mod' => 0, + 'group_member' => 0, + 'ignore_load' => 0, + 'user' => 0, + 'guest' => 0, +); +$online = $online_short = array('userlist' => ''); + +$sql = " + SELECT + u.username, u.user_id, u.user_allow_viewonline, u.user_level, + u.ignore_srv_load, + s.session_logged_in, s.session_ip, (s.session_time - s.session_start) AS ses_len, COUNT(s.session_id) AS sessions, COUNT(DISTINCT s.session_ip) AS ips + FROM ". BB_SESSIONS ." s, ". BB_USERS ." u + WHERE s.session_time > $time_online + AND u.user_id = s.session_user_id + GROUP BY s.session_user_id + ORDER BY u.username +"; + +foreach (DB()->fetch_rowset($sql) as $u) +{ + if ($u['session_logged_in']) + { + $stat = array(); + $style_color = $class = ''; + $name = $u['username']; + $level = $u['user_level']; + + if ($level == ADMIN) + { + $name = "$name"; + $class = ' class="colorAdmin"'; + $users_cnt['admin']++; + } + else if ($level == MOD) + { + $name = "$name"; + $class = ' class="colorMod"'; + $users_cnt['mod']++; + } + else if ($level == GROUP_MEMBER) + { + $name = "$name"; + $class = ' class="colorGroup"'; + $users_cnt['group_member']++; + } + else if ($u['ignore_srv_load']) + { + $class = ' class="colorISL"'; + $users_cnt['ignore_load']++; + } + else + { + $users_cnt['user']++; + } + + if ($u['sessions'] > 3) + { + $color = ($u['sessions'] > 2) ? '#FF0000' : '#B22222'; + $s = $u['sessions']; + $stat[] = "s:$s"; + } + if ($u['ips'] > 2) + { + $ip = $u['ips']; + $stat[] = "ip:$ip"; + } + if ($u['ses_len'] > 6*3600 && $level == USER) + { + $t = round($u['ses_len'] / 3600, 1); + $stat[] = "t:$t"; + } + + $h = PROFILE_URL . $u['user_id']; + $u = ""; + $u .= ($stat) ? "$name [". join(', ', $stat) .']' : $name; + $u .= ''; + $ulist[$level][] = $u; + } + else + { + $guests_online = $u['ips']; + $users_cnt['guest'] = $guests_online; + } +} + +if ($ulist) +{ + $inline = $block = $short = array(); + + foreach ($ulist as $level => $users) + { + if (empty($users)) continue; + + if (count($users) > 200) + { + $style = 'margin: 3px 0; padding: 2px 4px; border: 1px inset; height: 200px; overflow: auto;'; + $block[] = "
    \n". join(",\n", $users) ."
    \n"; + $short[] = ''. $lang['USERS'] .': '. count($users) .''; + } + else + { + $inline[] = join(",\n", $users); + $short[] = join(",\n", $users); + } + + $logged_online += count($users); + } + + $online['userlist'] = join(",\n", $inline) . join("\n", $block); + $online_short['userlist'] = join(",\n", $short); +} + +if (!$online['userlist']) +{ + $online['userlist'] = $online_short['userlist'] = $lang['NONE']; +} +else if (isset($_REQUEST['f'])) +{ + $online['userlist'] = $online_short['userlist'] = $lang['BROWSING_FORUM'] .' '. $online['userlist']; +} + +$total_online = $logged_online + $guests_online; + +if ($total_online > $bb_cfg['record_online_users']) +{ + bb_update_config(array( + 'record_online_users' => $total_online, + 'record_online_date' => TIMENOW, + )); +} + +$online['stat'] = $online_short['stat'] = sprintf($lang['ONLINE_USERS'], $total_online, $logged_online, $guests_online); + +$online['cnt'] = $online_short['cnt'] = <<{$users_cnt['admin']} · + {$users_cnt['mod']} · + {$users_cnt['group_member']} · + {$users_cnt['ignore_load']} · + {$users_cnt['user']} · + {$users_cnt['guest']} +] +HTML; + +CACHE('bb_cache')->set('online', $online, 45); +CACHE('bb_cache')->set('online_short', $online_short, 45); diff --git a/upload/includes/page_footer.php b/upload/includes/page_footer.php new file mode 100644 index 000000000..0d731c064 --- /dev/null +++ b/upload/includes/page_footer.php @@ -0,0 +1,108 @@ +assign_vars(array( + 'SIMPLE_FOOTER' => !empty($gen_simple_header), + + 'TRANSLATION_INFO' => isset($lang['TRANSLATION_INFO']) ? $lang['TRANSLATION_INFO'] : '', + 'SHOW_ADMIN_LINK' => (IS_ADMIN && !defined('IN_ADMIN')), + 'ADMIN_LINK_HREF' => "admin/index.php", + 'L_GOTO_ADMINCP' => $lang['ADMIN_PANEL'], + + )); + + $template->set_filenames(array('page_footer' => 'page_footer.tpl')); + $template->pparse('page_footer'); +} + +$show_dbg_info = (DBG_USER && IS_ADMIN && !defined('IN_ADMIN')); + +flush(); + +if ($show_dbg_info) +{ + $gen_time = utime() - TIMESTART; + $gen_time_txt = sprintf('%.3f', $gen_time); + $gzip_text = (UA_GZIP_SUPPORTED) ? 'GZIP' : 'GZIP'; + $gzip_text .= ($bb_cfg['gzip_compress']) ? ' ON' : ' OFF'; + $debug_text = (DEBUG) ? 'Debug ON' : 'Debug OFF'; + + $stat = '[  '; + $stat .= "Execution time: $gen_time_txt sec "; + + if (!empty($DBS)) + { + $sql_t = $DBS->sql_timetotal; + $sql_time_txt = ($sql_t) ? sprintf('%.3f sec (%d%%) in ', $sql_t, round($sql_t*100/$gen_time)) : ''; + $num_q = $DBS->num_queries; + $stat .= "  |  MySQL: {$sql_time_txt}{$num_q} queries"; + } + + $stat .= "  |  $gzip_text"; + + $stat .= '  |  Mem: '; + $stat .= humn_size($bb_cfg['mem_on_start'], 2) .' / '; + $stat .= humn_size(sys('mem_peak'), 2) .' / '; + $stat .= humn_size(sys('mem'), 2); + + if ($l = sys('la')) + { + $l = explode(' ', $l); + for ($i=0; $i < 3; $i++) + { + $l[$i] = round($l[$i], 1); + $l[$i] = (IS_ADMIN && $bb_cfg['max_srv_load'] && $l[$i] > ($bb_cfg['max_srv_load'] + 4)) ? "$l[$i]" : $l[$i]; + } + $stat .= "  |  {$bb_cfg['node_name']} [{$bb_cfg['node_addr']}]: $l[0] $l[1] $l[2]"; + } + + $stat .= '  ]'; + + echo '
    '. $stat .'
    '; +} + +echo ' + +'; + +if (DBG_USER && (SQL_DEBUG || PROFILER) && !defined('IN_ADMIN')) +{ + require(INC_DIR . 'page_footer_dev.php'); +} + +##### LOG ##### +global $log_ip_resp; + +if (isset($log_ip_resp[USER_IP]) || isset($log_ip_resp[CLIENT_IP])) +{ + $str = date('H:i:s') . LOG_SEPR . preg_replace("#\s+#", ' ', $contents) . LOG_LF; + $file = 'sessions/'. date('m-d') .'_{'. USER_IP .'}_'. CLIENT_IP .'_resp'; + bb_log($str, $file); +} +### LOG END ### + +if (DBG_USER && !empty($GLOBALS['timer_markers'])) +{ + $GLOBALS['timer']->stop(); + $GLOBALS['timer']->display(); +} + +echo ' + + +'; + +if (defined('REQUESTED_PAGE') && !defined('DISABLE_CACHING_OUTPUT')) +{ + if (IS_GUEST === true) + { + caching_output(true, 'store', REQUESTED_PAGE .'_guest'); + } +} + +bb_exit(); diff --git a/upload/includes/page_footer_dev.php b/upload/includes/page_footer_dev.php new file mode 100644 index 000000000..22287c1bb --- /dev/null +++ b/upload/includes/page_footer_dev.php @@ -0,0 +1,176 @@ + + + + +srv as $srv_name => $db_obj) + { + if (!empty($db_obj->do_explain)) + { + $db_obj->explain('display'); + } + } +} + +$sql_log = !empty($_COOKIE['sql_log']) ? get_sql_log() : ''; + +echo ' +
    +'; +if (PROFILER) { + echo ' +
    + Profiling + min time: + + + +
    + '; +} +if (DEBUG) { + echo ' +
    + Debug + +
    + '; +} +echo ' +
    + SQL + + + + [ + wrap · + max + ] +
    +'; +echo ' +
    + +
    +'. ($sql_log ? $sql_log : 'sql_log') .' +'. (UA_IE ? '
    ' : '') .' +
    + + + +
    +'; + +if (PROFILER && !empty($_COOKIE['prof_enabled'])) +{ + require(DEV_DIR .'profiler/profiler.php'); + $profiler = profiler::init(PROFILER); + + $min_time = !empty($_COOKIE['prof_min_time']) ? $_COOKIE['prof_min_time'] : '0.1%'; + $profiler->print_profile_data($min_time); +} + +?> + \ No newline at end of file diff --git a/upload/includes/page_header.php b/upload/includes/page_header.php new file mode 100644 index 000000000..9fb0df7dd --- /dev/null +++ b/upload/includes/page_header.php @@ -0,0 +1,360 @@ + '', + 'userlist' => '', + 'cnt' => '', + ); + + if (defined('IS_GUEST') && !(IS_GUEST || IS_USER)) + { + $template->assign_var('SHOW_ONLINE_LIST'); + + if (!${$online_list} = CACHE('bb_cache')->get($online_list)) + { + require(INC_DIR .'online_userlist.php'); + } + } + + $template->assign_vars(array( + 'TOTAL_USERS_ONLINE' => ${$online_list}['stat'], + 'LOGGED_IN_USER_LIST' => ${$online_list}['userlist'], + 'USERS_ONLINE_COUNTS' => ${$online_list}['cnt'], + 'RECORD_USERS' => sprintf($lang['RECORD_ONLINE_USERS'], $bb_cfg['record_online_users'], bb_date($bb_cfg['record_online_date'])), + 'U_VIEWONLINE' => "viewonline.php", + )); +} + +// Info about new private messages +$icon_pm = $images['pm_no_new_msg']; +$pm_info = $lang['NO_NEW_PM']; +$have_new_pm = $have_unread_pm = 0; + +if ($logged_in && empty($gen_simple_header) && !defined('IN_ADMIN')) +{ + if ($userdata['user_new_privmsg']) + { + $have_new_pm = $userdata['user_new_privmsg']; + $icon_pm = $images['pm_new_msg']; + $pm_info = declension($userdata['user_new_privmsg'], $lang['NEW_PMS_DECLENSION'], $lang['NEW_PMS_FORMAT']); + + if ($userdata['user_last_privmsg'] > $userdata['user_lastvisit'] && defined('IN_PM')) + { + $userdata['user_last_privmsg'] = $userdata['user_lastvisit']; + + db_update_userdata($userdata, array( + 'user_last_privmsg' => $userdata['user_lastvisit'], + )); + + $have_new_pm = ($userdata['user_new_privmsg'] > 1); + } + } + if (!$have_new_pm && $userdata['user_unread_privmsg']) + { + // synch unread pm count + if (defined('IN_PM')) + { + $row = DB()->fetch_row(" + SELECT COUNT(*) AS pm_count + FROM ". BB_PRIVMSGS ." + WHERE privmsgs_to_userid = ". $userdata['user_id'] ." + AND privmsgs_type = ". PRIVMSGS_UNREAD_MAIL ." + GROUP BY privmsgs_to_userid + "); + + $real_unread_pm_count = (int) $row['pm_count']; + + if ($userdata['user_unread_privmsg'] != $real_unread_pm_count) + { + $userdata['user_unread_privmsg'] = $real_unread_pm_count; + + db_update_userdata($userdata, array( + 'user_unread_privmsg' => $real_unread_pm_count, + )); + } + } + + $pm_info = declension($userdata['user_unread_privmsg'], $lang['UNREAD_PMS_DECLENSION'], $lang['UNREAD_PMS_FORMAT']); + $have_unread_pm = true; + } +} +$template->assign_vars(array( + 'HAVE_NEW_PM' => $have_new_pm, + 'HAVE_UNREAD_PM' => $have_unread_pm, +)); + +// The following assigns all _common_ variables that may be used at any point in a template +// Report +// +// Report list link +// +if ($bb_cfg['reports_enabled']) +{ + if (empty($gen_simple_header) && ($userdata['user_level'] == ADMIN || (!$bb_cfg['report_list_admin'] && $userdata['user_level'] == MOD))) + { + if (!function_exists("report_count_obtain")) + include(INC_DIR . "functions_report.php"); + + $report_count = report_count_obtain(); + if ($report_count > 0) + { + $template->assign_block_vars('switch_report_list_new', array()); + + $report_list = $lang['REPORTS']; + $report_list .= ($report_count == 1) ? $lang['NEW_REPORT'] : sprintf($lang['NEW_REPORTS'], $report_count); + } + else + { + $template->assign_block_vars('switch_report_list', array()); + + $report_list = $lang['REPORTS'] . $lang['NO_NEW_REPORTS']; + } + } + else + { + $report_list = ''; + } + // + // Get report general module and create report link + // + if (empty($gen_simple_header)) + { + if (!function_exists("report_count_obtain")) + include(INC_DIR . "functions_report.php"); + + $report_general = report_modules('name', 'report_general'); + + if ($report_general && $report_general->auth_check('auth_write')) + { + $template->assign_block_vars('switch_report_general', array()); + + $template->assign_vars(array( + 'U_WRITE_REPORT' => append_sid("report.php?mode=" . $report_general->mode), + 'L_WRITE_REPORT' => $report_general->lang['WRITE_REPORT']) + ); + } + } +} +else $report_list = ''; +// Report [END] + +$avatar_img = ''; +$avatar_img = get_avatar($userdata['user_avatar'], $userdata['user_avatar_type'], $userdata['user_allowavatar']); + +$template->assign_vars(array( + 'SIMPLE_HEADER' => !empty($gen_simple_header), + 'IN_ADMIN' => defined('IN_ADMIN'), + 'QUIRKS_MODE' => !empty($page_cfg['quirks_mode']), + 'SHOW_ADS' => (!$logged_in || isset($bb_cfg['show_ads_users'][$user->id]) || (!($is_admin || $is_mod) && $user->show_ads)), + + 'INCLUDE_BBCODE_JS' => !empty($page_cfg['include_bbcode_js']), + 'USER_OPTIONS_JS' => ($logged_in) ? bb_json_encode($user->opt_js) : '{}', + + 'USE_TABLESORTER' => !empty($page_cfg['use_tablesorter']), + + 'SITENAME' => $bb_cfg['sitename'], + 'U_INDEX' => BB_ROOT ."index.php", + 'T_INDEX' => sprintf($lang['FORUM_INDEX'], $bb_cfg['sitename']), + + 'IS_GUEST' => IS_GUEST, + 'IS_USER' => IS_USER, + 'IS_ADMIN' => IS_ADMIN, + 'IS_MOD' => IS_MOD, + 'IS_AM' => IS_AM, + + 'FORUM_PATH' => FORUM_PATH, + 'FULL_URL' => FULL_URL, + + 'LAST_VISIT_DATE' => ($logged_in) ? sprintf($lang['YOU_LAST_VISIT'], bb_date($userdata['user_lastvisit'], $bb_cfg['last_visit_date_format'])) : '', + 'CURRENT_TIME' => sprintf($lang['CURRENT_TIME'], bb_date(TIMENOW, $bb_cfg['last_visit_date_format'])), + 'S_TIMEZONE' => sprintf($lang['ALL_TIMES'], $lang[''.str_replace(',', '.', floatval($bb_cfg['board_timezone'])).'']), + + 'PM_INFO' => $pm_info, + 'PRIVMSG_IMG' => $icon_pm, + + // Report + 'REPORT_LIST' => $report_list, + 'U_REPORT_LIST' => append_sid("report.php"), + // Report [END] + + 'LOGGED_IN' => $logged_in, + 'SESSION_USER_ID' => $userdata['user_id'], + 'THIS_USERNAME' => $userdata['username'], + 'AVATAR' => $avatar_img, + 'SHOW_LOGIN_LINK' => !defined('IN_LOGIN'), + 'AUTOLOGIN_DISABLED' => !$bb_cfg['allow_autologin'], + 'S_LOGIN_ACTION' => BB_ROOT ."login.php", + + 'U_CUR_DOWNLOADS' => PROFILE_URL . $userdata['user_id'] .'#torrent', + 'U_FAQ' => $bb_cfg['faq_url'], + 'U_FORUM' => "viewforum.php", + 'U_GROUP_CP' => "groupcp.php", + 'U_LOGIN_LOGOUT' => $u_login_logout, + 'U_MEMBERLIST' => "memberlist.php", + 'U_MODCP' => "modcp.php", + 'U_OPTIONS' => "profile.php?mode=editprofile", + 'U_PRIVATEMSGS' => "privmsg.php?folder=inbox", + 'U_PROFILE' => PROFILE_URL . $userdata['user_id'], + 'U_READ_PM' => "privmsg.php?folder=inbox". (($userdata['user_newest_pm_id'] && $userdata['user_new_privmsg'] == 1) ? "&mode=read&p={$userdata['user_newest_pm_id']}" : ''), + 'U_REGISTER' => "profile.php?mode=register", + 'U_SEARCH' => "search.php", + 'U_SEND_PASSWORD' => "profile.php?mode=sendpassword", + 'U_TERMS' => $bb_cfg['terms_and_conditions_url'], + 'U_TRACKER' => "tracker.php", + + 'U_GALLERY' => "gallery.php", + 'SHOW_GALLERY' => (!empty($bb_cfg['gallery_enabled']) && !empty($bb_cfg['gallery_show_link']) ? true : false), + + 'SHOW_ADMIN_OPTIONS' => $is_admin, + 'SHOW_SIDEBAR1' => (!empty($page_cfg['show_sidebar1'][BB_SCRIPT]) || $bb_cfg['show_sidebar1_on_every_page']), + 'SHOW_SIDEBAR2' => (!empty($page_cfg['show_sidebar2'][BB_SCRIPT]) || $bb_cfg['show_sidebar2_on_every_page']), + + // Common urls + 'CAT_URL' => BB_ROOT . CAT_URL, + 'DOWNLOAD_URL' => BB_ROOT . DOWNLOAD_URL, + 'FORUM_URL' => BB_ROOT . FORUM_URL, + 'GROUP_URL' => BB_ROOT . GROUP_URL, + 'NEWEST_URL' => '&view=newest#newest', + 'POST_URL' => BB_ROOT . POST_URL, + 'PROFILE_URL' => BB_ROOT . PROFILE_URL, + 'TOPIC_URL' => BB_ROOT . TOPIC_URL, + + 'AJAX_HTML_DIR' => AJAX_HTML_DIR, + 'AJAX_HANDLER' => BB_ROOT .'ajax.php', + + 'ONLY_NEW_POSTS' => ONLY_NEW_POSTS, + 'ONLY_NEW_TOPICS' => ONLY_NEW_TOPICS, + + // Misc + 'DEBUG' => DEBUG, + 'BOT_UID' => BOT_UID, + 'COOKIE_MARK' => COOKIE_MARK, + 'SID' => $userdata['session_id'], + 'SID_HIDDEN' => '', + + 'CHECKED' => HTML_CHECKED, + 'DISABLED' => HTML_DISABLED, + 'READONLY' => HTML_READONLY, + 'SELECTED' => HTML_SELECTED, + + 'U_SEARCH_SELF_BY_LAST' => "search.php?uid={$userdata['user_id']}&o=5", +)); + +if (!empty($page_cfg['dl_links_user_id'])) +{ + $dl_link = "search.php?dlu={$page_cfg['dl_links_user_id']}&"; + + $template->assign_vars(array( + 'SHOW_SEARCH_DL' => true, + 'U_SEARCH_DL_WILL' => $dl_link .'dlw=1', + 'U_SEARCH_DL_DOWN' => $dl_link .'dld=1', + 'U_SEARCH_DL_COMPLETE' => $dl_link .'dlc=1', + 'U_SEARCH_DL_CANCEL' => $dl_link .'dla=1', + )); +} + +if (!empty($page_cfg['show_torhelp'][BB_SCRIPT]) && !empty($userdata['torhelp'])) +{ + $ignore_time = !empty($_COOKIE['torhelp']) ? (int) $_COOKIE['torhelp'] : 0; + + if (TIMENOW > $ignore_time) + { + if ($ignore_time) + { + bb_setcookie('torhelp', '', COOKIE_EXPIRED); + } + + $sql = " + SELECT topic_id, topic_title + FROM ". BB_TOPICS ." + WHERE topic_id IN(". $userdata['torhelp'] .") + LIMIT 8 + "; + $torhelp_topics = array(); + + foreach (DB()->fetch_rowset($sql) as $row) + { + $torhelp_topics[] = ''. $row['topic_title'] .''; + } + + $template->assign_vars(array( + 'TORHELP_TOPICS' => join("\n
  • ", $torhelp_topics), + )); + } +} + +if (DBG_USER) +{ + $template->assign_vars(array( + 'INCLUDE_DEVELOP_JS' => true, + 'EDITOR_PATH' => @addslashes($bb_cfg['dbg']['editor_path']), + 'EDITOR_ARGS' => @addslashes($bb_cfg['dbg']['editor_args']), + )); +} + +// Ads +if ($user->show_ads) +{ + $load_ads = array('trans'); + if (defined('BB_SCRIPT')) + { + $load_ads[] = BB_SCRIPT; + } + foreach ($ads->get($load_ads) as $block_id => $ad_html) + { + $template->assign_var("AD_BLOCK_{$block_id}", $ad_html); + } +} + +// Login box +$in_out = ($logged_in) ? 'in' : 'out'; +$template->assign_block_vars("switch_user_logged_{$in_out}", array()); + +// Work around for "current" Apache 2 + PHP module which seems to not +// cope with private cache control setting +if (!empty($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache/2')) +{ + header('Cache-Control: no-cache, pre-check=0, post-check=0'); +} +else +{ + header('Cache-Control: private, pre-check=0, post-check=0, max-age=0'); +} +header('Expires: 0'); +header('Pragma: no-cache'); + +$template->set_filenames(array('page_header' => 'page_header.tpl')); +$template->pparse('page_header'); + +define('PAGE_HEADER_SENT', true); + +flush(); diff --git a/upload/includes/report_hack/.htaccess b/upload/includes/report_hack/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/report_hack/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/report_hack/report_general.php b/upload/includes/report_hack/report_general.php new file mode 100644 index 000000000..e1d8fa576 --- /dev/null +++ b/upload/includes/report_hack/report_general.php @@ -0,0 +1,17 @@ +id = $id; + $this->data = $data; + $this->lang = $lang; + } +} \ No newline at end of file diff --git a/upload/includes/report_hack/report_post.php b/upload/includes/report_hack/report_post.php new file mode 100644 index 000000000..4184c38dd --- /dev/null +++ b/upload/includes/report_hack/report_post.php @@ -0,0 +1,276 @@ +id = $id; + $this->data = $data; + $this->lang = $lang; + } + + // + // Synchronizing function + // + function sync($uninstall = false) + { + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_reported = 0'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not reset post reported flag', '', __LINE__, __FILE__, $sql); + } + + if (!$uninstall) + { + $sql = 'SELECT report_subject + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . $this->id . ' + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + GROUP BY report_subject'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain open reports', '', __LINE__, __FILE__, $sql); + } + + $open_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $open_ids[] = $row['report_subject']; + } + DB()->sql_freeresult($result); + + if (!empty($open_ids)) + { + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_reported = 1 + WHERE post_id IN(' . implode(', ', $open_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not sync post reported flag', '', __LINE__, __FILE__, $sql); + } + } + } + } + + // + // Module action: Insert + // + function action_insert($report_subject, $report_id, $report_subject_data) + { + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_reported = 1 + WHERE post_id = ' . (int) $report_subject; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update post reported flag', '', __LINE__, __FILE__, $sql); + } + } + + // + // Module action: Update status + // + function action_update_status($report_subjects, $report_status) + { + switch ($report_status) + { + case REPORT_CLEARED: + case REPORT_DELETE: + $this->action_delete($report_subjects); + break; + + default: + report_prepare_subjects($report_subjects, true); + + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_reported = 1 + WHERE post_id IN(' . implode(', ', $report_subjects) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update post reported flag', '', __LINE__, __FILE__, $sql); + } + break; + } + } + + // + // Module action: Delete + // + function action_delete($report_subjects) + { + report_prepare_subjects($report_subjects, true); + + $sql = 'SELECT report_subject + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . $this->id . ' + AND report_id NOT IN(' . implode(', ', array_keys($report_subjects)) . ') + AND report_subject IN(' . implode(', ', $report_subjects) . ') + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + GROUP BY report_subject'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not get open reports', '', __LINE__, __FILE__, $sql); + } + + $open_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $open_ids[] = $row['report_subject']; + } + DB()->sql_freeresult($result); + + if (!empty($open_ids)) + { + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_reported = 1 + WHERE post_id IN(' . implode(', ', $open_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update post reported flag', '', __LINE__, __FILE__, $sql); + } + } + + $clear_ids = array(); + foreach ($report_subjects as $report_subject) + { + if (!in_array($report_subject, $open_ids)) + { + $clear_ids[] = $report_subject; + } + } + + if (!empty($clear_ids)) + { + $sql = 'UPDATE ' . BB_POSTS . ' + SET post_reported = 0 + WHERE post_id IN(' . implode(', ', $clear_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update post reported flag', '', __LINE__, __FILE__, $sql); + } + } + } + + // + // Returns url to a report subject + // + function subject_url($report_subject, $non_html_amp = false) + { + $report_subject = (int) $report_subject; + return append_sid("viewtopic.php?" . POST_POST_URL . "=$report_subject#$report_subject", $non_html_amp); + } + + // + // Returns report subject title + // + function subject_obtain($report_subject) + { + $sql = 'SELECT pt.post_subject, t.topic_title, t.topic_first_post_id + FROM ' . BB_POSTS . ' p + INNER JOIN ' . BB_POSTS_TEXT . ' pt + ON pt.post_id = p.post_id + INNER JOIN ' . BB_TOPICS . ' t + ON t.topic_id = p.topic_id + WHERE p.post_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report subject', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (!$row) + { + return false; + } + + if ($row['post_subject'] != '') + { + return $row['post_subject']; + } + else + { + $subject = ($row['topic_first_post_id'] == $report_subject) ? '' : 'Re: '; + $subject .= $row['topic_title']; + + return $subject; + } + } + + // + // Obtains additional subject data + // + function subject_data_obtain($report_subject) + { + $sql = 'SELECT forum_id + FROM ' . BB_POSTS . ' + WHERE post_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report subject data', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + return $row; + } + + // + // Obtains subjects authorisation + // + function subjects_auth_obtain($user_id, $report_subjects) + { + report_prepare_subjects($report_subjects); + $moderated_forums = user_moderated_forums($user_id); + + // + // Check stored forum ids + // + $check_posts = array(); + foreach ($report_subjects as $report_subject) + { + if (in_array($report_subject[1]['forum_id'], $moderated_forums)) + { + $this->subjects_auth[$user_id][$report_subject[0]] = true; + } + else + { + $this->subjects_auth[$user_id][$report_subject[0]] = false; + + $check_posts[] = $report_subject[0]; + } + } + + // + // Check current forum ids + // + if (!empty($check_posts)) + { + $sql = 'SELECT post_id, forum_id + FROM ' . BB_POSTS . ' + WHERE post_id IN(' . implode(', ', $check_posts) . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain current forum ids', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + if (in_array($row['forum_id'], $moderated_forums)) + { + $this->subjects_auth[$user_id][$row['post_id']] = true; + } + } + DB()->sql_freeresult($result); + } + } +} \ No newline at end of file diff --git a/upload/includes/report_hack/report_privmsg.php b/upload/includes/report_hack/report_privmsg.php new file mode 100644 index 000000000..17825515d --- /dev/null +++ b/upload/includes/report_hack/report_privmsg.php @@ -0,0 +1,257 @@ +id = $id; + $this->data = $data; + $this->lang = $lang; + } + + // + // Synchronizing function + // + function sync($uninstall = false) + { + $sql = 'UPDATE ' . BB_PRIVMSGS . ' + SET privmsgs_reported = 0'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not reset privmsgs reported flag', '', __LINE__, __FILE__, $sql); + } + + if (!$uninstall) + { + $sql = 'SELECT report_subject + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . $this->id . ' + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + GROUP BY report_subject'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain open reports', '', __LINE__, __FILE__, $sql); + } + + $open_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $open_ids[] = $row['report_subject']; + } + DB()->sql_freeresult($result); + + if (!empty($open_ids)) + { + $sql = 'UPDATE ' . BB_PRIVMSGS . ' + SET privmsgs_reported = 1 + WHERE privmsgs_id IN(' . implode(', ', $open_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not sync privmsgs reported flag', '', __LINE__, __FILE__, $sql); + } + } + } + } + + // + // Module action: Insert + // + function action_insert($report_subject, $report_id) + { + $sql = 'UPDATE ' . BB_PRIVMSGS . ' + SET privmsgs_reported = 1 + WHERE privmsgs_id = ' . (int) $report_subject; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update privmsgs reported flag', '', __LINE__, __FILE__, $sql); + } + } + + // + // Module action: Update status + // + function action_update_status($report_subjects, $report_status) + { + switch ($report_status) + { + case REPORT_CLEARED: + case REPORT_DELETE: + $this->action_delete($report_subjects); + break; + + default: + report_prepare_subjects($report_subjects, true); + + $sql = 'UPDATE ' . BB_PRIVMSGS . ' + SET privmsgs_reported = 1 + WHERE privmsgs_id IN(' . implode(', ', $report_subjects) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update privmsgs reported flag', '', __LINE__, __FILE__, $sql); + } + break; + } + } + + // + // Module action: Delete + // + function action_delete($report_subjects) + { + report_prepare_subjects($report_subjects, true); + + $sql = 'SELECT report_subject + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . $this->id . ' + AND report_id NOT IN(' . implode(', ', array_keys($report_subjects)) . ') + AND report_subject IN(' . implode(', ', $report_subjects) . ') + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + GROUP BY report_subject'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not get open reports', '', __LINE__, __FILE__, $sql); + } + + $open_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $open_ids[] = $row['report_subject']; + } + DB()->sql_freeresult($result); + + if (!empty($open_ids)) + { + $sql = 'UPDATE ' . BB_PRIVMSGS . ' + SET privmsgs_reported = 1 + WHERE privmsgs_id IN(' . implode(', ', $open_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topic reported flag', '', __LINE__, __FILE__, $sql); + } + } + + $clear_ids = array(); + foreach ($report_subjects as $report_subject) + { + if (!in_array($report_subject, $open_ids)) + { + $clear_ids[] = $report_subject; + } + } + + if (!empty($clear_ids)) + { + $sql = 'UPDATE ' . BB_PRIVMSGS . ' + SET privmsgs_reported = 0 + WHERE privmsgs_id IN(' . implode(', ', $clear_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topic reported flag', '', __LINE__, __FILE__, $sql); + } + } + } + + // + // Returns url to a report subject + // + function subject_url($report_subject, $non_html_amp = false) + { + $sep = ($non_html_amp) ? '&' : '&'; + return append_sid("privmsg.php?mode=read$sep" . POST_POST_URL . '=' . (int) $report_subject, $non_html_amp); + } + + // + // Returns report subject title + // + function subject_obtain($report_subject) + { + global $userdata; + + $sql = 'SELECT privmsgs_subject + FROM ' . BB_PRIVMSGS . ' + WHERE privmsgs_to_userid = ' . $userdata['user_id'] . ' + AND privmsgs_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report subject', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + return ($row) ? $row['privmsgs_subject'] : false; + } + + // + // Returns report subject details + // + function subject_details_obtain($report_subject) + { + $sql = 'SELECT p.privmsgs_subject, p.privmsgs_from_userid, p.privmsgs_enable_bbcode, p.privmsgs_enable_smilies, pt.privmsgs_bbcode_uid, pt.privmsgs_text, u.username + FROM ' . BB_PRIVMSGS . ' p + INNER JOIN ' . BB_PRIVMSGS_TEXT . ' pt + ON pt.privmsgs_text_id = privmsgs_id + LEFT JOIN ' . BB_USERS . ' u + ON u.user_id = p.privmsgs_from_userid + WHERE privmsgs_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, "Could not obtain report subject details", '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + if (!$row) + { + return false; + } + + $subject_details = array( + 'Message_id' => '#' . $report_subject, + 'Message_from' => '' . $row['username'] . '', + 'Message_title' => $row['privmsgs_subject'], + 'Message_text' => $row['privmsgs_text']); + + $this->_subject_details_prepare($subject_details['Message_text'], $subject_details['Message_title'], $row); + + return array( + 'details' => $subject_details); + } + + // + // Helper function for subject_details_obtain(), prepares private message and private + // message subject + // + function _subject_details_prepare(&$message, &$subject, $row) + { + global $bb_cfg, $userdata, $datastore; + include(INC_DIR . "bbcode.php"); + + // + // If the board has HTML off but the post has HTML + // on then we process it, else leave it alone + // + /*if ((!$bb_cfg['allow_html'] || !$userdata['user_allowhtml']) && $row['privmsgs_enable_html']) + { + $message = preg_replace('#(<)([\/]?.*?)(>)#is', '<\\2>', $message); + }*/ + + $message = bbcode2html($message); + + $orig_word = $replacement_word = array(); + obtain_word_list($orig_word, $replacement_word); + + if (!empty($orig_word)) + { + $subject = preg_replace($orig_word, $replacement_word, $subject); + $message = preg_replace($orig_word, $replacement_word, $message); + } + } +} \ No newline at end of file diff --git a/upload/includes/report_hack/report_topic.php b/upload/includes/report_hack/report_topic.php new file mode 100644 index 000000000..70511a50e --- /dev/null +++ b/upload/includes/report_hack/report_topic.php @@ -0,0 +1,256 @@ +id = $id; + $this->data = $data; + $this->lang = $lang; + } + + // + // Synchronizing function + // + function sync($uninstall = false) + { + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_reported = 0'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not reset topic reported flag', '', __LINE__, __FILE__, $sql); + } + + if (!$uninstall) + { + $sql = 'SELECT report_subject + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . $this->id . ' + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + GROUP BY report_subject'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain open reports', '', __LINE__, __FILE__, $sql); + } + + $open_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $open_ids[] = $row['report_subject']; + } + DB()->sql_freeresult($result); + + if (!empty($open_ids)) + { + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_reported = 1 + WHERE topic_id IN(' . implode(', ', $open_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not sync topic reported flag', '', __LINE__, __FILE__, $sql); + } + } + } + } + + // + // Module action: Insert + // + function action_insert($report_subject, $report_id, $report_subject_data) + { + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_reported = 1 + WHERE topic_id = ' . (int) $report_subject; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topic reported flag', '', __LINE__, __FILE__, $sql); + } + } + + // + // Module action: Update status + // + function action_update_status($report_subjects, $report_status) + { + switch ($report_status) + { + case REPORT_CLEARED: + case REPORT_DELETE: + $this->action_delete($report_subjects); + break; + + default: + report_prepare_subjects($report_subjects, true); + + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_reported = 1 + WHERE topic_id IN(' . implode(', ', $report_subjects) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topic reported flag', '', __LINE__, __FILE__, $sql); + } + break; + } + } + + // + // Module action: Delete + // + function action_delete($report_subjects) + { + report_prepare_subjects($report_subjects, true); + + $sql = 'SELECT report_subject + FROM ' . BB_REPORTS . ' + WHERE report_module_id = ' . $this->id . ' + AND report_id NOT IN(' . implode(', ', array_keys($report_subjects)) . ') + AND report_subject IN(' . implode(', ', $report_subjects) . ') + AND report_status NOT IN(' . REPORT_CLEARED . ', ' . REPORT_DELETE . ') + GROUP BY report_subject'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain open reports', '', __LINE__, __FILE__, $sql); + } + + $open_ids = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $open_ids[] = $row['report_subject']; + } + DB()->sql_freeresult($result); + + if (!empty($open_ids)) + { + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_reported = 1 + WHERE topic_id IN(' . implode(', ', $open_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topic reported flag', '', __LINE__, __FILE__, $sql); + } + } + + $clear_ids = array(); + foreach ($report_subjects as $report_subject) + { + if (!in_array($report_subject, $open_ids)) + { + $clear_ids[] = $report_subject; + } + } + + if (!empty($clear_ids)) + { + $sql = 'UPDATE ' . BB_TOPICS . ' + SET topic_reported = 0 + WHERE topic_id IN(' . implode(', ', $clear_ids) . ')'; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topic reported flag', '', __LINE__, __FILE__, $sql); + } + } + } + + // + // Returns url to a report subject + // + function subject_url($report_subject, $non_html_amp = false) + { + return append_sid("viewtopic.php?" . POST_TOPIC_URL . '=' . (int) $report_subject, $non_html_amp); + } + + // + // Returns report subject title + // + function subject_obtain($report_subject) + { + $sql = 'SELECT topic_title + FROM ' . BB_TOPICS . ' + WHERE topic_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report subject', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + return ($row) ? $row['topic_title'] : false; + } + + // + // Obtains additional subject data + // + function subject_data_obtain($report_subject) + { + $sql = 'SELECT forum_id + FROM ' . BB_TOPICS . ' + WHERE topic_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report subject data', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + return $row; + } + + // + // Obtains subjects authorisation + // + function subjects_auth_obtain($user_id, $report_subjects) + { + report_prepare_subjects($report_subjects); + $moderated_forums = user_moderated_forums($user_id); + + // + // Check stored forum ids + // + $check_topics = array(); + foreach ($report_subjects as $report_subject) + { + if (in_array($report_subject[1]['forum_id'], $moderated_forums)) + { + $this->subjects_auth[$user_id][$report_subject[0]] = true; + } + else + { + $this->subjects_auth[$user_id][$report_subject[0]] = false; + + $check_topics[] = $report_subject[0]; + } + } + + // + // Check current forum ids + // + if (!empty($check_topics)) + { + $sql = 'SELECT topic_id, forum_id + FROM ' . BB_TOPICS . ' + WHERE topic_id IN(' . implode(', ', $check_topics) . ')'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain current forum ids', '', __LINE__, __FILE__, $sql); + } + + while ($row = DB()->sql_fetchrow($result)) + { + if (in_array($row['forum_id'], $moderated_forums)) + { + $this->subjects_auth[$user_id][$row['topic_id']] = true; + } + } + DB()->sql_freeresult($result); + } + } +} \ No newline at end of file diff --git a/upload/includes/report_hack/report_user.php b/upload/includes/report_hack/report_user.php new file mode 100644 index 000000000..09600fcc3 --- /dev/null +++ b/upload/includes/report_hack/report_user.php @@ -0,0 +1,47 @@ +id = $id; + $this->data = $data; + $this->lang = $lang; + } + + // + // Returns url to a report subject + // + function subject_url($id, $non_html_amp = false) + { + $sep = ($non_html_amp) ? '&' : '&'; + return append_sid("profile.php?mode=viewprofile$sep" . POST_USERS_URL . '=' . (int) $id, $non_html_amp); + } + + // + // Returns report subject title + // + function subject_obtain($report_subject) + { + global $db; + + $sql = 'SELECT username + FROM ' . BB_USERS . ' + WHERE user_id = ' . (int) $report_subject; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report subject', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + return ($row) ? $row['username'] : false; + } +} \ No newline at end of file diff --git a/upload/includes/report_module.php b/upload/includes/report_module.php new file mode 100644 index 000000000..6f273b275 --- /dev/null +++ b/upload/includes/report_module.php @@ -0,0 +1,191 @@ + $this->lang['MODULE_TITLE'], + 'explain' => $this->lang['MODULE_EXPLAIN']); + } + + // + // Generates a return link based on the subject_url() method + // + function return_link($id) + { + global $lang; + + if (method_exists($this, 'subject_url') && isset($this->lang['CLICK_RETURN'])) + { + return '

    ' . sprintf($this->lang['CLICK_RETURN'], '', ''); + } + else + { + return ''; + } + } + + // + // Returns report reasons of the module + // + function reasons_obtain() + { + global $lang; + + $sql = 'SELECT report_reason_id, report_reason_desc + FROM ' . BB_REPORTS_REASONS . ' + WHERE report_module_id = ' . (int) $this->id . ' + ORDER BY report_reason_order'; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain report reasons', '', __LINE__, __FILE__, $sql); + } + + $rows = array(); + while ($row = DB()->sql_fetchrow($result)) + { + $rows[$row['report_reason_id']] = (isset($lang[$row['report_reason_desc']])) ? $lang[$row['report_reason_desc']] : $row['report_reason_desc']; + } + DB()->sql_freeresult($result); + + return (!empty($rows)) ? $rows : false; + } + + // + // Checks module authorisation + // + function auth_check($auth_names, $userdata = null) + { + if (!isset($userdata)) + { + global $userdata; + } + + if ($userdata['user_id'] == ANONYMOUS) + { + return false; + } + + // + // Set "virtual" column + // + if (!isset($this->data['auth_delete_view'])) + { + if ($this->data['auth_delete'] == REPORT_AUTH_CONFIRM) + { + $this->data['auth_delete_view'] = REPORT_AUTH_MOD; + } + else + { + $this->data['auth_delete_view'] = $this->data['auth_delete']; + } + } + + switch ($userdata['user_level']) + { + case ADMIN: + return true; + break; + + case MOD: + $auth_value = REPORT_AUTH_MOD; + break; + + case GROUP_MEMBER: + case USER: + $auth_value = REPORT_AUTH_USER; + break; + + default: + return false; + break; + } + + if (!is_array($auth_names)) + { + $auth_names = array($auth_names); + } + + // + // Check authorisation + // + foreach ($auth_names as $auth_name) + { + if ($this->data[$auth_name] > $auth_value) + { + return false; + } + } + + return true; + } + + // + // Checks the authorisation to view the specified report subjects + // + function subjects_auth_check(&$report_subjects, $userdata = null) + { + if (!method_exists($this, 'subjects_auth_obtain') || empty($report_subjects)) + { + return true; + } + + if (!isset($userdata)) + { + global $userdata; + } + + if ($userdata['user_level'] == ADMIN) + { + return true; + } + else if ($userdata['user_level'] != MOD) + { + return false; + } + + report_prepare_subjects($report_subjects); + + $user_id = $userdata['user_id']; + if (!isset($this->subject_auth[$user_id])) + { + $this->subject_auth[$user_id] = array(); + $this->subjects_auth_obtain($user_id, $report_subjects); + } + else + { + $check_ids = array(); + foreach ($report_subjects as $report_id => $report_subject) + { + if (!isset($this->subjects_auth[$user_id][$report_subject[0]])) + { + $check_ids[] = $report_subjects[$report_id]; + } + } + + if (!empty($check_ids)) + { + $this->subjects_auth_obtain($user_id, $check_ids); + } + } + + $subjects_count = count($report_subjects); + foreach ($report_subjects as $report_id => $report_subject) + { + if (!$this->subjects_auth[$user_id][$report_subject[0]]) + { + unset($report_subjects[$report_id]); + } + } + + return ($subjects_count == count($report_subjects)); + } +} \ No newline at end of file diff --git a/upload/includes/sessions.php b/upload/includes/sessions.php new file mode 100644 index 000000000..c3821dc02 --- /dev/null +++ b/upload/includes/sessions.php @@ -0,0 +1,966 @@ + false, // requires user to be logged in + 'req_session_admin' => false, // requires active admin session (for moderation or admin actions) + ); + + /** + * PHP-JS exchangeable options (JSON'ized as {USER_OPTIONS_JS} in TPL) + */ + var $opt_js = array( + 'only_new' => 0, // show ony new posts or topics + 'h_flag' => 0, // hide flags + 'h_av' => 0, // hide avatar + 'h_rnk_i' => 0, // hide rank images + 'h_post_i' => 0, // hide post images + 'h_smile' => 0, // hide smilies + 'h_sig' => 0, // hide signatures + 'sp_op' => 0, // show spoiler opened + 'tr_t_ax' => 0, // ajax open topics + ); + + /** + * Sessiondata + */ + var $sessiondata = array( + 'uk' => null, + 'uid' => null, + 'sid' => '', + ); + + /** + * Old $userdata + */ + var $data = array(); + + /** + * Shortcuts + */ + var $id = null; + + /** + * Misc + */ + var $show_ads = false; + + /** + * Constructor + */ + function user_common () + { + $this->get_sessiondata(); + } + + /** + * Start session (restore existent session or create new) + */ + function session_start ($cfg = array()) + { + global $bb_cfg; + + $update_sessions_table = false; + $this->cfg = array_merge($this->cfg, $cfg); + + $session_id = $this->sessiondata['sid']; + + // Does a session exist? + if ($session_id || !$this->sessiondata['uk']) + { + $SQL = DB()->get_empty_sql_array(); + + $SQL['SELECT'][] = "u.*, s.*"; + + $SQL['FROM'][] = BB_SESSIONS ." s"; + $SQL['INNER JOIN'][] = BB_USERS ." u ON(u.user_id = s.session_user_id)"; + + if ($session_id) + { + $SQL['WHERE'][] = "s.session_id = '$session_id'"; + + if ($bb_cfg['torhelp_enabled']) + { + $SQL['SELECT'][] = "th.topic_id_csv AS torhelp"; + $SQL['LEFT JOIN'][] = BB_BT_TORHELP ." th ON(u.user_id = th.user_id)"; + } + + $userdata_cache_id = $session_id; + } + else + { + $SQL['WHERE'][] = "s.session_ip = '". USER_IP ."'"; + $SQL['WHERE'][] = "s.session_user_id = ". ANONYMOUS; + + $userdata_cache_id = USER_IP; + } + + if (!$this->data = cache_get_userdata($userdata_cache_id)) + { + $this->data = DB()->fetch_row($SQL); + + if ($this->data && (TIMENOW - $this->data['session_time']) > $bb_cfg['session_update_intrv']) + { + $this->data['session_time'] = TIMENOW; + $update_sessions_table = true; + } + + cache_set_userdata($this->data); + } + } + + ##### LOG ##### + global $log_ip_req; + + if (isset($log_ip_req[USER_IP]) || isset($log_ip_req[CLIENT_IP])) + { + $file = 'sessions/'. date('m-d') .'_{'. USER_IP .'}_'. CLIENT_IP; + $str = array(); + $str[] = date('H:i:s'); + $str[] = (@$this->sessiondata['uid']) ? sprintf('%06d', strval($this->sessiondata['uid'])) : 'guest '; + $str[] = (@$this->data['session_start']) ? gmdate('H:i:s', $this->data['session_start']) : 'guest '; + $str[] = (@$this->sessiondata['sid']) ? sprintf('%-12s', strval($this->sessiondata['sid'])) : 'none '; + $str[] = $_SERVER['REQUEST_URI']; + # $str[] = 'REFERER: '. $_SERVER['HTTP_REFERER']; + $str[] = @$_SERVER['HTTP_USER_AGENT']; + $str = join(LOG_SEPR, $str) . LOG_LF; + bb_log($str, $file); + } + ### LOG END ### + + // Did the session exist in the DB? + if ($this->data) + { + // Do not check IP assuming equivalence, if IPv4 we'll check only first 24 + // bits ... I've been told (by vHiker) this should alleviate problems with + // load balanced et al proxies while retaining some reliance on IP security. + $ip_check_s = substr($this->data['session_ip'], 0, 6); + $ip_check_u = substr(USER_IP, 0, 6); + + if ($ip_check_s == $ip_check_u) + { + if ($this->data['user_id'] != ANONYMOUS && defined('IN_ADMIN')) + { + define('SID_GET', "sid={$this->data['session_id']}"); + } + $session_id = $this->sessiondata['sid'] = $this->data['session_id']; + + // Only update session a minute or so after last update + if ($update_sessions_table) + { + DB()->query(" + UPDATE ". BB_SESSIONS ." SET + session_time = ". TIMENOW ." + WHERE session_id = '$session_id' + LIMIT 1 + "); + } + $this->set_session_cookies($this->data['user_id']); + } + else + { + $this->data = array(); + } + } + // If we reach here then no (valid) session exists. So we'll create a new one, + // using the cookie user_id if available to pull basic user prefs. + if (!$this->data) + { + $login = false; + $user_id = ($bb_cfg['allow_autologin'] && $this->sessiondata['uk'] && $this->sessiondata['uid']) ? $this->sessiondata['uid'] : ANONYMOUS; + + if ($userdata = get_userdata(intval($user_id), false, true)) + { + if ($userdata['user_id'] != ANONYMOUS && $userdata['user_active']) + { + if (verify_id($this->sessiondata['uk'], LOGIN_KEY_LENGTH) && $this->verify_autologin_id($userdata, true, false)) + { + $login = ($userdata['autologin_id'] && $this->sessiondata['uk'] === $userdata['autologin_id']); + } + } + } + if (!$userdata || ($userdata['user_id'] != ANONYMOUS && !$login)) + { + $userdata = get_userdata(ANONYMOUS, false, true); + } + + $this->session_create($userdata, true); + } + + define('IS_GUEST', (!$this->data['session_logged_in'])); + define('IS_ADMIN', (!IS_GUEST && $this->data['user_level'] == ADMIN)); + define('IS_MOD', (!IS_GUEST && $this->data['user_level'] == MOD)); + define('IS_GROUP_MEMBER', (!IS_GUEST && $this->data['user_level'] == GROUP_MEMBER)); + define('IS_USER', (!IS_GUEST && $this->data['user_level'] == USER)); + define('IS_SUPER_ADMIN', (IS_ADMIN && isset($bb_cfg['super_admins'][$this->data['user_id']]))); + define('IS_AM', (IS_ADMIN || IS_MOD)); + + $this->set_shortcuts(); + + // Redirect guests to login page + if (IS_GUEST && $this->cfg['req_login']) + { + login_redirect(); + } + + $this->init_userprefs(); + + return $this->data; + } + + /** + * Create new session for the given user + */ + function session_create ($userdata, $auto_created = false) + { + global $bb_cfg; + + $this->data = $userdata; + $session_id = $this->sessiondata['sid']; + + $login = (int) ($this->data['user_id'] != ANONYMOUS); + $is_user = ($this->data['user_level'] == USER); + $user_id = (int) $this->data['user_id']; + $mod_admin_session = ($login && !$auto_created && !$is_user) ? $this->data['user_level'] : 0; + + if (($bb_cfg['max_srv_load'] || $bb_cfg['max_reg_users_online']) && $login && $is_user && !$this->data['ignore_srv_load']) + { + $this->limit_srv_load(); + } + + // Initial ban check against user_id or IP address + if ($is_user) + { + preg_match('#(..)(..)(..)(..)#', USER_IP, $ip); + + $where_sql = "ban_ip IN('". USER_IP ."', '$ip[1]$ip[2]$ip[3]ff', '$ip[1]$ip[2]ffff', '$ip[1]ffffff')"; + $where_sql .= ($login) ? " OR ban_userid = $user_id" : ''; + + $sql = "SELECT ban_id FROM ". BB_BANLIST ." WHERE $where_sql LIMIT 1"; + + if (DB()->fetch_row($sql)) + { + bb_exit('~'); + } + } + + // Create new session + for ($i=0, $max_try=5; $i <= $max_try; $i++) + { + $session_id = make_rand_str(SID_LENGTH); + + $args = DB()->build_array('INSERT', array( + 'session_id' => (string) $session_id, + 'session_user_id' => (int) $user_id, + 'session_start' => (int) TIMENOW, + 'session_time' => (int) TIMENOW, + 'session_ip' => (string) USER_IP, + 'session_logged_in' => (int) $login, + 'session_admin' => (int) $mod_admin_session, + )); + $sql = "INSERT INTO ". BB_SESSIONS . $args; + + if (@DB()->query($sql)) + { + break; + } + if ($i == $max_try) + { + trigger_error('Error creating new session', E_USER_ERROR); + } + } + // Update last visit for logged in users + if ($login) + { + $last_visit = $this->data['user_lastvisit']; + + if (!$session_time = $this->data['user_session_time']) + { + $last_visit = TIMENOW; + define('FIRST_LOGON', true); + } + else if ($session_time < (TIMENOW - $bb_cfg['last_visit_update_intrv'])) + { + $last_visit = max($session_time, (TIMENOW - 86400*$bb_cfg['max_last_visit_days'])); + } + + if ($last_visit != $this->data['user_lastvisit']) + { + DB()->query(" + UPDATE ". BB_USERS ." SET + user_session_time = ". TIMENOW .", + user_lastvisit = $last_visit, + user_last_ip = '". USER_IP ."', + user_reg_ip = IF(user_reg_ip = '', '". USER_IP ."', user_reg_ip) + WHERE user_id = $user_id + LIMIT 1 + "); + + bb_setcookie(COOKIE_TOPIC, ''); + bb_setcookie(COOKIE_FORUM, ''); + + $this->data['user_lastvisit'] = $last_visit; + } + if (!empty($_POST['autologin']) && $bb_cfg['allow_autologin']) + { + if (!$auto_created) + { + $this->verify_autologin_id($this->data, true, true); + } + $this->sessiondata['uk'] = $this->data['autologin_id']; + } + $this->sessiondata['uid'] = $user_id; + $this->sessiondata['sid'] = $session_id; + } + $this->data['session_id'] = $session_id; + $this->data['session_ip'] = USER_IP; + $this->data['session_user_id'] = $user_id; + $this->data['session_logged_in'] = $login; + $this->data['session_start'] = TIMENOW; + $this->data['session_time'] = TIMENOW; + $this->data['session_admin'] = $mod_admin_session; + + $this->set_session_cookies($user_id); + + if ($login && (defined('IN_ADMIN') || $mod_admin_session)) + { + define('SID_GET', "sid=$session_id"); + } + + cache_set_userdata($this->data); + + return $this->data; + } + + /** + * Initialize sessiondata stored in cookies + */ + function session_end ($update_lastvisit = false, $set_cookie = true) + { + DB()->query(" + DELETE FROM ". BB_SESSIONS ." + WHERE session_id = '{$this->data['session_id']}' + "); + + if (!IS_GUEST) + { + if ($update_lastvisit) + { + DB()->query(" + UPDATE ". BB_USERS ." SET + user_session_time = ". TIMENOW .", + user_lastvisit = ". TIMENOW .", + user_last_ip = '". USER_IP ."', + user_reg_ip = IF(user_reg_ip = '', '". USER_IP ."', user_reg_ip) + WHERE user_id = {$this->data['user_id']} + LIMIT 1 + "); + } + + if (isset($_REQUEST['reset_autologin'])) + { + $this->create_autologin_id($this->data, false); + + DB()->query(" + DELETE FROM ". BB_SESSIONS ." + WHERE session_user_id = '{$this->data['user_id']}' + "); + } + } + + if ($set_cookie) + { + $this->set_session_cookies(ANONYMOUS); + } + } + + /** + * Login + */ + function login ($args, $mod_admin_login = false) + { + global $bb_cfg; + + $username = !empty($args['login_username']) ? clean_username($args['login_username']) : ''; + $password = !empty($args['login_password']) ? $args['login_password'] : ''; + + if ($username && $password) + { + $username_sql = str_replace("\\'", "''", $username); + $password_sql = md5($password); + + $sql = " + SELECT * + FROM ". BB_USERS ." + WHERE username = '$username_sql' + AND user_password = '$password_sql' + AND user_active = 1 + AND user_id != ". ANONYMOUS ." + LIMIT 1 + "; + + if ($userdata = DB()->fetch_row($sql)) + { + if (!$userdata['username'] || !$userdata['user_password'] || $userdata['user_id'] == ANONYMOUS || md5($password) !== $userdata['user_password'] || !$userdata['user_active']) + { + trigger_error('invalid userdata', E_USER_ERROR); + } + + // Start mod/admin session + if ($mod_admin_login) + { + DB()->query(" + UPDATE ". BB_SESSIONS ." SET + session_admin = ". $this->data['user_level'] ." + WHERE session_user_id = ". $this->data['user_id'] ." + AND session_id = '". $this->data['session_id'] ."' + "); + $this->data['session_admin'] = $this->data['user_level']; + cache_update_userdata($this->data); + + return $this->data; + } + else if ($new_session_userdata = $this->session_create($userdata, false)) + { + // Removing guest sessions from this IP + DB()->query(" + DELETE FROM ". BB_SESSIONS ." + WHERE session_ip = '". USER_IP ."' + AND session_user_id = ". ANONYMOUS ." + "); + + return $new_session_userdata; + } + else + { + trigger_error("Couldn't start session : login", E_USER_ERROR); + } + } + } + + return array(); + } + + /** + * Initialize sessiondata stored in cookies + */ + function get_sessiondata () + { + $sd_resv = !empty($_COOKIE[COOKIE_DATA]) ? @unserialize($_COOKIE[COOKIE_DATA]) : array(); + + // autologin_id + if (!empty($sd_resv['uk']) && verify_id($sd_resv['uk'], LOGIN_KEY_LENGTH)) + { + $this->sessiondata['uk'] = $sd_resv['uk']; + } + // user_id + if (!empty($sd_resv['uid'])) + { + $this->sessiondata['uid'] = intval($sd_resv['uid']); + } + // sid + if (!empty($sd_resv['sid']) && verify_id($sd_resv['sid'], SID_LENGTH)) + { + $this->sessiondata['sid'] = $sd_resv['sid']; + } + } + + /** + * Store sessiondata in cookies + */ + function set_session_cookies ($user_id) + { + global $bb_cfg; + + if ($user_id == ANONYMOUS) + { + $delete_cookies = array( + COOKIE_DATA, + COOKIE_LOAD, + COOKIE_DBG, + //COOKIE_TEST, // dj_maxx: add visual confirmation to login form + 'torhelp', + 'phpbb2mysql_data', + 'kb_layout', + ); + // dj_maxx: add visual confirmation to login form + if (!defined('IN_PROFILE')) + { + $delete_cookies[] = COOKIE_TEST; + } + // end of + } + else + { + $delete_cookies = array('phpbb2mysql_data'); + + if (!(defined('IN_LOGIN') || defined('IN_PROFILE'))) + { + $delete_cookies[] = COOKIE_TEST; + } + } + + if ($delete_cookies) + { + foreach ($delete_cookies as $cookie) + { + if (isset($_COOKIE[$cookie])) + { + bb_setcookie($cookie, '', COOKIE_EXPIRED); + } + } + } + + if ($user_id != ANONYMOUS) + { + $c_sdata_resv = !empty($_COOKIE[COOKIE_DATA]) ? $_COOKIE[COOKIE_DATA] : null; + $c_sdata_curr = ($this->sessiondata) ? serialize($this->sessiondata) : ''; + + if ($c_sdata_curr !== $c_sdata_resv) + { + bb_setcookie(COOKIE_DATA, $c_sdata_curr, COOKIE_PERSIST, true); + } + if ($bb_cfg['max_srv_load']) + { + $c_isl_resv = isset($_COOKIE[COOKIE_LOAD]) ? intval($_COOKIE[COOKIE_LOAD]) : null; + $c_isl_curr = ($this->data['user_level'] == USER && !$this->data['ignore_srv_load']) ? TIMENOW : 0; + + if ($c_isl_curr !== $c_isl_resv) + { + bb_setcookie(COOKIE_LOAD, $c_isl_curr); + } + } + if (isset($bb_cfg['dbg_users'][$this->data['user_id']]) && !isset($_COOKIE[COOKIE_DBG])) + { + bb_setcookie(COOKIE_DBG, 1, COOKIE_SESSION); + } + } + } + + /** + * Verify autologin_id + */ + function verify_autologin_id ($userdata, $expire_check = false, $create_new = true) + { + global $bb_cfg; + + $autologin_id = $userdata['autologin_id']; + + if ($expire_check) + { + if ($create_new && !$autologin_id) + { + return $this->create_autologin_id($userdata); + } + else if ($autologin_id && $userdata['user_session_time'] && $bb_cfg['max_autologin_time']) + { + if (TIMENOW - $userdata['user_session_time'] > $bb_cfg['max_autologin_time']*86400) + { + return $this->create_autologin_id($userdata, $create_new); + } + } + } + + return verify_id($autologin_id, LOGIN_KEY_LENGTH); + } + + /** + * Create autologin_id + */ + function create_autologin_id ($userdata, $create_new = true) + { + $autologin_id = ($create_new) ? make_rand_str(LOGIN_KEY_LENGTH) : ''; + + DB()->query(" + UPDATE ". BB_USERS ." SET + autologin_id = '$autologin_id' + WHERE user_id = ". (int) $userdata['user_id'] ." + LIMIT 1 + "); + + return $autologin_id; + } + + /** + * Limit server load + */ + function limit_srv_load () + { + global $bb_cfg; + + if (!empty($_POST['message'])) return; + + $srv_overloaded = false; + + if (LOADAVG) + { + $srv_overloaded = (LOADAVG > $bb_cfg['max_srv_load']); + } + if (!$srv_overloaded && $bb_cfg['max_reg_users_online']) + { + $sql = "SELECT COUNT(DISTINCT session_user_id) AS users_count FROM ". BB_SESSIONS ." WHERE session_time > ". (TIMENOW - 300); + + if ($row = DB()->fetch_row($sql)) + { + $srv_overloaded = ($row['users_count'] > $bb_cfg['max_reg_users_online']); + } + } + if ($srv_overloaded) + { + require(TPL_LIMIT_LOAD_EXIT); + } + } + + /** + * Initialise user settings + */ + function init_userprefs () + { + global $bb_cfg, $theme, $lang, $DeltaTime; + + if (defined('LANG_DIR')) return; // prevent multiple calling + + define('DEFAULT_LANG_DIR', LANG_ROOT_DIR .'lang_'. $bb_cfg['default_lang'] .'/'); + define('ENGLISH_LANG_DIR', LANG_ROOT_DIR .'lang_english/'); + + if ($this->data['user_id'] != ANONYMOUS) + { + if ($this->data['user_lang'] && $this->data['user_lang'] != $bb_cfg['default_lang']) + { + $bb_cfg['default_lang'] = basename($this->data['user_lang']); + define('LANG_DIR', LANG_ROOT_DIR .'lang_'. $bb_cfg['default_lang'] .'/'); + } + + if ($this->data['user_dateformat']) + { + $bb_cfg['default_dateformat'] = $this->data['user_dateformat']; + } + + if (isset($this->data['user_timezone'])) + { + $bb_cfg['board_timezone'] = $this->data['user_timezone']; + } + } + + $this->data['user_lang'] = $bb_cfg['default_lang']; + $this->data['user_dateformat'] = $bb_cfg['default_dateformat']; + $this->data['user_timezone'] = $bb_cfg['board_timezone']; + + if (!defined('LANG_DIR')) + { + define('LANG_DIR', DEFAULT_LANG_DIR); + } + + require(LANG_DIR .'lang_main.php'); + + if (defined('IN_ADMIN')) + { + require(LANG_DIR .'lang_admin.php'); + require(LANG_DIR .'lang_admin_attach.php'); + } + + $theme = setup_style(); + $DeltaTime = new Date_Delta(); + + // Handle marking posts read + if (!IS_GUEST && !empty($_COOKIE[COOKIE_MARK])) + { + $this->mark_read($_COOKIE[COOKIE_MARK]); + } + + $this->load_opt_js(); + $this->enqueue_ads(); + } + + /** + * Mark read + */ + function mark_read ($type) + { + global $template, $lang; + + if ($type === 'all_forums') + { + // Update session time + DB()->query(" + UPDATE ". BB_SESSIONS ." SET + session_time = ". TIMENOW ." + WHERE session_id = '{$this->data['session_id']}' + LIMIT 1 + "); + + // Update userdata + $this->data['session_time'] = TIMENOW; + $this->data['user_lastvisit'] = TIMENOW; + + // Update lastvisit + db_update_userdata($this->data, array( + 'user_session_time' => $this->data['session_time'], + 'user_lastvisit' => $this->data['user_lastvisit'], + )); + + // Delete cookies + bb_setcookie(COOKIE_TOPIC, ''); + bb_setcookie(COOKIE_FORUM, ''); + bb_setcookie(COOKIE_MARK, ''); + + // Info message + # $template->assign_var('INFO_MESSAGE', $lang['FORUMS_MARKED_READ']); + } + } + + /** + * Load misc options + */ + function load_opt_js () + { + if (!IS_GUEST && !empty($_COOKIE['opt_js'])) + { + $opt_js = bb_json_decode($_COOKIE['opt_js']); + + if (is_array($opt_js)) + { + $this->opt_js = array_merge($this->opt_js, $opt_js); + } + } + } + + /** + * Set shortcuts + */ + function set_shortcuts () + { + $this->id =& $this->data['user_id']; + $this->opt =& $this->data['user_opt']; + } + + /** + * Get not auth forums + */ + function get_not_auth_forums ($auth_type) + { + global $datastore; + + if (IS_ADMIN) return ''; + + if (!$forums = $datastore->get('cat_forums')) + { + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); + } + + if ($auth_type == AUTH_VIEW) + { + if (IS_GUEST) + { + return $forums['not_auth_forums']['guest_view']; + } + } + if ($auth_type == AUTH_READ) + { + if (IS_GUEST) + { + return $forums['not_auth_forums']['guest_read']; + } + } + + $auth_field_match = array( + AUTH_VIEW => 'auth_view', + AUTH_READ => 'auth_read', + AUTH_POST => 'auth_post', + AUTH_REPLY => 'auth_reply', + AUTH_EDIT => 'auth_edit', + AUTH_DELETE => 'auth_delete', + AUTH_STICKY => 'auth_sticky', + AUTH_ANNOUNCE => 'auth_announce', + AUTH_VOTE => 'auth_vote', + AUTH_POLLCREATE => 'auth_pollcreate', + AUTH_ATTACH => 'auth_attachments', + AUTH_DOWNLOAD => 'auth_download', + ); + + $not_auth_forums = array(); + $auth_field = $auth_field_match[$auth_type]; + $is_auth_ary = auth($auth_type, AUTH_LIST_ALL, $this->data); + + foreach ($is_auth_ary as $forum_id => $is_auth) + { + if (!$is_auth[$auth_field]) + { + $not_auth_forums[] = $forum_id; + } + } + + return join(',', $not_auth_forums); + } + + /** + * Exclude porn forums + */ + function exclude_porn_forums () + { + global $bb_cfg; + + return ($bb_cfg['porno_forums'] && bf($this->opt, 'user_opt', 'hide_porn_forums')) ? $bb_cfg['porno_forums'] : ''; + } + + /** + * Get excluded forums + */ + function get_excluded_forums ($auth_type, $return_as = 'csv') + { + $excluded = array(); + + if ($not_auth = $this->get_not_auth_forums($auth_type)) + { + $excluded[] = $not_auth; + } + if ($porn = $this->exclude_porn_forums()) + { + $excluded[] = $porn; + } + + switch ($return_as) + { + case 'csv': return join(',', $excluded); + case 'array': return $excluded; + case 'flip': return array_flip(explode(',', $excluded)); + } + } + + /** + * Check if user can hide ads + */ + function hide_ads () + { + return (bf($this->opt, 'user_opt', 'can_hide_ads') && bf($this->opt, 'user_opt', 'hide_ads')); + } + + /** + * Enqueue ads + */ + function enqueue_ads () + { + global $datastore, $bb_cfg; + + if ($bb_cfg['show_ads'] && !$this->hide_ads() && !defined('IN_ADMIN') && !defined('IN_AJAX')) + { + $datastore->enqueue('ads'); + $this->show_ads = true; + } + } +} + + +// +// userdata cache +// +function ignore_cached_userdata () +{ + return (defined('IN_PM')) ? true : false; +} + +function cache_get_userdata ($id) +{ + if (ignore_cached_userdata()) return false; + + return CACHE('session_cache')->get($id); +} + +function cache_set_userdata ($userdata, $force = false) +{ + global $bb_cfg; + + if (!$userdata || (ignore_cached_userdata() && !$force)) return false; + + $id = ($userdata['user_id'] == ANONYMOUS) ? $userdata['session_ip'] : $userdata['session_id']; + return CACHE('session_cache')->set($id, $userdata, $bb_cfg['session_update_intrv']); +} + +function cache_rm_userdata ($userdata) +{ + if (!$userdata) return false; + + $id = ($userdata['user_id'] == ANONYMOUS) ? $userdata['session_ip'] : $userdata['session_id']; + return CACHE('session_cache')->rm($id); +} + +// $user_id - array(id1,id2,..) or (string) id +function cache_rm_user_sessions ($user_id) +{ + $user_id = get_id_csv($user_id); + + $rowset = DB()->fetch_rowset(" + SELECT session_id FROM ". BB_SESSIONS ." WHERE session_user_id IN($user_id) + "); + + foreach ($rowset as $row) + { + CACHE('session_cache')->rm($row['session_id']); + } +} + +function cache_update_userdata ($userdata) +{ + return cache_set_userdata($userdata, true); +} + +function db_update_userdata ($userdata, $sql_ary, $data_already_escaped = true) +{ + if (!$userdata) return false; + + $sql_args = DB()->build_array('UPDATE', $sql_ary, $data_already_escaped); + DB()->query("UPDATE ". BB_USERS ." SET $sql_args WHERE user_id = {$userdata['user_id']}"); + + if (DB()->affected_rows()) + { + cache_rm_userdata($userdata); + } +} + +// $user_id - array(id1,id2,..) or (string) id +function delete_user_sessions ($user_id) +{ + cache_rm_user_sessions($user_id); + + $user_id = get_id_csv($user_id); + DB()->query("DELETE FROM ". BB_SESSIONS ." WHERE session_user_id IN($user_id)"); +} + +function append_sid ($url, $non_html_amp = false) +{ + if (defined('SID_GET') && !strpos($url, SID_GET)) + { + $url .= ((strpos($url, '?') !== false) ? (($non_html_amp) ? '&' : '&') : '?') . SID_GET; + } + return $url; +} + +// deprecated +function session_begin ($userdata, $page_id = 0, $enable_autologin = false, $auto_created = false) +{ + global $user; + + $user->session_create($userdata, $auto_created); + + return $user->data; +} + +// deprecated +function session_pagestart ($user_ip = USER_IP, $page_id = 0, $req_login = false) +{ + global $user; + + $user->session_start(array('req_login' => $req_login)); + + return $user->data; +} \ No newline at end of file diff --git a/upload/includes/smtp.php b/upload/includes/smtp.php new file mode 100644 index 000000000..19c575408 --- /dev/null +++ b/upload/includes/smtp.php @@ -0,0 +1,186 @@ + 1) + { + $headers = join("\n", $headers); + } + else + { + $headers = $headers[0]; + } + } + $headers = chop($headers); + + // Make sure there are no bare linefeeds in the headers + $headers = preg_replace('#(?\r\n"); + server_parse($socket, "250", __LINE__); + + // Specify each user to send to and build to header. + $to_header = ''; + + // Add an additional bit of error checking to the To field. + $mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to); + if (preg_match('#[^ ]+\@[^ ]+#', $mail_to)) + { + fputs($socket, "RCPT TO: <$mail_to>\r\n"); + server_parse($socket, "250", __LINE__); + } + + // Ok now do the CC and BCC fields... + @reset($bcc); + while(list(, $bcc_address) = each($bcc)) + { + // Add an additional bit of error checking to bcc header... + $bcc_address = trim($bcc_address); + if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address)) + { + fputs($socket, "RCPT TO: <$bcc_address>\r\n"); + server_parse($socket, "250", __LINE__); + } + } + + @reset($cc); + while(list(, $cc_address) = each($cc)) + { + // Add an additional bit of error checking to cc header + $cc_address = trim($cc_address); + if (preg_match('#[^ ]+\@[^ ]+#', $cc_address)) + { + fputs($socket, "RCPT TO: <$cc_address>\r\n"); + server_parse($socket, "250", __LINE__); + } + } + + // Ok now we tell the server we are ready to start sending data + fputs($socket, "DATA\r\n"); + + // This is the last response code we look for until the end of the message. + server_parse($socket, "354", __LINE__); + + // Send the Subject Line... + fputs($socket, "Subject: $subject\r\n"); + + // Now the To Header. + fputs($socket, "To: $mail_to\r\n"); + + // Now any custom headers.... + fputs($socket, "$headers\r\n\r\n"); + + // Ok now we are ready for the message... + fputs($socket, "$message\r\n"); + + // Ok the all the ingredients are mixed in let's cook this puppy... + fputs($socket, ".\r\n"); + server_parse($socket, "250", __LINE__); + + // Now tell the server we are done and close the socket... + fputs($socket, "QUIT\r\n"); + fclose($socket); + + return TRUE; +} \ No newline at end of file diff --git a/upload/includes/sphinxapi.php b/upload/includes/sphinxapi.php new file mode 100644 index 000000000..3426e3bbc --- /dev/null +++ b/upload/includes/sphinxapi.php @@ -0,0 +1,1691 @@ +=8 ) + { + $v = (int)$v; + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", $v < 0 ? -1 : 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + if ( bccomp ( $v, 0 ) == -1 ) + $v = bcadd ( "18446744073709551616", $v ); + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = abs((float)substr($v, $p)); + $hi = abs((float)substr($v, 0, $p)); + + $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912 + $q = floor($m/4294967296.0); + $l = $m - ($q*4294967296.0); + $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328 + + if ( $v<0 ) + { + if ( $l==0 ) + $h = 4294967296.0 - $h; + else + { + $h = 4294967295.0 - $h; + $l = 4294967296.0 - $l; + } + } + return pack ( "NN", $h, $l ); +} + +/// pack 64-bit unsigned +function sphPackU64 ( $v ) +{ + assert ( is_numeric($v) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + assert ( $v>=0 ); + + // x64, int + if ( is_int($v) ) + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + + // x64, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, 4294967296, 0 ); + $l = bcmod ( $v, 4294967296 ); + return pack ( "NN", $h, $l ); + } + + // x64, no-bcmath + $p = max ( 0, strlen($v) - 13 ); + $lo = (int)substr ( $v, $p ); + $hi = (int)substr ( $v, 0, $p ); + + $m = $lo + $hi*1316134912; + $l = $m % 4294967296; + $h = $hi*2328 + (int)($m/4294967296); + + return pack ( "NN", $h, $l ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = (float)substr($v, $p); + $hi = (float)substr($v, 0, $p); + + $m = $lo + $hi*1316134912.0; + $q = floor($m / 4294967296.0); + $l = $m - ($q * 4294967296.0); + $h = $hi*2328.0 + $q; + + return pack ( "NN", $h, $l ); +} + +// unpack 64-bit unsigned +function sphUnpackU64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + // x64, int + if ( $hi<=2147483647 ) + return ($hi<<32) + $lo; + + // x64, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x64, no-bcmath + $C = 100000; + $h = ((int)($hi / $C) << 32) + (int)($lo / $C); + $l = (($hi % $C) << 32) + ($lo % $C); + if ( $l>$C ) + { + $h += (int)($l / $C); + $l = $l % $C; + } + + if ( $h==0 ) + return $l; + return sprintf ( "%d%05d", $h, $l ); + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0; + $h = $q*4294967296.0 + $r*429.0 + $mq; + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return sprintf( "%.0f", (float)$l ); + return $h . $l; +} + +// unpack 64-bit signed +function sphUnpackI64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + return ($hi<<32) + $lo; + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + // x32, int + elseif ( $hi==-1 ) + { + if ( $lo<0 ) + return $lo; + return sprintf ( "%.0f", $lo - 4294967296.0 ); + } + + $neg = ""; + $c = 0; + if ( $hi<0 ) + { + $hi = ~$hi; + $lo = ~$lo; + $c = 1; + $neg = "-"; + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0 + $c; + $h = $q*4294967296.0 + $r*429.0 + $mq; + if ( $l==10000000 ) + { + $l = 0; + $h += 1; + } + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return $neg . sprintf( "%.0f", (float)$l ); + return $neg . $h . $l; +} + + +function sphFixUint ( $value ) +{ + if ( PHP_INT_SIZE>=8 ) + { + // x64 route, workaround broken unpack() in 5.2.2+ + if ( $value<0 ) $value += (1<<32); + return $value; + } + else + { + // x32 route, workaround php signed/unsigned braindamage + return sprintf ( "%u", $value ); + } +} + + +/// sphinx searchd client class +class SphinxClient +{ + var $_host; ///< searchd host (default is "localhost") + var $_port; ///< searchd port (default is 9312) + var $_offset; ///< how many records to seek from result-set start (default is 0) + var $_limit; ///< how many records to return from result-set starting at offset (default is 20) + var $_mode; ///< query matching mode (default is SPH_MATCH_ALL) + var $_weights; ///< per-field weights (default is 1 for all fields) + var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE) + var $_sortby; ///< attribute to sort by (defualt is "") + var $_min_id; ///< min ID to match (default is 0, which means no limit) + var $_max_id; ///< max ID to match (default is 0, which means no limit) + var $_filters; ///< search filters + var $_groupby; ///< group-by attribute name + var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with) + var $_groupsort; ///< group-by sorting clause (to sort groups in result set with) + var $_groupdistinct;///< group-by count-distinct attribute + var $_maxmatches; ///< max matches to retrieve + var $_cutoff; ///< cutoff to stop searching at (default is 0) + var $_retrycount; ///< distributed retries count + var $_retrydelay; ///< distributed retries delay + var $_anchor; ///< geographical anchor point + var $_indexweights; ///< per-index weights + var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25) + var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit) + var $_fieldweights; ///< per-field-name weights + var $_overrides; ///< per-query attribute values overrides + var $_select; ///< select-list (attributes or expressions, with optional aliases) + + var $_error; ///< last error message + var $_warning; ///< last warning message + var $_connerror; ///< connection error vs remote error flag + + var $_reqs; ///< requests array for multi-query + var $_mbenc; ///< stored mbstring encoding + var $_arrayresult; ///< whether $result["matches"] should be a hash or an array + var $_timeout; ///< connect timeout + + ///////////////////////////////////////////////////////////////////////////// + // common stuff + ///////////////////////////////////////////////////////////////////////////// + + /// create a new client object and fill defaults + function SphinxClient () + { + // per-client-object settings + $this->_host = "localhost"; + $this->_port = 9312; + $this->_path = false; + $this->_socket = false; + + // per-query settings + $this->_offset = 0; + $this->_limit = 20; + $this->_mode = SPH_MATCH_ALL; + $this->_weights = array (); + $this->_sort = SPH_SORT_RELEVANCE; + $this->_sortby = ""; + $this->_min_id = 0; + $this->_max_id = 0; + $this->_filters = array (); + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + $this->_maxmatches = 1000; + $this->_cutoff = 0; + $this->_retrycount = 0; + $this->_retrydelay = 0; + $this->_anchor = array (); + $this->_indexweights= array (); + $this->_ranker = SPH_RANK_PROXIMITY_BM25; + $this->_maxquerytime= 0; + $this->_fieldweights= array(); + $this->_overrides = array(); + $this->_select = "*"; + + $this->_error = ""; // per-reply fields (for single-query case) + $this->_warning = ""; + $this->_connerror = false; + + $this->_reqs = array (); // requests storage (for multi-query case) + $this->_mbenc = ""; + $this->_arrayresult = false; + $this->_timeout = 0; + } + + function __destruct() + { + if ( $this->_socket !== false ) + fclose ( $this->_socket ); + } + + /// get last error message (string) + function GetLastError () + { + return $this->_error; + } + + /// get last warning message (string) + function GetLastWarning () + { + return $this->_warning; + } + + /// get last error flag (to tell network connection errors from searchd errors or broken responses) + function IsConnectError() + { + return $this->_connerror; + } + + /// set searchd host name (string) and port (integer) + function SetServer ( $host, $port = 0 ) + { + assert ( is_string($host) ); + if ( $host[0] == '/') + { + $this->_path = 'unix://' . $host; + return; + } + if ( substr ( $host, 0, 7 )=="unix://" ) + { + $this->_path = $host; + return; + } + + assert ( is_int($port) ); + $this->_host = $host; + $this->_port = $port; + $this->_path = ''; + + } + + /// set server connection timeout (0 to remove) + function SetConnectTimeout ( $timeout ) + { + assert ( is_numeric($timeout) ); + $this->_timeout = $timeout; + } + + + function _Send ( $handle, $data, $length ) + { + if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length ) + { + $this->_error = 'connection unexpectedly closed (timed out?)'; + $this->_connerror = true; + return false; + } + return true; + } + + ///////////////////////////////////////////////////////////////////////////// + + /// enter mbstring workaround mode + function _MBPush () + { + $this->_mbenc = ""; + if ( ini_get ( "mbstring.func_overload" ) & 2 ) + { + $this->_mbenc = mb_internal_encoding(); + mb_internal_encoding ( "latin1" ); + } + } + + /// leave mbstring workaround mode + function _MBPop () + { + if ( $this->_mbenc ) + mb_internal_encoding ( $this->_mbenc ); + } + + /// connect to searchd server + function _Connect () + { + if ( $this->_socket!==false ) + { + // we are in persistent connection mode, so we have a socket + // however, need to check whether it's still alive + if ( !@feof ( $this->_socket ) ) + return $this->_socket; + + // force reopen + $this->_socket = false; + } + + $errno = 0; + $errstr = ""; + $this->_connerror = false; + + if ( $this->_path ) + { + $host = $this->_path; + $port = 0; + } + else + { + $host = $this->_host; + $port = $this->_port; + } + + if ( $this->_timeout<=0 ) + $fp = @fsockopen ( $host, $port, $errno, $errstr ); + else + $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout ); + + if ( !$fp ) + { + if ( $this->_path ) + $location = $this->_path; + else + $location = "{$this->_host}:{$this->_port}"; + + $errstr = trim ( $errstr ); + $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)"; + $this->_connerror = true; + return false; + } + + // send my version + // this is a subtle part. we must do it before (!) reading back from searchd. + // because otherwise under some conditions (reported on FreeBSD for instance) + // TCP stack could throttle write-write-read pattern because of Nagle. + if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) ) + { + fclose ( $fp ); + $this->_error = "failed to send client protocol version"; + return false; + } + + // check version + list(,$v) = unpack ( "N*", fread ( $fp, 4 ) ); + $v = (int)$v; + if ( $v<1 ) + { + fclose ( $fp ); + $this->_error = "expected searchd protocol version 1+, got version '$v'"; + return false; + } + + return $fp; + } + + /// get and check response packet from searchd server + function _GetResponse ( $fp, $client_ver ) + { + $response = ""; + $len = 0; + + $header = fread ( $fp, 8 ); + if ( strlen($header)==8 ) + { + list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) ); + $left = $len; + while ( $left>0 && !feof($fp) ) + { + $chunk = fread ( $fp, min ( 8192, $left ) ); + if ( $chunk ) + { + $response .= $chunk; + $left -= strlen($chunk); + } + } + } + if ( $this->_socket === false ) + fclose ( $fp ); + + // check response + $read = strlen ( $response ); + if ( !$response || $read!=$len ) + { + $this->_error = $len + ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)" + : "received zero-sized searchd response"; + return false; + } + + // check status + if ( $status==SEARCHD_WARNING ) + { + list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_warning = substr ( $response, 4, $wlen ); + return substr ( $response, 4+$wlen ); + } + if ( $status==SEARCHD_ERROR ) + { + $this->_error = "searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status==SEARCHD_RETRY ) + { + $this->_error = "temporary searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status!=SEARCHD_OK ) + { + $this->_error = "unknown status code '$status'"; + return false; + } + + // check version + if ( $ver<$client_ver ) + { + $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work", + $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff ); + } + + return $response; + } + + ///////////////////////////////////////////////////////////////////////////// + // searching + ///////////////////////////////////////////////////////////////////////////// + + /// set offset and count into result set, + /// and optionally set max-matches and cutoff limits + function SetLimits ( $offset, $limit, $max=0, $cutoff=0 ) + { + assert ( is_int($offset) ); + assert ( is_int($limit) ); + assert ( $offset>=0 ); + assert ( $limit>0 ); + assert ( $max>=0 ); + $this->_offset = $offset; + $this->_limit = $limit; + if ( $max>0 ) + $this->_maxmatches = $max; + if ( $cutoff>0 ) + $this->_cutoff = $cutoff; + } + + /// set maximum query time, in milliseconds, per-index + /// integer, 0 means "do not limit" + function SetMaxQueryTime ( $max ) + { + assert ( is_int($max) ); + assert ( $max>=0 ); + $this->_maxquerytime = $max; + } + + /// set matching mode + function SetMatchMode ( $mode ) + { + assert ( $mode==SPH_MATCH_ALL + || $mode==SPH_MATCH_ANY + || $mode==SPH_MATCH_PHRASE + || $mode==SPH_MATCH_BOOLEAN + || $mode==SPH_MATCH_EXTENDED + || $mode==SPH_MATCH_FULLSCAN + || $mode==SPH_MATCH_EXTENDED2 ); + $this->_mode = $mode; + } + + /// set ranking mode + function SetRankingMode ( $ranker ) + { + assert ( $ranker>=0 && $ranker_ranker = $ranker; + } + + /// set matches sorting mode + function SetSortMode ( $mode, $sortby="" ) + { + assert ( + $mode==SPH_SORT_RELEVANCE || + $mode==SPH_SORT_ATTR_DESC || + $mode==SPH_SORT_ATTR_ASC || + $mode==SPH_SORT_TIME_SEGMENTS || + $mode==SPH_SORT_EXTENDED || + $mode==SPH_SORT_EXPR ); + assert ( is_string($sortby) ); + assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 ); + + $this->_sort = $mode; + $this->_sortby = $sortby; + } + + /// bind per-field weights by order + /// DEPRECATED; use SetFieldWeights() instead + function SetWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $weight ) + assert ( is_int($weight) ); + + $this->_weights = $weights; + } + + /// bind per-field weights by name + function SetFieldWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $name=>$weight ) + { + assert ( is_string($name) ); + assert ( is_int($weight) ); + } + $this->_fieldweights = $weights; + } + + /// bind per-index weights by name + function SetIndexWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $index=>$weight ) + { + assert ( is_string($index) ); + assert ( is_int($weight) ); + } + $this->_indexweights = $weights; + } + + /// set IDs range to match + /// only match records if document ID is beetwen $min and $max (inclusive) + function SetIDRange ( $min, $max ) + { + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + $this->_min_id = $min; + $this->_max_id = $max; + } + + /// set values set filter + /// only match records where $attribute value is in given set + function SetFilter ( $attribute, $values, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_array($values) ); + assert ( count($values) ); + + if ( is_array($values) && count($values) ) + { + foreach ( $values as $value ) + assert ( is_numeric($value) ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values ); + } + } + + /// set range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// set float range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_float($min) ); + assert ( is_float($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// setup anchor point for geosphere distance calculations + /// required to use @geodist in filters and sorting + /// latitude and longitude must be in radians + function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long ) + { + assert ( is_string($attrlat) ); + assert ( is_string($attrlong) ); + assert ( is_float($lat) ); + assert ( is_float($long) ); + + $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long ); + } + + /// set grouping attribute and function + function SetGroupBy ( $attribute, $func, $groupsort="@group desc" ) + { + assert ( is_string($attribute) ); + assert ( is_string($groupsort) ); + assert ( $func==SPH_GROUPBY_DAY + || $func==SPH_GROUPBY_WEEK + || $func==SPH_GROUPBY_MONTH + || $func==SPH_GROUPBY_YEAR + || $func==SPH_GROUPBY_ATTR + || $func==SPH_GROUPBY_ATTRPAIR ); + + $this->_groupby = $attribute; + $this->_groupfunc = $func; + $this->_groupsort = $groupsort; + } + + /// set count-distinct attribute for group-by queries + function SetGroupDistinct ( $attribute ) + { + assert ( is_string($attribute) ); + $this->_groupdistinct = $attribute; + } + + /// set distributed retries count and delay + function SetRetries ( $count, $delay=0 ) + { + assert ( is_int($count) && $count>=0 ); + assert ( is_int($delay) && $delay>=0 ); + $this->_retrycount = $count; + $this->_retrydelay = $delay; + } + + /// set result set format (hash or array; hash by default) + /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs + function SetArrayResult ( $arrayresult ) + { + assert ( is_bool($arrayresult) ); + $this->_arrayresult = $arrayresult; + } + + /// set attribute values override + /// there can be only one override per attribute + /// $values must be a hash that maps document IDs to attribute values + function SetOverride ( $attrname, $attrtype, $values ) + { + assert ( is_string ( $attrname ) ); + assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) ); + assert ( is_array ( $values ) ); + + $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values ); + } + + /// set select-list (attributes or expressions), SQL-like syntax + function SetSelect ( $select ) + { + assert ( is_string ( $select ) ); + $this->_select = $select; + } + + ////////////////////////////////////////////////////////////////////////////// + + /// clear all filters (for multi-queries) + function ResetFilters () + { + $this->_filters = array(); + $this->_anchor = array(); + } + + /// clear groupby settings (for multi-queries) + function ResetGroupBy () + { + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + } + + /// clear all attribute value overrides (for multi-queries) + function ResetOverrides () + { + $this->_overrides = array (); + } + + ////////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, run given search query through given indexes, + /// and return the search results + function Query ( $query, $index="*", $comment="" ) + { + assert ( empty($this->_reqs) ); + + $this->AddQuery ( $query, $index, $comment ); + $results = $this->RunQueries (); + $this->_reqs = array (); // just in case it failed too early + + if ( !is_array($results) ) + return false; // probably network error; error message should be already filled + + $this->_error = $results[0]["error"]; + $this->_warning = $results[0]["warning"]; + if ( $results[0]["status"]==SEARCHD_ERROR ) + return false; + else + return $results[0]; + } + + /// helper to pack floats in network byte order + function _PackFloat ( $f ) + { + $t1 = pack ( "f", $f ); // machine order + list(,$t2) = unpack ( "L*", $t1 ); // int in machine order + return pack ( "N", $t2 ); + } + + /// add query to multi-query batch + /// returns index into results array from RunQueries() call + function AddQuery ( $query, $index="*", $comment="" ) + { + // mbstring workaround + $this->_MBPush (); + + // build request + $req = pack ( "NNNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker, $this->_sort ); // mode and limits + $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby; + $req .= pack ( "N", strlen($query) ) . $query; // query itself + $req .= pack ( "N", count($this->_weights) ); // weights + foreach ( $this->_weights as $weight ) + $req .= pack ( "N", (int)$weight ); + $req .= pack ( "N", strlen($index) ) . $index; // indexes + $req .= pack ( "N", 1 ); // id64 range marker + $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range + + // filters + $req .= pack ( "N", count($this->_filters) ); + foreach ( $this->_filters as $filter ) + { + $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"]; + $req .= pack ( "N", $filter["type"] ); + switch ( $filter["type"] ) + { + case SPH_FILTER_VALUES: + $req .= pack ( "N", count($filter["values"]) ); + foreach ( $filter["values"] as $value ) + $req .= sphPackI64 ( $value ); + break; + + case SPH_FILTER_RANGE: + $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] ); + break; + + case SPH_FILTER_FLOATRANGE: + $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] ); + break; + + default: + assert ( 0 && "internal error: unhandled filter type" ); + } + $req .= pack ( "N", $filter["exclude"] ); + } + + // group-by clause, max-matches count, group-sort clause, cutoff count + $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby; + $req .= pack ( "N", $this->_maxmatches ); + $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort; + $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay ); + $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct; + + // anchor point + if ( empty($this->_anchor) ) + { + $req .= pack ( "N", 0 ); + } else + { + $a =& $this->_anchor; + $req .= pack ( "N", 1 ); + $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"]; + $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"]; + $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] ); + } + + // per-index weights + $req .= pack ( "N", count($this->_indexweights) ); + foreach ( $this->_indexweights as $idx=>$weight ) + $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight ); + + // max query time + $req .= pack ( "N", $this->_maxquerytime ); + + // per-field weights + $req .= pack ( "N", count($this->_fieldweights) ); + foreach ( $this->_fieldweights as $field=>$weight ) + $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight ); + + // comment + $req .= pack ( "N", strlen($comment) ) . $comment; + + // attribute overrides + $req .= pack ( "N", count($this->_overrides) ); + foreach ( $this->_overrides as $key => $entry ) + { + $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"]; + $req .= pack ( "NN", $entry["type"], count($entry["values"]) ); + foreach ( $entry["values"] as $id=>$val ) + { + assert ( is_numeric($id) ); + assert ( is_numeric($val) ); + + $req .= sphPackU64 ( $id ); + switch ( $entry["type"] ) + { + case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break; + case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break; + default: $req .= pack ( "N", $val ); break; + } + } + } + + // select-list + $req .= pack ( "N", strlen($this->_select) ) . $this->_select; + + // mbstring workaround + $this->_MBPop (); + + // store request to requests array + $this->_reqs[] = $req; + return count($this->_reqs)-1; + } + + /// connect to searchd, run queries batch, and return an array of result sets + function RunQueries () + { + if ( empty($this->_reqs) ) + { + $this->_error = "no queries defined, issue AddQuery() first"; + return false; + } + + // mbstring workaround + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return false; + } + + // send query, get response + $nreqs = count($this->_reqs); + $req = join ( "", $this->_reqs ); + $len = 8+strlen($req); + $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header + + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) ) + { + $this->_MBPop (); + return false; + } + + // query sent ok; we can reset reqs now + $this->_reqs = array (); + + // parse and return response + return $this->_ParseSearchResponse ( $response, $nreqs ); + } + + /// parse and return search query (or queries) response + function _ParseSearchResponse ( $response, $nreqs ) + { + $p = 0; // current position + $max = strlen($response); // max position for checks, to protect against broken responses + + $results = array (); + for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ ) + { + $results[] = array(); + $result =& $results[$ires]; + + $result["error"] = ""; + $result["warning"] = ""; + + // extract status + list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $result["status"] = $status; + if ( $status!=SEARCHD_OK ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $message = substr ( $response, $p, $len ); $p += $len; + + if ( $status==SEARCHD_WARNING ) + { + $result["warning"] = $message; + } else + { + $result["error"] = $message; + continue; + } + } + + // read schema + $fields = array (); + $attrs = array (); + + list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nfields-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $fields[] = substr ( $response, $p, $len ); $p += $len; + } + $result["fields"] = $fields; + + list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nattrs-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attr = substr ( $response, $p, $len ); $p += $len; + list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrs[$attr] = $type; + } + $result["attrs"] = $attrs; + + // read match count + list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + + // read matches + $idx = -1; + while ( $count-->0 && $p<$max ) + { + // index into result array + $idx++; + + // parse document id and weight + if ( $id64 ) + { + $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; + list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + } + else + { + list ( $doc, $weight ) = array_values ( unpack ( "N*N*", + substr ( $response, $p, 8 ) ) ); + $p += 8; + $doc = sphFixUint($doc); + } + $weight = sprintf ( "%u", $weight ); + + // create match entry + if ( $this->_arrayresult ) + $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight ); + else + $result["matches"][$doc]["weight"] = $weight; + + // parse and create attributes + $attrvals = array (); + foreach ( $attrs as $attr=>$type ) + { + // handle 64bit ints + if ( $type==SPH_ATTR_BIGINT ) + { + $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8; + continue; + } + + // handle floats + if ( $type==SPH_ATTR_FLOAT ) + { + list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$fval) = unpack ( "f*", pack ( "L", $uval ) ); + $attrvals[$attr] = $fval; + continue; + } + + // handle everything else as unsigned ints + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + if ( $type & SPH_ATTR_MULTI ) + { + $attrvals[$attr] = array (); + $nvalues = $val; + while ( $nvalues-->0 && $p<$max ) + { + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrvals[$attr][] = sphFixUint($val); + } + } else if ( $type==SPH_ATTR_STRING ) + { + $attrvals[$attr] = substr ( $response, $p, $val ); + $p += $val; + } else + { + $attrvals[$attr] = sphFixUint($val); + } + } + + if ( $this->_arrayresult ) + $result["matches"][$idx]["attrs"] = $attrvals; + else + $result["matches"][$doc]["attrs"] = $attrvals; + } + + list ( $total, $total_found, $msecs, $words ) = + array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) ); + $result["total"] = sprintf ( "%u", $total ); + $result["total_found"] = sprintf ( "%u", $total_found ); + $result["time"] = sprintf ( "%.3f", $msecs/1000 ); + $p += 16; + + while ( $words-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $word = substr ( $response, $p, $len ); $p += $len; + list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + $result["words"][$word] = array ( + "docs"=>sprintf ( "%u", $docs ), + "hits"=>sprintf ( "%u", $hits ) ); + } + } + + $this->_MBPop (); + return $results; + } + + ///////////////////////////////////////////////////////////////////////////// + // excerpts generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate exceprts (snippets) + /// of given documents for given query. returns false on failure, + /// an array of snippets on success + function BuildExcerpts ( $docs, $index, $words, $opts=array() ) + { + assert ( is_array($docs) ); + assert ( is_string($index) ); + assert ( is_string($words) ); + assert ( is_array($opts) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // fixup options + ///////////////// + + if ( !isset($opts["before_match"]) ) $opts["before_match"] = ""; + if ( !isset($opts["after_match"]) ) $opts["after_match"] = ""; + if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... "; + if ( !isset($opts["limit"]) ) $opts["limit"] = 256; + if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0; + if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0; + if ( !isset($opts["around"]) ) $opts["around"] = 5; + if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false; + if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false; + if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false; + if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false; + if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false; + if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false; + if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1; + if ( !isset($opts["load_files"]) ) $opts["load_files"] = false; + if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index"; + if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false; + if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none"; + if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false; + + ///////////////// + // build request + ///////////////// + + // v.1.2 req + $flags = 1; // remove spaces + if ( $opts["exact_phrase"] ) $flags |= 2; + if ( $opts["single_passage"] ) $flags |= 4; + if ( $opts["use_boundaries"] ) $flags |= 8; + if ( $opts["weight_order"] ) $flags |= 16; + if ( $opts["query_mode"] ) $flags |= 32; + if ( $opts["force_all_words"] ) $flags |= 64; + if ( $opts["load_files"] ) $flags |= 128; + if ( $opts["allow_empty"] ) $flags |= 256; + if ( $opts["emit_zones"] ) $flags |= 512; + $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", strlen($words) ) . $words; // req words + + // options + $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"]; + $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"]; + $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"]; + $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] ); + $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2 + $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"]; + $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"]; + + // documents + $req .= pack ( "N", count($docs) ); + foreach ( $docs as $doc ) + { + assert ( is_string($doc) ); + $req .= pack ( "N", strlen($doc) ) . $doc; + } + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + for ( $i=0; $i $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + $res[] = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + } + + $this->_MBPop (); + return $res; + } + + + ///////////////////////////////////////////////////////////////////////////// + // keyword generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate keyword list for a given query + /// returns false on failure, + /// an array of words on success + function BuildKeywords ( $query, $index, $hits ) + { + assert ( is_string($query) ); + assert ( is_string($index) ); + assert ( is_bool($hits) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // build request + ///////////////// + + // v.1.0 req + $req = pack ( "N", strlen($query) ) . $query; // req query + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", (int)$hits ); + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) ); + $pos += 4; + for ( $i=0; $i<$nwords; $i++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $tokenized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $normalized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized ); + + if ( $hits ) + { + list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) ); + $pos += 8; + $res [$i]["docs"] = $ndocs; + $res [$i]["hits"] = $nhits; + } + + if ( $pos > $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + } + + $this->_MBPop (); + return $res; + } + + function EscapeString ( $string ) + { + $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' ); + $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' ); + + return str_replace ( $from, $to, $string ); + } + + ///////////////////////////////////////////////////////////////////////////// + // attribute updates + ///////////////////////////////////////////////////////////////////////////// + + /// batch update given attributes in given rows in given indexes + /// returns amount of updated documents (0 or more) on success, or -1 on failure + function UpdateAttributes ( $index, $attrs, $values, $mva=false ) + { + // verify everything + assert ( is_string($index) ); + assert ( is_bool($mva) ); + + assert ( is_array($attrs) ); + foreach ( $attrs as $attr ) + assert ( is_string($attr) ); + + assert ( is_array($values) ); + foreach ( $values as $id=>$entry ) + { + assert ( is_numeric($id) ); + assert ( is_array($entry) ); + assert ( count($entry)==count($attrs) ); + foreach ( $entry as $v ) + { + if ( $mva ) + { + assert ( is_array($v) ); + foreach ( $v as $vv ) + assert ( is_int($vv) ); + } else + assert ( is_int($v) ); + } + } + + // build request + $this->_MBPush (); + $req = pack ( "N", strlen($index) ) . $index; + + $req .= pack ( "N", count($attrs) ); + foreach ( $attrs as $attr ) + { + $req .= pack ( "N", strlen($attr) ) . $attr; + $req .= pack ( "N", $mva ? 1 : 0 ); + } + + $req .= pack ( "N", count($values) ); + foreach ( $values as $id=>$entry ) + { + $req .= sphPackU64 ( $id ); + foreach ( $entry as $v ) + { + $req .= pack ( "N", $mva ? count($v) : $v ); + if ( $mva ) + foreach ( $v as $vv ) + $req .= pack ( "N", $vv ); + } + } + + // connect, send query, get response + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return -1; + } + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header + if ( !$this->_Send ( $fp, $req, $len+8 ) ) + { + $this->_MBPop (); + return -1; + } + + if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) )) + { + $this->_MBPop (); + return -1; + } + + // parse response + list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_MBPop (); + return $updated; + } + + ///////////////////////////////////////////////////////////////////////////// + // persistent connections + ///////////////////////////////////////////////////////////////////////////// + + function Open() + { + if ( $this->_socket !== false ) + { + $this->_error = 'already connected'; + return false; + } + if ( !$fp = $this->_Connect() ) + return false; + + // command, command version = 0, body length = 4, body = 1 + $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 ); + if ( !$this->_Send ( $fp, $req, 12 ) ) + return false; + + $this->_socket = $fp; + return true; + } + + function Close() + { + if ( $this->_socket === false ) + { + $this->_error = 'not connected'; + return false; + } + + fclose ( $this->_socket ); + $this->_socket = false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////// + // status + ////////////////////////////////////////////////////////////////////////// + + function Status () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1 + if ( !( $this->_Send ( $fp, $req, 12 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) ) + { + $this->_MBPop (); + return false; + } + + $res = substr ( $response, 4 ); // just ignore length, error handling, etc + $p = 0; + list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + + $res = array(); + for ( $i=0; $i<$rows; $i++ ) + for ( $j=0; $j<$cols; $j++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $res[$i][] = substr ( $response, $p, $len ); $p += $len; + } + + $this->_MBPop (); + return $res; + } + + ////////////////////////////////////////////////////////////////////////// + // flush + ////////////////////////////////////////////////////////////////////////// + + function FlushAttributes () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return -1; + } + + $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0 + if ( !( $this->_Send ( $fp, $req, 8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) ) + { + $this->_MBPop (); + return -1; + } + + $tag = -1; + if ( strlen($response)==4 ) + list(,$tag) = unpack ( "N*", $response ); + else + $this->_error = "unexpected response length"; + + $this->_MBPop (); + return $tag; + } +} + +// +// $Id$ +// diff --git a/upload/includes/sql_parse.php b/upload/includes/sql_parse.php new file mode 100644 index 000000000..45e29ce20 --- /dev/null +++ b/upload/includes/sql_parse.php @@ -0,0 +1,192 @@ + 0)) + { + if ($lines[$i][0] != "#") + { + $output .= $lines[$i] . "\n"; + } + else + { + $output .= "\n"; + } + // Trading a bit of speed for lower mem. use here. + $lines[$i] = ""; + } + } + + return $output; + +} + +// +// split_sql_file will split an uploaded sql file into single sql statements. +// Note: expects trim() to have already been run on $sql. +// +function split_sql_file($sql, $delimiter) +{ + // Split up our string into "possible" SQL statements. + $tokens = explode($delimiter, $sql); + + // try to save mem. + $sql = ""; + $output = array(); + + // we don't actually care about the matches preg gives us. + $matches = array(); + + // this is faster than calling count($oktens) every time thru the loop. + $token_count = count($tokens); + for ($i = 0; $i < $token_count; $i++) + { + // Don't wanna add an empty string as the last thing in the array. + if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0))) + { + // This is the total number of single quotes in the token. + $total_quotes = preg_match_all("/'/", $tokens[$i], $matches); + // Counts single quotes that are preceded by an odd number of backslashes, + // which means they're escaped quotes. + $escaped_quotes = preg_match_all("/(?execute() scope!) + * "#" - constant, {#CON} is eq to CON + * + */ + +/** + * Original authors: Nathan Codding of the phpBB group, CyberAlien + * The interface was originally inspired by PHPLib templates + * IF, ELSEIF, ENDIF tags are backported from phpBB 2.2 + * Thanks to DMaJ007 for idea on how to include some extra tags. + */ + +if (!defined('BB_ROOT')) +{ + die(basename(__FILE__)); +} + +define('XS_SEPARATOR', '.'); +define('XS_USE_ISSET', '1'); + +// cache filenames prefix +define('XS_TPL_PREFIX', 'tpl_'); +define('XS_TPL_PREFIX2', 'tpl2_'); + +// internal xs mod definitions. do not edit. +define('XS_TAG_NONE', 0); +define('XS_TAG_PHP', 1); +define('XS_TAG_BEGIN', 2); +define('XS_TAG_END', 3); +define('XS_TAG_INCLUDE', 4); +define('XS_TAG_IF', 5); +define('XS_TAG_ELSE', 6); +define('XS_TAG_ELSEIF', 7); +define('XS_TAG_ENDIF', 8); +define('XS_TAG_BEGINELSE', 11); + + +class Template { + var $classname = "Template"; + + // variable that holds all the data we'll be substituting into + // the compiled templates. + // ... + // This will end up being a multi-dimensional array like this: + // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value + // if it's a root-level variable, it'll be like this: + // $this->vars[varname] == value or $this->_tpldata['.'][0][varname] == value + // array "vars" is added for easier access to data + var $_tpldata = array('.' => array(0 => array())); + var $vars; + + // Hash of filenames for each template handle. + var $files = array(); + var $files_cache = array(); // array of cache files that exists + var $files_cache2 = array(); // array of cache files (exists or not exists) + + // Root template directory. + var $root = ''; + + // Cache directory + var $cachedir = CACHE_DIR; + + // Template root directory (generated by set_rootdir) + var $tpldir = ''; + + // Default template directory. + // If file for default template isn't found file from this template is used. + var $tpldef = 'default'; + + // this will hash handle names to the compiled code for that handle. + var $compiled_code = array(); + + // This will hold the uncompiled code for that handle. + var $uncompiled_code = array(); + + // Cache settings + var $use_cache = 1; + var $cache_writable = 1; + + // Auto-compile setting + var $auto_compile = 1; + + // Current template name + var $tpl = ''; + var $cur_tpl = ''; + + // List of replacements. tpl files in this list will be replaced with other tpl files + // according to configuration in xs.cfg + var $replace = array(); + + // counter for include + var $include_count = 0; + + // php extension. will be replaced by $this->php in Template() function unless you disable it there + var $php = 'php'; + + // eXtreme Styles variables + var $xs_started = 0; + var $xs_version = 8; // number version. internal. do not change. + var $xs_versiontxt = '2.3.1'; // text version + + // These handles will be parsed if pparse() is executed. + // Can be used to automatically include header/footer if there is any content. + var $preparse = ''; + var $postparse = ''; + + // subtemplates mod detection + var $subtemplates = false; + + // style configuration + var $style_config = array(); + + var $lang = array(); + + /** + * Constructor. Installs XS mod on first run or updates it and sets the root dir. + */ + function Template($root = '.') + { + // setting pointer "vars" + $this->vars = &$this->_tpldata['.'][0]; + // load configuration + $this->load_config($root, true); + $this->lang =& $GLOBALS['lang']; + } + + /** + * Load mod configuration + */ + function load_config($root, $edit_db) + { + global $bb_cfg; + + $this->cached_tpl_ext = $bb_cfg['xs_php']; + $this->use_cache = $bb_cfg['xs_use_cache']; + $this->auto_compile = $bb_cfg['xs_auto_compile']; + $this->set_rootdir($root); + } + + /** + * Sets the template root directory for this Template object. + */ + function set_rootdir($dir) + { + // creating absolute path for cache + // creating absolute path for current template and root dir + $this->tpldir = TEMPLATES_DIR; + $this->root = $dir; + $this->tpl = $this->template_name($dir); + } + + /** + * Destroys this template object. Should be called when you're done with it, in order + * to clear out the template data so you can load/parse a new template set. + */ + function destroy() + { + $this->_tpldata = array('.' => array(0 => array())); + $this->vars = &$this->_tpldata['.'][0]; + $this->xs_started = 0; + } + + /** + * Extracts template name from path + */ + function template_name($dir) + { + return basename($dir); + } + + /** + * Generates a full path+filename for the given filename, which can either + * be an absolute name, or a name relative to the rootdir for this Template + * object. + */ + function make_filename($filename, $xs_include = false) + { + // Check replacements list + if(!$xs_include && isset($this->replace[$filename])) + { + $filename = $this->replace[$filename]; + } + // Check if it's an absolute or relative path. + if ((substr($filename, 0, 1) !== '/') && (substr($filename, 1, 1) !== ':')) + { + return $this->root . '/' . $filename; + } + else + { + return $filename; + } + } + + /** + * Converts template filename to cache filename. + * Returns empty string if non-cachable (for tpl files outside of root dir). + * $filename should be absolute filename + */ + function make_filename_cache ($filename) + { + $filename = clean_filename(str_replace(TEMPLATES_DIR, '', $filename)); + + return $this->cachedir . XS_TPL_PREFIX . $filename .'.'. $this->cached_tpl_ext; + } + + /** + * Sets the template filenames for handles. $filename_array + * should be a hash of handle => filename pairs. + */ + function set_filenames ($filenames) + { + foreach ($filenames as $handle => $filename) + { + $this->set_filename($handle, $filename); + } + } + + /** + * Assigns template filename for handle. + */ + function set_filename($handle, $filename, $xs_include = false, $quiet = false) + { + global $bb_cfg; + + $can_cache = $this->use_cache; + $this->files[$handle] = $this->make_filename($filename, $xs_include); + $this->files_cache[$handle] = ''; + $this->files_cache2[$handle] = ''; + // check if we are in admin control panel and override extreme styles mod controls if needed + if(defined('XS_ADMIN_OVERRIDE') && XS_ADMIN_OVERRIDE === true && @function_exists('xs_admin_override')) + { + xs_admin_override(); + } + // checking if we have valid filename + if(!$this->files[$handle]) + { + if($xs_include || $quiet) + { + return false; + } + else + { + die("Template->make_filename(): Error - invalid template $filename"); + } + } + // creating cache filename + if($can_cache) + { + $this->files_cache2[$handle] = $this->make_filename_cache($this->files[$handle]); + if(@file_exists($this->files_cache2[$handle])) + { + $this->files_cache[$handle] = $this->files_cache2[$handle]; + } + } + // checking if tpl and/or php file exists + if(empty($this->files_cache[$handle]) && !@file_exists($this->files[$handle])) + { + if($quiet) + { + return false; + } + die('Template->make_filename(): Error - template file not found:

    ' . hide_bb_path($this->files[$handle])); + } + // checking if we should recompile cache + if(!empty($this->files_cache[$handle]) && !empty($bb_cfg['xs_auto_recompile'])) + { + $cache_time = @filemtime($this->files_cache[$handle]); + if(@filemtime($this->files[$handle]) > $cache_time || $bb_cfg['xs_template_time'] > $cache_time) + { + // file was changed. don't use cache file (will be recompled if configuration allowes it) + $this->files_cache[$handle] = ''; + } + } + return true; + } + + /** + * includes file or executes code + */ + function execute($filename, $code, $handle) + { + $this->cur_tpl = $filename; + + global $lang, $bb_cfg; + + $L =& $lang; + $V =& $this->vars; + + if ($bb_cfg['xs_add_comments'] && $handle) + { + echo ''; + } + if ($filename) + { + include($filename); + } + else + { + eval($code); + } + if ($bb_cfg['xs_add_comments'] && $handle) + { + echo ''; + } + } + + /** + * Load the file for the handle, compile the file, + * and run the compiled code. This will print out + * the results of executing the template. + */ + function pparse($handle) + { + global $bb_cfg; + // parsing header if there is one + if($this->preparse || $this->postparse) + { + $preparse = $this->preparse; + $postparse = $this->postparse; + $this->preparse = ''; + $this->postparse = ''; + if($preparse) + { + $this->pparse($preparse); + } + if($postparse) + { + $str = $handle; + $handle = $postparse; + $this->pparse($str); + } + } + // checking if handle exists + if (empty($this->files[$handle]) && empty($this->files_cache[$handle])) + { + die("Template->loadfile(): No files found for handle $handle"); + } + $this->xs_startup(); + $force_recompile = empty($this->uncompiled_code[$handle]) ? false : true; + // checking if php file exists. + if (!empty($this->files_cache[$handle]) && !$force_recompile) + { + // php file exists - running it instead of tpl + $this->execute($this->files_cache[$handle], '', $handle); + return true; + } + if (!$this->loadfile($handle)) + { + die("Template->pparse(): Couldn't load template file for handle $handle"); + } + // actually compile the template now. + if (empty($this->compiled_code[$handle])) + { + // Actually compile the code now. + if(!empty($this->files_cache2[$handle]) && empty($this->files_cache[$handle]) && !$force_recompile) + { + $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]); + } + else + { + $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], '', ''); + } + } + // Run the compiled code. + if (empty($this->files_cache[$handle]) || $force_recompile) + { + $this->execute('', $this->compiled_code[$handle], $handle); + } + else + { + $this->execute($this->files_cache[$handle], '', $handle); + } + return true; + } + + /** + * Precompile file + */ + function precompile($template, $filename) + { + global $precompile_num, $bb_cfg; + if(empty($precompile_num)) + { + $precompile_num = 0; + } + $precompile_num ++; + $handle = 'precompile_' . $precompile_num; + // save old configuration + $root = $this->root; + $tpl_name = $this->tpl; + $old_config = $this->use_cache; + $old_autosave = $this->auto_compile; + // set temporary configuration + $this->root = $this->tpldir . $template; + $this->tpl = $template; + $this->use_cache = 1; + $this->auto_compile = 1; + // set filename + $res = $this->set_filename($handle, $filename, true, true); + if(!$res || !$this->files_cache2[$handle]) + { + $this->root = $root; + $this->tpl = $tpl_name; + $this->use_cache = $old_config; + $this->auto_compile = $old_autosave; + return false; + } + $this->files_cache[$handle] = ''; + // load template + $res = $this->loadfile($handle); + if(!$res || empty($this->uncompiled_code[$handle])) + { + $this->root = $root; + $this->tpl = $tpl_name; + $this->use_cache = $old_config; + $this->auto_compile = $old_autosave; + return false; + } + // compile the code + $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]); + // restore confirugation + $this->root = $root; + $this->tpl = $tpl_name; + $this->use_cache = $old_config; + $this->auto_compile = $old_autosave; + return true; + } + + /** + * Inserts the uncompiled code for $handle as the + * value of $varname in the root-level. This can be used + * to effectively include a template in the middle of another + * template. + * Note that all desired assignments to the variables in $handle should be done + * BEFORE calling this function. + */ + function assign_var_from_handle($varname, $handle) + { + ob_start(); + $res = $this->pparse($handle); + $this->vars[$varname] = ob_get_contents(); + ob_end_clean(); + return $res; + } + + /** + * Block-level variable assignment. Adds a new block iteration with the given + * variable assignments. Note that this should only be called once per block + * iteration. + */ + function assign_block_vars($blockname, $vararray) + { + if (strstr($blockname, '.')) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $str = &$this->_tpldata; + for($i = 0; $i < $blockcount; $i++) + { + $str = &$str[$blocks[$i].'.']; + $str = &$str[sizeof($str)-1]; + } + // Now we add the block that we're actually assigning to. + // We're adding a new iteration to this block with the given + // variable assignments. + $str[$blocks[$blockcount].'.'][] = $vararray; + } + else + { + // Top-level block. + // Add a new iteration to this block with the variable assignments + // we were given. + $this->_tpldata[$blockname.'.'][] = $vararray; + } + + return true; + } + + /** + * Root-level variable assignment. Adds to current assignments, overriding + * any existing variable assignment with the same name. + */ + function assign_vars ($vararray) + { + foreach ($vararray as $key => $val) + { + $this->vars[$key] = $val; + } + } + + /** + * Root-level variable assignment. Adds to current assignments, overriding + * any existing variable assignment with the same name. + */ + function assign_var ($varname, $varval = true) + { + $this->vars[$varname] = $varval; + } + + /** + * TODO: Add type check [??] + * Root-level. Adds to current assignments, appends + * to any existing variable assignment with the same name. + */ + function append_vars ($vararray) + { + foreach ($vararray as $key => $val) + { + $this->vars[$key] = !isset($this->vars[$key]) ? $val : $this->vars[$key] . $val; + } + } + + /** + * If not already done, load the file for the given handle and populate + * the uncompiled_code[] hash with its code. Do not compile. + */ + function loadfile($handle) + { + global $bb_cfg; + // If cached file exists do nothing - it will be included via include() + if(!empty($this->files_cache[$handle])) + { + return true; + } + + // If the file for this handle is already loaded and compiled, do nothing. + if (!empty($this->uncompiled_code[$handle])) + { + return true; + } + + // If we don't have a file assigned to this handle, die. + if (empty($this->files[$handle])) + { + die("Template->loadfile(): No file specified for handle $handle"); + } + + $filename = $this->files[$handle]; + + if (($str = @file_get_contents($filename)) === false) + { + die("Template->loadfile(): File $filename for handle $handle is empty"); + } + + $this->uncompiled_code[$handle] = $str; + + return true; + } + + + + /** + * Generates a reference to the given variable inside the given (possibly nested) + * block namespace. This is a string of the form: + * ' . $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['varname'] . ' + * It's ready to be inserted into an "echo" line in one of the templates. + * NOTE: expects a trailing "." on the namespace. + */ + function generate_block_varref($namespace, $varname) + { + // Strip the trailing period. + $namespace = substr($namespace, 0, strlen($namespace) - 1); + + // Get a reference to the data block for this namespace. + $varref = $this->generate_block_data_ref($namespace, true); + // Prepend the necessary code to stick this in an echo line. + + // Append the variable reference. + $varref .= "['$varname']"; + + $varref = ""; + + return $varref; + } + + + /** + * Generates a reference to the array of data values for the given + * (possibly nested) block namespace. This is a string of the form: + * $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['$childN.'] + * + * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. + * NOTE: does not expect a trailing "." on the blockname. + */ + function generate_block_data_ref($blockname, $include_last_iterator) + { + // Get an array of the blocks involved. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + if($include_last_iterator) + { + return '$'. $blocks[$blockcount]. '_item'; + } + else + { + return '$'. $blocks[$blockcount-1]. '_item[\''. $blocks[$blockcount]. '.\']'; + } + } + + function compile_code($filename, $code) + { + // $filename - file to load code from. used if $code is empty + // $code - tpl code + + // load code from file + if (!$code && !empty($filename)) + { + $code = file_get_contents($filename); + } + + // Replace phpBB 2.2 tags + $search = array('', ''); + $replace = array('<'.'?php ', ' ?'.'>'); + $code = str_replace($search, $replace, $code); + + // Break it up into lines and put " -->" back. + $code_lines = explode(' -->', $code); + $count = count($code_lines); + for ($i = 0; $i < ($count - 1); $i++) + { + $code_lines[$i] .= ' -->'; + } + + $block_nesting_level = 0; + $block_names = array(); + $block_names[0] = "."; + $block_items = array(); + $count_if = 0; + + // prepare array for compiled code + $compiled = array(); + + // array of switches + $sw = array(); + + // replace all short php tags + $new_code = array(); + $line_count = count($code_lines); + for($i=0; $i<$line_count; $i++) + { + $line = $code_lines[$i]; + $pos = strpos($line, ''; + $code_lines[$i] = substr($line, $pos + 2); + $i --; + } + $code_lines = $new_code; + + // main loop + $line_count = count($code_lines); + for($i=0; $i<$line_count; $i++) + { + $line = $code_lines[$i]; + // reset keyword type + $keyword_type = XS_TAG_NONE; + // check if we have valid keyword in current line + $pos1 = strpos($line, '', $pos1); + if($pos2 !== false) + { + // find end of keyword in comment + $pos3 = strpos($line, ' ', $pos1 + 5); + if($pos3 !== false && $pos3 <= $pos2) + { + $keyword = substr($line, $pos1 + 5, $pos3 - $pos1 - 5); + // check keyword against list of supported keywords. case-sensitive + if($keyword === 'BEGIN') + { + $keyword_type = XS_TAG_BEGIN; + } + elseif($keyword === 'END') + { + $keyword_type = XS_TAG_END; + } + elseif($keyword === 'INCLUDE') + { + $keyword_type = XS_TAG_INCLUDE; + } + elseif($keyword === 'IF') + { + $keyword_type = XS_TAG_IF; + } + elseif($keyword === 'ELSE') + { + $keyword_type = XS_TAG_ELSE; + } + elseif($keyword === 'ELSEIF') + { + $keyword_type = XS_TAG_ELSEIF; + } + elseif($keyword === 'ENDIF') + { + $keyword_type = XS_TAG_ENDIF; + } + elseif($keyword === 'BEGINELSE') + { + $keyword_type = XS_TAG_BEGINELSE; + } + } + } + if(!$keyword_type) + { + // not valid keyword. process the rest of line + $compiled[] = $this->_compile_text(substr($line, 0, $pos1 + 4)); + $code_lines[$i] = substr($line, $pos1 + 4); + $i --; + continue; + } + // remove code before keyword + if($pos1 > 0) + { + $compiled[] = $this->_compile_text(substr($line, 0, $pos1)); + } + // remove keyword + $keyword_str = substr($line, $pos1, $pos2 - $pos1 + 4); + $params_str = $pos2 == $pos3 ? '' : substr($line, $pos3 + 1, $pos2 - $pos3 - 1); + $code_lines[$i] = substr($line, $pos2 + 4); + $i--; + // Check keywords + + /* + * + */ + if($keyword_type == XS_TAG_BEGIN) + { + $params = explode(' ', $params_str); + $num_params = count($params); + // get variable name + if($num_params == 1) + { + $var = $params[0]; + } + elseif($num_params == 2) + { + if($params[0] === '') + { + $var = $params[1]; + } + elseif($params[1] === '') + { + $var = $params[0]; + } + else + { + // invalid tag + $compiled[] = $keyword_str; + continue; + } + } + else + { + // invalid tag + $compiled[] = $keyword_str; + continue; + } + // adding code + $block_nesting_level++; + $block_names[$block_nesting_level] = $var; + if(isset($block_items[$var])) + { + $block_items[$var] ++; + } + else + { + $block_items[$var] = 1; + } + if ($block_nesting_level < 2) + { + // Block is not nested. + $line = '<'."?php\n\n"; + $line .= '$'. $var. '_count = ( isset($this->_tpldata[\''. $var. '.\']) ) ? sizeof($this->_tpldata[\''. $var. '.\']) : 0;'; + $line .= "\n" . 'for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)'; + $line .= "\n". '{'. "\n"; + $line .= ' $'. $var. '_item = &$this->_tpldata[\''. $var. '.\'][$'. $var. '_i];'."\n"; + $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;\n"; + $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;\n"; + $line .= "\n?".">"; + } + else + { + // This block is nested. + // Generate a namespace string for this block. + $namespace = join('.', $block_names); + // strip leading period from root level.. + $namespace = substr($namespace, 2); + // Get a reference to the data array for this block that depends on the + // current indices of all parent blocks. + $varref = $this->generate_block_data_ref($namespace, false); + // Create the for loop code to iterate over this block. + $line = '<'."?php\n\n"; + $line .= '$'. $var. '_count = ( isset('. $varref. ') ) ? sizeof('. $varref. ') : 0;'; + $line .= "\n". 'for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)'; + $line .= "\n". '{'. "\n"; + $line .= ' $'. $var. '_item = &'. $varref. '[$'. $var. '_i];'."\n"; + $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;\n"; + $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;\n"; + $line .= "\n?".">"; + } + $compiled[] = $line; + continue; + } + /* + * + */ + if($keyword_type == XS_TAG_END) + { + $params = explode(' ', $params_str); + $num_params = count($params); + if($num_params == 1) + { + $var = $params[0]; + } + elseif($num_params == 2 && $params[0] === '') + { + $var = $params[1]; + } + elseif($num_params == 2 && $params[1] === '') + { + $var = $params[0]; + } + else + { + $compiled[] = $keyword_str; + continue; + } + // We have the end of a block. + $line = '<'."?php\n\n"; + $line .= '} // END ' . $var . "\n\n"; + $line .= 'if(isset($' . $var . '_item)) { unset($' . $var . '_item); } '; + $line .= "\n\n?".">"; + if(isset($block_items[$var])) + { + $block_items[$var] --; + } + else + { + $block_items[$var] = -1; + } + unset($block_names[$block_nesting_level]); + $block_nesting_level--; + $compiled[] = $line; + continue; + } + /* + * + */ + if($keyword_type == XS_TAG_BEGINELSE) + { + if($block_nesting_level) + { + $var = $block_names[$block_nesting_level]; + $compiled[] = '<' . '?php } if(!$' . $var . '_count) { ?' . '>'; + } + else + { + $compiled[] = $keyword_str; + continue; + } + } + /* + * + */ + if($keyword_type == XS_TAG_INCLUDE) + { + $params = explode(' ', $params_str); + $num_params = count($params); + if($num_params != 1) + { + $compiled[] = $keyword_str; + continue; + } + $line = '<'.'?php '; + $filehash = md5($params_str . $this->include_count . time()); + $line .= ' $this->set_filename(\'xs_include_' . $filehash . '\', \'' . $params_str .'\', true); '; + $line .= ' $this->pparse(\'xs_include_' . $filehash . '\'); '; + $line .= ' ?'.'>'; + $this->include_count ++; + $compiled[] = $line; + continue; + } + /* + * + */ + if($keyword_type == XS_TAG_IF || $keyword_type == XS_TAG_ELSEIF) + { + if(!$count_if) + { + $keyword_type = XS_TAG_IF; + } + $str = $this->compile_tag_if($params_str, $keyword_type == XS_TAG_IF ? false : true); + if($str) + { + $compiled[] = ''; + if($keyword_type == XS_TAG_IF) + { + $count_if ++; + } + } + else + { + $compiled[] = $keyword_str; + } + continue; + } + /* + * + */ + if($keyword_type == XS_TAG_ELSE && $count_if > 0) + { + $compiled[] = ''; + continue; + } + /* + * + */ + if($keyword_type == XS_TAG_ENDIF && $count_if > 0) + { + $compiled[] = ''; + $count_if --; + continue; + } + } + + // bring it back into a single string. + $code_header = ''; + $code_footer = ''; + + return $code_header . join('', $compiled) . $code_footer; + } + + /* + * Compile code between tags + */ + function _compile_text($code) + { + if(strlen($code) < 3) + { + return $code; + } + // change template varrefs into PHP varrefs + // This one will handle varrefs WITH namespaces + $varrefs = array(); + preg_match_all('#\{(([a-z0-9\-_]+?\.)+)([a-z0-9\-_]+?)\}#is', $code, $varrefs); + $varcount = sizeof($varrefs[1]); + $search = array(); + $replace = array(); + for ($i = 0; $i < $varcount; $i++) + { + $namespace = $varrefs[1][$i]; + $varname = $varrefs[3][$i]; + $new = $this->generate_block_varref($namespace, $varname); + $search[] = $varrefs[0][$i]; + $replace[] = $new; + } + if(count($search) > 0) + { + $code = str_replace($search, $replace, $code); + } + // This will handle the remaining root-level varrefs +# $code = preg_replace('#\{(L_([a-z0-9\-_]+?))\}#i', '<'.'?php if (isset($L[\'$2\'])) { echo $L[\'$2\']; } else { echo ($V[\'$1\']) ? $V[\'$1\'] : $this->lang_error(\'$2\'); } ?'.'>', $code); + $code = preg_replace('#\{(L_([a-z0-9\-_]+?))\}#i', '', $code); + $code = preg_replace('#\{(\$[a-z_][a-z0-9_$\->\'\"\.\[\]]*?)\}#i', '', $code); + $code = preg_replace('#\{(\#([a-z_][a-z0-9_]*?))\}#i', '', $code); + $code = preg_replace('#\{([a-z0-9\-_]+?)\}#i', '', $code); + return $code; + } + + // + // Compile IF tags - much of this is from Smarty with + // some adaptions for our block level methods + // + function compile_tag_if($tag_args, $elseif) + { + /* Tokenize args for 'if' tag. */ + preg_match_all('/(?: + "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | + \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | + [(),] | + [^\s(),]+)/x', $tag_args, $match); + + $tokens = $match[0]; + $tokens_cnt = count($tokens); + $is_arg_stack = array(); + + for ($i = 0; $i < $tokens_cnt; $i++) + { + $token = &$tokens[$i]; + + switch ($token) + { + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; + $is_arg = join(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + $i = $is_arg_start; + + default: + $pattern = '@^ + ( # 1 + ([a-z0-9\-_]+?\.)+? # 2 block tpl vars (VAR1.VAR2.) but without last + )? + ( # 3 + ([a-z_][a-z0-9\-_]*)? # 4 single tpl var or last block var (last in block) + (\$[a-z_][a-z0-9_$\->\'\"\.\[\]]*)? # 5 php var + (\#([a-z_][a-z0-9_]*))? # 7 php const + ) + $@ix'; + if (preg_match($pattern, $token, $m)) + { + if (!empty($m[1])) + { + $token = $this->generate_block_data_ref(substr($m[1], 0, -1), true) . "['{$m[4]}']"; + } + else if (!empty($m[4])) + { + $token = ($tokens_cnt == 1) ? "!empty(\$V['{$m[4]}'])" : "\$V['{$m[4]}']"; + } + else if (!empty($m[5])) + { + $token = ($tokens_cnt == 1) ? "!empty({$m[5]})" : "{$m[5]}"; + } + else if (!empty($m[7])) + { + $token = ($tokens_cnt == 1) ? "defined('{$m[7]}') && {$m[7]}" : "{$m[7]}"; + } + } + break; + } + } + + if ($elseif) + { + $code = '} elseif ('. join(' ', $tokens) .') {'; + } + else + { + $code = 'if ('. join(' ', $tokens) .') {'; + } + + return $code; + } + + // This is from Smarty + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') + { + $negate_expr = true; + $expr_type = array_shift($tokens); + } + else + { + $expr_type = $first_token; + } + + switch ($expr_type) + { + case 'even': + if (@$tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(($is_arg / $expr_arg) % $expr_arg)"; + } + else + { + $expr = "!($is_arg % 2)"; + } + break; + + case 'odd': + if (@$tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(($is_arg / $expr_arg) % $expr_arg)"; + } + else + { + $expr = "($is_arg % 2)"; + } + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % $expr_arg)"; + } + break; + + default: + break; + } + + if ($negate_expr) + { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Compiles code and writes to cache if needed + */ + function compile2($code, $handle, $cache_file) + { + $code = $this->compile_code('', $code, XS_USE_ISSET); + if($cache_file && !empty($this->use_cache) && !empty($this->auto_compile)) + { + $res = $this->write_cache($cache_file, $code); + if($handle && $res) + { + $this->files_cache[$handle] = $cache_file; + } + } + $code = '?'.'>'.$code.'<'."?php\n"; + return $code; + } + + /** + * Compiles the given string of code, and returns + * the result in a string. + * If "do_not_echo" is true, the returned code will not be directly + * executable, but can be used as part of a variable assignment + * for use in assign_code_from_handle(). + * This function isn't used and kept only for compatibility with original template.php + */ + function compile($code, $do_not_echo = false, $retvar = '') + { + $code = ' ?'.'>' . $this->compile_code('', $code, true) . '<'."?php \n"; + if($do_not_echo) + { + $code = "ob_start();\n". $code. "\n\${$retvar} = ob_get_contents();\nob_end_clean();\n"; + } + return $code; + } + + /** + * Write cache to disk + */ + function write_cache($filename, $code) + { + file_write($code, $filename, false, true, true); + } + + function xs_startup() + { + global $bb_cfg; + if(empty($this->xs_started)) + { // adding predefined variables + $this->xs_started = 1; + // file extension with session ID (eg: "php?sid=123&" or "php?") + // can be used to make custom URLs without modding phpbb + // contains "&" or "?" at the end so you can easily append paramenters + $php = append_sid('php'); + if(strpos($php, '?')) + { + $php .= '&'; + } + else + { + $php .= '?'; + } + $this->vars['PHP'] = isset($this->vars['PHP']) ? $this->vars['PHP'] : $php; + // adding language variable (eg: "english" or "german") + // can be used to make truly multi-lingual templates + $this->vars['LANG'] = isset($this->vars['LANG']) ? $this->vars['LANG'] : $bb_cfg['default_lang']; + // adding current template + $tpl = $this->root . '/'; // BB_ROOT . 'templates/' . $this->tpl . '/'; + if(substr($tpl, 0, 2) === './') + { + $tpl = substr($tpl, 2, strlen($tpl)); + } + $this->vars['TEMPLATE'] = isset($this->vars['TEMPLATE']) ? $this->vars['TEMPLATE'] : $tpl; + $this->vars['TEMPLATE_NAME'] = isset($this->vars['TEMPLATE_NAME']) ? $this->vars['TEMPLATE_NAME'] : $this->tpl; + $this->_tpldata['switch_xs_enabled.'] = array(array('version' => $this->xs_versiontxt)); + } + } + + function lang_error($var) + { + trigger_error(basename($this->cur_tpl) ." : undefined language variable {L_{$var}}", E_USER_WARNING); + return "Undefined: {L_{$var}}"; + } + + // + // + // Functions added for USERGROUP MOD (optimized) + // + // + function append_var_from_handle_to_block($blockname, $varname, $handle) + { + $this->assign_var_from_handle('_tmp', $handle); + // assign the value of the generated variable to the given varname. + $this->append_block_vars($blockname, array($varname => $this->vars['_tmp'])); + return true; + } + + function append_block_vars($blockname, $vararray) + { + if(strstr($blockname, '.')) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + $str = &$this->_tpldata; + for($i = 0; $i < $blockcount; $i++) + { + $str = &$str[$blocks[$i].'.']; + $str = &$str[sizeof($str)-1]; + } + // Now we add the block that we're actually assigning to. + // We're adding a new iteration to this block with the given + // variable assignments. + $str = &$str[$blocks[$blockcount].'.']; + $count = sizeof($str) - 1; + if($count >= 0) + { + // adding only if there is at least one item + $str[$count] = array_merge($str[$count], $vararray); + } + } + else + { + // Top-level block. + // Add a new iteration to this block with the variable assignments + // we were given. + $str = &$this->_tpldata[$blockname.'.']; + $count = sizeof($str) - 1; + if($count >= 0) + { + // adding only if there is at least one item + $str[$count] = array_merge($str[$count], $vararray); + } + } + return true; + } + + /* + * Flush a root level block, so it becomes empty. + */ + function flush_block_vars($blockname) + { + // Top-level block. + // flush a existing block we were given. + $current_iteration = sizeof($this->_tpldata[$blockname . '.']) - 1; + unset($this->_tpldata[$blockname . '.']); + return true; + } +} + +function xs_switch($tpl, $name) +{ + return (isset($tpl->_tpldata[$name.'.']) && count($tpl->_tpldata[$name.'.']) > 0); +} \ No newline at end of file diff --git a/upload/includes/topic_templates.php b/upload/includes/topic_templates.php new file mode 100644 index 000000000..42660a5b0 --- /dev/null +++ b/upload/includes/topic_templates.php @@ -0,0 +1,129 @@ + $val) + { + if (is_array($item)) + { + $name = array_keys($item); + $item = $name[0]; + } + $message .= build_tpl_item($item, $val); + } + return $message; +} + +function tpl_func_screen_shots ($item, $val) +{ + if (!$val) return ''; + + $img = preg_replace('#(?<=\s)(http\S+?(jpg|gif|png))(?=\s)#i', '[img]$1[/img]', " $val "); + + return '[spoiler="'. $GLOBALS['lang']['TPL'][strtoupper($item)] .'"]' . trim($img) ."\n" ."[/spoiler]"; +} + +// get tpl data +$sql = "SELECT * + FROM ". BB_TOPIC_TPL ." + WHERE tpl_id = ". (int) $post_info['topic_tpl_id']; + +if ($topic_tpl = DB()->fetch_row($sql)) +{ + $message = $subject = ''; + $tpl_script = basename($topic_tpl['tpl_script']); + + // this include() should return $message and $subject on submit + require(INC_DIR ."topic_templates/$tpl_script.php"); + + $lang['TPL']['GUIDE'] = array(); + @include(INC_DIR ."topic_templates/{$tpl_script}_guide.php"); + + if (isset($_REQUEST['preview'])) + { + $_POST['subject'] = $subject; + $_POST['message'] = $message; + } + else + { + require(INC_DIR .'topic_templates/tpl_selects.php'); + + $template->assign_vars(array( + 'PAGE_TITLE' => $lang['BT_NEW_RELEASE'], + 'FORUM_NAME' => htmlCHR($post_info['forum_name']), + 'S_ACTION' => append_sid("posting.php?mode=newtopic&tpl=1&". POST_FORUM_URL .'='. $post_info['forum_id']), + 'S_CANCEL_ACTION' => append_sid(FORUM_URL . $post_info['forum_id']), + 'TORRENT_EXT' => TORRENT_EXT, + 'TORRENT_EXT_LEN' => strlen(TORRENT_EXT) + 1, + 'U_VIEW_FORUM' => append_sid(FORUM_URL . $post_info['forum_id']), + + 'REGULAR_TOPIC_BUTTON' => true, # (IS_MOD || IS_ADMIN), + 'REGULAR_TOPIC_HREF' => append_sid("posting.php?mode=newtopic&". POST_FORUM_URL .'='. $post_info['forum_id']), + 'L_POST_REGULAR_TOPIC' => $lang['POST_REGULAR_TOPIC'], + + 'L_BACK' => $lang['BT_BACK'], + 'L_ERROR' => $lang['BT_BAD_FIELDS'], + 'L_NEXT' => $lang['BT_NEXT'], + 'L_RELEASE_WELCOME' => $lang['BT_FILL_FORM'], + 'L_TITLE' => $lang['TPL']['RELEASE_NAME'], + 'L_TITLE_DESC' => $lang['TPL']['RELEASE_NAME_DESC'], + 'L_ORIGINAL_TITLE' => $lang['TPL']['ORIGINAL_NAME'], + 'L_ORIGINAL_TITLE_DESC' => $lang['TPL']['ORIGINAL_NAME_DESC'], + 'L_TITLE_EXP' => $lang['TPL']['NAME_EXP'], + + 'TORRENT_SIGN' => $bb_cfg['torrent_sign'], + )); + + foreach ($lang['TPL'] as $name => $val) + { + $template->assign_vars(array( + 'L_'. strtoupper($name) => $val, + )); + } + foreach ($lang['TPL']['GUIDE'] as $name => $guide_post_id) + { + $template->assign_vars(array( + strtoupper($name) .'_HREF' => append_sid(POST_URL ."$guide_post_id&single=1#$guide_post_id"), + )); + } + + $tpl_file = basename($topic_tpl['tpl_template']) .'.tpl'; + + print_page("topic_templates/$tpl_file"); + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/.htaccess b/upload/includes/topic_templates/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/topic_templates/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/topic_templates/audiobooks.php b/upload/includes/topic_templates/audiobooks.php new file mode 100644 index 000000000..c05549ca1 --- /dev/null +++ b/upload/includes/topic_templates/audiobooks.php @@ -0,0 +1,66 @@ + "[img{$img_align}]%s[/img]", + 'release_name' => "[size=$title_font_size]%s[/size]\n\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = @$_POST['msg'][$item]; + } + array_deep($msg, 'trim'); + + if ($msg) + { + // Subject + $subject = $msg['release_name']; + + if ($msg['author']) + { + $subject = $msg['author'] .' - '. $subject; + } + + if ($msg['performer']) + { + $sbj_ext[] = $msg['performer']; + } + if ($msg['year']) + { + $sbj_ext[] = $msg['year']; + } + if ($sbj_ext) + { + $subject .= ' ['. join(', ', $sbj_ext) .']'; + } + + // Message + $message = tpl_build_message($msg); + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/books.php b/upload/includes/topic_templates/books.php new file mode 100644 index 000000000..7f4ed7863 --- /dev/null +++ b/upload/includes/topic_templates/books.php @@ -0,0 +1,67 @@ + "[img{$img_align}]%s[/img]\n\n", + 'release_name' => "[size=$title_font_size]%s[/size]\n\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = @$_POST['msg'][$item]; + } + array_deep($msg, 'trim'); + + if ($msg) + { + // Subject + $subject = $msg['release_name']; + + if ($msg['author']) + { + $subject = $msg['author'] .' - '. $subject; + } + + if ($msg['year']) + { + $sbj_ext[] = $msg['year']; + } + if ($msg['format']) + { + $sbj_ext[] = $msg['format']; + } + if ($sbj_ext) + { + $subject .= ' ['. join(', ', $sbj_ext) .']'; + } + + // Message + $message = tpl_build_message($msg); + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/games.php b/upload/includes/topic_templates/games.php new file mode 100644 index 000000000..819cffe35 --- /dev/null +++ b/upload/includes/topic_templates/games.php @@ -0,0 +1,64 @@ + "[img{$img_align}]%s[/img]\n\n", + 'release_name' => "[size=$title_font_size]%s[/size]\n\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = @$_POST['msg'][$item]; + } + array_deep($msg, 'trim'); + + if ($msg) + { + $message = tpl_build_message($msg); + $subject = $msg['release_name']; + $subject .= ($msg['year']) ? ' ('. trim($msg['year'], '/') .')' : ''; + $subject .= ($msg['publisher']) ? ' ('. trim($msg['publisher'], '/') .')' : ''; + $subject .= ($msg['localization']) ? ' ('. trim($msg['localization'], '/') .')' : ''; + $subject .= ($msg['source_type']) ? ' ['. trim($msg['source_type'], '/') .']' : ''; + + if ($msg['localization'] == 'Multi5') + { + $subject .= ' [multi5]'; + } + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/music.php b/upload/includes/topic_templates/music.php new file mode 100644 index 000000000..59409e994 --- /dev/null +++ b/upload/includes/topic_templates/music.php @@ -0,0 +1,51 @@ + "[img{$img_align}]%s[/img]\n\n", + 'release_name' => "[size=$title_font_size]%s[/size]\n\n", + 'tracklist' => "[b]{$lang['TPL']['TRACKLIST']}[/b]:\n%s\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = @$_POST['msg'][$item]; + } + array_deep($msg, 'trim'); + + if ($msg) + { + $message = tpl_build_message($msg); + + $genre = ($msg['genre']) ? '('. $msg['genre'] .') ' : ''; + $year = ($msg['year']) ? ' - '. $msg['year'] : ''; + $bitrate = ($msg['audio_bitrate']) ? ', '. $msg['audio_bitrate'] : ''; + $format = ($msg['format']) ? ', '. $msg['format'] . $bitrate .'' : ''; + + $subject = $genre . $msg['release_name'] . $year . $format; + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/progs.php b/upload/includes/topic_templates/progs.php new file mode 100644 index 000000000..4aaa3fceb --- /dev/null +++ b/upload/includes/topic_templates/progs.php @@ -0,0 +1,52 @@ + "[size=$title_font_size]%s[/size]\n\n", + 'picture' => "[img{$img_align}]%s[/img]\n\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = @$_POST['msg'][$item]; + } + array_deep($msg, 'trim'); + + if ($msg) + { + $message = tpl_build_message($msg); + $subject = $msg['release_name']; + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/sport.php b/upload/includes/topic_templates/sport.php new file mode 100644 index 000000000..5b6725154 --- /dev/null +++ b/upload/includes/topic_templates/sport.php @@ -0,0 +1,74 @@ + "[img{$img_align}]%s[/img]\n\n", + 'release_name' => "[size=$title_font_size]%s[/size]\n\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = @$_POST['msg'][$item]; + } + array_deep($msg, 'trim'); + + if ($msg) + { + // Subject + $subject = $msg['release_name']; + + if ($msg['year']) + { + $sbj_ext[] = sprintf($lang['TPL']['Y'], $msg['year']); + } + if ($msg['sport_type']) + { + $sbj_ext[] = $msg['sport_type']; + } + if ($msg['quality']) + { + $sbj_ext[] = $msg['quality']; + } + if ($sbj_ext) + { + $subject .= ' ['. join(', ', $sbj_ext) .']'; + } + + // Message + $message = tpl_build_message($msg); + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/tpl_selects.php b/upload/includes/topic_templates/tpl_selects.php new file mode 100644 index 000000000..104a4f835 --- /dev/null +++ b/upload/includes/topic_templates/tpl_selects.php @@ -0,0 +1,137 @@ + array( + 'DVDRip', + 'DVD5', + "DVD5 {$lang['TPL']['COMPRESSED']}", + 'DVD9', + 'HDTV', + 'HDTVRip', + 'TVRip', + 'TeleCine', + 'TeleSynch', + 'CamRip', + 'SATRip', + 'VHSRip', + 'DVDScreener', + ), + + 'SEL_VIDEO_CODECS' => array( + 'DivX', + 'XviD', + "{$lang['BT_OTHER']} MPEG4", + 'VPx', + 'MPEG1', + 'MPEG2', + 'Windows Media', + 'QuickTime', + 'H.26x', + 'Flash', + ), + + 'SEL_VIDEO_FORMATS' => array( + 'AVI', + 'DVD Video', + 'OGM', + 'MKV', + 'WMV', + 'MPEG', + ), + + 'SEL_AUDIO_CODECS' => array( + 'AC3', + 'ALAC (image + .cue)', + 'ALAC (tracks)', + 'APE (image + .cue)', + 'APE (tracks)', + 'DTS', + 'DVD-Audio', + 'FLAC (image + .cue)', + 'FLAC (tracks)', + 'M4A (image + .cue)', + 'M4A (tracks)', + 'MP3', + 'MPEG Audio', + 'OGG Vorbis', + 'SHN (image + .cue)', + 'SHN (tracks)', + 'TTA (image + .cue)', + 'TTA (tracks)', + 'WAVPack (image + .cue)', + 'WAVPack (tracks)', + 'Windows Media', + ), + + 'SEL_BITRATE' => array( + 'lossless', + '64 kbps', + '128 kbps', + '160 kbps', + '192 kbps', + '224 kbps', + '256 kbps', + '320 kbps', + 'VBR 128-192 kbps', + 'VBR 192-320 kbps', + ), + + 'SEL_TEXT_FORMATS' => array( + $lang['TPL']['SIMPLE_TEXT'], + 'PDF', + 'DjVu', + 'CHM', + 'HTML', + 'DOC', + ), + + 'SEL_TEXT_QUALITY' => array( + $lang['TPL']['SCANNED'], + $lang['TPL']['NATIVE'], + $lang['TPL']['OCR_W_O_ERRORS'], + $lang['TPL']['OCR_W_ERRORS'], + ), + + 'SEL_SOURCE_TYPE' => $lang['TPL']['SOURCE_TYPE_OPTIONS'], + + 'SEL_LOCALIZATION' => array( + $lang['TPL']['NOT_NEEDED'], + $lang['TPL']['INCLUDED'], + $lang['TPL']['NOT_INCLUDED'], + ), + + 'SEL_LANG' => $lang['TPL']['LANG_OPTIONS'], + + 'SEL_UI_LANG' => $lang['TPL']['UI_LANG_OPTIONS'], + + 'SEL_UI_LANG_PS' => $lang['TPL']['UI_LANG_OPTIONS_PS'], + + 'SEL_AUDIOBOOK_TYPE' => $lang['TPL']['AUDIOBOOK_TYPE_OPTIONS'], + + 'SEL_MEDICINE' => array( + $lang['TPL']['NOT_NEEDED'], + $lang['TPL']['INCLUDED'], + $lang['TPL']['NOT_INCLUDED'], + ), + + 'SEL_VISTA_COMPATIBLE' => $lang['TPL']['VISTA_COMPATIBLE_OPTIONS'], + + 'SEL_TRANSLATION' => $lang['TPL']['TRANSLATION_OPTIONS'], + + 'SEL_TRANSLATION_TYPE' => $lang['TPL']['TRANSLATION_TYPES'], + + 'SEL_PLATFORM_PS' => array('PS', 'PS2'), + + 'SEL_MULTIPLAYER' => $lang['TPL']['MULTIPLAYER_OPTIONS'], + + 'SEL_REGION' => array('PAL', 'NTSC'), +); + +foreach ($selects as $tpl_name => $sel_ary) +{ + $template->assign_vars(array( + $tpl_name => join("','", replace_quote($sel_ary)) + )); +} \ No newline at end of file diff --git a/upload/includes/topic_templates/video.php b/upload/includes/topic_templates/video.php new file mode 100644 index 000000000..117dc08a5 --- /dev/null +++ b/upload/includes/topic_templates/video.php @@ -0,0 +1,98 @@ + "[img{$img_align}]%s[/img]\n\n", + 'release_name' => "[size=$title_font_size]%s[/size]\n\n", + ); + + $message = $subject = ''; + $msg = $sbj_ext = array(); + + foreach ($tpl_items as $item) + { + $msg[$item] = !empty($_POST['msg'][$item]) ? $_POST['msg'][$item] : ''; + } + array_deep($msg, 'trim'); + + if ($msg) + { + if ($msg['original_name']) + { + $msg['release_name'] .= ' / '. trim($msg['original_name'], '/'); + unset($msg['original_name']); + } + + // Subject + $subject = $msg['release_name']; + $subject .= ($msg['director']) ? ' ('. trim($msg['director'], '/') .')' : ''; + + if ($msg['year']) + { + $sbj_ext[] = sprintf($lang['TPL']['Y'], $msg['year']); + } + if ($msg['genre']) + { + $sbj_ext[] = $msg['genre']; + } + if ($msg['quality']) + { + $sbj_ext[] = $msg['quality']; + } + if ($sbj_ext) + { + $subject .= ' ['. join(', ', $sbj_ext) .']'; + } + + // Message + $message = tpl_build_message($msg); + } +} \ No newline at end of file diff --git a/upload/includes/topic_templates/video_guide.php b/upload/includes/topic_templates/video_guide.php new file mode 100644 index 000000000..cba236540 --- /dev/null +++ b/upload/includes/topic_templates/video_guide.php @@ -0,0 +1,21 @@ + POST_ID (with guide) + 'title' => 330880, + 'picture' => 330951, + 'country' => 330955, + 'director' => 330959, + 'genre' => 330965, + 'playtime' => 330966, + 'year' => 330969, + 'translation' => 330970, + 'casting' => 330972, + 'description' => 330974, + 'moreinfo' => 330978, + 'format' => 330980, + 'video' => 330982, + 'audio' => 330984, + 'torrent' => 330985, +); +$lang['TPL']['GUIDE'] = array(); \ No newline at end of file diff --git a/upload/includes/torrent_announce_urls.php b/upload/includes/torrent_announce_urls.php new file mode 100644 index 000000000..89efdf5ac --- /dev/null +++ b/upload/includes/torrent_announce_urls.php @@ -0,0 +1,15 @@ +assign_vars(array('DL_BUTTONS' => false)); + +$count_mode = ($bb_cfg['bt_dl_list_only_count'] && !(@$_GET['dl'] === 'names')); + +$dl_topic = ($t_data['topic_dl_type'] == TOPIC_DL_TYPE_DL && !($bb_cfg['bt_dl_list_only_1st_page'] && $start)); +$show_dl_list = ($dl_topic && ($bb_cfg['bt_show_dl_list'] || ($bb_cfg['allow_dl_list_names_mode'] && @$_GET['dl'] === 'names'))); +$show_dl_buttons = ($dl_topic && $bb_cfg['bt_show_dl_list_buttons']); + +// link to clear DL-List +$template->assign_vars(array('S_DL_DELETE' => false)); +if (($is_auth['auth_mod']) && ($t_data['topic_dl_type'] == TOPIC_DL_TYPE_DL)) +{ + $s_dl_delete = "
    '. $lang['DL_LIST_DEL'] .''; + $template->assign_vars(array('S_DL_DELETE' => $s_dl_delete)); +} + +$dl_cat = $dl_count = array(); + +if ($show_dl_list) +{ + foreach ($dl_status_css as $i => $desc) + { + $dl_cat[$i] = ''; + $dl_count[$i] = 0; + } + + if ($count_mode) + { + $sql = "SELECT dl_status AS user_status, users_count AS username + FROM ". BB_BT_DLSTATUS_SNAP ." + WHERE topic_id = $topic_id"; + } + else + { + $sql = "SELECT d.user_status, d.user_id, DATE_FORMAT(d.last_modified_dlstatus, '%Y-%m-%d') AS last_modified_dlstatus, u.username + FROM ". BB_BT_DLSTATUS ." d, ". BB_USERS ." u + WHERE d.topic_id = $topic_id + AND d.user_id = u.user_id + AND d.user_status != ". DL_STATUS_RELEASER ." + ORDER BY d.user_status /* ASC, d.last_modified_dlstatus DESC */ + LIMIT $dl_list_sql_limit"; + } + + if ($dl_info = DB()->fetch_rowset($sql)) + { + if ($count_mode) + { + $template->assign_block_vars('dl_counts', array()); + } + else + { + $template->assign_block_vars('dl_users', array()); + } + + foreach ($dl_info as $rid => $u) + { + $u_link_class = $dl_status_css[$u['user_status']]; + + if ($count_mode) + { + $dl_cat[$u['user_status']] = $u['username']; + $dl_count[$u['user_status']] = $u['username']; + } + else + { + $u_prof_href = ($u['user_id'] == ANONYMOUS) ? '#' : append_sid("profile.php?mode=viewprofile&u=". $u['user_id']) .'#torrent'; + $dl_cat[$u['user_status']] .= ''. $u['username'] .', '; + $dl_count[$u['user_status']]++; + } + } + + foreach ($dl_status_css as $i => $desc) + { + if ($dl_cat[$i] && !$count_mode) + { + $dl_users_div_style = ($dl_count[$i] > $max_dl_users_before_overflow) ? $dl_users_div_style_overflow : $dl_users_div_style_normal; + $dl_cat[$i][strlen($dl_cat[$i])-2] = ' '; + $dl_cat[$i] = "". $dl_cat[$i] .''; + + $template->assign_block_vars('dl_users.users_row', array( + 'DL_OPTION_NAME' => $lang[strtoupper($desc) .'_2'], + 'DL_OPTION_USERS' => $dl_cat[$i], + 'DL_COUNT' => $dl_count[$i], + 'DL_USERS_DIV_STYLE' => $dl_users_div_style)); + } + else if ($dl_count[$i] && $count_mode) + { + if ($i == DL_STATUS_CANCEL && !$show_canceled_in_count_mode) + { + continue; + } + $template->assign_block_vars('dl_counts.count_row', array( + 'DL_OPTION_NAME' => $lang[strtoupper($desc) .'_2'], + 'DL_OPTION_USERS' => $dl_count[$i])); + } + } + } + else + { + $template->assign_block_vars('dl_list_none', array()); + } +} + +if ($show_dl_buttons) +{ + $template->assign_vars(array( + 'DL_BUTTONS' => true, + 'DL_BUT_WILL' => $bb_cfg['bt_show_dl_but_will'], + 'DL_BUT_DOWN' => $bb_cfg['bt_show_dl_but_down'], + 'DL_BUT_COMPL' => $bb_cfg['bt_show_dl_but_compl'], + 'DL_BUT_CANCEL' => $bb_cfg['bt_show_dl_but_cancel'], + )); + + $dl_hidden_fields = ' + + + + + '; + + $template->assign_vars(array( + 'L_NONE' => $lang['NONE'], + 'DL_HIDDEN_FIELDS' => $dl_hidden_fields, + 'S_DL_ACTION' => append_sid("dl_list.php?". POST_TOPIC_URL ."=$topic_id"), + )); +} + +$template->assign_vars(array('SHOW_DL_LIST' => $show_dl_list)); +unset($dl_info); \ No newline at end of file diff --git a/upload/includes/ucp/.htaccess b/upload/includes/ucp/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/ucp/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/ucp/fonts/.htaccess b/upload/includes/ucp/fonts/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/includes/ucp/fonts/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/includes/ucp/fonts/antiqua.png b/upload/includes/ucp/fonts/antiqua.png new file mode 100644 index 000000000..78d93d597 Binary files /dev/null and b/upload/includes/ucp/fonts/antiqua.png differ diff --git a/upload/includes/ucp/fonts/baskerville.png b/upload/includes/ucp/fonts/baskerville.png new file mode 100644 index 000000000..5a635287d Binary files /dev/null and b/upload/includes/ucp/fonts/baskerville.png differ diff --git a/upload/includes/ucp/fonts/batang.png b/upload/includes/ucp/fonts/batang.png new file mode 100644 index 000000000..ba0075634 Binary files /dev/null and b/upload/includes/ucp/fonts/batang.png differ diff --git a/upload/includes/ucp/fonts/bookman.png b/upload/includes/ucp/fonts/bookman.png new file mode 100644 index 000000000..1132a122a Binary files /dev/null and b/upload/includes/ucp/fonts/bookman.png differ diff --git a/upload/includes/ucp/fonts/calisto.png b/upload/includes/ucp/fonts/calisto.png new file mode 100644 index 000000000..b3b0dd560 Binary files /dev/null and b/upload/includes/ucp/fonts/calisto.png differ diff --git a/upload/includes/ucp/fonts/cambria.png b/upload/includes/ucp/fonts/cambria.png new file mode 100644 index 000000000..76ad92107 Binary files /dev/null and b/upload/includes/ucp/fonts/cambria.png differ diff --git a/upload/includes/ucp/fonts/centaur.png b/upload/includes/ucp/fonts/centaur.png new file mode 100644 index 000000000..30a46cadd Binary files /dev/null and b/upload/includes/ucp/fonts/centaur.png differ diff --git a/upload/includes/ucp/fonts/century.png b/upload/includes/ucp/fonts/century.png new file mode 100644 index 000000000..abf89d7e2 Binary files /dev/null and b/upload/includes/ucp/fonts/century.png differ diff --git a/upload/includes/ucp/fonts/chaparral.png b/upload/includes/ucp/fonts/chaparral.png new file mode 100644 index 000000000..7395bacdb Binary files /dev/null and b/upload/includes/ucp/fonts/chaparral.png differ diff --git a/upload/includes/ucp/fonts/constantia.png b/upload/includes/ucp/fonts/constantia.png new file mode 100644 index 000000000..d3abc6464 Binary files /dev/null and b/upload/includes/ucp/fonts/constantia.png differ diff --git a/upload/includes/ucp/fonts/footlight.png b/upload/includes/ucp/fonts/footlight.png new file mode 100644 index 000000000..cb2a634ec Binary files /dev/null and b/upload/includes/ucp/fonts/footlight.png differ diff --git a/upload/includes/ucp/fonts/garamond.png b/upload/includes/ucp/fonts/garamond.png new file mode 100644 index 000000000..eb7222123 Binary files /dev/null and b/upload/includes/ucp/fonts/garamond.png differ diff --git a/upload/includes/ucp/fonts/georgia.png b/upload/includes/ucp/fonts/georgia.png new file mode 100644 index 000000000..d00bb75e4 Binary files /dev/null and b/upload/includes/ucp/fonts/georgia.png differ diff --git a/upload/includes/ucp/fonts/goudy_old.png b/upload/includes/ucp/fonts/goudy_old.png new file mode 100644 index 000000000..b4d236d9a Binary files /dev/null and b/upload/includes/ucp/fonts/goudy_old.png differ diff --git a/upload/includes/ucp/fonts/kozuka.png b/upload/includes/ucp/fonts/kozuka.png new file mode 100644 index 000000000..ececa1104 Binary files /dev/null and b/upload/includes/ucp/fonts/kozuka.png differ diff --git a/upload/includes/ucp/fonts/lucida.png b/upload/includes/ucp/fonts/lucida.png new file mode 100644 index 000000000..050732aa7 Binary files /dev/null and b/upload/includes/ucp/fonts/lucida.png differ diff --git a/upload/includes/ucp/fonts/minion.png b/upload/includes/ucp/fonts/minion.png new file mode 100644 index 000000000..34384e51a Binary files /dev/null and b/upload/includes/ucp/fonts/minion.png differ diff --git a/upload/includes/ucp/fonts/palatino.png b/upload/includes/ucp/fonts/palatino.png new file mode 100644 index 000000000..3a9d37b24 Binary files /dev/null and b/upload/includes/ucp/fonts/palatino.png differ diff --git a/upload/includes/ucp/fonts/perpetua.png b/upload/includes/ucp/fonts/perpetua.png new file mode 100644 index 000000000..8b4c0871a Binary files /dev/null and b/upload/includes/ucp/fonts/perpetua.png differ diff --git a/upload/includes/ucp/fonts/rockwell.png b/upload/includes/ucp/fonts/rockwell.png new file mode 100644 index 000000000..da19566d1 Binary files /dev/null and b/upload/includes/ucp/fonts/rockwell.png differ diff --git a/upload/includes/ucp/fonts/times.png b/upload/includes/ucp/fonts/times.png new file mode 100644 index 000000000..656e99d97 Binary files /dev/null and b/upload/includes/ucp/fonts/times.png differ diff --git a/upload/includes/ucp/fonts/warnock.png b/upload/includes/ucp/fonts/warnock.png new file mode 100644 index 000000000..c114dbcb9 Binary files /dev/null and b/upload/includes/ucp/fonts/warnock.png differ diff --git a/upload/includes/ucp/torrent_userprofile.php b/upload/includes/ucp/torrent_userprofile.php new file mode 100644 index 000000000..82d1cf7fe --- /dev/null +++ b/upload/includes/ucp/torrent_userprofile.php @@ -0,0 +1,200 @@ +assign_vars(array( + 'EDIT_PROF' => true, + 'L_EDIT_PROF' => $lang['EDIT_PROFILE'], + 'EDIT_PROF_HREF' => append_sid("profile.php?mode=editprofile"), + )); +} +else +{ + $template->assign_vars(array('EDIT_PROF' => false)); +} + +// Set tpl vars for bt_userdata +show_bt_userdata($profile_user_id); + +if (IS_ADMIN) +{ + $template->assign_vars(array( + 'SHOW_PASSKEY' => true, + 'S_GEN_PASSKEY' => "'. $lang['BT_GEN_PASSKEY_URL'] .'', + 'CAN_EDIT_RATIO' => IS_SUPER_ADMIN, + )); +} +else +{ + $template->assign_vars(array( + 'CAN_EDIT_RATIO' => false, + )); +} + +// Auth +$not_auth_forums_sql = ($f = $user->get_not_auth_forums(AUTH_READ)) ? "AND f.forum_id NOT IN($f)" : ''; +$datastore->rm('cat_forums'); + +// Get users active torrents +$sql = 'SELECT f.forum_id, f.forum_name, t.topic_title, tor.size, tr.* + FROM '. BB_FORUMS .' f, '. BB_TOPICS .' t, '. BB_BT_TRACKER .' tr, '. BB_BT_TORRENTS ." tor + WHERE tr.user_id = $profile_user_id + AND tr.topic_id = tor.topic_id + AND tor.topic_id = t.topic_id + AND t.forum_id = f.forum_id + $not_auth_forums_sql + GROUP BY tr.topic_id + ORDER BY f.forum_name, t.topic_title"; + +if (!$result = DB()->sql_query($sql)) +{ + message_die(GENERAL_ERROR, 'Could not query users torrent profile information', '', __LINE__, __FILE__, $sql); +} + +if ($rowset = @DB()->sql_fetchrowset($result)) +{ + DB()->sql_freeresult($result); + $rowset_count = count($rowset); + + for ($i=0; $i<$rowset_count; $i++) + { + if ($rowset[$i]['releaser']) + { + $releasing[] = $rowset[$i]; + } + else if ($rowset[$i]['seeder']) + { + $seeding[] = $rowset[$i]; + } + else + { + $leeching[] = $rowset[$i]; + } + } + unset($rowset); +} + +if ($releasing_count = count($releasing)) +{ + $template->assign_block_vars('released', array()); + + for ($i=0; $i<$releasing_count; $i++) + { + $template->assign_block_vars('released.releasedrow', array( + 'FORUM_NAME' => htmlCHR($releasing[$i]['forum_name']), + 'TOPIC_TITLE' => wbr($releasing[$i]['topic_title']), + 'U_VIEW_FORUM' => "viewforum.php?". POST_FORUM_URL .'='. $releasing[$i]['forum_id'], + 'U_VIEW_TOPIC' => "viewtopic.php?". POST_TOPIC_URL .'='. $releasing[$i]['topic_id'] .'&spmode=full#seeders', + )); + } +} +else +{ + $template->assign_block_vars('switch_releasing_none', array()); +} + +if ($seeding_count = count($seeding)) +{ + $template->assign_block_vars('seed', array()); + + for ($i=0; $i<$seeding_count; $i++) + { + $template->assign_block_vars('seed.seedrow', array( + 'FORUM_NAME' => htmlCHR($seeding[$i]['forum_name']), + 'TOPIC_TITLE' => wbr($seeding[$i]['topic_title']), + 'U_VIEW_FORUM' => "viewforum.php?". POST_FORUM_URL .'='. $seeding[$i]['forum_id'], + 'U_VIEW_TOPIC' => "viewtopic.php?". POST_TOPIC_URL .'='. $seeding[$i]['topic_id'] .'&spmode=full#seeders', + )); + } +} +else +{ + $template->assign_block_vars('switch_seeding_none', array()); +} + +if ($leeching_count = count($leeching)) +{ + $template->assign_block_vars('leech', array()); + + for ($i=0; $i<$leeching_count; $i++) + { + $compl_size = ($leeching[$i]['remain'] && $leeching[$i]['size'] && $leeching[$i]['size'] > $leeching[$i]['remain']) ? ($leeching[$i]['size'] - $leeching[$i]['remain']) : 0; + $compl_perc = ($compl_size) ? floor($compl_size * 100 / $leeching[$i]['size']) : 0; + + $template->assign_block_vars('leech.leechrow', array( + 'FORUM_NAME' => htmlCHR($leeching[$i]['forum_name']), + 'TOPIC_TITLE' => wbr($leeching[$i]['topic_title']), + 'U_VIEW_FORUM' => "viewforum.php?". POST_FORUM_URL .'='. $leeching[$i]['forum_id'], + 'U_VIEW_TOPIC' => "viewtopic.php?". POST_TOPIC_URL .'='. $leeching[$i]['topic_id'] .'&spmode=full#leechers', + 'COMPL_PERC' => $compl_perc, + )); + } +} +else +{ + $template->assign_block_vars('switch_leeching_none', array()); +} + +$template->assign_vars(array( + 'USERNAME' => $username, + 'L_RELEASINGS'=> ''. $lang['RELEASING'] .''. (($releasing_count) ? "
    [ $releasing_count ]" : ''), + 'L_SEEDINGS' => ''. $lang['SEEDING'] .''. (($seeding_count) ? "
    [ $seeding_count ]" : ''), + 'L_LEECHINGS' => ''. $lang['LEECHING'] .''. (($leeching_count) ? "
    [ $leeching_count ]" : ''), + + 'L_VIEW_TOR_PROF' => sprintf($lang['VIEWING_USER_BT_PROFILE'], $username), + 'RELEASED_ROWSPAN' => ($releasing_count) ? 'rowspan="'. ($releasing_count + 1) .'"' : '', + 'SEED_ROWSPAN' => ($seeding_count) ? 'rowspan="'. ($seeding_count + 1) .'"' : '', + 'LEECH_ROWSPAN' => ($leeching_count) ? 'rowspan="'. ($leeching_count + 1) .'"' : '', +)); + +$template->assign_vars(array('SHOW_SEARCH_DL' => false)); + +if (!IS_USER || $profile_user_id == $userdata['user_id']) +{ + $page_cfg['dl_links_user_id'] = $profile_user_id; +} + +$template->assign_vars(array( + 'U_TORRENT_PROFILE' => append_sid("profile.php?mode=viewprofile&u=". $profiledata['user_id']) . '#torrent', + 'L_TORRENT_PROFILE' => $lang['VIEW_TORRENT_PROFILE'], + 'L_UP_TOTAL' => $lang['PROFILE_UP_TOTAL'], + 'L_DOWN_TOTAL' => $lang['PROFILE_DOWN_TOTAL'], + 'L_BONUS' => $lang['PROFILE_BONUS'], + 'L_TOTAL_RELEASED' => $lang['PROFILE_RELEASED'], + 'L_USER_RATIO' => $lang['PROFILE_RATIO'], + 'L_MAX_SPEED' => $lang['PROFILE_MAX_SPEED'], + 'L_IT_WILL_BE_DOWN' => $lang['PROFILE_IT_WILL_BE_DOWNLOADED'], +)); + +$sql = 'SELECT SUM(speed_up) as speed_up, SUM(speed_down) as speed_down + FROM '. BB_BT_TRACKER .' + WHERE user_id = ' . $profile_user_id . ''; + +if ($row = DB()->fetch_row($sql)) +{ + $speed_up = ($row['speed_up']) ? humn_size($row['speed_up']).'/s' : '-'; + $speed_down = ($row['speed_down']) ? humn_size($row['speed_down']).'/s' : '-'; + + $template->assign_vars(array( + 'SPEED_UP' => $speed_up, + 'SPEED_DOWN' => $speed_down, + )); +} \ No newline at end of file diff --git a/upload/includes/ucp/usercp_activate.php b/upload/includes/ucp/usercp_activate.php new file mode 100644 index 000000000..93614c083 --- /dev/null +++ b/upload/includes/ucp/usercp_activate.php @@ -0,0 +1,89 @@ +sql_query($sql)) ) +{ + message_die(GENERAL_ERROR, 'Could not obtain user information', '', __LINE__, __FILE__, $sql); +} + +if ( $row = DB()->sql_fetchrow($result) ) +{ + if ( $row['user_active'] && trim($row['user_actkey']) == '' ) + { + message_die(GENERAL_MESSAGE, $lang['ALREADY_ACTIVATED']); + } + else if ((trim($row['user_actkey']) == trim($_GET['act_key'])) && (trim($row['user_actkey']) != '')) + { + if (intval($bb_cfg['require_activation']) == USER_ACTIVATION_ADMIN && $row['user_newpasswd'] == '') + { + if (!$userdata['session_logged_in']) + { + redirect(append_sid('login.php?redirect=profile.php&mode=activate&' . POST_USERS_URL . '=' . $row['user_id'] . '&act_key=' . trim($_GET['act_key']))); + } + else if (!IS_ADMIN) + { + message_die(GENERAL_MESSAGE, $lang['NOT_AUTHORISED']); + } + } + + $sql_update_pass = ( $row['user_newpasswd'] != '' ) ? ", user_password = '" . str_replace("\'", "''", $row['user_newpasswd']) . "', user_newpasswd = ''" : ''; + + $sql = "UPDATE " . BB_USERS . " + SET user_active = 1, user_actkey = ''" . $sql_update_pass . " + WHERE user_id = " . $row['user_id']; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not update users table', '', __LINE__, __FILE__, $sql_update); + } + + if ( intval($bb_cfg['require_activation']) == USER_ACTIVATION_ADMIN && $sql_update_pass == '' ) + { + include(INC_DIR . 'emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('admin_welcome_activated', $row['user_lang']); + $emailer->email_address($row['user_email']); + $emailer->set_subject($lang['ACCOUNT_ACTIVATED_SUBJECT']); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'USERNAME' => $row['username'], + 'PASSWORD' => $password_confirm, + 'EMAIL_SIG' => (!empty($bb_cfg['board_email_sig'])) ? str_replace('
    ', "\n", "-- \n" . $bb_cfg['board_email_sig']) : '') + ); + $emailer->send(); + $emailer->reset(); + + message_die(GENERAL_MESSAGE, $lang['ACCOUNT_ACTIVE_ADMIN']); + } + else + { + $message = ( $sql_update_pass == '' ) ? $lang['ACCOUNT_ACTIVE'] : $lang['PASSWORD_ACTIVATED']; + message_die(GENERAL_MESSAGE, $message); + } + } + else + { + message_die(GENERAL_MESSAGE, $lang['WRONG_ACTIVATION']); + } +} +else +{ + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_USER']); +} \ No newline at end of file diff --git a/upload/includes/ucp/usercp_attachcp.php b/upload/includes/ucp/usercp_attachcp.php new file mode 100644 index 000000000..7d5ba5f4b --- /dev/null +++ b/upload/includes/ucp/usercp_attachcp.php @@ -0,0 +1,332 @@ + 0) +{ + $select_sort_mode = ''; +} + +$select_sort_order = ''; + +$delete = (isset($_POST['delete'])) ? true : false; +$delete_id_list = (isset($_POST['delete_id_list'])) ? array_map('intval', $_POST['delete_id_list']) : array(); + +$confirm = (isset($_POST['confirm']) && $_POST['confirm']) ? true : false; + +if ($confirm && sizeof($delete_id_list) > 0) +{ + $attachments = array(); + + for ($i = 0; $i < sizeof($delete_id_list); $i++) + { + $sql = 'SELECT post_id + FROM ' . BB_ATTACHMENTS . ' + WHERE attach_id = ' . intval($delete_id_list[$i]) . ' + AND user_id_1 = ' . intval($profiledata['user_id']); + $result = DB()->sql_query($sql); + + if ($result) + { + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + delete_attachment(0, intval($delete_id_list[$i])); + } + } +} +else if ($delete && sizeof($delete_id_list) > 0) +{ + // Not confirmed, show confirmation message + $hidden_fields = ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + $hidden_fields .= ''; + + for ($i = 0; $i < sizeof($delete_id_list); $i++) + { + $hidden_fields .= ''; + } + + print_confirmation(array( + 'QUESTION' => $lang['CONFIRM_DELETE_ATTACHMENTS'], + 'FORM_ACTION' => "profile.php?mode=attachcp", + 'HIDDEN_FIELDS' => $hidden_fields, + )); +} + +$hidden_fields = ''; + +$total_rows = 0; + +$username = $profiledata['username']; + +$s_hidden = ''; +$s_hidden .= ''; + +// Assign Template Vars +$template->assign_vars(array( + 'PAGE_TITLE' => $lang['USER_ACP_TITLE'], + 'L_FILENAME' => $lang['FILE_NAME'], + 'L_FILECOMMENT' => $lang['FILE_COMMENT_CP'], + 'L_SIZE' => $lang['SIZE_IN_KB'], + + 'USERNAME' => $profiledata['username'], + + 'S_USER_HIDDEN' => $s_hidden, + 'S_MODE_ACTION' => append_sid(BB_ROOT ."profile.php?mode=attachcp"), + 'S_MODE_SELECT' => $select_sort_mode, + 'S_ORDER_SELECT' => $select_sort_order) +); + +$sql = "SELECT attach_id + FROM " . BB_ATTACHMENTS . " + WHERE user_id_1 = " . intval($profiledata['user_id']) . " + GROUP BY attach_id"; + +if ( !($result = DB()->sql_query($sql)) ) +{ + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); +} + +$attach_ids = DB()->sql_fetchrowset($result); +$num_attach_ids = DB()->num_rows($result); +DB()->sql_freeresult($result); + +$total_rows = $num_attach_ids; + +$attachments = array(); + +if ($num_attach_ids > 0) +{ + $attach_id = array(); + + for ($j = 0; $j < $num_attach_ids; $j++) + { + $attach_id[] = (int) $attach_ids[$j]['attach_id']; + } + + $sql = "SELECT a.* + FROM " . BB_ATTACHMENTS_DESC . " a + WHERE a.attach_id IN (" . join(', ', $attach_id) . ") " . + $order_by; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Couldn't query attachments", '', __LINE__, __FILE__, $sql); + } + + $attachments = DB()->sql_fetchrowset($result); + $num_attach = DB()->num_rows($result); + DB()->sql_freeresult($result); +} + +if (sizeof($attachments) > 0) +{ + for ($i = 0; $i < sizeof($attachments); $i++) + { + // Is the Attachment assigned to more than one post? + // If it's not assigned to any post, it's an private message thingy. ;) + $post_titles = array(); + + $sql = 'SELECT * + FROM ' . BB_ATTACHMENTS . ' + WHERE attach_id = ' . (int) $attachments[$i]['attach_id']; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Couldn\'t query attachments', '', __LINE__, __FILE__, $sql); + } + + $ids = DB()->sql_fetchrowset($result); + $num_ids = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($j = 0; $j < $num_ids; $j++) + { + if ($ids[$j]['post_id'] != 0) + { + $sql = "SELECT t.topic_title + FROM " . BB_TOPICS . " t, " . BB_POSTS . " p + WHERE p.post_id = " . (int) $ids[$j]['post_id'] . " AND p.topic_id = t.topic_id + GROUP BY t.topic_id, t.topic_title"; + + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Couldn\'t query topic', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + DB()->sql_freeresult($result); + + $post_title = $row['topic_title']; + + $post_title = str_short($post_title, 30); + + $view_topic = append_sid(BB_ROOT .'viewtopic.php?' . POST_POST_URL . '=' . $ids[$j]['post_id'] . '#' . $ids[$j]['post_id']); + + $post_titles[] = '' . $post_title . ''; + } + } + + // Iron out those Attachments assigned to us, but not more controlled by us. ;) (PM's) + if (sizeof($post_titles) > 0) + { + $delete_box = ''; + + for ($j = 0; $j < sizeof($delete_id_list); $j++) + { + if ($delete_id_list[$j] == $attachments[$i]['attach_id']) + { + $delete_box = ''; + break; + } + } + + $post_titles = join('
    ', $post_titles); + + $hidden_field = ''; + $hidden_field .= ''; + + $comment = str_replace("\n", '
    ', $attachments[$i]['comment']); + + $template->assign_block_vars('attachrow', array( + 'ROW_NUMBER' => $i + ($start + 1 ), + + 'ATTACH_ID' => $attachments[$i]['attach_id'], + 'FILENAME' => htmlspecialchars($attachments[$i]['real_filename']), + 'COMMENT' => htmlspecialchars($comment), + 'EXTENSION' => $attachments[$i]['extension'], + 'SIZE_RAW' => $attachments[$i]['filesize'], + 'SIZE' => round(($attachments[$i]['filesize'] / MEGABYTE), 2), + 'DOWNLOAD_COUNT' => $attachments[$i]['download_count'], + 'POST_TIME_RAW' => $attachments[$i]['filetime'], + 'POST_TIME' => bb_date($attachments[$i]['filetime']), + 'POST_TITLE' => $post_titles, + + 'S_DELETE_BOX' => $delete_box, + 'S_HIDDEN' => $hidden_field, + 'U_VIEW_ATTACHMENT' => append_sid(BB_ROOT .'download.php?id=' . $attachments[$i]['attach_id'])) + // 'U_VIEW_POST' => ($attachments[$i]['post_id'] != 0) ? append_sid("../viewtopic.php?" . POST_POST_URL . "=" . $attachments[$i]['post_id'] . "#" . $attachments[$i]['post_id']) : '') + ); + } + } +} + +// Generate Pagination +if ($do_pagination && $total_rows > $bb_cfg['topics_per_page']) +{ + $pagination = generate_pagination(BB_ROOT ."profile.php?mode=attachcp&mode_a=$mode&order=$sort_order&" . POST_USERS_URL . '=' . $profiledata['user_id'] . '&sid=' . $userdata['session_id'], $total_rows, $bb_cfg['topics_per_page'], $start).' '; + + $template->assign_vars(array( + 'PAGINATION' => $pagination, + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], (floor($start / $bb_cfg['topics_per_page']) + 1), ceil($total_rows / $bb_cfg['topics_per_page'])), + )); +} + +print_page('usercp_attachcp.tpl'); diff --git a/upload/includes/ucp/usercp_avatar.php b/upload/includes/ucp/usercp_avatar.php new file mode 100644 index 000000000..5869bec34 --- /dev/null +++ b/upload/includes/ucp/usercp_avatar.php @@ -0,0 +1,411 @@ +' . $lang['AVATAR_FILETYPE'] : $lang['AVATAR_FILETYPE']; + break; + } + + return false; +} + +function user_avatar_delete($avatar_type, $avatar_file) +{ + global $bb_cfg, $userdata; + + $avatar_file = basename($avatar_file); + if ( $avatar_type == USER_AVATAR_UPLOAD && $avatar_file != '' ) + { + if ( @file_exists(@phpbb_realpath('./' . $bb_cfg['avatar_path'] . '/' . $avatar_file)) ) + { + @unlink('./' . $bb_cfg['avatar_path'] . '/' . $avatar_file); + } + } + + return ", user_avatar = '', user_avatar_type = " . USER_AVATAR_NONE; +} + +function user_avatar_gallery($mode, &$error, &$error_msg, $avatar_filename, $avatar_category) +{ + global $bb_cfg; + + $avatar_filename = phpbb_ltrim(basename($avatar_filename), "'"); + $avatar_category = phpbb_ltrim(basename($avatar_category), "'"); + + if(!preg_match('/(\.gif$|\.png$|\.jpg|\.jpeg)$/is', $avatar_filename)) + { + return ''; + } + if ($avatar_filename == "" || $avatar_category == "") + { + return ''; + } + + if ( file_exists(@phpbb_realpath($bb_cfg['avatar_gallery_path'] . '/' . $avatar_category . '/' . $avatar_filename)) && ($mode == 'editprofile') ) + { + $return = ", user_avatar = '" . str_replace("\'", "''", $avatar_category . '/' . $avatar_filename) . "', user_avatar_type = " . USER_AVATAR_GALLERY; + } + else + { + $return = ''; + } + return $return; +} + +function user_avatar_url($mode, &$error, &$error_msg, $avatar_filename) +{ + global $lang; + + if ( !preg_match('#^(http)|(ftp):\/\/#i', $avatar_filename) ) + { + $avatar_filename = 'http://' . $avatar_filename; + } + + $avatar_filename = substr($avatar_filename, 0, 100); + + if ( !preg_match("#^((ht|f)tp://)([^ \?&=\#\"\n\r\t<]*?(\.(jpg|jpeg|gif|png))$)#is", $avatar_filename) ) + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $lang['WRONG_REMOTE_AVATAR_FORMAT'] : $lang['WRONG_REMOTE_AVATAR_FORMAT']; + return; + } + + return ( $mode == 'editprofile' ) ? ", user_avatar = '" . str_replace("\'", "''", $avatar_filename) . "', user_avatar_type = " . USER_AVATAR_REMOTE : ''; + +} + +function user_avatar_upload($mode, $avatar_mode, &$current_avatar, &$current_type, &$error, &$error_msg, $avatar_filename, $avatar_realname, $avatar_filesize, $avatar_filetype) +{ + global $bb_cfg, $lang; + + $avatar_sql = ''; + + $ini_val = ( @phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var'; + + $width = $height = 0; + $type = ''; + + if ( $avatar_mode == 'remote' && preg_match('/^(http:\/\/)?([\w\-\.]+)\:?([0-9]*)\/([^ \?&=\#\"\n\r\t<]*?(\.(jpg|jpeg|gif|png)))$/', $avatar_filename, $url_ary) ) + { + if ( empty($url_ary[4]) ) + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $lang['INCOMPLETE_URL'] : $lang['INCOMPLETE_URL']; + return; + } + + $base_get = '/' . $url_ary[4]; + $port = ( !empty($url_ary[3]) ) ? $url_ary[3] : 80; + + if ( !($fsock = @fsockopen($url_ary[2], $port, $errno, $errstr)) ) + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $lang['NO_CONNECTION_URL'] : $lang['NO_CONNECTION_URL']; + return; + } + + @fputs($fsock, "GET $base_get HTTP/1.1\r\n"); + @fputs($fsock, "HOST: " . $url_ary[2] . "\r\n"); + @fputs($fsock, "Connection: close\r\n\r\n"); + + $avatar_data = ''; + while( !@feof($fsock) ) + { + $avatar_data .= @fread($fsock, $bb_cfg['avatar_filesize']); + } + @fclose($fsock); + + if (!preg_match('#Content-Length\: ([0-9]+)[^ /][\s]+#i', $avatar_data, $file_data1) || !preg_match('#Content-Type\: image/[x\-]*([a-z]+)[\s]+#i', $avatar_data, $file_data2)) + { + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $lang['FILE_NO_DATA'] : $lang['FILE_NO_DATA']; + return; + } + + $avatar_filesize = $file_data1[1]; + $avatar_filetype = $file_data2[1]; + + if ( !$error && $avatar_filesize > 0 && $avatar_filesize < $bb_cfg['avatar_filesize'] ) + { + $avatar_data = substr($avatar_data, strlen($avatar_data) - $avatar_filesize, $avatar_filesize); + + //$tmp_path = ( !@$ini_val('safe_mode') ) ? '/tmp' : './' . $bb_cfg['avatar_path'] . '/tmp'; + $tmp_path = ini_get('upload_tmp_dir'); + $tmp_filename = tempnam($tmp_path, uniqid(rand()) . '-'); + + $fptr = @fopen($tmp_filename, 'wb'); + $bytes_written = @fwrite($fptr, $avatar_data, $avatar_filesize); + @fclose($fptr); + + if ( $bytes_written != $avatar_filesize ) + { + @unlink($tmp_filename); + message_die(GENERAL_ERROR, 'Could not write avatar file to local storage. Please contact the board administrator with this message', '', __LINE__, __FILE__); + } + + list($width, $height, $type) = @getimagesize($tmp_filename); + } + else + { + $l_avatar_size = sprintf($lang['AVATAR_FILESIZE'], round($bb_cfg['avatar_filesize'] / 1024)); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $l_avatar_size : $l_avatar_size; + } + } + else if ( ( file_exists(@phpbb_realpath($avatar_filename)) ) && preg_match('/\.(jpg|jpeg|gif|png)$/i', $avatar_realname) ) + { + if ( $avatar_filesize <= $bb_cfg['avatar_filesize'] && $avatar_filesize > 0 ) + { + preg_match('#image\/[x\-]*([a-z]+)#', $avatar_filetype, $avatar_filetype); + $avatar_filetype = $avatar_filetype[1]; + } + else + { + $l_avatar_size = sprintf($lang['AVATAR_FILESIZE'], round($bb_cfg['avatar_filesize'] / 1024)); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $l_avatar_size : $l_avatar_size; + return; + } + + list($width, $height, $type) = @getimagesize($avatar_filename); + } + + if ( !($imgtype = check_image_type($avatar_filetype, $error, $error_msg)) ) + { + return; + } + + switch ($type) + { + // GIF + case 1: + if ($imgtype != '.gif') + { + @unlink($tmp_filename); + message_die(GENERAL_ERROR, 'Unable to upload file', '', __LINE__, __FILE__); + } + break; + + // JPG, JPC, JP2, JPX, JB2 + case 2: + case 9: + case 10: + case 11: + case 12: + if ($imgtype != '.jpg' && $imgtype != '.jpeg') + { + @unlink($tmp_filename); + message_die(GENERAL_ERROR, 'Unable to upload file', '', __LINE__, __FILE__); + } + break; + + // PNG + case 3: + if ($imgtype != '.png') + { + @unlink($tmp_filename); + message_die(GENERAL_ERROR, 'Unable to upload file', '', __LINE__, __FILE__); + } + break; + + default: + @unlink($tmp_filename); + message_die(GENERAL_ERROR, 'Unable to upload file', '', __LINE__, __FILE__); + } + + if ( $width > 0 && $height > 0 && $width <= $bb_cfg['avatar_max_width'] && $height <= $bb_cfg['avatar_max_height'] ) + { + $new_filename = uniqid(rand()) . $imgtype; + + if ( $mode == 'editprofile' && $current_type == USER_AVATAR_UPLOAD && $current_avatar != '' ) + { + user_avatar_delete($current_type, $current_avatar); + } + + if( $avatar_mode == 'remote' ) + { + @copy($tmp_filename, './' . $bb_cfg['avatar_path'] . "/$new_filename"); + @unlink($tmp_filename); + } + else + { + if ( @$ini_val('open_basedir') != '' ) + { + if ( @phpversion() < '4.0.3' ) + { + message_die(GENERAL_ERROR, 'open_basedir is set and your PHP version does not allow move_uploaded_file', '', __LINE__, __FILE__); + } + + $move_file = 'move_uploaded_file'; + } + else + { + $move_file = 'copy'; + } + + if (!is_uploaded_file($avatar_filename)) + { + message_die(GENERAL_ERROR, 'Unable to upload file', '', __LINE__, __FILE__); + } + $move_file($avatar_filename, './' . $bb_cfg['avatar_path'] . "/$new_filename"); + } + + @chmod('./' . $bb_cfg['avatar_path'] . "/$new_filename", 0777); + + $avatar_sql = ( $mode == 'editprofile' ) ? ", user_avatar = '$new_filename', user_avatar_type = " . USER_AVATAR_UPLOAD : "'$new_filename', " . USER_AVATAR_UPLOAD; + } + else + { + $l_avatar_size = sprintf($lang['AVATAR_IMAGESIZE'], $bb_cfg['avatar_max_width'], $bb_cfg['avatar_max_height']); + + $error = true; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $l_avatar_size : $l_avatar_size; + } + + return $avatar_sql; +} + +function display_avatar_gallery($mode, $category, $user_id, $email, $current_email, $username, $email, $new_password, $cur_password, $password_confirm, $icq, $website, $location, $user_flag, $occupation, $interests, $signature, $viewemail, $notifypm, $notifyreply, $attachsig, $hideonline, $style, $language, $timezone, $dateformat, &$session_id) +{ + global $bb_cfg, $template, $lang, $images, $theme; + + $dir = @opendir($bb_cfg['avatar_gallery_path']); + + $avatar_images = array(); + while( $file = @readdir($dir) ) + { + if( $file != '.' && $file != '..' && !is_file($bb_cfg['avatar_gallery_path'] . '/' . $file) && !is_link($bb_cfg['avatar_gallery_path'] . '/' . $file) ) + { + $sub_dir = @opendir($bb_cfg['avatar_gallery_path'] . '/' . $file); + + $avatar_row_count = 0; + $avatar_col_count = 0; + while( $sub_file = @readdir($sub_dir) ) + { + if( preg_match('/(\.gif$|\.png$|\.jpg|\.jpeg)$/is', $sub_file) ) + { + $avatar_images[$file][$avatar_row_count][$avatar_col_count] = $sub_file; + $avatar_name[$file][$avatar_row_count][$avatar_col_count] = ucfirst(str_replace("_", " ", preg_replace('/^(.*)\..*$/', '\1', $sub_file))); + + $avatar_col_count++; + if( $avatar_col_count == 5 ) + { + $avatar_row_count++; + $avatar_col_count = 0; + } + } + } + } + } + + @closedir($dir); + + @ksort($avatar_images); + @reset($avatar_images); + + if( empty($category) ) + { + list($category, ) = each($avatar_images); + } + @reset($avatar_images); + + $s_categories = ''; + + $s_colspan = 0; + for($i = 0; $i < count($avatar_images[$category]); $i++) + { + $template->assign_block_vars("avatar_row", array()); + + $s_colspan = max($s_colspan, count($avatar_images[$category][$i])); + + for($j = 0; $j < count($avatar_images[$category][$i]); $j++) + { + $template->assign_block_vars('avatar_row.avatar_column', array( + "AVATAR_IMAGE" => $bb_cfg['avatar_gallery_path'] . '/' . $category . '/' . $avatar_images[$category][$i][$j], + "AVATAR_NAME" => $avatar_name[$category][$i][$j]) + ); + + $template->assign_block_vars('avatar_row.avatar_option_column', array( + "S_OPTIONS_AVATAR" => $avatar_images[$category][$i][$j]) + ); + } + } + + $params = array('user_id', 'username', 'email', 'current_email', 'cur_password', 'new_password', 'password_confirm', 'icq', 'website', 'location', 'user_flag', 'occupation', 'interests', 'signature', 'viewemail', 'notifypm', 'notifyreply', 'attachsig', 'hideonline', 'style', 'language', 'timezone', 'dateformat'); + + $s_hidden_vars = ''; + + for($i = 0; $i < count($params); $i++) + { + $s_hidden_vars .= ''; + } + + $template->assign_vars(array( + 'S_CATEGORY_SELECT' => $s_categories, + 'S_COLSPAN' => $s_colspan, + 'S_PROFILE_ACTION' => append_sid("profile.php?mode=$mode"), + 'S_HIDDEN_FIELDS' => $s_hidden_vars) + ); + + return; +} \ No newline at end of file diff --git a/upload/includes/ucp/usercp_email.php b/upload/includes/ucp/usercp_email.php new file mode 100644 index 000000000..399e4ec52 --- /dev/null +++ b/upload/includes/ucp/usercp_email.php @@ -0,0 +1,141 @@ +fetch_row($sql) ) +{ + $username = $row['username']; + $user_email = $row['user_email']; + $user_lang = $row['user_lang']; + + if ( true || IS_ADMIN ) // TRUE instead of missing user_opt "prevent_email" + { + if ( isset($_POST['submit']) ) + { + $error = FALSE; + + if ( !empty($_POST['subject']) ) + { + $subject = trim(stripslashes($_POST['subject'])); + } + else + { + $error = TRUE; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $lang['EMPTY_SUBJECT_EMAIL'] : $lang['EMPTY_SUBJECT_EMAIL']; + } + + if ( !empty($_POST['message']) ) + { + $message = trim(stripslashes($_POST['message'])); + } + else + { + $error = TRUE; + $error_msg = ( !empty($error_msg) ) ? $error_msg . '
    ' . $lang['EMPTY_MESSAGE_EMAIL'] : $lang['EMPTY_MESSAGE_EMAIL']; + } + + if ( !$error ) + { + require(INC_DIR . 'emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($userdata['user_email']); + $emailer->replyto($userdata['user_email']); + + $email_headers = 'X-AntiAbuse: Board servername - ' . $server_name . "\n"; + $email_headers .= 'X-AntiAbuse: User_id - ' . $userdata['user_id'] . "\n"; + $email_headers .= 'X-AntiAbuse: Username - ' . $userdata['username'] . "\n"; + $email_headers .= 'X-AntiAbuse: User IP - ' . CLIENT_IP . "\n"; + + $emailer->use_template('profile_send_email', $user_lang); + $emailer->email_address($user_email); + $emailer->set_subject($subject); + $emailer->extra_headers($email_headers); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'BOARD_EMAIL' => $bb_cfg['board_email'], + 'FROM_USERNAME' => $userdata['username'], + 'TO_USERNAME' => $username, + 'MESSAGE' => $message) + ); + $emailer->send(); + $emailer->reset(); + + if ( !empty($_POST['cc_email']) ) + { + $emailer->from($userdata['user_email']); + $emailer->replyto($userdata['user_email']); + $emailer->use_template('profile_send_email'); + $emailer->email_address($userdata['user_email']); + $emailer->set_subject($subject); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'BOARD_EMAIL' => $bb_cfg['board_email'], + 'FROM_USERNAME' => $userdata['username'], + 'TO_USERNAME' => $username, + 'MESSAGE' => $message) + ); + $emailer->send(); + $emailer->reset(); + } + + sleep(7); + $message = $lang['EMAIL_SENT'] . '

    ' . sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + message_die(GENERAL_MESSAGE, $message); + } + } + + if (!empty($error)) + { + $template->assign_vars(array('ERROR_MESSAGE' => $error_msg)); + } + + $template->assign_vars(array( + 'USERNAME' => $username, + + 'S_HIDDEN_FIELDS' => '', + 'S_POST_ACTION' => append_sid("profile.php?mode=email&" . POST_USERS_URL . "=$user_id"), + + 'L_MESSAGE_BODY_DESC' => $lang['EMAIL_MESSAGE_DESC'], + )); + + print_page('usercp_email.tpl'); + } + else + { + message_die(GENERAL_MESSAGE, $lang['USER_PREVENT_EMAIL']); + } +} +else +{ + message_die(GENERAL_MESSAGE, $lang['USER_NOT_EXIST']); +} \ No newline at end of file diff --git a/upload/includes/ucp/usercp_register.php b/upload/includes/ucp/usercp_register.php new file mode 100644 index 000000000..d4dde532e --- /dev/null +++ b/upload/includes/ucp/usercp_register.php @@ -0,0 +1,598 @@ + can_edit + $profile_fields = array( + 'username' => true, + 'user_password' => true, + 'user_email' => true, + 'user_timezone' => true, + ); + + $pr_data = array( + 'user_id' => ANONYMOUS, + 'username' => '', + 'user_password' => '', + 'user_email' => '', + 'user_timezone' => $bb_cfg['board_timezone'], + 'user_opt' => 0, + ); + break; + + /** + * Редактирование профиля + */ + case 'editprofile': + if (IS_GUEST) + { + login_redirect(); + } + + // field => can_edit + $profile_fields = array( + 'username' => IS_ADMIN, + 'user_password' => true, + 'user_timezone' => true, + 'user_opt' => true, + 'user_email' => true, // должен быть после user_password + 'user_icq' => true, + 'user_website' => true, + 'user_from' => true, + 'user_sig' => true, + 'user_occ' => true, + 'user_interests' => true, + ); + + // Выбор профиля: для юзера свой, для админа любой + if (IS_ADMIN && !empty($_REQUEST['u'])) + { + $pr_user_id = (int) $_REQUEST['u']; + $adm_edit = ($pr_user_id != $user->id); + } + else + { + $pr_user_id = $user->id; + } + $profile_fields_sql = join(', ', array_keys($profile_fields)); + $sql = " + SELECT + user_id, + user_level, + $profile_fields_sql + FROM ". BB_USERS ." + WHERE user_id = $pr_user_id + LIMIT 1 + "; + if (!$pr_data = DB()->fetch_row($sql)) + { + bb_die('Профиль не найден'); + } + break; + + default: + trigger_error("invalid mode: $mode", E_USER_ERROR); +} + +// CAPTCHA +$need_captcha = ($mode == 'register' && !IS_ADMIN); + +if ($submit) +{ + if ($need_captcha && !CAPTCHA()->verify_code()) + { + $errors[] = $lang['CONFIRM_CODE_WRONG']; + } +} + +// Валидация данных +$cur_pass_valid = $adm_edit; + +foreach ($profile_fields as $field => $can_edit) +{ + switch ($field) + { + /** + * Имя (edit, reg) + */ + case 'username': + if ($can_edit) + { + $username = !empty($_POST['username']) ? clean_username($_POST['username']) : $pr_data['username']; + if ($submit) + { + if ($mode == 'register') + { + if (empty($username)) + { + $errors[] = 'Вы должны выбрать имя'; + } + if (!$errors AND $err = validate_username($username)) + { + $errors[] = $err; + } + + $db_data['username'] = $username; + } + else + { + if ($username != $pr_data['username']) + { + if (!$errors AND $err = validate_username($username)) + { + $errors[] = $err; + } + $db_data['username'] = $username; + } + } + } + $tp_data['CAN_EDIT_USERNAME'] = true; + $tp_data['USERNAME'] = $username; + } + else + { + $tp_data['USERNAME'] = $pr_data['username']; + } + break; + + /** + * Пароль (edit, reg) + */ + case 'user_password': + if ($submit) + { + $cur_pass = (string) @$_POST['cur_pass']; + $new_pass = (string) @$_POST['new_pass']; + $cfm_pass = (string) @$_POST['cfm_pass']; + + // пароль для гостя и при смене пароля юзером + if (!empty($new_pass)) + { + if (strlen($new_pass) > 20) + { + $errors[] = 'Пароль должен быть не длиннее 20 символов'; + } + else if ($new_pass != $cfm_pass) + { + $errors[] = 'Введённые пароли не совпадают'; + } + $db_data['user_password'] = md5($new_pass); + } + + if ($mode == 'register') + { + if (empty($new_pass)) + { + $errors[] = 'Вы должны указать пароль'; + } + } + else + { + if (!empty($cur_pass)) + { + $cur_pass_valid = ($pr_data['user_password'] === md5($cur_pass)); + } + if (!empty($new_pass) && !$cur_pass_valid) + { + $errors[] = 'Для изменения пароля вы должны правильно указать текущий пароль'; + } + } + } + + break; + + /** + * E-mail (edit, reg) + */ + case 'user_email': + $email = !empty($_POST['user_email']) ? (string) $_POST['user_email'] : $pr_data['user_email']; + if ($submit) + { + if ($mode == 'register') + { + if (empty($email)) + { + $errors[] = 'Вы должны указать e-mail'; + } + if (!$errors AND $err = validate_email($email)) + { + $errors[] = $err; + } + $db_data['user_email'] = $email; + } + else if ($email != $pr_data['user_email']) // если смена мейла юзером + { + if (!$cur_pass_valid) + { + $errors[] = 'Для изменения e-mail вы должны правильно указать текущий пароль'; + } + if (!$errors AND $err = validate_email($email)) + { + $errors[] = $err; + } + $db_data['user_email'] = $email; + } + } + $tp_data['USER_EMAIL'] = htmlCHR($email); + break; + + /** + * Часовой пояс (edit, reg) + */ + case 'user_timezone': + $user_timezone = isset($_POST['user_timezone']) ? (int) $_POST['user_timezone'] : $pr_data['user_timezone']; + if ($submit) + { + if (isset($lang['TZ'][$user_timezone]) && $user_timezone != $pr_data['user_timezone']) + { + $pr_data['user_timezone'] = $user_timezone; + $db_data['user_timezone'] = (int) $user_timezone; + } + } + break; + + /** + * opt (edit) + */ + case 'user_opt': + $user_opt = $pr_data['user_opt']; + + $update_user_opt = array( + 'notify_pm' => true, + 'hide_porn_forums' => true, + ); + foreach ($update_user_opt as $opt => $can_change_opt) + { + if ($submit && $can_change_opt && isset($_POST[$opt])) + { + setbit($user_opt, $bf['user_opt'][$opt], !empty($_POST[$opt])); + } + $tp_data[strtoupper($opt)] = bf($user_opt, 'user_opt', $opt); + } + if ($submit && $user_opt != $pr_data['user_opt']) + { + $pr_data['user_opt'] = $user_opt; + $db_data['user_opt'] = (int) $user_opt; + } + break; + + /** + * ICQ (edit) + */ + case 'user_icq': + $icq = isset($_POST['user_icq']) ? (string) $_POST['user_icq'] : $pr_data['user_icq']; + if ($submit) + { + if ($icq != $pr_data['user_icq']) + { + if ($icq == '' || preg_match('#^\d{6,15}$#', $icq)) + { + $pr_data['user_icq'] = $icq; + $db_data['user_icq'] = (string) $icq; + } + else + { + $pr_data['user_icq'] = ''; + $errors[] = htmlCHR('Поле "ICQ" может содержать только номер icq'); + } + } + } + $tp_data['USER_ICQ'] = $pr_data['user_icq']; + break; + + /** + * Сайт (edit) + */ + case 'user_website': + $website = isset($_POST['user_website']) ? (string) $_POST['user_website'] : $pr_data['user_website']; + $website = htmlCHR($website); + if ($submit) + { + if ($website != $pr_data['user_website']) + { + if ($website == '' || preg_match('#^https?://[a-z0-9_:;?&=/.%~\-]+$#i', $website)) + { + $pr_data['user_website'] = $website; + $db_data['user_website'] = (string) $website; + } + else + { + $pr_data['user_website'] = ''; + $errors[] = htmlCHR('Поле "Сайт" может содержать только http:// ссылку'); + } + } + } + $tp_data['USER_WEBSITE'] = $pr_data['user_website']; + break; + + /** + * Откуда (edit) + */ + case 'user_from': + $from = isset($_POST['user_from']) ? (string) $_POST['user_from'] : $pr_data['user_from']; + $from = htmlCHR($from); + if ($submit) + { + if ($from != $pr_data['user_from']) + { + $pr_data['user_from'] = $from; + $db_data['user_from'] = (string) $from; + } + } + $tp_data['USER_FROM'] = $pr_data['user_from']; + break; + + /** + * Подпись (edit) + */ + case 'user_sig': + $sig = isset($_POST['user_sig']) ? (string) $_POST['user_sig'] : $pr_data['user_sig']; + if ($submit) + { + $sig_esc = prepare_message($sig); + + if (strlen($sig) > $bb_cfg['max_sig_chars']) + { + $errors[] = 'Слишком длинная подпись'; + } + else if (preg_match('#speedtest|vkontakte|danasoft#i', $sig)) + { + $errors[] = 'Подпись нарушает правила'; + } + else if (preg_match('#<(a|b|i|u|table|tr|td|img) #i', $sig) || preg_match('#(href|src|target|title)=#i', $sig)) + { + $errors[] = 'Подпись может содержать только BBCode'; + } + else if ($sig_esc != $pr_data['user_sig']) + { + $pr_data['user_sig'] = $sig_esc; + $db_data['user_sig'] = (string) $sig_esc; + } + } + $tp_data['USER_SIG'] = $pr_data['user_sig']; + break; + + /** + * Род занятий (edit) + */ + case 'user_occ': + $occ = isset($_POST['user_occ']) ? (string) $_POST['user_occ'] : $pr_data['user_occ']; + $occ = htmlCHR($occ); + if ($submit) + { + if ($occ != $pr_data['user_occ']) + { + $pr_data['user_occ'] = $occ; + $db_data['user_occ'] = (string) $occ; + } + } + $tp_data['USER_OCC'] = $pr_data['user_occ']; + break; + + /** + * Интересы + */ + case 'user_interests': + $interests = isset($_POST['user_interests']) ? (string) $_POST['user_interests'] : $pr_data['user_interests']; + $interests = htmlCHR($interests); + if ($submit) + { + if ($interests != $pr_data['user_interests']) + { + $pr_data['user_interests'] = $interests; + $db_data['user_interests'] = (string) $interests; + } + } + $tp_data['USER_INTERESTS'] = $pr_data['user_interests']; + break; + + /** + * default + */ + default: + trigger_error("invalid profile field: $field", E_USER_ERROR); + } +} + +// submit +if ($submit && !$errors) +{ + /** + * Создание нового профиля + */ + if ($mode == 'register') + { + if ($bb_cfg['reg_email_activation']) + { + $db_data['user_active'] = 0; + $user_actkey = make_rand_str(12); + } + else + { + $db_data['user_active'] = 1; + $user_actkey = ''; + } + $db_data['user_regdate'] = time(); + + $sql_args = DB()->build_array('INSERT', $db_data); + + DB()->query("INSERT INTO ". BB_USERS . $sql_args); + $new_user_id = DB()->sql_nextid(); + + if (IS_ADMIN) + { + set_pr_die_append_msg($new_user_id); + $die_msg = "Пользователь $username был успешно создан"; + } + else if ($bb_cfg['reg_email_activation']) + { + $email_sbj = "Добро пожаловать на сайт {$bb_cfg['sitename']}"; + + require(INC_DIR .'emailer.php'); + $emailer = new emailer('user_welcome_inactive', $email_sbj, $email); + + $emailer->assign_vars(array( + 'WELCOME_MSG' => $email_sbj, + 'USERNAME' => html_entity_decode($username), + 'PASSWORD' => $new_pass, + 'U_ACTIVATE' => make_url("profile.php?mode=activate&u=$new_user_id&act_key=$user_actkey"), + )); + $emailer->send(); + + $die_msg = file_get_contents(BB_PATH .'/misc/html/account_inactive.html'); + } + else + { + $die_msg = 'Спасибо за регистрацию, учётная запись была создана

    Вы можете войти в систему, используя ваше имя и пароль'; + } + bb_die($die_msg); + } + /** + * Редактирование + */ + else + { + set_pr_die_append_msg($pr_data['user_id']); + + // если что-то было изменено + if ($db_data) + { + $sql_args = DB()->build_array('UPDATE', $db_data); + + DB()->query("UPDATE ". BB_USERS ." SET $sql_args WHERE user_id = {$pr_data['user_id']} LIMIT 1"); + + if ($pr_data['user_id'] != $user->id) + { + if ($pr_data['user_level'] == MOD && !empty($db_data['username'])) + { + $datastore->update('moderators'); + } + } + + $die_msg = ($adm_edit) ? "Профиль {$pr_data['username']} был успешно изменён" : 'Ваш профиль был успешно изменён'; + bb_die($die_msg); + } + else + { + bb_die('Ничего не было изменено'); + } + } +} + +$template->assign_vars($tp_data); + + + +$template->assign_vars(array( + 'PAGE_TITLE' => ($mode == 'editprofile') ? 'Редактирование профиля'. ($adm_edit ? " :: {$pr_data['username']}" : '') : 'Регистрация', + 'SHOW_REG_AGREEMENT' => ($mode == 'register' && !IS_ADMIN), + 'ERROR_MESSAGE' => ($errors) ? join('
    ', $errors) : '', + 'MODE' => $mode, + 'EDIT_PROFILE' => ($mode == 'editprofile'), + 'ADM_EDIT' => $adm_edit, + 'SHOW_PASS' => ($adm_edit || ($mode == 'register' && IS_ADMIN)), + 'CAPTCHA_HTML' => ($need_captcha) ? CAPTCHA()->get_html() : '', + + 'TIMEZONE_SELECT' => tz_select($user_timezone, 'user_timezone'), + + + 'PR_USER_ID' => $pr_data['user_id'], + 'U_RESET_AUTOLOGIN' => "login.php?logout=1&reset_autologin=1&sid={$userdata['session_id']}", + +)); + +//bt +if ($mode == 'editprofile' && $userdata['session_logged_in']) +{ + $template->assign_block_vars('switch_bittorrent', array()); + + $sql = 'SELECT auth_key + FROM '. BB_BT_USERS .' + WHERE user_id = '. $userdata['user_id']; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not query users passkey', '', __LINE__, __FILE__, $sql); + } + + $row = DB()->sql_fetchrow($result); + $curr_passkey = ($row['auth_key']) ? $row['auth_key'] : ''; + + $template->assign_vars(array( + 'L_GEN_PASSKEY' => $lang['BT_GEN_PASSKEY'], + 'L_GEN_PASSKEY_EXPLAIN' => $lang['BT_GEN_PASSKEY_EXPLAIN'], + 'L_GEN_PASSKEY_EXPLAIN_2' => $lang['BT_GEN_PASSKEY_EXPLAIN_2'], + 'S_GEN_PASSKEY' => "' . $lang['BT_GEN_PASSKEY_URL'] . '', + 'CURR_PASSKEY' => $curr_passkey, + )); +} +//bt end + +function set_pr_die_append_msg ($pr_uid) +{ + global $template; + + $template->assign_var('BB_DIE_APPEND_MSG', ' + Перейти к просмотру профиля +

    + Вернуться к редактированию +

    + Вернуться на главную страницу + '); +} + + +print_page('usercp_register.tpl'); \ No newline at end of file diff --git a/upload/includes/ucp/usercp_sendpasswd.php b/upload/includes/ucp/usercp_sendpasswd.php new file mode 100644 index 000000000..04276963b --- /dev/null +++ b/upload/includes/ucp/usercp_sendpasswd.php @@ -0,0 +1,99 @@ +sql_query($sql) ) + { + if ( $row = DB()->sql_fetchrow($result) ) + { + if (!$row['user_active']) + { + bb_die($lang['NO_SEND_ACCOUNT_INACTIVE']); + } + if (in_array($row['user_level'], array(MOD, ADMIN))) + { + bb_die($lang['NO_SEND_ACCOUNT']); + } + + $username = $row['username']; + $user_id = $row['user_id']; + + $user_actkey = make_rand_str(12); + $user_password = make_rand_str(8); + + $sql = "UPDATE " . BB_USERS . " + SET user_newpasswd = '" . md5($user_password) . "', user_actkey = '$user_actkey' + WHERE user_id = " . $row['user_id']; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update new password information', '', __LINE__, __FILE__, $sql); + } + + include(INC_DIR . 'emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('user_activate_passwd', $row['user_lang']); + $emailer->email_address($row['user_email']); + $emailer->set_subject($lang['NEW_PASSWORD_ACTIVATION']); + + $emailer->assign_vars(array( + 'SITENAME' => $bb_cfg['sitename'], + 'USERNAME' => $username, + 'PASSWORD' => $user_password, + 'EMAIL_SIG' => (!empty($bb_cfg['board_email_sig'])) ? str_replace('
    ', "\n", "-- \n" . $bb_cfg['board_email_sig']) : '', + + 'U_ACTIVATE' => $server_url . '?mode=activate&' . POST_USERS_URL . '=' . $user_id . '&act_key=' . $user_actkey) + ); + $emailer->send(); + $emailer->reset(); + + $message = $lang['PASSWORD_UPDATED'] . '

    ' . sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + } + else + { + message_die(GENERAL_MESSAGE, $lang['NO_EMAIL_MATCH']); + } + } + else + { + message_die(GENERAL_ERROR, 'Could not obtain user information for sendpassword', '', __LINE__, __FILE__, $sql); + } +} +else +{ + $username = ''; + $email = ''; +} + +$template->assign_vars(array( + 'USERNAME' => $username, + 'EMAIL' => $email, + + 'S_HIDDEN_FIELDS' => '', + 'S_PROFILE_ACTION' => append_sid("profile.php?mode=sendpassword")) +); + +print_page('usercp_sendpasswd.tpl'); diff --git a/upload/includes/ucp/usercp_viewprofile.php b/upload/includes/ucp/usercp_viewprofile.php new file mode 100644 index 000000000..d2340b90b --- /dev/null +++ b/upload/includes/ucp/usercp_viewprofile.php @@ -0,0 +1,213 @@ +enqueue(array( + 'ranks', +)); + +if (!$userdata['session_logged_in']) +{ + redirect(append_sid("login.php?redirect={$_SERVER['REQUEST_URI']}", TRUE)); +} +if ( empty($_GET[POST_USERS_URL]) || $_GET[POST_USERS_URL] == ANONYMOUS ) +{ + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED']); +} +$profiledata = get_userdata($_GET[POST_USERS_URL]); + +if (!$profiledata) +{ + message_die(GENERAL_MESSAGE, $lang['NO_USER_ID_SPECIFIED']); +} + +// +// Calculate the number of days this user has been a member ($memberdays) +// Then calculate their posts per day +// +$regdate = $profiledata['user_regdate']; +$memberdays = max(1, round( ( time() - $regdate ) / 86400 )); +$posts_per_day = $profiledata['user_posts'] / $memberdays; + +// Get the users percentage of total posts +if ( $profiledata['user_posts'] != 0 ) +{ + $total_posts = get_db_stat('postcount'); + $percentage = ( $total_posts ) ? min(100, ($profiledata['user_posts'] / $total_posts) * 100) : 0; +} +else +{ + $percentage = 0; +} +$avatar_img = ''; +$avatar_img = get_avatar($profiledata['user_avatar'], $profiledata['user_avatar_type'], $profiledata['user_allowavatar']); + +if (!$ranks = $datastore->get('ranks')) +{ + $datastore->update('ranks'); + $ranks = $datastore->get('ranks'); +} +$poster_rank = $rank_image = ''; + +if ($user_rank = $profiledata['user_rank'] AND isset($ranks[$user_rank])) +{ + $rank_image = ($ranks[$user_rank]['rank_image']) ? '' : ''; + $poster_rank = $ranks[$user_rank]['rank_title']; +} + +$temp_url = append_sid("privmsg.php?mode=post&" . POST_USERS_URL . "=" . $profiledata['user_id']); +$pm_img = '' . $lang['SEND_PRIVATE_MESSAGE'] . ''; + +$location = ($profiledata['user_from']) ? $profiledata['user_from'] : ''; +$location .= ($profiledata['user_from_flag'] && $profiledata['user_from_flag'] != 'blank.gif') ? ' '. make_user_flag($profiledata['user_from_flag']) : ''; + +$pm = '' . $lang['SEND_PRIVATE_MESSAGE'] . ''; + +if ( bf($profiledata['user_opt'], 'user_opt', 'viewemail') || IS_ADMIN ) +{ + $email_uri = ( $bb_cfg['board_email_form'] ) ? append_sid("profile.php?mode=email&" . POST_USERS_URL .'=' . $profiledata['user_id']) : 'mailto:' . $profiledata['user_email']; + $email_img = '' . $lang['SEND_EMAIL'] . ''; + $email = '' . $lang['SEND_EMAIL'] . ''; +} +else +{ + $email_img = ''; + $email = ''; +} +$www_img = ( $profiledata['user_website'] ) ? '' . $lang['VISIT_WEBSITE'] . '' : ''; +$www = ( $profiledata['user_website'] ) ? '' . $profiledata['user_website'] . '' : ''; +if ( !empty($profiledata['user_icq']) ) +{ + $icq_status_img = ''; + $icq_img = '' . $lang['ICQ'] . ''; + $icq = '' . $profiledata['user_icq'] . ''; +} +else +{ + $icq_status_img = ''; + $icq_img = ''; + $icq = ''; +} +$temp_url = append_sid("search.php?search_author=1&uid={$profiledata['user_id']}"); +$search_img = '' . $lang['SEARCH_USER_POSTS'] . ''; +$search = '' . sprintf($lang['SEARCH_USER_POSTS'], $profiledata['username']) . ''; + +// Report +// +// Get report user module and create report link +// +include(INC_DIR . "functions_report.php"); +$report_user = report_modules('name', 'report_user'); + +if ($report_user && $report_user->auth_check('auth_write')) +{ + $template->assign_block_vars('switch_report_user', array()); + $template->assign_vars(array( + 'U_REPORT_USER' => append_sid("report.php?mode=" . $report_user->mode . '&id=' . $profiledata['user_id']), + 'L_REPORT_USER' => $report_user->lang['WRITE_REPORT']) + ); +} +// Report [END] + +// +// Generate page +// +if ($profiledata['user_id'] == $userdata['user_id'] || IS_ADMIN) +{ + require(BB_ROOT .'attach_mod/attachment_mod.php'); + display_upload_attach_box_limits($profiledata['user_id']); +} + +// IP Mod (c) Pandora +// Не админ у админа инфу смотреть не может +if ($profiledata['user_level'] == ADMIN && !IS_ADMIN) +{ + $reg_ip = $last_ip = 'скрыт'; +// Модератор у модератора, ИП не может смотерть (шифруемся) +} elseif ($profiledata['user_level'] == MOD && IS_MOD) +{ + $reg_ip = $last_ip = 'скрыт'; +// В иных случаях может +} else { + $reg_ip = decode_ip($profiledata['user_reg_ip']); + $last_ip = decode_ip($profiledata['user_last_ip']); +} +// IP Mod End + +$template->assign_vars(array( + 'PAGE_TITLE' => sprintf($lang['VIEWING_USER_PROFILE'], $profiledata['username']), + 'USERNAME' => $profiledata['username'], + 'PROFILE_USER_ID' => $profiledata['user_id'], + 'USER_REGDATE' => bb_date($profiledata['user_regdate']), + 'POSTER_RANK' => $poster_rank, + 'RANK_IMAGE' => $rank_image, + 'POSTS_PER_DAY' => $posts_per_day, + 'POSTS' => $profiledata['user_posts'], + 'PERCENTAGE' => $percentage . '%', + 'POST_DAY_STATS' => sprintf($lang['USER_POST_DAY_STATS'], $posts_per_day), + 'POST_PERCENT_STATS' => sprintf($lang['USER_POST_PCT_STATS'], $percentage), + 'SEARCH_IMG' => $search_img, + 'SEARCH' => $search, + 'PM_IMG' => $pm_img, + 'PM' => $pm, + 'EMAIL_IMG' => $email_img, + 'EMAIL' => $email, + 'WWW_IMG' => $www_img, + 'WWW' => $www, + 'ICQ_STATUS_IMG' => $icq_status_img, + 'ICQ_IMG' => $icq_img, + 'ICQ' => $icq, + 'LAST_VISIT_TIME' => ($profiledata['user_lastvisit']) ? bb_date($profiledata['user_lastvisit']) : $lang['NEVER'], + 'LAST_ACTIVITY_TIME' => ($profiledata['user_session_time']) ? bb_date($profiledata['user_session_time']) : $lang['NEVER'], + 'LOCATION' => $location, + + 'REG_IP' => $reg_ip, + 'LAST_IP' => $last_ip, + + 'USER_ACTIVE' => $profiledata['user_active'], + + 'OCCUPATION' => ( $profiledata['user_occ'] ) ? $profiledata['user_occ'] : '', + 'INTERESTS' => ( $profiledata['user_interests'] ) ? $profiledata['user_interests'] : '', + 'AVATAR_IMG' => $avatar_img, + + 'L_VIEWING_PROFILE' => sprintf($lang['VIEWING_USER_PROFILE'], $profiledata['username']), + 'L_ABOUT_USER_PROFILE' => sprintf($lang['ABOUT_USER'], $profiledata['username']), + 'L_SEARCH_USER_POSTS_PROFILE' => sprintf($lang['SEARCH_USER_POSTS'], ''. $profiledata['username'] .''), + + 'U_SEARCH_USER' => "search.php?search_author=1&uid={$profiledata['user_id']}", + 'U_SEARCH_TOPICS' => "search.php?uid={$profiledata['user_id']}&myt=1", + 'U_SEARCH_RELEASES' => "tracker.php?rid={$profiledata['user_id']}#results", + 'L_SEARCH_RELEASES' => $lang['SEARCH_USER_RELEASES'], + + 'S_PROFILE_ACTION' => "profile.php", +)); + +//bt +// Show users torrent-profile +define('IN_VIEWPROFILE', TRUE); +include(INC_DIR .'ucp/torrent_userprofile.php'); +//bt end + +$template->assign_vars(array( + 'SHOW_ACCESS_PRIVILEGE' => IS_ADMIN, + 'L_ACCESS' => $lang['ACCESS'], + 'L_ACCESS_SRV_LOAD' => $lang['ACCESS_SRV_LOAD'], + 'IGNORE_SRV_LOAD' => ($profiledata['user_level'] != USER || $profiledata['ignore_srv_load']) ? $lang['NO'] : $lang['YES'], + 'IGNORE_SRV_LOAD_EDIT' => ($profiledata['user_level'] == USER), +)); + +if (IS_ADMIN) +{ + $template->assign_vars(array( + 'EDITABLE_TPLS' => true, + + 'U_MANAGE' => "admin/admin_users.php?mode=edit&u={$profiledata['user_id']}", + 'U_PERMISSIONS' => "admin/admin_ug_auth.php?mode=user&u={$profiledata['user_id']}", + )); +} + +print_page('usercp_viewprofile.tpl'); diff --git a/upload/index.php b/upload/index.php new file mode 100644 index 000000000..876984f05 --- /dev/null +++ b/upload/index.php @@ -0,0 +1,354 @@ +enqueue(array( + 'stats', + 'moderators', +)); +if ($bb_cfg['show_latest_news']) +{ + $datastore->enqueue('latest_news'); +} + +// Init userdata +$user->session_start(); + +// Init main vars +$viewcat = isset($_GET['c']) ? (int) $_GET['c'] : 0; +$lastvisit = (IS_GUEST) ? TIMENOW : $userdata['user_lastvisit']; + +// Caching output +$req_page = 'index_page'; +$req_page .= ($viewcat) ? "_c{$viewcat}" : ''; + +define('REQUESTED_PAGE', $req_page); +caching_output(IS_GUEST, 'send', REQUESTED_PAGE .'_guest'); + +// Topics read tracks +$tracking_topics = get_tracks('topic'); +$tracking_forums = get_tracks('forum'); + +// Statistics +if (!$stats = $datastore->get('stats')) +{ + $datastore->update('stats'); + $stats = $datastore->get('stats'); +} + +// Forums data +if (!$forums = $datastore->get('cat_forums')) +{ + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); +} +$cat_title_html = $forums['cat_title_html']; +$forum_name_html = $forums['forum_name_html']; + +$anon = ANONYMOUS; +$excluded_forums_csv = $user->get_excluded_forums(AUTH_VIEW); +$only_new = $user->opt_js['only_new']; + +// Validate requested category id +if ($viewcat AND !$viewcat =& $forums['c'][$viewcat]['cat_id']) +{ + redirect("index.php"); +} +// Forums +$forums_join_sql = 'f.cat_id = c.cat_id'; +$forums_join_sql .= ($viewcat) ? " + AND f.cat_id = $viewcat +" : ''; +$forums_join_sql .= ($excluded_forums_csv) ? " + AND f.forum_id NOT IN($excluded_forums_csv) + AND f.forum_parent NOT IN($excluded_forums_csv) +" : ''; + +// Posts +$posts_join_sql = "p.post_id = f.forum_last_post_id"; +$posts_join_sql .= ($only_new == ONLY_NEW_POSTS) ? " + AND p.post_time > $lastvisit +" : ''; +$join_p_type = ($only_new == ONLY_NEW_POSTS) ? 'INNER JOIN' : 'LEFT JOIN'; + +// Topics +$topics_join_sql = "t.topic_last_post_id = p.post_id"; +$topics_join_sql .= ($only_new == ONLY_NEW_TOPICS) ? " + AND t.topic_time > $lastvisit +" : ''; +$join_t_type = ($only_new == ONLY_NEW_TOPICS) ? 'INNER JOIN' : 'LEFT JOIN'; + +$sql = " + SELECT SQL_CACHE + f.cat_id, f.forum_id, f.forum_status, f.forum_parent, f.show_on_index, + p.post_id AS last_post_id, p.post_time AS last_post_time, + t.topic_id AS last_topic_id, t.topic_title AS last_topic_title, + u.user_id AS last_post_user_id, + IF(p.poster_id = $anon, p.post_username, u.username) AS last_post_username + FROM ". BB_CATEGORIES ." c + INNER JOIN ". BB_FORUMS ." f ON($forums_join_sql) + $join_p_type ". BB_POSTS ." p ON($posts_join_sql) + $join_t_type ". BB_TOPICS ." t ON($topics_join_sql) + LEFT JOIN ". BB_USERS ." u ON(u.user_id = p.poster_id) + ORDER BY c.cat_order, f.forum_order +"; +$cat_forums = array(); + +$replace_in_parent = array( + 'last_post_id', + 'last_post_time', + 'last_post_user_id', + 'last_post_username', + 'last_topic_title', + 'last_topic_id', +); + +foreach (DB()->fetch_rowset($sql) as $row) +{ + if (!$cat_id = $row['cat_id'] OR !$forum_id = $row['forum_id']) + { + continue; + } + + if ($parent_id = $row['forum_parent']) + { + if (!$parent =& $cat_forums[$cat_id]['f'][$parent_id]) + { + $parent = $forums['f'][$parent_id]; + $parent['last_post_time'] = 0; + } + if ($row['last_post_time'] > $parent['last_post_time']) + { + foreach ($replace_in_parent as $key) + { + $parent[$key] = $row[$key]; + } + } + if ($show_subforums && $row['show_on_index']) + { + $parent['last_sf_id'] = $forum_id; + } + else + { + continue; + } + } + else + { + $f =& $forums['f'][$forum_id]; + $row['forum_desc'] = $f['forum_desc']; + $row['forum_posts'] = $f['forum_posts']; + $row['forum_topics'] = $f['forum_topics']; + } + + $cat_forums[$cat_id]['f'][$forum_id] = $row; +} +unset($forums); +$datastore->rm('cat_forums'); + +// Obtain list of moderators +$moderators = array(); +if (!$mod = $datastore->get('moderators')) +{ + $datastore->update('moderators'); + $mod = $datastore->get('moderators'); +} + +if (!empty($mod)) +{ + foreach ($mod['mod_users'] as $forum_id => $user_ids) + { + foreach ($user_ids as $user_id) + { + $moderators[$forum_id][] = ''. $mod['name_users'][$user_id] .''; + } + } + foreach ($mod['mod_groups'] as $forum_id => $group_ids) + { + foreach ($group_ids as $group_id) + { + $moderators[$forum_id][] = ''. $mod['name_groups'][$group_id] .''; + } + } +} + +unset($mod); +$datastore->rm('moderators'); + +if (!$forums_count = count($cat_forums) AND $viewcat) +{ + redirect("index.php"); +} + +$template->assign_vars(array( + 'SHOW_FORUMS' => $forums_count, + 'PAGE_TITLE' => $lang['INDEX'], + 'NO_FORUMS_MSG' => ($only_new) ? $lang['NO_NEW_POSTS'] : $lang['NO_FORUMS'], + + 'TOTAL_TOPICS' => sprintf($lang['POSTED_TOPICS_TOTAL'], $stats['topiccount']), + 'TOTAL_POSTS' => sprintf($lang['POSTED_ARTICLES_TOTAL'], $stats['postcount']), + 'TOTAL_USERS' => sprintf($lang['REGISTERED_USERS_TOTAL'], $stats['usercount']), + 'NEWEST_USER' => sprintf($lang['NEWEST_USER'], '', $stats['newestuser']['username'], ''), + + // Tracker stats + 'TORRENTS_STAT' => sprintf($lang['TORRENTS_STAT'], $stats['torrentcount'], humn_size($stats['size'])), + 'PEERS_STAT' => sprintf($lang['PEERS_STAT'], $stats['peers'], $stats['seeders'], $stats['leechers']), + 'SPEED_STAT' => sprintf($lang['SPEED_STAT'], humn_size($stats['speed']) .'/s'), + + 'FORUM_IMG' => $images['forum'], + 'FORUM_NEW_IMG' => $images['forum_new'], + 'FORUM_LOCKED_IMG' => $images['forum_locked'], + + 'SHOW_ONLY_NEW_MENU' => true, + 'ONLY_NEW_POSTS_ON' => ($only_new == ONLY_NEW_POSTS), + 'ONLY_NEW_TOPICS_ON' => ($only_new == ONLY_NEW_TOPICS), + + 'U_SEARCH_NEW' => "search.php?new=1", + 'U_SEARCH_SELF_BY_MY' => "search.php?uid={$userdata['user_id']}&o=1", + 'U_SEARCH_LATEST' => "search.php?search_id=latest", + 'U_SEARCH_UNANSWERED' => "search.php?search_id=unanswered", + + 'SHOW_LAST_TOPIC' => $show_last_topic, +)); + +// Build index page +foreach ($cat_forums as $cid => $c) +{ + $template->assign_block_vars('c', array( + 'CAT_ID' => $cid, + 'CAT_TITLE' => $cat_title_html[$cid], + 'U_VIEWCAT' => "index.php?c=$cid", + )); + + foreach ($c['f'] as $fid => $f) + { + if (!$fname_html =& $forum_name_html[$fid]) + { + continue; + } + $is_sf = $f['forum_parent']; + + $new = is_unread($f['last_post_time'], $f['last_topic_id'], $f['forum_id']) ? '_new' : ''; + $folder_image = ($is_sf) ? $images["icon_minipost{$new}"] : $images["forum{$new}"]; + + if ($f['forum_status'] == FORUM_LOCKED) + { + $folder_image = ($is_sf) ? $images['icon_minipost'] : $images['forum_locked']; + } + + if ($is_sf) + { + $template->assign_block_vars('c.f.sf', array( + 'SF_ID' => $fid, + 'SF_NAME' => $fname_html, + 'SF_NEW' => $new ? ' new' : '', + )); + continue; + } + + $template->assign_block_vars('c.f', array( + 'FORUM_FOLDER_IMG' => $folder_image, + + 'FORUM_ID' => $fid, + 'FORUM_NAME' => $fname_html, + 'FORUM_DESC' => $f['forum_desc'], + 'POSTS' => commify($f['forum_posts']), + 'TOPICS' => commify($f['forum_topics']), + 'LAST_SF_ID' => isset($f['last_sf_id']) ? $f['last_sf_id'] : null, + + 'MODERATORS' => isset($moderators[$fid]) ? join(', ', $moderators[$fid]) : '', + 'FORUM_FOLDER_ALT' => ($new) ? 'new' : 'old', + )); + + if ($f['last_post_id']) + { + $template->assign_block_vars('c.f.last', array( + 'LAST_TOPIC_ID' => $f['last_topic_id'], + 'LAST_TOPIC_TIP' => $f['last_topic_title'], + 'LAST_TOPIC_TITLE' => wbr(str_short($f['last_topic_title'], $last_topic_max_len)), + + 'LAST_POST_TIME' => bb_date($f['last_post_time'], $bb_cfg['last_post_date_format']), + 'LAST_POST_USER_ID' => ($f['last_post_user_id'] != ANONYMOUS) ? $f['last_post_user_id'] : false, + 'LAST_POST_USER_NAME' => ($f['last_post_username']) ? str_short($f['last_post_username'], 15) : $lang['GUEST'], + )); + } + } +} + +// Set tpl vars for bt_userdata +if ($bb_cfg['bt_show_dl_stat_on_index'] && !IS_GUEST) +{ + show_bt_userdata($userdata['user_id']); +} + +// Latest news +if ($bb_cfg['show_latest_news']) +{ + if (!$latest_news = $datastore->get('latest_news')) + { + $datastore->update('latest_news'); + $latest_news = $datastore->get('latest_news'); + } + + $template->assign_vars(array( + 'SHOW_LATEST_NEWS' => true, + )); + + foreach ($latest_news as $news) + { + $template->assign_block_vars('news', array( + 'NEWS_TOPIC_ID' => $news['topic_id'], + 'NEWS_TITLE' => $news['topic_title'], + 'NEWS_TIME' => bb_date($news['topic_time'], 'd-M'), + 'NEWS_IS_NEW' => $news['topic_time'] > $lastvisit, + )); + } +} +// Allow cron +if (IS_ADMIN || IS_MOD) +{ + if (@file_exists(CRON_RUNNING)) { + if (@file_exists(CRON_ALLOWED)) + { + unlink (CRON_ALLOWED); + } + rename(CRON_RUNNING, CRON_ALLOWED); + } +} + +// Display page +define('SHOW_ONLINE', $show_online_users); + +print_page('index.tpl'); diff --git a/upload/language/.htaccess b/upload/language/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_english/.htaccess b/upload/language/lang_english/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/lang_english/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_english/email/.htaccess b/upload/language/lang_english/email/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/lang_english/email/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_english/email/admin_activate.tpl b/upload/language/lang_english/email/admin_activate.tpl new file mode 100644 index 000000000..e5bf095e5 --- /dev/null +++ b/upload/language/lang_english/email/admin_activate.tpl @@ -0,0 +1,10 @@ +Subject: New user account +Charset: UTF-8 + +Hello, + +The account owned by "{USERNAME}" has been deactivated or newly created, you should check the details of this user (if required) and activate it using the following link: + +{U_ACTIVATE} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/admin_send_email.tpl b/upload/language/lang_english/email/admin_send_email.tpl new file mode 100644 index 000000000..d092ee52e --- /dev/null +++ b/upload/language/lang_english/email/admin_send_email.tpl @@ -0,0 +1,12 @@ +Charset: UTF-8 + +The following is an email sent to you by an administrator of "{SITENAME}". If this message is spam, contains abusive or other comments you find offensive please contact the webmaster of the board at the following address: + +{BOARD_EMAIL} + +Include this full email (particularly the headers). + +Message sent to you follows: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +{MESSAGE} diff --git a/upload/language/lang_english/email/admin_welcome_activated.tpl b/upload/language/lang_english/email/admin_welcome_activated.tpl new file mode 100644 index 000000000..9ef91ee7e --- /dev/null +++ b/upload/language/lang_english/email/admin_welcome_activated.tpl @@ -0,0 +1,8 @@ +Subject: Account Activated +Charset: UTF-8 + +Hello {USERNAME}, + +Your account on "{SITENAME}" has now been activated, you may login using the username and password you received in a previous email. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/admin_welcome_inactive.tpl b/upload/language/lang_english/email/admin_welcome_inactive.tpl new file mode 100644 index 000000000..37ff793c5 --- /dev/null +++ b/upload/language/lang_english/email/admin_welcome_inactive.tpl @@ -0,0 +1,19 @@ +Subject: Welcome to {SITENAME} Forums +Charset: UTF-8 + +{WELCOME_MSG} + +Please keep this email for your records. Your account information is as follows: + +---------------------------- +Username: {USERNAME} +Password: {PASSWORD} +---------------------------- + +Your account is currently inactive, the administrator of the board will need to activate it before you can log in. You will receive another email when this has occured. + +Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. + +Thank you for registering. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/blank.tpl b/upload/language/lang_english/email/blank.tpl new file mode 100644 index 000000000..9f6da3253 --- /dev/null +++ b/upload/language/lang_english/email/blank.tpl @@ -0,0 +1 @@ +{MESSAGE} \ No newline at end of file diff --git a/upload/language/lang_english/email/group_added.tpl b/upload/language/lang_english/email/group_added.tpl new file mode 100644 index 000000000..7ee9fe534 --- /dev/null +++ b/upload/language/lang_english/email/group_added.tpl @@ -0,0 +1,12 @@ +Subject: You have been added to this usergroup +Charset: UTF-8 + +Congratulations, + +You have been added to the "{GROUP_NAME}" group on {SITENAME}. +This action was done by the group moderator or the site administrator, contact them for more information. + +You can view your groups information here: +{U_GROUPCP} + +{EMAIL_SIG} diff --git a/upload/language/lang_english/email/group_approved.tpl b/upload/language/lang_english/email/group_approved.tpl new file mode 100644 index 000000000..cbcfbf56d --- /dev/null +++ b/upload/language/lang_english/email/group_approved.tpl @@ -0,0 +1,11 @@ +Subject: Your request has been approved +Charset: UTF-8 + +Congratulations, + +Your request to join the "{GROUP_NAME}" group on {SITENAME} has been approved. +Click on the following link to see your group membership. + +{U_GROUPCP} + +{EMAIL_SIG} diff --git a/upload/language/lang_english/email/group_request.tpl b/upload/language/lang_english/email/group_request.tpl new file mode 100644 index 000000000..21d21abf6 --- /dev/null +++ b/upload/language/lang_english/email/group_request.tpl @@ -0,0 +1,11 @@ +Subject: A request to join your group has been made +Charset: UTF-8 + +Dear {GROUP_MODERATOR}, + +A user {USER} has requested to join a group you moderator on {SITENAME}. +To approve or deny this request for group membership please visit the following link: + +{U_GROUPCP} + +{EMAIL_SIG} diff --git a/upload/language/lang_english/email/privmsg_notify.tpl b/upload/language/lang_english/email/privmsg_notify.tpl new file mode 100644 index 000000000..601006024 --- /dev/null +++ b/upload/language/lang_english/email/privmsg_notify.tpl @@ -0,0 +1,12 @@ +Subject: New Private Message has arrived +Charset: UTF-8 + +Hello {USERNAME}, + +You have received a new private message to your account on "{SITENAME}" and you have requested that you be notified on this event. You can view your new message by clicking on the following link: + +{U_INBOX} + +Remember that you can always choose not to be notified of new messages by changing the appropriate setting in your profile. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/profile_send_email.tpl b/upload/language/lang_english/email/profile_send_email.tpl new file mode 100644 index 000000000..b98c70758 --- /dev/null +++ b/upload/language/lang_english/email/profile_send_email.tpl @@ -0,0 +1,14 @@ +Charset: UTF-8 + +Hello {TO_USERNAME}, + +The following is an email sent to you by {FROM_USERNAME} via your account on {SITENAME}. If this message is spam, contains abusive or other comments you find offensive please contact the webmaster of the board at the following address: + +{BOARD_EMAIL} + +Include this full email (particularly the headers). Please note that the reply address to this email has been set to that of {FROM_USERNAME}. + +Message sent to you follows +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +{MESSAGE} diff --git a/upload/language/lang_english/email/topic_notify.tpl b/upload/language/lang_english/email/topic_notify.tpl new file mode 100644 index 000000000..564be8d00 --- /dev/null +++ b/upload/language/lang_english/email/topic_notify.tpl @@ -0,0 +1,14 @@ +Subject: Topic Reply Notification - {TOPIC_TITLE} +Charset: UTF-8 + +Hello, + +You are receiving this email because you are watching the topic, "{TOPIC_TITLE}" at {SITENAME}. This topic has received a reply since your last visit. You can use the following link to view the replies made, no more notifications will be sent until you visit the topic. + +{U_TOPIC} + +If you no longer wish to watch this topic you can either click the "Stop watching this topic link" found at the bottom of the topic above, or by clicking the following link: + +{U_STOP_WATCHING_TOPIC} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/user_activate.tpl b/upload/language/lang_english/email/user_activate.tpl new file mode 100644 index 000000000..1133e4a39 --- /dev/null +++ b/upload/language/lang_english/email/user_activate.tpl @@ -0,0 +1,10 @@ +Subject: Reactivate your account +Charset: UTF-8 + +Hello {USERNAME}, + +Your account on "{SITENAME}" has been deactivated, most likely due to changes made to your profile. In order to reactivate your account you must click on the link below: + +{U_ACTIVATE} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/user_activate_passwd.tpl b/upload/language/lang_english/email/user_activate_passwd.tpl new file mode 100644 index 000000000..a8ea43877 --- /dev/null +++ b/upload/language/lang_english/email/user_activate_passwd.tpl @@ -0,0 +1,18 @@ +Subject: New password activation +Charset: UTF-8 + +Hello {USERNAME} + +You are receiving this email because you have (or someone pretending to be you has) requested a new password be sent for your account on {SITENAME}. If you did not request this email then please ignore it, if you keep receiving it please contact the board administrator. + +To use the new password you need to activate it. To do this click the link provided below. + +{U_ACTIVATE} + +If sucessful you will be able to login using the following password: + +Password: {PASSWORD} + +You can of course change this password yourself via the profile page. If you have any difficulties please contact the board administrator. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/user_welcome.tpl b/upload/language/lang_english/email/user_welcome.tpl new file mode 100644 index 000000000..c7eff38a5 --- /dev/null +++ b/upload/language/lang_english/email/user_welcome.tpl @@ -0,0 +1,17 @@ +Subject: Welcome to {SITENAME} Forums +Charset: UTF-8 + +{WELCOME_MSG} + +Please keep this email for your records. Your account information is as follows: + +---------------------------- +Username: {USERNAME} +Password: {PASSWORD} +---------------------------- + +Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. + +Thank you for registering. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/email/user_welcome_inactive.tpl b/upload/language/lang_english/email/user_welcome_inactive.tpl new file mode 100644 index 000000000..61851ae9f --- /dev/null +++ b/upload/language/lang_english/email/user_welcome_inactive.tpl @@ -0,0 +1,21 @@ +Subject: Welcome to {SITENAME} Forums +Charset: UTF-8 + +{WELCOME_MSG} + +Please keep this email for your records. Your account information is as follows: + +---------------------------- +Username: {USERNAME} +Password: {PASSWORD} +---------------------------- + +Your account is currently inactive. You cannot use it until you visit the following link: + +{U_ACTIVATE} + +Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. + +Thank you for registering. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_english/lang_admin.php b/upload/language/lang_english/lang_admin.php new file mode 100644 index 000000000..d51b1f1f6 --- /dev/null +++ b/upload/language/lang_english/lang_admin.php @@ -0,0 +1,677 @@ +sticky topics and announcements. You will need to remove those topics manually.'; +$lang['DO_PRUNE'] = 'Do Prune'; +$lang['ALL_FORUMS'] = 'All Forums'; +$lang['PRUNE_TOPICS_NOT_POSTED'] = 'Prune topics with no replies in this many days'; +$lang['TOPICS_PRUNED'] = 'Topics pruned'; +$lang['POSTS_PRUNED'] = 'Posts pruned'; +$lang['PRUNE_SUCCESS'] = 'Pruning of forums was successful'; + + +// +// Word censor +// +$lang['WORDS_TITLE'] = 'Word Censoring'; +$lang['WORDS_EXPLAIN'] = 'From this control panel you can add, edit, and remove words that will be automatically censored on your forums. In addition people will not be allowed to register with usernames containing these words. Wildcards (*) are accepted in the word field. For example, *test* will match detestable, test* would match testing, *test would match detest.'; +$lang['WORD'] = 'Word'; +$lang['EDIT_WORD_CENSOR'] = 'Edit word censor'; +$lang['REPLACEMENT'] = 'Replacement'; +$lang['ADD_NEW_WORD'] = 'Add new word'; +$lang['UPDATE_WORD'] = 'Update word censor'; + +$lang['MUST_ENTER_WORD'] = 'You must enter a word and its replacement'; +$lang['NO_WORD_SELECTED'] = 'No word selected for editing'; + +$lang['WORD_UPDATED'] = 'The selected word censor has been successfully updated'; +$lang['WORD_ADDED'] = 'The word censor has been successfully added'; +$lang['WORD_REMOVED'] = 'The selected word censor has been successfully removed'; + +$lang['CLICK_RETURN_WORDADMIN'] = 'Click %sHere%s to return to Word Censor Administration'; + + +// +// Mass Email +// +$lang['MASS_EMAIL_EXPLAIN'] = 'Here you can email a message to either all of your users or all users of a specific group. To do this, an email will be sent out to the administrative email address supplied, with a blind carbon copy sent to all recipients. If you are emailing a large group of people please be patient after submitting and do not stop the page halfway through. It is normal for a mass emailing to take a long time and you will be notified when the script has completed'; +$lang['COMPOSE'] = 'Compose'; + +$lang['RECIPIENTS'] = 'Recipients'; +$lang['ALL_USERS'] = 'All Users'; + +$lang['EMAIL_SUCCESSFULL'] = 'Your message has been sent'; +$lang['CLICK_RETURN_MASSEMAIL'] = 'Click %sHere%s to return to the Mass Email form'; + + +// +// Ranks admin +// +$lang['RANKS_TITLE'] = 'Rank Administration'; +$lang['RANKS_EXPLAIN'] = 'Using this form you can add, edit, view and delete ranks. You can also create custom ranks which can be applied to a user via the user management facility'; + +$lang['ADD_NEW_RANK'] = 'Add new rank'; + +$lang['RANK_TITLE'] = 'Rank Title'; +$lang['RANK_SPECIAL'] = 'Set as Special Rank'; +$lang['RANK_MINIMUM'] = 'Minimum Posts'; +$lang['RANK_MAXIMUM'] = 'Maximum Posts'; +$lang['RANK_IMAGE'] = 'Rank Image (Relative to phpBB2 root path)'; +$lang['RANK_IMAGE_EXPLAIN'] = 'Use this to define a small image associated with the rank'; + +$lang['MUST_SELECT_RANK'] = 'You must select a rank'; +$lang['NO_ASSIGNED_RANK'] = 'No special rank assigned'; + +$lang['RANK_UPDATED'] = 'The rank was successfully updated'; +$lang['RANK_ADDED'] = 'The rank was successfully added'; +$lang['RANK_REMOVED'] = 'The rank was successfully deleted'; +$lang['NO_UPDATE_RANKS'] = 'The rank was successfully deleted. However, user accounts using this rank were not updated. You will need to manually reset the rank on these accounts'; + +$lang['CLICK_RETURN_RANKADMIN'] = 'Click %sHere%s to return to Rank Administration'; + +// +// Disallow Username Admin +// +$lang['DISALLOW_CONTROL'] = 'Username Disallow Control'; +$lang['DISALLOW_EXPLAIN'] = 'Here you can control usernames which will not be allowed to be used. Disallowed usernames are allowed to contain a wildcard character of *. Please note that you will not be allowed to specify any username that has already been registered. You must first delete that name then disallow it.'; + +$lang['DELETE_DISALLOW'] = 'Delete'; +$lang['DELETE_DISALLOW_TITLE'] = 'Remove a Disallowed Username'; +$lang['DELETE_DISALLOW_EXPLAIN'] = 'You can remove a disallowed username by selecting the username from this list and clicking submit'; + +$lang['ADD_DISALLOW'] = 'Add'; +$lang['ADD_DISALLOW_TITLE'] = 'Add a disallowed username'; +$lang['ADD_DISALLOW_EXPLAIN'] = 'You can disallow a username using the wildcard character * to match any character'; + +$lang['NO_DISALLOWED'] = 'No Disallowed Usernames'; + +$lang['DISALLOWED_DELETED'] = 'The disallowed username has been successfully removed'; +$lang['DISALLOW_SUCCESSFUL'] = 'The disallowed username has been successfully added'; +$lang['DISALLOWED_ALREADY'] = 'The name you entered could not be disallowed. It either already exists in the list, exists in the word censor list, or a matching username is present.'; + +$lang['CLICK_RETURN_DISALLOWADMIN'] = 'Click %sHere%s to return to Disallow Username Administration'; + +// FTP +$lang['ATTACHMENT_FTP_SETTINGS'] = 'Setting up an FTP upload for attachments'; +$lang['FTP_CHOOSE'] = 'Choose Download Method'; +$lang['FTP_OPTION'] = '
    Since FTP extensions are enabled in this version of PHP you may also be given the option of first trying to automatically FTP the config file into place.'; +$lang['FTP_INSTRUCTS'] = 'You have chosen to FTP the file to the account containing phpBB 2 automatically. Please enter the information below to facilitate this process. Note that the FTP path should be the exact path via FTP to your phpBB2 installation as if you were FTPing to it using any normal client.'; +$lang['FTP_INFO'] = 'Enter Your FTP Information'; +$lang['ATTEMPT_FTP'] = 'Attempt to FTP config file into place'; +$lang['SEND_FILE'] = 'Just send the file to me and I\'ll FTP it manually'; +$lang['FTP_PATH'] = 'FTP path to phpBB 2'; +$lang['FTP_USERNAME'] = 'Your FTP Username'; +$lang['FTP_PASSWORD'] = 'Your FTP Password'; +$lang['TRANSFER_CONFIG'] = 'Start Transfer'; +$lang['NOFTP_CONFIG'] = 'The attempt to FTP the config file into place failed. Please download the config file and FTP it into place manually.'; + +// +// Version Check +// +$lang['VERSION_INFORMATION'] = 'Version Information'; + +// +// Login attempts configuration +// +$lang['MAX_LOGIN_ATTEMPTS'] = 'Allowed login attempts'; +$lang['MAX_LOGIN_ATTEMPTS_EXPLAIN'] = 'The number of allowed board login attempts.'; +$lang['LOGIN_RESET_TIME'] = 'Login lock time'; +$lang['LOGIN_RESET_TIME_EXPLAIN'] = 'Time in minutes the user have to wait until he is allowed to login again after exceeding the number of allowed login attempts.'; + +// +// Permissions List +// +$lang['PERMISSIONS_LIST'] = 'Permissions List'; +$lang['AUTH_CONTROL_CATEGORY'] = 'Category Permissions Control'; +$lang['FORUM_AUTH_LIST_EXPLAIN'] = 'This provides a summary of the authorisation levels of each forum. You can edit these permissions, using either a simple or advanced method by clicking on the forum name. Remember that changing the permission level of forums will affect which users can carry out the various operations within them.'; +$lang['CAT_AUTH_LIST_EXPLAIN'] = 'This provides a summary of the authorisation levels of each forum within this category. You can edit the permissions of individual forums, using either a simple or advanced method by clicking on the forum name. Alternatively, you can set the permissions for all the forums in this category by using the drop-down menus at the bottom of the page. Remember that changing the permission level of forums will affect which users can carry out the various operations within them.'; +$lang['FORUM_AUTH_LIST_EXPLAIN_ALL'] = 'All users'; +$lang['FORUM_AUTH_LIST_EXPLAIN_REG'] = 'All registered users'; +$lang['FORUM_AUTH_LIST_EXPLAIN_PRIVATE'] = 'Only users granted special permission'; +$lang['FORUM_AUTH_LIST_EXPLAIN_MOD'] = 'Only moderators of this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_ADMIN'] = 'Only administrators'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_VIEW'] = '%s can view this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_READ'] = '%s can read posts in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_POST'] = '%s can post in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_REPLY'] = '%s can reply to posts this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_EDIT'] = '%s can edit posts in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_DELETE'] = '%s can delete posts in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_STICKY'] = '%s can post sticky topics in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_ANNOUNCE'] = '%s can post announcements in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_VOTE'] = '%s can vote in polls in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_POLLCREATE'] = '%s can create polls in this forum'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_ATTACHMENTS'] = '%s can post attachments'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_DOWNLOAD'] = '%s can download attachments'; + +// +// Misc +// +$lang['SF_SHOW_ON_INDEX'] = 'Show on main page'; +$lang['SF_PARENT_FORUM'] = 'Parent forum'; +$lang['SF_NO_PARENT'] = 'No parent forum'; +$lang['TEMPLATE'] = 'Template'; +//Misc END + +// +// Reports (need to translate!) +// +$lang['REPORT_CONFIG_EXPLAIN'] = 'On this page you can change the general configuration of the report feature.'; +$lang['REPORT_SUBJECT_AUTH'] = 'Individual permissions'; +$lang['REPORT_SUBJECT_AUTH_EXPLAIN'] = 'If this setting is enabled, moderators can only view reports they can edit. For example a post report will be hidden if the user isn\'t a moderator of the forum the post belongs to.'; +$lang['REPORT_MODULES_CACHE'] = 'Cache modules in a file'; +$lang['REPORT_MODULES_CACHE_EXPLAIN'] = 'Note: The cache directory must be set to CHMOD 777 (full write permissions).'; +$lang['REPORT_NOTIFY'] = 'Email notification'; +$lang['REPORT_NOTIFY_CHANGE'] = 'on status changes and new reports'; +$lang['REPORT_NOTIFY_NEW'] = 'on new reports'; +$lang['REPORT_LIST_ADMIN'] = 'Admin-only report list'; +$lang['REPORT_NEW_WINDOW'] = 'Open subjects in a new window'; +$lang['REPORT_NEW_WINDOW_EXPLAIN'] = 'This setting also affects direct links to the reports at the view topic page.'; +$lang['REPORT_CONFIG_UPDATED'] = 'The configuration was updated.'; +$lang['CLICK_RETURN_REPORT_CONFIG'] = 'Click %sHere%s to return to the configuration.'; + +$lang['MODULES_REASONS'] = 'Modules & Reasons'; +$lang['REPORT_ADMIN_EXPLAIN'] = 'On this page you can install new report modules and edit or uninstall currently installed modules. In addition you can set up predefined reasons for every report module.'; +$lang['REPORT_MODULE'] = 'Report module'; +$lang['INSTALLED_MODULES'] = 'Installed modules'; +$lang['NO_MODULES_INSTALLED'] = 'No modules installed'; +$lang['REASONS'] = 'Reasons (%d)'; +$lang['SYNC'] = 'Sync'; +$lang['UNINSTALL'] = 'Uninstall'; +$lang['INSTALL2'] = 'Install'; +$lang['INACTIVE_MODULES'] = 'Inactive modules'; +$lang['NO_MODULES_INACTIVE'] = 'No inactive modules'; +$lang['REPORT_MODULE_NOT_EXISTS'] = 'The selected module doesn\'t exist.'; +$lang['CLICK_RETURN_REPORT_ADMIN'] = 'Click %sHere%s to return to the Modules & Reasons administration.'; + +$lang['BACK_MODULES'] = 'Back to the modules'; +$lang['REPORT_REASON'] = 'Report reason'; +$lang['NO_REASONS'] = 'No reasons for this module'; +$lang['ADD_REASON'] = 'Add reason'; +$lang['EDIT_REASON'] = 'Edit reason'; +$lang['REASON_DESC_EXPLAIN'] = 'If the description matches with a language variable, the variable will be used instead.'; +$lang['REASON_DESC_EMPTY'] = 'You have to enter a report reason.'; +$lang['REPORT_REASON_ADDED'] = 'The report reason was added.'; +$lang['REPORT_REASON_EDITED'] = 'The report reason was edited.'; +$lang['DELETE_REASON'] = 'Delete reason'; +$lang['DELETE_REPORT_REASON_EXPLAIN'] = 'Are you sure you want to delete the selected report reason?'; +$lang['REPORT_REASON_DELETED'] = 'The report reason was deleted.'; +$lang['REPORT_REASON_NOT_EXISTS'] = 'The selected report reason doesn\'t exist.'; +$lang['CLICK_RETURN_REPORT_REASONS'] = 'Click %sHere%s to return to the report reasons administration.'; + +$lang['REPORT_MODULE_SYNCED'] = 'The module was synced.'; + +$lang['UNINSTALL_REPORT_MODULE'] = 'Uninstall module'; +$lang['UNINSTALL_REPORT_MODULE_EXPLAIN'] = 'Are you sure you want to uninstall the selected report module?
    Note: All reports in the module will be deleted, too.'; +$lang['REPORT_MODULE_UNINSTALLED'] = 'The module was uninstalled.'; + +$lang['INSTALL_REPORT_MODULE'] = 'Install module'; +$lang['EDIT_REPORT_MODULE'] = 'Edit module'; +$lang['REPORT_PRUNE'] = 'Prune reports'; +$lang['REPORT_PRUNE_EXPLAIN'] = 'Cleared reports and reports marked for deletion will be deleted automatically after x days. Set to zero to disable the feature.'; +$lang['REPORT_PERMISSIONS'] = 'Report permissions'; +$lang['WRITE'] = 'Write'; +$lang['REPORT_AUTH'] = array( + REPORT_AUTH_USER => 'Users', + REPORT_AUTH_MOD => 'Moderators', + REPORT_AUTH_CONFIRM => 'Moderators (after confirmation)', + REPORT_AUTH_ADMIN => 'Administrators'); +$lang['REPORT_AUTH_NOTIFY_EXPLAIN'] = 'Moderators will only be notified if they can view and edit the report.'; +$lang['REPORT_AUTH_DELETE_EXPLAIN'] = 'If you select Moderators (after confirmation), deletions have to be confirmed by an administrator.'; +$lang['REPORT_MODULE_INSTALLED'] = 'The module was installed.'; +$lang['REPORT_MODULE_EDITED'] = 'The module was edited.'; +$lang['REPORTS'] = 'Reports'; +// +// Reports [END] +// diff --git a/upload/language/lang_english/lang_admin_attach.php b/upload/language/lang_english/lang_admin_attach.php new file mode 100644 index 000000000..07495c1d3 --- /dev/null +++ b/upload/language/lang_english/lang_admin_attach.php @@ -0,0 +1,226 @@ + Management +$lang['ATTACH_SETTINGS'] = 'Attachment Settings'; +$lang['MANAGE_ATTACHMENTS_EXPLAIN'] = 'Here you can configure the Main Settings for the Attachment Mod. If you press the Test Settings Button, the Attachment Mod does a few System Tests to be sure that the Mod will work properly. If you have problems with uploading Files, please run this Test, to get a detailed error-message.'; +$lang['ATTACH_FILESIZE_SETTINGS'] = 'Attachment Filesize Settings'; +$lang['ATTACH_NUMBER_SETTINGS'] = 'Attachment Number Settings'; +$lang['ATTACH_OPTIONS_SETTINGS'] = 'Attachment Options'; + +$lang['UPLOAD_DIRECTORY'] = 'Upload Directory'; +$lang['UPLOAD_DIRECTORY_EXPLAIN'] = 'Enter the relative path from your phpBB2 installation to the Attachments upload directory. For example, enter \'files\' if your phpBB2 Installation is located at http://www.yourdomain.com/phpBB2 and the Attachment Upload Directory is located at http://www.yourdomain.com/phpBB2/files.'; +$lang['ATTACH_IMG_PATH'] = 'Attachment Posting Icon'; +$lang['ATTACH_IMG_PATH_EXPLAIN'] = 'This Image is displayed next to Attachment Links in individual Postings. Leave this field empty if you don\'t want an icon to be displayed. This Setting will be overwritten by the Settings in Extension Groups Management.'; +$lang['ATTACH_TOPIC_ICON'] = 'Attachment Topic Icon'; +$lang['ATTACH_TOPIC_ICON_EXPLAIN'] = 'This Image is displayed before topics with Attachments. Leave this field empty if you don\'t want an icon to be displayed.'; +$lang['ATTACH_DISPLAY_ORDER'] = 'Attachment Display Order'; +$lang['ATTACH_DISPLAY_ORDER_EXPLAIN'] = 'Here you can choose whether to display the Attachments in Posts/PMs in Descending Filetime Order (Newest Attachment First) or Ascending Filetime Order (Oldest Attachment First).'; + +$lang['MAX_FILESIZE_ATTACH'] = 'Filesize'; +$lang['MAX_FILESIZE_ATTACH_EXPLAIN'] = 'Maximum filesize for Attachments. A value of 0 means \'unlimited\'. This Setting is restricted by your Server Configuration. For example, if your php Configuration only allows a maximum of 2 MB uploads, this cannot be overwritten by the Mod.'; +$lang['ATTACH_QUOTA'] = 'Attachment Quota'; +$lang['ATTACH_QUOTA_EXPLAIN'] = 'Maximum Disk Space ALL Attachments can hold on your Webspace. A value of 0 means \'unlimited\'.'; +$lang['MAX_FILESIZE_PM'] = 'Maximum Filesize in Private Messages Folder'; +$lang['MAX_FILESIZE_PM_EXPLAIN'] = 'Maximum Disk Space Attachments can use up in each User\'s Private Message box. A value of 0 means \'unlimited\'.'; +$lang['DEFAULT_QUOTA_LIMIT'] = 'Default Quota Limit'; +$lang['DEFAULT_QUOTA_LIMIT_EXPLAIN'] = 'Here you are able to select the Default Quota Limit automatically assigned to newly registered Users and Users without an defined Quota Limit. The Option \'No Quota Limit\' is for not using any Attachment Quotas, instead using the default Settings you have defined within this Management Panel.'; + +$lang['MAX_ATTACHMENTS'] = 'Maximum Number of Attachments'; +$lang['MAX_ATTACHMENTS_EXPLAIN'] = 'The maximum number of attachments allowed in one post.'; +$lang['MAX_ATTACHMENTS_PM'] = 'Maximum number of Attachments in one Private Message'; +$lang['MAX_ATTACHMENTS_PM_EXPLAIN'] = 'Define the maximum number of attachments the user is allowed to include in a private message.'; + +$lang['DISABLE_MOD'] = 'Disable Attachment Mod'; +$lang['DISABLE_MOD_EXPLAIN'] = 'This option is mainly for testing new templates or themes, it disables all Attachment Functions except the Admin Panel.'; +$lang['PM_ATTACHMENTS'] = 'Allow Attachments in Private Messages'; +$lang['PM_ATTACHMENTS_EXPLAIN'] = 'Allow/Disallow attaching files to Private Messages.'; +$lang['FTP_UPLOAD'] = 'Enable FTP Upload'; +$lang['FTP_UPLOAD_EXPLAIN'] = 'Enable/Disable the FTP Upload option. If you set it to yes, you have to define the Attachment FTP Settings and the Upload Directory is no longer used.'; + +$lang['FTP_SERVER'] = 'FTP Upload Server'; +$lang['FTP_SERVER_EXPLAIN'] = 'Here you can enter the IP-Address or FTP-Hostname of the Server used for your uploaded files. If you leave this field empty, the Server on which your phpBB2 Board is installed will be used. Please note that it is not allowed to add ftp:// or something else to the address, just plain ftp.foo.com or, which is a lot faster, the plain IP Address.'; + +$lang['ATTACH_FTP_PATH'] = 'FTP Path to your upload directory'; +$lang['ATTACH_FTP_PATH_EXPLAIN'] = 'The Directory where your Attachments will be stored. This Directory doesn\'t have to be chmodded. Please don\'t enter your IP or FTP-Address here, this input field is only for the FTP Path.
    For example: /home/web/uploads'; +$lang['FTP_DOWNLOAD_PATH'] = 'Download Link to FTP Path'; +$lang['FTP_DOWNLOAD_PATH_EXPLAIN'] = 'Enter the URL to your FTP Path, where your Attachments are stored.
    If you are using a Remote FTP Server, please enter the complete url, for example http://www.mystorage.com/phpBB2/upload.
    If you are using your Local Host to store your Files, you are able to enter the url path relative to your phpBB2 Directory, for example \'upload\'.
    A trailing slash will be removed. Leave this field empty, if the FTP Path is not accessible from the Internet. With this field empty you are unable to use the physical download method.'; +$lang['FTP_PASSIVE_MODE'] = 'Enable FTP Passive Mode'; +$lang['FTP_PASSIVE_MODE_EXPLAIN'] = 'The PASV command requests that the remote server open a port for the data connection and return the address of that port. The remote server listens on that port and the client connects to it.'; + +$lang['NO_FTP_EXTENSIONS_INSTALLED'] = 'You are not able to use the FTP Upload Methods, because FTP Extensions are not compiled into your PHP Installation.'; + +// Attachments -> Shadow Attachments +$lang['SHADOW_ATTACHMENTS_EXPLAIN'] = 'Here you can delete attachment data from postings when the files are missing from your filesystem, and delete files that are no longer attached to any postings. You can download or view a file if you click on it; if no link is present, the file does not exist.'; +$lang['SHADOW_ATTACHMENTS_FILE_EXPLAIN'] = 'Delete all attachments files that exist on your filesystem and are not assigned to an existing post.'; +$lang['SHADOW_ATTACHMENTS_ROW_EXPLAIN'] = 'Delete all posting attachment data for files that don\'t exist on your filesystem.'; +$lang['EMPTY_FILE_ENTRY'] = 'Empty File Entry'; + +// Attachments -> Sync +$lang['SYNC_THUMBNAIL_RESETTED'] = 'Thumbnail resetted for Attachment: %s'; // replace %s with physical Filename +$lang['ATTACH_SYNC_FINISHED'] = 'Attachment Syncronization Finished.'; +$lang['SYNC_TOPICS'] = 'Sync Topics'; +$lang['SYNC_POSTS'] = 'Sync Posts'; +$lang['SYNC_THUMBNAILS'] = 'Sync Thumbnails'; + + +// Extensions -> Extension Control +$lang['MANAGE_EXTENSIONS'] = 'Manage Extensions'; +$lang['MANAGE_EXTENSIONS_EXPLAIN'] = 'Here you can manage your File Extensions. If you want to allow/disallow a Extension to be uploaded, please use the Extension Groups Management.'; +$lang['EXPLANATION'] = 'Explanation'; +$lang['EXTENSION_GROUP'] = 'Extension Group'; +$lang['INVALID_EXTENSION'] = 'Invalid Extension'; +$lang['EXTENSION_EXIST'] = 'The Extension %s already exist'; // replace %s with the Extension +$lang['UNABLE_ADD_FORBIDDEN_EXTENSION'] = 'The Extension %s is forbidden, you are not able to add it to the allowed Extensions'; // replace %s with Extension + +// Extensions -> Extension Groups Management +$lang['MANAGE_EXTENSION_GROUPS'] = 'Manage Extension Groups'; +$lang['MANAGE_EXTENSION_GROUPS_EXPLAIN'] = 'Here you can add, delete and modify your Extension Groups, you can disable Extension Groups, assign a special Category to them, change the download mechanism and you can define a Upload Icon which will be displayed in front of an Attachment belonging to the Group.'; +$lang['SPECIAL_CATEGORY'] = 'Special Category'; +$lang['CATEGORY_IMAGES'] = 'Images'; +$lang['CATEGORY_STREAM_FILES'] = 'Stream Files'; +$lang['CATEGORY_SWF_FILES'] = 'Flash Files'; +$lang['ALLOWED'] = 'Allowed'; +$lang['ALLOWED_FORUMS'] = 'Allowed Forums'; +$lang['EXT_GROUP_PERMISSIONS'] = 'Group Permissions'; +$lang['DOWNLOAD_MODE'] = 'Download Mode'; +$lang['UPLOAD_ICON'] = 'Upload Icon'; +$lang['MAX_GROUPS_FILESIZE'] = 'Maximum Filesize'; +$lang['EXTENSION_GROUP_EXIST'] = 'The Extension Group %s already exist'; // replace %s with the group name +$lang['COLLAPSE'] = '+'; +$lang['DECOLLAPSE'] = '-'; + +// Extensions -> Special Categories +$lang['MANAGE_CATEGORIES'] = 'Manage Special Categories'; +$lang['MANAGE_CATEGORIES_EXPLAIN'] = 'Here you can configure the Special Categories. You can set up Special Parameters and Conditions for the Special Categorys assigned to an Extension Group.'; +$lang['SETTINGS_CAT_IMAGES'] = 'Settings for Special Category: Images'; +$lang['SETTINGS_CAT_STREAMS'] = 'Settings for Special Category: Stream Files'; +$lang['SETTINGS_CAT_FLASH'] = 'Settings for Special Category: Flash Files'; +$lang['DISPLAY_INLINED'] = 'Display Images Inlined'; +$lang['DISPLAY_INLINED_EXPLAIN'] = 'Choose whether to display images directly within the post (yes) or to display images as a link ?'; +$lang['MAX_IMAGE_SIZE'] = 'Maximum Image Dimensions'; +$lang['MAX_IMAGE_SIZE_EXPLAIN'] = 'Here you can define the maximum allowed Image Dimension to be attached (Width x Height in pixels).
    If it is set to 0x0, this feature is disabled. With some Images this Feature will not work due to limitations in PHP.'; +$lang['IMAGE_LINK_SIZE'] = 'Image Link Dimensions'; +$lang['IMAGE_LINK_SIZE_EXPLAIN'] = 'If this defined Dimension of an Image is reached, the Image will be displayed as a Link, rather than displaying it inlined,
    if Inline View is enabled (Width x Height in pixels).
    If it is set to 0x0, this feature is disabled. With some Images this Feature will not work due to limitations in PHP.'; +$lang['ASSIGNED_GROUP'] = 'Assigned Group'; + +$lang['IMAGE_CREATE_THUMBNAIL'] = 'Create Thumbnail'; +$lang['IMAGE_CREATE_THUMBNAIL_EXPLAIN'] = 'Always create a Thumbnail. This feature overrides nearly all Settings within this Special Category, except of the Maximum Image Dimensions. With this Feature a Thumbnail will be displayed within the post, the User can click it to open the real Image.
    Please Note that this feature requires Imagick to be installed, if it\'s not installed or if Safe-Mode is enabled the GD-Extension of PHP will be used. If the Image-Type is not supported by PHP, this Feature will be not used.'; +$lang['IMAGE_MIN_THUMB_FILESIZE'] = 'Minimum Thumbnail Filesize'; +$lang['IMAGE_MIN_THUMB_FILESIZE_EXPLAIN'] = 'If a Image is smaller than this defined Filesize, no Thumbnail will be created, because it\'s small enough.'; +$lang['IMAGE_IMAGICK_PATH'] = 'Imagick Program (Complete Path)'; +$lang['IMAGE_IMAGICK_PATH_EXPLAIN'] = 'Enter the Path to the convert program of imagick, normally /usr/bin/convert (on windows: c:/imagemagick/convert.exe).'; +$lang['IMAGE_SEARCH_IMAGICK'] = 'Search Imagick'; + +$lang['USE_GD2'] = 'Make use of GD2 Extension'; +$lang['USE_GD2_EXPLAIN'] = 'PHP is able to be compiled with the GD1 or GD2 Extension for image manipulating. To correctly create Thumbnails without imagemagick the Attachment Mod uses two different methods, based on your selection here. If your thumbnails are in a bad quality or screwed up, try to change this setting.'; +$lang['ATTACHMENT_VERSION'] = 'Attachment Mod Version %s'; // %s is the version number + +// Extensions -> Forbidden Extensions +$lang['MANAGE_FORBIDDEN_EXTENSIONS'] = 'Manage Forbidden Extensions'; +$lang['MANAGE_FORBIDDEN_EXTENSIONS_EXPLAIN'] = 'Here you can add or delete the forbidden extensions. The Extensions php, php3 and php4 are forbidden by default for security reasons, you can not delete them.'; +$lang['FORBIDDEN_EXTENSION_EXIST'] = 'The forbidden Extension %s already exist'; // replace %s with the extension +$lang['EXTENSION_EXIST_FORBIDDEN'] = 'The Extension %s is defined in your allowed Extensions, please delete it their before you add it here.'; // replace %s with the extension + +// Extensions -> Extension Groups Control -> Group Permissions +$lang['GROUP_PERMISSIONS_TITLE_ADMIN'] = 'Extension Group Permissions -> \'%s\''; // Replace %s with the Groups Name +$lang['GROUP_PERMISSIONS_EXPLAIN'] = 'Here you are able to restrict the selected Extension Group to Forums of your choice (defined in the Allowed Forums Box). The Default is to allow Extension Groups to all Forums the User is able to Attach Files into (the normal way the Attachment Mod did it since the beginning). Just add those Forums you want the Extension Group (the Extensions within this Group) to be allowed there, the default ALL FORUMS will disappear when you add Forums to the List. You are able to re-add ALL FORUMS at any given Time. If you add a Forum to your Board and the Permission is set to ALL FORUMS nothing will change. But if you have changed and restricted the access to certain Forums, you have to check back here to add your newly created Forum. It is easy to do this automatically, but this will force you to edit a bunch of Files, therefore i have chosen the way it is now. Please keep in mind, that all of your Forums will be listed here.'; +$lang['NOTE_ADMIN_EMPTY_GROUP_PERMISSIONS'] = 'NOTE:
    Within the below listed Forums your Users are normally allowed to attach files, but since no Extension Group is allowed to be attached there, your Users are unable to attach anything. If they try, they will receive Error Messages. Maybe you want to set the Permission \'Post Files\' to ADMIN at these Forums.

    '; +$lang['ADD_FORUMS'] = 'Add Forums'; +$lang['ADD_SELECTED'] = 'Add Selected'; +$lang['PERM_ALL_FORUMS'] = 'ALL FORUMS'; + +// Attachments -> Quota Limits +$lang['MANAGE_QUOTAS'] = 'Manage Attachment Quota Limits'; +$lang['MANAGE_QUOTAS_EXPLAIN'] = 'Here you are able to add/delete/change Quota Limits. You are able to assign these Quota Limits to Users and Groups later. To assign a Quota Limit to a User, you have to go to Users->Management, select the User and you will see the Options at the bottom. To assign a Quota Limit to a Group, go to Groups->Management, select the Group to edit it, and you will see the Configuration Settings. If you want to see, which Users and Groups are assigned to a specific Quota Limit, click on \'View\' at the left of the Quota Description.'; +$lang['ASSIGNED_USERS'] = 'Assigned Users'; +$lang['ASSIGNED_GROUPS'] = 'Assigned Groups'; +$lang['QUOTA_LIMIT_EXIST'] = 'The Quota Limit %s exist already.'; // Replace %s with the Quota Description + +// Attachments -> Control Panel +$lang['CONTROL_PANEL_TITLE'] = 'File Attachment Control Panel'; +$lang['CONTROL_PANEL_EXPLAIN'] = 'Here you can view and manage all attachments based on Users, Attachments, Views etc...'; +$lang['FILE_COMMENT_CP'] = 'File Comment'; + +// Control Panel -> Search +$lang['SEARCH_WILDCARD_EXPLAIN'] = 'Use * as a wildcard for partial matches'; +$lang['SIZE_SMALLER_THAN'] = 'Attachment size smaller than (bytes)'; +$lang['SIZE_GREATER_THAN'] = 'Attachment size greater than (bytes)'; +$lang['COUNT_SMALLER_THAN'] = 'Download count is smaller than'; +$lang['COUNT_GREATER_THAN'] = 'Download count is greater than'; +$lang['MORE_DAYS_OLD'] = 'More than this many days old'; +$lang['NO_ATTACH_SEARCH_MATCH'] = 'No Attachments met your search criteria'; + +// Control Panel -> Statistics +$lang['NUMBER_OF_ATTACHMENTS'] = 'Number of Attachments'; +$lang['TOTAL_FILESIZE'] = 'Total Filesize'; +$lang['NUMBER_POSTS_ATTACH'] = 'Number of Posts with Attachments'; +$lang['NUMBER_TOPICS_ATTACH'] = 'Number of Topics with Attachments'; +$lang['NUMBER_USERS_ATTACH'] = 'Independent Users Posted Attachments'; +$lang['NUMBER_PMS_ATTACH'] = 'Total Number of Attachments in Private Messages'; + +// Control Panel -> Attachments +$lang['STATISTICS_FOR_USER'] = 'Attachment Statistics for %s'; // replace %s with username +$lang['SIZE_IN_KB'] = 'Size (KB)'; +$lang['DOWNLOADS'] = 'Downloads'; +$lang['POST_TIME'] = 'Post Time'; +$lang['POSTED_IN_TOPIC'] = 'Posted in Topic'; +$lang['SUBMIT_CHANGES'] = 'Submit Changes'; + +// Sort Types +$lang['SORT_ATTACHMENTS'] = 'Attachments'; +$lang['SORT_SIZE'] = 'Size'; +$lang['SORT_FILENAME'] = 'Filename'; +$lang['SORT_COMMENT'] = 'Comment'; +$lang['SORT_EXTENSION'] = 'Extension'; +$lang['SORT_DOWNLOADS'] = 'Downloads'; +$lang['SORT_POSTTIME'] = 'Post Time'; +$lang['SORT_POSTS'] = 'Posts'; + +// View Types +$lang['VIEW_STATISTIC'] = 'Statistics'; +$lang['VIEW_SEARCH'] = 'Search'; +$lang['VIEW_USERNAME'] = 'Username'; +$lang['VIEW_ATTACHMENTS'] = 'Attachments'; + +// Successfully updated +$lang['ATTACH_CONFIG_UPDATED'] = 'Attachment Configuration updated successfully'; +$lang['CLICK_RETURN_ATTACH_CONFIG'] = 'Click %sHere%s to return to Attachment Configuration'; +$lang['TEST_SETTINGS_SUCCESSFUL'] = 'Settings Test finished, configuration seems to be fine.'; + +// Some basic definitions +$lang['ATTACHMENTS'] = 'Attachments'; +$lang['ATTACHMENT'] = 'Attachment'; +$lang['EXTENSIONS'] = 'Extensions'; +$lang['EXTENSION'] = 'Extension'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_admin_bt.php b/upload/language/lang_english/lang_admin_bt.php new file mode 100644 index 000000000..8ded368de --- /dev/null +++ b/upload/language/lang_english/lang_admin_bt.php @@ -0,0 +1,141 @@ +"No" - compatible mode (chosen by client)'; +$lang['BROWSER_REDIRECT_URL'] = 'Browser redirect URL'; +$lang['BROWSER_REDIRECT_URL_EXPL'] = 'if user tries to open tracker URL in Web browser
    leave blank to disable'; + +$lang['ANNOUNCE_INTERVAL_HEAD'] = 'Misc'; +$lang['ANNOUNCE_INTERVAL'] = 'Announce interval'; +$lang['ANNOUNCE_INTERVAL_EXPL'] = 'peers should wait at least this many seconds between announcements'; +$lang['NUMWANT'] = 'Numwant value'; +$lang['NUMWANT_EXPL'] = 'number of peers being sent to client'; +$lang['EXPIRE_FACTOR'] = 'Peer expire factor'; +$lang['EXPIRE_FACTOR_EXPL'] = 'Consider a peer dead if it has not announced in a number of seconds equal to this many times the calculated announce interval at the time of its last announcement (must be greater than 1)'; +$lang['IGNORE_GIVEN_IP'] = 'Ignore IP reported by client'; +$lang['UPDATE_DLSTAT'] = 'Store users up/down statistics'; + +$lang['LIMIT_ACTIVE_TOR_HEAD'] = 'Limits'; +$lang['LIMIT_ACTIVE_TOR'] = 'Limit active torrents'; +$lang['LIMIT_SEED_COUNT'] = 'Seeding limit'; +$lang['LIMIT_SEED_COUNT_EXPL'] = '(0 - no limit)'; +$lang['LIMIT_LEECH_COUNT'] = 'Leeching limit'; +$lang['LIMIT_LEECH_COUNT_EXPL'] = '(0 - no limit)'; +$lang['LEECH_EXPIRE_FACTOR'] = 'Leech expire factor'; +$lang['LEECH_EXPIRE_FACTOR_EXPL'] = 'Treat a peer as active for this number of minutes even if it sent "stopped" event after starting dl
    0 - take into account "stopped" event'; +$lang['LIMIT_CONCURRENT_IPS'] = "Limit concurrent IP's"; +$lang['LIMIT_CONCURRENT_IPS_EXPL'] = 'per torrent limit'; +$lang['LIMIT_SEED_IPS'] = 'Seeding IP limit'; +$lang['LIMIT_SEED_IPS_EXPL'] = "allow seeding from no more than xx IP's
    0 - no limit"; +$lang['LIMIT_LEECH_IPS'] = 'Leeching IP limit'; +$lang['LIMIT_LEECH_IPS_EXPL'] = "allow leeching from no more than xx IP's
    0 - no limit"; + +$lang['USE_AUTH_KEY_HEAD'] = 'Authorization'; +$lang['USE_AUTH_KEY'] = 'Passkey'; +$lang['USE_AUTH_KEY_EXPL'] = 'enable check for passkey'; +$lang['AUTH_KEY_NAME'] = 'Passkey name'; +$lang['AUTH_KEY_NAME_EXPL'] = 'passkey key name in GET request'; +$lang['ALLOW_GUEST_DL'] = 'Allow guest access to tracker'; + +// +// Forum config +// +$lang['FORUM_CFG_EXPL'] = 'Forum config'; + +$lang['BT_SELECT_FORUMS'] = 'Forum options:'; +$lang['BT_SELECT_FORUMS_EXPL'] = 'hold down Ctrl while selecting multiple forums'; + +$lang['ALLOW_REG_TRACKER'] = 'Allowed forums for registering .torrents on tracker'; +$lang['ALLOW_DL_TOPIC'] = 'Allow post Download topics'; +$lang['SHOW_DL_BUTTONS'] = 'Show buttons for manually changing DL-status'; +$lang['SELF_MODERATED'] = 'Users can move their topics to another forum'; + +$lang['BT_ANNOUNCE_URL_HEAD'] = 'Announce URL'; +$lang['BT_ANNOUNCE_URL'] = 'Announce url'; +$lang['BT_ANNOUNCE_URL_EXPL'] = 'you can define additional allowed urls in "includes/announce_urls.php"'; +$lang['BT_DISABLE_DHT'] = 'Disable DHT network'; +$lang['BT_DISABLE_DHT_EXPL'] = 'Disable Peer Exchange and DHT (recommended for private networks, only url announce)'; +$lang['BT_CHECK_ANNOUNCE_URL'] = 'Verify announce url'; +$lang['BT_CHECK_ANNOUNCE_URL_EXPL'] = 'register on tracker only allowed urls'; +$lang['BT_REPLACE_ANN_URL'] = 'Replace announce url'; +$lang['BT_REPLACE_ANN_URL_EXPL'] = 'replace original announce url with your default in .torrent files'; +$lang['BT_DEL_ADDIT_ANN_URLS'] = 'Remove all additional announce urls'; +$lang['BT_ADD_COMMENT'] = 'Torrent comments'; +$lang['BT_ADD_COMMENT_EXPL'] = 'adds the Comments filed to the .torrent files (leave blank to use the topic URL as a comment)'; +$lang['BT_ADD_PUBLISHER'] = 'Torrent\'s publisher'; +$lang['BT_ADD_PUBLISHER_EXPL'] = 'adds the Publisher field and topic URL as the Publisher-url to the .torrent files (leave blank to disable)'; + +$lang['BT_SHOW_PEERS_HEAD'] = 'Peers-List'; +$lang['BT_SHOW_PEERS'] = 'Show peers (seeders and leechers)'; +$lang['BT_SHOW_PEERS_EXPL'] = 'this will show seeders/leechers list above the topic with torrent'; +$lang['BT_SHOW_PEERS_MODE'] = 'By default, show peers as:'; +$lang['BT_SHOW_PEERS_MODE_COUNT'] = 'Count only'; +$lang['BT_SHOW_PEERS_MODE_NAMES'] = 'Names only'; +$lang['BT_SHOW_PEERS_MODE_FULL'] = 'Full details'; +$lang['BT_ALLOW_SPMODE_CHANGE'] = 'Allow "Full details" mode'; +$lang['BT_ALLOW_SPMODE_CHANGE_EXPL'] = 'if "no", only default peer display mode will be available'; +$lang['BT_SHOW_IP_ONLY_MODER'] = 'Peers\' IPs are visible to moderators only'; +$lang['BT_SHOW_PORT_ONLY_MODER'] = 'Peers\' Ports are visible to moderators only'; + +$lang['BT_SHOW_DL_LIST_HEAD'] = 'DL-List'; +$lang['BT_SHOW_DL_LIST'] = 'Show DL-List in Download topics'; +$lang['BT_DL_LIST_ONLY_1ST_PAGE'] = 'Show DL-List only on first page in topics'; +$lang['BT_DL_LIST_ONLY_COUNT'] = 'Show only number of users'; +$lang['BT_SHOW_DL_LIST_BUTTONS'] = 'Show buttons for manually changing DL-status'; +$lang['BT_SHOW_DL_BUT_WILL'] = $lang['DL_WILL']; +$lang['BT_SHOW_DL_BUT_DOWN'] = $lang['DL_DOWN']; +$lang['BT_SHOW_DL_BUT_COMPL'] = $lang['DL_COMPLETE']; +$lang['BT_SHOW_DL_BUT_CANCEL'] = $lang['DL_CANCEL']; + +$lang['BT_ADD_AUTH_KEY_HEAD'] = 'Passkey'; +$lang['BT_ADD_AUTH_KEY'] = 'Enable adding passkey to the torrent-files before downloading'; +$lang['BT_GEN_PASSKEY_ON_REG'] = 'Automatically generate passkey'; +$lang['BT_GEN_PASSKEY_ON_REG_EXPL'] = "generate passkey during first downloading attempt if current user's passkey is empty"; + +$lang['BT_TOR_BROWSE_ONLY_REG_HEAD'] = 'Torrent browser (tracker)'; +$lang['BT_TOR_BROWSE_ONLY_REG'] = 'Torrent browser (tracker.php) accessible only for logged in users'; +$lang['BT_SEARCH_BOOL_MODE'] = 'Allow boolean full-text searches'; +$lang['BT_SEARCH_BOOL_MODE_EXPL'] = 'use *, +, -,.. in searches'; + +$lang['BT_SHOW_DL_STAT_ON_INDEX_HEAD'] = "Miscellaneous"; +$lang['BT_SHOW_DL_STAT_ON_INDEX'] = "Show users UL/DL statistics at the top of the forum's main page"; +$lang['BT_NEWTOPIC_AUTO_REG'] = 'Automatically register torrent on tracker for new topics'; +$lang['BT_SET_DLTYPE_ON_TOR_REG'] = 'Change topic status to "Download" while registering torrent on tracker'; +$lang['BT_SET_DLTYPE_ON_TOR_REG_EXPL'] = 'will change topic type to "Download" regardless of forum settings'; +$lang['BT_UNSET_DLTYPE_ON_TOR_UNREG'] = 'Change topic status to "Normal" while unregistering torrent from tracker'; + +// +// Release +// +$lang['RELEASE_EXP'] = 'This page displays all forums. For each of them you can set the release type which should be posted in the forum.'; +$lang['TPL_NONE'] = 'Don\'t use templates'; +$lang['TPL_VIDEO'] = 'Video (basic)'; +$lang['TPL_VIDEO_HOME'] = 'Video (home)'; +$lang['TPL_VIDEO_SIMPLE'] = 'Video (simple)'; +$lang['TPL_VIDEO_LESSON'] = 'Video (lesson)'; +$lang['TPL_GAMES'] = 'Games'; +$lang['TPL_GAMES_PS'] = 'Games PS/PS2'; +$lang['TPL_GAMES_PSP'] = 'Games PSP'; +$lang['TPL_GAMES_XBOX'] = 'Games XBOX'; +$lang['TPL_PROGS'] = 'Programs'; +$lang['TPL_PROGS_MAC'] = 'Programs Mac OS'; +$lang['TPL_MUSIC'] = 'Music'; +$lang['TPL_BOOKS'] = 'Books'; +$lang['TPL_AUDIOBOOKS'] = 'Audiobooks'; +$lang['TPL_SPORT'] = 'Sport'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_admin_cron.php b/upload/language/lang_english/lang_admin_cron.php new file mode 100644 index 000000000..8d70e9f62 --- /dev/null +++ b/upload/language/lang_english/lang_admin_cron.php @@ -0,0 +1,61 @@ + '; +$lang['REPAIR_CRON'] = '[Repair Cron]'; + +$lang['CRON_EDIT_HEAD_EDIT'] = 'Edit job'; +$lang['CRON_EDIT_HEAD_ADD'] = 'Add job'; +$lang['CRON_ID'] = 'Cron id'; +$lang['CRON_ACTIVE'] = 'Cron active'; +$lang['CRON_ACTIVE_EXPL'] = 'this job is active?'; +$lang['CRON_TITLE'] = 'Cron title'; +$lang['CRON_SCRIPT'] = 'Cron script'; +$lang['CRON_SCRIPT_EXPL'] = 'name of the script from "includes/cron/jobs/"'; +$lang['SCHEDULE'] = 'Schedule'; +//schedule +$lang['HOURLY'] = 'hourly'; +$lang['DAILY'] = 'daily'; +$lang['WEEKLY'] = 'weekly'; +$lang['MONTHLY'] = 'monthly'; +$lang['INTERVAL'] = 'interval'; +// +$lang['RUN_DAY'] = 'Run day'; +$lang['RUN_DAY_EXPL'] = 'the day when this job run'; +$lang['RUN_TIME'] = 'Run time'; +$lang['RUN_TIME_EXPL'] = 'the time when this job run (e.g. 05:00:00)'; +$lang['RUN_ORDER'] = 'Run order'; +$lang['LAST_RUN'] = 'Last Run'; +$lang['NEXT_RUN'] = 'Next Run'; +$lang['RUN_INTERVAL'] = 'Run interval'; +$lang['RUN_INTERVAL_EXPL'] = 'e.g. 00:10:00'; +$lang['LOG_ENABLED'] = 'Log enabled'; +$lang['LOG_FILE'] = 'Log file'; +$lang['LOG_FILE_EXPL'] = 'the file for save the log'; +$lang['LOG_SQL_QUERIES'] = 'Log SQL queries'; +$lang['DISABLE_BOARD'] = 'Disable board'; +$lang['DISABLE_BOARD_EXPL'] = 'disable board when this job is run'; +$lang['RUN_COUNTER'] = 'Run counter'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_admin_rebuild_search.php b/upload/language/lang_english/lang_admin_rebuild_search.php new file mode 100644 index 000000000..29f98cb95 --- /dev/null +++ b/upload/language/lang_english/lang_admin_rebuild_search.php @@ -0,0 +1,132 @@ +
    +It may take a long time to show its progress (depending on "Posts per cycle" and "Time limit"), +so please do not move from its progress page until it is complete, unless of course you want to interrupt it.'; + +// +// Input screen +// +$lang['STARTING_POST_ID'] = 'Starting post_id'; +$lang['STARTING_POST_ID_EXPLAIN'] = 'First post where processing will begin from
    You can choose to start from the beginning or from the post you last stopped'; + +$lang['START_OPTION_BEGINNING'] = 'start from beginning'; +$lang['START_OPTION_CONTINUE'] = 'continue from last stopped'; + +$lang['CLEAR_SEARCH_TABLES'] = 'Clear search tables'; +$lang['CLEAR_SEARCH_TABLES_EXPLAIN'] = ''; +$lang['CLEAR_SEARCH_NO'] = 'NO'; +$lang['CLEAR_SEARCH_DELETE'] = 'DELETE'; +$lang['CLEAR_SEARCH_TRUNCATE'] = 'TRUNCATE'; + +$lang['NUM_OF_POSTS'] = 'Number of posts'; +$lang['NUM_OF_POSTS_EXPLAIN'] = 'Number of total posts to process
    It\'s automatically filled with the number of total/remaining posts found in the db'; + +$lang['POSTS_PER_CYCLE'] = 'Posts per cycle'; +$lang['POSTS_PER_CYCLE_EXPLAIN'] = 'Number of posts to process per cycle
    Keep it low to avoid php/webserver timeouts'; + +$lang['REFRESH_RATE'] = 'Refresh rate'; +$lang['REFRESH_RATE_EXPLAIN'] = 'How much time (secs) to stay idle before moving to next processing cycle
    Usually you don\'t have to change this'; + +$lang['TIME_LIMIT'] = 'Time limit'; +$lang['TIME_LIMIT_EXPLAIN'] = 'How much time (secs) post processing can last before moving to next cycle'; +$lang['TIME_LIMIT_EXPLAIN_SAFE'] = 'Your php (safe mode) has a timeout of %s secs configured, so stay below this value'; +$lang['TIME_LIMIT_EXPLAIN_WEBSERVER'] = 'Your webserver has a timeout of %s secs configured, so stay below this value'; + +$lang['DISABLE_BOARD'] = 'Disable board'; +$lang['DISABLE_BOARD_EXPLAIN'] = 'Whether or not to disable your board while processing'; +$lang['DISABLE_BOARD_EXPLAIN_ENABLED'] = 'It will be enabled automatically after the end of processing'; +$lang['DISABLE_BOARD_EXPLAIN_ALREADY'] = 'Your board is already disabled'; + +// +// Information strings +// +$lang['INFO_PROCESSING_STOPPED'] = 'You last stopped the processing at post_id %s (%s processed posts) on %s'; +$lang['INFO_PROCESSING_ABORTED'] = 'You last aborted the processing at post_id %s (%s processed posts) on %s'; +$lang['INFO_PROCESSING_ABORTED_SOON'] = 'Please wait some mins before you continue...'; +$lang['INFO_PROCESSING_FINISHED'] = 'You successfully finished the processing (%s processed posts) on %s'; +$lang['INFO_PROCESSING_FINISHED_NEW'] = 'You successfully finished the processing at post_id %s (%s processed posts) on %s,
    but there have been %s new post(s) after that date'; + +// +// Progress screen +// +$lang['REBUILD_SEARCH_PROGRESS'] = 'Rebuild Search Progress'; + +$lang['PROCESSED_POST_IDS'] = 'Processed post ids : %s - %s'; +$lang['TIMER_EXPIRED'] = 'Timer expired at %s secs. '; +$lang['CLEARED_SEARCH_TABLES'] = 'Cleared search tables. '; +$lang['DELETED_POSTS'] = '%s post(s) were deleted by your users during processing. '; +$lang['PROCESSING_NEXT_POSTS'] = 'Processing next %s post(s). Please wait...'; +$lang['ALL_SESSION_POSTS_PROCESSED'] = 'Processed all posts in current session.'; +$lang['ALL_POSTS_PROCESSED'] = 'All posts were processed successfully.'; +$lang['ALL_TABLES_OPTIMIZED'] = 'All search tables were optimized successfully.'; + +$lang['PROCESSING_POST_DETAILS'] = 'Processing post'; +$lang['PROCESSED_POSTS'] = 'Processed Posts'; +$lang['PERCENT'] = 'Percent'; +$lang['CURRENT_SESSION'] = 'Current Session'; +$lang['TOTAL'] = 'Total'; + +$lang['PROCESS_DETAILS'] = 'from %s to %s (out of total %s)'; +$lang['PERCENT_COMPLETED'] = '%s %% completed'; + +$lang['PROCESSING_TIME_DETAILS'] = 'Current session details'; +$lang['PROCESSING_TIME'] = 'Processing time'; +$lang['TIME_LAST_POSTS'] = 'Last %s post(s)'; +$lang['TIME_FROM_THE_BEGINNING'] = 'From the beginning'; +$lang['TIME_AVERAGE'] = 'Average per cycle'; +$lang['TIME_ESTIMATED'] = 'Estimated until finish'; + +$lang['DAYS'] = 'days'; +$lang['HOURS'] = 'hours'; +$lang['MINUTES'] = 'minutes'; +$lang['SECONDS'] = 'seconds'; + +$lang['DATABASE_SIZE_DETAILS'] = 'Database size details'; +$lang['SIZE_CURRENT'] = 'Current'; +$lang['SIZE_ESTIMATED'] = 'Estimated after finish'; +$lang['SIZE_SEARCH_TABLES'] = 'Search Tables size'; +$lang['SIZE_DATABASE'] = 'Database size'; + +$lang['BYTES'] = 'Bytes'; + +$lang['ACTIVE_PARAMETERS'] = 'Active parameters'; +$lang['POSTS_LAST_CYCLE'] = 'Processed post(s) on last cycle'; +$lang['BOARD_STATUS'] = 'Board status'; +$lang['BOARD_DISABLED'] = 'Disabled'; +$lang['BOARD_ENABLED'] = 'Enabled'; + +$lang['INFO_ESTIMATED_VALUES'] = '(*) All the estimated values are calculated approximately
    + based on the current completed percent and may not represent the actual final values.
    + As the completed percent increases the estimated values will come closer to the actual ones.'; + +$lang['CLICK_RETURN_REBUILD_SEARCH'] = 'Click %shere%s to return to Rebuild Search'; +$lang['REBUILD_SEARCH_ABORTED'] = 'Rebuild search aborted at post_id %s.

    If you aborted while processing was on, you have to wait for some mins until you run Rebuild Search again, so the last cycle can finish.'; +$lang['WRONG_INPUT'] = 'You have entered some wrong values. Please check your input and try again.'; + +// Buttons +$lang['NEXT'] = 'Next'; +$lang['PROCESSING'] = 'Processing...'; +$lang['FINISHED'] = 'Finished'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_bbcode.php b/upload/language/lang_english/lang_bbcode.php new file mode 100644 index 000000000..8599171e9 --- /dev/null +++ b/upload/language/lang_english/lang_bbcode.php @@ -0,0 +1,73 @@ +
  • To make a piece of text bold enclose it in [b][/b], eg.

    [b]Hello[/b]

    will become Hello
  • For underlining use [u][/u], for example:

    [u]Good Morning[/u]

    becomes Good Morning
  • To italicise text use [i][/i], eg.

    This is [i]Great![/i]

    would give This is Great!
  • "); +$faq[] = array("How to change the text colour or size", "To alter the color or size of your text the following tags can be used. Keep in mind that how the output appears will depend on the viewers browser and system:
    • Changing the colour of text is achieved by wrapping it in [color=][/color]. You can specify either a recognised colour name (eg. red, blue, yellow, etc.) or the hexadecimal triplet alternative, eg. #FFFFFF, #000000. For example, to create red text you could use:

      [color=red]Hello![/color]

      or

      [color=#FF0000]Hello![/color]

      will both output Hello!
    • Changing the text size is achieved in a similar way using [size=][/size]. This tag is dependent on the template you are using but the recommended format is a numerical value representing the text size in pixels, starting at 1 (so tiny you will not see it) through to 29 (very large). For example:

      [size=9]SMALL[/size]

      will generally be SMALL

      whereas:

      [size=24]HUGE![/size]

      will be HUGE!
    "); +$faq[] = array("Can I combine formatting tags?", "Yes, of course you can; for example to get someones attention you may write:

    [size=18][color=red][b]LOOK AT ME![/b][/color][/size]

    this would output LOOK AT ME!

    We don't recommend you output lots of text that looks like this, though! Remember that it is up to you, the poster, to ensure that tags are closed correctly. For example, the following is incorrect:

    [b][u]This is wrong[/b][/u]"); + +$faq[] = array("--","Quoting and outputting fixed-width text"); +$faq[] = array("Quoting text in replies", "There are two ways you can quote text: with a reference or without.
    • When you utilise the Quote function to reply to a post on the board you should notice that the post text is added to the message window enclosed in a [quote=\"\"][/quote] block. This method allows you to quote with a reference to a person or whatever else you choose to put. For example, to quote a piece of text Mr. Blobby wrote, you would enter:

      [quote=\"Mr. Blobby\"]The text Mr. Blobby wrote would go here[/quote]

      The resulting output will automatically add: Mr. Blobby wrote: before the actual text. Remember that you must include the quotation marks \"\" around the name you are quoting -- they are not optional.
    • The second method allows you to blindly quote something. To utilise this enclose the text in [quote][/quote] tags. When you view the message it will simply show: Quote: before the text itself.
    "); +$faq[] = array("Outputting code or fixed width data", "If you want to output a piece of code or in fact anything that requires a fixed width with a Courier-type font, you should enclose the text in [code][/code] tags, eg.

    [code]echo \"This is some code\";[/code]

    All formatting used within [code][/code] tags is retained when you later view it."); + +$faq[] = array("--","Generating lists"); +$faq[] = array("Creating an Un-ordered list", "BBCode supports two types of lists, unordered and ordered. They are essentially the same as their HTML equivalents. An unordered list ouputs each item in your list sequentially one after the other indenting each with a bullet character. To create an unordered list you use [list][/list] and define each item within the list using [*]. For example, to list your favorite colours you could use:

    [list]
    [*]Red
    [*]Blue
    [*]Yellow
    [/list]

    This would generate the following list:
    • Red
    • Blue
    • Yellow
    "); +$faq[] = array("Creating an Ordered list", "The second type of list, an ordered list gives you control over what is output before each item. To create an ordered list you use [list=1][/list] to create a numbered list or alternatively [list=a][/list] for an alphabetical list. As with the unordered list items are specified using [*]. For example:

    [list=1]
    [*]Go to the shops
    [*]Buy a new computer
    [*]Swear at computer when it crashes
    [/list]

    will generate the following:
    1. Go to the shops
    2. Buy a new computer
    3. Swear at computer when it crashes
    Whereas for an alphabetical list you would use:

    [list=a]
    [*]The first possible answer
    [*]The second possible answer
    [*]The third possible answer
    [/list]

    giving
    1. The first possible answer
    2. The second possible answer
    3. The third possible answer
    "); + +$faq[] = array("--", "Creating Links"); +$faq[] = array("Linking to another site", "phpBB BBCode supports a number of ways of creating URIs, Uniform Resource Indicators better known as URLs.
    • The first of these uses the [url=][/url] tag; whatever you type after the = sign will cause the contents of that tag to act as a URL. For example, to link to phpBB.com you could use:

      [url=http://www.phpbb.com/]Visit phpBB![/url]

      This would generate the following link, Visit phpBB! You will notice the link opens in a new window so the user can continue browsing the forums if they wish.
    • If you want the URL itself displayed as the link you can do this by simply using:

      [url]http://www.phpbb.com/[/url]

      This would generate the following link: http://www.phpbb.com/
    • Additionally phpBB features something called Magic Linkswhich will turn any syntatically correct URL into a link without you needing to specify any tags or even the leading http://. For example typing www.phpbb.com into your message will automatically lead to www.phpbb.com being output when you view the message.
    • The same thing applies equally to email addresses; you can either specify an address explicitly, like:

      [email]no.one@domain.adr[/email]

      which will output no.one@domain.adr or you can just type no.one@domain.adr into your message and it will be automatically converted when you view.
    As with all the BBCode tags you can wrap URLs around any of the other tags such as [img][/img] (see next entry), [b][/b], etc. As with the formatting tags it is up to you to ensure the correct open and close order is following. For example:

    [url=http://www.phpbb.com/][img]http://www.phpbb.com/images/phplogo.gif[/url][/img]

    is not correct which may lead to your post being deleted so take care."); + +$faq[] = array("--", "Showing images in posts"); +$faq[] = array("Adding an image to a post", "phpBB BBCode incorporates a tag for including images in your posts. Two very important things to remember when using this tag are: many users do not appreciate lots of images being shown in posts and second, the image you display must already be available on the Internet (it cannot exist only on your computer, for example, unless you run a webserver!). There is currently no way of storing images locally with phpBB (all these issues are expected to be addressed in the next release of phpBB). To display an image, you must surround the URL pointing to the image with [img][/img] tags. For example:

    [img]http://www.phpbb.com/images/phplogo.gif[/img]

    As noted in the URL section above you can wrap an image in a [url][/url] tag if you wish, eg.

    [url=http://www.phpbb.com/][img]http://www.phpbb.com/images/phplogo.gif[/img][/url]

    would generate:

    \"\"
    "); + +$faq[] = array("--", "Other matters"); +$faq[] = array("Can I add my own tags?", "No, I am afraid not directly in phpBB 2.0. We are looking at offering customisable BBCode tags for the next major version."); + +// +// This ends the BBCode guide entries +// \ No newline at end of file diff --git a/upload/language/lang_english/lang_bot.php b/upload/language/lang_english/lang_bot.php new file mode 100644 index 000000000..9c78f14c2 --- /dev/null +++ b/upload/language/lang_english/lang_bot.php @@ -0,0 +1,5 @@ +%s to forum %s

    %s'; +$lang['BOT_MESS_SPLITS'] = 'Topic has been split. New topic - %s

    %s'; +$lang['BOT_TOPIC_SPLITS'] = 'Topic has been split from %s

    %s'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_callseed.php b/upload/language/lang_english/lang_callseed.php new file mode 100644 index 000000000..7234b8a31 --- /dev/null +++ b/upload/language/lang_english/lang_callseed.php @@ -0,0 +1,16 @@ +
    Your help is needed in the release %s :: %s
    If you decide to help, but already deleted the torrent file, you can download it this

    I hope for your help!'; + +$lang['CALLSEED_MSG_OK'] = 'Message (PM) has been sent to all those who downloaded this release'; +$lang['CALLSEED_MSG_SPAM'] = 'Request has already been once successfully sent (Probably not you) +

    The next opportunity to send a request to be %s hours.
    + Call you can download it only once in day'; +$lang['CALLSEED_MSG_MSG'] = 'Error sending message'; +$lang['CALLSEED_MSG_MSG_TEXT'] = 'Error saving text messages'; +$lang['CALLSEED_MSG_POPUP'] = 'Error of popup'; +$lang['CALLSEED_MSG_TIME'] = 'Unable to set the last query'; +$lang['CALLSEED_HAVE_SEED'] = 'Topic does not require help (Seeders: %d, Leechers: %d)'; + +$lang['CALLSEED_RETURN'] = '

    Back to the topic'; diff --git a/upload/language/lang_english/lang_countries.php b/upload/language/lang_english/lang_countries.php new file mode 100644 index 000000000..25a2c3275 --- /dev/null +++ b/upload/language/lang_english/lang_countries.php @@ -0,0 +1,250 @@ +Log me in automatically box when you log in, the board will only keep you logged in for a preset time. This prevents misuse of your account by anyone else. To stay logged in, check the box during login. This is not recommended if you access the board from a shared computer, e.g. library, internet cafe, university cluster, etc."); +$faq[] = array("How do I prevent my username from appearing in the online user listings?", "In your profile you will find an option Hide your online status; if you switch this on you'll only appear to board administrators or to yourself. You will be counted as a hidden user."); +$faq[] = array("I've lost my password!", "Don't panic! While your password cannot be retrieved it can be reset. To do this go to the login page and click I've forgotten my password. Follow the instructions and you should be back online in no time."); +$faq[] = array("I registered but cannot log in!", "First check that you are entering the correct username and password. If they are okay then one of two things may have happened: if COPPA support is enabled and you clicked the I am under 13 years old link while registering then you will have to follow the instructions you received. If this is not the case then maybe your account need activating. Some boards will require all new registrations be activated, either by yourself or by the administrator before you can log on. When you registered it would have told you whether activation was required. If you were sent an email then follow the instructions; if you did not receive the email then check that your email address is valid. One reason activation is used is to reduce the possibility of rogue users abusing the board anonymously. If you are sure the email address you used is valid then try contacting the board administrator."); +$faq[] = array("I registered in the past but cannot log in anymore!", "The most likely reasons for this are: you entered an incorrect username or password (check the email you were sent when you first registered) or the administrator has deleted your account for some reason. If it is the latter case then perhaps you did not post anything? It is usual for boards to periodically remove users who have not posted anything so as to reduce the size of the database. Try registering again and get involved in discussions."); + + +$faq[] = array("--","User Preferences and settings"); +$faq[] = array("How do I change my settings?", "All your settings (if you are registered) are stored in the database. To alter them click the Profile link (generally shown at the top of pages but this may not be the case). This will allow you to change all your settings."); +$faq[] = array("The times are not correct!", "The times are almost certainly correct; however, what you may be seeing are times displayed in a timezone different from the one you are in. If this is the case, you should change your profile setting for the timezone to match your particular area, e.g. London, Paris, New York, Sydney, etc. Please note that changing the timezone, like most settings, can only be done by registered users. So if you are not registered, this is a good time to do so, if you pardon the pun!"); +$faq[] = array("I changed the timezone and the time is still wrong!", "If you are sure you have set the timezone correctly and the time is still different, the most likely answer is daylight savings time (or summer time as it is known in the UK and other places). The board is not designed to handle the changeovers between standard and daylight time so during summer months the time may be an hour different from the real local time."); +$faq[] = array("My language is not in the list!", "The most likely reasons for this are either the administrator did not install your language or someone has not translated this board into your language. Try asking the board administrator if they can install the language pack you need or if it does not exist, please feel free to create a new translation. More information can be found at the phpBB Group website (see link at bottom of pages)"); +$faq[] = array("How do I show an image below my username?", "There may be two images below a username when viewing posts. The first is an image associated with your rank; generally these take the form of stars or blocks indicating how many posts you have made or your status on the forums. Below this may be a larger image known as an avatar; this is generally unique or personal to each user. It is up to the board administrator to enable avatars and they have a choice over the way in which avatars can be made available. If you are unable to use avatars then this is the decision of the board admin and you should ask them their reasons (we're sure they'll be good!)"); +$faq[] = array("How do I change my rank?", "In general you cannot directly change the wording of any rank (ranks appear below your username in topics and on your profile depending on the style used). Most boards use ranks to indicate the number of posts you have made and to identify certain users. For example, moderators and administrators may have a special rank. Please do not abuse the board by posting unnecessarily just to increase your rank -- you will probably find the moderator or administrator will simply lower your post count."); +$faq[] = array("When I click the email link for a user it asks me to log in.", "Sorry, but only registered users can send email to people via the built-in email form (if the admin has enabled this feature). This is to prevent malicious use of the email system by anonymous users."); + + +$faq[] = array("--","Posting Issues"); +$faq[] = array("How do I post a topic in a forum?", "Easy -- click the relevant button on either the forum or topic screens. You may need to register before you can post a message. The facilities available to you are listed at the bottom of the forum and topic screens (the You can post new topics, You can vote in polls, etc. list)"); +$faq[] = array("How do I edit or delete a post?", "Unless you are the board admin or forum moderator you can only edit or delete your own posts. You can edit a post (sometimes for only a limited time after it was made) by clicking the edit button for the relevant post. If someone has already replied to the post, you will find a small piece of text output below the post when you return to the topic that lists the number of times you edited it. This will only appear if no one has replied; it also will not appear if moderators or administrators edit the post (they should leave a message saying what they altered and why). Please note that normal users cannot delete a post once someone has replied."); +$faq[] = array("How do I add a signature to my post?", "To add a signature to a post you must first create one; this is done via your profile. Once created you can check the Add Signature box on the posting form to add your signature. You can also add a signature by default to all your posts by checking the appropriate radio box in your profile. You can still prevent a signature being added to individual posts by un-checking the add signature box on the posting form."); +$faq[] = array("How do I create a poll?", "Creating a poll is easy -- when you post a new topic (or edit the first post of a topic, if you have permission) you should see a Add Poll form below the main posting box. If you cannot see this then you probably do not have rights to create polls. You should enter a title for the poll and then at least two options -- to set an option type in the poll question and click the Add option button. You can also set a time limit for the poll, 0 being an infinite amount. There will be a limit to the number of options you can list, which is set by the board administrator"); +$faq[] = array("How do I edit or delete a poll?", "As with posts, polls can only be edited by the original poster, a moderator, or board administrator. To edit a poll, click the first post in the topic, which always has the poll associated with it. If no one has cast a vote then users can delete the poll or edit any poll option. However, if people have already placed votes only moderators or administrators can edit or delete it; this is to prevent people rigging polls by changing options mid-way through a poll"); +$faq[] = array("Why can't I access a forum?", "Some forums may be limited to certain users or groups. To view, read, post, etc. you may need special authorization which only the forum moderator and board administrator can grant, so you should contact them."); +$faq[] = array("Why can't I vote in polls?", "Only registered users can vote in polls so as to prevent spoofing of results. If you have registered and still cannot vote then you probably do not have appropriate access rights."); + + +$faq[] = array("--","Formatting and Topic Types"); +$faq[] = array("What is BBCode?", "BBCode is a special implementation of HTML. Whether you can use BBCode is determined by the administrator. You can also disable it on a per post basis from the posting form. BBCode itself is similar in style to HTML: tags are enclosed in square braces [ and ] rather than < and > and it offers greater control over what and how something is displayed. For more information on BBCode see the guide which can be accessed from the posting page."); +$faq[] = array("Can I use HTML?", "That depends on whether the administrator allows you to; they have complete control over it. If you are allowed to use it, you will probably find only certain tags work. This is a safety feature to prevent people from abusing the board by using tags which may destroy the layout or cause other problems. If HTML is enabled you can disable it on a per post basis from the posting form."); +$faq[] = array("What are Smileys?", "Smileys, or Emoticons, are small graphical images which can be used to express some feeling using a short code, e.g. :) means happy, :( means sad. The full list of emoticons can be seen via the posting form. Try not to overuse smileys, though, as they can quickly render a post unreadable and a moderator may decide to edit them out or remove the post altogether."); +$faq[] = array("Can I post Images?", "Images can indeed be shown in your posts. However, there is no facility at present for uploading images directly to this board. Therefore you must link to an image stored on a publicly accessible web server, e.g. http://www.some-unknown-place.net/my-picture.gif. You cannot link to pictures stored on your own PC (unless it is a publicly accessible server) nor to images stored behind authentication mechanisms such as Hotmail or Yahoo mailboxes, password-protected sites, etc. To display the image use either the BBCode [img] tag or appropriate HTML (if allowed)."); +$faq[] = array("What are Announcements?", "Announcements often contain important information and you should read them as soon as possible. Announcements appear at the top of every page in the forum to which they are posted. Whether or not you can post an announcement depends on the permissions required, which are set by the administrator."); +$faq[] = array("What are Sticky topics?", "Sticky topics appear below any announcements in viewforum and only on the first page. They are often quite important so you should read them where possible. As with announcements the board administrator determines what permissions are required to post sticky topics in each forum."); +$faq[] = array("What are Locked topics?", "Locked topics are set this way by either the forum moderator or board administrator. You cannot reply to locked topics and any poll contained inside is automatically ended. Topics may be locked for many reasons."); + + +$faq[] = array("--","User Levels and Groups"); +$faq[] = array("What are Administrators?", "Administrators are people assigned the highest level of control over the entire board. These people can control all facets of board operation which include setting permissions, banning users, creating usergroups or moderators, etc. They also have full moderator capabilities in all the forums."); +$faq[] = array("What are Moderators?", "Moderators are individuals (or groups of individuals) whose job it is to look after the running of the forums from day to day. They have the power to edit or delete posts and lock, unlock, move, delete and split topics in the forum they moderate. Generally moderators are there to prevent people going off-topic or posting abusive or offensive material."); +$faq[] = array("What are Usergroups?", "Usergroups are a way in which board administrators can group users. Each user can belong to several groups (this differs from most other boards) and each group can be assigned individual access rights. This makes it easy for administrators to set up several users as moderators of a forum, or to give them access to a private forum, etc."); +$faq[] = array("How do I join a Usergroup?", "To join a usergroup click the usergroup link on the page header (dependent on template design) and you can then view all usergroups. Not all groups are open access -- some are closed and some may even have hidden memberships. If the board is open then you can request to join it by clicking the appropriate button. The user group moderator will need to approve your request; they may ask why you want to join the group. Please do not pester a group moderator if they turn your request down -- they will have their reasons."); +$faq[] = array("How do I become a Usergroup Moderator?", "Usergroups are initially created by the board administrator who also assigns a board moderator. If you are interested in creating a usergroup then your first point of contact should be the administrator, so try dropping them a private message."); + + +$faq[] = array("--","Private Messaging"); +$faq[] = array("I cannot send private messages!", "There are three reasons for this; you are not registered and/or not logged on, the board administrator has disabled private messaging for the entire board, or the board administrator has prevented you individually from sending messages. If it is the latter case you should try asking the administrator why."); +$faq[] = array("I keep getting unwanted private messages!", "In the future we will be adding an ignore list to the private messaging system. For now, though, if you keep receiving unwanted private messages from someone, inform the board administrator -- they have the power to prevent a user from sending private messages at all."); +$faq[] = array("I have received a spamming or abusive email from someone on this board!", "We are sorry to hear that. The email form feature of this board includes safeguards to try to track users who send such posts. You should email the board administrator with a full copy of the email you received and it is very important this include the headers (these list details of the user that sent the email). They can then take action."); + +// +// These entries should remain in all languages and for all modifications +// +$faq[] = array("--","phpBB 2 Issues"); +$faq[] = array("Who wrote this bulletin board?", "This software (in its unmodified form) is produced, released and is copyrighted phpBB Group. It is made available under the GNU General Public License and may be freely distributed; see link for more details"); +$faq[] = array("Why isn't X feature available?", "This software was written by and licensed through phpBB Group. If you believe a feature needs to be added then please visit the phpbb.com website and see what the phpBB Group has to say. Please do not post feature requests to the board at phpbb.com, as the Group uses sourceforge to handle tasking of new features. Please read through the forums and see what, if any, our position may already be for features and then follow the procedure given there."); +$faq[] = array("Whom do I contact about abusive and/or legal matters related to this board?", "You should contact the administrator of this board. If you cannot find who that is, you should first contact one of the forum moderators and ask them who you should in turn contact. If still get no response you should contact the owner of the domain (do a whois lookup) or, if this is running on a free service (e.g. yahoo, free.fr, f2s.com, etc.), the management or abuse department of that service. Please note that phpBB Group has absolutely no control and cannot in any way be held liable over how, where or by whom this board is used. It is absolutely pointless contacting phpBB Group in relation to any legal (cease and desist, liable, defamatory comment, etc.) matter not directly related to the phpbb.com website or the discrete software of phpBB itself. If you do email phpBB Group about any third party use of this software then you should expect a terse response or no response at all."); + +// +// This ends the FAQ entries +// \ No newline at end of file diff --git a/upload/language/lang_english/lang_faq_attach.php b/upload/language/lang_english/lang_faq_attach.php new file mode 100644 index 000000000..7b6ef9bc4 --- /dev/null +++ b/upload/language/lang_english/lang_faq_attach.php @@ -0,0 +1,31 @@ +Add an Attachment form below the main posting box. When you click the Browse... button the standard Open dialogue window for your computer will open. Browse to the file you want to attach, select it and click OK, Open or doubleclick according to your liking and/or the correct procedure for your computer. If you choose to add a comment in the File Comment field this comment will be used as a link to the attached file. If you haven't added a comment the filename itself will be used to link to the attachment. If the board administrator has allowed it you will be able to upload multiple attachements by following the same procedure as described above until you reach the max allowed number of attachments for each post.

    The board administrator sets an upper limit for filesize, defined file extensions and other things for attachments on the board. Be aware that it's your responsiblity that your attachments comply with the boards acceptance of use policy, and that they may be deleted without warning.

    Please note that the boards owner, webmaster, administrator or moderators can not and will not take responsibility for any loss of data."); +$faq[] = array("How do I add an attachment after the initial posting?", "To add an attachment after the initial posting you'll need to edit your post and follow the description above. The new attachment will be added when you click Submit to add the edited post."); +$faq[] = array("How do I delete an attachment?", "To delete attachments you'll need to edit your post and click on the Delete Attachment next to the attachment you want to delete in the Posted Attachments box. The attachment will be deleted when you click Submit to add the edited post."); +$faq[] = array("How do I update a file comment?", "To update a file comment you'll need to edit your post, edit the text in the File Comment field and click on the Update Comment button next to the file comment you want to update in the Posted Attachments box. The file comment will be updated when you click Submit to add the edited post."); +$faq[] = array("Why isn't my attachment visible in the post?", "Most probably the file or Extension is no longer allowed on the forum, or a moderator or administrator has deleted it for being in conflict with the boards acceptance of use policy."); +$faq[] = array("Why can't I add attachments?", "On some forums adding attachments may be limited to certain users or groups. To add attachments you may need special authorisation, only the forum moderator and board admin can grant this access, you should contact them."); +$faq[] = array("I've got the necessary permissions, why can't I add attachments?", "The board administrator sets an upper limit for filesize, file extensions and other things for attachments on the board. A moderator or administrator may have altered your permissions, or discontinued attachments in the specific forum. You should get an explanation in the error message when trying to add an attachment, if not you might consider contacting the moderator or administrator."); +$faq[] = array("Why can't I delete attachments?", "On some forums deleting attachments may be limited to certain users or groups. To delete attachments you may need special authorisation, only the forum moderator and board admin can grant this access, you should contact them."); +$faq[] = array("Why can't I view/download attachments?", "On some viewing/downloading forums attachments may be limited to certain users or groups. To view/download attachments you may need special authorisation, only the forum moderator and board admin can grant this access, you should contact them."); +$faq[] = array("Who do I contact about illegal or possibly illegal attachments?", "You should contact the administrator of this board. If you cannot find who this is you should first contact one of the forum moderators and ask them who you should in turn contact. If you still get no response you should contact the owner of the domain (do a whois lookup) or, if this is running on a free service (e.g. yahoo, free.fr, f2s.com, etc.), the management or abuse department of that service. Please note that phpBB Group has absolutely no control and cannot in any way be held liable over how, where or by whom this board is used. It is absolutely pointless contacting phpBB Group in relation to any legal (cease and desist, liable, defamatory comment, etc.) matter not directly related to the phpbb.com website or the discrete software of phpBB itself. If you do email phpBB Group about any third party use of this software then you should expect a terse response or no response at all."); \ No newline at end of file diff --git a/upload/language/lang_english/lang_gallery.php b/upload/language/lang_english/lang_gallery.php new file mode 100644 index 000000000..48d18ee62 --- /dev/null +++ b/upload/language/lang_english/lang_gallery.php @@ -0,0 +1,29 @@ + 'Topic:
    deleted', + 'mod_topic_move' => 'Topic:
    moved', + 'mod_topic_lock' => 'Topic:
    closed', + 'mod_topic_unlock' => 'Topic:
    opened', + 'mod_topic_split' => 'Topic:
    split', + 'mod_post_delete' => 'Post:
    deleted', + 'adm_user_delete' => 'User:
    deleted', + 'adm_user_ban' => 'User:
    ban', + 'adm_user_unban' => 'User:
    unban', +); + +$lang['ACTS_LOG_ALL_ACTIONS'] = 'All actions'; +$lang['ACTS_LOG_SEARCH_OPTIONS'] = 'Actions Log: Search options'; +$lang['ACTS_LOG_FORUM'] = 'Forum'; +$lang['ACTS_LOG_ACTION'] = 'Action'; +$lang['ACTS_LOG_USER'] = 'User'; +$lang['ACTS_LOG_LOGS_FROM'] = 'Logs from '; +$lang['ACTS_LOG_FIRST'] = 'first '; +$lang['ACTS_LOG_DAYS_BACK'] = 'days back'; +$lang['ACTS_LOG_TOPIC_MATCH'] = 'Topic title match'; +$lang['ACTS_LOG_SORT_BY'] = 'Sort by'; +$lang['ACTS_LOG_LOGS_ACTION'] = 'Action'; +$lang['ACTS_LOG_USERNAME'] = 'Username'; +$lang['ACTS_LOG_TIME'] = 'Time'; +$lang['ACTS_LOG_INFO'] = 'Info'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_main.php b/upload/language/lang_english/lang_main.php new file mode 100644 index 000000000..07024cab4 --- /dev/null +++ b/upload/language/lang_english/lang_main.php @@ -0,0 +1,1530 @@ +%d of %s'; + +$lang['ICQ'] = 'ICQ Number'; + +$lang['FORUM_INDEX'] = '%s Forum Index'; // eg. sitename Forum Index, %s can be removed if you prefer + +$lang['POST_NEW_TOPIC'] = 'Post new topic'; +$lang['POST_REGULAR_TOPIC'] = 'Post regular topic'; +$lang['REPLY_TO_TOPIC'] = 'Reply to topic'; +$lang['REPLY_WITH_QUOTE'] = 'Reply with quote'; + +$lang['CLICK_RETURN_TOPIC'] = 'Click %sHere%s to return to the topic'; // %s's here are for uris, do not remove! +$lang['CLICK_RETURN_LOGIN'] = 'Click %sHere%s to try again'; +$lang['CLICK_RETURN_FORUM'] = 'Click %sHere%s to return to the forum'; +$lang['CLICK_VIEW_MESSAGE'] = 'Click %sHere%s to view your message'; +$lang['CLICK_RETURN_MODCP'] = 'Click %sHere%s to return to the Moderator Control Panel'; +$lang['CLICK_RETURN_GROUP'] = 'Click %sHere%s to return to group information'; + +$lang['ADMIN_PANEL'] = 'Go to Administration Panel'; + +$lang['BOARD_DISABLE'] = 'Sorry, but this board is currently unavailable. Please try again later.'; + +$lang['LOADING'] = 'Loading...'; +$lang['JUMPBOX_TITLE'] = 'Select forum'; +$lang['DISPLAYING_OPTIONS'] = 'Displaying options'; + +// +// Global Header strings +// +$lang['REGISTERED_USERS'] = 'Registered Users:'; +$lang['BROWSING_FORUM'] = 'Users browsing this forum:'; +$lang['ONLINE_USERS'] = 'In total there are %1$d users online: %2$d Registered and %3$d Guests'; +$lang['RECORD_ONLINE_USERS'] = 'Most users ever online was %s on %s'; // first %s = number of users, second %s is the date. +$lang['USERS'] = 'users'; + +$lang['ONLINE_ADMIN'] = 'Administrator'; +$lang['ONLINE_MOD'] = 'Moderator'; +$lang['ONLINE_GROUP_MEMBER'] = 'Group member'; + +$lang['YOU_LAST_VISIT'] = 'You last visited on: %s'; +$lang['CURRENT_TIME'] = 'The time now is: %s'; + +$lang['SEARCH_NEW'] = 'View newest posts'; +$lang['SEARCH_SELF'] = 'my posts'; +$lang['SEARCH_SELF_BY_LAST'] = 'last post time'; +$lang['SEARCH_SELF_BY_MY'] = 'my post time'; +$lang['SEARCH_UNANSWERED'] = 'View unanswered posts'; +$lang['SEARCH_UNANSWERED_SHORT'] = 'unanswered'; +$lang['SEARCH_LATEST'] = 'latest'; + +$lang['REGISTER'] = 'Register'; +$lang['PROFILE'] = 'Profile'; +$lang['EDIT_PROFILE'] = 'Edit your profile'; +$lang['SEARCH'] = 'Search'; +$lang['MEMBERLIST'] = 'Memberlist'; +$lang['FAQ'] = 'FAQ'; +$lang['BBCODE_GUIDE'] = 'BBCode Guide'; +$lang['USERGROUPS'] = 'Usergroups'; +$lang['LASTPOST'] = 'Last Post'; +$lang['MODERATOR'] = 'Moderator'; +$lang['MODERATORS'] = 'Moderators'; +$lang['TERMS'] = 'Terms'; + +// +// Stats block text +// +$lang['POSTED_TOPICS_TOTAL'] = 'Our users have posted a total of %s topics'; // Number of topics +$lang['POSTED_ARTICLES_ZERO_TOTAL'] = 'Our users have posted a total of 0 articles'; // Number of posts +$lang['POSTED_ARTICLES_TOTAL'] = 'Our users have posted a total of %s articles'; // Number of posts +$lang['REGISTERED_USERS_ZERO_TOTAL'] = 'We have 0 registered users'; // # registered users +$lang['REGISTERED_USERS_TOTAL'] = 'We have %s registered users'; // # registered users +$lang['NEWEST_USER'] = 'The newest registered user is %s%s%s'; // a href, username, /a + +// Tracker stats +$lang['TORRENTS_STAT'] = 'Torrents: %s,  total size: %s'; // first %s = number of torrents, second %s is the total size. +$lang['PEERS_STAT'] = 'Peers: %s,  seeders: %s,  leechers: %s'; // first %s = number of peers, second %s = number of seeders, third %s = number of leechers. +$lang['SPEED_STAT'] = 'Total speed: %s '; // %s = total speed. + +$lang['NO_NEW_POSTS_LAST_VISIT'] = 'No new posts since your last visit'; +$lang['NO_NEW_POSTS'] = 'No new posts'; +$lang['NEW_POSTS'] = 'New posts'; +$lang['NEW_POST'] = 'New post'; +$lang['NO_NEW_POSTS_HOT'] = 'No new posts [ Popular ]'; +$lang['NEW_POSTS_HOT'] = 'New posts [ Popular ]'; +$lang['NO_NEW_POSTS_LOCKED'] = 'Locked'; +$lang['NEW_POSTS_LOCKED'] = 'New posts [ Locked ]'; +$lang['FORUM_LOCKED_MAIN'] = 'Forum is locked'; + + +// +// Login +// +$lang['ENTER_PASSWORD'] = 'Please enter your username and password to log in.'; +$lang['LOGIN'] = 'Log in'; +$lang['LOGOUT'] = 'Log out'; +$lang['CONFIRM_LOGOUT'] = 'Are you sure you want to log out?'; + +$lang['FORGOTTEN_PASSWORD'] = 'Forgot password?'; +$lang['AUTO_LOGIN'] = 'Log me on automatically each visit'; +$lang['ERROR_LOGIN'] = 'You have specified an incorrect or inactive username, or an invalid password.'; +$lang['REMEMBER'] = 'Remember'; +$lang['USER_WELCOME'] = 'Welcome,'; + +// +// Index page +// +$lang['INDEX'] = 'Index'; +$lang['HOME'] = 'Home'; +$lang['NO_POSTS'] = 'No Posts'; +$lang['NO_FORUMS'] = 'This board has no forums'; + +$lang['PRIVATE_MESSAGE'] = 'Private Message'; +$lang['PRIVATE_MESSAGES'] = 'Private Messages'; +$lang['WHOSONLINE'] = 'Who is Online'; + +$lang['MARK_ALL_FORUMS_READ'] = 'Mark all forums read'; +$lang['FORUMS_MARKED_READ'] = 'All forums have been marked read'; + +$lang['LATEST_NEWS'] = 'Latest news'; +$lang['SUBFORUMS'] = 'Subforums'; + +// +// Viewforum +// +$lang['VIEW_FORUM'] = 'View Forum'; + +$lang['FORUM_NOT_EXIST'] = 'The forum you selected does not exist.'; +$lang['REACHED_ON_ERROR'] = 'You have reached this page in error.'; + +$lang['DISPLAY_TOPICS'] = 'Display topics from previous'; +$lang['ALL_TOPICS'] = 'All Topics'; +$lang['TOPICS_PER_PAGE'] = 'topics per page'; +$lang['MODERATE_FORUM'] = 'Moderate this forum'; +$lang['TITLE_SEARCH_HINT'] = 'search title...'; + +$lang['TOPIC_ANNOUNCEMENT'] = 'Announcement:'; +$lang['TOPIC_STICKY'] = 'Sticky:'; +$lang['TOPIC_MOVED'] = 'Moved:'; +$lang['TOPIC_POLL'] = '[ Poll ]'; + +$lang['MARK_TOPICS_READ'] = 'Mark all topics read'; +$lang['TOPICS_MARKED_READ'] = 'The topics for this forum have now been marked read'; + +$lang['RULES_POST_CAN'] = 'You can post new topics in this forum'; +$lang['RULES_POST_CANNOT'] = 'You cannot post new topics in this forum'; +$lang['RULES_REPLY_CAN'] = 'You can reply to topics in this forum'; +$lang['RULES_REPLY_CANNOT'] = 'You cannot reply to topics in this forum'; +$lang['RULES_EDIT_CAN'] = 'You can edit your posts in this forum'; +$lang['RULES_EDIT_CANNOT'] = 'You cannot edit your posts in this forum'; +$lang['RULES_DELETE_CAN'] = 'You can delete your posts in this forum'; +$lang['RULES_DELETE_CANNOT'] = 'You cannot delete your posts in this forum'; +$lang['RULES_VOTE_CAN'] = 'You can vote in polls in this forum'; +$lang['RULES_VOTE_CANNOT'] = 'You cannot vote in polls in this forum'; +$lang['RULES_MODERATE'] = 'You can moderate this forum'; + +$lang['NO_TOPICS_POST_ONE'] = 'There are no posts in this forum.
    Click on the Post New Topic link on this page to post one.'; + + +// +// Viewtopic +// +$lang['VIEW_TOPIC'] = 'View topic'; + +$lang['GUEST'] = 'Guest'; +$lang['POST_SUBJECT'] = 'Post subject'; +$lang['SUBMIT_VOTE'] = 'Submit Vote'; +$lang['VIEW_RESULTS'] = 'View Results'; + +$lang['NO_NEWER_TOPICS'] = 'There are no newer topics in this forum'; +$lang['NO_OLDER_TOPICS'] = 'There are no older topics in this forum'; +$lang['TOPIC_POST_NOT_EXIST'] = 'The topic or post you requested does not exist'; +$lang['NO_POSTS_TOPIC'] = 'No posts exist for this topic'; + +$lang['DISPLAY_POSTS'] = 'Display posts from previous'; +$lang['ALL_POSTS'] = 'All Posts'; +$lang['NEWEST_FIRST'] = 'Newest First'; +$lang['OLDEST_FIRST'] = 'Oldest First'; + +$lang['BACK_TO_TOP'] = 'Back to top'; + +$lang['READ_PROFILE'] = 'View user\'s profile'; +$lang['VISIT_WEBSITE'] = 'Visit poster\'s website'; +$lang['VIEW_IP'] = 'View IP address of poster'; +$lang['MODERATE_POST'] = 'Moderate posts'; +$lang['DELETE_POST'] = 'Delete this post'; + +$lang['WROTE'] = 'wrote'; // proceeds the username and is followed by the quoted text +$lang['QUOTE'] = 'Quote'; // comes before bbcode quote output. +$lang['CODE'] = 'Code'; // comes before bbcode code output. +$lang['CODE_COPIED'] = 'Code copied to clipboard'; +$lang['CODE_COPY'] = 'copy to clipboard'; +$lang['SPOILER_HEAD'] = 'hidden text'; + +$lang['EDITED_TIME_TOTAL'] = 'Last edited by %s on %s; edited %d time in total'; // Last edited by me on 12 Oct 2001; edited 1 time in total +$lang['EDITED_TIMES_TOTAL'] = 'Last edited by %s on %s; edited %d times in total'; // Last edited by me on 12 Oct 2001; edited 2 times in total + +$lang['LOCK_TOPIC'] = 'Lock this topic'; +$lang['UNLOCK_TOPIC'] = 'Unlock this topic'; +$lang['MOVE_TOPIC'] = 'Move this topic'; +$lang['DELETE_TOPIC'] = 'Delete this topic'; +$lang['SPLIT_TOPIC'] = 'Split this topic'; + +$lang['STOP_WATCHING_TOPIC'] = 'Stop watching this topic'; +$lang['START_WATCHING_TOPIC'] = 'Watch this topic for replies'; +$lang['NO_LONGER_WATCHING'] = 'You are no longer watching this topic'; +$lang['YOU_ARE_WATCHING'] = 'You are now watching this topic'; + +$lang['TOTAL_VOTES'] = 'Total Votes'; +$lang['SEARCH_IN_TOPIC'] = 'search in topic...'; +$lang['HIDE_IN_TOPIC'] = 'Hide'; + +$lang['FLAGS'] = 'flags'; +$lang['AVATARS'] = 'avatars'; +$lang['RANK_IMAGES'] = 'rank images'; +$lang['POST_IMAGES'] = 'post images'; +$lang['SMILIES'] = 'smilies'; +$lang['SIGNATURES'] = 'signatures'; +$lang['SPOILER'] = 'Spoiler'; +$lang['SHOW_OPENED'] = 'show opened'; + +$lang['MODERATE_TOPIC'] = 'Moderate this topic'; +$lang['SELECT_POSTS_PER_PAGE'] = 'posts per page'; + +// +// Posting/Replying (Not private messaging!) +// +$lang['MESSAGE_BODY'] = 'Message body'; +$lang['TOPIC_REVIEW'] = 'Topic review'; + +$lang['NO_POST_MODE'] = 'No post mode specified'; // If posting.php is called without a mode (newtopic/reply/delete/etc, shouldn't be shown normaly) + +$lang['POST_A_NEW_TOPIC'] = 'Post a new topic'; +$lang['POST_A_REPLY'] = 'Post a reply'; +$lang['POST_TOPIC_AS'] = 'Post topic as'; +$lang['EDIT_POST'] = 'Edit post'; +$lang['OPTIONS'] = 'Options'; + +$lang['POST_ANNOUNCEMENT'] = 'Announcement'; +$lang['POST_STICKY'] = 'Sticky'; +$lang['POST_NORMAL'] = 'Normal'; +$lang['POST_DOWNLOAD'] = 'Download'; + +$lang['CONFIRM_DELETE'] = 'Are you sure you want to delete this post?'; +$lang['CONFIRM_DELETE_POLL'] = 'Are you sure you want to delete this poll?'; + +$lang['FLOOD_ERROR'] = 'You cannot make another post so soon after your last; please try again in a short while.'; +$lang['EMPTY_SUBJECT'] = 'You must specify a subject when posting a new topic.'; +$lang['EMPTY_MESSAGE'] = 'You must enter a message when posting.'; +$lang['FORUM_LOCKED'] = 'This forum is locked: you cannot post, reply to, or edit topics.'; +$lang['TOPIC_LOCKED'] = 'This topic is locked: you cannot edit posts or make replies.'; +$lang['TOPIC_LOCKED_SHORT'] = 'Topic locked'; +$lang['NO_POST_ID'] = 'You must select a post to edit'; +$lang['NO_TOPIC_ID'] = 'You must select a topic to reply to'; +$lang['NO_VALID_MODE'] = 'You can only post, reply, edit, or quote messages. Please return and try again.'; +$lang['NO_SUCH_POST'] = 'There is no such post. Please return and try again.'; +$lang['EDIT_OWN_POSTS'] = 'Sorry, but you can only edit your own posts.'; +$lang['DELETE_OWN_POSTS'] = 'Sorry, but you can only delete your own posts.'; +$lang['CANNOT_DELETE_REPLIED'] = 'Sorry, but you may not delete posts that have been replied to.'; +$lang['CANNOT_DELETE_POLL'] = 'Sorry, but you cannot delete an active poll.'; +$lang['EMPTY_POLL_TITLE'] = 'You must enter a title for your poll.'; +$lang['TO_FEW_POLL_OPTIONS'] = 'You must enter at least two poll options.'; +$lang['TO_MANY_POLL_OPTIONS'] = 'You have tried to enter too many poll options.'; +$lang['POST_HAS_NO_POLL'] = 'This post has no poll.'; +$lang['ALREADY_VOTED'] = 'You have already voted in this poll.'; +$lang['NO_VOTE_OPTION'] = 'You must specify an option when voting.'; +$lang['LOCKED_WARN'] = 'You posted into locked topic!'; + +$lang['ADD_POLL'] = 'Add a Poll'; +$lang['ADD_POLL_EXPLAIN'] = 'If you do not want to add a poll to your topic, leave the fields blank.'; +$lang['POLL_QUESTION'] = 'Poll question'; +$lang['POLL_OPTION'] = 'Poll option'; +$lang['ADD_OPTION'] = 'Add option'; +$lang['UPDATE'] = 'Update'; +$lang['DELETE'] = 'Delete'; +$lang['POLL_FOR'] = 'Run poll for'; +$lang['DAYS'] = 'Days'; +$lang['POLL_FOR_EXPLAIN'] = '[ Enter 0 or leave blank for a never-ending poll ]'; +$lang['DELETE_POLL'] = 'Delete Poll'; + +$lang['DISABLE_BBCODE_POST'] = 'Disable BBCode in this post'; +$lang['DISABLE_SMILIES_POST'] = 'Disable Smilies in this post'; + +$lang['BBCODE_IS_ON'] = '%sBBCode%s is ON'; // %s are replaced with URI pointing to FAQ +$lang['BBCODE_IS_OFF'] = '%sBBCode%s is OFF'; +$lang['SMILIES_ARE_ON'] = 'Smilies are ON'; +$lang['SMILIES_ARE_OFF'] = 'Smilies are OFF'; + +$lang['ATTACH_SIGNATURE'] = 'Attach signature (signatures can be changed in profile)'; +$lang['NOTIFY'] = 'Notify me when a reply is posted'; + +$lang['STORED'] = 'Your message has been entered successfully.'; +$lang['DELETED'] = 'Your message has been deleted successfully.'; +$lang['POLL_DELETE'] = 'Your poll has been deleted successfully.'; +$lang['VOTE_CAST'] = 'Your vote has been cast.'; + +$lang['TOPIC_REPLY_NOTIFICATION'] = 'Topic Reply Notification'; + +$lang['BBCODE_B_HELP'] = 'Bold text: [b]text[/b] (alt+b)'; +$lang['BBCODE_I_HELP'] = 'Italic text: [i]text[/i] (alt+i)'; +$lang['BBCODE_U_HELP'] = 'Underline text: [u]text[/u] (alt+u)'; +$lang['BBCODE_Q_HELP'] = 'Quote text: [quote]text[/quote] (alt+q)'; +$lang['BBCODE_C_HELP'] = 'Code display: [code]code[/code] (alt+c)'; +$lang['BBCODE_L_HELP'] = 'List: [list]text[/list] (alt+l)'; +$lang['BBCODE_O_HELP'] = 'Ordered list: [list=]text[/list] (alt+o)'; +$lang['BBCODE_P_HELP'] = 'Insert image: [img]http://image_url[/img] (alt+p)'; +$lang['BBCODE_W_HELP'] = 'Insert URL: [url]http://url[/url] or [url=http://url]URL text[/url] (alt+w)'; +$lang['BBCODE_A_HELP'] = 'Close all open bbCode tags'; +$lang['BBCODE_S_HELP'] = 'Font color: [color=red]text[/color] Tip: you can also use color=#FF0000'; +$lang['BBCODE_F_HELP'] = 'Font size: [size=x-small]small text[/size]'; + +$lang['EMOTICONS'] = 'Emoticons'; +$lang['MORE_EMOTICONS'] = 'View more Emoticons'; + +$lang['FONT_COLOR'] = 'Font colour'; +$lang['COLOR_DEFAULT'] = 'Default'; +$lang['COLOR_DARK_RED'] = 'Dark Red'; +$lang['COLOR_RED'] = 'Red'; +$lang['COLOR_ORANGE'] = 'Orange'; +$lang['COLOR_BROWN'] = 'Brown'; +$lang['COLOR_YELLOW'] = 'Yellow'; +$lang['COLOR_GREEN'] = 'Green'; +$lang['COLOR_OLIVE'] = 'Olive'; +$lang['COLOR_CYAN'] = 'Cyan'; +$lang['COLOR_BLUE'] = 'Blue'; +$lang['COLOR_DARK_BLUE'] = 'Dark Blue'; +$lang['COLOR_INDIGO'] = 'Indigo'; +$lang['COLOR_VIOLET'] = 'Violet'; +$lang['COLOR_WHITE'] = 'White'; +$lang['COLOR_BLACK'] = 'Black'; + +$lang['FONT_SIZE'] = 'Font size'; +$lang['FONT_TINY'] = 'Tiny'; +$lang['FONT_SMALL'] = 'Small'; +$lang['FONT_NORMAL'] = 'Normal'; +$lang['FONT_LARGE'] = 'Large'; +$lang['FONT_HUGE'] = 'Huge'; + +$lang['STYLES_TIP'] = 'Tip: Styles can be applied quickly to selected text.'; + +$lang['NEW_POSTS_PREVIEW'] = 'Topic has new, edited or unread posts'; + +// +// Private Messaging +// +$lang['PRIVATE_MESSAGING'] = 'Private Messaging'; + +$lang['NO_NEW_PM'] = 'no new messages'; + +$lang['NEW_PMS_FORMAT'] = '%1$s %2$s'; // 1 new message +$lang['NEW_PMS_DECLENSION'] = array('new message', 'new messages'); + +$lang['UNREAD_PMS_FORMAT'] = '%1$s %2$s'; // 1 new message +$lang['UNREAD_PMS_DECLENSION'] = array('unread', 'unread'); + +$lang['UNREAD_MESSAGE'] = 'Unread message'; +$lang['READ_MESSAGE'] = 'Read message'; + +$lang['READ_PM'] = 'Read message'; +$lang['POST_NEW_PM'] = 'Post message'; +$lang['POST_REPLY_PM'] = 'Reply to message'; +$lang['POST_QUOTE_PM'] = 'Quote message'; +$lang['EDIT_PM'] = 'Edit message'; + +$lang['INBOX'] = 'Inbox'; +$lang['OUTBOX'] = 'Outbox'; +$lang['SAVEBOX'] = 'Savebox'; +$lang['SENTBOX'] = 'Sentbox'; +$lang['FLAG'] = 'Flag'; +$lang['SUBJECT'] = 'Subject'; +$lang['FROM'] = 'From'; +$lang['TO'] = 'To'; +$lang['DATE'] = 'Date'; +$lang['MARK'] = 'Mark'; +$lang['SENT'] = 'Sent'; +$lang['SAVED'] = 'Saved'; +$lang['DELETE_MARKED'] = 'Delete Marked'; +$lang['DELETE_ALL'] = 'Delete All'; +$lang['SAVE_MARKED'] = 'Save Marked'; +$lang['SAVE_MESSAGE'] = 'Save Message'; +$lang['DELETE_MESSAGE'] = 'Delete Message'; + +$lang['DISPLAY_MESSAGES'] = 'Display messages from previous'; // Followed by number of days/weeks/months +$lang['ALL_MESSAGES'] = 'All Messages'; + +$lang['NO_MESSAGES_FOLDER'] = 'You have no messages in this folder'; + +$lang['PM_DISABLED'] = 'Private messaging has been disabled on this board.'; +$lang['CANNOT_SEND_PRIVMSG'] = 'Sorry, but the administrator has prevented you from sending private messages.'; +$lang['NO_TO_USER'] = 'You must specify a username to whom to send this message.'; +$lang['NO_SUCH_USER'] = 'Sorry, but no such user exists.'; + +$lang['GALLERY_DISABLE'] = 'Gallery disable'; + +$lang['DISABLE_BBCODE_PM'] = 'Disable BBCode in this message'; +$lang['DISABLE_SMILIES_PM'] = 'Disable Smilies in this message'; + +$lang['MESSAGE_SENT'] = 'Your message has been sent.'; + +$lang['CLICK_RETURN_INBOX'] = 'Return to your:

    %sInbox%s'; +$lang['CLICK_RETURN_SENTBOX'] = '   %sSentbox%s'; +$lang['CLICK_RETURN_OUTBOX'] = '   %sOutbox%s'; +$lang['CLICK_RETURN_SAVEBOX'] = '   %sSavebox%s'; +$lang['CLICK_RETURN_INDEX'] = '%sReturn to the Index%s'; + +$lang['SEND_A_NEW_MESSAGE'] = 'Send a new private message'; +$lang['SEND_A_REPLY'] = 'Reply to a private message'; +$lang['EDIT_MESSAGE'] = 'Edit private message'; + +$lang['NOTIFICATION_SUBJECT'] = 'New Private Message has arrived!'; + +$lang['FIND_USERNAME'] = 'Find a username'; +$lang['SELECT_USERNAME'] = 'Select a Username'; +$lang['FIND'] = 'Find'; +$lang['NO_MATCH'] = 'No matches found.'; + +$lang['NO_POST_ID'] = 'No post ID was specified'; +$lang['NO_SUCH_FOLDER'] = 'No such folder exists'; +$lang['NO_FOLDER'] = 'No folder specified'; + +$lang['MARK_ALL'] = 'Mark all'; +$lang['UNMARK_ALL'] = 'Unmark all'; + +$lang['CONFIRM_DELETE_PM'] = 'Are you sure you want to delete this message?'; +$lang['CONFIRM_DELETE_PMS'] = 'Are you sure you want to delete these messages?'; + +$lang['INBOX_SIZE'] = 'Your Inbox is
    %d%% full'; // eg. Your Inbox is 50% full +$lang['SENTBOX_SIZE'] = 'Your Sentbox is
    %d%% full'; +$lang['SAVEBOX_SIZE'] = 'Your Savebox is
    %d%% full'; + +$lang['CLICK_VIEW_PRIVMSG'] = 'Click %sHere%s to visit your Inbox'; + +$lang['OUTBOX_EXPL'] = ''; + +// +// Profiles/Registration +// +$lang['VIEWING_USER_PROFILE'] = 'Viewing profile :: %s'; // %s is username +$lang['ABOUT_USER'] = 'All about %s'; // %s is username + +$lang['DISABLED_USER'] = 'Account disabled'; +$lang['MANAGE_USER'] = 'Administration'; + +$lang['PREFERENCES'] = 'Preferences'; +$lang['ITEMS_REQUIRED'] = 'Items marked with a * are required unless stated otherwise.'; +$lang['REGISTRATION_INFO'] = 'Registration Information'; +$lang['PROFILE_INFO'] = 'Profile Information'; +$lang['PROFILE_INFO_WARN'] = 'This information will be publicly viewable'; +$lang['AVATAR_PANEL'] = 'Avatar control panel'; +$lang['AVATAR_GALLERY'] = 'Avatar gallery'; + +$lang['WEBSITE'] = 'Website'; +$lang['LOCATION'] = 'Location'; +$lang['CONTACT'] = 'Contact'; +$lang['EMAIL_ADDRESS'] = 'E-mail address'; +$lang['SEND_PRIVATE_MESSAGE'] = 'Send private message'; +$lang['HIDDEN_EMAIL'] = '[ Hidden ]'; +$lang['INTERESTS'] = 'Interests'; +$lang['OCCUPATION'] = 'Occupation'; +$lang['POSTER_RANK'] = 'Poster rank'; + +$lang['TOTAL_POSTS'] = 'Total posts'; +$lang['USER_POST_PCT_STATS'] = '%.2f%% of total'; // 1.25% of total +$lang['USER_POST_DAY_STATS'] = '%.2f posts per day'; // 1.5 posts per day +$lang['SEARCH_USER_POSTS'] = 'Find posts by %s'; // Find all posts by username +$lang['SEARCH_USER_POSTS_SHORT'] = 'Find user posts'; +$lang['SEARCH_USER_TOPICS'] = 'Find user topics'; // Find all topics by username + +$lang['NO_USER_ID_SPECIFIED'] = 'Sorry, but that user does not exist.'; +$lang['WRONG_PROFILE'] = 'You cannot modify a profile that is not your own.'; + +$lang['ONLY_ONE_AVATAR'] = 'Only one type of avatar can be specified'; +$lang['FILE_NO_DATA'] = 'The file at the URL you gave contains no data'; +$lang['NO_CONNECTION_URL'] = 'A connection could not be made to the URL you gave'; +$lang['INCOMPLETE_URL'] = 'The URL you entered is incomplete'; +$lang['WRONG_REMOTE_AVATAR_FORMAT'] = 'The URL of the remote avatar is not valid'; +$lang['NO_SEND_ACCOUNT_INACTIVE'] = 'Sorry, but your password cannot be retrieved because your account is currently inactive'; +$lang['NO_SEND_ACCOUNT'] = 'Sorry, but your password cannot be retrieved. Please contact the forum administrator for more information'; + +$lang['ALWAYS_ADD_SIG'] = 'Always attach my signature'; +$lang['HIDE_PORN_FORUMS'] = 'Hide porno forums'; +$lang['ALWAYS_NOTIFY'] = 'Always notify me of replies'; +$lang['ALWAYS_NOTIFY_EXPLAIN'] = 'Sends an e-mail when someone replies to a topic you have posted in. This can be changed whenever you post.'; + +$lang['BOARD_STYLE'] = 'Board Style'; +$lang['BOARD_LANG'] = 'Board Language'; +$lang['NO_THEMES'] = 'No Themes In database'; +$lang['TIMEZONE'] = 'Timezone'; +$lang['DATE_FORMAT_PROFILE'] = 'Date format'; +$lang['DATE_FORMAT_EXPLAIN'] = 'The syntax used is identical to the PHP date() function.'; +$lang['SIGNATURE'] = 'Signature'; +$lang['SIGNATURE_EXPLAIN'] = 'This is a block of text that can be added to posts you make. There is a %d character limit'; +$lang['PUBLIC_VIEW_EMAIL'] = 'Always show my e-mail address'; + +$lang['CURRENT_PASSWORD'] = 'Current password'; +$lang['NEW_PASSWORD'] = 'New password'; +$lang['CONFIRM_PASSWORD'] = 'Confirm password'; +$lang['CONFIRM_PASSWORD_EXPLAIN'] = 'You must confirm your current password if you wish to change it or alter your e-mail address'; +$lang['PASSWORD_IF_CHANGED'] = 'You only need to supply a password if you want to change it'; +$lang['PASSWORD_CONFIRM_IF_CHANGED'] = 'You only need to confirm your password if you changed it above'; + +$lang['AUTOLOGIN'] = 'Autologin'; +$lang['RESET_AUTOLOGIN'] = 'Reset autologin key'; +$lang['RESET_AUTOLOGIN_EXPL'] = ''; + +$lang['AVATAR'] = 'Avatar'; +$lang['AVATAR_EXPLAIN'] = 'Displays a small graphic image below your details in posts. Only one image can be displayed at a time, its width can be no greater than %d pixels, the height no greater than %d pixels, and the file size no more than %d KB.'; +$lang['UPLOAD_AVATAR_FILE'] = 'Upload Avatar from your machine'; +$lang['UPLOAD_AVATAR_URL'] = 'Upload Avatar from a URL'; +$lang['UPLOAD_AVATAR_URL_EXPLAIN'] = 'Enter the URL of the location containing the Avatar image, it will be copied to this site.'; +$lang['PICK_LOCAL_AVATAR'] = 'Select Avatar from the gallery'; +$lang['LINK_REMOTE_AVATAR'] = 'Link to off-site Avatar'; +$lang['LINK_REMOTE_AVATAR_EXPLAIN'] = 'Enter the URL of the location containing the Avatar image you wish to link to.'; +$lang['AVATAR_URL'] = 'URL of Avatar Image'; +$lang['SELECT_FROM_GALLERY'] = 'Select Avatar from gallery'; +$lang['VIEW_AVATAR_GALLERY'] = 'Show gallery'; + +$lang['SELECT_AVATAR'] = 'Select avatar'; +$lang['RETURN_PROFILE'] = 'Cancel avatar'; +$lang['SELECT_CATEGORY'] = 'Select category'; + +$lang['DELETE_IMAGE'] = 'Delete Image'; +$lang['CURRENT_IMAGE'] = 'Current Image'; + +$lang['NOTIFY_ON_PRIVMSG'] = 'Notify on new Private Message'; +$lang['HIDE_USER'] = 'Hide your online status'; + +$lang['PROFILE_UPDATED'] = 'Your profile has been updated'; +$lang['PROFILE_UPDATED_INACTIVE'] = 'Your profile has been updated. However, you have changed vital details, thus your account is now inactive. Check your e-mail to find out how to reactivate your account, or if admin activation is required, wait for the administrator to reactivate it.'; + +$lang['PASSWORD_MISMATCH'] = 'The passwords you entered did not match.'; +$lang['CURRENT_PASSWORD_MISMATCH'] = 'The current password you supplied does not match that stored in the database.'; +$lang['PASSWORD_LONG'] = 'Your password must be no more than 32 characters.'; +$lang['TOO_MANY_REGISTERS'] = 'You have made too many registration attempts. Please try again later.'; +$lang['USERNAME_TAKEN'] = 'Sorry, but this username has already been taken.'; +$lang['USERNAME_INVALID'] = 'Sorry, but this username contains an invalid character such as \'.'; +$lang['USERNAME_DISALLOWED'] = 'Sorry, but this username has been disallowed.'; +$lang['EMAIL_TAKEN'] = 'Sorry, but that e-mail address is already registered to a user.'; +$lang['EMAIL_BANNED'] = 'Sorry, but %s address has been banned.'; +$lang['EMAIL_INVALID'] = 'Sorry, but this e-mail address is invalid.'; +$lang['SIGNATURE_TOO_LONG'] = 'Your signature is too long.'; +$lang['FIELDS_EMPTY'] = 'You must fill in the required fields.'; +$lang['AVATAR_FILETYPE'] = 'The avatar filetype must be .jpg, .gif or .png'; +$lang['AVATAR_FILESIZE'] = 'The avatar image file size must be less than %d KB'; // The avatar image file size must be less than 6 KB +$lang['AVATAR_IMAGESIZE'] = 'The avatar must be less than %d pixels wide and %d pixels high'; + +$lang['WELCOME_SUBJECT'] = 'Welcome to %s Forums'; // Welcome to my.com forums +$lang['NEW_ACCOUNT_SUBJECT'] = 'New user account'; +$lang['ACCOUNT_ACTIVATED_SUBJECT'] = 'Account Activated'; + +$lang['ACCOUNT_ADDED'] = 'Thank you for registering. Your account has been created. You may now log in with your username and password'; +$lang['ACCOUNT_INACTIVE'] = 'Your account has been created. However, this forum requires account activation. An activation key has been sent to the e-mail address you provided. Please check your e-mail for further information'; +$lang['ACCOUNT_INACTIVE_ADMIN'] = 'Your account has been created. However, this forum requires account activation by the administrator. An e-mail has been sent to them and you will be informed when your account has been activated'; +$lang['ACCOUNT_ACTIVE'] = 'Your account has now been activated. Thank you for registering'; +$lang['ACCOUNT_ACTIVE_ADMIN'] = 'The account has now been activated'; +$lang['REACTIVATE'] = 'Reactivate your account!'; +$lang['ALREADY_ACTIVATED'] = 'You have already activated your account'; + +$lang['REGISTRATION'] = 'Registration Agreement Terms'; + +$lang['WRONG_ACTIVATION'] = 'The activation key you supplied does not match any in the database.'; +$lang['SEND_PASSWORD'] = 'Send me a new password'; +$lang['PASSWORD_UPDATED'] = 'A new password has been created; please check your e-mail for details on how to activate it.'; +$lang['NO_EMAIL_MATCH'] = 'The e-mail address you supplied does not match the one listed for that username.'; +$lang['NEW_PASSWORD_ACTIVATION'] = 'New password activation'; +$lang['PASSWORD_ACTIVATED'] = 'Your account has been re-activated. To log in, please use the password supplied in the e-mail you received.'; + +$lang['SEND_EMAIL_MSG'] = 'Send an e-mail message'; +$lang['NO_USER_SPECIFIED'] = 'No user was specified'; +$lang['USER_PREVENT_EMAIL'] = 'This user does not wish to receive e-mail. Try sending them a private message.'; +$lang['USER_NOT_EXIST'] = 'That user does not exist'; +$lang['CC_EMAIL'] = 'Send a copy of this e-mail to yourself'; +$lang['EMAIL_MESSAGE_DESC'] = 'This message will be sent as plain text, so do not include any HTML or BBCode. The return address for this message will be set to your e-mail address.'; +$lang['FLOOD_EMAIL_LIMIT'] = 'You cannot send another e-mail at this time. Try again later.'; +$lang['RECIPIENT'] = 'Recipient'; +$lang['EMAIL_SENT'] = 'The e-mail has been sent.'; +$lang['SEND_EMAIL'] = 'Send e-mail'; +$lang['EMPTY_SUBJECT_EMAIL'] = 'You must specify a subject for the e-mail.'; +$lang['EMPTY_MESSAGE_EMAIL'] = 'You must enter a message to be e-mailed.'; + +$lang['USER_AGREEMENT'] = 'User Agreement'; +$lang['USER_AGREEMENT_HEAD'] = 'In order to proceed, you must agree with the following rules'; +$lang['USER_AGREEMENT_AGREE'] = 'I have read and agree to the User Agreement above'; + +$lang['COPYRIGHT_HOLDERS'] = 'For Copyright Holders'; +$lang['ADVERT'] = 'Advertise on this site'; + +// +// Visual confirmation system strings +// +$lang['CONFIRM_CODE_WRONG'] = 'The confirmation code you entered was incorrect'; +$lang['TOO_MANY_REGISTERS'] = 'You have exceeded the number of registration attempts for this session. Please try again later.'; +$lang['CONFIRM_CODE_IMPAIRED'] = 'If you are visually impaired or cannot otherwise read this code please contact the %sAdministrator%s for help.'; +$lang['CONFIRM_CODE'] = 'Confirmation code'; +$lang['CONFIRM_CODE_EXPLAIN'] = 'Enter the code exactly as you see it. The code is case sensitive and zero has a diagonal line through it.'; + + + +// +// Memberslist +// +$lang['SORT'] = 'Sort'; +$lang['SORT_TOP_TEN'] = 'Top Ten Posters'; +$lang['SORT_JOINED'] = 'Joined Date'; +$lang['SORT_USERNAME'] = 'Username'; +$lang['SORT_LOCATION'] = 'Location'; +$lang['SORT_POSTS'] = 'Total posts'; +$lang['SORT_EMAIL'] = 'Email'; +$lang['SORT_WEBSITE'] = 'Website'; +$lang['ASC'] = 'Ascending'; +$lang['DESC'] = 'Descending'; +$lang['ORDER'] = 'Order'; + + +// +// Group control panel +// +$lang['GROUP_CONTROL_PANEL'] = 'User Groups'; +$lang['MEMBERSHIP_DETAILS'] = 'Group Membership Details'; +$lang['JOIN_A_GROUP'] = 'Join a Group'; + +$lang['GROUP_INFORMATION'] = 'Group Information'; +$lang['GROUP_NAME'] = 'Group name'; +$lang['GROUP_DESCRIPTION'] = 'Group description'; +$lang['GROUP_MEMBERSHIP'] = 'Group membership'; +$lang['GROUP_MEMBERS'] = 'Group Members'; +$lang['GROUP_MODERATOR'] = 'Group Moderator'; +$lang['PENDING_MEMBERS'] = 'Pending Members'; + +$lang['GROUP_TYPE'] = 'Group type'; +$lang['GROUP_OPEN'] = 'Open group'; +$lang['GROUP_CLOSED'] = 'Closed group'; +$lang['GROUP_HIDDEN'] = 'Hidden group'; + +$lang["GROUP_MEMBER_MOD"] = 'Group moderator'; +$lang["GROUP_MEMBER_MEMBER"] = 'Current memberships'; +$lang["GROUP_MEMBER_PENDING"] = 'Memberships pending'; +$lang["GROUP_MEMBER_OPEN"] = 'Open groups'; +$lang["GROUP_MEMBER_CLOSED"] = 'Closed groups'; +$lang["GROUP_MEMBER_HIDDEN"] = 'Hidden groups'; + +$lang['NO_GROUPS_EXIST'] = 'No Groups Exist'; +$lang['GROUP_NOT_EXIST'] = 'That user group does not exist'; + +$lang['NO_GROUP_MEMBERS'] = 'This group has no members'; +$lang['HIDDEN_GROUP_MEMBERS'] = 'This group is hidden; you cannot view its membership'; +$lang['NO_PENDING_GROUP_MEMBERS'] = 'This group has no pending members'; +$lang['GROUP_JOINED'] = 'You have successfully subscribed to this group.
    You will be notified when your subscription is approved by the group moderator.'; +$lang['GROUP_REQUEST'] = 'A request to join your group has been made.'; +$lang['GROUP_APPROVED'] = 'Your request has been approved.'; +$lang['GROUP_ADDED'] = 'You have been added to this usergroup.'; +$lang['ALREADY_MEMBER_GROUP'] = 'You are already a member of this group'; +$lang['USER_IS_MEMBER_GROUP'] = 'User is already a member of this group'; +$lang['GROUP_TYPE_UPDATED'] = 'Successfully updated group type.'; + +$lang['COULD_NOT_ADD_USER'] = 'The user you selected does not exist.'; +$lang['COULD_NOT_ANON_USER'] = 'You cannot make Anonymous a group member.'; + +$lang['CONFIRM_UNSUB'] = 'Are you sure you want to unsubscribe from this group?'; +$lang['CONFIRM_UNSUB_PENDING'] = 'Your subscription to this group has not yet been approved; are you sure you want to unsubscribe?'; + +$lang['UNSUB_SUCCESS'] = 'You have been un-subscribed from this group.'; + +$lang['APPROVE_SELECTED'] = 'Approve Selected'; +$lang['DENY_SELECTED'] = 'Deny Selected'; +$lang['NOT_LOGGED_IN'] = 'You must be logged in to join a group.'; +$lang['REMOVE_SELECTED'] = 'Remove Selected'; +$lang['ADD_MEMBER'] = 'Add Member'; +$lang['NOT_GROUP_MODERATOR'] = 'You are not this group\'s moderator, therefore you cannot perform that action.'; + +$lang['LOGIN_TO_JOIN'] = 'Log in to join or manage group memberships'; +$lang['THIS_OPEN_GROUP'] = 'This is an open group: click to request membership'; +$lang['THIS_CLOSED_GROUP'] = 'This is a closed group: no more users accepted'; +$lang['THIS_HIDDEN_GROUP'] = 'This is a hidden group: automatic user addition is not allowed'; +$lang['MEMBER_THIS_GROUP'] = 'You are a member of this group'; +$lang['PENDING_THIS_GROUP'] = 'Your membership of this group is pending'; +$lang['ARE_GROUP_MODERATOR'] = 'You are the group moderator'; +$lang['NONE'] = 'None'; + +$lang['SUBSCRIBE'] = 'Subscribe'; +$lang['UNSUBSCRIBE_GROUP'] = 'Unsubscribe'; +$lang['VIEW_INFORMATION'] = 'View Information'; + + +// +// Search +// +$lang['SEARCH_QUERY'] = 'Search Query'; +$lang['SEARCH_OPTIONS'] = 'Search Options'; + +$lang['SEARCH_WORDS'] = 'Search for Keywords'; +$lang['SEARCH_WORDS_EXPL'] = 'You can use + to define words which must be in the results and - to define words which should not be in the result (ex: "+word1 -word2"). Use * as a wildcard for partial matches'; +$lang['SEARCH_AUTHOR'] = 'Search for Author'; +$lang['SEARCH_AUTHOR_EXPL'] = 'Use * as a wildcard for partial matches'; + +$lang['SEARCH_TITLES_ONLY'] = 'Search topic titles only'; +$lang['SEARCH_ALL_WORDS'] = 'all words'; +$lang['IN_MY_POSTS'] = 'In my posts'; +$lang['SEARCH_MY_TOPICS'] = 'in my topics'; +$lang['NEW_TOPICS'] = 'New topics'; + +$lang['RETURN_FIRST'] = 'Return first'; // followed by xxx characters in a select box +$lang['CHARACTERS_POSTS'] = 'characters of posts'; + +$lang['SEARCH_PREVIOUS'] = 'Search previous'; + +$lang['SORT_BY'] = 'Sort by'; +$lang['SORT_TIME'] = 'Post Time'; +$lang['SORT_POST_SUBJECT'] = 'Post Subject'; +$lang['SORT_TOPIC_TITLE'] = 'Topic Title'; +$lang['SORT_AUTHOR'] = 'Author'; +$lang['SORT_FORUM'] = 'Forum'; + +$lang['DISPLAY_RESULTS_AS'] = 'Display results as'; +$lang['ALL_AVAILABLE'] = 'All available'; +$lang['BRIEFLY'] = 'Briefly'; +$lang['NO_SEARCHABLE_FORUMS'] = 'You do not have permissions to search any forum on this site.'; + +$lang['NO_SEARCH_MATCH'] = 'No topics or posts met your search criteria'; +$lang['FOUND_SEARCH_MATCH'] = 'Search found %d match'; // eg. Search found 1 match +$lang['FOUND_SEARCH_MATCHES'] = 'Search found %d matches'; // eg. Search found 24 matches +$lang['TOO_MANY_SEARCH_RESULTS'] = 'Too many results may be found, please try to be more specific'; + +$lang['CLOSE_WINDOW'] = 'Close Window'; +$lang['CLOSE'] = 'close'; +$lang['HIDE'] = 'hide'; +$lang['SEARCH_TERMS'] = 'Search terms'; + +// +// Auth related entries +// +// Note the %s will be replaced with one of the following 'user' arrays +$lang['SORRY_AUTH_VIEW'] = 'Sorry, but only %s can view this forum.'; +$lang['SORRY_AUTH_READ'] = 'Sorry, but only %s can read topics in this forum.'; +$lang['SORRY_AUTH_POST'] = 'Sorry, but only %s can post topics in this forum.'; +$lang['SORRY_AUTH_REPLY'] = 'Sorry, but only %s can reply to posts in this forum.'; +$lang['SORRY_AUTH_EDIT'] = 'Sorry, but only %s can edit posts in this forum.'; +$lang['SORRY_AUTH_DELETE'] = 'Sorry, but only %s can delete posts in this forum.'; +$lang['SORRY_AUTH_VOTE'] = 'Sorry, but only %s can vote in polls in this forum.'; +$lang['SORRY_AUTH_STICKY'] = 'Sorry, but only %s can post sticky messages in this forum.'; +$lang['SORRY_AUTH_ANNOUNCE'] = 'Sorry, but only %s can post announcements in this forum.'; + +// These replace the %s in the above strings +$lang['AUTH_ANONYMOUS_USERS'] = 'anonymous users'; +$lang['AUTH_REGISTERED_USERS'] = 'registered users'; +$lang['AUTH_USERS_GRANTED_ACCESS'] = 'users granted special access'; +$lang['AUTH_MODERATORS'] = 'moderators'; +$lang['AUTH_ADMINISTRATORS'] = 'administrators'; + +$lang['NOT_MODERATOR'] = 'You are not a moderator of this forum.'; +$lang['NOT_AUTHORISED'] = 'Not Authorised'; + +$lang['YOU_BEEN_BANNED'] = 'You have been banned from this forum.
    Please contact the webmaster or board administrator for more information.'; + + +// +// Viewonline +// +$lang['REG_USERS_ZERO_ONLINE'] = 'There are 0 Registered users and '; // There are 5 Registered and +$lang['REG_USERS_ONLINE'] = 'There are %d Registered users and '; // There are 5 Registered and +$lang['REG_USER_ONLINE'] = 'There is %d Registered user and '; // There is 1 Registered and +$lang['HIDDEN_USERS_ZERO_ONLINE'] = '0 Hidden users online'; // 6 Hidden users online +$lang['HIDDEN_USERS_ONLINE'] = '%d Hidden users online'; // 6 Hidden users online +$lang['HIDDEN_USER_ONLINE'] = '%d Hidden user online'; // 6 Hidden users online +$lang['GUEST_USERS_ONLINE'] = 'There are %d Guest users online'; // There are 10 Guest users online +$lang['GUEST_USERS_ZERO_ONLINE'] = 'There are 0 Guest users online'; // There are 10 Guest users online +$lang['GUEST_USER_ONLINE'] = 'There is %d Guest user online'; // There is 1 Guest user online +$lang['NO_USERS_BROWSING'] = 'There are no users currently browsing this forum'; + +$lang['ONLINE_EXPLAIN'] = 'users active over the past five minutes'; +$lang['LAST_UPDATED'] = 'Last Updated'; + +// +// Moderator Control Panel +// +$lang['MOD_CP'] = 'Moderator Control Panel'; +$lang['MOD_CP_EXPLAIN'] = 'Using the form below you can perform mass moderation operations on this forum. You can lock, unlock, move or delete any number of topics.'; + +$lang['SELECT'] = 'Select'; +$lang['DELETE'] = 'Delete'; +$lang['MOVE'] = 'Move'; +$lang['LOCK'] = 'Lock'; +$lang['UNLOCK'] = 'Unlock'; + +$lang['TOPICS_REMOVED'] = 'The selected topics have been successfully removed from the database.'; +$lang['TOPICS_LOCKED'] = 'The selected topics have been locked.'; +$lang['TOPICS_MOVED'] = 'The selected topics have been moved.'; +$lang['TOPICS_UNLOCKED'] = 'The selected topics have been unlocked.'; +$lang['NO_TOPICS_MOVED'] = 'No topics were moved.'; + +$lang['CONFIRM_DELETE_TOPIC'] = 'Are you sure you want to remove the selected topic/s?'; +$lang['CONFIRM_LOCK_TOPIC'] = 'Are you sure you want to lock the selected topic/s?'; +$lang['CONFIRM_UNLOCK_TOPIC'] = 'Are you sure you want to unlock the selected topic/s?'; +$lang['CONFIRM_MOVE_TOPIC'] = 'Are you sure you want to move the selected topic/s?'; + +$lang['MOVE_TO_FORUM'] = 'Move to forum'; +$lang['LEAVE_SHADOW_TOPIC'] = 'Leave shadow topic in old forum.'; + +$lang['SPLIT_TOPIC'] = 'Split Topic Control Panel'; +$lang['SPLIT_TOPIC_EXPLAIN'] = 'Using the form below you can split a topic in two, either by selecting the posts individually or by splitting at a selected post'; +$lang['NEW_TOPIC_TITLE'] = 'New topic title'; +$lang['FORUM_FOR_NEW_TOPIC'] = 'Forum for new topic'; +$lang['SPLIT_POSTS'] = 'Split selected posts'; +$lang['SPLIT_AFTER'] = 'Split from selected post'; +$lang['TOPIC_SPLIT'] = 'The selected topic has been split successfully'; + +$lang['TOO_MANY_ERROR'] = 'You have selected too many posts. You can only select one post to split a topic after!'; + +$lang['NONE_SELECTED'] = 'You have none selected to perform this operation on. Please go back and select at least one.'; +$lang['NEW_FORUM'] = 'New forum'; + +$lang['THIS_POSTS_IP'] = 'IP address for this post'; +$lang['OTHER_IP_THIS_USER'] = 'Other IP addresses this user has posted from'; +$lang['USERS_THIS_IP'] = 'Users posting from this IP address'; +$lang['IP_INFO'] = 'IP Information'; +$lang['LOOKUP_IP'] = 'Look up IP address'; + + +// +// Timezones ... for display on each page +// +$lang['ALL_TIMES'] = 'All times are %s'; // eg. All times are GMT - 12 Hours (times from next block) + +$lang['-12'] = 'GMT - 12 Hours'; +$lang['-11'] = 'GMT - 11 Hours'; +$lang['-10'] = 'GMT - 10 Hours'; +$lang['-9'] = 'GMT - 9 Hours'; +$lang['-8'] = 'GMT - 8 Hours'; +$lang['-7'] = 'GMT - 7 Hours'; +$lang['-6'] = 'GMT - 6 Hours'; +$lang['-5'] = 'GMT - 5 Hours'; +$lang['-4'] = 'GMT - 4 Hours'; +$lang['-3.5'] = 'GMT - 3.5 Hours'; +$lang['-3'] = 'GMT - 3 Hours'; +$lang['-2'] = 'GMT - 2 Hours'; +$lang['-1'] = 'GMT - 1 Hours'; +$lang['0'] = 'GMT'; +$lang['1'] = 'GMT + 1 Hour'; +$lang['2'] = 'GMT + 2 Hours'; +$lang['3'] = 'GMT + 3 Hours'; +$lang['3.5'] = 'GMT + 3.5 Hours'; +$lang['4'] = 'GMT + 4 Hours'; +$lang['4.5'] = 'GMT + 4.5 Hours'; +$lang['5'] = 'GMT + 5 Hours'; +$lang['5.5'] = 'GMT + 5.5 Hours'; +$lang['6'] = 'GMT + 6 Hours'; +$lang['6.5'] = 'GMT + 6.5 Hours'; +$lang['7'] = 'GMT + 7 Hours'; +$lang['8'] = 'GMT + 8 Hours'; +$lang['9'] = 'GMT + 9 Hours'; +$lang['9.5'] = 'GMT + 9.5 Hours'; +$lang['10'] = 'GMT + 10 Hours'; +$lang['11'] = 'GMT + 11 Hours'; +$lang['12'] = 'GMT + 12 Hours'; +$lang['13'] = 'GMT + 13 Hours'; + +// These are displayed in the timezone select box +$lang['TZ']['-12'] = 'GMT - 12 Hours'; +$lang['TZ']['-11'] = 'GMT - 11 Hours'; +$lang['TZ']['-10'] = 'GMT - 10 Hours'; +$lang['TZ']['-9'] = 'GMT - 9 Hours'; +$lang['TZ']['-8'] = 'GMT - 8 Hours'; +$lang['TZ']['-7'] = 'GMT - 7 Hours'; +$lang['TZ']['-6'] = 'GMT - 6 Hours'; +$lang['TZ']['-5'] = 'GMT - 5 Hours'; +$lang['TZ']['-4'] = 'GMT - 4 Hours'; +$lang['TZ']['-3.5'] = 'GMT - 3.5 Hours'; +$lang['TZ']['-3'] = 'GMT - 3 Hours'; +$lang['TZ']['-2'] = 'GMT - 2 Hours'; +$lang['TZ']['-1'] = 'GMT - 1 Hours'; +$lang['TZ']['0'] = 'GMT'; +$lang['TZ']['1'] = 'GMT + 1 Hour'; +$lang['TZ']['2'] = 'GMT + 2 Hours'; +$lang['TZ']['3'] = 'GMT + 3 Hours'; +$lang['TZ']['3.5'] = 'GMT + 3.5 Hours'; +$lang['TZ']['4'] = 'GMT + 4 Hours'; +$lang['TZ']['4.5'] = 'GMT + 4.5 Hours'; +$lang['TZ']['5'] = 'GMT + 5 Hours'; +$lang['TZ']['5.5'] = 'GMT + 5.5 Hours'; +$lang['TZ']['6'] = 'GMT + 6 Hours'; +$lang['TZ']['6.5'] = 'GMT + 6.5 Hours'; +$lang['TZ']['7'] = 'GMT + 7 Hours'; +$lang['TZ']['8'] = 'GMT + 8 Hours'; +$lang['TZ']['9'] = 'GMT + 9 Hours'; +$lang['TZ']['9.5'] = 'GMT + 9.5 Hours'; +$lang['TZ']['10'] = 'GMT + 10 Hours'; +$lang['TZ']['11'] = 'GMT + 11 Hours'; +$lang['TZ']['12'] = 'GMT + 12 Hours'; +$lang['TZ']['13'] = 'GMT + 13 Hours'; + +$lang['DATETIME']['SUNDAY'] = 'Sunday'; +$lang['DATETIME']['MONDAY'] = 'Monday'; +$lang['DATETIME']['TUESDAY'] = 'Tuesday'; +$lang['DATETIME']['WEDNESDAY'] = 'Wednesday'; +$lang['DATETIME']['THURSDAY'] = 'Thursday'; +$lang['DATETIME']['FRIDAY'] = 'Friday'; +$lang['DATETIME']['SATURDAY'] = 'Saturday'; +$lang['DATETIME']['SUN'] = 'Sun'; +$lang['DATETIME']['MON'] = 'Mon'; +$lang['DATETIME']['TUE'] = 'Tue'; +$lang['DATETIME']['WED'] = 'Wed'; +$lang['DATETIME']['THU'] = 'Thu'; +$lang['DATETIME']['FRI'] = 'Fri'; +$lang['DATETIME']['SAT'] = 'Sat'; +$lang['DATETIME']['JANUARY'] = 'January'; +$lang['DATETIME']['FEBRUARY'] = 'February'; +$lang['DATETIME']['MARCH'] = 'March'; +$lang['DATETIME']['APRIL'] = 'April'; +$lang['DATETIME']['MAY'] = 'May'; +$lang['DATETIME']['JUNE'] = 'June'; +$lang['DATETIME']['JULY'] = 'July'; +$lang['DATETIME']['AUGUST'] = 'August'; +$lang['DATETIME']['SEPTEMBER'] = 'September'; +$lang['DATETIME']['OCTOBER'] = 'October'; +$lang['DATETIME']['NOVEMBER'] = 'November'; +$lang['DATETIME']['DECEMBER'] = 'December'; +$lang['DATETIME']['JAN'] = 'Jan'; +$lang['DATETIME']['FEB'] = 'Feb'; +$lang['DATETIME']['MAR'] = 'Mar'; +$lang['DATETIME']['APR'] = 'Apr'; +$lang['DATETIME']['JUN'] = 'Jun'; +$lang['DATETIME']['JUL'] = 'Jul'; +$lang['DATETIME']['AUG'] = 'Aug'; +$lang['DATETIME']['SEP'] = 'Sep'; +$lang['DATETIME']['OCT'] = 'Oct'; +$lang['DATETIME']['NOV'] = 'Nov'; +$lang['DATETIME']['DEC'] = 'Dec'; + +// +// Errors (not related to a +// specific failure on a page) +// +$lang['INFORMATION'] = 'Information'; +$lang['CRITICAL_INFORMATION'] = 'Critical Information'; + +$lang['GENERAL_ERROR'] = 'Error'; +$lang['CRITICAL_ERROR'] = 'Critical Error'; +$lang['AN_ERROR_OCCURED'] = 'An Error Occurred'; +$lang['A_CRITICAL_ERROR'] = 'A Critical Error Occurred'; + +$lang['ADMIN_REAUTHENTICATE'] = 'To administer/moderate the board you must re-authenticate yourself.'; +$lang['LOGIN_ATTEMPTS_EXCEEDED'] = 'The maximum number of %s login attempts has been exceeded. You are not allowed to login for the next %s minutes.'; + +// +// Attachment Mod Main Language Variables +// + +// Auth Related Entries +$lang['RULES_ATTACH_CAN'] = 'You can attach files in this forum'; +$lang['RULES_ATTACH_CANNOT'] = 'You cannot attach files in this forum'; +$lang['RULES_DOWNLOAD_CAN'] = 'You can download files in this forum'; +$lang['RULES_DOWNLOAD_CANNOT'] = 'You cannot download files in this forum'; +$lang['SORRY_AUTH_VIEW_ATTACH'] = 'Sorry but you are not authorized to view or download this Attachment'; + +// Viewtopic -> Display of Attachments +$lang['DESCRIPTION'] = 'Description'; // used in Administration Panel too... +$lang['DOWNLOAD'] = 'Download'; // this Language Variable is defined in lang_admin.php too, but we are unable to access it from the main Language File +$lang['FILESIZE'] = 'Filesize'; +$lang['VIEWED'] = 'Viewed'; +$lang['DOWNLOAD_NUMBER'] = '%d times'; // replace %d with count +$lang['EXTENSION_DISABLED_AFTER_POSTING'] = 'The Extension \'%s\' was deactivated by an board admin, therefore this Attachment is not displayed.'; // used in Posts and PM's, replace %s with mime type + +// Posting/PM -> Posting Attachments +$lang['ADD_ATTACHMENT'] = 'Add Attachment'; +$lang['ADD_ATTACHMENT_TITLE'] = 'Add an Attachment'; +$lang['ADD_ATTACHMENT_EXPLAIN'] = 'If you do not want to add an Attachment to your Post, please leave the Fields blank'; +$lang['FILE_NAME'] = 'Filename'; +$lang['FILE_COMMENT'] = 'File Comment'; + +// Posting/PM -> Posted Attachments +$lang['POSTED_ATTACHMENTS'] = 'Posted Attachments'; +$lang['UPDATE_COMMENT'] = 'Update Comment'; +$lang['DELETE_ATTACHMENTS'] = 'Delete Attachments'; +$lang['DELETE_ATTACHMENT'] = 'Delete Attachment'; +$lang['DELETE_THUMBNAIL'] = 'Delete Thumbnail'; +$lang['UPLOAD_NEW_VERSION'] = 'Upload New Version'; + +// Errors -> Posting Attachments +$lang['INVALID_FILENAME'] = '%s is an invalid filename'; // replace %s with given filename +$lang['ATTACHMENT_PHP_SIZE_NA'] = 'The Attachment is too big.
    Couldn\'t get the maximum Size defined in PHP.
    The Attachment Mod is unable to determine the maximum Upload Size defined in the php.ini.'; +$lang['ATTACHMENT_PHP_SIZE_OVERRUN'] = 'The Attachment is too big.
    Maximum Upload Size: %d MB.
    Please note that this Size is defined in php.ini, this means it\'s set by PHP and the Attachment Mod can not override this value.'; // replace %d with ini_get('upload_max_filesize') +$lang['DISALLOWED_EXTENSION'] = 'The Extension %s is not allowed'; // replace %s with extension (e.g. .php) +$lang['DISALLOWED_EXTENSION_WITHIN_FORUM'] = 'You are not allowed to post Files with the Extension %s within this Forum'; // replace %s with the Extension +$lang['ATTACHMENT_TOO_BIG'] = 'The Attachment is too big.
    Max Size: %d %s'; // replace %d with maximum file size, %s with size var +$lang['ATTACH_QUOTA_REACHED'] = 'Sorry, but the maximum filesize for all Attachments is reached. Please contact the Board Administrator if you have questions.'; +$lang['TOO_MANY_ATTACHMENTS'] = 'Attachment cannot be added, since the max. number of %d Attachments in this post was achieved'; // replace %d with maximum number of attachments +$lang['ERROR_IMAGESIZE'] = 'The Attachment/Image must be less than %d pixels wide and %d pixels high'; +$lang['GENERAL_UPLOAD_ERROR'] = 'Upload Error: Could not upload Attachment to %s.'; // replace %s with local path + +$lang['ERROR_EMPTY_ADD_ATTACHBOX'] = 'You have to enter values in the \'Add an Attachment\' Box'; +$lang['ERROR_MISSING_OLD_ENTRY'] = 'Unable to Update Attachment, could not find old Attachment Entry'; + +// Errors -> PM Related +$lang['ATTACH_QUOTA_SENDER_PM_REACHED'] = 'Sorry, but the maximum filesize for all Attachments in your Private Message Folder has been reached. Please delete some of your received/sent Attachments.'; +$lang['ATTACH_QUOTA_RECEIVER_PM_REACHED'] = 'Sorry, but the maximum filesize for all Attachments in the Private Message Folder of \'%s\' has been reached. Please let him know, or wait until he/she has deleted some of his/her Attachments.'; + +// Errors -> Download +$lang['NO_ATTACHMENT_SELECTED'] = 'You haven\'t selected an attachment to download or view.'; +$lang['ERROR_NO_ATTACHMENT'] = 'The selected Attachment does not exist anymore'; + +// Delete Attachments +$lang['CONFIRM_DELETE_ATTACHMENTS'] = 'Are you sure you want to delete the selected Attachments?'; +$lang['DELETED_ATTACHMENTS'] = 'The selected Attachments have been deleted.'; +$lang['ERROR_DELETED_ATTACHMENTS'] = 'Could not delete Attachments.'; +$lang['CONFIRM_DELETE_PM_ATTACHMENTS'] = 'Are you sure you want to delete all Attachments posted in this PM?'; + +// General Error Messages +$lang['ATTACHMENT_FEATURE_DISABLED'] = 'The Attachment Feature is disabled.'; + +$lang['DIRECTORY_DOES_NOT_EXIST'] = 'The Directory \'%s\' does not exist or couldn\'t be found.'; // replace %s with directory +$lang['DIRECTORY_IS_NOT_A_DIR'] = 'Please check if \'%s\' is a directory.'; // replace %s with directory +$lang['DIRECTORY_NOT_WRITEABLE'] = 'Directory \'%s\' is not writeable. You\'ll have to create the upload path and chmod it to 777 (or change the owner to you httpd-servers owner) to upload files.
    If you have only plain ftp-access change the \'Attribute\' of the directory to rwxrwxrwx.'; // replace %s with directory + +$lang['FTP_ERROR_CONNECT'] = 'Could not connect to FTP Server: \'%s\'. Please check your FTP-Settings.'; +$lang['FTP_ERROR_LOGIN'] = 'Could not login to FTP Server. The Username \'%s\' or the Password is wrong. Please check your FTP-Settings.'; +$lang['FTP_ERROR_PATH'] = 'Could not access ftp directory: \'%s\'. Please check your FTP Settings.'; +$lang['FTP_ERROR_UPLOAD'] = 'Could not upload files to ftp directory: \'%s\'. Please check your FTP Settings.'; +$lang['FTP_ERROR_DELETE'] = 'Could not delete files in ftp directory: \'%s\'. Please check your FTP Settings.
    Another reason for this error could be the non-existence of the Attachment, please check this first in Shadow Attachments.'; +$lang['FTP_ERROR_PASV_MODE'] = 'Unable to enable/disable FTP Passive Mode'; + +// Attach Rules Window +$lang['RULES_PAGE'] = 'Attachment Rules'; +$lang['ATTACH_RULES_TITLE'] = 'Allowed Extension Groups and their Sizes'; +$lang['GROUP_RULE_HEADER'] = '%s -> Maximum Upload Size: %s'; // Replace first %s with Extension Group, second one with the Size STRING +$lang['ALLOWED_EXTENSIONS_AND_SIZES'] = 'Allowed Extensions and Sizes'; +$lang['NOTE_USER_EMPTY_GROUP_PERMISSIONS'] = 'NOTE:
    You are normally allowed to attach files within this Forum,
    but since no Extension Group is allowed to be attached here,
    you are unable to attach anything. If you try,
    you will receive an Error Message.
    '; + +// Quota Variables +$lang['UPLOAD_QUOTA'] = 'Upload Quota'; +$lang['PM_QUOTA'] = 'PM Quota'; +$lang['USER_UPLOAD_QUOTA_REACHED'] = 'Sorry, you have reached your maximum Upload Quota Limit of %d %s'; // replace %d with Size, %s with Size Lang (MB for example) + +// User Attachment Control Panel +$lang['USER_ACP_TITLE'] = 'User ACP'; +$lang['UACP'] = 'User Attachment Control Panel'; +$lang['USER_UPLOADED_PROFILE'] = 'Uploaded: %s'; +$lang['USER_QUOTA_PROFILE'] = 'Quota: %s'; +$lang['UPLOAD_PERCENT_PROFILE'] = '%d%% of total'; + +// Common Variables +$lang['BYTES'] = 'Bytes'; +$lang['KB'] = 'KB'; +$lang['MB'] = 'MB'; +$lang['ATTACH_SEARCH_QUERY'] = 'Search Attachments'; +$lang['TEST_SETTINGS'] = 'Test Settings'; +$lang['NOT_ASSIGNED'] = 'Not Assigned'; +$lang['NO_FILE_COMMENT_AVAILABLE'] = 'No File Comment available'; +$lang['ATTACHBOX_LIMIT'] = 'Your Attachbox is
    %d%% full'; +$lang['NO_QUOTA_LIMIT'] = 'No Quota Limit'; +$lang['UNLIMITED'] = 'Unlimited'; + +//bt +$lang['BT_REG_YES'] = 'Registered'; +$lang['BT_REG_NO'] = 'Not registered'; +$lang['BT_ADDED'] = 'Added'; +$lang['BT_REG_ON_TRACKER'] = 'Register on tracker'; +$lang['BT_REG_FAIL'] = 'Could not register torrent on tracker'; +$lang['BT_REG_FAIL_SAME_HASH'] = 'Another torrent with same info_hash already registered'; +$lang['BT_UNREG_FROM_TRACKER'] = 'Remove from tracker'; +$lang['BT_UNREGISTERED'] = 'Torrent unregistered'; +$lang['BT_REGISTERED'] = 'Torrent registered on tracker

    Now you need to download your torrent and run it using your BitTorrent client choosing the folder with the original files you\'re sharing as the download path'; +$lang['INVALID_ANN_URL'] = 'Invalid Announce URL [%s]

    must be %s'; +$lang['PASSKEY_ERR_TOR_NOT_REG'] = 'Could not add passkey

    Torrent not registered on tracker'; +$lang['PASSKEY_ERR_EMPTY'] = 'Could not add passkey (passkey is empty)

    Go to your forum profile and generate it'; +$lang['BT_GEN_PASSKEY'] = 'Passkey'; +$lang['BT_GEN_PASSKEY_URL'] = 'Generate or change Passkey'; +$lang['BT_GEN_PASSKEY_EXPLAIN'] = 'Generate your personal id for torrent tracker'; +$lang['BT_GEN_PASSKEY_EXPLAIN_2'] = "Warning! After generating new id you'll need to redownload all active torrent's!"; +$lang['BT_GEN_PASSKEY_OK'] = 'New personal identifier generated'; +$lang['BT_NO_SEARCHABLE_FORUMS'] = 'No searchable forums found'; + +$lang['SEEDERS'] = 'Seeders'; +$lang['LEECHERS'] = 'Leechers'; +$lang['RELEASING'] = 'Self'; +$lang['SEEDING'] = 'Seeding'; +$lang['LEECHING'] = 'Leeching'; +$lang['IS_REGISTERED'] = 'Registered'; +$lang['MAGNET'] = 'Magnet'; + +//torrent status mod +$lang['TOR_STATUS'] = 'Status'; +$lang['TOR_STATUS_SELECT_ACTION'] = 'Select status'; +$lang['TOR_STATUS_CHECKED'] = 'checked';//2 +$lang['TOR_STATUS_NOT_CHECKED'] = 'not checked';//0 +$lang['TOR_STATUS_CLOSED'] = 'closed';//1 +$lang['TOR_STATUS_D'] = 'repeat';//3 +$lang['TOR_STATUS_NOT_PERFECT'] = 'neoformleno';//4 +$lang['TOR_STATUS_PART_PERFECT'] = 'nedooformleno';//5 +$lang['TOR_STATUS_FISHILY'] = 'doubtful';//6 +$lang['TOR_STATUS_COPY'] = 'closed right';//7 +//end torrent status mod + +$lang['BT_TOPIC_TITLE'] = 'Topic title'; +$lang['BT_SEEDER_LAST_SEEN'] = 'Seed last seen'; +$lang['BT_SORT_FORUM'] = 'Forum'; +$lang['SIZE'] = 'Size'; +$lang['PIECE_LENGTH'] = 'Piece length'; +$lang['COMPLETED'] = 'Completed'; +$lang['ADDED'] = 'Added'; +$lang['DELETE_TORRENT'] = 'Delete torrent'; +$lang['DEL_MOVE_TORRENT'] = 'Delete and move topic'; +$lang['DL_TORRENT'] = 'Download .torrent'; +$lang['BT_LAST_POST'] = 'Last post'; +$lang['BT_CREATED'] = 'Topic posted'; +$lang['BT_REPLIES'] = 'Replies'; +$lang['BT_VIEWS'] = 'Views'; + +// Gold/Silver releases +$lang['GOLD'] = 'Gold'; +$lang['SILVER'] = 'Silver'; +$lang['SET_GOLD_TORRENT'] = 'Make gold'; +$lang['UNSET_GOLD_TORRENT'] = 'UnMake gold'; +$lang['SET_SILVER_TORRENT'] = 'Make silver'; +$lang['UNSET_SILVER_TORRENT'] = 'UnMake gold'; +$lang['GOLD_STATUS'] = 'GOLD TORRENT! DOWNLOAD TRAFFIC DOES NOT CONSIDER!'; +$lang['SILVER_STATUS'] = 'SILVER TORRENT! DOWNLOAD TRAFFIC PARTIALLY CONSIDERED!'; +// End - Gold/Silver releases + +$lang['SEARCH_IN_FORUMS'] = 'Search in Forums'; +$lang['SELECT_CAT'] = 'Select category'; +$lang['GO_TO_SECTION'] = 'Goto section'; +$lang['TORRENTS_FROM'] = 'Posts from'; +$lang['SHOW_ONLY'] = 'Show only'; +$lang['SHOW_COLUMN'] = 'Show column'; + +$lang['BT_ONLY_ACTIVE'] = 'Active'; +$lang['BT_ONLY_MY'] = 'My releases'; +$lang['BT_SEED_EXIST'] = 'Seeder exist'; +$lang['BT_ONLY_NEW'] = 'New from last visit'; +$lang['BT_SHOW_CAT'] = 'Category'; +$lang['BT_SHOW_FORUM'] = 'Forum'; +$lang['BT_SHOW_AUTHOR'] = 'Author'; +$lang['BT_SHOW_SPEED'] = 'Speed'; +$lang['SEED_NOT_SEEN'] = 'Seeder not seen'; +$lang['TITLE_MATCH'] = 'Title match'; +$lang['BT_USER_NOT_FOUND'] = 'not found'; +$lang['DL_SPEED'] = 'Overall download speed'; + +$lang['BT_DISREGARD'] = 'disregarding'; +$lang['BT_NEVER'] = 'never'; +$lang['BT_ALL_DAYS_FOR'] = 'all the time'; +$lang['BT_1_DAY_FOR'] = 'last day'; +$lang['BT_3_DAY_FOR'] = 'last three days'; +$lang['BT_7_DAYS_FOR'] = 'last week'; +$lang['BT_2_WEEKS_FOR'] = 'last two weeks'; +$lang['BT_1_MONTH_FOR'] = 'last month'; +$lang['BT_1_DAY'] = '1 day'; +$lang['BT_3_DAYS'] = '3 days'; +$lang['BT_7_DAYS'] = 'week'; +$lang['BT_2_WEEKS'] = '2 weeks'; +$lang['BT_1_MONTH'] = 'month'; + +$lang['DL_LIST_AND_TORRENT_ACTIVITY'] = 'DL-List and Torrent activity'; +$lang['DL_WILL'] = 'Will download'; +$lang['DL_DOWN'] = 'Downloading'; +$lang['DL_COMPLETE'] = 'Complete'; +$lang['DL_CANCEL'] = 'Cancel'; + +$lang['DLWILL_2'] = 'Will download'; +$lang['DLDOWN_2'] = 'Downloading'; +$lang['DLCOMPLETE_2'] = 'Complete'; +$lang['DLCANCEL_2'] = 'Cancel'; + +$lang['DL_LIST_DEL'] = 'Clear DL-List'; +$lang['DL_LIST_DEL_CONFIRM'] = 'Delete DL-List for this topic?'; +$lang['SHOW_DL_LIST'] = 'Show DL-List'; +$lang['SET_DL_STATUS'] = 'Download'; +$lang['UNSET_DL_STATUS'] = 'Not Download'; +$lang['TOPICS_DOWN_SETS'] = 'Topic status changed to Download'; +$lang['TOPICS_DOWN_UNSETS'] = 'Download status removed'; + +$lang['TOPIC_DL'] = 'DL'; + +$lang['MY_DOWNLOADS'] = 'My Downloads'; +$lang['SEARCH_DL_WILL'] = 'Planned'; +$lang['SEARCH_DL_WILL_DOWNLOADS'] = 'Planned Downloads'; +$lang['SEARCH_DL_DOWN'] = 'Current'; +$lang['SEARCH_DL_COMPLETE'] = 'Completed'; +$lang['SEARCH_DL_COMPLETE_DOWNLOADS'] = 'Completed Downloads'; +$lang['SEARCH_DL_CANCEL'] = 'Canceled'; +$lang['CUR_DOWNLOADS'] = 'Current Downloads'; +$lang['CUR_UPLOADS'] = 'Current Uploads'; +$lang['SEARCH_USER_RELEASES'] = 'Find all current releases'; +$lang['TOR_SEARCH_TITLE'] = 'Torrent search options'; +$lang['OPEN_TOPIC'] = 'Open topic'; + +$lang['ALLOWED_ONLY_1ST_POST_ATTACH'] = 'Posting torrents allowed only in first post'; +$lang['ALLOWED_ONLY_1ST_POST_REG'] = 'Registering torrents allowed only from first post'; +$lang['REG_NOT_ALLOWED_IN_THIS_FORUM'] = 'Could not register torrent in this forum'; +$lang['ALREADY_REG'] = 'Torrent already registered'; +$lang['NOT_TORRENT'] = 'This file is not torrent'; +$lang['ONLY_1_TOR_PER_POST'] = 'You can register only one torrent in one post'; +$lang['ONLY_1_TOR_PER_TOPIC'] = 'You can register only one torrent in one topic'; +$lang['VIEWING_USER_BT_PROFILE'] = 'Viewing torrent-profile :: %s'; // %s is username +$lang['CUR_ACTIVE_DLS'] = 'Currently active torrents'; +$lang['VIEW_TORRENT_PROFILE'] = 'Torrent-profile'; + +$lang['PROFILE_UP_TOTAL'] = 'Total uploaded'; +$lang['PROFILE_DOWN_TOTAL'] = 'Total downloaded'; +$lang['PROFILE_BONUS'] = 'Bonus'; +$lang['PROFILE_RELEASED'] = 'Total released'; +$lang['PROFILE_RATIO'] = 'Ratio'; +$lang['PROFILE_MAX_SPEED'] = 'Speed'; +$lang['PROFILE_IT_WILL_BE_DOWNLOADED'] = 'it will start to be considered after it will be downloaded'; + +$lang['CURR_PASSKEY'] = 'Current passkey:'; +$lang['SPMODE_FULL'] = 'Show peers in full details'; + +$lang['BT_RATIO'] = 'Ratio'; +$lang['YOUR_RATIO'] = 'Your Ratio'; +$lang['DOWNLOADED'] = 'Downloaded'; +$lang['UPLOADED'] = 'Uploaded'; +$lang['RELEASED'] = 'Released'; +$lang['BT_BONUS_UP'] = 'Bonus'; + +$lang['TRACKER'] = 'Tracker'; +$lang['GALLERY'] = 'Gallery'; +$lang['OPEN_TOPICS'] = 'Open topics'; +$lang['OPEN_IN_SAME_WINDOW'] = 'open in same window'; + +$lang['BT_LOW_RATIO_FUNC'] = "You can't use this option (ratio is too low)"; +$lang['BT_LOW_RATIO_FOR_DL'] = "With ratio %s you can't download torrents"; +$lang['BT_RATIO_WARNING_MSG'] = 'If your ratio falls below %s, you will not be able to download Torrents! More about the rating.'; + +$lang['SEEDER_LAST_SEEN'] = 'Seeder not seen: %s'; + +// +// MAIL.RU Keyboard +// +$lang['KB_TITLE'] = 'Russian keyboard'; +$lang['KB_RUS_KEYLAYOUT'] = 'Layout: '; +$lang['KB_NONE'] = 'None'; +$lang['KB_TRANSLIT'] = 'Translit'; +$lang['KB_TRADITIONAL'] = 'Traditional'; +$lang['KB_RULES'] = 'Using translit'; +$lang['KB_SHOW'] = 'Show keyboard (Make sure you\'re using Cyrillic codepage!)'; +$lang['KB_ABOUT'] = 'About'; +$lang['KB_CLOSE'] = 'Close'; +$lang['KB_TRANSLIT_MOZILLA'] = 'Select text you wish to translit and click \'Translit\'.'; +$lang['KB_TRANSLIT_OPERA7'] = 'Click here to translit your message.'; + +$lang['NEED_TO_LOGIN_FIRST'] = 'You need to login first'; +$lang['ONLY_FOR_MOD'] = 'This option only for moderators'; +$lang['ONLY_FOR_ADMIN'] = 'This option only for admins'; +$lang['ONLY_FOR_SUPER_ADMIN'] = 'This option only for super admins'; + +$lang['ACCESS'] = 'Access'; +$lang['ACCESS_SRV_LOAD'] = 'Depend on server load'; +$lang['LOGS'] = 'Topic history'; + +$lang['LAST_IP'] = 'Last IP:'; +$lang['REG_IP'] = 'Registration IP:'; +$lang['ALREADY_REG'] = 'With your IP-address is already registered user %s. If you have not previously registered on our tracker, mail to Administrator'; + +// +// That's all, Folks! +// ------------------------------------------------- + +// from lang_admin +$lang['NOT_ADMIN'] = 'You are not authorised to administer this board'; + +$lang['COOKIES_REQUIRED'] = 'Cookies must be enabled!'; +$lang['SESSION_EXPIRED'] = 'Session expired'; + +// FLAGHACK-start +$lang['COUNTRY_FLAG'] = 'Country Flag'; +$lang['SELECT_COUNTRY'] = 'SELECT COUNTRY' ; +// FLAGHACK-end + +// Sort memberlist per letter +$lang['SORT_PER_LETTER'] = 'Show only usernames starting with'; +$lang['OTHERS'] = 'others'; +$lang['ALL'] = 'all'; + +$lang['POST_LINK'] = 'Post link'; +$lang['LAST_VISITED'] = 'Last Visited'; +$lang['LAST_ACTIVITY'] = 'Last activity'; +$lang['NEVER'] = 'Never'; + +//mpd +$lang['DELETE_POSTS'] = 'Delete selected posts'; +$lang['DELETE_POSTS_SUCCESFULLY'] = 'The selected posts have been successfully removed'; +//mpd end + +//ts +$lang['TOPICS_ANNOUNCEMENT'] = 'Announcements'; +$lang['TOPICS_STICKY'] = 'Stickies'; +$lang['TOPICS_NORMAL'] = 'Topics'; +//ts end + +//dpc +$lang['DOUBLE_POST_ERROR'] = 'You cannot make another post with the exact same text as your last.'; +//dpc end + +//upt +$lang['UPDATE_POST_TIME'] = 'Update post time'; +//upt end + +$lang['TOPIC_SPLIT_NEW'] = 'New topic'; +$lang['TOPIC_SPLIT_OLD'] = 'Old topic'; +$lang['BOT_LEAVE_MSG_MOVED'] = 'Add bot-message about moving'; +$lang['BOT_AFTER_SPLIT_TO_OLD'] = 'Add bot-message about split to old topic'; +$lang['BOT_AFTER_SPLIT_TO_NEW'] = 'Add bot-message about split to new topic'; +//qr +$lang['QUICK_REPLY'] = 'Quick Reply'; +$lang['INS_NAME_TIP'] = 'Insert name or selected text.'; +$lang['QUOTE_SELECTED'] = 'Quote selected'; +$lang['TRANSLIT_RULES'] = 'Translit Rules'; +$lang['QR_ATTACHSIG'] = 'Attach signature'; +$lang['QR_NOTIFY'] = 'Notify on reply'; +$lang['QR_DISABLE'] = 'Disable'; +$lang['QR_USERNAME'] = 'Name'; +$lang['NO_TEXT_SEL'] = 'Select a text anywhere on a page and try again'; +$lang['QR_FONT_SEL'] = 'Font face'; +$lang['QR_COLOR_SEL'] = 'Font color'; +$lang['QR_SIZE_SEL'] = 'Font size'; +$lang['COLOR_STEEL_BLUE'] = 'Steel Blue'; +$lang['COLOR_GRAY'] = 'Gray'; +$lang['COLOR_DARK_GREEN'] = 'Dark Green'; +//qr end + +//txtb +$lang['ICQ_TXTB'] = '[ICQ]'; +$lang['AIM_TXTB'] = '[AIM]'; +$lang['MSNM_TXTB'] = '[MSN]'; +$lang['YIM_TXTB'] = '[Yahoo]'; +$lang['REPLY_WITH_QUOTE_TXTB'] = '[Quote]'; +$lang['READ_PROFILE_TXTB'] = '[Profile]'; +$lang['SEND_EMAIL_TXTB'] = '[E-mail]'; +$lang['VISIT_WEBSITE_TXTB'] = '[www]'; +$lang['EDIT_DELETE_POST_TXTB'] = '[Edit]'; +$lang['SEARCH_USER_POSTS_TXTB'] = '[Search]'; +$lang['VIEW_IP_TXTB'] = '[ip]'; +$lang['DELETE_POST_TXTB'] = '[x]'; +$lang['MODERATE_POST_TXTB'] = '[m]'; +$lang['SEND_PM_TXTB'] = '[PM]'; +//txtb end + +$lang['DECLENSION']['REPLIES'] = array('reply', 'replies'); +$lang['DECLENSION']['TIMES'] = array('time', 'times'); + +$lang['DELTA_TIME']['INTERVALS'] = array( + 'seconds' => array('second', 'seconds'), + 'minutes' => array('minute', 'minutes'), + 'hours' => array('hour', 'hours'), + 'mday' => array('day', 'days'), + 'mon' => array('month', 'months'), + 'year' => array('year', 'years'), +); +$lang['DELTA_TIME']['FORMAT'] = '%1$s %2$s'; // 5(%1) minutes(%2) + +$lang['AUTH_TYPES'][AUTH_ALL] = $lang['AUTH_ANONYMOUS_USERS']; +$lang['AUTH_TYPES'][AUTH_REG] = $lang['AUTH_REGISTERED_USERS']; +$lang['AUTH_TYPES'][AUTH_ACL] = $lang['AUTH_USERS_GRANTED_ACCESS']; +$lang['AUTH_TYPES'][AUTH_MOD] = $lang['AUTH_MODERATORS']; +$lang['AUTH_TYPES'][AUTH_ADMIN] = $lang['AUTH_ADMINISTRATORS']; + +$lang['NEW_USER_REG_DISABLED'] = 'Sorry, registration is disabled at this time'; +$lang['ONLY_NEW_POSTS'] = 'only new posts'; +$lang['ONLY_NEW_TOPICS'] = 'only new topics'; + +$lang['TORHELP_TITLE'] = 'Please help seeding these torrents!'; + +// +// Reports (need to translate it!) +// +$lang['REPORTS'] = 'Reports'; +$lang['NEW_REPORT'] = ' (one open)'; +$lang['NO_NEW_REPORTS'] = ': no new Reports'; +$lang['NEW_REPORTS'] = ' (%d open)'; +$lang['REPORT_INDEX'] = 'Index'; +$lang['STATISTICS'] = 'Statistics'; +$lang['STATISTIC'] = 'Statistic'; +$lang['VALUE'] = 'Value'; +$lang['REPORT_COUNT'] = 'Current report count'; +$lang['REPORT_MODULES_COUNT'] = 'Report modules count'; +$lang['REPORT_HACK_COUNT'] = 'Overall report count'; +$lang['DELETED_REPORTS'] = 'Reports suggested for deletion'; +$lang['REPORT_TYPE'] = 'Report type'; +$lang['REPORT_BY'] = 'by'; +$lang['NO_REPORTS'] = 'No reports'; +$lang['INVERT_SELECT'] = 'Invert selection'; +$lang['REPORTED_BY'] = 'Reported by'; +$lang['REPORTED_TIME'] = 'Reported on'; +$lang['STATUS'] = 'Status'; +$lang['LAST_CHANGED_BY'] = 'Last changed by'; +$lang['CHANGES'] = 'Changes'; +$lang['REPORT_CHANGE_TEXT'] = 'Marked as "%1$s" by %2$s on %3$s.'; +$lang['REPORT_CHANGE_TEXT_COMMENT'] = 'Marked as "%1$s" by %2$s on %3$s:
    %4$s'; +$lang['REPORT_CHANGE_DELETE_TEXT'] = 'Suggested for deletion by %1$s on %2$s.'; +$lang['ACTION'] = 'Action'; +$lang['REPORT_MARK'] = 'Mark as'; +$lang['OPEN_REPORTS'] = 'Offene Meldungen'; +$lang['NO_REPORTS_FOUND'] = 'No matching reports found.'; +$lang['NO_REPORTS_SELECTED'] = 'No reports were selected.'; +$lang['REPORT_NOT_EXISTS'] = 'The selected report doesn\'t exist.'; +$lang['REPORT_NOT_SUPPORTED'] = 'This feature isn\'t supported.'; +$lang['CLICK_RETURN_REPORT'] = '%sClick here%s to return to the report.'; +$lang['CLICK_RETURN_REPORT_LIST'] = '%sClick here%s to return to the report list.'; + +$lang['REPORT_STATUS'] = array( + REPORT_NEW => 'new', + REPORT_OPEN => 'open', + REPORT_IN_PROCESS => 'in process', + REPORT_CLEARED => 'cleared', + REPORT_DELETE => 'suggested for deletion'); + +$lang['REASON'] = 'Reason'; +$lang['REPORT_SUBJECT'] = 'Subject'; +$lang['REPORT_TITLE_EMPTY'] = 'You have to enter a title of the report.'; +$lang['REPORT_DESC_EMPTY'] = 'You have to enter a message.'; +$lang['REPORT_INSERTED'] = 'The report was sent to the team.'; + +$lang['CHANGE_REPORT'] = 'Change report'; +$lang['CHANGE_REPORTS'] = 'Change reports'; +$lang['CHANGE_REPORT_EXPLAIN'] = 'Are you sure you want to change the status of the selected report?'; +$lang['CHANGE_REPORTS_EXPLAIN'] = 'Are you sure you want to change the status of the selected reports?'; +$lang['COMMENT'] = 'Comment'; +$lang['REPORT_CHANGED'] = 'The status of the selected report was changed.'; +$lang['REPORTS_CHANGED'] = 'The status of the selected reports was changed.'; + +$lang['DELETE_REPORT'] = 'Delete report'; +$lang['DELETE_REPORTS'] = 'Delete reports'; +$lang['DELETE_REPORT_EXPLAIN'] = 'Are you sure you want to delete the selected report?'; +$lang['DELETE_REPORTS_EXPLAIN'] = 'Are you sure you want to delete the selected reports?'; +$lang['REPORT_DELETED'] = 'The selected report was deleted.'; +$lang['REPORTS_DELETED'] = 'The selected reports were deleted.';// +// Reports [END] +// + +// Medal [BEGIN] +$lang['MEDAL'] = 'Honour roll'; +$lang['TOP_10'] = 'Ten best'; +$lang['TOP_10_RATIO'] = 'on Upload/Download Ratio'; +$lang['TOP_10_SIZE_DOWNLOAD'] = 'on volume of the loaded'; +$lang['BEST_RELIZER'] = 'Ten best'; +$lang['BEST_RELEASES'] = 'The best releases'; +$lang['DOWNLOAD_MONTH'] = 'Downloadings of releases for a month'; +$lang['THANKS_MONTH'] = 'Thank\'s of releases for month'; +$lang['BEST_RELEASES_MONTH'] = 'The best releases for a month'; +$lang['BEST_RELEASES_WEEK'] = 'The best releases for a week'; +$lang['THANKS'] = 'Thanks'; +$lang['RELEASES'] = 'Releases'; +$lang['AVERAGE_RATING'] = 'Average estimation'; +$lang['BEST_COUNT_DOWNLOAD'] = 'on count downloadings'; +$lang['BEST_COUNT_THANKS'] = 'on count thanks'; +$lang['DOWNLOADS'] = 'Downloads'; +$lang['ON_AVERAGE'] = 'On average'; +// Medal [END] + +// search +$lang['SEARCH_S'] = 'search...'; +$lang['FORUM_S'] = 'on forum'; +$lang['TRACKER_S'] = 'on tracker'; + +// copyright +$lang['NOTICE'] = '!ATTENTION!'; +$lang['POWERED'] = 'Powered by
    TorrentPier © Meithar, RoadTrain, Pandora'; +$lang['DIVE'] = 'The forum is submitted on base phpBB © phpBB Group'; +$lang['COPY'] = 'The site does not give electronic versions of products, and is engaged only in a collecting and cataloguing of the references sent and published at a forum by our readers. If you are the legal owner of any submitted material and do not wish that the reference to him{it} was in our catalogue, contact us and we shall immediately remove her. Files for an exchange on tracker are given by users of a site, and the administration does not bear the responsibility for their maintenance. The request to not fill in the files protected by copyrights, and also files of the illegal maintenance!'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_topic_templates.php b/upload/language/lang_english/lang_topic_templates.php new file mode 100644 index 000000000..fb9308176 --- /dev/null +++ b/upload/language/lang_english/lang_topic_templates.php @@ -0,0 +1,153 @@ + %s'; +$lang['SEARCH_USERS_ADVANCED'] = 'Advanced User Search'; +$lang['SEARCH_USERS_EXPLAIN'] = 'This Module allows you to perform advanced searches for users on a wide range of criteria. Please read the descriptions under each field to understand each search option completely.'; +$lang['SEARCH_USERNAME_EXPLAIN'] = 'Here you can perform a case insensitive search for usernames. If you would like to match part of the username, use * (an asterix) as a wildcard. Checking the Regular Expressions box will allow you to search based on your regex pattern. Note: Regular Expressions will only work in MySQL, PostgreSQL and Oracle 10g+.'; +$lang['SEARCH_EMAIL_EXPLAIN'] = 'Enter an expression to match a user\'s email address. This is case insensitive. If you want to do a partial match, use * (an asterix) as a wildcard. Checking the Regular Expressions box will allow you to search based on your regex pattern. Note: Regular Expressions will only work in MySQL, PostgreSQL and Oracle 10g+.'; +$lang['SEARCH_IP_EXPLAIN'] = 'Search for users by a specific IP address (xxx.xxx.xxx.xxx), wildcard (xxx.xxx.xxx.*) or range (xxx.xxx.xxx.xxx-yyy.yyy.yyy.yyy). Note: the last quad .255 is considered the range of all the IPs in that quad. If you enter 10.0.0.255, it is just like entering 10.0.0.* (No IP is assigned .255 for that matter, it is reserved). Where you may encounter this is in ranges, 10.0.0.5-10.0.0.255 is the same as "10.0.0.*" . You should really enter 10.0.0.5-10.0.0.254 .'; +$lang['SEARCH_USERS_JOINED'] = 'Users that joined'; +$lang['SEARCH_USERS_LASTVISITED'] = 'Users whom have visited'; +$lang['IN_THE_LAST'] = 'in the last'; +$lang['AFTER_THE_LAST'] = 'after the last'; +$lang['BEFORE'] = 'Before'; +$lang['AFTER'] = 'After'; +$lang['SEARCH_USERS_JOINED_EXPLAIN'] = 'Search for users the join Before or After (and on) a specific date. The date format is YYYY/MM/DD.'; +$lang['SEARCH_USERS_GROUPS_EXPLAIN'] = 'View all members of the selected group.'; +$lang['SEARCH_USERS_RANKS_EXPLAIN'] = 'View all carriers of the selected rank.'; +$lang['ADMINISTRATORS'] = 'Administrators'; +$lang['BANNED_USERS'] = 'Banned Users'; +$lang['DISABLED_USERS'] = 'Disabled Users'; +$lang['USERS_DISABLED_PMS'] = 'Users with disabled PMs'; +$lang['SEARCH_USERS_MISC_EXPLAIN'] = 'Administrators - All users with Administrator powers; Moderators - All forum moderators; Banned Users - All accounts that have been banned on these forums; Disabled Users - All users with disabled accounts (either manually disabled or never verified their email address); Users with disabled PMs - Selects users who have the Private Messages priviliges removed (Done via User Management)'; +$lang['POSTCOUNT'] = 'Postcount'; +$lang['EQUALS'] = 'Equals'; +$lang['GREATER_THAN'] = 'Greater than'; +$lang['LESS_THAN'] = 'Less than'; +$lang['SEARCH_USERS_POSTCOUNT_EXPLAIN'] = 'You can search for users based on the Postcount value. You can either search by a specific value, greater than or lesser than a value or between two values. To do the range search, select "Equals" then put the beginning and ending values of the range separated by a dash (-), e.g. 10-15'; +$lang['USERFIELD'] = 'Userfield'; +$lang['SEARCH_USERS_USERFIELD_EXPLAIN'] = 'Search for users based on various profile fields. Wildcards are supported using an asterix (*). Checking the Regular Expressions box will allow you to search based on your regex pattern. Note: Regular Expressions will only work in MySQL, PostgreSQL and Oracle 10g+.'; +$lang['SEARCH_USERS_LASTVISITED_EXPLAIN'] = 'You can search for users based on their last login date using this search option'; +$lang['SEARCH_USERS_LANGUAGE_EXPLAIN'] = 'This will display users whom have selected a specific language in their Profile'; +$lang['SEARCH_USERS_TIMEZONE_EXPLAIN'] = 'Users who have selected a specific timezone in their profile'; +$lang['SEARCH_USERS_STYLE_EXPLAIN'] = 'Display users who have selected a specific style.'; +$lang['MODERATORS_OF'] = 'Moderators of'; +$lang['SEARCH_USERS_MODERATORS_EXPLAIN'] = 'Search for users with Moderating permissions to a specific forum. Moderating permissions are recoginised either by User Permissions or by being in a Group with the right Group Permssions.'; +$lang['REGULAR_EXPRESSION'] = 'Regular Expression?'; + +$lang['MANAGE'] = 'Manage'; +$lang['SEARCH_USERS_NEW'] = '%s yielded %d result(s). Perform another search.'; +$lang['BANNED'] = 'Banned'; +$lang['NOT_BANNED'] = 'Not Banned'; +$lang['SEARCH_NO_RESULTS'] = 'No users match your selected criteria. Please try another search. If you\'re searching the username or email address fields, for partial matches you must use the wildcard * (an asterix).'; +$lang['ACCOUNT_STATUS'] = 'Account Status'; +$lang['SORT_OPTIONS'] = 'Sort options:'; +$lang['LAST_VISIT'] = 'Last Visit'; +$lang['DAY'] = 'Day'; \ No newline at end of file diff --git a/upload/language/lang_english/lang_xs.php b/upload/language/lang_english/lang_xs.php new file mode 100644 index 000000000..014b0bb76 --- /dev/null +++ b/upload/language/lang_english/lang_xs.php @@ -0,0 +1,140 @@ +
    Click here to see menu.'; +$lang['XS_MAIN_TITLE'] = 'eXtreme Styles Navigation Menu'; +$lang['XS_MENU'] = 'eXtreme Styles Menu'; + +$lang['XS_CONFIGURATION'] = 'Configuration'; +$lang['XS_CONFIGURATION_EXPLAIN'] = 'This feature allows you to change the eXtreme Styles configuration.'; +$lang['XS_MANAGE_CACHE'] = 'Manage Cache'; +$lang['XS_MANAGE_CACHE_EXPLAIN'] = 'This feature allows you to manage cached files.'; +$lang['XS_SET_CONFIGURATION_LC'] = 'set configuration'; +$lang['XS_SET_DEFAULT_STYLE_LC'] = 'set default style'; +$lang['XS_MANAGE_CACHE_LC'] = 'manage cache'; + +/* +* config.tpl +*/ + +$lang['XS_CONFIG_UPDATED'] = 'Configuration updated.'; +$lang['XS_CONFIG_UPDATED_EXPLAIN'] = 'You need to refresh this page before the new configuration can take effect. Click here to refresh page.'; +$lang['XS_CONFIG_WARNING'] = 'Warning: cache cannot be written.'; +$lang['XS_CONFIG_WARNING_EXPLAIN'] = 'Cache directory is not writeable. eXtreme Styles can attempt to fix this problem.
    Click here to try to change access mode to cache directory.

    If cache doesn\'t work on your server for some reason don\'t worry - eXtreme Styles
    increases forum speed many times even without cache.'; + +$lang['XS_CONFIG_MAINTITLE'] = 'eXtreme Styles mod Configuration'; +$lang['XS_CONFIG_SUBTITLE'] = 'This is the configuration for eXtreme Styles. If you don\'t understand what certain variables do then don\'t change it.'; +$lang['XS_CONFIG_TITLE'] = 'eXtreme Styles mod v{VERSION} settings'; +$lang['XS_CONFIG_CACHE'] = 'Cache configuration'; + +$lang['XS_CONFIG_TPL_COMMENTS'] = 'Add tpl filenames in html'; +$lang['XS_CONFIG_TPL_COMMENTS_EXPLAIN'] = 'This feature adds comments to html code that allow style designers to detect which tpl file is displayed.'; + +$lang['XS_CONFIG_USE_CACHE'] = 'Use cache'; +$lang['XS_CONFIG_USE_CACHE_EXPLAIN'] = 'Cache is saved to disk and it will accelerate templates system because there would be no need to compile template every time it is shown.'; + +$lang['XS_CONFIG_AUTO_COMPILE'] = 'Automatically save cache'; +$lang['XS_CONFIG_AUTO_COMPILE_EXPLAIN'] = 'This will automatically compile templates that are not cached and save to cache directory.'; + +$lang['XS_CONFIG_AUTO_RECOMPILE'] = 'Automatically re-compile cache'; +$lang['XS_CONFIG_AUTO_RECOMPILE_EXPLAIN'] = 'This will automatically re-compile templates if a template was changed.'; + +$lang['XS_CONFIG_PHP'] = 'Extension of cache filenames'; +$lang['XS_CONFIG_PHP_EXPLAIN'] = 'This is extension of cached files. Files are stored in php format so default extension is "php". Do not include dot'; + +$lang['XS_CONFIG_BACK'] = 'Click here to return to configuration.'; +$lang['XS_CONFIG_SQL_ERROR'] = 'Failed to update general configuration for {VAR}'; + +// Debug info +$lang['XS_DEBUG_HEADER'] = 'Debug info'; +$lang['XS_DEBUG_EXPLAIN'] = 'This is debug info. Used to find/fix problems when configuring cache.'; +$lang['XS_DEBUG_VARS'] = 'Template variables'; +$lang['XS_DEBUG_TPL_NAME'] = 'Template filename:'; +$lang['XS_DEBUG_CACHE_FILENAME'] = 'Cache filename:'; +$lang['XS_DEBUG_DATA'] = 'Debug data:'; + +$lang['XS_CHECK_HDR'] = 'Checking cache for %s'; +$lang['XS_CHECK_FILENAME'] = 'Error: invalid filename'; +$lang['XS_CHECK_OPENFILE1'] = 'Error: cannot open file "%s". Will try to create directories...'; +$lang['XS_CHECK_OPENFILE2'] = 'Error: cannot open file "%s" for the second time. Giving up...'; +$lang['XS_CHECK_NODIR'] = 'Checking "%s" - no such directory.'; +$lang['XS_CHECK_NODIR2'] = 'Error: cannot create directory "%s" - you might need to check permissions.'; +$lang['XS_CHECK_CREATEDDIR'] = 'Created directory "%s"'; +$lang['XS_CHECK_DIR'] = 'Checking "%s" - directory exists.'; +$lang['XS_CHECK_OK'] = 'Opened file "%s" for writing. Everything seems to be ok.'; +$lang['XS_ERROR_DEMO_EDIT'] = 'you cannot edit file in demo mode'; +$lang['XS_ERROR_NOT_INSTALLED'] = 'eXtreme Styles mod is not installed. You forgot to upload includes/template.php'; + +/* +* chmod +*/ + +$lang['XS_CHMOD'] = 'CHMOD'; +$lang['XS_CHMOD_RETURN'] = '

    Click here to return to configuration.'; +$lang['XS_CHMOD_MESSAGE1'] = 'Configuration changed.'; +$lang['XS_CHMOD_ERROR1'] = 'Cannot change access mode to cache directory'; + +/* +* cache management +*/ + +$lang['XS_MANAGE_CACHE_EXPLAIN2'] = 'This feature allows you to compile or remove cached files for styles.'; +$lang['XS_CLEAR_ALL_LC'] = 'clear all'; +$lang['XS_COMPILE_ALL_LC'] = 'compile all'; +$lang['XS_CLEAR_CACHE_LC'] = 'clear cache'; +$lang['XS_COMPILE_CACHE_LC'] = 'compile cache'; +$lang['XS_CACHE_CONFIRM'] = 'If you have many styles it might cause huge server load. Are you sure you want to continue?'; + +$lang['XS_CACHE_NOWRITE'] = 'Error: cannot access cache directory'; +$lang['XS_CACHE_LOG_DELETED'] = 'Deleted {FILE}'; +$lang['XS_CACHE_LOG_NODELETE'] = 'Error: cannot delete file {FILE}'; +$lang['XS_CACHE_LOG_NOTHING'] = 'Nothing to delete for template {TPL}'; +$lang['XS_CACHE_LOG_NOTHING2'] = 'Nothing to delete in cache directory'; +$lang['XS_CACHE_LOG_COUNT'] = 'Successfully deleted {NUM} files'; +$lang['XS_CACHE_LOG_COUNT2'] = 'Error deleting {NUM} files'; +$lang['XS_CACHE_LOG_COMPILED'] = 'Compiled: {NUM} files'; +$lang['XS_CACHE_LOG_ERRORS'] = 'Errors: {NUM}'; +$lang['XS_CACHE_LOG_NOACCESS'] = 'Error: cannot access directory {DIR}'; +$lang['XS_CACHE_LOG_COMPILED2'] = 'Compiled: {FILE}'; +$lang['XS_CACHE_LOG_NOCOMPILE'] = 'Error compiling: {FILE}'; + +/* +* style configuration +*/ +$lang['TEMPLATE_CONFIG'] = 'Template Config'; +$lang['XS_STYLE_CONFIGURATION'] = 'Template Configuration'; \ No newline at end of file diff --git a/upload/language/lang_english/report_hack/.htaccess b/upload/language/lang_english/report_hack/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/lang_english/report_hack/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_english/report_hack/lang_report_general.php b/upload/language/lang_english/report_hack/lang_report_general.php new file mode 100644 index 000000000..e964376cd --- /dev/null +++ b/upload/language/lang_english/report_hack/lang_report_general.php @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/upload/language/lang_english/report_hack/lang_report_post.php b/upload/language/lang_english/report_hack/lang_report_post.php new file mode 100644 index 000000000..0213e715c --- /dev/null +++ b/upload/language/lang_english/report_hack/lang_report_post.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/upload/language/lang_english/report_hack/lang_report_privmsg.php b/upload/language/lang_english/report_hack/lang_report_privmsg.php new file mode 100644 index 000000000..f0b12777d --- /dev/null +++ b/upload/language/lang_english/report_hack/lang_report_privmsg.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/upload/language/lang_english/report_hack/lang_report_topic.php b/upload/language/lang_english/report_hack/lang_report_topic.php new file mode 100644 index 000000000..72f813895 --- /dev/null +++ b/upload/language/lang_english/report_hack/lang_report_topic.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/upload/language/lang_english/report_hack/lang_report_user.php b/upload/language/lang_english/report_hack/lang_report_user.php new file mode 100644 index 000000000..0ba6ede59 --- /dev/null +++ b/upload/language/lang_english/report_hack/lang_report_user.php @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/upload/language/lang_english/search_stopwords.txt b/upload/language/lang_english/search_stopwords.txt new file mode 100644 index 000000000..7b024271c --- /dev/null +++ b/upload/language/lang_english/search_stopwords.txt @@ -0,0 +1,617 @@ +able +about +above +ac3 +according +accordingly +across +actually +afaik +afair +after +afterwards +again +against +ago +ain +all +allow +allows +almost +alone +along +alot +already +also +although +always +among +amongst +and +another +answer +any +anybody +anybodys +anyhow +anyone +anything +anyway +anyways +anywhere +apart +ape +appear +appreciate +appropriate +are +aren +arent +around +aside +ask +askd +asking +associated +audio +available +avi +away +awfully +bad +became +because +become +becomes +becoming +been +before +beforehand +behind +being +believe +below +beside +besides +best +better +between +beyond +big +both +br +brief +btw +but +came +camrip +can +cannot +cant +cause +causes +certain +certainly +changes +chm +clearly +code +com +come +comes +concerning +consequently +consider +considering +contain +containing +contains +corresponding +could +couldn +couldnt +course +cue +currently +day +days +definitely +described +despite +did +didn +didnt +different +divx +djvu +doc +does +doesn +doesnt +doing +don +done +dont +down +downwards +dts +during +dvd +dvd5 +dvd9 +dvdrip +dvdscreener +each +ebook +edu +eek +eight +either +else +elsewhere +email +enough +entirely +especially +etc +even +ever +every +everybody +everybodys +everyone +everything +everywhere +exactly +example +except +far +few +fifth +find +first +five +flac +followed +following +follows +font +for +former +formerly +forth +forum +found +four +from +ftp +further +furthermore +get +gets +getting +given +gives +goes +going +gone +good +got +gotten +greetings +grin +had +hadn +happens +hardly +has +hasn +have +haven +havent +having +hdtv +hello +help +hence +her +here +hereafter +hereby +herein +hereupon +hers +herself +him +himself +his +hither +home +hopefully +how +howbeit +however +hows +hr +href +htm +html +http +ignored +iirc +image +img +imho +immediate +inasmuch +inc +indeed +indicate +indicated +indicates +ini +inner +insofar +instead +into +inward +isbn +isn +isnt +its +itself +ive +just +kbps +keep +keeps +kept +know +known +knows +large +last +lately +later +latter +latterly +least +left +less +lest +let +like +liked +likely +list +little +lol +look +looked +looking +looks +lot +ltd +mainly +many +may +maybe +mean +meanwhile +media +merely +might +mkv +mon +more +moreover +most +mostly +mp3 +mpeg +mpeg1 +mpeg2 +mpeg4 +mrgreen +much +must +mustnt +myself +name +namely +near +nearly +necessary +need +needs +neither +never +nevertheless +new +news +next +nine +nobody +non +none +noone +nor +normally +not +nothing +novel +now +nowhere +obviously +ocr +off +often +ogg +ogm +okay +old +once +one +ones +only +onto +oops +other +others +otherwise +ought +our +ours +ourselves +out +outside +over +overall +own +page +particular +particularly +pcm +pdf +per +perhaps +placed +please +plus +possible +post +presumably +probably +provides +put +que +question +questioned +questions +quicktime +quite +quote +rar +rather +razz +really +reasonably +recent +regarding +regardless +regards +relatively +respectively +right +roll +rotf +rotflmao +said +same +satrip +saw +say +saying +says +second +secondly +see +seeing +seem +seemed +seeming +seems +seen +sees +self +selves +sensible +sent +serious +seriously +seven +several +shall +she +should +shouldn +since +sites +six +size +small +smile +some +somebody +somehow +someone +something +sometime +sometimes +somewhat +somewhere +soon +sorry +specified +specify +specifying +still +sub +such +sup +sure +tab +take +taken +telecine +telesynch +tell +tends +than +thank +thanks +thanx +that +thatd +thats +the +their +theirs +them +themselves +then +thence +there +thereafter +thereby +therefore +therein +theres +thereupon +these +they +theyd +theyll +theyre +think +third +this +thorough +thoroughly +those +though +three +through +throughout +thru +thus +time +times +together +too +took +topic +toward +towards +tried +tries +true +truly +try +trying +tvrip +twice +twisted +two +under +unfortunately +unless +unlikely +until +unto +untrue +upon +url +use +used +useful +users +uses +using +usually +value +various +version +very +via +viz +vorbis +vpx +want +wants +was +wasn +wave +way +web +welcome +well +went +were +weren +werent +what +whatever +when +whence +whenever +where +whereafter +whereas +whereby +wherein +whereupon +wherever +whether +which +while +whither +who +whoever +whole +whom +whose +why +wide +will +willing +windows +wink +wish +with +within +without +won +wonder +wont +world +worse +worst +would +wouldn +wrote +www +xvid +yes +yet +ymmv +you +youd +youll +your +youre +yours +yourself +yourselves +zero +zip diff --git a/upload/language/lang_english/search_synonyms.txt b/upload/language/lang_english/search_synonyms.txt new file mode 100644 index 000000000..2616c8683 --- /dev/null +++ b/upload/language/lang_english/search_synonyms.txt @@ -0,0 +1,149 @@ +abcense absence +abridgement abridgment +accomodate accommodate +acknowledgment acknowledgement +airplane aeroplane +allright alright +andy andrew +anemia anaemia +anemic anaemic +anesthesia anaesthesia +appologize appologise +archean archaean +archeology archaeology +archeozoic archaeozoic +armor armour +artic arctic +attachment attachement +attendence attendance +barbecue barbeque +behavior behaviour +biassed biased +biol biology +buletin bulletin +calender calendar +canceled cancelled +car automobile +catalog catalogue +cenozoic caenozoic +center centre +check cheque +color colour +comission commission +comittee committee +commitee committee +conceed concede +creating createing +curiculum curriculum +defense defence +develope develop +discription description +dulness dullness +encyclopedia encyclopaedia +enroll enrol +esthetic aesthetic +etiology aetiology +exhorbitant exorbitant +exhuberant exuberant +existance existence +favorite favourite +fetus foetus +ficticious fictitious +flavor flavour +flourescent fluorescent +foriegn foreign +fourty forty +gage guage +geneology genealogy +grammer grammar +gray grey +guerilla guerrilla +gynecology gynaecology +harbor harbour +heighth height +hemaglobin haemaglobin +hematin haematin +hematite haematite +hematology haematology +honor honour +innoculate inoculate +installment instalment +irrelevent irrelevant +irrevelant irrelevant +jeweler jeweller +judgement judgment +labeled labelled +labor labour +laborer labourer +laborers labourers +laboring labouring +licence license +liesure leisure +liquify liquefy +maintainance maintenance +maintenence maintenance +medieval mediaeval +meter metre +milage mileage +millipede millepede +miscelaneous miscellaneous +morgage mortgage +noticable noticeable +occurence occurrence +offense offence +ommision omission +ommission omission +optimize optimize +organise organize +pajamas pyjamas +paleography palaeography +paleolithic palaeolithic +paleontological palaeontological +paleontologist palaeontologist +paleontology palaeontology +paleozoic palaeozoic +pamplet pamphlet +paralell parallel +parl parliament +parlt parliament +pediatric paediatric +pediatrician paediatrician +pediatrics paediatrics +pedodontia paedodontia +pedodontics paedodontics +personel personnel +practise practice +program programme +psych psychology +questionaire questionnaire +rarify rarefy +reccomend recommend +recieve receive +resistence resistance +restaraunt restaurant +savior saviour +sep september +seperate separate +sept september +sieze seize +summarize summarise +summerize summarise +superceed supercede +superintendant superintendent +supersede supercede +suprise surprise +surprize surprise +synchronise synchronize +temperary temporary +theater theatre +threshhold threshold +transfered transferred +truely truly +truley truly +useable usable +valor valour +vigor vigour +vol volume +whack wack +withold withhold +yeild yield \ No newline at end of file diff --git a/upload/language/lang_english/translit_table.php b/upload/language/lang_english/translit_table.php new file mode 100644 index 000000000..408a71e0b --- /dev/null +++ b/upload/language/lang_english/translit_table.php @@ -0,0 +1,5 @@ + 'to', +); \ No newline at end of file diff --git a/upload/language/lang_russian/.htaccess b/upload/language/lang_russian/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/lang_russian/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_russian/email/.htaccess b/upload/language/lang_russian/email/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/lang_russian/email/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_russian/email/admin_activate.tpl b/upload/language/lang_russian/email/admin_activate.tpl new file mode 100644 index 000000000..627c854f6 --- /dev/null +++ b/upload/language/lang_russian/email/admin_activate.tpl @@ -0,0 +1,10 @@ +Subject: Новый пользователь +Charset: UTF-8 + +Здравствуйте, + +Учётная запись "{USERNAME}" была отключена или только что создана. Вы должны проверить информацию о пользователе и активизировать её, перейдя по этой ссылке: + +{U_ACTIVATE} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/admin_send_email.tpl b/upload/language/lang_russian/email/admin_send_email.tpl new file mode 100644 index 000000000..2bb179bdb --- /dev/null +++ b/upload/language/lang_russian/email/admin_send_email.tpl @@ -0,0 +1,12 @@ +Charset: UTF-8 + +Это письмо отправлено вам администратором сайта "{SITENAME}". Если это сообщение является спамом, содержит оскорбления или прочие неприятные вам комментарии, пожалуйста свяжитесь с вебмастером по адресу: + +{BOARD_EMAIL} + +Включите данное сообщение целиком (особенно заголовки). + +Отправленное вам сообщение: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +{MESSAGE} \ No newline at end of file diff --git a/upload/language/lang_russian/email/admin_welcome_activated.tpl b/upload/language/lang_russian/email/admin_welcome_activated.tpl new file mode 100644 index 000000000..51f4a536a --- /dev/null +++ b/upload/language/lang_russian/email/admin_welcome_activated.tpl @@ -0,0 +1,8 @@ +Subject: Учётная запись активизирована +Charset: UTF-8 + +Здравствуйте, {USERNAME}! + +Ваша учётная запись на сайте "{SITENAME}" была активизирована. Теперь вы можете входить в систему, используя имя и пароль, присланные вам в предыдущем письме. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/admin_welcome_inactive.tpl b/upload/language/lang_russian/email/admin_welcome_inactive.tpl new file mode 100644 index 000000000..480344978 --- /dev/null +++ b/upload/language/lang_russian/email/admin_welcome_inactive.tpl @@ -0,0 +1,19 @@ +Subject: Добро пожаловать на форумы {SITENAME} +Charset: UTF-8 + +{WELCOME_MSG} + +Пожалуйста сохраните это сообщение. Параметры вашей учётной записи таковы: + +---------------------------- +Имя пользователя: {USERNAME} +Пароль: {PASSWORD} +---------------------------- + +Ваша учётная запись ещё не активна, её должен активизировать администратор форумов. Как только это произойдёт, вам будет прислано письмо. + +Не забывайте свой пароль: он хранится в нашей базе в зашифрованном виде, и мы не сможем вам его выслать. Если вы всё же забудете пароль, то сможете запросить новый, который придётся активизировать таким же образом, как и вашу учётную запись. + +Спасибо за то, что зарегистрировались на наших форумах. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/blank.tpl b/upload/language/lang_russian/email/blank.tpl new file mode 100644 index 000000000..9f6da3253 --- /dev/null +++ b/upload/language/lang_russian/email/blank.tpl @@ -0,0 +1 @@ +{MESSAGE} \ No newline at end of file diff --git a/upload/language/lang_russian/email/group_added.tpl b/upload/language/lang_russian/email/group_added.tpl new file mode 100644 index 000000000..e6d1f96c5 --- /dev/null +++ b/upload/language/lang_russian/email/group_added.tpl @@ -0,0 +1,12 @@ +Subject: Вы были включены в группу +Charset: UTF-8 + +Поздравляем! + +Вы были приняты в группу "{GROUP_NAME}" на сайте {SITENAME}. +Это было проделано модератором группы или администратором сайта, обратитесь к ним за дополнительной информацией. + +Перейдите по ссылке, чтобы увидеть информацию о вашем членстве в группах: +{U_GROUPCP} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/group_approved.tpl b/upload/language/lang_russian/email/group_approved.tpl new file mode 100644 index 000000000..cacf730bd --- /dev/null +++ b/upload/language/lang_russian/email/group_approved.tpl @@ -0,0 +1,11 @@ +Subject: Ваша просьба была удовлетворена +Charset: UTF-8 + +Поздравляем! + +Ваша просьба о вступлении в группу "{GROUP_NAME}" на сайте {SITENAME} была удовлетворена. +Перейдите по ссылке, чтобы увидеть информацию о вашем членстве в группах: + +{U_GROUPCP} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/group_request.tpl b/upload/language/lang_russian/email/group_request.tpl new file mode 100644 index 000000000..f8b9d68e7 --- /dev/null +++ b/upload/language/lang_russian/email/group_request.tpl @@ -0,0 +1,11 @@ +Subject: Просьба о вступлении в группу +Charset: UTF-8 + +Уважаемый(ая) {GROUP_MODERATOR}! + +Пользователь {USER} попросил о вступлении в группу (на сайте {SITENAME}), модератором которой Вы являетесь. +Чтобы удовлетворить или отклонить эту просьбу, перейдите по следующей ссылке: + +{U_GROUPCP} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/privmsg_notify.tpl b/upload/language/lang_russian/email/privmsg_notify.tpl new file mode 100644 index 000000000..710506d54 --- /dev/null +++ b/upload/language/lang_russian/email/privmsg_notify.tpl @@ -0,0 +1,14 @@ +Subject: Новое личное сообщение +Charset: UTF-8 + +Здравствуйте, {USERNAME}! + +{NAME_FROM} отправил(а) Вам личное сообщение на сайте {SITENAME}. + +Вы можете прочитать его, перейдя по следующей ссылке: + +{U_INBOX} + +Вы можете отказаться от получения подобных уведомлений, если измените настройки в своём профиле. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/profile_send_email.tpl b/upload/language/lang_russian/email/profile_send_email.tpl new file mode 100644 index 000000000..76df28e29 --- /dev/null +++ b/upload/language/lang_russian/email/profile_send_email.tpl @@ -0,0 +1,14 @@ +Charset: UTF-8 + +Здравствуйте, {TO_USERNAME}! + +Ниже следует письмо, отправленное вам пользователем {FROM_USERNAME} через вашу регистрацию на сайте {SITENAME}. Если это сообщение является спамом, содержит оскорбления или прочие неприятные вам комментарии, пожалуйста свяжитесь с вебмастером по адресу: + +{BOARD_EMAIL} + +Включите данное сообщение целиком (особенно заголовки). Пожалуйста учтите, что адрес ответа в этом сообщении является адресом {FROM_USERNAME}. + +Посланное вам сообщение: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +{MESSAGE} \ No newline at end of file diff --git a/upload/language/lang_russian/email/topic_notify.tpl b/upload/language/lang_russian/email/topic_notify.tpl new file mode 100644 index 000000000..bd635c7fd --- /dev/null +++ b/upload/language/lang_russian/email/topic_notify.tpl @@ -0,0 +1,14 @@ +Subject: Уведомление об ответе - {TOPIC_TITLE} +Charset: UTF-8 + +Здравствуйте, {USERNAME}! + +Вы получили это сообщение потому, что следите за темой "{TOPIC_TITLE}" на сайте {SITENAME}. В этой теме со времени вашего последнего посещения появилось новое сообщение. Вы можете перейти по ссылке, чтобы прочитать поступившие ответы; новые уведомления не будут приходить, пока вы не просмотрите тему: + +{U_TOPIC} + +Если вы больше не хотите следить за темой, то либо щёлкните по ссылке "перестать следить за темой" внизу страницы, либо перейдите по следующей ссылке: + +{U_STOP_WATCHING_TOPIC} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/user_activate.tpl b/upload/language/lang_russian/email/user_activate.tpl new file mode 100644 index 000000000..da8ca1ed2 --- /dev/null +++ b/upload/language/lang_russian/email/user_activate.tpl @@ -0,0 +1,10 @@ +Subject: Повторная активизация учётной записи +Charset: UTF-8 + +Здравствуйте, {USERNAME}! + +Ваша учётная запись на {SITENAME} была отключена, скорее всего из-за внесённых в ваш профиль изменений. Чтобы вновь её активизировать, перейдите по этой ссылке: + +{U_ACTIVATE} + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/user_activate_passwd.tpl b/upload/language/lang_russian/email/user_activate_passwd.tpl new file mode 100644 index 000000000..d67629609 --- /dev/null +++ b/upload/language/lang_russian/email/user_activate_passwd.tpl @@ -0,0 +1,18 @@ +Subject: Активизация нового пароля +Charset: UTF-8 + +Здравствуйте, {USERNAME}! + +Вы получили это письмо потому, что вы (либо кто-то, выдающий себя за вас) попросили выслать новый пароль к вашей учётной записи на сайте {SITENAME}. Если вы не просили выслать пароль, то не обращайте внимания на это письмо, если же подобные письма будут продолжать приходить, обратитесь к администратору форумов. + +Прежде чем использовать новый пароль, вы должны его активизировать. Для этого перейдите по ссылке: + +{U_ACTIVATE} + +В случае успешной активизации вы сможете входить в систему, используя следующий пароль: + +Пароль: {PASSWORD} + +Вы сможете сменить этот пароль на странице редактирования профиля. Если у вас возникнут какие-то трудности, обратитесь к администратору форумов. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/user_welcome.tpl b/upload/language/lang_russian/email/user_welcome.tpl new file mode 100644 index 000000000..7a7018053 --- /dev/null +++ b/upload/language/lang_russian/email/user_welcome.tpl @@ -0,0 +1,17 @@ +Subject: Добро пожаловать на форумы {SITENAME} +Charset: UTF-8 + +{WELCOME_MSG} + +Пожалуйста сохраните это сообщение. Параметры вашей учётной записи таковы: + +---------------------------- +Имя пользователя: {USERNAME} +Пароль: {PASSWORD} +---------------------------- + +Не забывайте свой пароль: он хранится в нашей базе в зашифрованном виде, и мы не сможем вам его выслать. Если вы всё же забудете пароль, то сможете запросить новый, который придётся активизировать таким же образом, как и вашу учётную запись. + +Спасибо за то, что зарегистрировались на наших форумах. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/email/user_welcome_inactive.tpl b/upload/language/lang_russian/email/user_welcome_inactive.tpl new file mode 100644 index 000000000..8158e8e9a --- /dev/null +++ b/upload/language/lang_russian/email/user_welcome_inactive.tpl @@ -0,0 +1,21 @@ +Subject: Добро пожаловать на форумы {SITENAME} +Charset: UTF-8 + +{WELCOME_MSG} + +Пожалуйста сохраните это сообщение. Параметры вашей учётной записи таковы: + +---------------------------- +Имя пользователя: {USERNAME} +Пароль: {PASSWORD} +---------------------------- + +Ваша учётная запись ещё не активна. Вы не сможете ей пользоваться, пока не перейдёте по следующей ссылке: + +{U_ACTIVATE} + +Не забывайте свой пароль: он хранится в нашей базе в зашифрованном виде, и мы не сможем вам его выслать. Если вы всё же забудете пароль, то сможете запросить новый, который придётся активизировать таким же образом, как и вашу учётную запись. + +Спасибо за то, что зарегистрировались на наших форумах. + +{EMAIL_SIG} \ No newline at end of file diff --git a/upload/language/lang_russian/lang_admin.php b/upload/language/lang_russian/lang_admin.php new file mode 100644 index 000000000..36d524d40 --- /dev/null +++ b/upload/language/lang_russian/lang_admin.php @@ -0,0 +1,676 @@ +прилепленные темы и объявления. Вам придётся удалять такие темы вручную.'; +$lang['DO_PRUNE'] = 'Провести чистку'; +$lang['ALL_FORUMS'] = 'Все форумы'; +$lang['PRUNE_TOPICS_NOT_POSTED'] = 'Удалить темы, в которых не было ответов за данное кол-во дней'; +$lang['TOPICS_PRUNED'] = 'Тем вычищено'; +$lang['POSTS_PRUNED'] = 'Сообщений вычищено'; +$lang['PRUNE_SUCCESS'] = 'Форум успешно почищен'; + + +// +// Word censor +// +$lang['WORDS_TITLE'] = 'Автоцензор'; +$lang['WORDS_EXPLAIN'] = 'Здесь вы можете добавить, изменить или удалить слова, которые будут автоматически подвергаться цензуре на ваших форумах. Кроме того, пользователи не смогут зарегистрироваться под именами, содержащими эти слова. В списке слов могут использоваться шаблоны (*), т.е. к \'*тест*\' подойдёт \'протестировать\', к \'тест*\' — \'тестирование\', к \'*тест\' — \'протест\'.
    (Примечание переводчика) Рекомендую пользоваться этой фичей очень аккуратно: например, некие очевидные замены буду неадекватно реагировать на слова \'потребитель\', \'употреблять\' и т.п.'; +$lang['WORD'] = 'Слово'; +$lang['EDIT_WORD_CENSOR'] = 'Изменить автоцензор'; +$lang['REPLACEMENT'] = 'Замена'; +$lang['ADD_NEW_WORD'] = 'Добавить новое слово'; +$lang['UPDATE_WORD'] = 'Обновить автоцензор'; + +$lang['MUST_ENTER_WORD'] = 'Вы должны ввести слово и его замену'; +$lang['NO_WORD_SELECTED'] = 'Не выбрано слово для редактирования'; + +$lang['WORD_UPDATED'] = 'Выбранный автоцензор был успешно изменён'; +$lang['WORD_ADDED'] = 'Автоцензор был успешно добавлен'; +$lang['WORD_REMOVED'] = 'Выбранный автоцензор был успешно удалён'; + +$lang['CLICK_RETURN_WORDADMIN'] = '%sВернуться к управлению автоцензором%s'; + + +// +// Mass Email +// +$lang['MASS_EMAIL_EXPLAIN'] = 'Вы можете разослать e-mail сообщение либо всем вашим пользователям, либо пользователям, входящим в определённую группу. Сообщение будет отправлено на административный адрес, с BCC: всем получателям. Если вы отправляете письмо большой группе людей, то будьте терпеливы: не останавливайте загрузку страницы после нажатия кнопки. Массовая рассылка может занять много времени, вы увидите сообщение, когда выполнение завершится.'; +$lang['COMPOSE'] = 'Текст сообщения'; + +$lang['RECIPIENTS'] = 'Получатели'; +$lang['ALL_USERS'] = 'Все пользователи'; + +$lang['EMAIL_SUCCESSFULL'] = 'Ваше сообщение было отправлено'; +$lang['CLICK_RETURN_MASSEMAIL'] = '%sВернуться к массовой рассылке%s'; + + +// +// Ranks admin +// +$lang['RANKS_TITLE'] = 'Управление званиями'; +$lang['RANKS_EXPLAIN'] = 'Здесь вы можете добавлять, редактировать, просматривать и удалять звания. Вы также можете создавать специальные звания, которые могут затем быть присвоены пользователям на странице управления пользователями.'; + +$lang['ADD_NEW_RANK'] = 'Новое звание'; + +$lang['RANK_TITLE'] = 'Звание'; +$lang['RANK_SPECIAL'] = 'Специальное звание'; +$lang['RANK_MINIMUM'] = 'Минимум сообщений'; +$lang['RANK_MAXIMUM'] = 'Максимум сообщений'; +$lang['RANK_IMAGE'] = 'Картинка к званию (относительно корня phpBB2)'; +$lang['RANK_IMAGE_EXPLAIN'] = 'Здесь вы можете присвоить всем имеющим такое звание специальное изображение. Вы можете указать либо относительный, либо абсолютный путь к изображению'; + +$lang['MUST_SELECT_RANK'] = 'Извините, вы не выбрали звание. Вернитесь и попробуйте ещё раз.'; +$lang['NO_ASSIGNED_RANK'] = 'Специального звания не присвоено'; + +$lang['RANK_UPDATED'] = 'Звание было успешно изменено'; +$lang['RANK_ADDED'] = 'Звание было успешно добавлено'; +$lang['RANK_REMOVED'] = 'Звание было успешно удалено'; +$lang['NO_UPDATE_RANKS'] = 'Звание было успешно удалено. Тем не менее, информация о пользователях, у которых было это звание, не была изменена. Вам придётся изменить эту информацию вручную.'; + +$lang['CLICK_RETURN_RANKADMIN'] = '%sВернуться к управлению званиями%s'; + +// +// Disallow Username Admin +// +$lang['DISALLOW_CONTROL'] = 'Запрещённые имена пользователя'; +$lang['DISALLOW_EXPLAIN'] = "Здесь вы можете задать имена, которые будут запрещены к использованию. Запрещённые имена могут содержать шаблон '*'. Учтите: вы не сможете запретить имя, если уже существует пользователь с таким именем. Вам придётся сначала удалить пользователя, а уже потом запретить имя."; + +$lang['DELETE_DISALLOW'] = 'Удалить'; +$lang['DELETE_DISALLOW_TITLE'] = 'Удалить запрещённое имя пользователя'; +$lang['DELETE_DISALLOW_EXPLAIN'] = 'Вы можете убрать запрещённое имя, выбрав его из списка и нажав кнопку «сохранить»'; + +$lang['ADD_DISALLOW'] = 'Добавить'; +$lang['ADD_DISALLOW_TITLE'] = 'Добавить запрещённое имя пользователя'; +$lang['ADD_DISALLOW_EXPLAIN'] = 'Вы можете запретить имя пользователя, используя шаблон \'*\', который подходит к любому символу'; + +$lang['NO_DISALLOWED'] = 'Нет запрещённых имён'; + +$lang['DISALLOWED_DELETED'] = 'Запрещённое имя пользователя было успешно удалено'; +$lang['DISALLOW_SUCCESSFUL'] = 'Запрещённое имя пользователя было успешно добавлено'; +$lang['DISALLOWED_ALREADY'] = 'Имя, которое вы пытаетесь запретить, либо уже запрещено, либо есть в списке нецензурных слов, либо существует пользователь с подходящим именем'; + +$lang['CLICK_RETURN_DISALLOWADMIN'] = '%sВернуться к управлению запрещёнными именами%s'; + +// FTP +$lang['ATTACHMENT_FTP_SETTINGS'] = 'Настройка закачки вложений на FTP'; +$lang['FTP_CHOOSE'] = 'Выберите метод скачивания'; +$lang['FTP_OPTION'] = '
    В этой версии PHP включены возможности FTP, вы можете попробовать сначала автоматически закачать файл настроек по FTP в нужный каталог.'; +$lang['FTP_INSTRUCTS'] = 'Вы решили закачать файл настроек по FTP в каталог, содержащий phpBB 2. Пожалуйста, укажите информацию, требуемую для осуществления этого процесса. Учтите, что путь FTP должен быть полным путём к вашей установке phpBB 2, как если бы вы пользовались обычным клиентом FTP.'; +$lang['FTP_INFO'] = 'Укажите настройки FTP'; +$lang['ATTEMPT_FTP'] = 'Попробовать закачать файл настроек по FTP'; +$lang['SEND_FILE'] = 'Просто прислать файл, я закачаю его вручную'; +$lang['FTP_PATH'] = 'Путь FTP к каталогу phpBB 2'; +$lang['FTP_USERNAME'] = 'Имя пользователя для FTP'; +$lang['FTP_PASSWORD'] = 'Пароль для FTP'; +$lang['TRANSFER_CONFIG'] = 'Начать закачку'; +$lang['NOFTP_CONFIG'] = 'Попытка закачать файл настроек по FTP завершилась неудачей. Пожалуйста, скачайте файл настроек и поместите его в нужный каталог вручную.'; + +// +// Version Check +// +$lang['VERSION_INFORMATION'] = 'Информация о версии TorrentPier'; + +// +// Login attempts configuration +// +$lang['MAX_LOGIN_ATTEMPTS'] = 'Разрешено попыток входа'; +$lang['MAX_LOGIN_ATTEMPTS_EXPLAIN'] = 'Количество разрешенных попыток входа на трекер. Для отключения поставьте 0.'; +$lang['LOGIN_RESET_TIME'] = 'Время блокировки имени пользователя.'; +$lang['LOGIN_RESET_TIME_EXPLAIN'] = 'Время, через которое пользователь сможет войти на трекер, после превышения количества разрешенных попыток входа (в минутах).'; + +// TODO: Translate PLST to RUS +// Permissions List +// +$lang['PERMISSIONS_LIST'] = 'Список прав доступа'; +$lang['AUTH_CONTROL_CATEGORY'] = 'Права доступа к категориям'; +$lang['FORUM_AUTH_LIST_EXPLAIN'] = 'Этот модуль дает возможность установить права доступа для каждого форума. Вы можете изменить эти права, простым или расширеным способом, нажав на название форума. Помните, что при изменении прав доступа повлияет на пользователей, выполнять различные операции в них.'; +$lang['CAT_AUTH_LIST_EXPLAIN'] = 'This provides a summary of the authorisation levels of each forum within this category. You can edit the permissions of individual forums, using either a simple or advanced method by clicking on the forum name. Alternatively, you can set the permissions for all the forums in this category by using the drop-down menus at the bottom of the page. Remember that changing the permission level of forums will affect which users can carry out the various operations within them.'; +$lang['FORUM_AUTH_LIST_EXPLAIN_ALL'] = 'Все пользователи'; +$lang['FORUM_AUTH_LIST_EXPLAIN_REG'] = 'Все зарегистрированые пользователи'; +$lang['FORUM_AUTH_LIST_EXPLAIN_PRIVATE'] = 'Только пользователи со спец правами'; +$lang['FORUM_AUTH_LIST_EXPLAIN_MOD'] = 'Только модераторы этого форума'; +$lang['FORUM_AUTH_LIST_EXPLAIN_ADMIN'] = 'Только администраторы'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_VIEW'] = '%s может просматривать этот форум'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_READ'] = '%s может просматривать сообщения в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_POST'] = '%s может создавать сообщения в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_REPLY'] = '%s может отвечать на сообщения в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_EDIT'] = '%s может редактировать сообщения в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_DELETE'] = '%s может удалять сообщения в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_STICKY'] = '%s может прикреплять темы в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_ANNOUNCE'] = '%s может размещать объявления в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_VOTE'] = '%s может голосовать в опросах этого форума'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_POLLCREATE'] = '%s может создавать опросы в этом форуме'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_ATTACHMENTS'] = '%s может прикреплять вложения'; +$lang['FORUM_AUTH_LIST_EXPLAIN_AUTH_DOWNLOAD'] = '%s может скачивать вложения'; + +// +// Misc +// +$lang['SF_SHOW_ON_INDEX'] = 'Показывать на главной'; +$lang['SF_PARENT_FORUM'] = 'Родительский форум'; +$lang['SF_NO_PARENT'] = 'Нет родительского форума'; +$lang['TEMPLATE'] = 'Шаблон'; + +// +// Reports +// +$lang['REPORT_CONFIG_EXPLAIN'] = 'На этой странице находятся основные настройки модуля "Сообщения о нарушениях".'; +$lang['REPORT_SUBJECT_AUTH'] = 'Индивидуальные права доступа'; +$lang['REPORT_SUBJECT_AUTH_EXPLAIN'] = 'Если опция включена, то модераторы смогут просматривать и редактировать только сообщения о нарушениях в модерируемых ими форумах.'; +$lang['REPORT_MODULES_CACHE'] = 'Кэшировать модули в файлах'; +$lang['REPORT_MODULES_CACHE_EXPLAIN'] = 'Замечание: права доступа к директории cache в режим "полный доступ на запись и чтение" (CHMOD 777).'; +$lang['REPORT_NOTIFY'] = 'Уведомления по e-mail'; +$lang['REPORT_NOTIFY_CHANGE'] = 'об изменениях статусов и новых сообщениях'; +$lang['REPORT_NOTIFY_NEW'] = 'о новых сообщениях'; +$lang['REPORT_LIST_ADMIN'] = 'Список сообщений доступен только администратору'; +$lang['REPORT_NEW_WINDOW'] = 'Открывать страницу с нарушением в новом окне'; +$lang['REPORT_NEW_WINDOW_EXPLAIN'] = 'Эта опция так же влияет н вид ссылок к форме отправки сообщения о нарушении на страницах просмотра тем.'; +$lang['REPORT_CONFIG_UPDATED'] = 'Конфигурция обновлена.'; +$lang['CLICK_RETURN_REPORT_CONFIG'] = '%sНажмите%s для возврата к настройкам модуля.'; + +$lang['MODULES_REASONS'] = 'Модули & Причины'; +$lang['REPORT_ADMIN_EXPLAIN'] = 'На этой странице вы можете установить новый модуль, изменить настройки модуля или удалить уже установленный модуль. Так же здесь вы можете задать установить Причины написания сообщений о нарушении для каждого модуля.'; +$lang['REPORT_MODULE'] = 'Модуль Сообщений о нарушении'; +$lang['INSTALLED_MODULES'] = 'Установленные модули'; +$lang['NO_MODULES_INSTALLED'] = 'Нет установленных модулей'; +$lang['REASONS'] = 'Причины (%d)'; +$lang['SYNC'] = 'Синхронизировать'; +$lang['UNINSTALL'] = 'Удалить'; +$lang['INSTALL2'] = 'Установить'; +$lang['INACTIVE_MODULES'] = 'Неактивные модули'; +$lang['NO_MODULES_INACTIVE'] = 'Нет неактивных модулей'; +$lang['REPORT_MODULE_NOT_EXISTS'] = 'Выбранный модель не существует.'; +$lang['CLICK_RETURN_REPORT_ADMIN'] = '%sНажмите%s для возврата к настройкам Модулей & Причин.'; + +$lang['BACK_MODULES'] = 'Назад к модулям'; +$lang['REPORT_REASON'] = 'Причина написания сообщения'; +$lang['NO_REASONS'] = 'Нет определенных Причин для этого модуля'; +$lang['ADD_REASON'] = 'Добавить Причину'; +$lang['EDIT_REASON'] = 'Редактировать Причину'; +$lang['REASON_DESC_EXPLAIN'] = 'Если название совпадет с языковой переменно, то будет использована переменная.'; +$lang['REASON_DESC_EMPTY'] = 'Нобходимо ввести текст Причины.'; +$lang['REPORT_REASON_ADDED'] = 'Причина добавлена.'; +$lang['REPORT_REASON_EDITED'] = 'Причина отредактирована.'; +$lang['DELETE_REASON'] = 'Удалить Причину'; +$lang['DELETE_REPORT_REASON_EXPLAIN'] = 'Вы уверены, что хотите удалить выбранную Причину?'; +$lang['REPORT_REASON_DELETED'] = 'Причина удалена.'; +$lang['REPORT_REASON_NOT_EXISTS'] = 'Выбранная Причина не существует.'; +$lang['CLICK_RETURN_REPORT_REASONS'] = '%sНажмите%s для возврата к настройкам Причин сообщений о нарушениях.'; + +$lang['REPORT_MODULE_SYNCED'] = 'Модуль синхронизирован.'; + +$lang['UNINSTALL_REPORT_MODULE'] = 'Удалить модуль'; +$lang['UNINSTALL_REPORT_MODULE_EXPLAIN'] = 'Вы уверены, что хотите удалить выбранный модуль?
    Замечание: все сообщения для этого модуля также будут удалены.'; +$lang['REPORT_MODULE_UNINSTALLED'] = 'Модуль удален.'; + +$lang['INSTALL_REPORT_MODULE'] = 'Установить модуль'; +$lang['EDIT_REPORT_MODULE'] = 'Редактировать настройки модуля'; +$lang['REPORT_PRUNE'] = 'Очистить сообщения'; +$lang['REPORT_PRUNE_EXPLAIN'] = 'Зыкрытые и отмеченные для удаления сообщения автоматически будут удалены через x дней. Значение zero отключает автоматическую чистку.'; +$lang['REPORT_PERMISSIONS'] = 'Права доступа'; +$lang['WRITE'] = 'Написать'; +$lang['REPORT_AUTH'] = array( + REPORT_AUTH_USER => 'Пользователи', + REPORT_AUTH_MOD => 'Модераторы', + REPORT_AUTH_CONFIRM => 'Модераторы (после подтверждения)', + REPORT_AUTH_ADMIN => 'Администраторы'); +$lang['REPORT_AUTH_NOTIFY_EXPLAIN'] = 'Модераторы будут уведомлены только, если они могут просматривать и редактировать сообщение.'; +$lang['REPORT_AUTH_DELETE_EXPLAIN'] = 'Если выбрано Модераторы (после подтверждения), удаление сообщения должно быть подтверждено администратором.'; +$lang['REPORT_MODULE_INSTALLED'] = 'Модуль удален.'; +$lang['REPORT_MODULE_EDITED'] = 'Модуль отредактирован.'; +$lang['REPORTS'] = 'Нарушения'; +// +// Reports [END] +// diff --git a/upload/language/lang_russian/lang_admin_attach.php b/upload/language/lang_russian/lang_admin_attach.php new file mode 100644 index 000000000..d4b8359e2 --- /dev/null +++ b/upload/language/lang_russian/lang_admin_attach.php @@ -0,0 +1,234 @@ + Management +$lang['ATTACH_SETTINGS'] = 'Конфигурация приложений'; +$lang['MANAGE_ATTACHMENTS_EXPLAIN'] = 'Здесь Вы можете конфигурировать главные настройки для Мода Приложений. Если Вы нажмёте на кнопку "Проверить Настройки", Мод Приложений проведёт несколько тестов, чтобы проверить - всё ли правильно настроено. Если у Вас возникли проблемы с закачиванием файлов, используйте эту функцию, чтобы получить подробную информацию об ошибке.'; +$lang['ATTACH_FILESIZE_SETTINGS'] = 'Настройки размеров приложений'; +$lang['ATTACH_NUMBER_SETTINGS'] = 'Настройка количества приложений'; +$lang['ATTACH_OPTIONS_SETTINGS'] = 'Настройка приложений'; + +$lang['UPLOAD_DIRECTORY'] = 'Папка для закачанных приложений'; +$lang['UPLOAD_DIRECTORY_EXPLAIN'] = 'Задайте относительный путь от папки форума к папке приложений. Например, задайте \'files\', если путь к форуму http://www.yourdomain.com/phpBB2 и папка приложений находится в http://www.yourdomain.com/phpBB2/files.'; +$lang['ATTACH_IMG_PATH'] = 'Иконка для приложений'; +$lang['ATTACH_IMG_PATH_EXPLAIN'] = 'Эта картинка появляется возле ссылок к приложениям в персональных сообщениях. Оставьте это поле пустым, если не хотите видеть иконку. Эта конфигурация будет переписана настройками в Контроле Групп Расширений.'; +$lang['ATTACH_TOPIC_ICON'] = 'Иконка для тем с приложениями'; +$lang['ATTACH_TOPIC_ICON_EXPLAIN'] = 'Эта картинка появляется возле тем с приложениями. Оставьте это поле пустым, если не хотите видеть иконку.'; +$lang['ATTACH_DISPLAY_ORDER'] = 'Последовательность отображения приложений'; +$lang['ATTACH_DISPLAY_ORDER_EXPLAIN'] = 'Здесь Вы можете выбрать, как показывать приложения в постах/личных сообщениях - в порядке убывания (самое новое приложение сначала) или в порядке возрастания (самое старое приложение сначала).'; +$lang['SHOW_APCP'] = 'Использовать новую панель контроля приложений'; +$lang['SHOW_APCP_EXPLAIN'] = 'Выберите, хотите ли Вы использовать отдельную панель контроля приложений (да), или старый метод с двумя боксами для приложений и редактирования приложений (нет) в окне сообщения. Трудно объяснить, как это выглядит, поэтому попробуйте сами.'; + +$lang['MAX_FILESIZE_ATTACH'] = 'Максимальный размер приложений'; +$lang['MAX_FILESIZE_ATTACH_EXPLAIN'] = 'Максимальный размер для приложений. Ноль значит неограниченно. Эта настройка зависит от конфигурации Вашего сёрвера. Например, если php на Вашем сервере позволяет закачивать файлы не более 2 МБ, то эту величину изменить невозможно.'; +$lang['ATTACH_QUOTA'] = 'Квота приложений'; +$lang['ATTACH_QUOTA_EXPLAIN'] = 'Максимальный размер для всех приложений. Ноль значит неограниченно.'; +$lang['MAX_FILESIZE_PM'] = 'Максимальный размер в папке для личных сообщений'; +$lang['MAX_FILESIZE_PM_EXPLAIN'] = 'Максимальная величина, которую приложения могут занимать в личных почтовых ящиках каждого пользователя. Ноль значит неограниченно.'; +$lang['DEFAULT_QUOTA_LIMIT'] = 'Стандартное ограничение квоты'; +$lang['DEFAULT_QUOTA_LIMIT_EXPLAIN'] = 'Здесь Вы можете конфигурировать стандартное ограничение квоты для новых пользователей или пользователей без установленных ограничений. Настройка "Без Ограничений" для тех, кто не хочет использовать квоты приложений. Вместо этого будут использованы стандартные настройки, заданные в контрольной панеле.'; + +$lang['MAX_ATTACHMENTS'] = 'Максимальное количество приложений'; +$lang['MAX_ATTACHMENTS_EXPLAIN'] = 'Максимальное количество приложений, разрешённых в каждом сообщении.'; +$lang['MAX_ATTACHMENTS_PM'] = 'Максимальное количество приложений разрешённых в каждом личном сообщении'; +$lang['MAX_ATTACHMENTS_PM_EXPLAIN'] = 'Задайте максимальное количество приложений, разрешённое в каждом личном сообщении.'; + +$lang['DISABLE_MOD'] = 'Выключить мод приложений'; +$lang['DISABLE_MOD_EXPLAIN'] = 'Эта настройка используется главным образом для проверки новых скинов, она выключает все функции Мода Приложений, кроме административной панели.'; +$lang['PM_ATTACHMENTS'] = 'Разрешить приложения в личных сообщениях'; +$lang['PM_ATTACHMENTS_EXPLAIN'] = 'Разрешить/Запретить добавлять приложения к личным сообщениям.'; +$lang['FTP_UPLOAD'] = 'Включить FTP закачивание'; +$lang['FTP_UPLOAD_EXPLAIN'] = 'Включить закачивание через FTP. Если поставите на "да", Вам нужно будет сконфигурировать настройки для FTP и папка для приложений не будет использоваться.'; +$lang['ATTACHMENT_TOPIC_REVIEW'] = 'Показывать приложения в окне обзора сообщений темы при написании ответа?'; +$lang['ATTACHMENT_TOPIC_REVIEW_EXPLAIN'] = 'Если поставите "да", все приложения будут показываться в окне обзора сообщений темы.'; + +$lang['FTP_SERVER'] = 'FTP сервер для загрузки'; +$lang['FTP_SERVER_EXPLAIN'] = 'Здесь Вы можете задать IP адрес или домен FTP сервера, который будет использоваться для загрузки файлов. Если оставите это поле пустым, будет использоваться сервер, на котором установлен Ваш форум. Заметьте, что нельзя добавлять ftp:// или что то ещё к адресу, только ftp.foo.com или просто IP адрес.'; + +$lang['ATTACH_FTP_PATH'] = 'FTP путь к папке для закаченных файлов'; +$lang['ATTACH_FTP_PATH_EXPLAIN'] = 'Папка для приложений. CMOD не нужен. Пожалуйста не вставляйте Ваш IP или FTP адрес, только относительный или абсолютный путь к папке на самом сервере.
    Например: /home/web/uploads'; +$lang['FTP_DOWNLOAD_PATH'] = 'Ссылка для скачивания файлов c FTP'; +$lang['FTP_DOWNLOAD_PATH_EXPLAIN'] = 'Задайте ссылку к FTP, где лежат приложения.
    Если Вы используете удаленный FTP сервер, задайте полный адрес, например: http://www.mystorage.com/phpBB2/upload.
    Если Вы используете локальный сервер для приложений, задайте относительный адрес к папке форума "upload".
    Слеш будет удален. Оставьте поле пустым, если FTP недоступен из интернета. Если поле будет пустым, физический метод скачивания будет недоступен.'; +$lang['FTP_PASSIVE_MODE'] = 'Задействовать пассивный FTP режим'; +$lang['FTP_PASSIVE_MODE_EXPLAIN'] = 'Команда PASV просит удаленный сервер открыть порт для связи и сообщить номер данного порта. Удалённый сервер открывает порт и клиент подключается к нему.'; + +$lang['NO_FTP_EXTENSIONS_INSTALLED'] = 'Вы не можете использовать FTP для закачивания файлов, потому что Ваш PHP этого не поддерживает данную возможность.'; + +// Attachments -> Shadow Attachments +$lang['SHADOW_ATTACHMENTS_EXPLAIN'] = 'Здесь Вы можете удалить приложения, если сами файлы исчезли с сервера, или удалить файлы, которые не прикреплены ни к каким сообщениям. Вы можете скачать или посмотреть файл кликнув по нему. Если ссылки нет, то файл не существует.'; +$lang['SHADOW_ATTACHMENTS_FILE_EXPLAIN'] = 'Удалить все приложения, которые существуют на сервере и не прикреплены ни к какому сообщению.'; +$lang['SHADOW_ATTACHMENTS_ROW_EXPLAIN'] = 'Удалить всю информацию про приложения, которые больше не существуют в системе.'; +$lang['EMPTY_FILE_ENTRY'] = 'Занесение пустого файла'; + +// Attachments -> Sync +$lang['SYNC_THUMBNAIL_RESETTED'] = 'Обновлена миниатюра для приложения: %s'; // replace %s with physical Filename +$lang['ATTACH_SYNC_FINISHED'] = 'Синхронизация приложений окончена.'; +$lang['SYNC_TOPICS'] = 'Синхронизация тем'; +$lang['SYNC_POSTS'] = 'Синхронизация сообщений'; +$lang['SYNC_THUMBNAILS'] = 'Синхронизация миниатюр'; + +// Extensions -> Extension Control +$lang['MANAGE_EXTENSIONS'] = 'Конфигурация расширений'; +$lang['MANAGE_EXTENSIONS_EXPLAIN'] = 'Здесь Вы можете настроить расширения файлов. Если Вы хотите разрешить/запретить определённые расширения, пожалуйста, используйте Контроль Групп Расширений.'; +$lang['EXPLANATION'] = 'Обьяснение'; +$lang['EXTENSION_GROUP'] = 'Группа Расширений'; +$lang['INVALID_EXTENSION'] = 'Неправильное расширения'; +$lang['EXTENSION_EXIST'] = 'Расширение %s уже существует'; // replace %s with the Extension +$lang['UNABLE_ADD_FORBIDDEN_EXTENSION'] = 'Расширение %s запрещено, Вы не можете добавить его к группе разрешённых расширений'; // replace %s with Extension + +// Extensions -> Extension Groups Management +$lang['MANAGE_EXTENSION_GROUPS'] = 'Контроль Групп Расширений'; +$lang['MANAGE_EXTENSION_GROUPS_EXPLAIN'] = 'Здесь Вы можете добавить, убрать или изменить группы расширений, Вы можете выключить группы расширений, добавить их в определённые категории, изменить механизм скачивания и выбрать иконку, которая будет отображаться приложением, которое относится к определённой группе.'; +$lang['SPECIAL_CATEGORY'] = 'Специальная категория'; +$lang['CATEGORY_IMAGES'] = 'Картинки'; +$lang['CATEGORY_STREAM_FILES'] = 'Потоковые файлы'; +$lang['CATEGORY_SWF_FILES'] = 'Flash файлы'; +$lang['ALLOWED'] = 'Разрешено'; +$lang['ALLOWED_FORUMS'] = 'Разрешённые форумы'; +$lang['EXT_GROUP_PERMISSIONS'] = 'Права Групп'; +$lang['DOWNLOAD_MODE'] = 'Метод скачивания'; +$lang['UPLOAD_ICON'] = 'Иконка для закачки'; +$lang['MAX_GROUPS_FILESIZE'] = 'Максимальный размер файла'; +$lang['EXTENSION_GROUP_EXIST'] = 'Группа расширений %s уже существует'; // replace %s with the group name +$lang['COLLAPSE'] = '+'; +$lang['DECOLLAPSE'] = '-'; + +// Extensions -> Special Categories +$lang['MANAGE_CATEGORIES'] = 'Контроль специальных категорий'; +$lang['MANAGE_CATEGORIES_EXPLAIN'] = 'Здесь Вы можете настраивать специальные категории. Вы можете задать специальные параметры для специальных категорий прикреплённых к группам расширений.'; +$lang['SETTINGS_CAT_IMAGES'] = 'Настройки для специальной категории: Изображения'; +$lang['SETTINGS_CAT_STREAMS'] = 'Настройки для специальной категории: Потоковые файлы'; +$lang['SETTINGS_CAT_FLASH'] = 'Настройки для специальной категории: Flash файлы'; +$lang['DISPLAY_INLINED'] = 'Отображать изображения в сообщениях'; +$lang['DISPLAY_INLINED_EXPLAIN'] = 'Выберите отображать ли изображения прямо в сообщениях (да) или отображать изображения в виде ссылок на них?'; +$lang['MAX_IMAGE_SIZE'] = 'Максимальная величина изображения'; +$lang['MAX_IMAGE_SIZE_EXPLAIN'] = 'Здесь Вы можете задать максимальную величину изображения (ширина х высота в пикселях).
    Если установлен ноль, то эта функция отключена. С некоторыми изображениями эта функция не будет работать из-за ограничений в PHP.'; +$lang['IMAGE_LINK_SIZE'] = 'Величина изображений, которые будут автоматически показываться как ссылка'; +$lang['IMAGE_LINK_SIZE_EXPLAIN'] = 'Картинки установленной величины будут отображаться как ссылка, а не прямо в сообщении,
    если включена функция "Отображать изображения в сообщениях".
    Если установлен ноль, эта функция отключена. С некоторыми изображениями эта функция не будет работать из-за ограничений в PHP.'; +$lang['ASSIGNED_GROUP'] = 'Прикрепленная группа'; + +$lang['IMAGE_CREATE_THUMBNAIL'] = 'Создать миниатюру'; +$lang['IMAGE_CREATE_THUMBNAIL_EXPLAIN'] = 'Всегда создавать миниатюры. Эта функция замещает все настройки в этой специальной категории, кроме настройки "Максимальная величина изображения". При включении этой функции в сообщении будет отображаться миниатюра, пользователь может на неё нажать, чтобы открыть само изображение.
    Пожалуйста, заметьте, что для этой функции необходим Imagick, если он не инсталлирован или если включен Safe-Mode, будет использоваться PHP расширения GD. Если тип изображения не поддерживается PHP, эта функция не будет задействована.'; +$lang['IMAGE_MIN_THUMB_FILESIZE'] = 'Минимальный размер миниатюры'; +$lang['IMAGE_MIN_THUMB_FILESIZE_EXPLAIN'] = 'Если изображение меньше, чем данный размер, миниатюра создаваться не будет, потому что само изображение уже достаточно маленькое.'; +$lang['IMAGE_IMAGICK_PATH'] = 'Приложение Imagick (полный путь)'; +$lang['IMAGE_IMAGICK_PATH_EXPLAIN'] = 'Задайте путь к программе конвертации Imagick, обычно /usr/bin/convert (в windows: c:/imagemagick/convert.exe).'; +$lang['IMAGE_SEARCH_IMAGICK'] = 'Поиск Imagick'; + +$lang['USE_GD2'] = 'Включить использование GD2 расширения'; +$lang['USE_GD2_EXPLAIN'] = 'PHP может быть скомпилировано с расширением GD1 или GD2 для работы с изображениями. Чтобы правильно создать миниатюры без imagemagick, Мод приложений может использовать два разных способа, основываясь на Вашем выборе в данной опции. Если Ваши Эскизы будут плохого качества или обезображены, попробуйте изменить эту настройку.'; +$lang['ATTACHMENT_VERSION'] = 'Версия Мода приложений (Attachment Mod) %s'; // %s is the version number + +// Extensions -> Forbidden Extensions +$lang['MANAGE_FORBIDDEN_EXTENSIONS'] = 'Управление запрещёнными расширениями'; +$lang['MANAGE_FORBIDDEN_EXTENSIONS_EXPLAIN'] = 'Здесь Вы можете добавить или удалить запрещённое расширение. Расширения php, php3, php4 запрещены для безопасности по умолчанию, и их невозможно удалить.'; +$lang['FORBIDDEN_EXTENSION_EXIST'] = 'Запрещённое расширение %s уже существует'; // replace %s with the extension +$lang['EXTENSION_EXIST_FORBIDDEN'] = 'Расширение %s уже задано в разрешённых расширениях, пожалуйста, удалите его оттуда, перед тем, как добавлять его здесь.'; // replace %s with the extension + +// Extensions -> Extension Groups Control -> Group Permissions +$lang['GROUP_PERMISSIONS_TITLE_ADMIN'] = 'Права групп расширений -> \'%s\''; // Replace %s with the Groups Name +$lang['GROUP_PERMISSIONS_EXPLAIN'] = 'Здесь Вы можете ограничить использование определённых групп расширений в форумах (как задано в боксе "Разрешённые Форумы"). По умолчанию разрешены все группы расширений во всех форумах, в которых пользователь может добавлять файлы (т.е. нормальный метод, который использовался в Моде приложений с самого начала). Если Вы разрешите только определённые форумы, то вариант "Все Форумы" исчезнет. Вы сможете снова добавить все форумы в любое время. Если Вы добавите новый раздел на Вашем форуме и разрешение установлено на "Все форумы", то ничего не изменится. Но если Вы изменили или ограничили доступ к определённым форумам, Вы должны вернуться сюда и добавить этот новый форум. Это можно было бы сделать автоматически, но Вам бы пришлось изменять много файлов, поэтому автор решил использовать текущий вариант. Пожалуйста, заметьте, что здесь будут перечислены все Вами форумы.'; +$lang['NOTE_ADMIN_EMPTY_GROUP_PERMISSIONS'] = 'Замечание:
    В ниже перечисленных форумах пользователи обычно могут добавлять файлы, но так как никакие группы расширений там не разрешены, пользователи не смогут ничего прикрепить. Если они попробуют, они увидят сообщение об ошибке. Может быть Вы хотите установить разрешение \'Добавить файлы\' для администрации в этих форумах.

    '; +$lang['ADD_FORUMS'] = 'Добавить форумы'; +$lang['ADD_SELECTED'] = 'Добавить выбранные'; +$lang['PERM_ALL_FORUMS'] = 'Все форумы'; + +// Attachments -> Quota Limits +$lang['MANAGE_QUOTAS'] = 'Настройка лимита квоты для расширений'; +$lang['MANAGE_QUOTAS_EXPLAIN'] = 'Здесь Вы можете добавить/удалить/изменить квоты для расширений. Позднее Вы можете прикрепить эти ограничения к определённым пользователям или группам. Чтобы прикрепить ограничение к пользователю, откройте Пользователи->Управление, выберите пользователя и Вы увидите необходимые настройки внизу страницы. Чтобы прикрепить ограничение к группе, откройте Группы->Управление, выберите группу и Вы увидите панель настроек. Если Вы хотите увидеть, какие пользователи и группы прикреплены к определённым ограничениям, нажмите на "Посмотреть" слева от описания квоты.'; +$lang['ASSIGNED_USERS'] = 'Прикрепленные пользователи'; +$lang['ASSIGNED_GROUPS'] = 'Прикрепленные группы'; +$lang['QUOTA_LIMIT_EXIST'] = 'Ограничение %s уже существует.'; // Replace %s with the Quota Description + +// Attachments -> Control Panel +$lang['CONTROL_PANEL_TITLE'] = 'Контрольная панель приложений'; +$lang['CONTROL_PANEL_EXPLAIN'] = 'Здесь Вы можете увидеть и настроить все приложения в зависимости от пользователей, приложений, количества просмотров и т.п.'; +$lang['FILE_COMMENT_CP'] = 'Комментарий к файлу'; + +// Control Panel -> Search +$lang['SEARCH_WILDCARD_EXPLAIN'] = 'Используйте *, если не знаете точного названия'; +$lang['SIZE_SMALLER_THAN'] = 'Приложение меньше чем (в байтах)'; +$lang['SIZE_GREATER_THAN'] = 'Приложение больше чем (в байтах)'; +$lang['COUNT_SMALLER_THAN'] = 'Количество скачиваний меньше чем'; +$lang['COUNT_GREATER_THAN'] = 'Количество скачиваний больше чем'; +$lang['MORE_DAYS_OLD'] = 'Старее, чем это количество дней'; +$lang['NO_ATTACH_SEARCH_MATCH'] = 'Не найдено ни одного приложения, которое бы отвечало Вашему поиску'; + +// Control Panel -> Statistics +$lang['NUMBER_OF_ATTACHMENTS'] = 'Количество приложений'; +$lang['TOTAL_FILESIZE'] = 'Общий размер всех приложений'; +$lang['NUMBER_POSTS_ATTACH'] = 'Количество сообщений с приложениями'; +$lang['NUMBER_TOPICS_ATTACH'] = 'Количество тем с приложениями'; +$lang['NUMBER_USERS_ATTACH'] = 'Уникальных пользователей прикрепивших приложения'; +$lang['NUMBER_PMS_ATTACH'] = 'Количество приложений в личных сообщениях'; +$lang['ATTACHMENTS_PER_DAY'] = 'Прикрепления за день'; + +// Control Panel -> Attachments +$lang['STATISTICS_FOR_USER'] = 'Статистика приложений для %s'; // replace %s with username +$lang['SIZE_IN_KB'] = 'Размер (КБ)'; +$lang['DOWNLOADS'] = 'Скачиваний'; +$lang['POST_TIME'] = 'Дата сообщения'; +$lang['POSTED_IN_TOPIC'] = 'Размещено в теме'; +$lang['SUBMIT_CHANGES'] = 'Сохранить изменения'; + +// Sort Types +$lang['SORT_ATTACHMENTS'] = 'Приложения'; +$lang['SORT_SIZE'] = 'Размер'; +$lang['SORT_FILENAME'] = 'Название файла'; +$lang['SORT_COMMENT'] = 'Комментарий'; +$lang['SORT_EXTENSION'] = 'Расширение'; +$lang['SORT_DOWNLOADS'] = 'Скачено'; +$lang['SORT_POSTTIME'] = 'Дата сообщения'; +$lang['SORT_POSTS'] = 'Сообщение'; + +// View Types +$lang['VIEW_STATISTIC'] = 'Статистика'; +$lang['VIEW_SEARCH'] = 'Поиск'; +$lang['VIEW_USERNAME'] = 'Имя'; +$lang['VIEW_ATTACHMENTS'] = 'Приложения'; + +// Successfully updated +$lang['ATTACH_CONFIG_UPDATED'] = 'Конфигурация приложений успешно изменена'; +$lang['CLICK_RETURN_ATTACH_CONFIG'] = 'Нажмите %sтут%s, чтобы вернуться к конфигурации приложений'; +$lang['TEST_SETTINGS_SUCCESSFUL'] = 'Тест настроек окончен, конфигурация в порядке.'; + +// Some basic definitions +$lang['ATTACHMENTS'] = 'Приложения'; +$lang['ATTACHMENT'] = 'Приложение'; +$lang['EXTENSIONS'] = 'Расширения'; +$lang['EXTENSION'] = 'Расширение'; + +// Auth pages +$lang['AUTH_ATTACH'] = 'Добавить файлы'; +$lang['AUTH_DOWNLOAD'] = 'Скачать файлы'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_admin_bt.php b/upload/language/lang_russian/lang_admin_bt.php new file mode 100644 index 000000000..38867f0e4 --- /dev/null +++ b/upload/language/lang_russian/lang_admin_bt.php @@ -0,0 +1,142 @@ +"Нет" - будет определяется клиентом
    в компактном режиме расход трафика наименьший, но могут возникнуть проблемы из-за несовместимости с очень старыми клиентами'; +$lang['BROWSER_REDIRECT_URL'] = 'Browser redirect URL'; +$lang['BROWSER_REDIRECT_URL_EXPL'] = "переадресация на этот URL при попытке зайти на трекер Web browser'ом
    оставьте пустым для отключения"; + +$lang['ANNOUNCE_INTERVAL_HEAD'] = 'Разное'; +$lang['ANNOUNCE_INTERVAL'] = 'Announce интервал'; +$lang['ANNOUNCE_INTERVAL_EXPL'] = 'пауза между announcements'; +$lang['NUMWANT'] = 'Значение numwant'; +$lang['NUMWANT_EXPL'] = 'количество источников (peers) отправляемых клиенту'; +$lang['EXPIRE_FACTOR'] = 'Фактор смерти peer\'ов'; +$lang['EXPIRE_FACTOR_EXPL'] = "время жизни peer'а расчитывается как announce интервал умноженный на фактор смерти peer'а
    должен быть не меньше 1"; +$lang['IGNORE_GIVEN_IP'] = 'Игнорировать указанный клиентом IP'; +$lang['UPDATE_DLSTAT'] = 'Вести учет скачанного/отданного юзером'; + +$lang['LIMIT_ACTIVE_TOR_HEAD'] = 'Ограничения'; +$lang['LIMIT_ACTIVE_TOR'] = 'Ограничить количество одновременных закачек'; +$lang['LIMIT_SEED_COUNT'] = 'Seeding ограничение'; +$lang['LIMIT_SEED_COUNT_EXPL'] = 'ограничение на количество одновременных раздач
    0 - нет ограничений'; +$lang['LIMIT_LEECH_COUNT'] = 'Leeching ограничение'; +$lang['LIMIT_LEECH_COUNT_EXPL'] = 'ограничение на количество одновременных закачек
    0 - нет ограничений'; +$lang['LEECH_EXPIRE_FACTOR'] = 'Leech expire factor'; +$lang['LEECH_EXPIRE_FACTOR_EXPL'] = 'сколько минут считать начатую закачку активной, независимо от того, остановил ли ее юзер
    0 - учитывать остановку'; +$lang['LIMIT_CONCURRENT_IPS'] = 'Ограничить количество подключений с разных IP'; +$lang['LIMIT_CONCURRENT_IPS_EXPL'] = 'считается отдельно для каждого торрента'; +$lang['LIMIT_SEED_IPS'] = 'Seeding IP ограничение'; +$lang['LIMIT_SEED_IPS_EXPL'] = "раздаваь можно не более чем с хх IP's
    (0 - нет ограничений)"; +$lang['LIMIT_LEECH_IPS'] = 'Leeching IP ограничение'; +$lang['LIMIT_LEECH_IPS_EXPL'] = "скачивать можно не более чем с хх IP's
    (0 - нет ограничений)"; + +$lang['USE_AUTH_KEY_HEAD'] = 'Авторизация'; +$lang['USE_AUTH_KEY'] = 'Passkey'; +$lang['USE_AUTH_KEY_EXPL'] = 'включить авторизацию по passkey'; +$lang['AUTH_KEY_NAME'] = 'Имя ключа passkey'; +$lang['AUTH_KEY_NAME_EXPL'] = 'имя ключа, который будет добавляться в GET запросе к announce url для идентификации юзера'; +$lang['ALLOW_GUEST_DL'] = 'Разрешить "гостям" (неавторизованным юзерам) доступ к трекеру'; + +// +// Forum config +// +$lang['FORUM_CFG_EXPL'] = 'Настройки форума'; + +$lang['BT_SELECT_FORUMS'] = 'Форумы, в которых:'; +$lang['BT_SELECT_FORUMS_EXPL'] = 'для выделения нескольких форумов, отмечайте их с нажатой клавишей Ctrl'; + +$lang['ALLOW_REG_TRACKER'] = 'Разрешена регистрация торентов на трекере'; +$lang['ALLOW_DL_TOPIC'] = 'Разрешено создавать Download топики'; +$lang['SHOW_DL_BUTTONS'] = 'Показывать кнопки для изменения DL-статуса'; +$lang['SELF_MODERATED'] = 'Автор топика может перенести его в другой форум'; + +$lang['BT_ANNOUNCE_URL_HEAD'] = 'Announce URL'; +$lang['BT_ANNOUNCE_URL'] = 'Announce url'; +$lang['BT_ANNOUNCE_URL_EXPL'] = 'дополнительные разрешенные адреса можно задать в "includes/announce_urls.php"'; +$lang['BT_DISABLE_DHT'] = 'Запретить DHT сети'; +$lang['BT_DISABLE_DHT_EXPL'] = 'Запретить обмен пирами и DHT (рекомендовано для приватных сетей, только url announce)'; +$lang['BT_CHECK_ANNOUNCE_URL'] = 'Проверять announce url'; +$lang['BT_CHECK_ANNOUNCE_URL_EXPL'] = 'разрешить регистрацию на трекере только если announce url входит в список разрешенных'; +$lang['BT_REPLACE_ANN_URL'] = 'Заменять announce url'; +$lang['BT_REPLACE_ANN_URL_EXPL'] = 'заменять оригинальный announce url в .torrent файлах на ваш'; +$lang['BT_DEL_ADDIT_ANN_URLS'] = 'Удалять все дополнительные announce urls'; +$lang['BT_DEL_ADDIT_ANN_URLS_EXPL'] = 'если торент содержит адреса других трекеров, они будут удалены'; +$lang['BT_ADD_COMMENT'] = 'Добавлять в торент комментарий'; +$lang['BT_ADD_COMMENT_EXPL'] = 'оставьте пустым для добавления адреса топика в качестве комментария'; +$lang['BT_ADD_PUBLISHER'] = 'Добавлять адрес топика как publisher-url и это имя в качестве имени publisher'; +$lang['BT_ADD_PUBLISHER_EXPL'] = 'для отключения - оставьте пустым'; + +$lang['BT_SHOW_PEERS_HEAD'] = 'Peers-List'; +$lang['BT_SHOW_PEERS'] = 'Показывать список источников (seeders/leechers)'; +$lang['BT_SHOW_PEERS_EXPL'] = 'будет выводиться над топиком с торентом'; +$lang['BT_SHOW_PEERS_MODE'] = 'По умолчанию показывать источники как:'; +$lang['BT_SHOW_PEERS_MODE_COUNT'] = 'Только количество'; +$lang['BT_SHOW_PEERS_MODE_NAMES'] = 'Только имена'; +$lang['BT_SHOW_PEERS_MODE_FULL'] = 'Подробно'; +$lang['BT_ALLOW_SPMODE_CHANGE'] = 'Разрешить подробный показ источников'; +$lang['BT_ALLOW_SPMODE_CHANGE_EXPL'] = 'если выбрано "нет" - будет доступен только режим по умолчанию'; +$lang['BT_SHOW_IP_ONLY_MODER'] = 'IP могут видеть только модераторы'; +$lang['BT_SHOW_PORT_ONLY_MODER'] = 'Port могут видеть только модераторы'; + +$lang['BT_SHOW_DL_LIST_HEAD'] = 'DL-List'; +$lang['BT_SHOW_DL_LIST'] = 'Показывать DL-List при просмотре топика'; +$lang['BT_DL_LIST_ONLY_1ST_PAGE'] = 'Показывать DL-List только на первой странице топика'; +$lang['BT_DL_LIST_ONLY_COUNT'] = 'Показывать только количество'; +$lang['BT_SHOW_DL_LIST_BUTTONS'] = 'Показывать кнопки для изменения DL-статуса'; +$lang['BT_SHOW_DL_BUT_WILL'] = $lang['DL_WILL']; +$lang['BT_SHOW_DL_BUT_DOWN'] = $lang['DL_DOWN']; +$lang['BT_SHOW_DL_BUT_COMPL'] = $lang['DL_COMPLETE']; +$lang['BT_SHOW_DL_BUT_CANCEL'] = $lang['DL_CANCEL']; + +$lang['BT_ADD_AUTH_KEY_HEAD'] = 'Passkey'; +$lang['BT_ADD_AUTH_KEY'] = 'Aвтодобавление passkey к торент-файлам перед их скачиванием'; +$lang['BT_GEN_PASSKEY_ON_REG'] = 'Автоматически генерировать passkey'; +$lang['BT_GEN_PASSKEY_ON_REG_EXPL'] = 'если passkey не найден, генерировать его при первом скачивании торента'; + +$lang['BT_TOR_BROWSE_ONLY_REG_HEAD'] = 'Torrent browser (трекер)'; +$lang['BT_TOR_BROWSE_ONLY_REG'] = 'Torrent browser (tracker.php) не доступен для гостей'; +$lang['BT_SEARCH_BOOL_MODE'] = 'Разрешить полнотекстовый поиск в логическом режиме'; +$lang['BT_SEARCH_BOOL_MODE_EXPL'] = 'использовать *, +, - и т.д. при поиске'; + +$lang['BT_SHOW_DL_STAT_ON_INDEX_HEAD'] = 'Разное'; +$lang['BT_SHOW_DL_STAT_ON_INDEX'] = 'Показывать UL/DL статистику юзера на главной странице форума'; +$lang['BT_NEWTOPIC_AUTO_REG'] = 'Регистрировать торренты на трекере для новых топиков'; +$lang['BT_SET_DLTYPE_ON_TOR_REG'] = 'Изменять статус топика на "Download" во время регистрации торента на трекере'; +$lang['BT_SET_DLTYPE_ON_TOR_REG_EXPL'] = 'не зависит от того, разрешено ли в этом форуме создавать Download-топики (в настройках форумов)'; +$lang['BT_UNSET_DLTYPE_ON_TOR_UNREG'] = 'Изменять статус топика на "Normal" во время удаления торрента с трекера'; + +// +// Release +// +$lang['RELEASE_EXP'] = 'На этой странице отображаются форумы, для которых можно выбрать шаблон нового топика (релиза).'; +$lang['TPL_NONE'] = 'Не использовать шаблоны'; +$lang['TPL_VIDEO'] = 'Видео, с указанием перевода'; +$lang['TPL_VIDEO_HOME'] = 'Видео, без указания перевода'; +$lang['TPL_VIDEO_SIMPLE'] = 'Видео, без подробностей'; +$lang['TPL_VIDEO_LESSON'] = 'Видеоуроки'; +$lang['TPL_GAMES'] = 'Игры'; +$lang['TPL_GAMES_PS'] = 'Игры PS/PS2'; +$lang['TPL_GAMES_PSP'] = 'Игры PSP'; +$lang['TPL_GAMES_XBOX'] = 'Игры XBOX'; +$lang['TPL_PROGS'] = 'Программы'; +$lang['TPL_PROGS_MAC'] = 'Программы Mac OS'; +$lang['TPL_MUSIC'] = 'Музыка'; +$lang['TPL_BOOKS'] = 'Книги'; +$lang['TPL_AUDIOBOOKS'] = 'Аудиокниги'; +$lang['TPL_SPORT'] = 'Спорт'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_admin_cron.php b/upload/language/lang_russian/lang_admin_cron.php new file mode 100644 index 000000000..c73dd07a9 --- /dev/null +++ b/upload/language/lang_russian/lang_admin_cron.php @@ -0,0 +1,61 @@ + '; +$lang['REPAIR_CRON'] = '[Восстановить]'; + +$lang['CRON_EDIT_HEAD_EDIT'] = 'Редактировать задачу'; +$lang['CRON_EDIT_HEAD_ADD'] = 'Добавить задачу'; +$lang['CRON_ID'] = 'ID'; +$lang['CRON_ACTIVE'] = 'Активность'; +$lang['CRON_ACTIVE_EXPL'] = 'эта задача включена?'; +$lang['CRON_TITLE'] = 'Название задачи'; +$lang['CRON_SCRIPT'] = 'Скрипт'; +$lang['CRON_SCRIPT_EXPL'] = 'название в папке "includes/cron/jobs/"'; +$lang['SCHEDULE'] = 'Запуск'; +//schedule +$lang['HOURLY'] = 'ежечасно'; +$lang['DAILY'] = 'ежедневно'; +$lang['WEEKLY'] = 'еженедельно'; +$lang['MONTHLY'] = 'ежемесячно'; +$lang['INTERVAL'] = 'интервал'; +// +$lang['RUN_DAY'] = 'День запуска'; +$lang['RUN_DAY_EXPL'] = 'день месяца/недели, когда эта задача будет выполняться'; +$lang['RUN_TIME'] = 'Время запуска'; +$lang['RUN_TIME_EXPL'] = 'время запуска этой задачи (напр. 05:00:00)'; +$lang['RUN_ORDER'] = 'Порядок запуска'; +$lang['LAST_RUN'] = 'Последний запуск'; +$lang['NEXT_RUN'] = 'Следующий запуск'; +$lang['RUN_INTERVAL'] = 'Интервал запуска'; +$lang['RUN_INTERVAL_EXPL'] = 'напр. 00:10:00'; +$lang['LOG_ENABLED'] = 'Логирование включено'; +$lang['LOG_FILE'] = 'Файл лога'; +$lang['LOG_FILE_EXPL'] = 'файл, куда будут сохраняться логи'; +$lang['LOG_SQL_QUERIES'] = 'Логировать SQL запросы'; +$lang['DISABLE_BOARD'] = 'Отключать форум'; +$lang['DISABLE_BOARD_EXPL'] = 'отключать форум, когда задача выполняется?'; +$lang['RUN_COUNTER'] = 'Кол-во запусков'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_admin_rebuild_search.php b/upload/language/lang_russian/lang_admin_rebuild_search.php new file mode 100644 index 000000000..d33b0e593 --- /dev/null +++ b/upload/language/lang_russian/lang_admin_rebuild_search.php @@ -0,0 +1,130 @@ + +Пожалуйста, не закрывайте эту страницу до окончания индексации'; + +// +// Input screen +// +$lang['STARTING_POST_ID'] = 'Начальный ID сообщения'; +$lang['STARTING_POST_ID_EXPLAIN'] = 'Первая запись, с которой начнется обработка
    Вы можете выбрать, чтобы начать с начала или с записи, на которой вы в последний раз остановились'; + +$lang['START_OPTION_BEGINNING'] = 'начать с начала'; +$lang['START_OPTION_CONTINUE'] = 'продолжить с последней остановленной'; + +$lang['CLEAR_SEARCH_TABLES'] = 'Очистить таблицы поиска'; +$lang['CLEAR_SEARCH_TABLES_EXPLAIN'] = ''; +$lang['CLEAR_SEARCH_NO'] = 'Нет'; +$lang['CLEAR_SEARCH_DELETE'] = 'Удаление'; +$lang['CLEAR_SEARCH_TRUNCATE'] = 'Очистка'; + +$lang['NUM_OF_POSTS'] = 'Количество записей'; +$lang['NUM_OF_POSTS_EXPLAIN'] = 'Общее количество записей в процессе
    Автоматически заполняется количество от общего/оставшегося числа записей, найденных в БД'; + +$lang['POSTS_PER_CYCLE'] = 'Записей за цикл'; +$lang['POSTS_PER_CYCLE_EXPLAIN'] = 'Количество записей для обработки за один цикл
    Держите его низким, чтобы избежать таймаута PHP / веб-сервера'; + +$lang['REFRESH_RATE'] = 'Период обновления'; +$lang['REFRESH_RATE_EXPLAIN'] = 'Сколько времени (сек) бездействовать перед переходом к следующему циклу обработки
    Обычно вам не нужно менять это'; + +$lang['TIME_LIMIT'] = 'Ограничение времени'; +$lang['TIME_LIMIT_EXPLAIN'] = 'Сколько времени (сек) после обработки может длиться до перехода к следующему циклу'; +$lang['TIME_LIMIT_EXPLAIN_SAFE'] = 'Ваш PHP (Safe Mode) настроен на таймаут %s сек, так что не превышайте этого значения'; +$lang['TIME_LIMIT_EXPLAIN_WEBSERVER'] = 'Ваш веб-сервер настроен на таймаут %s сек, так что не превышайте этого значения'; + +$lang['DISABLE_BOARD'] = 'Отключение форума'; +$lang['DISABLE_BOARD_EXPLAIN'] = 'Отключать ли форум при обработке'; +$lang['DISABLE_BOARD_EXPLAIN_ENABLED'] = 'Он будет включен автоматически после окончания обработки'; +$lang['DISABLE_BOARD_EXPLAIN_ALREADY'] = 'Ваш форум уже отключен'; + +// +// Information strings +// +$lang['INFO_PROCESSING_STOPPED'] = 'В последний раз вы остановились в процессе обработки на post_id %s (%s обработанных записей) от %s'; +$lang['INFO_PROCESSING_ABORTED'] = 'В последний раз вы прервали процесс обработки на post_id %s (%s обработанных записей) от %s'; +$lang['INFO_PROCESSING_ABORTED_SOON'] = 'Пожалуйста, подождите несколько минут, прежде чем продолжить…'; +$lang['INFO_PROCESSING_FINISHED'] = 'Вы успешно завершили процесс (%s обработанных записей) от %s'; +$lang['INFO_PROCESSING_FINISHED_NEW'] = 'Вы успешно завершили процесс на post_id %s (%s обработанных записей) от %s,
    но были %s новых записей после этой даты'; + +// +// Progress screen +// +$lang['REBUILD_SEARCH_PROGRESS'] = 'Процесс перестроения поиска'; + +$lang['PROCESSED_POST_IDS'] = 'Обработанные записи: %s - %s'; +$lang['TIMER_EXPIRED'] = 'Таймер истек в %s секунд. '; +$lang['CLEARED_SEARCH_TABLES'] = 'Очистка таблиц поиска. '; +$lang['DELETED_POSTS'] = '%s записей были удалены пользователей во время обработки. '; +$lang['PROCESSING_NEXT_POSTS'] = 'Обрабатывается следующие %s записей. Ждите...'; +$lang['ALL_SESSION_POSTS_PROCESSED'] = 'Обработаны все записи в текущей сессии.'; +$lang['ALL_POSTS_PROCESSED'] = 'Все записи были обработаны успешно.'; +$lang['ALL_TABLES_OPTIMIZED'] = 'Все поисковые таблицы были оптимизированы успешно.'; + +$lang['PROCESSING_POST_DETAILS'] = 'Обрабатываемая запись'; +$lang['PROCESSED_POSTS'] = 'Обработанные записи'; +$lang['PERCENT'] = 'Процентов'; +$lang['CURRENT_SESSION'] = 'Текущая сессия'; +$lang['TOTAL'] = 'Всего'; + +$lang['PROCESS_DETAILS'] = 'с %s до %s (из общего %s)'; +$lang['PERCENT_COMPLETED'] = '%s %% завершено'; + +$lang['PROCESSING_TIME_DETAILS'] = 'Детали текущей сесии'; +$lang['PROCESSING_TIME'] = 'Время выполнения'; +$lang['TIME_LAST_POSTS'] = 'Последние %s записей'; +$lang['TIME_FROM_THE_BEGINNING'] = 'Время с начала'; +$lang['TIME_AVERAGE'] = 'Среднее время за цикл'; +$lang['TIME_ESTIMATED'] = 'Расчетное время до завершения'; + +$lang['DAYS'] = 'дней'; +$lang['HOURS'] = 'часов'; +$lang['MINUTES'] = 'минут'; +$lang['SECONDS'] = 'секунд'; + +$lang['DATABASE_SIZE_DETAILS'] = 'Детали размера БД'; +$lang['SIZE_CURRENT'] = 'Текущий'; +$lang['SIZE_ESTIMATED'] = 'Расчетный размер после окончания'; +$lang['SIZE_SEARCH_TABLES'] = 'Размер таблицы поиска'; +$lang['SIZE_DATABASE'] = 'Размер ДБ'; + +$lang['BYTES'] = 'Байт'; + +$lang['ACTIVE_PARAMETERS'] = 'Активные параметры'; +$lang['POSTS_LAST_CYCLE'] = 'Обработанная(ые) запись(и) на последнем цикле'; +$lang['BOARD_STATUS'] = 'Статус форума'; +$lang['BOARD_DISABLED'] = 'Отключен'; +$lang['BOARD_ENABLED'] = 'Включен'; + +$lang['INFO_ESTIMATED_VALUES'] = '(*) Все оценочные значения рассчитываются примерно
    + на основе текущего завершенного процента и не могут представлять фактического конечного значения.
    + С ростом процентов расчетные значения приближаются к фактическим.'; + +$lang['CLICK_RETURN_REBUILD_SEARCH'] = 'Нажмите %sздесь%s, чтобы вернуться к перестроению поиска'; +$lang['REBUILD_SEARCH_ABORTED'] = 'Перестроение поиска прервано на post_id %s.

    Если вы прервали процесс обработки, вы должны подождать несколько минут до запуска перестроения поиска снова, чтобы последний цикл можно было закончить.'; +$lang['WRONG_INPUT'] = 'Вы ввели некоторые неправильные значения. Проверьте введенные данные и попробуйте еще раз.'; + +// Buttons +$lang['NEXT'] = 'Далее'; +$lang['PROCESSING'] = 'Идет обработка...'; +$lang['FINISHED'] = 'Закончить'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_bbcode.php b/upload/language/lang_russian/lang_bbcode.php new file mode 100644 index 000000000..20e39264f --- /dev/null +++ b/upload/language/lang_russian/lang_bbcode.php @@ -0,0 +1,56 @@ +
  • Чтобы сделать текст жирным, заключите его в [b][/b], например

    [b]Привет[/b]

    станет Привет
  • Для подчёркивания используйте [u][/u], например:

    [u]Доброе утро[/u]

    станет Доброе утро
  • Курсив делается тегами [i][/i], например:

    Это [i]круто![/i]

    выдаст Это круто!
  • "); +$faq[] = array("Как изменить цвет или размер текста", "Для изменения цвета или размера шрифта могут быть использованы следующие теги (окончательный вид будет зависеть от системы и браузера пользователя):
    • Цвет текста можно изменить, окружив его [color=][/color]. Вы можете указать либо известное имя цвета (red, blue, yellow и т.п.), или шестнадцатеричное представление, например #FFFFFF, #000000. Таким образом, для создания красного текста вы можете использовать:

      [color=red]Привет![/color]

      или

      [color=#FF0000]Привет![/color]

      оба способа дадут в результате Привет!
    • Изменение размера достигается аналогичным образом при использовании [size=][/size]. Этот тег зависит от используемых шаблонов, рекомендуемый формат — число, показывающее размер текста в пикселях, начиная от 1 (настолько маленький, что вы его не увидите) до 29 (очень большой). Например:

      [size=9]МАЛЕНЬКИЙ[/size]

      скорее всего будет МАЛЕНЬКИЙ

      в то время как:

      [size=24]ЗДОРОВЫЙ![/size]

      будет ЗДОРОВЫЙ!
    "); +$faq[] = array("Могу ли я комбинировать теги?", "Да, конечно можете. Например для привлечения чьего-то внимания вы сможете написать:

    [size=18][color=red][b]ПОСМОТРИТЕ НА МЕНЯ![/b][/color][/size]

    что выдаст ПОСМОТРИТЕ НА МЕНЯ!

    Мы не рекомендуем выводить таким образом длинные тексты! Учтите, что вы, автор сообщения, должны позаботиться о том, чтобы теги были правильно вложены. Вот этот BBCode, например, неправилен:

    [b][u]Это неверно[/b][/u]"); + +$faq[] = array("--","Цитирование и вывод форматированных текстов"); +$faq[] = array("Цитирование при ответах", "Есть два способа процитировать текст, со ссылкой и без.
    • Когда вы используете кнопку «Ответить с цитатой» для ответа на сообщение, то его текст добавляется в поле ввода окружённым блоком [quote=\"\"][/quote]. Этот метод позволит вам цитировать со ссылкой на автора, либо на что-то ещё, что вы туда впишете. Например для цитирования отрывка текста, написанного Mr. Blobby, вы напишете:

      [quote=\"Mr. Blobby\"]Текст Mr. Blobby будет здесь[/quote]

      В результате перед текстом будут вставлены слова \"Mr. Blobby написал:\". Помните, вы должны поставить кавычки \"\" вокруг имени, они не могут быть опущены.
    • Второй метод просто позволяет вам что-то процитировать. Для этого вам надо заключить текст в теги [quote][/quote]. При просмотре сообщения перед текстом будет стоять только слово \"Цитата:\"
    "); +$faq[] = array("Вывод кода или форматированного текста", "Если вам надо вывести кусок программы или что-то, что должно быть выведено шрифтом фиксированной ширины (Courier) вы должны заключить текст в теги [code][/code], например

    [code]echo \"This is some code\";[/code]

    Всё форматирование, используемое внутри тегов [code][/code] будет сохранено."); + +$faq[] = array("--","Создание списков"); +$faq[] = array("Создание маркированного списка", "BBCode поддерживает два вида списков: маркированные и нумерованные. Они практически идентичны своим эквивалентам из HTML. В маркированном списке все элементы выводятся последовательно, каждый отмечается символом-маркером. Для создания маркированного списка используйте [list][/list] и определите каждый элемент при помощи [*]. Например, чтобы вывести свои любимые цвета, вы можете использовать:

    [list]
    [*]Красный
    [*]Синий
    [*]Жёлтый
    [/list]

    Это выдаст такой список:
    • Красный
    • Синий
    • Жёлтый
    "); +$faq[] = array("Создание нумерованного списка", "Второй тип списка, нумерованный, позволяет выбрать, что именно будет выводиться перед каждым элементом. Для создания нумерованного списка используйте [list=1][/list] или [list=a][/list] для создания алфавитного списка. Как и в случае маркированного списка, элементы определяются с помощью [*]. Например:

    [list=1]
    [*]Пойти в магазин
    [*]Купить новый компьютер
    [*]Обругать компьютер, когда случится ошибка
    [/list]

    выдаст следующее:
    1. Пойти в магазин
    2. Купить новый компьютер
    3. Обругать компьютер, когда случится ошибка
    Для алфавитного списка используйте:

    [list=a]
    [*]Первый возможный ответ
    [*]Второй возможный ответ
    [*]Третий возможный ответ
    [/list]

    что выдаст
    1. Первый возможный ответ
    2. Второй возможный ответ
    3. Третий возможный ответ
    "); + +$faq[] = array("--", "Создание ссылок"); +$faq[] = array("Ссылки на другой сайт", "В BBCode поддерживается несколько способов создания URL'ов.
    • Первый из них использует тег [url=][/url], после знака = должен идти нужный URL. Например, для ссылки на phpBB.com вы могли бы использовать:

      [url=http://www.phpbb.com/]Посетите phpBB![/url]

      Это создаст следующую ссылку: Посетите phpBB! Ссылка будет открываться в новом окне, так что пользователь сможет продолжать читать форумы.
    • Если вы хотите, чтобы в качестве текста ссылки показывался сам URL, вы можете просто сделать следующее:

      [url]http://www.phpbb.com/[/url]

      Это выдаст следующую ссылку: http://www.phpbb.com/
    • Кроме того phpBB поддерживает возможность, называемую Автоматические ссылки, это переведёт любой синтаксически правильный URL в ссылку без необходимости указания тегов и даже префикса http://. Например, ввод www.phpbb.com в ваше сообщение приведёт к автоматической выдаче www.phpbb.com при просмотре сообщения.
    • То же самое относится и к адресам e-mail, вы можете либо указать адрес в явном виде:

      [email]no.one@domain.adr[/email]

      что выдаст no.one@domain.adr или просто ввести no.one@domain.adr в ваше сообщение, и он будет автоматически преобразован при просмотре.
    Как и со всеми прочими тегами BBCode, вы можете заключать в URL'ы любые другие теги, например [img][/img] (см. следующий пункт), [b][/b] и т.д. Как и с тегами форматирования, правильная вложенность тегов зависит от вас, например:

    [url=http://www.phpbb.com/][img]http://www.phpbb.com/images/phplogo.gif[/url][/img]

    неверно, что может привести к последующему удалению вашего сообщения, так что будьте аккуратнее."); + +$faq[] = array("--", "Показ картинок в сообщениях"); +$faq[] = array("Добавление картинки в сообщение", "BBCode включает тег для добавления картинки в ваше сообщение. При этом следует помнить две очень важные вещи: во-первых, многих пользователей раздражает большое количество картинок, во-вторых, ваша картинка уже должна быть размещена в интернете (т.е. она не может быть расположена только на вашем компьютере, если, конечно, вы не запустили на нём вебсервер!). На данный момент нет возможности хранить изображения локально на phpBB (ожидается, что это ограничение будет снято в следующей версии phpBB). Для вывода картинки вы должны окружить её URL тегами [img][/img]. Например:

    [img]http://www.phpbb.com/images/phplogo.gif[/img]

    Как указано в предыдущем пункте, вы можете заключить картинку в теги [url][/url], то есть

    [url=http://www.phpbb.com/][img]http://www.phpbb.com/images/phplogo.gif[/img][/url]

    выдаст:

    \"\"
    "); + +$faq[] = array("--", "Прочее"); +$faq[] = array("Могу ли я добавить собственные теги?", "Нет, по крайней мере, не в phpBB 2.0. Мы планируем добавить поддержку настраиваемых тегов BBCode в следующей версии"); + +// +// This ends the BBCode guide entries +// \ No newline at end of file diff --git a/upload/language/lang_russian/lang_bot.php b/upload/language/lang_russian/lang_bot.php new file mode 100644 index 000000000..a7f9febc1 --- /dev/null +++ b/upload/language/lang_russian/lang_bot.php @@ -0,0 +1,5 @@ +%s в форум %s

    %s'; +$lang['BOT_MESS_SPLITS'] = 'Сообщения из этой темы были выделены в отдельный топик %s

    %s'; +$lang['BOT_TOPIC_SPLITS'] = 'Тема была выделена из %s

    %s'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_callseed.php b/upload/language/lang_russian/lang_callseed.php new file mode 100644 index 000000000..bfef86cae --- /dev/null +++ b/upload/language/lang_russian/lang_callseed.php @@ -0,0 +1,16 @@ +
    Ваша помощь необходима в раздаче %s :: %s
    Если вы решили помочь, но уже удалили торрент-файл, можете скачать его здесь

    Надеюсь на вашу помощь!'; + +$lang['CALLSEED_MSG_OK'] = 'Сообщение (ЛС) успешно отправлено всем скачавшим данный релиз'; +$lang['CALLSEED_MSG_SPAM'] = 'Запрос уже был однажды успешно отослан (возможно не Вами) +

    Следующая возможность отослать запрос будет через %s часов.
    + Позвать скачавших можно лишь один раз в сутки'; +$lang['CALLSEED_MSG_MSG'] = 'Ошибка отправки сообщения'; +$lang['CALLSEED_MSG_MSG_TEXT'] = 'Ошибка сохранения текста сообщения'; +$lang['CALLSEED_MSG_POPUP'] = 'Ошибка работы всплывающего окна'; +$lang['CALLSEED_MSG_TIME'] = 'Не удалось установить время последнего запроса'; +$lang['CALLSEED_HAVE_SEED'] = 'Раздача не нуждаются в помощи (Сидеров: %d, Личеров: %d)'; + +$lang['CALLSEED_RETURN'] = '

    Вернуться в тему'; diff --git a/upload/language/lang_russian/lang_countries.php b/upload/language/lang_russian/lang_countries.php new file mode 100644 index 000000000..701cf878a --- /dev/null +++ b/upload/language/lang_russian/lang_countries.php @@ -0,0 +1,249 @@ +Входить автоматически, вы сможете оставаться под своим именем на форуме только некоторое ограниченное время. Это сделано для того, чтобы никто другой не смог воспользоваться вашей учётной записью. Для того, чтобы вас автоматически не отключало от форума, вы можете выбрать пункт Входить автоматически, но мы не рекомендуем вам делать это на общедоступном компьютере, например в библиотеке, интернет-кафе, университете и т.д."); +$faq[] = array("Как сделать, чтобы я не появлялся в списке активных пользователей?", "В настройках вашего профиля вы найдёте опцию Скрывать ваше пребывание на форуме, если вы выберете Да, то будете видны только администраторам и самому себе. Для всех остальных вы будете показываться как скрытый пользователь."); +$faq[] = array("Я забыл пароль!", "Не паникуйте! Хотя ваш пароль и не может быть восстановлен, вам может быть присвоен новый. Для этого кликните на Я забыл пароль, следуйте инструкциям, и скоро вы снова сможете войти на форум"); +$faq[] = array("Я зарегистрирован, но не могу войти!", "Первое: проверьте, правильно ли вы ввели имя и пароль. Второе: возможно, ваша учётная запись требует активизации. Некоторые форумы требуют, чтобы все новые пользователи были активизированы самостоятельно либо администратором форума до того, как вы сможете в него войти. Главная причина, по которой требуется активизация, — она уменьшает возможности для анонимных злоупотреблений в форуме. Когда вы завершали процесс регистрации, вам было сказано, требуется активизация или нет. Если вам был прислан e-mail, то следуйте инструкциям в письме, если вы не получили письмо, то убедитесь, что указали правильный адрес e-mail. Если же вы уверены, что ввели правильный адрес e-mail, но письма не получили, то свяжитесь с администратором форума."); +$faq[] = array("Я был зарегистрирован, но больше не могу войти!", "Наиболее вероятные причины: вы ввели неверное имя или пароль (проверьте письмо, которое вам прислали, когда вы зарегистрировались) или администратор удалил вашу учётную запись по каким-то причинам. Если верно второе, то возможно вы не написали ни одного сообщения? Администраторы могут удалять неактивных пользователей, чтобы уменьшить размер базы данных. Попробуйте зарегистрироваться снова и принять участие в дискуссиях."); + + +$faq[] = array("--","Параметры и настройки пользователя"); +$faq[] = array("Как мне изменить мои настройки?", "Все ваши настройки хранятся в базе данных (если вы зарегистрированы). Чтобы изменить их, перейдите в раздел Профиль (обычно ссылка на него находится вверху форума, но могут быть и исключения). Там вы можете изменить все свои настройки"); +$faq[] = array("В форумах неправильное время!", "Время обычно правильное, но вы можете видеть время, относящееся к другому часовому поясу, не к тому, в котором находитесь вы. В этом случае вы можете изменить часовой пояс на тот, в котором вы находитесь: Москва, Киев и т.д. Пожалуйста, учтите, что для смены часового пояса, как и для смены большинства настроек, требуется быть зарегистрированным пользователем."); +$faq[] = array("Я изменил часовой пояс, но время все равно неправильное!", "Если вы уверены, что указали часовой пояс правильно, то причина может быть в летнем времени. Этот форум не умеет работать с летним временем, так что в период действия летнего времени может появляться разница в один час с реальным временем."); +$faq[] = array("Моего языка нет в списке!", "Причина скорее всего в том, что администратор не установил поддержку вашего языка в форуме, или же просто никто не перевёл этот форум на ваш язык. Попробуйте узнать у администратора форума, может ли он установить требуемый язык. Если же поддержки нужного языка пока не существует, то вы сами можете перевести этот форум на свой язык. Дополнительную информацию вы можете получить на сайте Группы phpBB (ссылка есть внизу страницы)"); +$faq[] = array("Как я могу поместить картинку под своим именем?", "Под именем пользователя могут быть две картинки. Первая картинка относится к вашему званию, обычно это звёздочки, указывающие на то, сколько сообщений вы оставили в форуме или на ваш статус в этом форуме. Чуть ниже может находиться картинка побольше, которая называется «аватара». Эта картинка обычно уникальна для каждого пользователя. От администраторов зависит, включена ли поддержка аватар, и от них же зависит, какие аватары могут быть использованы. Если в данном форуме не включена поддержка аватар, то это решение администраторов, вы можете выяснить у них причины."); +$faq[] = array("Как я могу изменить своё звание?", "Обычно вы не можете напрямую изменить своё звание (звание отображается ниже вашего имени в созданном вами сообщении или теме, а так же в вашем профиле, в зависимости от используемого стиля). Большинство форумов используют звания, чтобы показать какое количество сообщений было написано и чтобы идентифицировать определённых пользователей: например модераторы и администраторы могут иметь специальные звания. Пожалуйста, не засоряйте форум ненужными сообщениями только для того, чтобы повысить ваше звание, за это модератор или администратор может просто понизить количество отправленных вами сообщений."); +$faq[] = array("Когда я щёлкаю по ссылке «Отправить e-mail», от меня требуют войти?", "Только зарегистрированные пользователи могут посылать e-mail через встроенную в форум форму (если эта возможность вообще разрешена администратором). Это сделано для того, чтобы предотвратить злоупотребления системой e-mail анонимными пользователями."); + + +$faq[] = array("--","Создание сообщений"); +$faq[] = array("Как мне создать тему в форуме?", "Легко, щёлкните по соответствующей кнопке в окне форума или темы. Вам, возможно, придётся зарегистрироваться прежде чем отправить сообщение. То что вы можете делать в данном форуме перечислено внизу страницы форума и темы (Вы можете начинать темы в этом форуме, Вы можете отвечать на сообщения и т.д.)"); +$faq[] = array("Как я могу редактировать или удалить сообщение?", "Если вы не администратор или модератор форума, вы можете редактировать и удалять только свои собственные сообщения. Вы можете редактировать сообщение (иногда только в течении некоторого времени с момента создания) щёлкнув по кнопке Редактировать, относящейся к данному сообщению. Если кто-то уже ответил на ваше сообщение, то под ним появится небольшая надпись, она показывает сколько раз вы редактировали сообщение. Эта надпись не появляется, если никто не отвечал на ваше сообщение, она также не появляется, если ваше сообщение отредактировал администратор или модератор (они должны сами оставить пометку, где сказано, почему они это сделали). Учтите, что обычные пользователи не могут удалить сообщение, если на него уже кто-то ответил."); +$faq[] = array("Как присоединить подпись к моему сообщению?", "Для того, чтобы присоединить подпись, вы должны сначала создать её в своём профиле. После создания вы должны отметить галочкой пункт Присоединить подпись в форме отправки сообщения, чтобы подпись добавилась. Вы также можете сделать чтобы подпись присоединялась по умолчанию, если отметите соответствующий пункт в вашем профиле (вы сможете отключать подпись в определённых сообщениях, убрав галочку Присоединить подпись)"); +$faq[] = array("Как создать опрос?", "Создать опрос легко: когда вы создаёте тему (или редактируете первое сообщение в теме, если у вас есть на то права) чуть ниже основной формы для создания сообщений, вы увидите форму Создать опрос. Если же вы её не видите, то скорее всего у вас нет прав на создание опроса. Вы должны ввести тему опроса, затем как минимум два варианта ответа (чтобы добавить вариант ответа, введите его и щёлкните кнопку Добавить вариант. Вы также можете установить лимит времени на опрос, 0 означает постоянный опрос. Также существует ограничение на количество вариантов ответа, оно устанавливается администратором."); +$faq[] = array("Как я могу редактировать или удалить опрос?", "Также как и сообщения, опросы могут удалять только их создатели, модераторы или администраторы. Чтобы редактировать опрос, перейдите к редактированию первого сообщения в теме (оно всегда относится к опросу). Если никто не успел проголосовать, то пользователи могут редактировать или удалять опрос, но если уже кто-то проголосовал, то только модераторы или администраторы могут удалить его. Это сделано для того, чтобы нельзя было менять варианты ответов, в то время как люди уже проголосовали."); +$faq[] = array("Почему мне недоступны некоторые форумы?", "Некоторые форумы доступны только определённым пользователям или группам пользователей. Чтобы их просматривать, создавать сообщения и т.д., вам может потребоваться специальное разрешение. Только модераторы или администраторы форума могут предоставить такое разрешение, свяжитесь с ними."); +$faq[] = array("Почему я не могу голосовать в опросе?", "Только зарегистрированные пользователи могут участвовать в опросе (чтобы предотвратить подтасовку результатов анонимными пользователями). Если вы зарегистрированы, но не можете голосовать, то, скорее всего, у вас нет на это необходимых прав доступа."); + + +$faq[] = array("--","Форматирование сообщений и типы создаваемых тем"); +$faq[] = array("Что такое BBCode?", "BBCode это особая реализация HTML, возможность использования BBCode определяется администратором (вы также можете отключить его в каждом создаваемом вами сообщении). BBCode очень похож на HTML, тэги в нём заключаются в квадратные скобки [ и ], а не < и >, он даёт пользователю больше возможностей в создании сообщений. За дополнительной информацией о BBCode смотрите руководство по BBCode, ссылка на которое доступна из формы отправки сообщений."); +$faq[] = array("Могу ли я использовать HTML?", "Зависит от того разрешено ли это администратором. Если разрешено его использовать, то, скорее всего, работать будут лишь несколько тэгов. Это сделано для безопасности, чтобы запретить использование тэгов которые могут вызвать проблемы. Если HTML включён, то вы сможете выключить его для конкретного сообщения при создании этого сообщения."); +$faq[] = array("Что такое смайлики?", "Смайлики, или эмотиконы — это маленькие картинки, которые могут быть использованы для выражения чувств, например :) значит радость, :( значит грусть. Полный список смайликов можно увидеть в форме создания сообщений. Только не перестарайтесь, используя их: они легко могут сделать сообщение нечитаемым, и модератор может отредактировать ваше сообщение, или вообще удалить его."); +$faq[] = array("Могу ли я вставлять картинки?", "Вы можете вставлять картинки в сообщения. Но пока нет возможности загружать картинки на форум. Вы должны указать ссылку на картинку, которая находится на общедоступном сервере, например: http://www.some-unknown-place.net/my-picture.gif. Вы не можете указать ни ссылку на свой компьютер (если, конечно, он не является общедоступным сервером), ни на картинки которые находятся за механизмом авторизации, например в почтовых ящиках mail.ru, на защищённых паролем сайтах и т.д. Для отображения картинки в сообщении используйте тэг [img] BBCode или соответствующий тэг HTML (если это разрешено)."); +$faq[] = array("Что такое «Объявление»?", "Объявление чаще всего содержит важную информацию, которую вы должны прочесть как можно скорее. Объявления всегда находится в самом верху форума в котором они было созданы. Возможность создания объявлений зависит от вашего уровня доступа, который определяется администратором."); +$faq[] = array("Что такое «Прилепленная тема»?", "Прилепленные темы находятся ниже объявлений на странице просмотра форума, и при этом только на первой странице. Обычно они тоже несут какую-то важную информацию, и вам стоит прочесть их, как только у вас появится возможность. Так же как и при создании объявлений, вам потребуется необходимый уровень доступа."); +$faq[] = array("Что значит «Тема закрыта»?", "Темы могут быть закрыты только модераторами или администраторами. Вы не можете отвечать на закрытые темы, и любой опрос в закрытой теме автоматически прекращается. Темы закрываются по многим причинам..."); + + +$faq[] = array("--","Уровни пользователей и группы"); +$faq[] = array("Кто такие администраторы?", "Администраторы имеют высший уровень контроля над форумом. Эти люди могут контролировать все аспекты форума: назначение доступа, отключение пользователей, создание групп пользователей и назначение модераторов и т.д. Они также имеют полные модераторские права во всех форумах."); +$faq[] = array("Кто такие модераторы?", "Модераторы это пользователи (или группы пользователей) чья работа — ежедневно следить за форумами. У них есть возможность редактировать, удалять, закрывать и вновь открывать темы, перемещать и разделять темы в форумах, за которые они отвечают. Главные задачи модераторов: не допускать беспорядка в форумах, оскорблений, следить, чтобы сообщения соответствовали теме форума."); +$faq[] = array("Что такое группы пользователей?", "Администраторы могут объединять пользователей в группы. Каждый пользователь может состоять в нескольких группах, и каждой группе могут быть назначены индивидуальные права доступа. Это облегчает администраторам работу с назначением нескольких пользователей модераторами форума, или предоставлением доступа к приватным форумам и т.д."); +$faq[] = array("Как мне вступить в группу?", "Для того, чтобы вступить в группу, щёлкните по ссылке «Группы», которая, как правило, находится наверху (но это зависит от дизайна) и вы увидите список групп. Не все группы общедоступны, некоторый могут быть закрытыми, а некоторые могут быть скрытыми. Если группа общедоступна, то вы можете запросить членство в ней, щёлкнув по соответствующей кнопке. Модератор группы должен будет одобрить ваше участие в группе, он может спросить, зачем вы хотите присоединиться. Пожалуйста, не донимайте модератора группы, выясняя, почему ваш запрос был отклонён, у него могут быть свои причины."); +$faq[] = array("Как мне стать модератором группы?", "Группы пользователей создаются администраторами форума, они же и назначают модераторов групп. Если вы заинтересованы в создании группы, то свяжитесь с администратором, попробуйте отправить ему личное сообщение."); + + +$faq[] = array("--","Личные сообщения"); +$faq[] = array("Я не могу отправить личное сообщение!", "Это может быть вызвано тремя причинами; вы не зарегистрированы и/или не вошли на форум, администратор запретил отправку личных сообщений на всем форуме или же администратор запретил лично вам отправлять личные сообщения. Если верно третье, то спросите у администратора, почему он это сделал."); +$faq[] = array("Я всё время получаю нежелательные личные сообщения!", "В будущем мы добавим возможность создания игнор-списка в службу личных сообщений. Пока же, если вы продолжаете получать нежелательные письма от кого-либо, поставьте в известность администратора: он может вообще запретить этому пользователю отправку личных сообщений."); +$faq[] = array("Я получил спам или оскорбительный e-mail от кого-то с этого форума!", "Очень жаль это слышать. Форма отправки e-mail на данном форуме включает меры предосторожности и возможность отслеживания пользователей, отправляющих подобные сообщения. Вы должны написать e-mail администратору форума с полной копией полученного письма, при этом очень важно включить все заголовки (в них содержится детальная информация о пользователе, который отправил сообщение). Администратор сможет затем принять меры."); + +// +// These entries should remain in all languages and for all modifications +// +$faq[] = array("--","Информация о phpBB 2"); +$faq[] = array("Кто написал этот форум?", "Это программное обеспечение (в его исходной форме) написано и распространяется Группой phpBB, ей и принадлежат авторские права на него. Этот форум выпускается под лицензией GNU General Public Licence и может свободно распространяться, за дополнительной информацией смотрите ссылку вверху"); +$faq[] = array("Почему здесь нет такой-то функции?", "Этот форум был написан Группой phpBB. Если вы уверены, что какая-то функция должна быть добавлена, посетите сайт phpbb.com и узнайте, что думает по этому поводу Группа phpBB. Пожалуйста, не пишите просьбы о включении каких либо функций на форум phpbb.com, Группа использует sourceforge чтобы работать над новыми функциями. Пожалуйста, сначала просмотрите форумы, чтобы выяснить, каково наше мнение по поводу данной функции (если такое мнение у нас есть) и только после этого следуйте процедуре, которая там будет описана."); +$faq[] = array("С кем можно связаться по вопросу некорректного использования и юридических вопросов, связанных с этим форумом?", "Вы должны связаться с администратором данного форума. Если вы не можете выяснить, кто является администратором, то сперва свяжитесь с модератором и спросите у него, с кем вы можете связаться по данному вопросу. Если и теперь вы не получили ответа, свяжитесь с владельцем домена (сделайте whois lookup) или, если форум запущен на бесплатном домене (например chat.ru, yahoo, free.fr, f2s.com, etc.), с техподдержкой данного домена. Пожалуйста, учтите, что Группа phpBB не имеет никакого контроля над данным форумом, и не может нести никакой ответственности за то кем и как данный форум используется. Абсолютно бессмысленно обращаться к Группе phpBB по юридическим вопросам (по приостановке форума, ответственности за него и т.д.), которые не относятся напрямую к вебсайту phpbb.com, или которые частично относятся к программному обеспечению phpBB группы. Если же вы все-таки пошлёте e-mail Группе phpBB об использовании третьей стороной данного форума, то не ждите подробного письма, или вы можете вообще не получить ответа."); + +// +// This ends the FAQ entries +// \ No newline at end of file diff --git a/upload/language/lang_russian/lang_faq_attach.php b/upload/language/lang_russian/lang_faq_attach.php new file mode 100644 index 000000000..b8b8bb4a3 --- /dev/null +++ b/upload/language/lang_russian/lang_faq_attach.php @@ -0,0 +1,33 @@ +Вставить вложение под основным окном отправки сообщения. Когда вы нажмёте на кнопку Поиск..., откроется стандартный диалог. Найдите файл, который вы хотите добавить, выберите его и нажмите ОК. Если вы хотите добавить комментарий в поле Комментарии ваш комментарий будет использован как ссылка к прикреплённому файлу. Если вы не добавили комментарий, само название файла будет использоваться, как ссылка на вложение. Если администратор форума разрешил, вы сможете добавить несколько файлов, используя тот же метод, что описан наверху, пока не будет достигнуто число разрешённых вложений для каждого сообщения.

    Размер файлов, разрешённые расширения и другие вещи, связанные с вложениями, зависят от администратора форума. Но вся ответственность за вложенные вами файлы ложится на вас. Проверьте, что файлы отвечают правилам форума, иначе они будут удалены без предупреждения.

    Пожалуйста заметьте, что администраторы и модераторы форума не принимают ответственности за потерю файлов."); +$faq[] = array("Как добавить вложение, если сообщение уже отправлено?", "Чтобы добавить вложение после отправки сообщения, вам необходимо отредактировать ваше сообщение. Новое вложение будет добавлено когда вы нажмёте Отправить, чтобы отправить отредактированное сообщение."); +$faq[] = array("Как удалить вложение?", "Чтобы удалить вложение, необходимо отредактировать сообщение и нажать на Удалить вложение возле вложение, которое вы хотите удалить. Вложение будет удалено, когда вы нажмёте на Отправить, чтобы отправить отредактированное сообщение."); +$faq[] = array("Как изменить комментарий к файлу?", "Чтобы изменить комментарий к файлу, нужно отредактировать почту, изменив текст в поле Комментарий к файлуи нажать на кнопку Обновить комментарии возле комментария, который вы хотите изменить. Комментарий будет изменён, когда вы нажмёте на кнопку Отрпавить, чтобы отправить отредактированное сообщение."); +$faq[] = array("Как изменить комментарий к файлу?", "Чтобы изменить комментарий к файлу, нужно отредактировать почту, изменив текст в поле Комментарий к файлуи нажать на кнопку Обновить комментарии возле комментария, который вы хотите изменить. Комментарий будет изменён, когда вы нажмёте на кнопку Отправить, чтобы отправить отредактированное сообщение."); +$faq[] = array("Почему моего вложения не видно в сообщении?", "Наверное файл или расширение больше не разрешены на форуме, или модератор/администратор убрал его, потому что оно конфликтует с правилами форума."); +$faq[] = array("Почему я не могу добавить вложение?", "В некоторых форумах добавление файлов разрешено только определённым пользователям или группам. Чтобы добавить файлы, необходимо получить специальное разрешение. Только модератор форума или администратор может вам его дать, так что свяжитесь с ними."); +$faq[] = array("Я получил разрешение, почему я всё ещё не могу добавлять приложения?", "Размер файлов, разрешённые расширения и другие вещи зависят от администратора форума. Может быть модератор или администратор изменили ваши права, или запретили приложения в определённых форумах. Когда вы пытаетесь добавить файл, форум должен выдать подробное описание проблемы, почему приложения не работают. Если этого недостаточно, свяжитесь с модератором или администратором, чтобы решить проблему."); +$faq[] = array("Почему я не могу удалить вложение?", "В некоторых форумах удаление вложений разрешено только определённым пользователям или группам. Чтобы удалить вложение, необходимы права, которые могут дать только модератор или администратор форума, поэтому свяжитесь с ними."); +$faq[] = array("Почему я не могу просмотреть/скачать вложение?", "В некоторых форумах скачивание файлов может быть разрешено только определённым пользователям или группам. Чтобы скачать файлы, нужны определённые права, и только модератор и администратор могут их вам дать, так что свяжитесь с ними."); +$faq[] = array("С кем мне надо связаться, чтобы сообщить о незаконных приложениях?", "Свяжитесь с администратором форума. Если вы не знаете, кто это, свяжитесь сначала с модераторами и спросите их, как связаться с администратором. Если вы не получите ответа, вам нужно будет связаться с владельцем домена (с помощью whois поиска), или, если сайт находится на бесплатном хостинге, вроде yahoo/tripod,, свяжитесь с администратором того сёрвера. Заметьте, что phpBB Group не принимает никакой ответственности за то, как или кто использует форум. Поэтому совершенно бесполезно контактировать phpBB Group с просьбами о прекращении какой бы то ни было нелегальной деятельности совершённой 3-ми лицами."); +$faq[] = array("С кем мне надо связаться, чтобы сообщить о незаконных приложениях?", "Свяжитесь с администратором форума. Если вы не знаете, кто это, свяжитесь сначала с модераторами и спросите их, как связаться с администратором. Если вы не получите ответа, вам нужно будет связаться с владельцем домена (с помощью whois поиска), или, если сайт находится на бесплатном хостинге, вроде yahoo/tripod,, свяжитесь с администратором того сёрвера. Заметьте, что phpBB Group не принимает никакой ответственности за то, как или кто использует форум. Поэтому совершенно бесполезно контактировать phpBB Group с просьбами о прекращении какой бы то ни было нелегальной деятельности совершённой 3-ми лицами."); diff --git a/upload/language/lang_russian/lang_gallery.php b/upload/language/lang_russian/lang_gallery.php new file mode 100644 index 000000000..d050f54f8 --- /dev/null +++ b/upload/language/lang_russian/lang_gallery.php @@ -0,0 +1,29 @@ + 'Топик:
    удален', + 'mod_topic_move' => 'Топик:
    перенесен', + 'mod_topic_lock' => 'Топик:
    закрыт', + 'mod_topic_unlock' => 'Топик:
    открыт', + 'mod_topic_split' => 'Топик:
    разделен', + 'mod_post_delete' => 'Пост:
    удален', + 'adm_user_delete' => 'Юзер:
    удален', + 'adm_user_ban' => 'Юзер:
    забанен', + 'adm_user_unban' => 'Юзер:
    разбанен' +); + +$lang['ACTS_LOG_ALL_ACTIONS'] = 'Все действия'; +$lang['ACTS_LOG_SEARCH_OPTIONS'] = 'Настройки отчета по действиям'; +$lang['ACTS_LOG_FORUM'] = 'Форум'; +$lang['ACTS_LOG_ACTION'] = 'Действие'; +$lang['ACTS_LOG_USER'] = 'Юзер'; +$lang['ACTS_LOG_LOGS_FROM'] = 'Логи с '; +$lang['ACTS_LOG_FIRST'] = 'сначала '; +$lang['ACTS_LOG_DAYS_BACK'] = 'дней назад'; +$lang['ACTS_LOG_TOPIC_MATCH'] = 'Совпадение с названием темы'; +$lang['ACTS_LOG_SORT_BY'] = 'Сотировать по'; +$lang['ACTS_LOG_LOGS_ACTION'] = 'Действие'; +$lang['ACTS_LOG_USERNAME'] = 'Имя пользователя'; +$lang['ACTS_LOG_TIME'] = 'Время'; +$lang['ACTS_LOG_INFO'] = 'Инфо'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_main.php b/upload/language/lang_russian/lang_main.php new file mode 100644 index 000000000..419246866 --- /dev/null +++ b/upload/language/lang_russian/lang_main.php @@ -0,0 +1,1537 @@ +%d из %s'; + +$lang['ICQ'] = 'ICQ Number'; + +$lang['FORUM_INDEX'] = 'Список форумов %s'; + +$lang['POST_NEW_TOPIC'] = 'Начать новую тему'; +$lang['POST_REGULAR_TOPIC'] = 'Создать обычную тему'; +$lang['REPLY_TO_TOPIC'] = 'Ответить на тему'; +$lang['REPLY_WITH_QUOTE'] = 'Ответить с цитатой'; + +$lang['CLICK_RETURN_TOPIC'] = '%sВернуться в тему%s'; +$lang['CLICK_RETURN_LOGIN'] = '%sПопробовать ещё раз%s'; +$lang['CLICK_RETURN_FORUM'] = '%sВернуться в форум%s'; +$lang['CLICK_VIEW_MESSAGE'] = '%sПросмотреть ваше сообщение%s'; +$lang['CLICK_RETURN_MODCP'] = '%sВернуться к панели модерации%s'; +$lang['CLICK_RETURN_GROUP'] = '%sВернуться к информации о группах%s'; + +$lang['ADMIN_PANEL'] = 'Перейти в администраторский раздел'; + +$lang['BOARD_DISABLE'] = 'Извините, эти форумы отключены. Попробуйте зайти попозже'; + +$lang['LOADING'] = 'Загружается...'; +$lang['JUMPBOX_TITLE'] = 'Выберите форум для перехода'; +$lang['DISPLAYING_OPTIONS'] = 'Опции показа'; + +// +// Global Header strings +// +$lang['REGISTERED_USERS'] = 'Зарегистрированные пользователи:'; +$lang['BROWSING_FORUM'] = 'Сейчас этот форум просматривают:'; +$lang['ONLINE_USERS'] = 'Сейчас на форуме %1$d посетителей: %2$d зарегистрированных и %3$d гостей'; +$lang['RECORD_ONLINE_USERS'] = 'Больше всего посетителей (%s) здесь было %s'; // first %s = number of users, second %s is the date. +$lang['USERS'] = 'юзеров'; + +$lang['ONLINE_ADMIN'] = 'Администратор'; +$lang['ONLINE_MOD'] = 'Модератор'; +$lang['ONLINE_GROUP_MEMBER'] = 'Участник групп'; + +$lang['YOU_LAST_VISIT'] = 'Ваш последний визит: %s'; +$lang['CURRENT_TIME'] = 'Текущее время: %s'; + +$lang['SEARCH_NEW'] = 'Новые сообщения'; +$lang['SEARCH_SELF'] = 'Мои сообщения'; +$lang['SEARCH_SELF_BY_LAST'] = 'времени последнего сообщения'; +$lang['SEARCH_SELF_BY_MY'] = 'времени моего сообщения'; +$lang['SEARCH_UNANSWERED'] = 'Сообщения без ответов'; +$lang['SEARCH_UNANSWERED_SHORT'] = 'без ответов'; +$lang['SEARCH_LATEST'] = 'Последние'; + +$lang['REGISTER'] = 'Регистрация'; +$lang['PROFILE'] = 'Профиль'; +$lang['EDIT_PROFILE'] = 'Редактирование вашего профиля'; +$lang['SEARCH'] = 'Поиск'; +$lang['MEMBERLIST'] = 'Пользователи'; +$lang['FAQ'] = 'FAQ'; +$lang['BBCODE_GUIDE'] = 'Руководство по BBCode'; +$lang['USERGROUPS'] = 'Группы'; +$lang['LASTPOST'] = 'Посл. сообщение'; +$lang['MODERATOR'] = 'Модератор'; +$lang['MODERATORS'] = 'Модераторы'; +$lang['TERMS'] = 'Правила'; + +// +// Stats block text +// +$lang['POSTED_TOPICS_TOTAL'] = 'Наши пользователи создали тем: %s'; // Number of topics +$lang['POSTED_ARTICLES_ZERO_TOTAL'] = 'Наши пользователи не оставили ни одного сообщения'; // Number of posts +$lang['POSTED_ARTICLES_TOTAL'] = 'Наши пользователи оставили сообщений: %s'; // Number of posts +$lang['REGISTERED_USERS_ZERO_TOTAL'] = 'У нас нет зарегистрированных пользователей'; // # registered users +$lang['REGISTERED_USERS_TOTAL'] = 'Всего зарегистрированных пользователей: %s'; // # registered users +$lang['NEWEST_USER'] = 'Последний зарегистрированный пользователь: %s%s%s'; // username + +// Tracker stats +$lang['TORRENTS_STAT'] = 'Раздач: %s,  общий размер: %s'; // first %s = number of torrents, second %s is the total size. +$lang['PEERS_STAT'] = 'Пиров: %s,  сидеров: %s,  личеров: %s'; // first %s = number of peers, second %s = number of seeders, third %s = number of leechers. +$lang['SPEED_STAT'] = 'Скорость обмена: %s '; // %s = total speed. + +$lang['NO_NEW_POSTS_LAST_VISIT'] = 'Нет новых сообщений с последнего посещения'; +$lang['NO_NEW_POSTS'] = 'Нет новых сообщений'; +$lang['NEW_POSTS'] = 'Новые сообщения'; +$lang['NEW_POST'] = 'Новое сообщение'; +$lang['NO_NEW_POSTS_HOT'] = 'Нет новых сообщений [ Популярная тема ]'; +$lang['NEW_POSTS_HOT'] = 'Новые сообщения [ Популярная тема ]'; +$lang['NO_NEW_POSTS_LOCKED'] = 'Тема закрыта'; +$lang['NEW_POSTS_LOCKED'] = 'Новые сообщения [ Тема закрыта ]'; +$lang['FORUM_LOCKED_MAIN'] = 'Форум закрыт'; + +// +// Login +// +$lang['ENTER_PASSWORD'] = 'Введите ваше имя и пароль для входа в систему'; +$lang['LOGIN'] = 'Вход'; +$lang['LOGOUT'] = 'Выход'; +$lang['CONFIRM_LOGOUT'] = 'Вы уверены, что хотите выйти?'; + +$lang['FORGOTTEN_PASSWORD'] = 'Забыли пароль?'; +$lang['AUTO_LOGIN'] = 'Автоматически входить при каждом посещении'; +$lang['ERROR_LOGIN'] = 'Вы ввели неверное/неактивное имя пользователя или неверный пароль.'; +$lang['REMEMBER'] = 'Запомнить'; +$lang['USER_WELCOME'] = 'Вы зашли как: '; + +// +// Index page +// +$lang['INDEX'] = 'Главная'; +$lang['HOME'] = 'Главная'; +$lang['NO_POSTS'] = 'Нет сообщений'; +$lang['NO_FORUMS'] = 'На этом сайте нет форумов'; + +$lang['PRIVATE_MESSAGE'] = 'Личное сообщение'; +$lang['PRIVATE_MESSAGES'] = 'Личные сообщения'; +$lang['WHOSONLINE'] = 'Кто сейчас на форуме'; + +$lang['MARK_ALL_FORUMS_READ'] = 'Отметить все форумы как прочтённые'; +$lang['FORUMS_MARKED_READ'] = 'Все форумы были отмечены как прочтённые'; + +$lang['LATEST_NEWS'] = 'Последние новости'; +$lang['SUBFORUMS'] = 'Подфорумы'; + +// +// Viewforum +// +$lang['VIEW_FORUM'] = 'Просмотр форума'; + +$lang['FORUM_NOT_EXIST'] = 'Форума, который вы выбрали, не существует'; +$lang['REACHED_ON_ERROR'] = 'Вы попали на эту страницу из-за ошибки'; + +$lang['DISPLAY_TOPICS'] = 'Показать'; +$lang['ALL_TOPICS'] = 'все темы'; +$lang['TOPICS_PER_PAGE'] = 'тем на страницу'; +$lang['MODERATE_FORUM'] = 'Модерировать этот форум'; +$lang['TITLE_SEARCH_HINT'] = 'поиск по названию...'; + +$lang['TOPIC_ANNOUNCEMENT'] = 'Объявление:'; +$lang['TOPIC_STICKY'] = 'Прилеплена:'; +$lang['TOPIC_MOVED'] = 'Перемещена:'; +$lang['TOPIC_POLL'] = '[ Опрос ]'; + +$lang['MARK_TOPICS_READ'] = 'Отметить все темы как прочтённые'; +$lang['TOPICS_MARKED_READ'] = 'Все темы в этом форуме были отмечены как прочтённые'; + +$lang['RULES_POST_CAN'] = 'Вы можете начинать темы'; +$lang['RULES_POST_CANNOT'] = 'Вы не можете начинать темы'; +$lang['RULES_REPLY_CAN'] = 'Вы можете отвечать на сообщения'; +$lang['RULES_REPLY_CANNOT'] = 'Вы не можете отвечать на сообщения'; +$lang['RULES_EDIT_CAN'] = 'Вы можете редактировать свои сообщения'; +$lang['RULES_EDIT_CANNOT'] = 'Вы не можете редактировать свои сообщения'; +$lang['RULES_DELETE_CAN'] = 'Вы можете удалять свои сообщения'; +$lang['RULES_DELETE_CANNOT'] = 'Вы не можете удалять свои сообщения'; +$lang['RULES_VOTE_CAN'] = 'Вы можете голосовать в опросах'; +$lang['RULES_VOTE_CANNOT'] = 'Вы не можете голосовать в опросах'; +$lang['RULES_MODERATE'] = 'Вы можете модерировать этот форум'; + +$lang['NO_TOPICS_POST_ONE'] = 'В этом форуме пока нет сообщений
    Щёлкните Начать новую тему, и ваше сообщение станет первым.'; + + +// +// Viewtopic +// +$lang['VIEW_TOPIC'] = 'Просмотр темы'; + +$lang['GUEST'] = 'Гость'; +$lang['POST_SUBJECT'] = 'Заголовок сообщения'; +$lang['SUBMIT_VOTE'] = 'Проголосовать'; +$lang['VIEW_RESULTS'] = 'Результаты'; + +$lang['NO_NEWER_TOPICS'] = 'В этом форуме нет более новых тем'; +$lang['NO_OLDER_TOPICS'] = 'В этом форуме нет более старых тем'; +$lang['TOPIC_POST_NOT_EXIST'] = 'Темы, которую вы запросили, не существует.'; +$lang['NO_POSTS_TOPIC'] = 'В этой теме нет сообщений'; + +$lang['DISPLAY_POSTS'] = 'Показать сообщения'; +$lang['ALL_POSTS'] = 'все сообщения'; +$lang['NEWEST_FIRST'] = 'Начиная с новых'; +$lang['OLDEST_FIRST'] = 'Начиная со старых'; + +$lang['BACK_TO_TOP'] = 'Вернуться к началу'; + +$lang['READ_PROFILE'] = 'Посмотреть профиль'; +$lang['VISIT_WEBSITE'] = 'Посетить сайт автора'; +$lang['VIEW_IP'] = 'Показать IP адрес автора'; +$lang['MODERATE_POST'] = 'Модерировать сообщения'; +$lang['DELETE_POST'] = 'Удалить это сообщение'; + +$lang['WROTE'] = 'писал(а)'; // proceeds the username and is followed by the quoted text +$lang['QUOTE'] = 'Цитата'; // comes before bbcode quote output. +$lang['CODE'] = 'Код'; // comes before bbcode code output. +$lang['CODE_COPIED'] = 'Код скопирован в буфер обмена'; +$lang['CODE_COPY'] = 'скопировать в буфер обмена'; +$lang['SPOILER_HEAD'] = 'скрытый текст'; + +$lang['EDITED_TIME_TOTAL'] = 'Последний раз редактировалось: %s (%s), всего редактировалось %d раз'; // Last edited by me on 12 Oct 2001, edited 1 time in total +$lang['EDITED_TIMES_TOTAL'] = 'Последний раз редактировалось: %s (%s), всего редактировалось %d раз(а)'; // Last edited by me on 12 Oct 2001, edited 2 times in total + +$lang['LOCK_TOPIC'] = 'Закрыть тему'; +$lang['UNLOCK_TOPIC'] = 'Вновь открыть тему'; +$lang['MOVE_TOPIC'] = 'Перенести тему'; +$lang['DELETE_TOPIC'] = 'Удалить тему'; +$lang['SPLIT_TOPIC'] = 'Разделить тему'; + +$lang['STOP_WATCHING_TOPIC'] = 'Перестать следить за ответами'; +$lang['START_WATCHING_TOPIC'] = 'Следить за ответами в теме'; +$lang['NO_LONGER_WATCHING'] = 'Вы больше не следите за ответами в этой теме'; +$lang['YOU_ARE_WATCHING'] = 'Теперь вы следите за ответами в этой теме'; + +$lang['TOTAL_VOTES'] = 'Всего проголосовало'; +$lang['SEARCH_IN_TOPIC'] = 'искать в теме...'; +$lang['HIDE_IN_TOPIC'] = 'Не показывать'; + +$lang['FLAGS'] = 'флаги'; +$lang['AVATARS'] = 'аватары'; +$lang['RANK_IMAGES'] = 'картинки званий'; +$lang['POST_IMAGES'] = 'картинки в сообщениях'; +$lang['SMILIES'] = 'смайлики'; +$lang['SIGNATURES'] = 'подписи'; +$lang['SPOILER'] = 'Спойлер'; +$lang['SHOW_OPENED'] = 'показывать открытым'; + +$lang['MODERATE_TOPIC'] = 'Модерировать этот топик'; +$lang['SELECT_POSTS_PER_PAGE'] = 'сообщ. на страницу'; + + +// +// Posting/Replying (Not private messaging!) +// +$lang['MESSAGE_BODY'] = 'Сообщение'; +$lang['TOPIC_REVIEW'] = 'Обзор темы'; + +$lang['NO_POST_MODE'] = 'Не указан режим сообщения'; + +$lang['POST_A_NEW_TOPIC'] = 'Начать новую тему'; +$lang['POST_A_REPLY'] = 'Ответить'; +$lang['POST_TOPIC_AS'] = 'Статус создаваемой темы'; +$lang['EDIT_POST'] = 'Редактировать сообщение'; +$lang['OPTIONS'] = 'Настройки'; + +$lang['POST_ANNOUNCEMENT'] = 'Объявление'; +$lang['POST_STICKY'] = 'Прилепленная'; +$lang['POST_NORMAL'] = 'Обычная'; +$lang['POST_DOWNLOAD'] = 'Download'; + +$lang['CONFIRM_DELETE'] = 'Вы уверены, что хотите удалить это сообщение?'; +$lang['CONFIRM_DELETE_POLL'] = 'Вы уверены, что хотите удалить этот опрос?'; + +$lang['FLOOD_ERROR'] = 'Вы не можете отправить следующее сообщение сразу после предыдущего. Пожалуйста, попробуйте чуть попозже.'; +$lang['EMPTY_SUBJECT'] = 'Вы должны указать заголовок сообщения, когда начинаете новую тему'; +$lang['EMPTY_MESSAGE'] = 'Вы должны ввести текст сообщения'; +$lang['FORUM_LOCKED'] = 'Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.'; +$lang['TOPIC_LOCKED'] = 'Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.'; +$lang['TOPIC_LOCKED_SHORT'] = 'Тема закрыта'; +$lang['NO_POST_ID'] = 'Вы должны выбрать сообщение для редактирования'; +$lang['NO_TOPIC_ID'] = 'Вы должны выбрать тему для ответа'; +$lang['NO_VALID_MODE'] = 'Вы можете только создавать темы, отвечать и редактировать сообщения. Вернитесь и попробуйте ещё раз.'; +$lang['NO_SUCH_POST'] = 'Сообщение отсутствует. Вернитесь и попробуйте ещё раз.'; +$lang['EDIT_OWN_POSTS'] = 'Извините, вы можете редактировать только ваши собственные сообщения'; +$lang['DELETE_OWN_POSTS'] = 'Извините, вы можете удалять только ваши собственные сообщения'; +$lang['CANNOT_DELETE_REPLIED'] = 'Извините, вы не можете удалить сообщение, на которое были получены ответы'; +$lang['CANNOT_DELETE_POLL'] = 'Извините, вы не можете удалить активный опрос'; +$lang['EMPTY_POLL_TITLE'] = 'Вы должны ввести заголовок для опроса'; +$lang['TO_FEW_POLL_OPTIONS'] = 'Вы должны ввести не менее двух вариантов ответа'; +$lang['TO_MANY_POLL_OPTIONS'] = 'Вы попытались ввести слишком много вариантов ответа'; +$lang['POST_HAS_NO_POLL'] = 'В этом сообщении нет опроса'; +$lang['ALREADY_VOTED'] = 'Вы уже голосовали в этом опросе'; +$lang['NO_VOTE_OPTION'] = 'Вы должны указать вариант ответа при голосовании'; +$lang['LOCKED_WARN'] = 'Вы отправили сообщение в закрытый топик!'; + +$lang['ADD_POLL'] = 'Добавить опрос'; +$lang['ADD_POLL_EXPLAIN'] = 'Если вы не хотите добавлять опрос к вашему сообщению, оставьте поля пустыми'; +$lang['POLL_QUESTION'] = 'Вопрос'; +$lang['POLL_OPTION'] = 'Вариант ответа'; +$lang['ADD_OPTION'] = 'Добавить ещё вариант'; +$lang['UPDATE'] = 'Обновить'; +$lang['POLL_FOR'] = 'Опрос должен идти'; +$lang['DAYS'] = 'Дней'; +$lang['POLL_FOR_EXPLAIN'] = '[ оставьте поле пустым, чтобы опрос не кончался ]'; +$lang['DELETE_POLL'] = 'Удалить опрос'; + +$lang['DISABLE_BBCODE_POST'] = 'Отключить BBCode'; +$lang['DISABLE_SMILIES_POST'] = 'Отключить смайлики'; +$lang['MAX_SMILIES_PER_POST'] = 'Лимит в %s смайлов в сообщении привышен.'; + +$lang['BBCODE_IS_ON'] = '%sBBCode%s ВКЛЮЧЁН'; +$lang['BBCODE_IS_OFF'] = '%sBBCode%s ВЫКЛЮЧЕН'; +$lang['SMILIES_ARE_ON'] = 'Смайлики ВКЛЮЧЕНЫ'; +$lang['SMILIES_ARE_OFF'] = 'Смайлики ВЫКЛЮЧЕНЫ'; + +$lang['ATTACH_SIGNATURE'] = 'Присоединить подпись (можно изменять в профиле)'; +$lang['NOTIFY'] = 'Сообщать мне о получении ответа'; + +$lang['STORED'] = 'Ваше сообщение было успешно добавлено'; +$lang['DELETED'] = 'Ваше сообщение было успешно удалено'; +$lang['POLL_DELETE'] = 'Ваш опрос был успешно удалён'; +$lang['VOTE_CAST'] = 'Ваш голос был учтён'; + +$lang['TOPIC_REPLY_NOTIFICATION'] = 'Уведомление об ответе в теме'; + +$lang['BBCODE_B_HELP'] = 'Жирный текст: [b]текст[/b] (alt+b)'; +$lang['BBCODE_I_HELP'] = 'Наклонный текст: [i]текст[/i] (alt+i)'; +$lang['BBCODE_U_HELP'] = 'Подчёркнутый текст: [u]текст[/u] (alt+u)'; +$lang['BBCODE_Q_HELP'] = 'Цитата: [quote]текст[/quote] (alt+q)'; +$lang['BBCODE_C_HELP'] = 'Код (программа): [code]код[/code] (alt+c)'; +$lang['BBCODE_L_HELP'] = 'Список: [list]текст[/list] (alt+l)'; +$lang['BBCODE_O_HELP'] = 'Нумерованный список: [list=]текст[/list] (alt+o)'; +$lang['BBCODE_P_HELP'] = 'Вставить картинку: [img]http://image_url[/img] (alt+p)'; +$lang['BBCODE_W_HELP'] = 'Вставить ссылку: [url]http://url[/url] или [url=http://url]текст ссылки[/url] (alt+w)'; +$lang['BBCODE_A_HELP'] = 'Закрыть все открытые теги bbCode'; +$lang['BBCODE_S_HELP'] = 'Цвет шрифта: [color=red]текст[/color] Подсказка: можно использовать color=#FF0000'; +$lang['BBCODE_F_HELP'] = 'Размер шрифта: [size=x-small]маленький текст[/size]'; + +$lang['EMOTICONS'] = 'Смайлики'; +$lang['MORE_EMOTICONS'] = 'Дополнительные смайлики'; + +$lang['FONT_COLOR'] = 'Цвет'; +$lang['COLOR_DEFAULT'] = 'По умолчанию'; +$lang['COLOR_DARK_RED'] = 'Тёмно-красный'; +$lang['COLOR_RED'] = 'Красный'; +$lang['COLOR_ORANGE'] = 'Оранжевый'; +$lang['COLOR_BROWN'] = 'Коричневый'; +$lang['COLOR_YELLOW'] = 'Жёлтый'; +$lang['COLOR_GREEN'] = 'Зелёный'; +$lang['COLOR_OLIVE'] = 'Оливковый'; +$lang['COLOR_CYAN'] = 'Голубой'; +$lang['COLOR_BLUE'] = 'Синий'; +$lang['COLOR_DARK_BLUE'] = 'Тёмно-синий'; +$lang['COLOR_INDIGO'] = 'Индиго'; +$lang['COLOR_VIOLET'] = 'Фиолетовый'; +$lang['COLOR_WHITE'] = 'Белый'; +$lang['COLOR_BLACK'] = 'Чёрный'; + +$lang['FONT_SIZE'] = 'Размер'; +$lang['FONT_TINY'] = 'Очень маленький'; +$lang['FONT_SMALL'] = 'Маленький'; +$lang['FONT_NORMAL'] = 'Обычный'; +$lang['FONT_LARGE'] = 'Большой'; +$lang['FONT_HUGE'] = 'Огромный'; + +$lang['STYLES_TIP'] = 'Подсказка: Можно быстро применить стили к выделенному тексту'; + +$lang['NEW_POSTS_PREVIEW'] = 'В топике есть новые, измененные или непрочитанные сообщения'; + +// +// Private Messaging +// +$lang['PRIVATE_MESSAGING'] = 'Личные сообщения'; + +$lang['NO_NEW_PM'] = 'новых нет'; + +$lang['NEW_PMS_FORMAT'] = '%1$s %2$s'; // 1 новое сообщ. +$lang['NEW_PMS_DECLENSION'] = array('новое сообщение', 'новых сообщений'); + +$lang['UNREAD_PMS_FORMAT'] = '%1$s %2$s'; // 1 непрочитанное +$lang['UNREAD_PMS_DECLENSION'] = array('непрочитанное', 'непрочитанных'); + +$lang['UNREAD_MESSAGE'] = 'Непрочитанное сообщение'; +$lang['READ_MESSAGE'] = 'Прочитанное сообщение'; + +$lang['READ_PM'] = 'Прочитать сообщение'; +$lang['POST_NEW_PM'] = 'Написать новое сообщение'; +$lang['POST_REPLY_PM'] = 'Ответить на сообщение'; +$lang['POST_QUOTE_PM'] = 'Ответить с цитатой'; +$lang['EDIT_PM'] = 'Редактировать сообщение'; + +$lang['INBOX'] = 'Входящие'; +$lang['OUTBOX'] = 'Исходящие'; +$lang['SAVEBOX'] = 'Сохранённые'; +$lang['SENTBOX'] = 'Отправленные'; +$lang['FLAG'] = 'Флаг'; +$lang['SUBJECT'] = 'Тема'; +$lang['FROM'] = 'От'; +$lang['TO'] = 'Кому'; +$lang['DATE'] = 'Дата'; +$lang['MARK'] = 'Отметка'; +$lang['SENT'] = 'Отправлено'; +$lang['SAVED'] = 'Сохранено'; +$lang['DELETE_MARKED'] = 'Удалить отмеченное'; +$lang['DELETE_ALL'] = 'Удалить все'; +$lang['SAVE_MARKED'] = 'Сохранить отмеченное'; +$lang['SAVE_MESSAGE'] = 'Сохранить сообщение'; +$lang['DELETE_MESSAGE'] = 'Удалить сообщение'; + +$lang['DISPLAY_MESSAGES'] = 'Показать сообщения'; // Followed by number of days/weeks/months +$lang['ALL_MESSAGES'] = 'Все сообщения'; + +$lang['NO_MESSAGES_FOLDER'] = 'В этой папке нет сообщений'; + +$lang['PM_DISABLED'] = 'Возможность отправки личных сообщений на этих форумах была отключена'; +$lang['CANNOT_SEND_PRIVMSG'] = 'Извините, вам не разрешено отправлять личные сообщения'; +$lang['NO_TO_USER'] = 'Вы должны указать имя получателя этого сообщения'; +$lang['NO_SUCH_USER'] = 'Извините, но такого пользователя не существует'; + +$lang['GALLERY_DISABLED'] = 'Галерея отключена'; + +$lang['DISABLE_BBCODE_PM'] = 'Отключить BBCode'; +$lang['DISABLE_SMILIES_PM'] = 'Отключить смайлики'; + +$lang['MESSAGE_SENT'] = 'Ваше сообщение было отправлено'; + +$lang['CLICK_RETURN_INBOX'] = 'Перейти в папку:

    %sВходящие%s'; +$lang['CLICK_RETURN_SENTBOX'] = '   %sОтправленные%s'; +$lang['CLICK_RETURN_OUTBOX'] = '   %sИсходящие%s'; +$lang['CLICK_RETURN_SAVEBOX'] = '   %sСохраненные%s'; +$lang['CLICK_RETURN_INDEX'] = '%sВернуться к списку форумов%s'; + +$lang['SEND_A_NEW_MESSAGE'] = 'Отправить личное сообщение'; +$lang['SEND_A_REPLY'] = 'Ответить на личное сообщение'; +$lang['EDIT_MESSAGE'] = 'Редактировать личное сообщение'; + +$lang['NOTIFICATION_SUBJECT'] = 'Вам пришло новое личное сообщение'; + +$lang['FIND_USERNAME'] = 'Найти пользователя'; +$lang['SELECT_USERNAME'] = 'Выберите пользователя'; +$lang['FIND'] = 'Найти'; +$lang['NO_MATCH'] = 'Не найдено'; + +$lang['NO_POST_ID'] = 'Не указан ID'; +$lang['NO_SUCH_FOLDER'] = 'Такой папки нет'; +$lang['NO_FOLDER'] = 'Не указана папка'; + +$lang['MARK_ALL'] = 'Выделить все'; +$lang['UNMARK_ALL'] = 'Снять выделение'; + +$lang['CONFIRM_DELETE_PM'] = 'Вы уверены, что хотите удалить это сообщение?'; +$lang['CONFIRM_DELETE_PMS'] = 'Вы уверены, что хотите удалить эти сообщения?'; + +$lang['INBOX_SIZE'] = 'Ваша папка «Входящие»
    заполнена на %d%%'; // eg. Your Inbox is 50% full +$lang['SENTBOX_SIZE'] = 'Ваша папка «Отправленные»
    заполнена на %d%%'; +$lang['SAVEBOX_SIZE'] = 'Ваша папка «Сохранённые»
    заполнена на %d%%'; + +$lang['CLICK_VIEW_PRIVMSG'] = '%sПерейти в папку «Входящие»%s'; + +$lang['OUTBOX_EXPL'] = 'В папке Исходящие находятся отправленные, но еще не прочтённые получателем сообщения. В Отправленные они попадают только после того, как получатель их прочтет. Сообщения, находящиеся в папке Исходящие, можно отредактировать или удалить.'; + +// +// Profiles/Registration +// +$lang['VIEWING_USER_PROFILE'] = 'Профиль пользователя %s'; // %s is username +$lang['ABOUT_USER'] = 'О пользователе %s'; // слово 'пользователь' - чтобы не заморачиваться с мужским/женским родом + +$lang['DISABLED_USER'] = 'Пользователь деактивирован'; +$lang['MANAGE_USER'] = 'Администрирование'; + +$lang['PREFERENCES'] = 'Личные настройки'; +$lang['ITEMS_REQUIRED'] = 'Поля отмеченные * обязательны к заполнению, если не указано обратное'; +$lang['REGISTRATION_INFO'] = 'Регистрационная информация'; +$lang['PROFILE_INFO'] = 'Профиль'; +$lang['PROFILE_INFO_WARN'] = 'Эта информация будет в открытом доступе'; +$lang['AVATAR_PANEL'] = 'Управление аватарой'; +$lang['AVATAR_GALLERY'] = 'Галерея аватар'; + +$lang['WEBSITE'] = 'Сайт'; +$lang['LOCATION'] = 'Откуда'; +$lang['CONTACT'] = 'Как связаться с'; // Как связаться с Vasya_Poopkin +$lang['EMAIL_ADDRESS'] = 'Адрес e-mail'; +$lang['SEND_PRIVATE_MESSAGE'] = 'Отправить личное сообщение'; +$lang['HIDDEN_EMAIL'] = '[ скрыт ]'; +$lang['INTERESTS'] = 'Интересы'; +$lang['OCCUPATION'] = 'Род занятий'; +$lang['POSTER_RANK'] = 'Звание'; + +$lang['TOTAL_POSTS'] = 'Всего сообщений'; +$lang['USER_POST_PCT_STATS'] = '%.2f%% от общего числа'; // 15% of total +$lang['USER_POST_DAY_STATS'] = '%.2f сообщений в день'; // 1.5 posts per day +$lang['SEARCH_USER_POSTS'] = 'Найти сообщения пользователя %s'; // Find all posts by username +$lang['SEARCH_USER_POSTS_SHORT'] = 'Найти сообщения пользователя'; +$lang['SEARCH_USER_TOPICS'] = 'Начатые темы'; // Find all topics by username + +$lang['NO_USER_ID_SPECIFIED'] = 'Извините, такого пользователя не существует'; +$lang['WRONG_PROFILE'] = 'Вы не можете редактировать чужой профиль.'; + +$lang['ONLY_ONE_AVATAR'] = 'Может быть указан только один тип аватары'; +$lang['FILE_NO_DATA'] = 'Файл по указанному вами URL не содержит данных'; +$lang['NO_CONNECTION_URL'] = 'Невозможно установить соединения с указанным вами URL'; +$lang['INCOMPLETE_URL'] = 'Вы указали неполный URL'; +$lang['WRONG_REMOTE_AVATAR_FORMAT'] = 'Неверный URL удалённой аватары'; +$lang['NO_SEND_ACCOUNT_INACTIVE'] = 'Извините, но пароль не может быть выслан (учетная запись неактивна)'; +$lang['NO_SEND_ACCOUNT'] = 'Извините, но пароль для этого пользователя не может быть выслан. Обратитесь к администраторам форума за дополнительной информацией'; + +$lang['ALWAYS_ADD_SIG'] = 'Всегда присоединять мою подпись'; +$lang['HIDE_PORN_FORUMS'] = 'Скрыть pron форумы'; +$lang['ALWAYS_NOTIFY'] = 'Всегда сообщать мне об ответах'; +$lang['ALWAYS_NOTIFY_EXPLAIN'] = 'Когда кто-нибудь ответит на тему, в которую вы писали, вам высылается e-mail. Это можно также настроить при размещении сообщения.'; + +$lang['BOARD_STYLE'] = 'Внешний вид форумов'; +$lang['BOARD_LANG'] = 'Язык'; +$lang['NO_THEMES'] = 'В базе нет цветовых схем'; +$lang['TIMEZONE'] = 'Часовой пояс'; +$lang['DATE_FORMAT_PROFILE'] = 'Формат даты'; +$lang['DATE_FORMAT_EXPLAIN'] = 'Синтаксис идентичен функции date() языка PHP'; +$lang['SIGNATURE'] = 'Подпись'; +$lang['SIGNATURE_EXPLAIN'] = 'Это текст, который можно добавлять к размещаемым вами сообщениям. Длина его ограничена %d символами.'; +$lang['PUBLIC_VIEW_EMAIL'] = 'Всегда показывать мой адрес e-mail'; + +$lang['CURRENT_PASSWORD'] = 'Текущий пароль'; +$lang['NEW_PASSWORD'] = 'Новый пароль'; +$lang['CONFIRM_PASSWORD'] = 'Подтвердите пароль'; +$lang['CONFIRM_PASSWORD_EXPLAIN'] = 'Вы должны указать ваш текущий пароль, если хотите изменить его или поменять свой email.'; +$lang['PASSWORD_IF_CHANGED'] = 'Указывайте пароль только если вы хотите его поменять'; +$lang['PASSWORD_CONFIRM_IF_CHANGED'] = 'Подтверждать пароль нужно в том случае, если вы изменили его выше.'; + +$lang['AUTOLOGIN'] = 'Автовход'; +$lang['RESET_AUTOLOGIN'] = 'Удалить ключ автоматического входа на форум'; +$lang['RESET_AUTOLOGIN_EXPL'] = 'включая все места, где вы заходили на форум со включенным автовходом'; + +$lang['AVATAR'] = 'Аватара'; +$lang['AVATAR_EXPLAIN'] = 'Показывает небольшое изображение под информацией о вас в сообщениях. Может быть показано только одно изображение, шириной не более %d пикселов, высотой не более %d пикселов и объёмом не более %d кб.'; +$lang['UPLOAD_AVATAR_FILE'] = 'Загрузить аватару с вашего компьютера'; +$lang['UPLOAD_AVATAR_URL'] = 'Загрузить аватару с URL'; +$lang['UPLOAD_AVATAR_URL_EXPLAIN'] = 'Введите URL по которому находится файл с изображением, он будет скопирован на этот сайт.'; +$lang['PICK_LOCAL_AVATAR'] = 'Выбрать аватару из галереи'; +$lang['LINK_REMOTE_AVATAR'] = 'Показывать аватару с другого сервера'; +$lang['LINK_REMOTE_AVATAR_EXPLAIN'] = 'Введите URL изображения, на которое вы хотите сослаться.'; +$lang['AVATAR_URL'] = 'URL изображения аватары'; +$lang['SELECT_FROM_GALLERY'] = 'Выбрать аватару из галереи'; +$lang['VIEW_AVATAR_GALLERY'] = 'Показать галерею'; + +$lang['SELECT_AVATAR'] = 'Выберите аватару'; +$lang['RETURN_PROFILE'] = 'Вернуться к профилю'; +$lang['SELECT_CATEGORY'] = 'Выберите категорию'; + +$lang['DELETE_IMAGE'] = 'Удалить изображение'; +$lang['CURRENT_IMAGE'] = 'Текущее изображение'; + +$lang['NOTIFY_ON_PRIVMSG'] = 'Уведомлять о новых личных сообщениях'; +$lang['HIDE_USER'] = 'Скрывать ваше пребывание на форуме'; + +$lang['PROFILE_UPDATED'] = 'Ваш профиль был изменён'; +$lang['PROFILE_UPDATED_INACTIVE'] = 'Ваш профиль был изменён, но вы изменили важные данные, так что теперь ваша учётная запись неактивна. Проверьте ваш почтовый ящик, чтобы узнать как вновь активизировать учётную запись или, если требуется одобрение администратора, подождите пока это сделает администратор.'; + +$lang['PASSWORD_MISMATCH'] = 'Введённые пароли не совпадают'; +$lang['CURRENT_PASSWORD_MISMATCH'] = 'Введённый вами пароль не совпадает с паролем из базы'; +$lang['PASSWORD_LONG'] = 'Ваш пароль должен быть не длиннее 32 символов'; +$lang['TOO_MANY_REGISTERS'] = 'Вы сделали слишком много попыток зарегистрироваться. Пожалуйста, повторите попытку позднее.'; +$lang['USERNAME_TAKEN'] = 'Извините, пользователь с таким именем уже существует'; +$lang['USERNAME_INVALID'] = 'Извините, это имя содержит неподходящие символы, (например ")'; +$lang['USERNAME_DISALLOWED'] = 'Извините, это имя было запрещено к использованию'; +$lang['EMAIL_TAKEN'] = 'Извините, этот адрес e-mail уже занят другим пользователем'; +$lang['EMAIL_BANNED'] = 'Извините, адрес %s находится в чёрном списке'; +$lang['EMAIL_INVALID'] = 'Извините, этот адрес e-mail неправилен'; +$lang['SIGNATURE_TOO_LONG'] = 'Слишком длинная подпись'; +$lang['FIELDS_EMPTY'] = 'Вы должны заполнить обязательные поля'; +$lang['AVATAR_FILETYPE'] = 'Файл аватары должен быть .jpg, .gif или .png'; +$lang['AVATAR_FILESIZE'] = 'Объём файла аватары должен быть не более %d кб'; +$lang['AVATAR_IMAGESIZE'] = 'Аватара должна быть не больше %d пикселов в ширину и %d пикселов в высоту'; + +$lang['WELCOME_SUBJECT'] = 'Добро пожаловать на форумы %s'; +$lang['NEW_ACCOUNT_SUBJECT'] = 'Новый пользователь'; +$lang['ACCOUNT_ACTIVATED_SUBJECT'] = 'Учётная запись активизирована'; + +$lang['ACCOUNT_ADDED'] = 'Спасибо за регистрацию, учётная запись была создана. Вы можете войти в систему, используя ваше имя и пароль.'; +$lang['ACCOUNT_INACTIVE'] = 'Учётная запись была создана. На этом форуме требуется активизация учётной записи, ключ для активизации был выслан на введённый вами адрес. Проверьте свою почту для более подробной информации.'; +$lang['ACCOUNT_INACTIVE_ADMIN'] = 'Учётная запись была создана. На этом форуме требуется активизация новой учётной записи администраторами. Им был отправлен e-mail, и, как только они активизируют вашу учётную запись, вы получите уведомление.'; +$lang['ACCOUNT_ACTIVE'] = 'Ваша учётная запись была активизирована. Спасибо за регистрацию.'; +$lang['ACCOUNT_ACTIVE_ADMIN'] = 'Ваша учётная запись была активизирована.'; +$lang['REACTIVATE'] = 'Вновь активизировать учётную запись'; +$lang['ALREADY_ACTIVATED'] = 'Вы уже активизировали свою учётную запись'; + +$lang['REGISTRATION'] = 'Условия регистрации'; + +$lang['WRONG_ACTIVATION'] = 'Введённый вами ключ активизации не совпадает с хранящимся в базе'; +$lang['SEND_PASSWORD'] = 'Прислать новый пароль'; +$lang['PASSWORD_UPDATED'] = 'Новый пароль был создан, проверьте почтовый ящик, чтобы узнать как его активизировать'; +$lang['NO_EMAIL_MATCH'] = 'Введённый вами адрес e-mail не совпадает с записанным на этого пользователя'; +$lang['NEW_PASSWORD_ACTIVATION'] = 'Активизация нового пароля'; +$lang['PASSWORD_ACTIVATED'] = 'Ваша учётная запись была вновь активизирована. Для входа в систему используйте пароль из присланного вам письма.'; + +$lang['SEND_EMAIL_MSG'] = 'Отправить e-mail'; +$lang['NO_USER_SPECIFIED'] = 'Пользователь не был выбран'; +$lang['USER_PREVENT_EMAIL'] = 'Пользователь не желает получать e-mail. Попробуйте отправить ему/ей личное сообщение'; +$lang['USER_NOT_EXIST'] = 'Пользователя не существует'; +$lang['CC_EMAIL'] = 'Отправить копию сообщения самому себе'; +$lang['EMAIL_MESSAGE_DESC'] = 'Сообщение будет отправлено в виде простого текста, не включайте в него HTML или BBCode. В качестве обратного адреса будет показываться ваш адрес e-mail.'; +$lang['FLOOD_EMAIL_LIMIT'] = 'Вы не можете отправить ещё один e-mail сразу после предыдущего, попробуйте сделать это попозже.'; +$lang['RECIPIENT'] = 'Получатель'; +$lang['EMAIL_SENT'] = 'Сообщение было отправлено'; +$lang['SEND_EMAIL'] = 'Отправить e-mail'; +$lang['EMPTY_SUBJECT_EMAIL'] = 'Вы должны указать тему сообщения'; +$lang['EMPTY_MESSAGE_EMAIL'] = 'Вы должны указать текст сообщения для отправки'; + +$lang['USER_AGREEMENT'] = 'Пользовательское Соглашение'; +$lang['USER_AGREEMENT_HEAD'] = 'Для продолжения регистрации Вы должны принять наше ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ'; +$lang['USER_AGREEMENT_AGREE'] = 'Я прочел ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ и обязуюсь его не нарушать'; + +$lang['COPYRIGHT_HOLDERS'] = 'Для правообладателей'; +$lang['ADVERT'] = 'Реклама на сайте'; + +// +// Visual confirmation system strings +// +$lang['CONFIRM_CODE_WRONG'] = 'Вы ввели неверный код подтверждения'; +$lang['TOO_MANY_REGISTERS'] = 'Вы исчерпали предельное количество попыток регистрации для данной сессии. Повторите попытку позднее.'; +$lang['CONFIRM_CODE_IMPAIRED'] = 'Если у вас плохое зрение или вы не можете прочесть этот код по какой-то другой причине, то обратитесь за помощью к %sАдминистратору%s.'; +$lang['CONFIRM_CODE'] = 'Код подтверждения'; +$lang['CONFIRM_CODE_EXPLAIN'] = 'Введите код в точности так, как вы его видите. Код является регистро-зависимым, а символ нуля имеет косую линию внутри цифры.'; + +// +// Memberslist +// +$lang['SORT'] = 'Упорядочить'; +$lang['SORT_TOP_TEN'] = 'десять самых активных участников'; +$lang['SORT_JOINED'] = 'дате регистрации'; +$lang['SORT_USERNAME'] = 'имени пользователя'; +$lang['SORT_LOCATION'] = 'местонахождению'; +$lang['SORT_POSTS'] = 'количеству сообщений'; +$lang['SORT_EMAIL'] = 'адресу e-mail'; +$lang['SORT_WEBSITE'] = 'адресу сайта'; +$lang['ASC'] = 'по возрастанию'; +$lang['DESC'] = 'по убыванию'; +$lang['ORDER'] = ''; // не нужно, в английском используется в контексте 'Order ascending'; + + +// +// Group control panel +// +$lang['GROUP_CONTROL_PANEL'] = 'Группы'; +$lang['MEMBERSHIP_DETAILS'] = 'Информация о членстве в группах'; +$lang['JOIN_A_GROUP'] = 'Вступить в группу'; + +$lang['GROUP_INFORMATION'] = 'Информация о группе'; +$lang['GROUP_NAME'] = 'Название группы'; +$lang['GROUP_DESCRIPTION'] = 'Описание группы'; +$lang['GROUP_MEMBERSHIP'] = 'Членство в группе'; +$lang['GROUP_MEMBERS'] = 'Члены группы'; +$lang['GROUP_MODERATOR'] = 'Модератор группы'; +$lang['PENDING_MEMBERS'] = 'Кандидаты в члены группы'; + +$lang['GROUP_TYPE'] = 'Тип группы'; +$lang['GROUP_OPEN'] = 'Группа с открытым членством'; +$lang['GROUP_CLOSED'] = 'Группа с закрытым членством'; +$lang['GROUP_HIDDEN'] = 'Скрытая группа'; + +$lang["GROUP_MEMBER_MOD"] = 'Являетесь модератором групп'; +$lang["GROUP_MEMBER_MEMBER"] = 'Являетесь членом групп'; +$lang["GROUP_MEMBER_PENDING"] = 'Кандидат в члены групп'; +$lang["GROUP_MEMBER_OPEN"] = 'Группы с открытым членством'; +$lang["GROUP_MEMBER_CLOSED"] = 'Группы с закрытым членством'; +$lang["GROUP_MEMBER_HIDDEN"] = 'Скрытые группы'; + +$lang['NO_GROUPS_EXIST'] = 'Нет ни одной группы'; +$lang['GROUP_NOT_EXIST'] = 'Такой группы не существует'; + +$lang['NO_GROUP_MEMBERS'] = 'В этой группе нет ни одного члена'; +$lang['HIDDEN_GROUP_MEMBERS'] = 'Эта группа скрыта, вы не можете посмотреть её состав'; +$lang['NO_PENDING_GROUP_MEMBERS'] = 'В этой группе нет кандидатов в члены'; +$lang['GROUP_JOINED'] = 'Вы попросили о вступлении в группу. Когда вашу просьбу одобрит модератор группы, вам будет прислано уведомление.'; +$lang['GROUP_REQUEST'] = 'Было подана просьба о вступлении в группу.'; +$lang['GROUP_APPROVED'] = 'Ваша просьба была удовлетворена.'; +$lang['GROUP_ADDED'] = 'Вы были включены в группу'; +$lang['ALREADY_MEMBER_GROUP'] = 'Вы уже являетесь членом этой группы'; +$lang['USER_IS_MEMBER_GROUP'] = 'Пользователь уже является членом этой группы'; +$lang['GROUP_TYPE_UPDATED'] = 'Тип группы успешно изменён'; + +$lang['COULD_NOT_ADD_USER'] = 'Выбранного пользователя не существует'; +$lang['COULD_NOT_ANON_USER'] = 'Вы не можете сделать анонимного пользователя членом группы'; + +$lang['CONFIRM_UNSUB'] = 'Вы уверены, что хотите выйти из этой группы?'; +$lang['CONFIRM_UNSUB_PENDING'] = 'Вы уверены, что хотите отказаться от участия в этой группе? Ваша просьба о вступлении не была ни удовлетворена, ни отклонена!'; + +$lang['UNSUB_SUCCESS'] = 'Вы успешно покинули эту группу.'; + +$lang['APPROVE_SELECTED'] = 'Одобрить выделенное'; +$lang['DENY_SELECTED'] = 'Отклонить выделенное'; +$lang['NOT_LOGGED_IN'] = 'Вы должны войти в систему, прежде чем вступать в группу.'; +$lang['REMOVE_SELECTED'] = 'Удалить выделенное'; +$lang['ADD_MEMBER'] = 'Добавить члена группы'; +$lang['NOT_GROUP_MODERATOR'] = 'Вы не являетесь модератором группы и не можете выполнить данное действие'; + +$lang['LOGIN_TO_JOIN'] = 'Войдите в систему, чтобы менять своё членство в группах'; +$lang['THIS_OPEN_GROUP'] = 'Это группа с открытым членством, вы можете подать просьбу о вступлении'; +$lang['THIS_CLOSED_GROUP'] = 'Это группа с закрытым членством, новые пользователи не принимаются'; +$lang['THIS_HIDDEN_GROUP'] = 'Это скрытая группа, автоматическое добавление пользователей не разрешается'; +$lang['MEMBER_THIS_GROUP'] = 'Вы член этой группы'; +$lang['PENDING_THIS_GROUP'] = 'Вы кандидат в члены этой группы'; +$lang['ARE_GROUP_MODERATOR'] = 'Вы модератор этой группы'; +$lang['NONE'] = 'Нет'; + +$lang['SUBSCRIBE'] = 'Записаться в группу'; +$lang['UNSUBSCRIBE_GROUP'] = 'Выйти из группы'; +$lang['VIEW_INFORMATION'] = 'Просмотреть информацию'; + + +// +// Search +// +$lang['SEARCH_QUERY'] = 'Запрос'; +$lang['SEARCH_OPTIONS'] = 'Параметры запроса'; + +$lang['SEARCH_WORDS'] = 'Ключевые слова'; +$lang['SEARCH_WORDS_EXPL'] = 'Вы можете использовать + (знак "плюс" написанный слитно перед словом: "+слово") чтобы определить слова, которые должны быть в результатах и - (знак "минус") для слов, которых не должно быть. Используйте * в качестве шаблона для частичного совпадения.'; +$lang['SEARCH_AUTHOR'] = 'Поиск по автору'; +$lang['SEARCH_AUTHOR_EXPL'] = 'Используйте * в качестве шаблона'; + +$lang['SEARCH_TITLES_ONLY'] = 'Искать только в названиях тем'; +$lang['SEARCH_ALL_WORDS'] = 'искать все слова'; +$lang['SEARCH_MY_MSG_ONLY'] = 'Искать только в моих сообщениях'; +$lang['IN_MY_POSTS'] = 'В моих сообщениях'; +$lang['SEARCH_MY_TOPICS'] = 'в моих темах'; +$lang['NEW_TOPICS'] = 'Новые темы'; + +$lang['RETURN_FIRST'] = 'Показывать первые'; // followed by xxx characters +$lang['CHARACTERS_POSTS'] = 'символов сообщений'; + +$lang['SEARCH_PREVIOUS'] = 'Время размещения'; // followed by days, weeks, months, year, all + +$lang['SORT_BY'] = 'Упорядочить по'; +$lang['SORT_TIME'] = 'Время размещения'; +$lang['SORT_POST_SUBJECT'] = 'Заголовок сообщения'; +$lang['SORT_TOPIC_TITLE'] = 'Название темы'; +$lang['SORT_AUTHOR'] = 'Автор'; +$lang['SORT_FORUM'] = 'Форум'; + +$lang['DISPLAY_RESULTS_AS'] = 'Показывать результаты как'; +$lang['ALL_AVAILABLE'] = 'Все имеющиеся'; +$lang['BRIEFLY'] = 'Кратко'; +$lang['NO_SEARCHABLE_FORUMS'] = 'У вас нет доступа к поиску ни в одном из форумов на сайте'; + +$lang['NO_SEARCH_MATCH'] = 'Подходящих тем или сообщений не найдено'; +$lang['FOUND_SEARCH_MATCH'] = 'Результатов поиска: %d'; // eg. Search found 1 match +$lang['FOUND_SEARCH_MATCHES'] = 'Результатов поиска: %d'; // eg. Search found 24 matches +$lang['TOO_MANY_SEARCH_RESULTS'] = 'По вашему запросу может быть найдено слишком много сообщений. Постарайтесь более точно сформулировать то, что вы хотите найти.'; + +$lang['CLOSE_WINDOW'] = 'Закрыть окно'; +$lang['CLOSE'] = 'закрыть'; +$lang['HIDE'] = 'спрятать'; +$lang['SEARCH_TERMS'] = 'Поисковый запрос'; + + +// +// Auth related entries +// +// Note the %s will be replaced with one of the following 'user' arrays +$lang['SORRY_AUTH_VIEW'] = 'Извините, только %s могут видеть этот форум'; +$lang['SORRY_AUTH_READ'] = 'Извините, только %s могут читать сообщения в этом форуме'; +$lang['SORRY_AUTH_POST'] = 'Извините, только %s могут начинать темы в этом форуме'; +$lang['SORRY_AUTH_REPLY'] = 'Извините, только %s могут отвечать на сообщения в этом форуме'; +$lang['SORRY_AUTH_EDIT'] = 'Извините, только %s могут редактировать сообщения в этом форуме'; +$lang['SORRY_AUTH_DELETE'] = 'Извините, только %s могут удалять сообщения в этом форуме'; +$lang['SORRY_AUTH_VOTE'] = 'Извините, только %s могут голосовать в опросах этого форума'; +$lang['SORRY_AUTH_STICKY'] = 'Извините, только %s могут прилеплять темы в этом форуме'; +$lang['SORRY_AUTH_ANNOUNCE'] = 'Извините, только %s могут размещать объявления в этом форуме'; + +// These replace the %s in the above strings +$lang['AUTH_ANONYMOUS_USERS'] = 'гости'; +$lang['AUTH_REGISTERED_USERS'] = 'зарегистрированные пользователи'; +$lang['AUTH_USERS_GRANTED_ACCESS'] = 'пользователи со специальными правами доступа'; +//$lang['AUTH_USERS_GRANTED_ACCESS'] = 'пользователи, состоящие в группax'; +$lang['AUTH_MODERATORS'] = 'модераторы'; +$lang['AUTH_ADMINISTRATORS'] = 'администраторы'; + +$lang['NOT_MODERATOR'] = 'Вы не являетесь модератором этого форума'; +$lang['NOT_AUTHORISED'] = 'Нет доступа'; + +$lang['YOU_BEEN_BANNED'] = 'Вам был закрыт доступ к форуму
    Обратитесь к вебмастеру или администратору форумов за дополнительной информацией'; + + +// +// Viewonline +// +$lang['REG_USERS_ZERO_ONLINE'] = 'Сейчас на форуме зарегистрированных пользователей: 0 и '; // There ae 5 Registered and +$lang['REG_USERS_ONLINE'] = 'Сейчас на форуме зарегистрированных пользователей: %d и '; // There ae 5 Registered and +$lang['REG_USER_ONLINE'] = 'Сейчас на форуме зарегистрированных пользователей: %d и '; +$lang['HIDDEN_USERS_ZERO_ONLINE'] = 'скрытых пользователей: 0'; // 6 Hidden users online +$lang['HIDDEN_USERS_ONLINE'] = 'скрытых пользователей: %d'; +$lang['HIDDEN_USER_ONLINE'] = 'скрытых пользователей: %d'; // 6 Hidden users online +$lang['GUEST_USERS_ONLINE'] = 'Сейчас на форуме гостей: %d'; +$lang['GUEST_USERS_ZERO_ONLINE'] = 'Сейчас на форуме гостей: 0'; // There are 10 Guest users online +$lang['GUEST_USER_ONLINE'] = 'Сейчас на форуме гостей: %d'; +$lang['NO_USERS_BROWSING'] = 'Этот форум сейчас никто не просматривает'; + +$lang['ONLINE_EXPLAIN'] = 'данные за последние пять минут'; +$lang['LAST_UPDATED'] = 'Последнее изменение'; + +// +// Moderator Control Panel +// +$lang['MOD_CP'] = 'Панель модерации'; +$lang['MOD_CP_EXPLAIN'] = 'Здесь вы можете проводить массовую модерацию этого форума. Вы можете закрывать, открывать, перемещать или удалять любое количество тем.'; + +$lang['SELECT'] = 'Выбрать'; +$lang['DELETE'] = 'Удалить'; +$lang['MOVE'] = 'Переместить'; +$lang['LOCK'] = 'Закрыть'; +$lang['UNLOCK'] = 'Открыть'; + +$lang['TOPICS_REMOVED'] = 'Выбранные темы были успешно удалены из базы данных'; +$lang['TOPICS_LOCKED'] = 'Выбранные темы были закрыты'; +$lang['TOPICS_MOVED'] = 'Выбранные темы были перемещены'; +$lang['TOPICS_UNLOCKED'] = 'Выбранные темы были открыты'; +$lang['NO_TOPICS_MOVED'] = 'Не было перенесено ни одной темы'; + +$lang['CONFIRM_DELETE_TOPIC'] = 'Вы действительно хотите удалить выбранные темы?'; +$lang['CONFIRM_LOCK_TOPIC'] = 'Вы действительно хотите закрыть выбранные темы?'; +$lang['CONFIRM_UNLOCK_TOPIC'] = 'Вы действительно хотите открыть выбранные темы?'; +$lang['CONFIRM_MOVE_TOPIC'] = 'Вы действительно хотите переместить выбранные темы?'; + +$lang['MOVE_TO_FORUM'] = 'Переместить в форум'; +$lang['LEAVE_SHADOW_TOPIC'] = 'Оставить ссылку в старом форуме'; + +$lang['SPLIT_TOPIC'] = 'Разделение темы'; +$lang['SPLIT_TOPIC_EXPLAIN'] = 'С использованием этой формы вы можете разделить тему на две либо выбирая сообщения по одному, либо разбив по выбранному сообщению'; +$lang['NEW_TOPIC_TITLE'] = 'Заголовок новой темы'; +$lang['FORUM_FOR_NEW_TOPIC'] = 'Форум для новой темы'; +$lang['SPLIT_POSTS'] = 'Отделить выбранные сообщения'; +$lang['SPLIT_AFTER'] = 'Отделить все сообщения после выбранного'; +$lang['TOPIC_SPLIT'] = 'Выбранная тема была успешно отделена'; + +$lang['TOO_MANY_ERROR'] = 'Вы выбрали слишком много сообщений. Вы можете выбрать только одно сообщение, чтобы отделить все сообщения после него.'; + +$lang['NONE_SELECTED'] = 'Вы ничего не выбрали для совершения этой операции. Вернитесь назад и выберите.'; +$lang['NEW_FORUM'] = 'Новый форум'; + +$lang['THIS_POSTS_IP'] = 'IP адрес для этого сообщения'; +$lang['OTHER_IP_THIS_USER'] = 'Другие IP адреса с которых писал этот пользователь'; +$lang['USERS_THIS_IP'] = 'Пользователи, писавшие с этого IP'; +$lang['IP_INFO'] = 'Информация об IP адресе'; +$lang['LOOKUP_IP'] = 'Посмотреть хост для IP'; + + +// +// Timezones ... for display on each page +// +$lang['ALL_TIMES'] = 'Часовой пояс: %s'; // This is followed by GMT and the timezone offset + +$lang['-12'] = 'GMT - 12'; +$lang['-11'] = 'GMT - 11'; +$lang['-10'] = 'GMT - 10'; +$lang['-9'] = 'GMT - 9'; +$lang['-8'] = 'GMT - 8'; +$lang['-7'] = 'GMT - 7'; +$lang['-6'] = 'GMT - 6'; +$lang['-5'] = 'GMT - 5'; +$lang['-4'] = 'GMT - 4'; +$lang['-3.5'] = 'GMT - 3:30'; +$lang['-3'] = 'GMT - 3'; +$lang['-2'] = 'GMT - 2'; +$lang['-1'] = 'GMT - 1'; +$lang['0'] = 'GMT'; +$lang['1'] = 'GMT + 1'; +$lang['2'] = 'GMT + 2'; +$lang['3'] = 'GMT + 3'; +$lang['3.5'] = 'GMT + 3:30'; +$lang['4'] = 'GMT + 4'; +$lang['4.5'] = 'GMT + 4:30'; +$lang['5'] = 'GMT + 5'; +$lang['5.5'] = 'GMT + 5:30'; +$lang['6'] = 'GMT + 6'; +$lang['6.5'] = 'GMT + 6:30'; +$lang['7'] = 'GMT + 7'; +$lang['8'] = 'GMT + 8'; +$lang['9'] = 'GMT + 9'; +$lang['9.5'] = 'GMT + 9:30'; +$lang['10'] = 'GMT + 10'; +$lang['11'] = 'GMT + 11'; +$lang['12'] = 'GMT + 12'; +$lang['13'] = 'GMT + 13'; + +// это для выпадающего меню, раньше тут ещё были города +$lang['TZ']['-12'] = 'GMT - 12'; +$lang['TZ']['-11'] = 'GMT - 11'; +$lang['TZ']['-10'] = 'GMT - 10'; +$lang['TZ']['-9'] = 'GMT - 9'; +$lang['TZ']['-8'] = 'GMT - 8'; +$lang['TZ']['-7'] = 'GMT - 7'; +$lang['TZ']['-6'] = 'GMT - 6'; +$lang['TZ']['-5'] = 'GMT - 5'; +$lang['TZ']['-4'] = 'GMT - 4'; +$lang['TZ']['-3.5'] = 'GMT - 3:30'; +$lang['TZ']['-3'] = 'GMT - 3'; +$lang['TZ']['-2'] = 'GMT - 2'; +$lang['TZ']['-1'] = 'GMT - 1'; +$lang['TZ']['0'] = 'GMT (время по Гринвичу)'; +$lang['TZ']['1'] = 'GMT + 1'; +$lang['TZ']['2'] = 'GMT + 2'; +$lang['TZ']['3'] = 'GMT + 3'; +$lang['TZ']['3.5'] = 'GMT + 3:30'; +$lang['TZ']['4'] = 'GMT + 4 (московское время)'; +$lang['TZ']['4.5'] = 'GMT + 4:30'; +$lang['TZ']['5'] = 'GMT + 5'; +$lang['TZ']['5.5'] = 'GMT + 5:30'; +$lang['TZ']['6'] = 'GMT + 6'; +$lang['TZ']['6.5'] = 'GMT + 6:30'; +$lang['TZ']['7'] = 'GMT + 7'; +$lang['TZ']['8'] = 'GMT + 8'; +$lang['TZ']['9'] = 'GMT + 9'; +$lang['TZ']['9.5'] = 'GMT + 9:30'; +$lang['TZ']['10'] = 'GMT + 10'; +$lang['TZ']['11'] = 'GMT + 11'; +$lang['TZ']['12'] = 'GMT + 12'; +$lang['TZ']['13'] = 'GMT + 13'; + +$lang['DATETIME']['SUNDAY'] = 'Воскресенье'; +$lang['DATETIME']['MONDAY'] = 'Понедельник'; +$lang['DATETIME']['TUESDAY'] = 'Вторник'; +$lang['DATETIME']['WEDNESDAY'] = 'Среда'; +$lang['DATETIME']['THURSDAY'] = 'Четверг'; +$lang['DATETIME']['FRIDAY'] = 'Пятница'; +$lang['DATETIME']['SATURDAY'] = 'Суббота'; +$lang['DATETIME']['SUN'] = 'Вс'; +$lang['DATETIME']['MON'] = 'Пн'; +$lang['DATETIME']['TUE'] = 'Вт'; +$lang['DATETIME']['WED'] = 'Ср'; +$lang['DATETIME']['THU'] = 'Чт'; +$lang['DATETIME']['FRI'] = 'Пт'; +$lang['DATETIME']['SAT'] = 'Сб'; +$lang['DATETIME']['JANUARY'] = 'Январь'; +$lang['DATETIME']['FEBRUARY'] = 'Февраль'; +$lang['DATETIME']['MARCH'] = 'Март'; +$lang['DATETIME']['APRIL'] = 'Апрель'; +$lang['DATETIME']['MAY'] = 'Май'; +$lang['DATETIME']['JUNE'] = 'Июнь'; +$lang['DATETIME']['JULY'] = 'Июль'; +$lang['DATETIME']['AUGUST'] = 'Август'; +$lang['DATETIME']['SEPTEMBER'] = 'Сентябрь'; +$lang['DATETIME']['OCTOBER'] = 'Октябрь'; +$lang['DATETIME']['NOVEMBER'] = 'Ноябрь'; +$lang['DATETIME']['DECEMBER'] = 'Декабрь'; +$lang['DATETIME']['JAN'] = 'Янв'; +$lang['DATETIME']['FEB'] = 'Фев'; +$lang['DATETIME']['MAR'] = 'Мар'; +$lang['DATETIME']['APR'] = 'Апр'; +$lang['DATETIME']['JUN'] = 'Июн'; +$lang['DATETIME']['JUL'] = 'Июл'; +$lang['DATETIME']['AUG'] = 'Авг'; +$lang['DATETIME']['SEP'] = 'Сен'; +$lang['DATETIME']['OCT'] = 'Окт'; +$lang['DATETIME']['NOV'] = 'Ноя'; +$lang['DATETIME']['DEC'] = 'Дек'; + +// +// Errors (not related to a +// specific failure on a page) +// +$lang['INFORMATION'] = 'Информация'; +$lang['CRITICAL_INFORMATION'] = 'Критическая информация'; + +$lang['GENERAL_ERROR'] = 'Ошибка'; +$lang['CRITICAL_ERROR'] = 'Критическая ошибка'; +$lang['AN_ERROR_OCCURED'] = 'Произошла ошибка'; +$lang['A_CRITICAL_ERROR'] = 'Произошла критическая ошибка'; + +$lang['ADMIN_REAUTHENTICATE'] = 'Чтобы получить доступ к админ/мод панели, Вам необходимо еще раз ввести пароль.'; +$lang['LOGIN_ATTEMPTS_EXCEEDED'] = 'The maximum number of %s login attempts has been exceeded. You are not allowed to login for the next %s minutes.'; + +// +// Attachment Mod Main Language Variables +// + +// Auth Related Entries +$lang['RULES_ATTACH_CAN'] = 'Вы можете прикреплять файлы к сообщениям'; +$lang['RULES_ATTACH_CANNOT'] = 'Вы не можете прикреплять файлы к сообщениям'; +$lang['RULES_DOWNLOAD_CAN'] = 'Вы можете скачивать файлы'; +$lang['RULES_DOWNLOAD_CANNOT'] = 'Вы не можете скачивать файлы'; +$lang['SORRY_AUTH_VIEW_ATTACH'] = 'Вы не можете просматривать или скачивать файлы'; + +// Viewtopic -> Display of Attachments +$lang['DESCRIPTION'] = 'Описание'; // used in Administration Panel too... +$lang['DOWNLOAD'] = 'Скачать'; // this Language Variable is defined in lang_admin.php too, but we are unable to access it from the main Language File +$lang['FILESIZE'] = 'Размер'; +$lang['VIEWED'] = 'Просмотров'; +$lang['DOWNLOAD_NUMBER'] = '%d раз'; // replace %d with count +$lang['EXTENSION_DISABLED_AFTER_POSTING'] = 'The Extension \'%s\' was deactivated by an board admin, therefore this Attachment is not displayed.'; // used in Posts and PM's, replace %s with mime type + +// Posting/PM -> Posting Attachments +$lang['ADD_ATTACHMENT'] = 'Прикрепить файл'; +$lang['ADD_ATTACHMENT_TITLE'] = 'Прикрепить файл'; +$lang['ADD_ATTACHMENT_EXPLAIN'] = 'Если вы не хотите прикреплять файл, оставьте это поле пустым'; +$lang['FILE_NAME'] = 'Имя файла'; +$lang['FILE_COMMENT'] = 'Комментарий'; + +// Posting/PM -> Posted Attachments +$lang['POSTED_ATTACHMENTS'] = 'Прикрепленные файлы'; +$lang['UPDATE_COMMENT'] = 'Обновить комментарий'; +$lang['DELETE_ATTACHMENTS'] = 'Удалить файлы'; +$lang['DELETE_ATTACHMENT'] = 'Удалить файл'; +$lang['DELETE_THUMBNAIL'] = 'Удалить пиктограмму'; +$lang['UPLOAD_NEW_VERSION'] = 'Загрузить новую версию'; + +// Errors -> Posting Attachments +$lang['INVALID_FILENAME'] = '%s - неправильное имя файла'; // replace %s with given filename +$lang['ATTACHMENT_PHP_SIZE_NA'] = 'Вложение слишком велико.
    Невозможно превышать ограничение установленное в PHP.
    Attachment Mod не может определить максимальный размер закачиваемых файлов, определенный в php.ini.'; +$lang['ATTACHMENT_PHP_SIZE_OVERRUN'] = 'Вложение слишком велико.
    Максимальный размер закачиваемого файла: %d MB.
    Отметьте, что эта величина определена в php.ini и Attachment Mod не может изменить это значение в большую сторону.'; // replace %d with ini_get('upload_max_filesize') +$lang['DISALLOWED_EXTENSION'] = 'Расширение %s запрещено администратором'; // replace %s with extension (e.g. .php) +$lang['DISALLOWED_EXTENSION_WITHIN_FORUM'] = 'Вы не можете публиковать файлы с расширением %s в этом форуме'; // replace %s with the Extension +$lang['ATTACHMENT_TOO_BIG'] = 'Вложение слишком велико.
    Максимальный размер: %d %s'; // replace %d with maximum file size, %s with size var +$lang['ATTACH_QUOTA_REACHED'] = 'Достигнут максимальный общий размер ваших вложений. Пожалуйста, обратитесь к администратору по интересующим вас вопросам.'; +$lang['TOO_MANY_ATTACHMENTS'] = 'Вложение невозможно, так как максимальное количество (%d) вложений в этом сообщении достигнуто.'; // replace %d with maximum number of attachments +$lang['ERROR_IMAGESIZE'] = 'Изображение должно быть меньше, чем %d пикселей в ширину и %d пикселей в высоту.'; +$lang['GENERAL_UPLOAD_ERROR'] = 'Ошибка закачки: Невозможно закачать вложение в %s.'; // replace %s with local path + +$lang['ERROR_EMPTY_ADD_ATTACHBOX'] = 'Вы должны указать "Имя Файла" в форме "Прикрепить файл"'; +$lang['ERROR_MISSING_OLD_ENTRY'] = 'Невозможно обновить вложение, старое вложение не обнаружено'; + +// Errors -> PM Related +$lang['ATTACH_QUOTA_SENDER_PM_REACHED'] = 'К сожалению, вы достигли максимального общего объема закачанных файлов в папке личных сообщений. Пожалуйста, удалите часть принятых/отправленных вложений.'; +$lang['ATTACH_QUOTA_RECEIVER_PM_REACHED'] = 'К сожалению, \'%s\' достиг(ла) максимального общего объема закачанных файлов в папке личных сообщений. Пожалуйста, сообщите ему(ей) или подождите удаления некоторых из вложений.'; + +// Errors -> Download +$lang['NO_ATTACHMENT_SELECTED'] = 'Вы не выделили вложений для скачивания или просмотра.'; +$lang['ERROR_NO_ATTACHMENT'] = 'Выделенных вложений больше не существует.'; + +// Delete Attachments +$lang['CONFIRM_DELETE_ATTACHMENTS'] = 'Вы уверены, что хотите удалить выделенные вложения?'; +$lang['DELETED_ATTACHMENTS'] = 'Выделенные вложения удалены.'; +$lang['ERROR_DELETED_ATTACHMENTS'] = 'Невозможно удалить вложения.'; +$lang['CONFIRM_DELETE_PM_ATTACHMENTS'] = 'Вы уверены, что хотите удалить все вложения в этом ЛС?'; + +// General Error Messages +$lang['ATTACHMENT_FEATURE_DISABLED'] = 'Функция вложений выключена.'; + +$lang['DIRECTORY_DOES_NOT_EXIST'] = 'Директория \'%s\' не существует или не может быть найдена.'; // replace %s with directory +$lang['DIRECTORY_IS_NOT_A_DIR'] = 'Пожалуйста, проверьте является ли \'%s\' директорией.'; // replace %s with directory +$lang['DIRECTORY_NOT_WRITEABLE'] = 'Директория \'%s\' недоступна для записи. Вам нужно создать директорию для закачек и выполнить chmod 777 (или изменить владельца httpd-servers) для закачки фалов на сервер.
    Если у вас только FTP доступ к серверу измените \'Атрибуты\' директории на rwxrwxrwx.'; // replace %s with directory + +$lang['FTP_ERROR_CONNECT'] = 'Невозможно соединиться с FTP сервером: \'%s\'. Пожалуйста, проверьте ваши настройки FTP.'; +$lang['FTP_ERROR_LOGIN'] = 'Невозможно зайти на FTP сервер. Имя пользователя \'%s\' иои пароль неверны. Пожалуйста, проверьте ваши настройки FTP.'; +$lang['FTP_ERROR_PATH'] = 'Нет доступа к директории: \'%s\'. Пожалуйста, проверьте ваши настройки FTP.'; +$lang['FTP_ERROR_UPLOAD'] = 'Невозможно записать файлы в директорию: \'%s\'. Пожалуйста, проверьте ваши настройки FTP.'; +$lang['FTP_ERROR_DELETE'] = 'Невозможно удалить файлы в директории: \'%s\'. Пожалуйста, проверьте ваши настройки FTP.
    Другой причиной этой ошибки может быть отсутствие файла, проверьте сначала скрытые вложения.'; +$lang['FTP_ERROR_PASV_MODE'] = 'Невозможно включить/отключить пассивный режим'; + +// Attach Rules Window +$lang['RULES_PAGE'] = 'Правила вложений'; +$lang['ATTACH_RULES_TITLE'] = 'Разрешенные группы расширений и их размер'; +$lang['GROUP_RULE_HEADER'] = '%s -> Максимальный общий размер: %s'; // Replace first %s with Extension Group, second one with the Size STRING +$lang['ALLOWED_EXTENSIONS_AND_SIZES'] = 'Разрешенные расширения и их размер'; +$lang['NOTE_USER_EMPTY_GROUP_PERMISSIONS'] = 'ВНИМАНИЕ:
    Вы можете отправлять вложения в этот форум,
    но так как ни одной группе расширений не разрешено быть вложенной здесь,
    вы не можете ничего отправить. Если вы попытаетесь,
    то получите сообщение об ошибке.
    '; + +// Quota Variables +$lang['UPLOAD_QUOTA'] = 'Квота'; +$lang['PM_QUOTA'] = 'Квота ЛС'; +$lang['USER_UPLOAD_QUOTA_REACHED'] = 'К сожалению, вы достигли максимального общего объема закачанных файлов - %d %s'; // replace %d with Size, %s with Size Lang (MB for example) + +// User Attachment Control Panel +$lang['USER_ACP_TITLE'] = 'Управление вложениями';//'Панель управления вложениями пользователя'; +$lang['UACP'] = 'Управление вложениями'; +$lang['USER_UPLOADED_PROFILE'] = 'Закачано: %s'; +$lang['USER_QUOTA_PROFILE'] = 'Квота: %s'; +$lang['UPLOAD_PERCENT_PROFILE'] = '%d%% от общего'; + +// Common Variables +$lang['BYTES'] = 'Байт'; +$lang['KB'] = 'KB'; +$lang['MB'] = 'MB'; +$lang['ATTACH_SEARCH_QUERY'] = 'Поиск вложений'; +$lang['TEST_SETTINGS'] = 'Проверить настройки'; +$lang['NOT_ASSIGNED'] = 'Не назначено'; +$lang['NO_FILE_COMMENT_AVAILABLE'] = 'Комментарий недоступен'; +$lang['ATTACHBOX_LIMIT'] = 'Ваш ящик вложений заполнен на %d%%'; +$lang['NO_QUOTA_LIMIT'] = 'Квота отсутствует'; +$lang['UNLIMITED'] = 'Без ограничений'; + +//bt +$lang['BT_REG_YES'] = 'Зарегистрирован'; +$lang['BT_REG_NO'] = 'Не зарегистрирован'; +$lang['BT_ADDED'] = 'Добавлен'; +$lang['BT_REG_ON_TRACKER'] = 'Зарегистрировать торрент'; +$lang['BT_REG_FAIL'] = 'Не удалось зарегистрировать торрент на трекере'; +$lang['BT_REG_FAIL_SAME_HASH'] = 'Другой торрент с таким же info_hash уже зарегистрирован'; +$lang['BT_UNREG_FROM_TRACKER'] = 'Разрегистрировать торрент'; +$lang['BT_UNREGISTERED'] = 'Торрент разрегистрирован'; +$lang['BT_REGISTERED'] = 'Торент зарегистрирован на трекере

    Теперь вам нужно его скачать и поставить на закачку у самого себя в ту же директорию, где лежат оригинальные файлы'; +$lang['INVALID_ANN_URL'] = 'Неправильный Аnnounce URL [%s]

    должен быть %s'; +$lang['PASSKEY_ERR_TOR_NOT_REG'] = 'Невозможно добавить passkey

    Торрент не зарегистрирован на трекере'; +$lang['PASSKEY_ERR_EMPTY'] = 'Невозможно добавить passkey

    Вам необходимо зайти в ваш форумный профиль и сгенерировать passkey'; +$lang['BT_GEN_PASSKEY'] = 'Passkey'; +$lang['BT_GEN_PASSKEY_URL'] = 'Создать или изменить Passkey'; +$lang['BT_GEN_PASSKEY_EXPLAIN'] = 'Сгенерировать ваш личный id, который будет добавляться в торрент-файлы во время скачивания и затем использоваться трекером в качестве вашего аутентификатора.'; +$lang['BT_GEN_PASSKEY_EXPLAIN_2'] = 'Внимание! После изменения или создания нового id вам будет необходимо заново скачать все активные торренты!'; +$lang['BT_GEN_PASSKEY_OK'] = 'Новый персональный идентификатор сгенеририван'; +$lang['BT_NO_SEARCHABLE_FORUMS'] = 'Доступных для поиска форумов не найдено'; + +$lang['SEEDERS'] = 'Сидов'; +$lang['LEECHERS'] = 'Личеров'; +$lang['RELEASING'] = 'Свои'; +$lang['SEEDING'] = 'Раздает'; +$lang['LEECHING'] = 'Качает'; +$lang['IS_REGISTERED'] = 'Зарегистрирован'; +$lang['MAGNET'] = 'Magnet'; + +//torrent status mod +$lang['TOR_STATUS'] = 'Статус'; +$lang['TOR_STATUS_SELECT_ACTION'] = 'Выберите статус'; +$lang['TOR_STATUS_CHECKED'] = 'проверено'; // 2 +$lang['TOR_STATUS_NOT_CHECKED'] = 'не проверено';//0 +$lang['TOR_STATUS_CLOSED'] = 'закрыто';//1 +$lang['TOR_STATUS_D'] = 'повтор';//3 +$lang['TOR_STATUS_NOT_PERFECT'] = 'неоформлено';//4 +$lang['TOR_STATUS_PART_PERFECT'] = 'недооформлено';//5 +$lang['TOR_STATUS_FISHILY'] = 'сомнительно';//6 +$lang['TOR_STATUS_COPY'] = 'закрыто правообладателем';//7 +//end torrent status mod + +$lang['BT_TOPIC_TITLE'] = 'Название темы'; +$lang['BT_SEEDER_LAST_SEEN'] = 'Последний seeder'; +$lang['BT_SORT_FORUM'] = 'Форум'; +$lang['SIZE'] = 'Размер'; +$lang['PIECE_LENGTH'] = 'Размер блока'; +$lang['COMPLETED'] = 'Скачан'; +$lang['ADDED'] = 'Добавлен'; +$lang['DELETE_TORRENT'] = 'Удалить торрент'; +$lang['DEL_MOVE_TORRENT'] = 'Удалить и перенести топик'; +$lang['DL_TORRENT'] = 'Скачать .torrent'; +$lang['BT_LAST_POST'] = 'Посл. сообщение'; +$lang['BT_CREATED'] = 'Время создания топика'; +$lang['BT_REPLIES'] = 'Сообщения'; +$lang['BT_VIEWS'] = 'Просмотры'; + +// Gold/Silver releases +$lang['GOLD'] = 'Золото'; +$lang['SILVER'] = 'Серебро'; +$lang['SET_GOLD_TORRENT'] = 'Сделать золотым'; +$lang['UNSET_GOLD_TORRENT'] = 'Снять золото'; +$lang['SET_SILVER_TORRENT'] = 'Сделать серебряным'; +$lang['UNSET_SILVER_TORRENT'] = 'Снять серебро'; +$lang['GOLD_STATUS'] = 'ЗОЛОТАЯ РАЗДАЧА! СКАЧАННОЕ НЕ ЗАСЧИТЫВАЕТСЯ!'; +$lang['SILVER_STATUS'] = 'СЕРЕБРЯНАЯ РАЗДАЧА! СКАЧАННОЕ ЗАСЧИТЫВАЕТСЯ ТОЛЬКО НАПОЛОВИНУ!'; +// End - Gold/Silver releases + +$lang['SEARCH_IN_FORUMS'] = 'Искать в форумах'; +$lang['SELECT_CAT'] = 'Выбрать категорию...'; +$lang['GO_TO_SECTION'] = 'перейти к разделу'; +$lang['TORRENTS_FROM'] = 'Торенты за'; +$lang['SHOW_ONLY'] = 'Показывать только'; +$lang['SHOW_COLUMN'] = 'Показывать колонку'; + +$lang['BT_ONLY_ACTIVE'] = 'Активные (есть seeder или leecher)'; +$lang['BT_ONLY_MY'] = 'Мои раздачи'; +$lang['BT_SEED_EXIST'] = 'Есть seeder (полный источник)'; +$lang['BT_ONLY_NEW'] = 'Новые с последнего посещения'; +$lang['BT_SHOW_CAT'] = 'Категория'; +$lang['BT_SHOW_FORUM'] = 'Форум'; +$lang['BT_SHOW_AUTHOR'] = 'Автор'; +$lang['BT_SHOW_SPEED'] = 'Скорость'; +$lang['SEED_NOT_SEEN'] = 'Источника не было'; +$lang['TITLE_MATCH'] = 'Название содержит'; +$lang['BT_USER_NOT_FOUND'] = 'не найден'; +$lang['DL_SPEED'] = 'Общая скорость скачивания'; + +$lang['BT_DISREGARD'] = 'не учитывать'; +$lang['BT_NEVER'] = 'никогда'; +$lang['BT_ALL_DAYS_FOR'] = 'за все время'; +$lang['BT_1_DAY_FOR'] = 'за сегодня'; +$lang['BT_3_DAY_FOR'] = 'последние 3 дня'; +$lang['BT_7_DAYS_FOR'] = 'посл. неделю'; +$lang['BT_2_WEEKS_FOR'] = 'посл. 2 недели'; +$lang['BT_1_MONTH_FOR'] = 'последний месяц'; +$lang['BT_1_DAY'] = 'день'; +$lang['BT_3_DAYS'] = '3 дня'; +$lang['BT_7_DAYS'] = 'неделю'; +$lang['BT_2_WEEKS'] = '2 недели'; +$lang['BT_1_MONTH'] = 'месяц'; + +$lang['DL_LIST_AND_TORRENT_ACTIVITY'] = 'Статистика раздачи'; +$lang['DL_WILL'] = 'Буду качать'; +$lang['DL_DOWN'] = 'Качаю'; +$lang['DL_COMPLETE'] = 'Скачал'; +$lang['DL_CANCEL'] = 'Отмена'; + +$lang['DLWILL_2'] = 'Будут качать'; +$lang['DLDOWN_2'] = 'Качают'; +$lang['DLCOMPLETE_2'] = 'Скачали'; +$lang['DLCANCEL_2'] = 'Отмена'; + +$lang['DL_LIST_DEL'] = 'Очистить DL-List'; +$lang['DL_LIST_DEL_CONFIRM'] = 'Вы уверены, что хотите удалить DL-List для этого топика?'; +$lang['SHOW_DL_LIST'] = 'Список скачавших'; +$lang['SET_DL_STATUS'] = 'Download'; +$lang['UNSET_DL_STATUS'] = 'Not Download'; +$lang['TOPICS_DOWN_SETS'] = 'Выбранные темы изменили статус на: Download'; +$lang['TOPICS_DOWN_UNSETS'] = 'Выбранные темы перестали быть Download'; + +$lang['TOPIC_DL'] = 'DL'; + +$lang['MY_DOWNLOADS'] = 'Мои закачки'; +$lang['SEARCH_DL_WILL'] = 'Будущие'; +$lang['SEARCH_DL_WILL_DOWNLOADS'] = 'Будущие закачки'; +$lang['SEARCH_DL_DOWN'] = 'Текущие'; +$lang['SEARCH_DL_COMPLETE'] = 'Прошлые'; +$lang['SEARCH_DL_COMPLETE_DOWNLOADS'] = 'Прошлые закачки'; +$lang['SEARCH_DL_CANCEL'] = 'Отмененные'; +$lang['CUR_DOWNLOADS'] = 'Текущие закачки'; +$lang['CUR_UPLOADS'] = 'Текущие раздачи'; +$lang['SEARCH_USER_RELEASES'] = 'Найти все текущие раздачи'; +$lang['TOR_SEARCH_TITLE'] = 'Опции показа торрентов'; +$lang['OPEN_TOPIC'] = 'Открыть топик'; + +$lang['ALLOWED_ONLY_1ST_POST_ATTACH'] = 'Вы можете прикреплять торрент-файлы только к первому сообщению в теме'; +$lang['ALLOWED_ONLY_1ST_POST_REG'] = 'Вы можете регистрировать торрент-файлы на трекере только из первого сообщения в теме'; +$lang['REG_NOT_ALLOWED_IN_THIS_FORUM'] = 'В этом форуме регистрация торрентов на трекере запрещена'; +$lang['ALREADY_REG'] = 'Торрент уже зарегистрирован'; +$lang['NOT_TORRENT'] = 'Это не торрент-файл'; +$lang['ONLY_1_TOR_PER_POST'] = 'Вы не можете зарегистрировать еще один торрент для этого сообщения'; +$lang['ONLY_1_TOR_PER_TOPIC'] = 'Вы не можете зарегистрировать еще один торрент для этого топика'; +$lang['VIEWING_USER_BT_PROFILE'] = 'Torrent-профиль пользователя %s'; // %s is username +$lang['CUR_ACTIVE_DLS'] = 'Текущие активные torrent\'ы'; +$lang['VIEW_TORRENT_PROFILE'] = 'Torrent-профиль'; + +$lang['PROFILE_UP_TOTAL'] = 'Всего отдано'; +$lang['PROFILE_DOWN_TOTAL'] = 'Всего скачано'; +$lang['PROFILE_BONUS'] = 'Бонус'; +$lang['PROFILE_RELEASED'] = 'Отдано на своих раздачах'; +$lang['PROFILE_RATIO'] = 'Рейтинг'; +$lang['PROFILE_MAX_SPEED'] = 'Скорость'; +$lang['PROFILE_IT_WILL_BE_DOWNLOADED'] = 'начнет учитываться после того как будет скачано'; + +$lang['SPMODE_FULL'] = 'Подробная статистика пиров'; +$lang['CURR_PASSKEY'] = 'Текущий passkey:'; + +$lang['BT_RATIO'] = 'Рейтинг'; +$lang['YOUR_RATIO'] = 'Ваш рейтинг'; +$lang['DOWNLOADED'] = 'Скачано'; +$lang['UPLOADED'] = 'Отдано'; +$lang['RELEASED'] = 'на своих'; +$lang['BT_BONUS_UP'] = 'бонус'; + +$lang['TRACKER'] = 'Трекер'; +$lang['GALLERY'] = 'Галерея'; +$lang['OPEN_TOPICS'] = 'Открывать топики'; +$lang['OPEN_IN_SAME_WINDOW'] = 'открывать в этом же окне'; + +$lang['BT_LOW_RATIO_FUNC'] = 'У Вас слишком низкий рейтинг для того, чтобы воспользоваться этой функцией'; +$lang['BT_LOW_RATIO_FOR_DL'] = 'Рейтинг %s уже не позволяет Вам скачивать новые торренты.

    Для поднятия рейтинга, Вы можете что-либо раздать из Ваших прошлых закачек, либо организовать новую раздачу.

    Пожалуйста, помните о том, что Ваше yчастие в системе BitTorrent не может ограничиваться только скачиванием!'; +$lang['BT_RATIO_WARNING_MSG'] = 'Если ваш рейтинг упадёт ниже %s, Вы не сможете скачивать торренты ! Подробнее о рейтинге.'; + +$lang['SEEDER_LAST_SEEN'] = 'Полного источника не было: %s'; + +// +// MAIL.RU Keyboard +// +$lang['KB_TITLE'] = 'Русская клавиатура'; +$lang['KB_RUS_KEYLAYOUT'] = 'Раскладка: '; +$lang['KB_NONE'] = 'Отсутствует'; +$lang['KB_TRANSLIT'] = 'Транслит'; +$lang['KB_TRADITIONAL'] = 'Традиционная'; +$lang['KB_RULES'] = 'Правила набора'; +$lang['KB_SHOW'] = 'Показать клавиатуру'; +$lang['KB_ABOUT'] = 'О клавиатуре'; +$lang['KB_CLOSE'] = 'Закрыть'; +$lang['KB_TRANSLIT_MOZILLA'] = 'Выберите текст, который вы хотите для перевода в транслит, и нажмите кнопку \'Транслит\'.'; +$lang['KB_TRANSLIT_OPERA7'] = 'Нажмите здесь для перевода вашего сообщения в транслит.'; + +$lang['NEED_TO_LOGIN_FIRST'] = 'Вы должны авторизоваться на форуме'; +$lang['ONLY_FOR_MOD'] = 'Эта опция доступна только модераторам'; +$lang['ONLY_FOR_ADMIN'] = 'Эта опция доступна только администраторам'; +$lang['ONLY_FOR_SUPER_ADMIN'] = 'Эта опция доступна только супер администраторам'; + +$lang['ACCESS'] = 'Доступ'; +$lang['ACCESS_SRV_LOAD'] = 'Зависит от загрузки сервера'; +$lang['LOGS'] = 'История темы'; + +$lang['LAST_IP'] = 'Последний IP:'; +$lang['REG_IP'] = 'IP регистрации:'; +$lang['ALREADY_REG'] = 'С вашего IP-адреса уже зарегистрирован пользователь %s. Если Вы ранее не регистрировались на нашем трекере, обратитесь к Администрации'; + +// +// That's all, Folks! +// ------------------------------------------------- + +// from lang_admin +$lang['NOT_ADMIN'] = 'У вас нет прав на администрирование'; + +$lang['COOKIES_REQUIRED'] = 'Куки должны быть включены!'; +$lang['SESSION_EXPIRED'] = 'Сессия устарела'; + +// FLAGHACK-start +$lang['COUNTRY_FLAG'] = 'Флаг страны'; +$lang['SELECT_COUNTRY'] = 'ВЫБЕРИТЕ СТРАНУ' ; +// FLAGHACK-end + +// Sort memberlist per letter +$lang['SORT_PER_LETTER'] = 'Имя начинается с буквы'; +$lang['OTHERS'] = 'другие'; +$lang['ALL'] = 'все'; + +$lang['POST_LINK'] = 'Линк на это сообщение'; +$lang['LAST_VISITED'] = 'Последний визит'; +$lang['LAST_ACTIVITY'] = 'Последняя активность'; +$lang['NEVER'] = 'Никогда'; + +//mpd +$lang['DELETE_POSTS'] = 'Удалить сообщения'; +$lang['DELETE_POSTS_SUCCESFULLY'] = 'Выбранные сообщения были успешно удалены'; +//mpd end + +//ts +$lang['TOPICS_ANNOUNCEMENT'] = 'Объявления'; +$lang['TOPICS_STICKY'] = 'Прилеплены'; +$lang['TOPICS_NORMAL'] = 'Топики'; +//ts end + +//dpc +$lang['DOUBLE_POST_ERROR'] = 'Вы не можете отправить подряд два одинаковых сообщения'; +//dpc end + +//upt +$lang['UPDATE_POST_TIME'] = 'Обновить время сообщения'; +//upt end + +$lang['TOPIC_SPLIT_NEW'] = 'Новая тема'; +$lang['TOPIC_SPLIT_OLD'] = 'Старая тема'; +$lang['BOT_LEAVE_MSG_MOVED'] = 'Оставить сообщение о переносе'; +$lang['BOT_AFTER_SPLIT_TO_OLD'] = 'Оставить сообщение о разделении в старой теме'; +$lang['BOT_AFTER_SPLIT_TO_NEW'] = 'Добавить сообщение о разделении в новую тему'; +//qr +$lang['QUICK_REPLY'] = 'Быстрый ответ'; +$lang['INS_NAME_TIP'] = 'Вставить имя или выделенный кусок сообщения.'; +$lang['QUOTE_SELECTED'] = 'Цитировать выделенный текст'; +$lang['TRANSLIT_RULES'] = 'Правила транслита'; +$lang['QR_ATTACHSIG'] = 'Присоединить подпись'; +$lang['QR_NOTIFY'] = 'Уведомлять об ответах'; +$lang['QR_DISABLE'] = 'Отключить'; +$lang['QR_USERNAME'] = 'Имя'; +$lang['NO_TEXT_SEL'] = 'Нет выделенного текста'; +$lang['QR_FONT_SEL'] = 'Шрифт'; +$lang['QR_COLOR_SEL'] = 'Цвет шрифта'; +$lang['QR_SIZE_SEL'] = 'Размер шрифта'; +$lang['COLOR_STEEL_BLUE'] = 'Тёмно-Голубой'; +$lang['COLOR_GRAY'] = 'Серый'; +$lang['COLOR_DARK_GREEN'] = 'Тёмно-Зелёный'; +//qr end + +//txtb +$lang['ICQ_TXTB'] = '[ICQ]'; +$lang['AIM_TXTB'] = '[AIM]'; +$lang['MSNM_TXTB'] = '[MSN]'; +$lang['YIM_TXTB'] = '[Yahoo]'; +$lang['REPLY_WITH_QUOTE_TXTB'] = '[Цитировать]'; +$lang['READ_PROFILE_TXTB'] = '[Профиль]'; +$lang['SEND_EMAIL_TXTB'] = '[E-mail]'; +$lang['VISIT_WEBSITE_TXTB'] = '[www]'; +$lang['EDIT_DELETE_POST_TXTB'] = '[Изменить]'; +$lang['SEARCH_USER_POSTS_TXTB'] = '[Поиск]'; +$lang['VIEW_IP_TXTB'] = '[ip]'; +$lang['DELETE_POST_TXTB'] = '[x]'; +$lang['MODERATE_POST_TXTB'] = '[m]'; +$lang['SEND_PM_TXTB'] = '[ЛС]'; +//txtb end + +$lang['DECLENSION']['REPLIES'] = array('ответ', 'ответа', 'ответов'); +$lang['DECLENSION']['TIMES'] = array('раз', 'раза', 'раз'); + +$lang['DELTA_TIME']['INTERVALS'] = array( + 'seconds' => array('секунда', 'секунды', 'секунд'), + 'minutes' => array('минута', 'минуты', 'минут'), + 'hours' => array('час', 'часа', 'часов'), + 'mday' => array('день', 'дня', 'дней'), + 'mon' => array('месяц', 'месяца', 'месяцев'), + 'year' => array('год', 'года', 'лет'), +); +$lang['DELTA_TIME']['FORMAT'] = '%1$s %2$s'; // 5(%1) минут(%2) + +$lang['AUTH_TYPES'][AUTH_ALL] = $lang['AUTH_ANONYMOUS_USERS']; +$lang['AUTH_TYPES'][AUTH_REG] = $lang['AUTH_REGISTERED_USERS']; +$lang['AUTH_TYPES'][AUTH_ACL] = $lang['AUTH_USERS_GRANTED_ACCESS']; +$lang['AUTH_TYPES'][AUTH_MOD] = $lang['AUTH_MODERATORS']; +$lang['AUTH_TYPES'][AUTH_ADMIN] = $lang['AUTH_ADMINISTRATORS']; + +$lang['NEW_USER_REG_DISABLED'] = 'Регистрация новых пользователей временно отключена'; +$lang['ONLY_NEW_POSTS'] = 'только новые сообщения'; +$lang['ONLY_NEW_TOPICS'] = 'только новые темы'; + +$lang['TORHELP_TITLE'] = 'Этим раздачам необходима ваша помощь!'; + +// +// Reports +// +$lang['REPORTS'] = 'Нарушения'; +$lang['NEW_REPORT'] = ': одно открыто'; +$lang['NEW_REPORTS'] = ': %d открыто'; +$lang['NO_NEW_REPORTS'] = ': нет открытых'; +$lang['REPORT_INDEX'] = 'Полный список нарушений'; +$lang['STATISTICS'] = 'Статистика'; +$lang['STATISTIC'] = 'Параметр'; +$lang['VALUE'] = 'Значение'; +$lang['REPORT_COUNT'] = 'Текущее число сообщений'; +$lang['REPORT_MODULES_COUNT'] = 'Число модулей'; +$lang['REPORT_HACK_COUNT'] = 'Общее число сообщений'; +$lang['DELETED_REPORTS'] = 'Сообщения, отмеченные для удаления'; +$lang['REPORT_TYPE'] = 'Тип сообщения'; +$lang['REPORT_BY'] = 'от'; +$lang['NO_REPORTS'] = 'Нет сообщений'; +$lang['INVERT_SELECT'] = 'Обратить выделение'; +$lang['REPORTED_BY'] = 'Сообщение от'; +$lang['REPORTED_TIME'] = 'Дата сообщения'; +$lang['STATUS'] = 'Статус'; +$lang['LAST_CHANGED_BY'] = 'Последнее изменение'; +$lang['CHANGES'] = 'Изменения'; +$lang['REPORT_CHANGE_TEXT'] = 'Отмечено как "%1$s" пользователем %2$s в %3$s.'; +$lang['REPORT_CHANGE_TEXT_COMMENT'] = 'Отмечено как "%1$s" пользователем %2$s в %3$s:
    %4$s'; +$lang['REPORT_CHANGE_DELETE_TEXT'] = 'Отмечено для удаления пользователем %1$s в %2$s.'; +$lang['ACTION'] = 'Действие'; +$lang['REPORT_MARK'] = 'Отметить как'; +$lang['OPEN_REPORTS'] = 'открытые сообщения'; +$lang['NO_REPORTS_FOUND'] = 'Подходящих сообщений не найдено.'; +$lang['NO_REPORTS_SELECTED'] = 'Не было выделено ниодного сообщения.'; +$lang['REPORT_NOT_EXISTS'] = 'Выбранное сообщение не существует.'; +$lang['REPORT_NOT_SUPPORTED'] = 'Данная опция не поддерживается.'; +$lang['CLICK_RETURN_REPORT'] = '%sНажмите%s для возврата к сообщению.'; +$lang['CLICK_RETURN_REPORT_LIST'] = '%sНажмите%s для возврата к списку сообщений.'; + +$lang['REPORT_STATUS'] = array( + REPORT_NEW => 'Новое', + REPORT_OPEN => 'Открыто', + REPORT_IN_PROCESS => 'В обработке', + REPORT_CLEARED => 'Закрыто', + REPORT_DELETE => 'Отмечено для удаления'); + +$lang['REASON'] = 'Причина'; +$lang['REPORT_SUBJECT'] = 'Тема'; +$lang['REPORT_TITLE_EMPTY'] = 'Необходимо ввести заголовок сообщения.'; +$lang['REPORT_DESC_EMPTY'] = 'Необходимо ввести сообщение.'; +$lang['REPORT_INSERTED'] = 'Сообщение было отправлено администрации.'; + +$lang['CHANGE_REPORT'] = 'Изменить сообщение'; +$lang['CHANGE_REPORTS'] = 'Изменить сообщения'; +$lang['CHANGE_REPORT_EXPLAIN'] = 'Вы уверены, что хотите изменить статус выбранного сообщения?'; +$lang['CHANGE_REPORTS_EXPLAIN'] = 'Вы уверены, что хотите изменить статус выбранных сообщений?'; +$lang['COMMENT'] = 'Комментарий'; +$lang['REPORT_CHANGED'] = 'Статус выбранного сообщения был изменен.'; +$lang['REPORTS_CHANGED'] = 'Статус выбранных сообщений был изменен.'; + +$lang['DELETE_REPORT'] = 'Удалить сообщение'; +$lang['DELETE_REPORTS'] = 'Удалить сообщения'; +$lang['DELETE_REPORT_EXPLAIN'] = 'Вы уверены, что хотите удалить выбранное сообщение?'; +$lang['DELETE_REPORTS_EXPLAIN'] = 'Вы уверены, что хотите удалить выбранные сообщения?'; +$lang['REPORT_DELETED'] = 'Выбранное сообщение удалено.'; +$lang['REPORTS_DELETED'] = 'Выбранные сообщения удалены.'; +// +// Reports [END] +// + +// Medal [BEGIN] +$lang['MEDAL'] = 'Доска почета'; +$lang['TOP_10'] = 'Десятка лучших'; +$lang['TOP_10_RATIO'] = 'по Upload/Download Ratio'; +$lang['TOP_10_SIZE_DOWNLOAD'] = 'по объему загруженного'; +$lang['BEST_RELIZER'] = 'Десятка лучших'; +$lang['BEST_RELEASES'] = 'Лучшие раздачи'; +$lang['DOWNLOAD_MONTH'] = 'Скачивания релизов за месяц'; +$lang['THANKS_MONTH'] = 'Благодарности релизов за месяц'; +$lang['BEST_RELEASES_MONTH'] = 'Лучшие релизы за месяц'; +$lang['BEST_RELEASES_WEEK'] = 'Лучшие релизы за неделю'; +$lang['THANKS'] = 'Спасибо'; +$lang['RELEASES'] = 'Релизов'; +$lang['AVERAGE_RATING'] = 'Ср. оценка'; +$lang['BEST_COUNT_DOWNLOAD'] = 'по сумме скачиваний'; +$lang['BEST_COUNT_THANKS'] = 'по числу благодарностей'; +$lang['DOWNLOADS'] = 'Скачиваний'; +$lang['ON_AVERAGE'] = 'В среднем'; +// Medal [END] + +// search +$lang['SEARCH_S'] = 'поиск...'; +$lang['FORUM_S'] = 'по форуму'; +$lang['TRACKER_S'] = 'по трекеру'; + +// copyright +$lang['NOTICE'] = '!ВНИМАНИЕ!'; +$lang['POWERED'] = 'Powered by TorrentPier © Meithar, RoadTrain, Pandora'; +$lang['DIVE'] = 'Форум представлен на базе phpBB © phpBB Group'; +$lang['COPY'] = 'Сайт не предоставляет электронные версии произведений, а занимается лишь коллекционированием и каталогизацией ссылок, присылаемых и публикуемых на форуме нашими читателями. Если вы являетесь правообладателем какого-либо представленного материала и не желаете чтобы ссылка на него находилась в нашем каталоге, свяжитесь с нами и мы незамедлительно удалим её. Файлы для обмена на трекере предоставлены пользователями сайта, и администрация не несёт ответственности за их содержание. Просьба не заливать файлы, защищенные авторскими правами, а также файлы нелегального содержания!'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_topic_templates.php b/upload/language/lang_russian/lang_topic_templates.php new file mode 100644 index 000000000..aa0f81f9b --- /dev/null +++ b/upload/language/lang_russian/lang_topic_templates.php @@ -0,0 +1,167 @@ + %s'; +$lang['SEARCH_USERS_ADVANCED'] = 'Расширенный поиск пользователя'; +$lang['SEARCH_USERS_EXPLAIN'] = 'Позволяет осуществлять расширенный поиск пользователей по болшому диапазону критериев. Пожалуйста, читайте описания полей поиска, чтобы полностью понять каждую из поисковых возможностей.'; +$lang['SEARCH_USERNAME_EXPLAIN'] = 'Здесь можно произвести регистронезависимый поиск имени пользователя. Если вы хотите задать только часть имени, используйте * (звёздочка) как маску. Выбор регулярных выражений позволит искать по образцу. Примечание: Регулярные выражения работают только с MySQL, PostgreSQL и Oracle 10g+.'; +$lang['SEARCH_EMAIL_EXPLAIN'] = ' Введите выражение, соответствующее адресам email пользователей. Регистр не имеет значения. Для осуществления поиска по частичному соответствию, используйте * (звёздочка) как маску. Выбор регулярных выражений позволит искать по образцу. Примечание: Регулярные выражения работают только с MySQL, PostgreSQL и Oracle 10g+.'; +$lang['SEARCH_IP_EXPLAIN'] = 'Поиск пользователей по IP-адресу (xxx.xxx.xxx.xxx), по маске (xxx.xxx.xxx.*) или диапазону (xxx.xxx.xxx.xxx-yyy.yyy.yyy.yyy). Примечание: последняя четверть .255 означает весь диапазон IP адресов этой четверти. Если задано 10.0.0.255, это равнозначно запросу 10.0.0.* (IP-адрес .255 не присваивается, а является зарезервированным). Это можно встретить при поиске по диапазону, 10.0.0.5-10.0.0.255 равнозначно "10.0.0.*" . На самом деле необходимо задать 10.0.0.5-10.0.0.254 .'; +$lang['SEARCH_USERS_JOINED'] = 'Пользователи, зарегистрированные'; +$lang['SEARCH_USERS_LASTVISITED'] = 'Пользователи, посетившие конференцию'; +$lang['IN_THE_LAST'] = 'за последние'; +$lang['AFTER_THE_LAST'] = 'ранее чем за последние'; +$lang['BEFORE'] = 'До'; +$lang['AFTER'] = 'После'; +$lang['SEARCH_USERS_JOINED_EXPLAIN'] = 'Поиск пользователей, зарегистрированных До или После (включительно) указанной даты. Формат даты ГГГГ/ММ/ДД.'; +$lang['SEARCH_USERS_GROUPS_EXPLAIN'] = 'Просмотреть всех членов выбранной группы.'; +$lang['SEARCH_USERS_RANKS_EXPLAIN'] = 'Просмотреть всех носителей выбранного звания.'; +$lang['ADMINISTRATORS'] = 'Администраторы'; +$lang['BANNED_USERS'] = 'Забаненные пользователи'; +$lang['DISABLED_USERS'] = 'Отключенные пользователи'; +$lang['USERS_DISABLED_PMS'] = 'Пользователи с отключенными ЛС'; +$lang['SEARCH_USERS_MISC_EXPLAIN'] = 'Администраторы - все пользователи с правами администратора; Модераторы - все модераторы форумов; Забаненные пользователи - все учётные записи, запрещённые на конференции; отключенные пользователи - все пользователи с отключенными учётными записями (вручную, или не подтвердившие свой адрес email); Пользователи с отключенными ЛС - Пользователи, не имеющие права пользоваться личными сообщениями (установлено через управление пользователями)'; +$lang['POSTCOUNT'] = 'Число сообщений'; +$lang['EQUALS'] = 'Равно'; +$lang['GREATER_THAN'] = 'Больше чем'; +$lang['LESS_THAN'] = 'Меньше чем'; +$lang['SEARCH_USERS_POSTCOUNT_EXPLAIN'] = 'Вы можете искать пользователей по количеству оставленных сообщений. Поиск можно произвести либо по конкретному значению, либо большему или меньшему заданного, либо находящемуся в заданном диапазоне значений. Для поиска в диапазоне, выберите "Равно", и задайте начало и конец диапазона через дефис (-), напр. 10-15'; +$lang['USERFIELD'] = 'Поле профиля'; +$lang['SEARCH_USERS_USERFIELD_EXPLAIN'] = 'Поиск пользователей по различным полям профиля. В качестве маски разрешены звёздочки (*). Выбор регулярных выражений позволит искать по образцу. Примечание: Регулярные выражения работают только с MySQL, PostgreSQL и Oracle 10g+.'; +$lang['SEARCH_USERS_LASTVISITED_EXPLAIN'] = 'Вы можете искать пользователей по дате их последнего входа на конференцию, используя эту поисковую возможность.'; +$lang['SEARCH_USERS_LANGUAGE_EXPLAIN'] = 'Поиск пользователей, выбравших заданный язык в своём профиле'; +$lang['SEARCH_USERS_TIMEZONE_EXPLAIN'] = 'Поиск пользователей, выбравших заданный часовой пояс в своём профиле'; +$lang['SEARCH_USERS_STYLE_EXPLAIN'] = 'Поиск пользователей, выбравших заданный стиль в своём профиле'; +$lang['MODERATORS_OF'] = 'Модераторы'; +$lang['SEARCH_USERS_MODERATORS_EXPLAIN'] = 'Поиск пользователей с правами модератора на заданном форуме. Права модератора определяются в соответствии с правами пользователя, или в соответствии с правами группы, челоном которой он является.'; +$lang['REGULAR_EXPRESSION'] = 'Регулярное выражение?'; + +$lang['MANAGE'] = 'Управление'; +$lang['SEARCH_USERS_NEW'] = '%s дал %d результат(ов). Новый поиск.'; +$lang['BANNED'] = 'Забаненные'; +$lang['NOT_BANNED'] = 'Не забаненные'; +$lang['SEARCH_NO_RESULTS'] = 'Нет пользователей, отвечающих выбранным критериям. Пожалуйста, попробуйте повторить поиск. Если вы ищете имя пользователя или адрес email по частичному совпадению, вы должны использовать маску * (звёздочку).'; +$lang['ACCOUNT_STATUS'] = 'Статус учётной записи'; +$lang['SORT_OPTIONS'] = 'Поля сортировки:'; +$lang['LAST_VISIT'] = 'Последнее посещение'; +$lang['DAY'] = 'День'; \ No newline at end of file diff --git a/upload/language/lang_russian/lang_xs.php b/upload/language/lang_russian/lang_xs.php new file mode 100644 index 000000000..a68fe634e --- /dev/null +++ b/upload/language/lang_russian/lang_xs.php @@ -0,0 +1,140 @@ +eXtreme Styles».

    Открыть меню «eXtreme Styles»'; +$lang['XS_MAIN_TITLE'] = 'Навигационное меню «eXtreme Styles»'; +$lang['XS_MENU'] = 'Меню «eXtreme Styles»'; + +$lang['XS_CONFIGURATION'] = 'Конфигурация'; +$lang['XS_CONFIGURATION_EXPLAIN'] = 'Эта функция позволяет вам управлять стилями.'; +$lang['XS_MANAGE_CACHE'] = 'Управление кешем'; +$lang['XS_MANAGE_CACHE_EXPLAIN'] = 'This feature allows you to manage cached files.'; +$lang['XS_SET_CONFIGURATION_LC'] = 'Выбрать конфигурацию'; +$lang['XS_SET_DEFAULT_STYLE_LC'] = 'Выбрать стандартный стиль'; +$lang['XS_MANAGE_CACHE_LC'] = 'Управление кешем'; + +/* +* config.tpl +*/ + +$lang['XS_CONFIG_UPDATED'] = 'Конфигурация обновлена'; +$lang['XS_CONFIG_UPDATED_EXPLAIN'] = 'Здесь вы можете изменить конфигурацию и навигационное меню «eXtreme Styles».'; +$lang['XS_CONFIG_WARNING'] = 'Внимание: не удаётся записать кэш.'; +$lang['XS_CONFIG_WARNING_EXPLAIN'] = 'Каталог кэша защищён от записи. «eXtreme Styles» может пытаться устранить эту проблему.
    Щёлкните в этом месте, чтобы попытаться изменить режим доступа к каталогу кэша.

    Если кэш не работает на вашем сервере, то не беспокойтесь - «eXtreme Styles»
    всё равно увеличит скорость работы форума во много раз даже без кэша.'; + +$lang['XS_CONFIG_MAINTITLE'] = 'Настройка «eXtreme Styles»'; +$lang['XS_CONFIG_SUBTITLE'] = 'Если вы не понимаете, для чего предназначены некоторые переменный, то лучше не меняйте их.'; +$lang['XS_CONFIG_TITLE'] = 'Настройка «eXtreme Styles» v{VERSION}'; +$lang['XS_CONFIG_CACHE'] = 'Настройка кэширования'; + +$lang['XS_CONFIG_TPL_COMMENTS'] = 'Добавлять имена файлов tpl в HTML'; +$lang['XS_CONFIG_TPL_COMMENTS_EXPLAIN'] = 'При включении этого параметра в код HTML добавляются комментарии, которые позволяют разработчикам стиля видеть, какой файл *.tpl отображён.'; + +$lang['XS_CONFIG_USE_CACHE'] = 'Включить кэширование'; +$lang['XS_CONFIG_USE_CACHE_EXPLAIN'] = 'Кэш сохраняется на диске и ускоряет работу шаблонов, поскольку отпадает необходимость компилировать шаблон каждый раз при отображении.'; + +$lang['XS_CONFIG_AUTO_COMPILE'] = 'Автоматически сохранять кэш'; +$lang['XS_CONFIG_AUTO_COMPILE_EXPLAIN'] = 'Включение или отключение автоматической компиляции и сохранения на диск кэша шаблонов, которые ещё не кэшированы.'; + +$lang['XS_CONFIG_AUTO_RECOMPILE'] = 'Автоматически перекомпилирвоать кэш'; +$lang['XS_CONFIG_AUTO_RECOMPILE_EXPLAIN'] = 'Автоматическая повторная компиляция шаблонов при изменениях.'; + +$lang['XS_CONFIG_PHP'] = 'Расширение имён файлов кэш'; +$lang['XS_CONFIG_PHP_EXPLAIN'] = 'Это расширение кэшированных файлов. Файлы сохранены в формате php, так что расширение по умолчанию - php. Не включайте точку.'; + +$lang['XS_CONFIG_BACK'] = 'Вернуться на страницу конфигурации.'; +$lang['XS_CONFIG_SQL_ERROR'] = 'Не удалось обновить общую конфигурацию для {VAR}'; + +// Debug info +$lang['XS_DEBUG_HEADER'] = 'Отладочная информация'; +$lang['XS_DEBUG_EXPLAIN'] = 'Это отладочная информация. Используется для нахождения и устранения проблем при конфигурации кэша.'; +$lang['XS_DEBUG_VARS'] = 'Переменные шаблона'; +$lang['XS_DEBUG_TPL_NAME'] = 'Имя файла шаблона:'; +$lang['XS_DEBUG_CACHE_FILENAME'] = 'Имя файла кэша:'; +$lang['XS_DEBUG_DATA'] = 'Отладочные данные:'; + +$lang['XS_CHECK_HDR'] = 'Проверка кэша для %s'; +$lang['XS_CHECK_FILENAME'] = 'Ошибка: недопустимое имя файла'; +$lang['XS_CHECK_OPENFILE1'] = 'Ошибка: не удаётся открыть файл "%s". Будет попытка создания каталогов...'; +$lang['XS_CHECK_OPENFILE2'] = 'Ошибка: не удаётся повторно открыть файл "%s". Отказ...'; +$lang['XS_CHECK_NODIR'] = 'Проверка "%s" - нет такого каталога.'; +$lang['XS_CHECK_NODIR2'] = 'Ошибка: не удаётся создать каталог "%s". Проверьте права доступа.'; +$lang['XS_CHECK_CREATEDDIR'] = 'Создан каталог "%s"'; +$lang['XS_CHECK_DIR'] = 'Проверка "%s" - каталог существует.'; +$lang['XS_CHECK_OK'] = 'Файл "%s" открыт для записи. Внешне всё в порядке.'; +$lang['XS_ERROR_DEMO_EDIT'] = 'вы не можете редактировать файл в демонстрационном режиме'; +$lang['XS_ERROR_NOT_INSTALLED'] = 'Модуль «eXtreme Styles» не установлен. Вы забыли загрузить файл includes/template.php'; + +/* +* chmod +*/ + +$lang['XS_CHMOD'] = 'CHMOD'; +$lang['XS_CHMOD_RETURN'] = '

    Вернуться на страницу конфигурации.'; +$lang['XS_CHMOD_MESSAGE1'] = 'Конфигурация изменена.'; +$lang['XS_CHMOD_ERROR1'] = 'Не удаётся изменить режим доступа в каталоге кэша'; + +/* +* cache management +*/ + +$lang['XS_MANAGE_CACHE_EXPLAIN2'] = 'C помощью этой страницы вы можете компилировать или удалять кэшируемые файлы для стилей.'; +$lang['XS_CLEAR_ALL_LC'] = 'Очистить все'; +$lang['XS_COMPILE_ALL_LC'] = 'Компилировать все'; +$lang['XS_CLEAR_CACHE_LC'] = 'Очистить кэш'; +$lang['XS_COMPILE_CACHE_LC'] = 'Компилировать кэш'; +$lang['XS_CACHE_CONFIRM'] = 'Если у вас установлено много стилей, то эта процедура может вызвать большую нагрузку на сервер. Продолжить?'; + +$lang['XS_CACHE_NOWRITE'] = 'Ошибка: нет доступа в каталог кэша'; +$lang['XS_CACHE_LOG_DELETED'] = 'Удалён файл "{FILE}"'; +$lang['XS_CACHE_LOG_NODELETE'] = 'Ошибка: не удаётся удалить файл "{FILE}"'; +$lang['XS_CACHE_LOG_NOTHING'] = 'Нет файлов шаблонов для удаления {TPL}'; +$lang['XS_CACHE_LOG_NOTHING2'] = 'В каталоге кэша нет файлов для удаления'; +$lang['XS_CACHE_LOG_COUNT'] = 'Удалено {NUM} файлов'; +$lang['XS_CACHE_LOG_COUNT2'] = 'Ошибка при удалении {NUM} файлов'; +$lang['XS_CACHE_LOG_COMPILED'] = 'Скомпилировано {NUM} файлов'; +$lang['XS_CACHE_LOG_ERRORS'] = 'Ошибки: {NUM}'; +$lang['XS_CACHE_LOG_NOACCESS'] = 'Ошибка: нет доступа в каталог "{DIR}"'; +$lang['XS_CACHE_LOG_COMPILED2'] = 'Скомпилирован файл "{FILE}"'; +$lang['XS_CACHE_LOG_NOCOMPILE'] = 'Ошибка компиляции файла "{FILE}"'; + +/* +* style configuration +*/ +$lang['TEMPLATE_CONFIG'] = 'Конфигурация шаблона'; +$lang['XS_STYLE_CONFIGURATION'] = 'Конфигурация шаблона'; \ No newline at end of file diff --git a/upload/language/lang_russian/report_hack/.htaccess b/upload/language/lang_russian/report_hack/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/language/lang_russian/report_hack/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/language/lang_russian/report_hack/lang_report_general.php b/upload/language/lang_russian/report_hack/lang_report_general.php new file mode 100644 index 000000000..eb2789aff --- /dev/null +++ b/upload/language/lang_russian/report_hack/lang_report_general.php @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/upload/language/lang_russian/report_hack/lang_report_post.php b/upload/language/lang_russian/report_hack/lang_report_post.php new file mode 100644 index 000000000..7d18576f3 --- /dev/null +++ b/upload/language/lang_russian/report_hack/lang_report_post.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/upload/language/lang_russian/report_hack/lang_report_privmsg.php b/upload/language/lang_russian/report_hack/lang_report_privmsg.php new file mode 100644 index 000000000..0eb936b52 --- /dev/null +++ b/upload/language/lang_russian/report_hack/lang_report_privmsg.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/upload/language/lang_russian/report_hack/lang_report_topic.php b/upload/language/lang_russian/report_hack/lang_report_topic.php new file mode 100644 index 000000000..720aa16a0 --- /dev/null +++ b/upload/language/lang_russian/report_hack/lang_report_topic.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/upload/language/lang_russian/report_hack/lang_report_user.php b/upload/language/lang_russian/report_hack/lang_report_user.php new file mode 100644 index 000000000..fa0f75d83 --- /dev/null +++ b/upload/language/lang_russian/report_hack/lang_report_user.php @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/upload/language/lang_russian/search_stopwords.txt b/upload/language/lang_russian/search_stopwords.txt new file mode 100644 index 000000000..d73a0f482 --- /dev/null +++ b/upload/language/lang_russian/search_stopwords.txt @@ -0,0 +1,469 @@ +автор +алло +ало +английский +аннотация +аудио +аудиокнига +аудиоспектакль +без +битрейт +близко +более +больше +будем +будет +будете +будешь +будит +будто +буду +будут +будь +буедт +буит +бывает +был +была +были +было +быть +важная +важное +важные +важный +вам +вами +вас +ваш +ваша +ваше +ваши +вверх +вдали +вдруг +ведь +везде +версия +весь +видео +вниз +внизу +вокруг +вон +восемь +восьмой +вот +впрочем +времени +время +всё +все +всегда +всего +всем +всеми +всему +всех +всею +всю +всюду +вся +второй +выпуска +где +гоблинa +говорил +говорит +год +года +году +давай +давно +даже +дал +далеко +дальше +даром +два +двадцать +две +двенадцать +двух +двухголосый +девять +действительно +день +десять +для +дни +днями +довольно +долго +должно +доп +другая +другие +других +другова +другого +другое +другой +дублирование +дык +его +ему +если +есть +ещё +еще +жанр +закадровый +занят +занята +занято +заняты +затем +зато +зачем +здесь +зип +значит +ибо +издатель +издательство +изначально +или +именно +иметь +ими +имхо +имя +иногда +интерфейса +информация +исполнитель +кадра +каждая +каждое +каждые +каждый +кажется +как +какая +какже +какой +качество +кем +когда +кого +кодек +ком +компьютерное +кому +конечно +коотрый +которая +которого +которой +которые +который +которых +кроме +кругом +кто +куда +лет +либо +лишь +лол +лучше +любительский +люди +мало +мегалол +между +менее +меньше +меня +миллионов +мимо +минут +мля +мне +много +многоголосый +мной +мною +моё +мог +могли +могу +могут +модель +мое +может +можно +мои +мой +мочь +моя +наверху +над +надо +назад +название +наиболее +наконец +нам +нами +нас +нах +наш +наша +наше +наши +неё +него +недавно +недалеко +нее +ней +нельзя +нем +немного +нему +нередко +несжатый +несколько +нет +нею +нибудь +ниже +низко +никогда +никуда +ними +них +ничего +нужно +оба +обложка +обычно +обычный +один +однажды +однако +одного +одноголосый +одной +около +она +они +оно +операционные +описание +опять +оригинальное +особенно +особено +ответ +отовсюду +отсканированные +отсутствует +отсюда +очень +ошибками +ошибок +первый +перевод +перед +песен +платформа +под +пожалуйста +позже +пока +полное +пор +пора +после +посреди +постер +потом +потому +почему +почти +прекрасно +при +присутствует +про +продолжительность +просто +против +профессиональный +процент +процентов +прочем +пятый +пять +раз +разве +размер +разработчик +разработчика +рано +раньше +рар +режиссер +ролях +рус +русский +рядом +сайт +сам +сама +самаво +сами +самим +самими +самих +само +самого +самой +самом +самому +саму +сборки +своё +свое +своего +своей +свои +своих +свой +свою +своя +себе +себя +сегодня +седня +седьмой +сейчас +семь +сжатый +системные +системы +сих +сказал +сказала +сказать +сколько +скриншот +слишком +сначала +снова +собой +собою +совсем +спасибо +список +стал +страна +страницы +субтитры +суть +таб +таблэтка +тагда +так +такая +также +такие +такйо +такое +такой +там +тама +твоё +твой +твоя +тебе +тебя +текст +тем +теми +теперь +тех +тип +тобой +тобою +тогда +того +тоже +той +только +том +тому +топик +топика +торент +торрент +тот +точек +тоьлко +тою +транслит +требования +требуется +третий +три +трэклист +туда +тут +тысяч +тысяча +уже +уметь +упс +формат +форум +форума +хороше +хорошо +хотеть +хоть +хотя +хочешь +часто +чаще +чего +чей +человек +чем +чему +через +четвертый +четыре +что +чтоб +чтобы +чуть +чье +чья +шестой +шесть +щас +эта +эти +этим +этими +этих +это +этого +этой +этом +этому +этот +эту +язык diff --git a/upload/language/lang_russian/search_synonyms.txt b/upload/language/lang_russian/search_synonyms.txt new file mode 100644 index 000000000..6ee9fc600 --- /dev/null +++ b/upload/language/lang_russian/search_synonyms.txt @@ -0,0 +1,75 @@ +аббревиатура абревиатура +абонент абанент +агрессивный агресивный +агрессия агресия +агрессор агресор +аккумулятор акамулятор +аккумулятор акумулятор +аккуратно акуратно +аккуратный акуратный +апелляция апеляция +аппарат апарат +аппаратура апаратура +ассистент асистент +баррикада барикада +больше больеш +брэнд бренд +будущее будующее +будущем будующеем +будущем будующем +будущий будующий +видеть видить +всегда всигда +всегда свегда +всякий свякий +гауптвахта гаупвахта +грамотный граммотный +гуманизм гумманизм +делать деалть +дилер диллер +жизнь жизьнь +жизнь жызнь +зачет зачот +идти итти +именно миенно +инженер инжинер +интерес антирес +интерес интирес +инцидент инцедент +инцидент инциндент +легко лекго +легко лехко +машина машына +машина мошина +мощность мощьность +наконец наканец +например напирмер +ничего ничево +ничто ништо +новый нвоый +опечатка очепятка +офис оффис +перспектива переспектива +последний полседний +потом патом +потом поотм +программа софтинка +программист програмист +программу софтинку +просто рпосто +против проитв +раса расса +реклама рекламма +рекламу рекламму +свои сови +сказать сакзать +сколько сколко +случай случяй +смотреть смортеть +твой товй +теперь теепрь +функцыя функцыя +хороший хароший +черный чорный +черным чорным +эффект эфект \ No newline at end of file diff --git a/upload/language/lang_russian/translit_table.php b/upload/language/lang_russian/translit_table.php new file mode 100644 index 000000000..13273d5fa --- /dev/null +++ b/upload/language/lang_russian/translit_table.php @@ -0,0 +1,37 @@ + 'e', 'Ё' => 'E', + 'а' => 'a', 'А' => 'A', + 'б' => 'b', 'Б' => 'B', + 'в' => 'v', 'В' => 'V', + 'г' => 'g', 'Г' => 'G', + 'д' => 'd', 'Д' => 'D', + 'е' => 'e', 'Е' => 'E', + 'ж' => 'zh', 'Ж' => 'ZH', + 'з' => 'z', 'З' => 'Z', + 'и' => 'i', 'И' => 'I', + 'й' => 'y', 'Й' => 'Y', + 'к' => 'k', 'К' => 'K', + 'л' => 'l', 'Л' => 'L', + 'м' => 'm', 'М' => 'M', + 'н' => 'n', 'Н' => 'N', + 'о' => 'o', 'О' => 'O', + 'п' => 'p', 'П' => 'P', + 'р' => 'r', 'Р' => 'R', + 'с' => 's', 'С' => 'S', + 'т' => 't', 'Т' => 'T', + 'у' => 'u', 'У' => 'U', + 'ф' => 'f', 'Ф' => 'F', + 'х' => 'h', 'Х' => 'H', + 'ц' => 'c', 'Ц' => 'C', + 'ч' => 'ch', 'Ч' => 'CH', + 'ш' => 'sh', 'Ш' => 'SH', + 'щ' => 'sh', 'Щ' => 'SH', + 'ъ' => "'", 'Ъ' => "'", + 'ы' => 'y', 'Ы' => 'Y', + 'ь' => "'", 'Ь' => "'", + 'э' => 'e', 'Э' => 'E', + 'ю' => 'yu', 'Ю' => 'YU', + 'я' => 'ya', 'Я' => 'YA', +); \ No newline at end of file diff --git a/upload/log/.htaccess b/upload/log/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/log/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/login.php b/upload/login.php new file mode 100644 index 000000000..1e38e93d5 --- /dev/null +++ b/upload/login.php @@ -0,0 +1,126 @@ +session_start(); + +// Logout +if (!empty($_GET['logout'])) +{ + if (!IS_GUEST) + { + $user->session_end(); + } + redirect("index.php"); +} + +$redirect_url = "index.php"; +$login_errors = array(); + +// Requested redirect +if (preg_match('/^redirect=([a-z0-9\.#\/\?&=\+\-_]+)/si', $_SERVER['QUERY_STRING'], $matches)) +{ + $redirect_url = $matches[1]; + + if (!strstr($redirect_url, '?') && $first_amp = strpos($redirect_url, '&')) + { + $redirect_url[$first_amp] = '?'; + } +} +else if (!empty($_POST['redirect'])) +{ + $redirect_url = str_replace('&', '&', htmlspecialchars($_POST['redirect'])); +} +else if (!empty($_SERVER['HTTP_REFERER']) && ($parts = @parse_url($_SERVER['HTTP_REFERER']))) +{ + $redirect_url = (isset($parts['path']) ? $parts['path'] : "index.php") . (isset($parts['query']) ? '?'. $parts['query'] : ''); +} + +$redirect_url = str_replace('&admin=1', '', $redirect_url); +$redirect_url = str_replace('?admin=1', '', $redirect_url); + +if (!$redirect_url || strstr(urldecode($redirect_url), "\n") || strstr(urldecode($redirect_url), "\r") || strstr(urldecode($redirect_url), ';url')) +{ + $redirect_url = "index.php"; +} + +if (!empty($_POST['login']) && !empty($_POST['cookie_test'])) +{ + if (empty($_COOKIE[COOKIE_TEST]) || $_COOKIE[COOKIE_TEST] !== $_POST['cookie_test']) + { + $login_error = 'cookie'; + } +} + +$redirect_url = str_replace("&sid={$user->data['session_id']}", '', $redirect_url); + +if (isset($_REQUEST['admin']) && !IS_AM) +{ + bb_die($lang['NOT_ADMIN']); +} +$mod_admin_login = (IS_AM && !$user->data['session_admin']); + +// login username & password +$login_username = ($mod_admin_login) ? $userdata['username'] : (string) @$_POST['login_username']; +$login_password = (string) @$_POST['login_password']; + +// Login +$need_captcha = (!$mod_admin_login) ? CACHE('bb_login_err')->get('l_err_'. USER_IP) : false; + +// login +if (isset($_POST['login'])) +{ + if (!$mod_admin_login) + { + if (!IS_GUEST) + { + redirect('index.php'); + } + if ($login_username == '' || $login_password == '') + { + $login_errors[] = 'Вы должны ввести имя и пароль'; + } + } + + // Captcha + if ($need_captcha && !CAPTCHA()->verify_code()) + { + $login_errors[] = 'Вы должны правильно ввести код подтверждения'; + } + + if (!$login_errors) + { + if ($user->login($_POST, $mod_admin_login)) + { + $redirect_url = (defined('FIRST_LOGON')) ? $bb_cfg['first_logon_redirect_url'] : $redirect_url; + redirect($redirect_url); + } + + $login_errors[] = 'Вы ввели неверное/неактивное имя пользователя или неверный пароль'; + + $need_captcha = (!$mod_admin_login) ? CACHE('bb_login_err')->set('l_err_'. USER_IP, 1, 3600) : false; + } +} + +// Login page +if (IS_GUEST || $mod_admin_login) +{ + $template->assign_vars(array( + 'LOGIN_USERNAME' => htmlCHR($login_username), + 'LOGIN_PASSWORD' => htmlCHR($login_password), + 'LOGIN_ERR_MSG' => join('
    ', $login_errors), + 'ADMIN_LOGIN' => $mod_admin_login, + 'REDIRECT_URL' => htmlCHR($redirect_url), + 'CAPTCHA_HTML' => ($need_captcha) ? CAPTCHA()->get_html() : '', + )); + + print_page('login.tpl'); +} + +redirect('index.php'); diff --git a/upload/memberlist.php b/upload/memberlist.php new file mode 100644 index 000000000..97b79d7a5 --- /dev/null +++ b/upload/memberlist.php @@ -0,0 +1,286 @@ +session_start(array('req_login' => true)); + +$start = abs(intval(request_var('start', 0))); +$mode = (string) request_var('mode', 'joined'); +$sort_order = (request_var('order', 'ASC') == 'ASC') ? 'ASC' : 'DESC'; +$username = request_var('username', ''); +$paginationusername = $username; + +// +// Memberlist sorting +// +$mode_types_text = array( + $lang['SORT_JOINED'], + $lang['SORT_USERNAME'], + $lang['SORT_LOCATION'], + $lang['SORT_POSTS'], + $lang['SORT_EMAIL'], + $lang['SORT_WEBSITE'], + $lang['SORT_TOP_TEN'] +); + +$mode_types = array( + 'joined', + 'username', + 'location', + 'posts', + 'email', + 'website', + 'topten' +); + +// '; + +for ($i=0, $cnt=count($mode_types_text); $i < $cnt; $i++) +{ + $selected = ( $mode == $mode_types[$i] ) ? ' selected="selected"' : ''; + $select_sort_mode .= ''; +} +$select_sort_mode .= ''; + +// '; + +if ($sort_order == 'ASC') +{ + $select_sort_order .= ''; +} +else +{ + $select_sort_order .= ''; +} +$select_sort_order .= ''; + +// +// Generate page +// +$template->assign_vars(array( + 'S_MODE_SELECT' => $select_sort_mode, + 'S_ORDER_SELECT' => $select_sort_order, + 'S_MODE_ACTION' => append_sid("memberlist.php"), + 'S_USERNAME' => $paginationusername, +)); + +switch( $mode ) +{ + case 'joined': + $order_by = "user_id $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + break; + case 'username': + $order_by = "username $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + break; + case 'location': + $order_by = "user_from $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + break; + case 'posts': + $order_by = "user_posts $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + break; + case 'email': + $order_by = "user_email $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + break; + case 'website': + $order_by = "user_website $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + break; + case 'topten': + $order_by = "user_posts $sort_order LIMIT 10"; + break; + default: + $order_by = "user_regdate $sort_order LIMIT $start, " . $bb_cfg['topics_per_page']; + $mode = 'joined'; + break; +} + +// per-letter selection +$by_letter = 'all'; +$letters_range = 'a-z'; +$letters_range .= iconv('windows-1251', 'UTF-8', chr(224)); +$letters_range .= '-'; +$letters_range .= iconv('windows-1251', 'UTF-8', chr(255)); +$select_letter = $letter_sql = ''; + +$by_letter_req = (@$_REQUEST['letter']) ? strtolower(trim($_REQUEST['letter'])) : false; + +if ($by_letter_req) +{ + if ($by_letter_req === 'all') + { + $by_letter = 'all'; + $letter_sql = ''; + } + else if ($by_letter_req === 'others') + { + $by_letter = 'others'; + $letter_sql = "username REGEXP '^[!-@\\[-`].*$'"; + } + else if ($letter_req = preg_replace("#[^$letters_range]#ui", '', iconv('windows-1251', 'UTF-8', $by_letter_req[0]))) + { + $by_letter = DB()->escape($letter_req); + $letter_sql = "LOWER(username) LIKE '$by_letter%'"; + } +} + +// ENG +for ($i=ord('A'), $cnt=ord('Z'); $i <= $cnt; $i++) +{ + $select_letter .= ($by_letter == chr($i)) ? ''. chr($i) .' ' : ''. chr($i) .' '; +} +// RUS +$select_letter .= ': '; +for ($i=224, $cnt=255; $i <= $cnt; $i++) +{ + $select_letter .= ($by_letter == iconv('windows-1251', 'UTF-8', chr($i))) ? ''. iconv('windows-1251', 'UTF-8', chr($i-32)) .' ' : ''. iconv('windows-1251', 'UTF-8', chr($i-32)) .' '; +} + +$select_letter .= ': '; +$select_letter .= ($by_letter == 'others') ? ''. $lang['OTHERS'] .' ' : ''. $lang['OTHERS'] .' '; +$select_letter .= ': '; +$select_letter .= ($by_letter == 'all') ? ''. $lang['ALL'] .'' : ''. $lang['ALL'] .''; + +$template->assign_vars(array( + 'S_LETTER_SELECT' => $select_letter, + 'S_LETTER_HIDDEN' => '', +)); + +// per-letter selection end +$sql = "SELECT username, user_id, user_opt, user_posts, user_regdate, user_from, user_from_flag, user_website, user_email, user_icq, user_avatar, user_avatar_type, user_allowavatar + FROM ". BB_USERS ." + WHERE user_id NOT IN(". EXCLUDED_USERS_CSV .")"; +if ( $username ) +{ + $username = preg_replace('/\*/', '%', clean_username($username)); + $letter_sql = "username LIKE '". str_replace("\'", "''", $username) ."'"; +} +$sql .= ($letter_sql) ? " AND $letter_sql" : ''; +$sql .= " ORDER BY $order_by"; + +$result = DB()->sql_query($sql) OR message_die(GENERAL_ERROR, 'Could not query users', '', __LINE__, __FILE__, $sql); + +if ( $row = DB()->sql_fetchrow($result) ) +{ + $i = 0; + do + { + $username = $row['username']; + $user_id = $row['user_id']; + $from = $row['user_from']; +// FLAGHACK-start + $flag = ($row['user_from_flag'] && $row['user_from_flag'] != 'blank.gif') ? make_user_flag($row['user_from_flag']) : ''; +// FLAGHACK-end + + $joined = bb_date($row['user_regdate'], $lang['DATE_FORMAT']); + $posts = $row['user_posts']; + $poster_avatar = false; + + if ($row['user_avatar_type'] && $user_id != ANONYMOUS && $row['user_allowavatar']) + { + switch ($row['user_avatar_type']) + { + case USER_AVATAR_UPLOAD: + $poster_avatar = ($bb_cfg['allow_avatar_upload']) ? '' : false; + break; + case USER_AVATAR_REMOTE: + $poster_avatar = ($bb_cfg['allow_avatar_remote']) ? '' : false; + break; + case USER_AVATAR_GALLERY: + $poster_avatar = ($bb_cfg['allow_avatar_local']) ? '' : false; + break; + } + } + + $pm = ''. $lang['SEND_PM_TXTB'] .''; + $email = ($bb_cfg['board_email_form']) ? ''. $lang['SEND_EMAIL_TXTB'] .'' : false; + $www = ($row['user_website']) ? ''. $lang['VISIT_WEBSITE_TXTB'] .'' : false; + + $temp_url = append_sid("search.php?search_author=1&uid=$user_id"); + $search_img = '' . $lang['SEARCH_USER_POSTS'] . ''; + $search = '' . $lang['SEARCH_USER_POSTS'] . ''; + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars('memberrow', array( + 'ROW_NUMBER' => $i + ( $start + 1 ), + 'ROW_CLASS' => $row_class, + 'USERNAME' => $username, + 'FROM' => $from, + 'FLAG' => $flag, + 'JOINED_RAW' => $row['user_regdate'], + 'JOINED' => $joined, + 'POSTS' => $posts, + 'AVATAR_IMG' => $poster_avatar, + 'SEARCH' => $search, + 'PM' => $pm, + 'U_SEARCH_USER' => append_sid("search.php?mode=searchuser"), + 'EMAIL' => $email, + 'WWW' => $www, + 'U_VIEWPROFILE' => append_sid("profile.php?mode=viewprofile&". POST_USERS_URL ."=$user_id")) + ); + $i++; + } + while ( $row = DB()->sql_fetchrow($result) ); + DB()->sql_freeresult($result); +} +else +{ + $template->assign_block_vars('no_username', array( + 'NO_USER_ID_SPECIFIED' => $lang['NO_USER_ID_SPECIFIED'] ) + ); +} +$paginationurl = "memberlist.php?mode=$mode&order=$sort_order&letter=$by_letter"; +if ($paginationusername) $paginationurl .= "&username=$paginationusername"; +if ( $mode != 'topten' || $bb_cfg['topics_per_page'] < 10 ) +{ + $sql = "SELECT COUNT(*) AS total FROM ". BB_USERS; + $sql .= ($letter_sql) ? " WHERE $letter_sql" : ''; + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Error getting total users', '', __LINE__, __FILE__, $sql); + } + if ($total = DB()->sql_fetchrow($result)) + { + $total_members = $total['total']; + $pagination = generate_pagination($paginationurl, $total_members, $bb_cfg['topics_per_page'], $start). ' '; + } + DB()->sql_freeresult($result); +} +else +{ + $pagination = ' '; + $total_members = 10; +} +$template->assign_vars(array( + 'PAGE_TITLE' => $lang['MEMBERLIST'], + 'PAGINATION' => $pagination, + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], ( floor( $start / $bb_cfg['topics_per_page'] ) + 1 ), ceil( $total_members / $bb_cfg['topics_per_page'] )), +)); + +print_page('memberlist.tpl'); diff --git a/upload/misc.php b/upload/misc.php new file mode 100644 index 000000000..ab4e7aa91 --- /dev/null +++ b/upload/misc.php @@ -0,0 +1,176 @@ +session_start(); + +$do = request_var('do', ''); + +if ($do == 'attach_rules') +{ + if (!$forum_id = @intval(request_var('f', '')) OR !forum_exists($forum_id)) + { + bb_die('invalid forum_id'); + } + require(BB_ROOT .'attach_mod/attachment_mod.php'); + // Display the allowed Extension Groups and Upload Size + $auth = auth(AUTH_ALL, $forum_id, $userdata); + $_max_filesize = $attach_config['max_filesize']; + + if (!$auth['auth_attachments'] || !$auth['auth_view']) + { + bb_die('You are not allowed to call this file'); + } + + $sql = 'SELECT group_id, group_name, max_filesize, forum_permissions + FROM ' . BB_EXTENSION_GROUPS . ' + WHERE allow_group = 1 + ORDER BY group_name ASC'; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query Extension Groups.', '', __LINE__, __FILE__, $sql); + } + + $allowed_filesize = array(); + $rows = DB()->sql_fetchrowset($result); + $num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + // Ok, only process those Groups allowed within this forum + $nothing = true; + for ($i = 0; $i < $num_rows; $i++) + { + $auth_cache = trim($rows[$i]['forum_permissions']); + + $permit = ((is_forum_authed($auth_cache, $forum_id)) || trim($rows[$i]['forum_permissions']) == ''); + + if ($permit) + { + $nothing = false; + $group_name = $rows[$i]['group_name']; + $f_size = intval(trim($rows[$i]['max_filesize'])); + $det_filesize = (!$f_size) ? $_max_filesize : $f_size; + $size_lang = ($det_filesize >= 1048576) ? $lang['MB'] : (($det_filesize >= 1024) ? $lang['KB'] : $lang['BYTES']); + + if ($det_filesize >= 1048576) + { + $det_filesize = round($det_filesize / 1048576 * 100) / 100; + } + else if($det_filesize >= 1024) + { + $det_filesize = round($det_filesize / 1024 * 100) / 100; + } + + $max_filesize = ($det_filesize == 0) ? $lang['UNLIMITED'] : $det_filesize . ' ' . $size_lang; + + $template->assign_block_vars('group_row', array( + 'GROUP_RULE_HEADER' => sprintf($lang['GROUP_RULE_HEADER'], $group_name, $max_filesize)) + ); + + $sql = 'SELECT extension + FROM ' . BB_EXTENSIONS . " + WHERE group_id = " . (int) $rows[$i]['group_id'] . " + ORDER BY extension ASC"; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not query Extensions.', '', __LINE__, __FILE__, $sql); + } + + $e_rows = DB()->sql_fetchrowset($result); + $e_num_rows = DB()->num_rows($result); + DB()->sql_freeresult($result); + + for ($j = 0; $j < $e_num_rows; $j++) + { + $template->assign_block_vars('group_row.extension_row', array( + 'EXTENSION' => $e_rows[$j]['extension']) + ); + } + } + } + + $template->assign_vars(array( + 'PAGE_TITLE' => $lang['ATTACH_RULES_TITLE'], + 'L_RULES_TITLE' => $lang['ATTACH_RULES_TITLE'], + 'L_EMPTY_GROUP_PERMS' => $lang['NOTE_USER_EMPTY_GROUP_PERMISSIONS']) + ); + + if ($nothing) + { + $template->assign_block_vars('switch_nothing', array()); + } + + print_page('attach_rules.tpl', 'simple'); +} +elseif ($do == 'info') +{ + $req_mode = (string) request_var('show', 'not_found'); + if(preg_match('/\//i', $req_mode)) + { + die('Include detected!'); + } + if(preg_match('/ + + + + + + + + + + + +
    + + + + Go back'); +} diff --git a/upload/misc/.htaccess b/upload/misc/.htaccess new file mode 100644 index 000000000..81049dad0 --- /dev/null +++ b/upload/misc/.htaccess @@ -0,0 +1,3 @@ + +Deny from all + \ No newline at end of file diff --git a/upload/misc/html/advert.html b/upload/misc/html/advert.html new file mode 100644 index 000000000..27e94560d --- /dev/null +++ b/upload/misc/html/advert.html @@ -0,0 +1,31 @@ +РЕКЛАМА НА САЙТЕ + +
    +
    + РЕКЛАМА НА САЙТЕ +
    + +
    + +

    Размещение рекламы на

    + +

    + + + +
    +
    +
    +

    [ Закрыть ]

    +
    \ No newline at end of file diff --git a/upload/misc/html/agreement.html b/upload/misc/html/agreement.html new file mode 100644 index 000000000..a40698cf7 --- /dev/null +++ b/upload/misc/html/agreement.html @@ -0,0 +1,3 @@ +
    +
    misc/html/agreement.html
    +
    \ No newline at end of file diff --git a/upload/misc/html/copyright_holders.html b/upload/misc/html/copyright_holders.html new file mode 100644 index 000000000..f1446c5cf --- /dev/null +++ b/upload/misc/html/copyright_holders.html @@ -0,0 +1,53 @@ +ИНФОРМАЦИЯ ДЛЯ ПРАВООБЛАДАТЕЛЕЙ + +
    +
    + ИНФОРМАЦИЯ ДЛЯ ПРАВООБЛАДАТЕЛЕЙ +
    + + + +
    + +

    Информация для правообладателей.

    + +

    Если Вы являетесь правообладателем какого-либо материала, ссылка (либо ссылки) на который размещена на этом сайте, и не хотели бы чтобы данная информация распространялась пользователями без Вашего на то согласия, то мы будем рады оказать Вам содействие, удалив соответствующие ссылки.

    + +

    Для этого необходимо, чтобы вы прислали нам письмо (в электронном виде) +в котором указали нам следующую информацию:

    + +

    1. Документальное подтверждение ваших прав на материал, защищённый авторским правом:

    +

    - отсканированный документ с печатью, либо

    +

    - email с официального почтового домена компании правообладателя, либо

    +

    - иная контактная информация, позволяющая однозначно идентифицировать вас, как правообладателя данного материала.

    + +

    2. Текст который Вы желаете разместить в сопровождении удаляемой информации.

    + +

    В нем вы можете указать где, и на каких условиях можно получить информацию, ссылки на которую были удалены, а так же ваши контактные данные, для того чтобы пользователи могли получить от вас всю интересующую их информацию относительно данного материала.

    + +

    3. Прямые ссылки на страницы сайта, которые содержат ссылки на данные, которые необходимо удалить.

    + +

    Ссылки должны иметь вид http:///forum/viewtopic.php?t=XXXXX либо подобный.

    + +

    После этого, в течении 48 часов, мы удалим интересующие Вас ссылки с сайта.

    + +

    Наш email:

    + +

    ВНИМАНИЕ!

    + +

    а) Мы оставляем за собой право публикации на сайте любой информации присланной нам по почте

    + +

    б) Мы не осуществляем контроль за действиями пользователей, которые могут повторно размещать ссылки на информацию, являющуюся объектом вашего авторского права. Любая информация на форуме, размещается автоматически, без какого либо контроля с чьей либо стороны, что соответствует общепринятой мировой практике размещения информации в сети интернет. Однако, мы в любом случае рассмотрим все Ваши запросы, относительно ссылок на информацию, нарушающую Ваши права.

    + +

    в) Согласно закону об Авторском и Смежном правах, ссылка на любые данные (информационное сообщение), сама по себе, не является объектом авторского права (хотя может нарушать "соглашение об использовании сайта"). Таким образом, не стоит присылать письма содержащие угрозы либо требования, как не имеющие под собой реальных оснований.

    + +
    +
    +
    +

    [ Закрыть ]

    +
    + diff --git a/upload/misc/html/move_topic_bookmarks.html b/upload/misc/html/move_topic_bookmarks.html new file mode 100644 index 000000000..798dca1ba --- /dev/null +++ b/upload/misc/html/move_topic_bookmarks.html @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/upload/misc/html/not_found.html b/upload/misc/html/not_found.html new file mode 100644 index 000000000..ca2188a23 --- /dev/null +++ b/upload/misc/html/not_found.html @@ -0,0 +1,24 @@ +
    +
    + Файл не найден +
    + + + + +
    + +

    + +

    Файл не найден

    + +
    +
    +
    +

    [ Закрыть ]

    +
    + diff --git a/upload/misc/html/sidebar1.html b/upload/misc/html/sidebar1.html new file mode 100644 index 000000000..abee8480a --- /dev/null +++ b/upload/misc/html/sidebar1.html @@ -0,0 +1,26 @@ + + + +
    +

    BitTorrent клиенты

    +
      +
    • uTorrent (рекомендуемый: 2.0/2.0.4)
    • +
    +
    + +
    + + + +
    + + + + + \ No newline at end of file diff --git a/upload/misc/html/sidebar2.html b/upload/misc/html/sidebar2.html new file mode 100644 index 000000000..31546c5e8 --- /dev/null +++ b/upload/misc/html/sidebar2.html @@ -0,0 +1,2 @@ + +sidebar2 static content \ No newline at end of file diff --git a/upload/misc/html/user_agreement.html b/upload/misc/html/user_agreement.html new file mode 100644 index 000000000..eaf16e1da --- /dev/null +++ b/upload/misc/html/user_agreement.html @@ -0,0 +1,105 @@ + +ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ + +
    +
    + ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ +
    + + + + +
    + +

    + +

    ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ

    + +

    О САЙТЕ

    + +

    Интернет - ресурс (сайт) "> (в дальнейшем - Ресурс) является интернет-сайтом, позволяющим пользователям обмениваться друг с другом информацией по протоколу бит-торрент, а также в свободной форме, и предоставляющим средства для контроля целостности передаваемой информации (посредством hash-файлов).

    + +
      + +
    1. О ПОЛЬЗОВАТЕЛЬСКОМ СОГЛАШЕНИИ

      + +

      Настоящее ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ вступает в силу после нажатия кнопки "согласен" внизу страницы и действует все время использования Пользователем Ресурса. ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ может быть изменено Администрацией без какого-либо уведомления пользователей. Новая версия ПС вступает в силу по истечении 3 (трех) дней с момента ее размещения, если иное не предусмотрено новой редакцией ПОЛЬЗОВАТЕЛЬСКОГО СОГЛАШЕНИЯ.

      + +
    2. УСЛОВИЯ ОГРАНИЧЕНИЯ ОТВЕТСТВЕННОСТИ

      + +

      Пользователь прямо соглашается c тем, что использует Ресурс на свой собственный риск.

      + +

      Пользователь знает, и согласен с тем, что Ресурс имеет дело с материалами и данными, созданными третьими лицами и размещенными ими в сети Интернет на своих компьютерах и (или) серверах. Содержание и безопасность этих материалов не могут быть проконтролированы Администрацией Ресурса, поэтому последняя не несет ответственности:

      +
        +

        - за содержание материалов, полученных Пользователем в результате использования данных с Ресурса, их возможное несоответствие действующему законодательству или оскорбительный характер;

        +

        - за последствия применения, использования или неиспользования полученной информации;

        +

        - за возможное несоответствие результатов, полученных при использовании Ресурса, ожиданиям Пользователя;

        +

        - за какие-либо повреждения оборудования или программного обеспечения Пользователя, возникшие в результате использовании Ресурса;

        +

        - за отсутствие возможности использования Ресурса по каким-либо причинам;

        +

        - за последствия, которые может повлечь распространение нелегального либо нелицензионного программного обеспечения и аудио-/видеопродукции, а также иных материалов либо данных, затрагивающих права третьих лиц.

        +
      + +

      Ни при каких обстоятельствах Ресурс не несет перед Пользователем, либо третьими лицами ответственности за ущерб, убытки или расходы, возникшие в связи с настоящим Ресурсом, его использованием или невозможностью использования, включая упущенную либо недополученную прибыль.

      + +

      Администрация Ресурса не несет никаких обязательств по обеспечению конфиденциальности в отношении информации, предоставляемой его Пользователям, хотя принимает все возможные меры к этому, если не имеется договоренности об обратном или соответствующих требований действующего законодательства.

      + +

      В обязанности Ресурса НЕ ВХОДИТ контроль легальности или нелегальности передаваемой информации (любой, включая, но не ограничиваясь, информацией передаваемой между пользователями по протоколу бит-торрент, внутренней пересылки информации в виде различных ссылок, текстов или архивов), определение прав собственности или законности передачи, приема или использования этой информации.

      + +
    3. ОГРАНИЧЕНИЯ НА ИСПОЛЬЗОВАНИЕ РЕСУРСА ПОЛЬЗОВАТЕЛЕМ.

      + +

      При использовании данного Ресурса, ПОЛЬЗОВАТЕЛЬ не имеет права, и соглашается с этим:

      +
        +

        - размещать hash-файлы(торренты) данных, содержащие вирусы или другие компьютерные программы заведомо вредоносного действия, файлы или программы, предназначенные для нарушения, уничтожения либо ограничения функциональности любого компьютерного или телекоммуникационного оборудования или программ, для осуществления несанкционированного доступа, а также серийные номера к коммерческим программным продуктам и программы для их генерации, логины, пароли и прочие средства для получения несанкционированного доступа к платным ресурсам в Интернете, а также размещать ссылки на вышеуказанную информацию;

        +

        - размещать hash-файлы(торренты) любых сообщений, данных или программ, использование которых затрагивает какой-либо патент, торговую марку, коммерческую тайну, копирайт или прочие права собственности и/или авторские и смежные с ним права третьих лиц;

        +

        - отправлять на адреса электронной почты, указанные на сайте, несанкционированные почтовые сообщения рекламного типа (junk mail, spam);

        +

        - копировать и использовать в коммерческих целях любую информацию, получаемую посредством данного ресурса, нарушающую права других Пользователей или могущую нанести им прямой материальный или моральный ущерб;

        +

        - размещать ссылки на ресурсы Сети, содержание которых противоречит действующему законодательству РФ;

        +

        - выдавать себя за другого человека или за представителя организации и/или сообщества без достаточных на то прав, в том числе за сотрудников Aдминистрации, за владельца Ресурса.

        +
      + +
    4. ГАРАНТИИ РАБОТОСПОСОБНОСТИ

      + +

      Доступ к Ресурсу предоставляются по принципу «как есть» («as is») без гарантий любого рода, как прямых, так и косвенных.

      + +

      В частности Администрация Ресурса не гарантирует работоспособность как сайта и его отдельных разделов, так и работоспособность и достоверность ссылок, размещенных на нем его Пользователями.

      + +

      Ресурс не несет ответственности за любые прямые или непрямые убытки, произошедшие из-за: использования либо невозможности использования службы; несанкционированного доступа к Вашим коммуникациям.

      + +
    5. ПРАВА АДМИНИСТРАЦИИ РЕСУРСА.

      + +

      Администрация Ресурса вправе отказать в доступе к Ресурсу любому Пользователю, или группе Пользователей без объяснения причин своих действий и предварительного уведомления.

      + +

      Администрация Ресурса вправе изменять либо удалять ссылки на информацию, hash-файлы (торренты), графические, звуковые и прочие данные, размещенные Пользователями на Ресурсе, без предварительного уведомления и объяснения причин своих действий.

      + +
    6. ОТВЕТСТВЕННОСТЬ СТОРОН.

      + +

      Пользователь соглашается с тем, что все возможные споры по поводу СОГЛАШЕНИЯ ОБ ИСПОЛЬЗОВАНИИ будут разрешаться по нормам российского права.

      + +

      Пользователь соглашается с тем, что нормы и законы о защите прав потребителей не могут быть применимы к использованию им Ресурса, поскольку он не оказывает возмездных услуг.

      + +

      Ресурс не устанавливает с пользователями агентских отношений, отношений товарищества, отношений по совместной деятельности, отношений личного найма, а также каких-то иных отношений, прямо не описанных в СОГЛАШЕНИИ ОБ ИСПОЛЬЗОВАНИИ.

      + +

      Бездействие со стороны Ресурса в случае нарушения Пользователем, либо группой Пользователей ПОЛЬЗОВАТЕЛЬСКОГО СОГЛАШЕНИЯ не означает того, что Ресурс содействует Пользователю, либо группе Пользователей в таковых действиях.

      + +

      Бездействие со стороны Ресурса в случае нарушения Пользователем либо группой Пользователей ПОЛЬЗОВАТЕЛЬСКОГО СОГЛАШЕНИЯ не лишает Ресурс права предпринять соответствующие действия в защиту своих интересов позднее.

      + +
    7. СОГЛАСИЕ С ПОЛЬЗОВАТЕЛЬСКИМ СОГЛАШЕНИЕМ.

      + +

      ЕСЛИ ВЫ НЕ СОГЛАСНЫ СO ВСЕМИ ВЫШЕУКАЗАННЫМИ УСЛОВИЯМИ, ВЫ НЕ ИМЕЕТЕ ПРАВА ПОСЕЩАТЬ РЕСУРС КАК В ЦЕЛОМ, ТАК И ЛЮБУЮ ЕГО ЧАСТЬ, КРОМЕ СТРАНИЦЫ С ПОЛЬЗОВАТЕЛЬСКИМ СОГЛАШЕНИЕМ, ПОЛУЧАТЬ И/ИЛИ ИСПОЛЬЗОВАТЬ СОДЕРЖИМОЕ НАСТОЯЩЕГО РЕСУРСА ЛЮБЫМИ ДРУГИМИ СПОСОБАМИ КАК В ЦЕЛОМ ТАК И В ЛЮБОЙ ЕГО ЧАСТИ!

      + +

      ЕСЛИ ВЫ НЕ СОГЛАСНЫ С ПОЛЬЗОВАТЕЛЬСКИМ СОГЛАШЕНИЕМ, ВЫ ДОЛЖНЫ НЕМЕДЛЕННО ПОКИНУТЬ РЕСУРС.

      + +
    +

    + +
    + +
    +
    +

    [ Закрыть ]

    +
    + diff --git a/upload/misc/js/bbcode.js b/upload/misc/js/bbcode.js new file mode 100644 index 000000000..796337365 --- /dev/null +++ b/upload/misc/js/bbcode.js @@ -0,0 +1,452 @@ +// BBCode control. (based on bbcode.js from http://forum.dklab.ru) +function BBCode(textarea) { this.construct(textarea) } +BBCode.prototype = { + VK_TAB: 9, + VK_ENTER: 13, + VK_PAGE_UP: 33, + BRK_OP: '[', + BRK_CL: ']', + textarea: null, + stext: '', + quoter: null, + collapseAfterInsert: false, + replaceOnInsert: false, + + // Create new BBCode control. + construct: function(textarea) { + this.textarea = textarea + this.tags = new Object(); + // Tag for quoting. + this.addTag( + '_quoter', + function() { return '[quote="'+th.quoter+'"]' }, + '[/quote]\n', + null, + null, + function() { th.collapseAfterInsert=true; return th._prepareMultiline(th.quoterText) } + ); + + // Init events. + var th = this; + addEvent(textarea, 'keydown', function(e) { return th.onKeyPress(e, window.HTMLElement? 'down' : 'press') }); + addEvent(textarea, 'keypress', function(e) { return th.onKeyPress(e, 'press') }); + }, + + // Insert poster name or poster quotes to the text. + onclickPoster: function(name) { + var sel = this.getSelection()[0]; + if (sel) { + this.quoter = name; + this.quoterText = sel; + this.insertTag('_quoter'); + } else { + this.insertAtCursor("[b]" + name + '[/b]\n'); + } + return false; + }, + + // Quote selected text + onclickQuoteSel: function() { + var sel = this.getSelection()[0]; + if (sel) { + this.insertAtCursor('[quote]' + sel + '[/quote]\n'); + } + else { + alert('Please select text.'); + } + return false; + }, + + // Quote selected text + emoticon: function(em) { + if (em) { + this.insertAtCursor(' ' + em + ' '); + } + else { + return false; + } + return false; + }, + + // For stupid Opera - save selection before mouseover the button. + refreshSelection: function(get) { + if (get) this.stext = this.getSelection()[0]; + else this.stext = ''; + }, + + // Return current selection and range (if exists). + // In Opera, this function must be called periodically (on mouse over, + // for example), because on click stupid Opera breaks up the selection. + getSelection: function() { + var w = window; + var text='', range; + if (w.getSelection) { + // Opera & Mozilla? + text = w.getSelection(); + } else if (w.document.getSelection) { + // the Navigator 4.0x code + text = w.document.getSelection(); + } else if (w.document.selection && w.document.selection.createRange) { + // the Internet Explorer 4.0x code + range = w.document.selection.createRange(); + text = range.text; + } else { + return [null, null]; + } + if (text == '') text = this.stext; + text = ""+text; + text = text.replace("/^\s+|\s+$/g", ""); + return [text, range]; + }, + + // Insert string at cursor position of textarea. + insertAtCursor: function(text) { + // Focus is placed to textarea. + var t = this.textarea; + t.focus(); + // Insert the string. + if (document.selection && document.selection.createRange) { + var r = document.selection.createRange(); + if (!this.replaceOnInsert) r.collapse(); + r.text = text; + } else if (t.setSelectionRange) { + var start = this.replaceOnInsert? t.selectionStart : t.selectionEnd; + var end = t.selectionEnd; + var sel1 = t.value.substr(0, start); + var sel2 = t.value.substr(end); + t.value = sel1 + text + sel2; + t.setSelectionRange(start+text.length, start+text.length); + } else{ + t.value += text; + } + // For IE. + setTimeout(function() { t.focus() }, 100); + }, + + // Surround piece of textarea text with tags. + surround: function(open, close, fTrans) { + var t = this.textarea; + t.focus(); + if (!fTrans) fTrans = function(t) { return t; }; + + var rt = this.getSelection(); + var text = rt[0]; + var range = rt[1]; + if (text == null) return false; + + var notEmpty = text != null && text != ''; + + // Surround. + if (range) { + var notEmpty = text != null && text != ''; + var newText = open + fTrans(text) + (close? close : ''); + range.text = newText; + range.collapse(); + if (text != '') { + // Correction for stupid IE: \r for moveStart is 0 character. + var delta = 0; + for (var i=0; i= 0) text = "\n" + text + "\n"; + return text; + } + +} + +// Called before form submitting. +function checkForm(form) { + var formErrors = false; + if (form.message.value.length < 2) { + formErrors = "Please enter the message."; + } + if (formErrors) { + setTimeout(function() { alert(formErrors) }, 100); + return false; + } + return true; +} + +// Emulation of innerText for Mozilla. +if (window.HTMLElement && window.HTMLElement.prototype.__defineSetter__) { + HTMLElement.prototype.__defineSetter__("innerText", function (sText) { + this.innerHTML = sText.replace(/\&/g, "&").replace(//g, ">"); + }); + HTMLElement.prototype.__defineGetter__("innerText", function () { + var r = this.ownerDocument.createRange(); + r.selectNodeContents(this); + return r.toString(); + }); +} + +function AddSelectedText(BBOpen, BBClose) { + if (document.post.message.caretPos) document.post.message.caretPos.text = BBOpen + document.post.message.caretPos.text + BBClose; + else document.post.message.value += BBOpen + BBClose; + document.post.message.focus() +} + +function InsertBBCode(BBcode) +{ + AddSelectedText('[' + BBcode + ']','[/' + BBcode + ']'); +} + +function storeCaret(textEl) { + if (textEl.createTextRange) textEl.caretPos = document.selection.createRange().duplicate(); +} + +// Translit START + +// One character letters +var t_table1 = "ABVGDEZIJKLMNOPRSTUFXHCYWabvgdezijklmnoprstufxhcyw'#"; +var w_table1 = "АБВГДЕЗИЙКЛМНОПРСТУФХХЦЫЩабвгдезийклмнопрстуфххцыщьъ"; + +// Two character letters +var t_table2 = "EHSZYOJOZHCHSHYUJUYAJAehszyojozhchshyujuyajaEhSzYoJoZhChShYuJuYaJa"; +var w_table2 = "ЭЩЁЁЖЧШЮЮЯЯэщёёжчшююяяЭЩЁЁЖЧШЮЮЯЯ"; + +var tagArray = [ + 'code', '', + 'img', '', + 'quote', "(=[\"']?[^"+String.fromCharCode(92,93)+"]+)?", + 'email', "(=[\"']?[a-zA-Z0-9_.-]+@?[a-zA-Z0-9_.-]+[\"']?)?", + 'url', "(=[\"']?[^ \"'"+String.fromCharCode(92,93)+"]*[\"']?)?" +]; + +function translit2win (str) +{ + var len = str.length; + var new_str = ""; + + for (i = 0; i < len; i++) + { + /* non-translatable text must be in ^ */ + if(str.substr(i).indexOf("^")==0){ + end_len=str.substr(i+1).indexOf("^")+2; + if (end_len>1){ + new_str+=str.substr(i,end_len); + i += end_len - 1; + continue; + } + } + + /* Skipping emoticons */ + if(str.substr(i).indexOf(":")==0){ + iEnd = str.substr(i+1).indexOf(":")+2; + if (iEnd > 1 && str.substr(i,iEnd).match("^:[a-zA-Z0-9]+:$")){ + new_str += str.substr(i,iEnd); + i += iEnd - 1; + continue; + } + } + + /* Skipping http|news|ftp:/.../ links */ + rExp = new RegExp("^((http|https|news|ftp|ed2k):\\/\\/[\\/a-zA-Z0-9%_?.:;&#|\(\)+=@-]+)","i"); + if (newArr = str.substr(i).match(rExp)){ + new_str += newArr[1]; + i += newArr[1].length - 1; + continue; + } + + /* Skipping FONT, COLOR, SIZE tags */ + rExp = new RegExp("^(\\[\\/?(b|i|u|s|font(=[a-z0-9]+)?|size(=[0-9]+)?|color(=#?[a-z0-9]+)?)\\])","i"); + if (newArr = str.substr(i).match(rExp)){ + new_str += newArr[1]; + i += newArr[1].length - 1; + continue; + } + + /* Skipping [QUOTE]..[/QUOTE], [IMG]..[/IMG], [CODE]..[/CODE], [SQL]..[/SQL], [EMAIL]..[/EMAIL] tags */ + bSkip = false; + for(j = 0; j < tagArray.length; j += 2){ + rExp = new RegExp("^(\\["+tagArray[j]+tagArray[j+1]+"\\])","i"); + if (newArr = str.substr(i).match(rExp)){ + rExp = new RegExp("\\[\\/" + tagArray[j] + "\\]", "i"); + if (iEnd = str.substr(i + newArr[1].length + 2).search(rExp)){ + end_len = iEnd + newArr[1].length + tagArray[j].length + 4; + new_str += str.substr(i,end_len); + i += end_len - 1; + bSkip = true; + } + } + if(bSkip)break; + } + if(bSkip)continue; + + // Check for 2-character letters + is2char=false; + if (i < len-1) { + for(j = 0; j < w_table2.length; j++) + { + if(str.substr(i, 2) == t_table2.substr(j*2,2)) { + new_str+= w_table2.substr(j, 1); + i++; + is2char=true; + break; + } + } + } + + if(!is2char) { + // Convert one-character letter + var c = str.substr(i, 1); + var pos = t_table1.indexOf(c); + if (pos < 0) + new_str+= c; + else + new_str+= w_table1.substr(pos, 1); + } + } + +// document.REPLIER.Post.focus(); + return new_str; +} + +function transliterate (msg, e) +{ + if (e) e.disabled = true; + setTimeout(function() { + if (!bbcode.surround('', '', translit2win)) { + msg.value = translit2win(msg.value); + } + if (e) e.disabled = false; + }, 1); +} + +// Translit END diff --git a/upload/misc/js/develop.js b/upload/misc/js/develop.js new file mode 100644 index 000000000..17f639edb --- /dev/null +++ b/upload/misc/js/develop.js @@ -0,0 +1,2 @@ + +var dev = true; \ No newline at end of file diff --git a/upload/misc/js/firebug/errorIcon.png b/upload/misc/js/firebug/errorIcon.png new file mode 100644 index 000000000..2d75261bb Binary files /dev/null and b/upload/misc/js/firebug/errorIcon.png differ diff --git a/upload/misc/js/firebug/firebug.css b/upload/misc/js/firebug/firebug.css new file mode 100644 index 000000000..1f041c4da --- /dev/null +++ b/upload/misc/js/firebug/firebug.css @@ -0,0 +1,209 @@ + +html, body { + margin: 0; + background: #FFFFFF; + font-family: Lucida Grande, Tahoma, sans-serif; + font-size: 11px; + overflow: hidden; +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.toolbar { + height: 14px; + border-top: 1px solid ThreeDHighlight; + border-bottom: 1px solid ThreeDShadow; + padding: 2px 6px; + background: ThreeDFace; +} + +.toolbarRight { + position: absolute; + top: 4px; + right: 6px; +} + +#log { + overflow: auto; + position: absolute; + left: 0; + width: 100%; +} + +#commandLine { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 18px; + border: none; + border-top: 1px solid ThreeDShadow; +} + +/************************************************************************************************/ + +.logRow { + position: relative; + border-bottom: 1px solid #D7D7D7; + padding: 2px 4px 1px 6px; + background-color: #FFFFFF; +} + +.logRow-command { + font-family: Monaco, monospace; + color: blue; +} + +.objectBox-null { + padding: 0 2px; + border: 1px solid #666666; + background-color: #888888; + color: #FFFFFF; +} + +.objectBox-string { + font-family: Monaco, monospace; + color: red; + white-space: pre; +} + +.objectBox-number { + color: #000088; +} + +.objectBox-function { + font-family: Monaco, monospace; + color: DarkGreen; +} + +.objectBox-object { + color: DarkGreen; + font-weight: bold; +} + +/************************************************************************************************/ + +.logRow-info, +.logRow-error, +.logRow-warning { + background: #FFFFFF no-repeat 2px 2px; + padding-left: 20px; + padding-bottom: 3px; +} + +.logRow-info { + background-image: url(infoIcon.png); +} + +.logRow-warning { + background-color: cyan; + background-image: url(warningIcon.png); +} + +.logRow-error { + background-color: LightYellow; + background-image: url(errorIcon.png); +} + +.errorMessage { + vertical-align: top; + color: #FF0000; +} + +.objectBox-sourceLink { + position: absolute; + right: 4px; + top: 2px; + padding-left: 8px; + font-family: Lucida Grande, sans-serif; + font-weight: bold; + color: #0000FF; +} + +/************************************************************************************************/ + +.logRow-group { + background: #EEEEEE; + border-bottom: none; +} + +.logGroup { + background: #EEEEEE; +} + +.logGroupBox { + margin-left: 24px; + border-top: 1px solid #D7D7D7; + border-left: 1px solid #D7D7D7; +} + +/************************************************************************************************/ + +.selectorTag, +.selectorId, +.selectorClass { + font-family: Monaco, monospace; + font-weight: normal; +} + +.selectorTag { + color: #0000FF; +} + +.selectorId { + color: DarkBlue; +} + +.selectorClass { + color: red; +} + +/************************************************************************************************/ + +.objectBox-element { + font-family: Monaco, monospace; + color: #000088; +} + +.nodeChildren { + margin-left: 16px; +} + +.nodeTag { + color: blue; +} + +.nodeValue { + color: #FF0000; + font-weight: normal; +} + +.nodeText, +.nodeComment { + margin: 0 2px; + vertical-align: top; +} + +.nodeText { + color: #333333; +} + +.nodeComment { + color: DarkGreen; +} + +/************************************************************************************************/ + +.propertyNameCell { + vertical-align: top; +} + +.propertyName { + font-weight: bold; +} diff --git a/upload/misc/js/firebug/firebug.html b/upload/misc/js/firebug/firebug.html new file mode 100644 index 000000000..861e63932 --- /dev/null +++ b/upload/misc/js/firebug/firebug.html @@ -0,0 +1,23 @@ + + + + + + Firebug + + + + +
    + Clear + + Close + +
    +
    + + + + + diff --git a/upload/misc/js/firebug/firebug.js b/upload/misc/js/firebug/firebug.js new file mode 100644 index 000000000..14eaad2e8 --- /dev/null +++ b/upload/misc/js/firebug/firebug.js @@ -0,0 +1,672 @@ + +if (!window.console || !console.firebug) { +(function() +{ + window.console = + { + log: function() + { + logFormatted(arguments, ""); + }, + + debug: function() + { + logFormatted(arguments, "debug"); + }, + + info: function() + { + logFormatted(arguments, "info"); + }, + + warn: function() + { + logFormatted(arguments, "warning"); + }, + + error: function() + { + logFormatted(arguments, "error"); + }, + + assert: function(truth, message) + { + if (!truth) + { + var args = []; + for (var i = 1; i < arguments.length; ++i) + args.push(arguments[i]); + + logFormatted(args.length ? args : ["Assertion Failure"], "error"); + throw message ? message : "Assertion Failure"; + } + }, + + dir: function(object) + { + var html = []; + + var pairs = []; + for (var name in object) + { + try + { + pairs.push([name, object[name]]); + } + catch (exc) + { + } + } + + pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; }); + + html.push('
    '. $val .'
    '. str_replace(array("{$this->selected_db}.", ',', ';'), array('', ', ', ';
    '), $val) .'
    '); + for (var i = 0; i < pairs.length; ++i) + { + var name = pairs[i][0], value = pairs[i][1]; + + html.push('', + '', ''); + } + html.push('
    ', + escapeHTML(name), ''); + appendObject(value, html); + html.push('
    '); + + logRow(html, "dir"); + }, + + dirxml: function(node) + { + var html = []; + + appendNode(node, html); + logRow(html, "dirxml"); + }, + + group: function() + { + logRow(arguments, "group", pushGroup); + }, + + groupEnd: function() + { + logRow(arguments, "", popGroup); + }, + + time: function(name) + { + timeMap[name] = (new Date()).getTime(); + }, + + timeEnd: function(name) + { + if (name in timeMap) + { + var delta = (new Date()).getTime() - timeMap[name]; + logFormatted([name+ ":", delta+"ms"]); + delete timeMap[name]; + } + }, + + count: function() + { + this.warn(["count() not supported."]); + }, + + trace: function() + { + this.warn(["trace() not supported."]); + }, + + profile: function() + { + this.warn(["profile() not supported."]); + }, + + profileEnd: function() + { + }, + + clear: function() + { + consoleBody.innerHTML = ""; + }, + + open: function() + { + toggleConsole(true); + }, + + close: function() + { + if (frameVisible) + toggleConsole(); + } + }; + + // ******************************************************************************************** + + var consoleFrame = null; + var consoleBody = null; + var commandLine = null; + + var frameVisible = false; + var messageQueue = []; + var groupStack = []; + var timeMap = {}; + + var clPrefix = ">>> "; + + var isFirefox = navigator.userAgent.indexOf("Firefox") != -1; + var isIE = navigator.userAgent.indexOf("MSIE") != -1; + var isOpera = navigator.userAgent.indexOf("Opera") != -1; + var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1; + + // ******************************************************************************************** + + function toggleConsole(forceOpen) + { + frameVisible = forceOpen || !frameVisible; + if (consoleFrame) + consoleFrame.style.visibility = frameVisible ? "visible" : "hidden"; + else + waitForBody(); + } + + function focusCommandLine() + { + toggleConsole(true); + if (commandLine) + commandLine.focus(); + } + + function waitForBody() + { + if (document.body) + createFrame(); + else + setTimeout(waitForBody, 200); + } + + function createFrame() + { + if (consoleFrame) + return; + + window.onFirebugReady = function(doc) + { + window.onFirebugReady = null; + + var toolbar = doc.getElementById("toolbar"); + toolbar.onmousedown = onSplitterMouseDown; + + commandLine = doc.getElementById("commandLine"); + addEvent(commandLine, "keydown", onCommandLineKeyDown); + + addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown); + + consoleBody = doc.getElementById("log"); + layout(); + flush(); + } + + var baseURL = getFirebugURL(); + + consoleFrame = document.createElement("iframe"); + consoleFrame.setAttribute("src", baseURL+"/firebug.html"); + consoleFrame.setAttribute("frameBorder", "0"); + consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden"); + consoleFrame.style.zIndex = "2147483583"; + consoleFrame.style.position = document.all ? "absolute" : "fixed"; + consoleFrame.style.width = "100%"; + consoleFrame.style.left = "0"; + consoleFrame.style.bottom = "0"; + consoleFrame.style.height = "200px"; + document.body.appendChild(consoleFrame); + } + + function getFirebugURL() + { + var scripts = document.getElementsByTagName("script"); + for (var i = 0; i < scripts.length; ++i) + { + if (scripts[i].src.indexOf("firebug.js") != -1) + { + var lastSlash = scripts[i].src.lastIndexOf("/"); + return scripts[i].src.substr(0, lastSlash); + } + } + } + + function evalCommandLine() + { + var text = commandLine.value; + commandLine.value = ""; + + logRow([clPrefix, text], "command"); + + var value; + try + { + value = eval(text); + } + catch (exc) + { + } + + console.log(value); + } + + function layout() + { + var toolbar = consoleBody.ownerDocument.getElementById("toolbar"); + var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight); + consoleBody.style.top = toolbar.offsetHeight + "px"; + consoleBody.style.height = height + "px"; + + commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px"; + } + + function logRow(message, className, handler) + { + if (consoleBody) + writeMessage(message, className, handler); + else + { + messageQueue.push([message, className, handler]); + waitForBody(); + } + } + + function flush() + { + var queue = messageQueue; + messageQueue = []; + + for (var i = 0; i < queue.length; ++i) + writeMessage(queue[i][0], queue[i][1], queue[i][2]); + } + + function writeMessage(message, className, handler) + { + var isScrolledToBottom = + consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight; + + if (!handler) + handler = writeRow; + + handler(message, className); + + if (isScrolledToBottom) + consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight; + } + + function appendRow(row) + { + var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody; + container.appendChild(row); + } + + function writeRow(message, className) + { + var row = consoleBody.ownerDocument.createElement("div"); + row.className = "logRow" + (className ? " logRow-"+className : ""); + row.innerHTML = message.join(""); + appendRow(row); + } + + function pushGroup(message, className) + { + logFormatted(message, className); + + var groupRow = consoleBody.ownerDocument.createElement("div"); + groupRow.className = "logGroup"; + var groupRowBox = consoleBody.ownerDocument.createElement("div"); + groupRowBox.className = "logGroupBox"; + groupRow.appendChild(groupRowBox); + appendRow(groupRowBox); + groupStack.push(groupRowBox); + } + + function popGroup() + { + groupStack.pop(); + } + + // ******************************************************************************************** + + function logFormatted(objects, className) + { + var html = []; + + var format = objects[0]; + var objIndex = 0; + + if (typeof(format) != "string") + { + format = ""; + objIndex = -1; + } + + var parts = parseFormat(format); + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + part.appender(object, html); + } + else + appendText(part, html); + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + if (typeof(object) == "string") + appendText(object, html); + else + appendObject(object, html); + } + + logRow(html, className); + } + + function parseFormat(format) + { + var parts = []; + + var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/; + var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat}; + + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + var type = m[8] ? m[8] : m[5]; + var appender = type in appenderMap ? appenderMap[type] : appendObject; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({appender: appender, precision: precision}); + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + + return parts; + } + + function escapeHTML(value) + { + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); + } + + function objectToString(object) + { + try + { + return object+""; + } + catch (exc) + { + return null; + } + } + + // ******************************************************************************************** + + function appendText(object, html) + { + html.push(escapeHTML(objectToString(object))); + } + + function appendNull(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + } + + function appendString(object, html) + { + html.push('"', escapeHTML(objectToString(object)), + '"'); + } + + function appendInteger(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + } + + function appendFloat(object, html) + { + html.push('', escapeHTML(objectToString(object)), ''); + } + + function appendFunction(object, html) + { + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m ? m[1] : "function"; + html.push('', escapeHTML(name), '()'); + } + + function appendObject(object, html) + { + try + { + if (object == undefined) + appendNull("undefined", html); + else if (object == null) + appendNull("null", html); + else if (typeof object == "string") + appendString(object, html); + else if (typeof object == "number") + appendInteger(object, html); + else if (typeof object == "function") + appendFunction(object, html); + else if (object.nodeType == 1) + appendSelector(object, html); + else if (typeof object == "object") + appendObjectFormatted(object, html); + else + appendText(object, html); + } + catch (exc) + { + } + } + + function appendObjectFormatted(object, html) + { + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push('', m ? m[1] : text, '') + } + + function appendSelector(object, html) + { + html.push(''); + + html.push('', escapeHTML(object.nodeName.toLowerCase()), ''); + if (object.id) + html.push('#', escapeHTML(object.id), ''); + if (object.className) + html.push('.', escapeHTML(object.className), ''); + + html.push(''); + } + + function appendNode(node, html) + { + if (node.nodeType == 1) + { + html.push( + '
    ', + '<', node.nodeName.toLowerCase(), ''); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified) + continue; + + html.push(' ', attr.nodeName.toLowerCase(), + '="', escapeHTML(attr.nodeValue), + '"') + } + + if (node.firstChild) + { + html.push('>
    '); + + for (var child = node.firstChild; child; child = child.nextSibling) + appendNode(child, html); + + html.push('
    </', + node.nodeName.toLowerCase(), '>
    '); + } + else + html.push('/>
'); + } + else if (node.nodeType == 3) + { + html.push('
', escapeHTML(node.nodeValue), + '
'); + } + } + + // ******************************************************************************************** + + function addEvent(object, name, handler) + { + if (document.all) + object.attachEvent("on"+name, handler); + else + object.addEventListener(name, handler, false); + } + + function removeEvent(object, name, handler) + { + if (document.all) + object.detachEvent("on"+name, handler); + else + object.removeEventListener(name, handler, false); + } + + function cancelEvent(event) + { + if (document.all) + event.cancelBubble = true; + else + event.stopPropagation(); + } + + function onError(msg, href, lineNo) + { + var html = []; + + var lastSlash = href.lastIndexOf("/"); + var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1); + + html.push( + '', msg, '', + '' + ); + + logRow(html, "error"); + }; + + function onKeyDown(event) + { + if (event.keyCode == 123) + toggleConsole(); + else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey + && (event.metaKey || event.ctrlKey)) + focusCommandLine(); + else + return; + + cancelEvent(event); + } + + function onSplitterMouseDown(event) + { + if (isSafari || isOpera) + return; + + addEvent(document, "mousemove", onSplitterMouseMove); + addEvent(document, "mouseup", onSplitterMouseUp); + + for (var i = 0; i < frames.length; ++i) + { + addEvent(frames[i].document, "mousemove", onSplitterMouseMove); + addEvent(frames[i].document, "mouseup", onSplitterMouseUp); + } + } + + function onSplitterMouseMove(event) + { + var win = document.all + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument.defaultView; + + var clientY = event.clientY; + if (win != win.parent) + clientY += win.frameElement ? win.frameElement.offsetTop : 0; + + var height = consoleFrame.offsetTop + consoleFrame.clientHeight; + var y = height - clientY; + + consoleFrame.style.height = y + "px"; + layout(); + } + + function onSplitterMouseUp(event) + { + removeEvent(document, "mousemove", onSplitterMouseMove); + removeEvent(document, "mouseup", onSplitterMouseUp); + + for (var i = 0; i < frames.length; ++i) + { + removeEvent(frames[i].document, "mousemove", onSplitterMouseMove); + removeEvent(frames[i].document, "mouseup", onSplitterMouseUp); + } + } + + function onCommandLineKeyDown(event) + { + if (event.keyCode == 13) + evalCommandLine(); + else if (event.keyCode == 27) + commandLine.value = ""; + } + + window.onerror = onError; + addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown); + + if (document.documentElement.getAttribute("debug") == "true") + toggleConsole(true); +})(); +} diff --git a/upload/misc/js/firebug/firebugx.js b/upload/misc/js/firebug/firebugx.js new file mode 100644 index 000000000..343686250 --- /dev/null +++ b/upload/misc/js/firebug/firebugx.js @@ -0,0 +1,10 @@ + +if (!window.console || !console.firebug) +{ + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", + "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; + + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {} +} \ No newline at end of file diff --git a/upload/misc/js/firebug/infoIcon.png b/upload/misc/js/firebug/infoIcon.png new file mode 100644 index 000000000..da1e5334c Binary files /dev/null and b/upload/misc/js/firebug/infoIcon.png differ diff --git a/upload/misc/js/firebug/warningIcon.png b/upload/misc/js/firebug/warningIcon.png new file mode 100644 index 000000000..de51084e8 Binary files /dev/null and b/upload/misc/js/firebug/warningIcon.png differ diff --git a/upload/misc/js/jquery.pack.js b/upload/misc/js/jquery.pack.js new file mode 100644 index 000000000..07b0d7339 --- /dev/null +++ b/upload/misc/js/jquery.pack.js @@ -0,0 +1,183 @@ + +// jQuery 1.4.4 +(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= +h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;kd)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, +"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, +e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, +"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ +a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, +C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, +s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, +j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, +toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== +-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; +if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", +b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& +!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& +l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H
a";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), +k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, +scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= +false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= +1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="
";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="
t
";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= +"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= +c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); +else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; +if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, +attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& +b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; +c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, +arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= +d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ +c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== +8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== +"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ +d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= +B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== +"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== +0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); +(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; +break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, +q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= +l;g.sort(w);if(h)for(var i=1;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, +m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== +true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== +g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return in[3]-0},nth:function(g,i,n){return n[3]- +0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== +i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; +if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, +g);else if(typeof g.length==="number")for(var p=g.length;n";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); +n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& +function(){var g=k,i=t.createElement("div");i.innerHTML="

";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| +p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= +t.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? +function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n0)for(var h=d;h0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= +h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): +c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, +2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, +b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& +e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/\s]+\/)>/g,P={option:[1, +""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; +else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", +prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===""&&!x?r.childNodes:[];for(o=k.length- +1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); +d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, +jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, +zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), +h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); +if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= +d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; +e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/)<[^<]*)*<\/script>/gi, +ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== +"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("
").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& +!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, +getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", +script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| +!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= +false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; +A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", +b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& +c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| +c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= +encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", +[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), +e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); +if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", +3),a,b,d);else{d=0;for(var e=this.length;d=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, +d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* +Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} +var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; +this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| +this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= +c.timers,b=0;b-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, +e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& +c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); +c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ +b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); + +// compressor [http://refresh-sf.com/yui/] + +// json [http://jollytoad.googlepages.com/json.js] +(function($){var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},s={array:function(x){var a=["["],b,f,i,l=x.length,v;for(i=0;iul").hide()}return this.filter(":has(>ul)")},applyClasses:function(d,e){this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview",function(f){if(this==f.target){e.apply(a(this).next())}}).add(a("a",this)).hoverClass();if(!d.prerendered){this.filter(":has(>ul:hidden)").addClass(b.expandable).replaceClass(b.last,b.lastExpandable);this.not(":has(>ul:hidden)").addClass(b.collapsable).replaceClass(b.last,b.lastCollapsable);var c=this.find("div."+b.hitarea);if(!c.length){c=this.prepend('
').find("div."+b.hitarea)}c.removeClass().addClass(b.hitarea).each(function(){var f="";a.each(a(this).parent().attr("class").split(" "),function(){f+=this+"-hitarea "});a(this).addClass(f)})}this.find("div."+b.hitarea).click(e)},treeview:function(d){d=a.extend({cookieId:"treeview"},d);if(d.toggle){var i=d.toggle;d.toggle=function(){return i.apply(a(this).parent()[0],arguments)}}function c(l,n){function m(o){return function(){f.apply(a("div."+b.hitarea,l).filter(function(){return o?a(this).parent("."+o).length:true}));return false}}a("a:eq(0)",n).click(m(b.collapsable));a("a:eq(1)",n).click(m(b.expandable));a("a:eq(2)",n).click(m())}function f(){a(this).parent().find(">.hitarea").swapClass(b.collapsableHitarea,b.expandableHitarea).swapClass(b.lastCollapsableHitarea,b.lastExpandableHitarea).end().swapClass(b.collapsable,b.expandable).swapClass(b.lastCollapsable,b.lastExpandable).find(">ul").heightToggle(d.animated,d.toggle);if(d.unique){a(this).parent().siblings().find(">.hitarea").replaceClass(b.collapsableHitarea,b.expandableHitarea).replaceClass(b.lastCollapsableHitarea,b.lastExpandableHitarea).end().replaceClass(b.collapsable,b.expandable).replaceClass(b.lastCollapsable,b.lastExpandable).find(">ul").heightHide(d.animated,d.toggle)}}this.data("toggler",f);function k(){function m(n){return n?1:0}var l=[];j.each(function(n,o){l[n]=a(o).is(":has(>ul:visible)")?1:0});a.cookie(d.cookieId,l.join(""),d.cookieOptions)}function e(){var l=a.cookie(d.cookieId);if(l){var m=l.split("");j.each(function(n,o){a(o).find(">ul")[parseInt(m[n])?"show":"hide"]()})}}this.addClass("treeview");var j=this.find("li").prepareBranches(d);switch(d.persist){case"cookie":var h=d.toggle;d.toggle=function(){k();if(h){h.apply(this,arguments)}};e();break;case"location":var g=this.find("a").filter(function(){return this.href.toLowerCase()==location.href.toLowerCase()});if(g.length){g.addClass("selected").parents("ul, li").add(g.next()).show()}break}j.applyClasses(d,f);if(d.control){c(this,d.control);a(d.control).show()}return this}});a.treeview={};var b=(a.treeview.classes={open:"open",closed:"closed",expandable:"expandable",expandableHitarea:"expandable-hitarea",lastExpandableHitarea:"lastExpandable-hitarea",collapsable:"collapsable",collapsableHitarea:"collapsable-hitarea",lastCollapsableHitarea:"lastCollapsable-hitarea",lastCollapsable:"lastCollapsable",lastExpandable:"lastExpandable",last:"last",hitarea:"hitarea"});a.fn.Treeview=a.fn.treeview})(jQuery); + +// scrollTo 1.4.2 [http://flesler.blogspot.com/2007/10/jqueryscrollto.html] +(function(c){var a=c.scrollTo=function(f,e,d){c(window).scrollTo(f,e,d)};a.defaults={axis:"xy",duration:parseFloat(c.fn.jquery)>=1.3?0:1};a.window=function(d){return c(window)._scrollable()};c.fn._scrollable=function(){return this.map(function(){var e=this,d=!e.nodeName||c.inArray(e.nodeName.toLowerCase(),["iframe","#document","html","body"])!=-1;if(!d){return e}var f=(e.contentWindow||e).document||e.ownerDocument||e;return c.browser.safari||f.compatMode=="BackCompat"?f.body:f.documentElement})};c.fn.scrollTo=function(f,e,d){if(typeof e=="object"){d=e;e=0}if(typeof d=="function"){d={onAfter:d}}if(f=="max"){f=9000000000}d=c.extend({},a.defaults,d);e=e||d.speed||d.duration;d.queue=d.queue&&d.axis.length>1;if(d.queue){e/=2}d.offset=b(d.offset);d.over=b(d.over);return this._scrollable().each(function(){var l=this,j=c(l),k=f,i,g={},m=j.is("html,body");switch(typeof k){case"number":case"string":if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(k)){k=b(k);break}k=c(k,this);case"object":if(k.is||k.style){i=(k=c(k)).offset()}}c.each(d.axis.split(""),function(q,r){var s=r=="x"?"Left":"Top",u=s.toLowerCase(),p="scroll"+s,o=l[p],n=a.max(l,r);if(i){g[p]=i[u]+(m?0:o-j.offset()[u]);if(d.margin){g[p]-=parseInt(k.css("margin"+s))||0;g[p]-=parseInt(k.css("border"+s+"Width"))||0}g[p]+=d.offset[u]||0;if(d.over[u]){g[p]+=k[r=="x"?"width":"height"]()*d.over[u]}}else{var t=k[u];g[p]=t.slice&&t.slice(-1)=="%"?parseFloat(t)/100*n:t}if(/^\d+$/.test(g[p])){g[p]=g[p]<=0?0:Math.min(g[p],n)}if(!q&&d.queue){if(o!=g[p]){h(d.onAfterFirst)}delete g[p]}});h(d.onAfter);function h(n){j.animate(g,e,d.easing,n&&function(){n.call(this,f,d)})}}).end()};a.max=function(j,i){var h=i=="x"?"Width":"Height",e="scroll"+h;if(!c(j).is("html,body")){return j[e]-c(j)[h.toLowerCase()]()}var g="client"+h,f=j.ownerDocument.documentElement,d=j.ownerDocument.body;return Math.max(f[e],d[e])-Math.min(f[g],d[g])};function b(d){return typeof d=="object"?d:{top:d,left:d}}})(jQuery); + +// TableSorter 2.0.3 [http://tablesorter.com] +(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:".",debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms")}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s)}else{alert(s)}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug=""}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i  ')}table.config.headerList[index]=this});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders)}return $tableHeaders}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++))}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell)}}}return arr}function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true}return false}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true}return false}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i");$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($("
").css("width",$(this).width()))});$(table).prepend(colgroup)}}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;ib)?1:0))}function sortTextDesc(a,b){return((ba)?1:0))}function sortNumeric(a,b){return a-b}function sortNumericDesc(a,b){return b-a}function getCachedSortType(parsers,i){return parsers[i].type}this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies){return}var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList])}applyWidget(this)})};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;ij){k=1}else{if(l");for(var j=0;j","g"),"");e=a.trim(e.toLowerCase());return e};this.results=function(e){if(typeof k.noResults==="string"&&k.noResults!==""){if(e){a(k.noResults).hide()}else{a(k.noResults).show()}}return this};this.loader=function(e){if(typeof k.loader==="string"&&k.loader!==""){(e)?a(k.loader).show():a(k.loader).hide()}return this};this.test=function(m,l){for(var e=0;e>>(32-b))};var m=function(a,b){var c,lY4,lX8,lY8,lResult;lX8=(a&0x80000000);lY8=(b&0x80000000);c=(a&0x40000000);lY4=(b&0x40000000);lResult=(a&0x3FFFFFFF)+(b&0x3FFFFFFF);if(c&lY4){return(lResult^0x80000000^lX8^lY8)}if(c|lY4){if(lResult&0x40000000){return(lResult^0xC0000000^lX8^lY8)}else{return(lResult^0x40000000^lX8^lY8)}}else{return(lResult^lX8^lY8)}};var F=function(x,y,z){return(x&y)|((~x)&z)};var G=function(x,y,z){return(x&z)|(y&(~z))};var H=function(x,y,z){return(x^y^z)};var I=function(x,y,z){return(y^(x|(~z)))};var n=function(a,b,c,d,x,s,e){a=m(a,m(m(F(b,c,d),x),e));return m(l(a,s),b)};var o=function(a,b,c,d,x,s,e){a=m(a,m(m(G(b,c,d),x),e));return m(l(a,s),b)};var p=function(a,b,c,d,x,s,e){a=m(a,m(m(H(b,c,d),x),e));return m(l(a,s),b)};var q=function(a,b,c,d,x,s,e){a=m(a,m(m(I(b,c,d),x),e));return m(l(a,s),b)};var r=function(a){var b;var c=a.length;var d=c+8;var e=(d-(d%64))/64;var f=(e+1)*16;var g=Array(f-1);var h=0;var i=0;while(i>>29;return g};var t=function(a){var b="",WordToHexValue_temp="",lByte,lCount;for(lCount=0;lCount<=3;lCount++){lByte=(a>>>(lCount*8))&255;WordToHexValue_temp="0"+lByte.toString(16);b=b+WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2)}return b};var x=Array();var k,AA,BB,CC,DD,a,b,c,d;var u=7,S12=12,S13=17,S14=22;var v=5,S22=9,S23=14,S24=20;var w=4,S32=11,S33=16,S34=23;var A=6,S42=10,S43=15,S44=21;j=this.utf8_encode(j);x=r(j);a=0x67452301;b=0xEFCDAB89;c=0x98BADCFE;d=0x10325476;for(k=0;k127)&&(c<2048)){b[ac++]=String.fromCharCode((c>>6)|192);b[ac++]=String.fromCharCode((c&63)|128)}else{b[ac++]=String.fromCharCode((c>>12)|224);b[ac++]=String.fromCharCode(((c>>6)&63)|128);b[ac++]=String.fromCharCode((c&63)|128)}}return b.join('')}};window.$P=C()})(); + +// SWFObject 1.5.1 [http://blog.deconcept.com/swfobject/] +if(typeof deconcept=="undefined"){var deconcept={};}if(typeof deconcept.util=="undefined"){deconcept.util={};}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil={};}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params={};this.variables={};this.attributes=[];if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10]||"";},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15]||"";},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=[];var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="";_19+="";var _1d=this.getParams();for(var key in _1d){_19+="";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="";}_19+="";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.majorfv.major){return true;}if(this.minorfv.minor){return true;}if(this.rev=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject; diff --git a/upload/misc/js/main.js b/upload/misc/js/main.js new file mode 100644 index 000000000..b764e14d7 --- /dev/null +++ b/upload/misc/js/main.js @@ -0,0 +1,515 @@ +/** + * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ + * + * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + */ +if(typeof deconcept=="undefined"){var deconcept=new Object();}if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a){if(!document.getElementById){return;}this.DETECT_KEY=_a?_a:"detectflash";this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);this.params=new Object();this.variables=new Object();this.attributes=new Array();if(_1){this.setAttribute("swf",_1);}if(id){this.setAttribute("id",id);}if(w){this.setAttribute("width",w);}if(h){this.setAttribute("height",h);}if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&&document.all&&this.installedVer.major>7){deconcept.SWFObject.doPrepUnload=true;}if(c){this.addParam("bgcolor",c);}var q=_7?_7:"high";this.addParam("quality",q);this.setAttribute("useExpressInstall",false);this.setAttribute("doExpressInstall",false);var _c=(_8)?_8:window.location;this.setAttribute("xiRedirectUrl",_c);this.setAttribute("redirectUrl","");if(_9){this.setAttribute("redirectUrl",_9);}};deconcept.SWFObject.prototype={useExpressInstall:function(_d){this.xiSWFPath=!_d?"expressinstall.swf":_d;this.setAttribute("useExpressInstall",true);},setAttribute:function(_e,_f){this.attributes[_e]=_f;},getAttribute:function(_10){return this.attributes[_10];},addParam:function(_11,_12){this.params[_11]=_12;},getParams:function(){return this.params;},addVariable:function(_13,_14){this.variables[_13]=_14;},getVariable:function(_15){return this.variables[_15];},getVariables:function(){return this.variables;},getVariablePairs:function(){var _16=new Array();var key;var _18=this.getVariables();for(key in _18){_16[_16.length]=key+"="+_18[key];}return _16;},getSWFHTML:function(){var _19="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");this.setAttribute("swf",this.xiSWFPath);}_19="0){_19+="flashvars=\""+_1c+"\"";}_19+="/>";}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");this.setAttribute("swf",this.xiSWFPath);}_19="";_19+="";var _1d=this.getParams();for(var key in _1d){_19+="";}var _1f=this.getVariablePairs().join("&");if(_1f.length>0){_19+="";}_19+="";}return _19;},write:function(_20){if(this.getAttribute("useExpressInstall")){var _21=new deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){this.setAttribute("doExpressInstall",true);this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));document.title=document.title.slice(0,47)+" - Flash Player Installation";this.addVariable("MMdoctitle",document.title);}}if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){var n=(typeof _20=="string")?document.getElementById(_20):_20;n.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}return false;}};deconcept.SWFObjectUtil.getPlayerVersion=function(){var _23=new deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&&navigator.mimeTypes.length){var x=navigator.plugins["Shockwave Flash"];if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}}else{if(navigator.userAgent&&navigator.userAgent.indexOf("Windows CE")>=0){var axo=1;var _26=3;while(axo){try{_26++;axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+_26);_23=new deconcept.PlayerVersion([_26,0,0]);}catch(e){axo=null;}}}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";}catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}}}return _23;};deconcept.PlayerVersion=function(_29){this.major=_29[0]!=null?parseInt(_29[0]):0;this.minor=_29[1]!=null?parseInt(_29[1]):0;this.rev=_29[2]!=null?parseInt(_29[2]):0;};deconcept.PlayerVersion.prototype.versionIsValid=function(fv){if(this.majorfv.major){return true;}if(this.minorfv.minor){return true;}if(this.rev=0;i--){_2f[i].style.display="none";for(var x in _2f[i]){if(typeof _2f[i][x]=="function"){_2f[i][x]=function(){};}}}};if(deconcept.SWFObject.doPrepUnload){if(!deconcept.unloadSet){deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window.attachEvent("onunload",deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent("onbeforeunload",deconcept.SWFObjectUtil.prepUnload);deconcept.unloadSet=true;}}if(!document.getElementById&&document.all){document.getElementById=function(id){return document.all[id];};}var getQueryParamValue=deconcept.util.getRequestParameter;var FlashObject=deconcept.SWFObject;var SWFObject=deconcept.SWFObject; + +// prototype $ +function $p() { + var elements = new Array(); + + for (var i = 0; i < arguments.length; i++) { + var element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + + if (arguments.length == 1) + return element; + + elements.push(element); + } + + return elements; +} + +// from http://www.dustindiaz.com/rock-solid-addevent/ +function addEvent( obj, type, fn ) { + if (obj.addEventListener) { + obj.addEventListener( type, fn, false ); + EventCache.add(obj, type, fn); + } + else if (obj.attachEvent) { + obj["e"+type+fn] = fn; + obj[type+fn] = function() { obj["e"+type+fn]( window.event ); } + obj.attachEvent( "on"+type, obj[type+fn] ); + EventCache.add(obj, type, fn); + } + else { + obj["on"+type] = obj["e"+type+fn]; + } +} + +var EventCache = function(){ + var listEvents = []; + return { + listEvents : listEvents, + add : function(node, sEventName, fHandler){ + listEvents.push(arguments); + }, + flush : function(){ + var i, item; + for(i = listEvents.length - 1; i >= 0; i = i - 1){ + item = listEvents[i]; + if(item[0].removeEventListener){ + item[0].removeEventListener(item[1], item[2], item[3]); + }; + if(item[1].substring(0, 2) != "on"){ + item[1] = "on" + item[1]; + }; + if(item[0].detachEvent){ + item[0].detachEvent(item[1], item[2]); + }; + item[0][item[1]] = null; + }; + } + }; +}(); +if (document.all) { addEvent(window,'unload',EventCache.flush); } + +function imgFit (img, maxW) +{ + if (typeof(img.naturalHeight) == 'undefined') { + img.naturalHeight = img.height; + img.naturalWidth = img.width; + } +//alert(img.src+'\n\n'+'H: '+img.height+' natH: '+img.naturalHeight+'\n'+'W: '+img.width+' natW: '+img.naturalWidth+' maxW: '+maxW); + if (img.width > maxW) { + img.height = Math.round((maxW/img.width)*img.height); + img.width = maxW; + img.title = 'Click image to view full size'; + img.style.cursor = 'move'; + return false; + } + else if (img.width == maxW && img.width < img.naturalWidth) { + img.height = img.naturalHeight; + img.width = img.naturalWidth; + img.title = 'Click to fit in the browser window'; + return false; + } + else { + return true; + } +} + +function toggle_block (id) +{ + var el = document.getElementById(id); + el.style.display = (el.style.display == 'none') ? '' : 'none'; +} + +function toggle_disabled (id, val) +{ + document.getElementById(id).disabled = (val) ? 0 : 1; +} + +function rand (min, max) +{ + return min + Math.floor((max - min + 1) * Math.random()); +} + +// +// Cookie functions [based on ???] +// +/** + * name Name of the cookie + * value Value of the cookie + * [days] Number of days to remain active (default: end of current session) + * [path] Path where the cookie is valid (default: path of calling document) + * [domain] Domain where the cookie is valid + * (default: domain of calling document) + * [secure] Boolean value indicating if the cookie transmission requires a + * secure transmission + */ +function setCookie (name, value, days, path, domain, secure) +{ + if (days != 'SESSION') { + var date = new Date(); + days = days || 365; + date.setTime(date.getTime() + days*24*60*60*1000); + var expires = date.toGMTString(); + } else { + var expires = ''; + } + + document.cookie = + name +'='+ escape(value) + + ((expires) ? '; expires='+ expires : '') + + ((path) ? '; path='+ path : ((cookiePath) ? '; path='+ cookiePath : '')) + + ((domain) ? '; domain='+ domain : ((cookieDomain) ? '; domain='+ cookieDomain : '')) + + ((secure) ? '; secure' : ((cookieSecure) ? '; secure' : '')); +} + +/** + * Returns a string containing value of specified cookie, + * or null if cookie does not exist. + */ +function getCookie (name) +{ + var c, RE = new RegExp('(^|;)\\s*'+ name +'\\s*=\\s*([^\\s;]+)', 'g'); + return (c = RE.exec(document.cookie)) ? c[2] : null; +} + +/** + * name name of the cookie + * [path] path of the cookie (must be same as path used to create cookie) + * [domain] domain of the cookie (must be same as domain used to create cookie) + */ +function deleteCookie (name, path, domain) +{ + setCookie(name, '', -1, path, domain); +} + +// Simple Javascript Browser/OS detection (based on "Harald Hope, Tapio Markula, http://techpatterns.com ver 2.0.1") +var ua = navigator.userAgent; + +var os_win = ( navigator.appVersion.indexOf( 'Win' ) != -1 ); +var os_mac = ( navigator.appVersion.indexOf( 'Mac' ) != -1 ); +var os_lin = ( ua.indexOf( 'Linux' ) != -1 ); + +var is_opera = ( ua.indexOf( 'Opera' ) != -1 ); +var is_konq = ( ua.indexOf( 'Konqueror' ) != -1 ); +var is_saf = ( ua.indexOf( 'Safari' ) != -1 ); +var is_moz = ( ua.indexOf( 'Gecko' ) != -1 && !is_saf && !is_konq); +var is_ie = ( document.all && !is_opera ); +var is_ie4 = ( is_ie && !document.getElementById ); + +// ie5x tests only for functionality +// Opera will register true in this test if set to identify as IE 5 +var is_ie5x = ( document.all && document.getElementById ); +var os_ie5mac = ( os_mac && is_ie5x ); +var os_ie5xwin = ( os_win && is_ie5x ); + +// Copy text to clipboard. Originally got from decompiled `php_manual_en.chm`. +function ie_copyTextToClipboard (fromNode) +{ + var txt = document.body.createTextRange(); + txt.moveToElementText(fromNode); + return txt.execCommand("Copy"); +} + +// Clickable LABELs in IE +// based on http://web.tampabay.rr.com/bmerkey/examples/clickable-labels.html +function ie6_make_clickable_labels () +{ + var labels = document.getElementsByTagName("label"); + for (var i=0, len=labels.length; i'); + fixSqlLog(); + } + if (response.update_ids) { + for (id in response.update_ids) { + $('#'+id).html( response.update_ids[id] ); + } + } + if (response.prompt_password) { + var user_password = prompt('Please enter your password (for mod/admin session)', ''); + if (user_password) { + var req = ajax.request[action]; + req.user_password = user_password; + ajax.exec(req); + } + else { + ajax.clearActionState(action); + ajax.showErrorMsg('Wrong password'); + } + } + else if (response.prompt_confirm) { + if (window.confirm(response.confirm_msg)) { + var req = ajax.request[action]; + req.confirmed = 1; + ajax.exec(req); + } + else { + ajax.clearActionState(action); + } + } + else if (response.error_code) { + ajax.showErrorMsg(response.error_msg); + $('.loading-1').removeClass('loading-1').html('error'); + } + else { + ajax.callback[action](response); + ajax.clearActionState(action); + } + }, + + error: function(xml, desc) { + }, + + clearActionState: function(action){ + ajax.state[action] = ajax.request[action] = ''; + }, + + showErrorMsg: function(msg){ + alert(msg); + }, + + callInitFn: function(event) { + event.stopPropagation(); + var params = ajax.params[$(this).attr('id')]; + var action = params.action; + if (ajax.state[action] == 'readyToSubmit' || ajax.state[action] == 'error') { + return false; + } else { + ajax.state[action] = 'readyToSubmit'; + } + ajax.init[action](params); + }, + + setStatusBoxPosition: function($el) { + var newTop = $(document).scrollTop(); + var rCorner = $(document).scrollLeft() + $(window).width() - ($.browser.opera ? 14 : 8); + var newLeft = Math.max(0, rCorner - $el.width()); + $el.css({ top: newTop, left: newLeft }); + }, + + makeEditable: function(rootElementId, editableType) { + var $root = $('#'+rootElementId); + var $editable = $('.editable', $root); + var inputsHtml = $('#editable-tpl-'+editableType).html(); + $editable.hide().after(inputsHtml); + var $inputs = $('.editable-inputs', $root); + if (editableType == 'input' || editableType == 'textarea') { + $('.editable-value', $inputs).val( $.trim($editable.text()) ); + } + $('input.editable-submit', $inputs).click(function(){ + var params = ajax.params[rootElementId]; + var $val = $('.editable-value', '#'+rootElementId); + params.value = ($val.size() == 1) ? $val.val() : $val.filter('[checked]').val(); + params.submit = true; + ajax.init[params.action](params); + }); + $('input.editable-cancel', $inputs).click(function(){ + ajax.restoreEditable(rootElementId); + }); + $inputs.show().find('.editable-value').focus(); + $root.removeClass('editable-container'); + }, + + restoreEditable: function(rootElementId, newValue) { + var $root = $('#'+rootElementId); + var $editable = $('.editable', $root); + $('.editable-inputs', $root).remove(); + if (newValue) { + $editable.text(newValue); + } + $editable.show(); + ajax.clearActionState( ajax.params[rootElementId].action ); + ajax.params[rootElementId].submit = false; + $root.addClass('editable-container'); + } +}; + +$(document).ready(function(){ + // Setup ajax-loading box + $("#ajax-loading").ajaxStart(function(){ + $("#ajax-error").hide(); + $(this).show(); + ajax.setStatusBoxPosition($(this)); + }); + $("#ajax-loading").ajaxStop(function(){ $(this).hide(); }); + + // Setup ajax-error box + $("#ajax-error").ajaxError(function(req, xml){ + var status = xml.status; + var text = xml.statusText; + if (status == 200) { + status = ''; + text = 'invalid data format'; + } + $(this).html( + "Ajax error in: "+ ajax.url +"
"+ status +" "+ text +"" + ).show(); + ajax.setStatusBoxPosition($(this)); + }); + + // Bind ajax events + $('var.ajax-params').each(function(){ + var params = $.evalJSON( $(this).html() ); + params.event = params.event || 'dblclick'; + ajax.params[params.id] = params; + $("#"+params.id).bind(params.event, ajax.callInitFn); + if (params.event == 'click' || params.event == 'dblclick') { + $("#"+params.id).addClass('editable-container'); + } + }); +}); diff --git a/upload/misc/js/source/jquery.js b/upload/misc/js/source/jquery.js new file mode 100644 index 000000000..462cde56c --- /dev/null +++ b/upload/misc/js/source/jquery.js @@ -0,0 +1,4376 @@ +/*! + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){ + +var + // Will speed up references to window, and allows munging its name. + window = this, + // Will speed up references to undefined, and allows munging its name. + undefined, + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + // Map over the $ in case of overwrite + _$ = window.$, + + jQuery = window.jQuery = window.$ = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/, + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + this.context = selector; + return this; + } + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem && elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + var ret = jQuery( elem || [] ); + ret.context = document; + ret.selector = selector; + return ret; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return jQuery( document ).ready( selector ); + + // Make sure that old selector state is passed along + if ( selector.selector && selector.context ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return this.setArray(jQuery.isArray( selector ) ? + selector : + jQuery.makeArray(selector)); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.3.2", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num === undefined ? + + // Return a 'clean' array + Array.prototype.slice.call( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) + ret.selector = this.selector + (this.selector ? " " : "") + selector; + else if ( name ) + ret.selector = this.selector + "." + name + "(" + selector + ")"; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem && elem.jquery ? elem[0] : elem + , this ); + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( typeof name === "string" ) + if ( value === undefined ) + return this[0] && jQuery[ type || "attr" ]( this[0], name ); + + else { + options = {}; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text !== "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).clone(); + + if ( this[0].parentNode ) + wrap.insertBefore( this[0] ); + + wrap.map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }).append(this); + } + + return this; + }, + + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + + append: function() { + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: [].push, + sort: [].sort, + splice: [].splice, + + find: function( selector ) { + if ( this.length === 1 ) { + var ret = this.pushStack( [], "find", selector ); + ret.length = 0; + jQuery.find( selector, this[0], ret ); + return ret; + } else { + return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + })), "find", selector ); + } + }, + + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var html = this.outerHTML; + if ( !html ) { + var div = this.ownerDocument.createElement("div"); + div.appendChild( this.cloneNode(true) ); + html = div.innerHTML; + } + + return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0]; + } else + return this.cloneNode(true); + }); + + // Copy the events from the original to the clone + if ( events === true ) { + var orig = this.find("*").andSelf(), i = 0; + + ret.find("*").andSelf().each(function(){ + if ( this.nodeName !== orig[i].nodeName ) + return; + + var events = jQuery.data( orig[i], "events" ); + + for ( var type in events ) { + for ( var handler in events[ type ] ) { + jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data ); + } + } + + i++; + }); + } + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + + jQuery.multiFilter( selector, jQuery.grep(this, function(elem){ + return elem.nodeType === 1; + }) ), "filter", selector ); + }, + + closest: function( selector ) { + var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null, + closer = 0; + + return this.map(function(){ + var cur = this; + while ( cur && cur.ownerDocument ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) { + jQuery.data(cur, "closest", closer); + return cur; + } + cur = cur.parentNode; + closer++; + } + }); + }, + + not: function( selector ) { + if ( typeof selector === "string" ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return this.pushStack( jQuery.unique( jQuery.merge( + this.get(), + typeof selector === "string" ? + jQuery( selector ) : + jQuery.makeArray( selector ) + ))); + }, + + is: function( selector ) { + return !!selector && jQuery.multiFilter( selector, this ).length > 0; + }, + + hasClass: function( selector ) { + return !!selector && this.is( "." + selector ); + }, + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if( jQuery.nodeName( elem, 'option' ) ) + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(/\r/g, ""); + + } + + return undefined; + } + + if ( typeof value === "number" ) + value += ''; + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(value); + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value === undefined ? + (this[0] ? + this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") : + null) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, +i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ), + "slice", Array.prototype.slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function( args, table, callback ) { + if ( this[0] ) { + var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(), + scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ), + first = fragment.firstChild; + + if ( first ) + for ( var i = 0, l = this.length; i < l; i++ ) + callback.call( root(this[i], first), this.length > 1 || i > 0 ? + fragment.cloneNode(true) : fragment ); + + if ( scripts ) + jQuery.each( scripts, evalScript ); + } + + return this; + + function root( elem, cur ) { + return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ? + (elem.getElementsByTagName("tbody")[0] || + elem.appendChild(elem.ownerDocument.createElement("tbody"))) : + elem; + } + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +function now(){ + return +new Date; +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) + target = {}; + + // extend jQuery itself if only one argument is passed + if ( length == i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) + continue; + + // Recurse if we're merging object values + if ( deep && copy && typeof copy === "object" && !copy.nodeType ) + target[ name ] = jQuery.extend( deep, + // Never move original objects, clone them + src || ( copy.length != null ? [ ] : { } ) + , copy ); + + // Don't bring in undefined values + else if ( copy !== undefined ) + target[ name ] = copy; + + } + + // Return the modified object + return target; +}; + +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, + // cache defaultView + defaultView = document.defaultView || {}, + toString = Object.prototype.toString; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call(obj) === "[object Function]"; + }, + + isArray: function( obj ) { + return toString.call(obj) === "[object Array]"; + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument ); + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && /\S/.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + if ( jQuery.support.scriptEval ) + script.appendChild( document.createTextNode( data ) ); + else + script.text = data; + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, length = object.length; + + if ( args ) { + if ( length === undefined ) { + for ( name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( ; i < length; ) + if ( callback.apply( object[ i++ ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( length === undefined ) { + for ( name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames !== undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + + // internal only, use hasClass("class") + has: function( elem, className ) { + return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force, extra ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + + if ( extra === "border" ) + return; + + jQuery.each( which, function() { + if ( !extra ) + val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + if ( extra === "margin" ) + val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0; + else + val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + } + + if ( elem.offsetWidth !== 0 ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max(0, Math.round(val)); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret, style = elem.style; + + // We need to handle opacity special in IE + if ( name == "opacity" && !jQuery.support.opacity ) { + ret = jQuery.attr( style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + + if ( !force && style && style[ name ] ) + ret = style[ name ]; + + else if ( defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + + var computedStyle = defaultView.getComputedStyle( elem, null ); + + if ( computedStyle ) + ret = computedStyle.getPropertyValue( name ); + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + style.left = ret || 0; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; + } + } + + return ret; + }, + + clean: function( elems, context, fragment ) { + context = context || document; + + // !context.createElement fails in IE with an error but returns typeof 'object' + if ( typeof context.createElement === "undefined" ) + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { + var match = /^<(\w+)\s*\/?>$/.exec(elems[0]); + if ( match ) + return [ context.createElement( match[1] ) ]; + } + + var ret = [], scripts = [], div = context.createElement("div"); + + jQuery.each(elems, function(i, elem){ + if ( typeof elem === "number" ) + elem += ''; + + if ( !elem ) + return; + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase(); + + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "
", "
" ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and This is a p

+ * @before $.metadata.setType("elem", "script") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a nested script element + * + * @param String type The encoding type + * @param String name The name of the attribute to be used to get metadata (optional) + * @cat Plugins/Metadata + * @descr Sets the type of encoding to be used when loading metadata for the first time + * @type undefined + * @see metadata() + */ + +(function($) { + +$.extend({ + metadata : { + defaults : { + type: 'class', + name: 'metadata', + cre: /({.*})/, + single: 'metadata' + }, + setType: function( type, name ){ + this.defaults.type = type; + this.defaults.name = name; + }, + get: function( elem, opts ){ + var settings = $.extend({},this.defaults,opts); + // check for empty string in single property + if ( !settings.single.length ) settings.single = 'metadata'; + + var data = $.data(elem, settings.single); + // returned cached data if it already exists + if ( data ) return data; + + data = "{}"; + + if ( settings.type == "class" ) { + var m = settings.cre.exec( elem.className ); + if ( m ) + data = m[1]; + } else if ( settings.type == "elem" ) { + if( !elem.getElementsByTagName ) return; + var e = elem.getElementsByTagName(settings.name); + if ( e.length ) + data = $.trim(e[0].innerHTML); + } else if ( elem.getAttribute != undefined ) { + var attr = elem.getAttribute( settings.name ); + if ( attr ) + data = attr; + } + + if ( data.indexOf( '{' ) <0 ) + data = "{" + data + "}"; + + data = eval("(" + data + ")"); + + $.data( elem, settings.single, data ); + return data; + } + } +}); + +/** + * Returns the metadata object for the first member of the jQuery object. + * + * @name metadata + * @descr Returns element's metadata object + * @param Object opts An object contianing settings to override the defaults + * @type jQuery + * @cat Plugins/Metadata + */ +$.fn.metadata = function( opts ){ + return $.metadata.get( this[0], opts ); +}; + +})(jQuery); \ No newline at end of file diff --git a/upload/misc/js/source/sprintf.js b/upload/misc/js/source/sprintf.js new file mode 100644 index 000000000..93c22a1b9 --- /dev/null +++ b/upload/misc/js/source/sprintf.js @@ -0,0 +1,182 @@ +/* Copyright (c) 2005 Scott S. McCoy + * This was originally a non-object oriented interface + * Function printf(format_string,arguments...) + * Javascript emulation of the C printf function (modifiers and argument types + * "p" and "n" are not supported due to language restrictions) + * + * Copyright 2003 K&L Productions. All rights reserved + * http://www.klproductions.com + * + * Terms of use: This function can be used free of charge IF this header is not + * modified and remains with the function code. + * + * Legal: Use this code at your own risk. K&L Productions assumes NO resposibility + * for anything. + ********************************************************************************/ + +String.prototype.sprintf = function () { + var fstring = this.toString(); + + var pad = function(str,ch,len) { var ps=''; + for(var i=0; i0?str+ps:ps+str; + }; + var processFlags = function(flags,width,rs,arg) { + var pn = function(flags,arg,rs) { + if(arg>=0) { + if(flags.indexOf(' ')>=0) { + rs = ' ' + rs; + } else if(flags.indexOf('+')>=0) { + rs = '+' + rs; + } + } else { + rs = '-' + rs; + } + return rs; + }; + var iWidth = parseInt(width,10); + if(width.charAt(0) == '0') { + var ec=0; + if(flags.indexOf(' ')>=0 || flags.indexOf('+')>=0) { + ec++; + } + if(rs.length<(iWidth-ec)) { + rs = pad(rs,'0',rs.length-(iWidth-ec)); + } + return pn(flags,arg,rs); + } + rs = pn(flags,arg,rs); + if(rs.length=0) { + rs = rs.replace(/^(.*)(e.*)$/,'$1.$2'); + } + return processFlags(flags,width,rs,arg); + }; + converters.f = function(flags,width,precision,arg) { + iPrecision = parseInt(precision, 10); + if(isNaN(iPrecision)) { + iPrecision = 6; + } + rs = (Math.abs(arg)).toFixed(iPrecision); + if(rs.indexOf('.')<0 && flags.indexOf('#')>=0) { + rs = rs + '.'; + } + return processFlags(flags,width,rs,arg); + }; + converters.G = function(flags,width,precision,arg) { + return (converters.g(flags,width,precision,arg)).toUpperCase(); + }; + converters.g = function(flags,width,precision,arg) { + iPrecision = parseInt(precision, 10); + absArg = Math.abs(arg); + rse = absArg.toExponential(); + rsf = absArg.toFixed(6); + if(!isNaN(iPrecision)) { + rsep = absArg.toExponential(iPrecision); + rse = rsep.length < rse.length ? rsep : rse; + rsfp = absArg.toFixed(iPrecision); + rsf = rsfp.length < rsf.length ? rsfp : rsf; + } + if(rse.indexOf('.')<0 && flags.indexOf('#')>=0) { + rse = rse.replace(/^(.*)(e.*)$/,'$1.$2'); + } + if(rsf.indexOf('.')<0 && flags.indexOf('#')>=0) { + rsf = rsf + '.'; + } + rs = rse.length=0) { + rs='0'+rs; + } + return processFlags(flags,width,rs,arg); + }; + converters.X = function(flags,width,precision,arg) { + return (converters.x(flags,width,precision,arg)).toUpperCase(); + }; + converters.x = function(flags,width,precision,arg) { + var iPrecision=parseInt(precision, 10); + arg = Math.abs(arg); + var rs = Math.round(arg).toString(16); + if(rs.length=0) { + rs='0x'+rs; + } + return processFlags(flags,width,rs,arg); + }; + converters.s = function(flags,width,precision,arg) { + var iPrecision=parseInt(precision, 10); + var rs = arg; + if(rs.length > iPrecision) { + rs = rs.substring(0,iPrecision); + } + return processFlags(flags,width,rs,0); + }; + + farr = fstring.split('%'); + retstr = farr[0]; + fpRE = /^([-+ #]*)(?:(\d*)\$|)(\d*)\.?(\d*)([cdieEfFgGosuxX])(.*)$/; + for(var i = 1; i', ''); + $message .= '

'; + } + else if (count($req_topics) != 1) + { + $message .= sprintf($lang['CLICK_RETURN_MODCP'], '', ''); + $message .= '

'; + } + + $message .= sprintf($lang['CLICK_RETURN_FORUM'], '', ''); + + return $message; +} + +function validate_topics ($forum_id, &$req_topics, &$topic_titles) +{ + $valid_topics = $valid_titles = array(); + + if ($topic_csv = get_id_csv($req_topics)) + { + $sql = "SELECT topic_id, topic_title FROM ". BB_TOPICS ." WHERE topic_id IN($topic_csv) AND forum_id = $forum_id"; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $valid_topics[] = $row['topic_id']; + $valid_titles[] = $row['topic_title']; + } + } + + $req_topics = $valid_topics; + $topic_titles = $valid_titles; +} + +// Obtain initial vars +$forum_id = (int) @$_REQUEST['f']; +$topic_id = (int) @$_REQUEST['t']; +$post_id = (int) @$_REQUEST['p']; + +$start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; +$confirmed = isset($_POST['confirm']); + +$mode = $topic_title = ''; + +if (isset($_REQUEST['mode'])) +{ + $mode = (string) $_REQUEST['mode']; +} +else +{ + if (isset($_REQUEST['delete']) || @$_POST['mod_action'] === 'topic_delete') + { + $mode = 'delete'; + } + else if (isset($_REQUEST['move']) || @$_POST['mod_action'] === 'topic_move') + { + $mode = 'move'; + } + else if (isset($_REQUEST['lock']) || @$_POST['mod_action'] === 'topic_lock') + { + $mode = 'lock'; + } + else if (isset($_REQUEST['unlock']) || @$_POST['mod_action'] === 'topic_unlock') + { + $mode = 'unlock'; + } +} + +// Obtain relevant data +if ($topic_id) +{ + $sql = " + SELECT + f.forum_id, f.forum_name, f.forum_topics, f.self_moderated, + t.topic_first_post_id, t.topic_poster + FROM ". BB_TOPICS ." t, ". BB_FORUMS ." f + WHERE t.topic_id = $topic_id + AND f.forum_id = t.forum_id + LIMIT 1 + "; + + if (!$topic_row = DB()->fetch_row($sql)) + { + message_die(GENERAL_MESSAGE, 'Topic_post_not_exist'); + } + + $forum_id = $topic_row['forum_id']; + $forum_name = $topic_row['forum_name']; + $forum_topics = (!$topic_row['forum_topics']) ? 1 : $topic_row['forum_topics']; +} +else if ($forum_id) +{ + $sql = "SELECT forum_name, forum_topics FROM ". BB_FORUMS ." WHERE forum_id = $forum_id LIMIT 1"; + + if (!$topic_row = DB()->fetch_row($sql)) + { + message_die(GENERAL_MESSAGE, 'Forum_not_exist'); + } + + $forum_name = $topic_row['forum_name']; + $forum_topics = (!$topic_row['forum_topics']) ? 1 : $topic_row['forum_topics']; +} +else +{ + message_die(GENERAL_MESSAGE, 'Invalid request'); +} + +// Start session management +$user->session_start(array('req_login' => true)); + +// Check if user did or did not confirm. If they did not, forward them to the last page they were on +if (isset($_POST['cancel']) || IS_GUEST) +{ + $redirect = "index.php"; + + if ($topic_id || $forum_id) + { + $redirect = ($topic_id) ? TOPIC_URL . $topic_id : FORUM_URL . $forum_id; + } + redirect($redirect); +} + +// Start auth check +$is_auth = auth(AUTH_ALL, $forum_id, $userdata); +$is_moderator = (IS_MOD || IS_ADMIN); + +if ($mode == 'ip') +{ + // Moderator can view IP in all forums + $is_auth['auth_mod'] = $is_moderator; +} +else if ($mode == 'move' && !$is_auth['auth_mod']) +{ + // User can move his own topic if this forum is "self_moderated" + if ($topic_id && $topic_row['self_moderated'] && $topic_row['topic_poster'] == $userdata['user_id']) + { + $is_auth['auth_mod'] = true; + + $_POST['insert_bot_msg'] = 1; + unset($_POST['topic_id_list']); + unset($_POST['move_leave_shadow']); + } +} + +// Exit if user not authorized +if (!$is_auth['auth_mod']) +{ + message_die(GENERAL_MESSAGE, $lang['NOT_MODERATOR'], $lang['NOT_AUTHORISED']); +} + +// Redirect to login page if not admin session +if ($is_moderator && !$userdata['session_admin']) +{ + $redirect = isset($_POST['redirect']) ? $_POST['redirect'] : $_SERVER['REQUEST_URI']; + redirect("login.php?redirect=$redirect&admin=1"); +} + +// +// Get required vars +// +$req_topics = $topic_csv = $topic_titles = $hidden_fields = array(); + +switch ($mode) +{ + case 'delete': + case 'move': + case 'lock': + case 'unlock': + case 'set_download': + case 'unset_download': + + if (empty($_POST['topic_id_list']) && empty($topic_id)) + { + message_die(GENERAL_MESSAGE, $lang['NONE_SELECTED']); + } + + $req_topics = isset($_POST['topic_id_list']) ? $_POST['topic_id_list'] : $topic_id; + validate_topics($forum_id, &$req_topics, &$topic_titles); + + if (!$req_topics OR !$topic_csv = get_id_csv($req_topics)) + { + message_die(GENERAL_MESSAGE, $lang['NONE_SELECTED']); + } + + $hidden_fields = array( + 'sid' => $userdata['session_id'], + 'mode' => $mode, + 'f' => $forum_id, + 't' => $topic_id, + ); + foreach ($req_topics as $req_topic_id) + { + $hidden_fields['topic_id_list'][] = $req_topic_id; + } + + break; +} + +// +// Perform action or show confirm message +// +switch ($mode) +{ + case 'delete': + + if (!$is_auth['auth_delete']) + { + message_die(GENERAL_MESSAGE, sprintf($lang['SORRY_AUTH_DELETE'], $is_auth['auth_delete_type'])); + } + + if ($confirmed) + { + $result = topic_delete($req_topics, $forum_id); + + $msg = ($result) ? $lang['TOPICS_REMOVED'] : 'No topics were removed'; + message_die(GENERAL_MESSAGE, return_msg_mcp($msg)); + } + else + { + print_confirmation(array( + 'QUESTION' => $lang['CONFIRM_DELETE_TOPIC'], + 'ITEMS_LIST' => join("\n\n
  • \n", $topic_titles), + 'FORM_ACTION' => "modcp.php", + 'HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + )); + } + break; + + case 'move': + + if ($confirmed) + { + $result = topic_move($req_topics, $_POST['new_forum'], $forum_id, isset($_POST['move_leave_shadow']), isset($_POST['insert_bot_msg'])); + + $msg = ($result) ? $lang['TOPICS_MOVED'] : $lang['NO_TOPICS_MOVED']; + message_die(GENERAL_MESSAGE, return_msg_mcp($msg)); + } + else + { + if (IS_ADMIN) + { + $forum_select_mode = 'admin'; + } + else + { + $not_auth_forums_csv = $user->get_not_auth_forums(AUTH_VIEW); + $forum_select_mode = explode(',', $not_auth_forums_csv); + } + + $forum_select = get_forum_select($forum_select_mode, 'new_forum', $forum_id); + + $template->assign_vars(array( + 'TPL_MODCP_MOVE' => true, + 'SHOW_LEAVESHADOW' => $is_moderator, + 'SHOW_BOT_OPTIONS' => $is_moderator, + 'L_LEAVE_MSG' => $lang['BOT_LEAVE_MSG_MOVED'], + + 'MESSAGE_TITLE' => $lang['CONFIRM'], + 'MESSAGE_TEXT' => $lang['CONFIRM_MOVE_TOPIC'], + 'TOPIC_TITLES' => join("\n
  • \n
  • \n", $topic_titles), + + 'L_LEAVESHADOW' => $lang['LEAVE_SHADOW_TOPIC'], + + 'S_FORUM_SELECT' => $forum_select, + 'S_MODCP_ACTION' => "modcp.php", + 'S_HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + )); + + $template->set_filenames(array('body' => 'modcp.tpl')); + } + break; + + case 'lock': + case 'unlock': + $lock = ($mode == 'lock'); + $new_topic_status = ($lock) ? TOPIC_LOCKED : TOPIC_UNLOCKED; + + $sql = " + SELECT topic_id, topic_title + FROM ". BB_TOPICS ." + WHERE topic_id IN($topic_csv) + AND forum_id = $forum_id + AND topic_status != ". TOPIC_MOVED ." + AND topic_status != $new_topic_status + "; + + $topic_csv = array(); + + foreach (DB()->fetch_rowset($sql) as $row) + { + $topic_csv[] = $row['topic_id']; + $log_topics[$row['topic_id']] = $row['topic_title']; + } + + if (!$topic_csv = get_id_csv($topic_csv)) + { + message_die(GENERAL_MESSAGE, $lang['NONE_SELECTED']); + } + + DB()->query(" + UPDATE ". BB_TOPICS ." SET + topic_status = $new_topic_status + WHERE topic_id IN($topic_csv) + "); + + // Log action + $type = ($lock) ? 'mod_topic_lock' : 'mod_topic_unlock'; + + foreach ($log_topics as $topic_id => $topic_title) + { + $log_action->mod($type, array( + 'forum_id' => $forum_id, + 'topic_id' => $topic_id, + 'topic_title' => $topic_title, + )); + } + + $msg = ($lock) ? $lang['TOPICS_LOCKED'] : $lang['TOPICS_UNLOCKED']; + message_die(GENERAL_MESSAGE, return_msg_mcp($msg)); + + break; + + // Set or unset topics DL-type + case 'set_download': + case 'unset_download': + $set_download = ($mode == 'set_download'); + $new_dl_type = ($set_download) ? TOPIC_DL_TYPE_DL : TOPIC_DL_TYPE_NORMAL; + + DB()->query(" + UPDATE ". BB_TOPICS ." SET + topic_dl_type = $new_dl_type + WHERE topic_id IN($topic_csv) + AND forum_id = $forum_id + AND topic_moved_id = 0 + "); + + if ($mode == 'unset_download') + { + clear_dl_list($topic_csv); + } + + $msg = ($set_download) ? $lang['TOPICS_DOWN_SETS'] : $lang['TOPICS_DOWN_UNSETS']; + message_die(GENERAL_MESSAGE, return_msg_mcp($msg)); + + break; + + case 'split': + //mpd + $delete_posts = isset($_POST['delete_posts']); + $split = (isset($_POST['split_type_all']) || isset($_POST['split_type_beyond'])); + $posts = (isset($_POST['post_id_list'])) ? $_POST['post_id_list'] : array(); + $start = /* (isset($_POST['start'])) ? intval($_POST['start']) : */ 0; + $topic_first_post_id = (isset($topic_row['topic_first_post_id'])) ? $topic_row['topic_first_post_id'] : ''; + + $post_id_sql = $req_post_id_sql = array(); + + if (($split || $delete_posts) && ($posts && $topic_id && $forum_id && $topic_first_post_id) && $confirmed) + { + foreach ($posts as $post_id) + { + if ($pid = intval($post_id)) + { + $req_post_id_sql[] = $pid; + } + } + if ($req_post_id_sql = join(',', $req_post_id_sql)) + { + $sql = "SELECT post_id + FROM ". BB_POSTS ." + WHERE post_id IN($req_post_id_sql) + AND post_id != $topic_first_post_id + AND topic_id = $topic_id + AND forum_id = $forum_id"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not get post id information', '', __LINE__, __FILE__, $sql); + } + if ($rowset = DB()->sql_fetchrowset($result)) + { + foreach ($rowset as $rid => $row) + { + $post_id_sql[] = $row['post_id']; + } + $post_id_sql = join(',', $post_id_sql); + } + } + } + + if ($post_id_sql && $split) + //mpd end + { + $sql = "SELECT post_id, poster_id, topic_id, post_time + FROM " . BB_POSTS . " + WHERE post_id IN ($post_id_sql) + ORDER BY post_time ASC"; + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not get post information', '', __LINE__, __FILE__, $sql); + } + + if ($row = DB()->sql_fetchrow($result)) + { + $first_poster = $row['poster_id']; + $topic_id = $row['topic_id']; + $post_time = $row['post_time']; + + $user_id_sql = ''; + $post_id_sql = ''; + do + { + $user_id_sql .= (($user_id_sql != '') ? ', ' : '') . intval($row['poster_id']); + $post_id_sql .= (($post_id_sql != '') ? ', ' : '') . intval($row['post_id']);; + } + while ($row = DB()->sql_fetchrow($result)); + + $post_subject = trim(htmlspecialchars($_POST['subject'])); + if (empty($post_subject)) + { + message_die(GENERAL_MESSAGE, $lang['EMPTY_SUBJECT']); + } + + $new_forum_id = intval($_POST['new_forum_id']); + $topic_time = time(); + + $sql = 'SELECT forum_id FROM ' . BB_FORUMS . ' + WHERE forum_id = ' . $new_forum_id; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not select from forums table', '', __LINE__, __FILE__, $sql); + } + + if (!DB()->sql_fetchrow($result)) + { + message_die(GENERAL_MESSAGE, 'New forum does not exist'); + } + + DB()->sql_freeresult($result); + + $sql = "INSERT INTO " . BB_TOPICS . " (topic_title, topic_poster, topic_time, forum_id, topic_status, topic_type) + VALUES ('" . str_replace("\'", "''", $post_subject) . "', $first_poster, " . $topic_time . ", $new_forum_id, " . TOPIC_UNLOCKED . ", " . POST_NORMAL . ")"; + if (!(DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, 'Could not insert new topic', '', __LINE__, __FILE__, $sql); + } + + $new_topic_id = DB()->sql_nextid(); + + // Update topic watch table, switch users whose posts + // have moved, over to watching the new topic + $sql = "UPDATE " . BB_TOPICS_WATCH . " + SET topic_id = $new_topic_id + WHERE topic_id = $topic_id + AND user_id IN ($user_id_sql)"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update topics watch table', '', __LINE__, __FILE__, $sql); + } + + $sql_where = (!empty($_POST['split_type_beyond'])) ? " post_time >= $post_time AND topic_id = $topic_id" : "post_id IN ($post_id_sql)"; + + $sql = "UPDATE " . BB_POSTS . " + SET topic_id = $new_topic_id, forum_id = $new_forum_id + WHERE $sql_where"; + if (!DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not update posts table', '', __LINE__, __FILE__, $sql); + } + + //bot + if (isset($_POST['after_split_to_old'])) + { + insert_post('after_split_to_old', $topic_id, $forum_id, '', $new_topic_id, trim($_POST['subject'])); + } + if (isset($_POST['after_split_to_new'])) + { + insert_post('after_split_to_new', $new_topic_id, $new_forum_id, $forum_id, $new_topic_id, '', $topic_id); + } + //bot end + + sync('topic', array($topic_id, $new_topic_id)); + sync('forum', array($forum_id, $new_forum_id)); + + //bot + $message = $lang['TOPIC_SPLIT'] .'

    '. $lang['TOPIC_SPLIT_OLD'] .''; + $message .= '  ::  '. $lang['TOPIC_SPLIT_NEW'] .''; + //bot end + + // Log action + $log_action->mod('mod_topic_split', array( + 'forum_id' => $forum_id, + 'forum_id_new' => $new_forum_id, + 'topic_id' => $topic_id, + 'topic_title' => get_topic_title($topic_id), + 'topic_id_new' => $new_topic_id, + 'topic_title_new' => htmlCHR($_POST['subject']), + )); + + message_die(GENERAL_MESSAGE, $message); + } + } + //mpd + else if ($post_id_sql && $delete_posts) + { + if (!$is_auth['auth_delete']) + { + message_die(GENERAL_MESSAGE, sprintf($lang['SORRY_AUTH_DELETE'], $is_auth['auth_delete_type'])); + } + + // Delete posts + $result = post_delete(explode(',', $post_id_sql)); + + $msg = ($result) ? $lang['DELETE_POSTS_SUCCESFULLY'] : 'No posts were removed'; + message_die(GENERAL_MESSAGE, return_msg_mcp($msg)); + } + //mpd end + else + { + $sql = "SELECT u.username, p.*, pt.post_text, pt.bbcode_uid, pt.post_subject, p.post_username + FROM " . BB_POSTS . " p, " . BB_USERS . " u, " . BB_POSTS_TEXT . " pt + WHERE p.topic_id = $topic_id + AND p.poster_id = u.user_id + AND p.post_id = pt.post_id + ORDER BY p.post_time ASC"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get topic/post information', '', __LINE__, __FILE__, $sql); + } + + $s_hidden_fields = ''; + + if( ( $total_posts = DB()->num_rows($result) ) > 0 ) + { + $postrow = DB()->sql_fetchrowset($result); + + $template->assign_vars(array( + 'FORUM_NAME' => htmlCHR($forum_name), + 'U_VIEW_FORUM' => FORUM_URL . $forum_id, + 'S_SPLIT_ACTION' => "modcp.php", + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_FORUM_SELECT' => get_forum_select('admin', 'new_forum_id', $forum_id), + )); + + for($i = 0; $i < $total_posts; $i++) + { + $post_id = $postrow[$i]['post_id']; + $poster_id = $postrow[$i]['poster_id']; + $poster = $postrow[$i]['username']; + + $post_date = bb_date($postrow[$i]['post_time']); + + $bbcode_uid = $postrow[$i]['bbcode_uid']; + $message = $postrow[$i]['post_text']; + $post_subject = ( isset($postrow[$i]['post_subject']) ) ? $postrow[$i]['post_subject'] : $topic_title; + + // + // If the board has HTML off but the post has HTML + // on then we process it, else leave it alone + // + $message = bbcode2html($message); + + $row_class = !($i % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars('postrow', array( + 'ROW_CLASS' => $row_class, + 'POSTER_NAME' => wbr($poster), + 'POST_DATE' => $post_date, + 'POST_SUBJECT' => $post_subject, + 'MESSAGE' => $message, + + 'CHECKBOX' => (defined('BEGIN_CHECKBOX')) ? TRUE : FALSE, + 'POST_ID' => $post_id, + 'ROW_ID' => $i, + 'CB_ID' => 'cb_'. $i + )); + + if ($post_id == $topic_first_post_id) + { + define('BEGIN_CHECKBOX', TRUE); + } + } + } + } + $template->set_filenames(array('body' => 'modcp_split.tpl')); + break; + + case 'ip': + $anon = ANONYMOUS; + + $rdns_ip_num = ( isset($_GET['rdns']) ) ? $_GET['rdns'] : ""; + + if ( !$post_id ) + { + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_POST']); + } + + // Look up relevent data for this post + $sql = "SELECT * + FROM " . BB_POSTS . " + WHERE post_id = $post_id + AND forum_id = $forum_id"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get poster IP information', '', __LINE__, __FILE__, $sql); + } + + if ( !($post_row = DB()->sql_fetchrow($result)) ) + { + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_POST']); + } + + $ip_this_post = decode_ip($post_row['poster_ip']); + $ip_this_post = ( $rdns_ip_num == $ip_this_post ) ? gethostbyaddr($ip_this_post) : $ip_this_post; + + $poster_id = $post_row['poster_id']; + + $template->assign_vars(array( + 'TPL_MODCP_IP' => true, + 'L_THIS_POST_IP' => $lang['THIS_POSTS_IP'], + 'L_OTHER_IPS' => $lang['OTHER_IP_THIS_USER'], + 'L_OTHER_USERS' => $lang['USERS_THIS_IP'], + 'IP' => $ip_this_post, + 'U_LOOKUP_IP' => "modcp.php?mode=ip&" . POST_POST_URL . "=$post_id&" . POST_TOPIC_URL . "=$topic_id&rdns=$ip_this_post&sid=" . $userdata['session_id']) + ); + + // + // Get other IP's this user has posted under + // + $where_sql = ($poster_id == $anon) ? "post_username = '{$post_row['post_username']}'" : "poster_id = $poster_id"; + + $sql = "SELECT poster_ip, COUNT(*) AS postings + FROM " . BB_POSTS . " + WHERE $where_sql + GROUP BY poster_ip + ORDER BY postings DESC + LIMIT 100"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get IP information for this user', '', __LINE__, __FILE__, $sql); + } + + if ( $row = DB()->sql_fetchrow($result) ) + { + $i = 0; + do + { + if ( $row['poster_ip'] == $post_row['poster_ip'] ) + { + $template->assign_vars(array( + 'POSTS' => $row['postings'], + )); + continue; + } + + $ip = decode_ip($row['poster_ip']); + $ip = ( $rdns_ip_num == $row['poster_ip'] || $rdns_ip_num == 'all') ? gethostbyaddr($ip) : $ip; + + $template->assign_block_vars('iprow', array( + 'ROW_CLASS' => !($i % 2) ? 'row4' : 'row5', + 'IP' => $ip, + 'POSTS' => $row['postings'], + 'U_LOOKUP_IP' => "modcp.php?mode=ip&" . POST_POST_URL . "=$post_id&" . POST_TOPIC_URL . "=$topic_id&rdns=" . $row['poster_ip'] . "&sid=" . $userdata['session_id'], + )); + + $i++; + } + while ( $row = DB()->sql_fetchrow($result) ); + } + + // + // Get other users who've posted under this IP + // + $sql = "SELECT + u.user_id, + IF(u.user_id = $anon, p.post_username, u.username) AS username, + COUNT(*) as postings + FROM " . BB_USERS ." u, " . BB_POSTS . " p + WHERE p.poster_id = u.user_id + AND p.poster_ip = '" . $post_row['poster_ip'] . "' + GROUP BY u.user_id, p.post_username + ORDER BY postings DESC + LIMIT 100"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not get posters information based on IP', '', __LINE__, __FILE__, $sql); + } + + if ( $row = DB()->sql_fetchrow($result) ) + { + $i = 0; + do + { + $id = $row['user_id']; + $username = (!$row['username']) ? $lang['GUEST'] : $row['username']; + + $template->assign_block_vars('userrow', array( + 'ROW_CLASS' => !($i % 2) ? 'row4' : 'row5', + 'USERNAME' => wbr($username), + 'POSTS' => $row['postings'], + 'L_SEARCH_POSTS' => $lang['SEARCH_USER_POSTS_SHORT'], + 'U_PROFILE' => ($id == ANONYMOUS) ? "modcp.php?mode=ip&p=$post_id&t=$topic_id" : PROFILE_URL . $id, + 'U_SEARCHPOSTS' => "search.php?search_author=1&uid=$id", + )); + + $i++; + } + while ( $row = DB()->sql_fetchrow($result) ); + } + + $template->set_filenames(array('body' => 'modcp.tpl')); + break; + + default: + bb_die('invalid action'); + break; +} + +$template->assign_vars(array('PAGE_TITLE' => $lang['MOD_CP'])); + +require(PAGE_HEADER); + +$template->pparse('body'); + +require(PAGE_FOOTER); \ No newline at end of file diff --git a/upload/opensearch_desc.xml b/upload/opensearch_desc.xml new file mode 100644 index 000000000..55481b783 --- /dev/null +++ b/upload/opensearch_desc.xml @@ -0,0 +1,8 @@ + + +TorrentPier (Forum) +TorrentPier (Forum) +UTF-8 +http://site.ru/favicon.ico + + \ No newline at end of file diff --git a/upload/opensearch_desc_bt.xml b/upload/opensearch_desc_bt.xml new file mode 100644 index 000000000..60651011e --- /dev/null +++ b/upload/opensearch_desc_bt.xml @@ -0,0 +1,8 @@ + + +TorrentPier (Tracker) +TorrentPier (Tracker) +UTF-8 +http://site.ru/favicon.ico + + \ No newline at end of file diff --git a/upload/pictures/.htaccess b/upload/pictures/.htaccess new file mode 100644 index 000000000..34ed2a11e --- /dev/null +++ b/upload/pictures/.htaccess @@ -0,0 +1,3 @@ +php_flag engine off +RemoveHandler .php .php5 .php4 .php3 .phtml .pl .asp +AddType text/plain .php .php .htm .html .phtml .pl .asp \ No newline at end of file diff --git a/upload/posting.php b/upload/posting.php new file mode 100644 index 000000000..e422d5682 --- /dev/null +++ b/upload/posting.php @@ -0,0 +1,1019 @@ +session_start(); + +// Quick Reply +$template->assign_vars(array( + 'L_FONT_SEL' => $lang['QR_FONT_SEL'], + 'L_FONT_COLOR_SEL' => $lang['QR_COLOR_SEL'], + 'L_FONT_SIZE_SEL' => $lang['QR_SIZE_SEL'], + 'L_STEEL_BLUE' => $lang['COLOR_STEEL_BLUE'], + 'L_COLOR_GRAY' => $lang['COLOR_GRAY'], + 'L_COLOR_DARK_GREEN' => $lang['COLOR_DARK_GREEN'], +)); + +// What auth type do we need to check? +$is_auth = array(); +switch ($mode) +{ + case 'newtopic': + if ($topic_type == POST_ANNOUNCE) + { + $is_auth_type = 'auth_announce'; + } + else if ($topic_type == POST_STICKY) + { + $is_auth_type = 'auth_sticky'; + } + else + { + $is_auth_type = 'auth_post'; + } + break; + case 'reply': + case 'quote': + $is_auth_type = 'auth_reply'; + break; + case 'editpost': + $is_auth_type = 'auth_edit'; + break; + case 'delete': + case 'poll_delete': + $is_auth_type = 'auth_delete'; + break; + case 'vote': + $is_auth_type = 'auth_vote'; + break; + default: + message_die(GENERAL_MESSAGE, $lang['NO_POST_MODE']); + break; +} + +// Here we do various lookups to find topic_id, forum_id, post_id etc. +// Doing it here prevents spoofing (eg. faking forum_id, topic_id or post_id +$error_msg = ''; +$post_data = array(); +switch ($mode) +{ + case 'newtopic': + if (!$forum_id) + { + message_die(GENERAL_MESSAGE, $lang['FORUM_NOT_EXIST']); + } + $sql = "SELECT * FROM ". BB_FORUMS ." WHERE forum_id = $forum_id LIMIT 1"; + break; + + case 'reply': + case 'vote': + if (!$topic_id) + { + message_die(GENERAL_MESSAGE, $lang['NO_TOPIC_ID']); + } + $sql = "SELECT f.*, t.* + FROM ". BB_FORUMS ." f, ". BB_TOPICS ." t + WHERE t.topic_id = $topic_id + AND f.forum_id = t.forum_id + LIMIT 1"; + break; + + case 'quote': + case 'editpost': + case 'delete': + case 'poll_delete': + if (!$post_id) + { + message_die(GENERAL_MESSAGE, $lang['NO_POST_ID']); + } + + $select_sql = 'SELECT f.*, t.*, p.*'; + $select_sql .= (!$submit) ? ', pt.*, u.username, u.user_id' : ''; + + $from_sql = "FROM ". BB_POSTS ." p, ". BB_TOPICS ." t, ". BB_FORUMS ." f"; + $from_sql .= (!$submit) ? ", " . BB_POSTS_TEXT . " pt, " . BB_USERS . " u" : ''; + + $where_sql = " + WHERE p.post_id = $post_id + AND t.topic_id = p.topic_id + AND f.forum_id = p.forum_id + "; + $where_sql .= (!$submit) ? " + AND pt.post_id = p.post_id + AND u.user_id = p.poster_id + " : ''; + + $sql = "$select_sql $from_sql $where_sql LIMIT 1"; + break; + + default: + message_die(GENERAL_MESSAGE, $lang['NO_VALID_MODE']); +} + +if ($post_info = DB()->fetch_row($sql)) +{ + $forum_id = $post_info['forum_id']; + $forum_name = $post_info['forum_name']; + + $is_auth = auth(AUTH_ALL, $forum_id, $userdata, $post_info); + + if ($post_info['forum_status'] == FORUM_LOCKED && !$is_auth['auth_mod']) + { + message_die(GENERAL_MESSAGE, $lang['FORUM_LOCKED']); + } + else if ($mode != 'newtopic' && $post_info['topic_status'] == TOPIC_LOCKED && !$is_auth['auth_mod']) + { + message_die(GENERAL_MESSAGE, $lang['TOPIC_LOCKED']); + } + + if ($mode == 'editpost' || $mode == 'delete' || $mode == 'poll_delete') + { + $topic_id = $post_info['topic_id']; + + $post_data['poster_post'] = ($post_info['poster_id'] == $userdata['user_id']); + $post_data['first_post'] = ($post_info['topic_first_post_id'] == $post_id); + $post_data['last_post'] = ($post_info['topic_last_post_id'] == $post_id); + $post_data['last_topic'] = ($post_info['forum_last_post_id'] == $post_id); + $post_data['has_poll'] = (bool) $post_info['topic_vote']; + $post_data['topic_type'] = $post_info['topic_type']; + $post_data['poster_id'] = $post_info['poster_id']; + + if ($post_data['first_post'] && $post_data['has_poll']) + { + $sql = "SELECT * + FROM ". BB_VOTE_DESC ." vd, ". BB_VOTE_RESULTS ." vr + WHERE vd.topic_id = $topic_id + AND vr.vote_id = vd.vote_id + ORDER BY vr.vote_option_id"; + + if (!$result = DB()->sql_query($sql)) + { + message_die(GENERAL_ERROR, 'Could not obtain vote data for this topic', '', __LINE__, __FILE__, $sql); + } + + $poll_options = array(); + $poll_results_sum = 0; + if ($row = DB()->sql_fetchrow($result)) + { + $poll_title = $row['vote_text']; + $poll_id = $row['vote_id']; + $poll_length = $row['vote_length'] / 86400; + + do + { + $poll_options[$row['vote_option_id']] = $row['vote_option_text']; + $poll_results_sum += $row['vote_result']; + } + while ($row = DB()->sql_fetchrow($result)); + } + $post_data['edit_poll'] = ((!$poll_results_sum || $is_auth['auth_mod']) && $post_data['first_post']); + } + else + { + $post_data['edit_poll'] = ($post_data['first_post'] && $is_auth['auth_pollcreate']); + } + + // Can this user edit/delete the post/poll? + if ($post_info['poster_id'] != $userdata['user_id'] && !$is_auth['auth_mod']) + { + $message = ($delete || $mode == 'delete') ? $lang['DELETE_OWN_POSTS'] : $lang['EDIT_OWN_POSTS']; + $message .= '

    '. sprintf($lang['CLICK_RETURN_TOPIC'], '', ''); + + message_die(GENERAL_MESSAGE, $message); + } + else if (!$post_data['last_post'] && !$is_auth['auth_mod'] && ($mode == 'delete' || $delete)) + { + message_die(GENERAL_MESSAGE, $lang['CANNOT_DELETE_REPLIED']); + } + else if (!$post_data['edit_poll'] && !$is_auth['auth_mod'] && ($mode == 'poll_delete' || $poll_delete)) + { + message_die(GENERAL_MESSAGE, $lang['CANNOT_DELETE_POLL']); + } + } + else + { + if ($mode == 'quote') + { + $topic_id = $post_info['topic_id']; + } + if ($mode == 'newtopic') + { + $post_data['topic_type'] = POST_NORMAL; + } + $post_data['first_post'] = ($mode == 'newtopic'); + $post_data['last_post'] = false; + $post_data['has_poll'] = false; + $post_data['edit_poll'] = false; + } + if ($mode == 'poll_delete' && !$poll_id) + { + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_POST']); + } +} +else +{ + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_POST']); +} + +// The user is not authed, if they're not logged in then redirect +// them, else show them an error message +if (!$is_auth[$is_auth_type]) +{ + if (!IS_GUEST) + { + message_die(GENERAL_MESSAGE, sprintf($lang['SORRY_'. strtoupper($is_auth_type)], $is_auth[$is_auth_type .'_type'])); + } + + switch ($mode) + { + case 'newtopic': + $redirect = "mode=newtopic&f=$forum_id"; + break; + case 'reply': + $redirect = "mode=reply&t=$topic_id"; + break; + case 'quote': + case 'editpost': + $redirect = "mode=quote&p=$post_id"; + break; + default: + $redirect = ''; + } + redirect("login.php?redirect=/posting.php?$redirect"); +} + +if ($mode == 'newtopic' && $topic_tpl && $post_info['topic_tpl_id']) +{ + require(INC_DIR .'topic_templates.php'); +} + +// BBCode +if (!$bb_cfg['allow_bbcode']) +{ + $bbcode_on = 0; +} +else +{ + $bbcode_on = ($submit || $refresh) ? (int) empty($_POST['disable_bbcode']) : $bb_cfg['allow_bbcode']; +} + +// Smilies +if (!$bb_cfg['allow_smilies']) +{ + $smilies_on = 0; +} +else +{ + $smilies_on = ($submit || $refresh) ? (int) empty($_POST['disable_smilies']) : $bb_cfg['allow_smilies']; +} + +// Notify +if ($submit || $refresh) +{ + $notify_user = (int) !empty($_POST['notify']); +} +else +{ + if (!IS_GUEST && $mode != 'newtopic' && !$userdata['user_notify']) + { + $notify_user = (int) DB()->fetch_row(" + SELECT topic_id + FROM ". BB_TOPICS_WATCH ." + WHERE topic_id = $topic_id + AND user_id = ". $userdata['user_id'] ." + "); + } + else + { + $notify_user = $userdata['user_notify']; + } +} + +$attach_sig = ($submit || $refresh) ? (int) !empty($_POST['attach_sig']) : bf($userdata['user_opt'], 'user_opt', 'attachsig'); +$update_post_time = !empty($_POST['update_post_time']); + +execute_posting_attachment_handling(); + +// если за время пока вы писали ответ, в топике появились новые сообщения, перед тем как ваше сообщение будет отправлено, выводится предупреждение с обзором этих сообщений +$topic_has_new_posts = false; + +if (!IS_GUEST && $mode != 'newtopic' && ($submit || $preview || $mode == 'quote' || $mode == 'reply') && isset($_COOKIE[COOKIE_TOPIC])) +{ + if ($topic_last_read = max(intval(@$tracking_topics[$topic_id]), intval(@$tracking_forums[$forum_id]))) + { + $sql = "SELECT p.*, pt.post_text, pt.bbcode_uid, u.username + FROM ". BB_POSTS ." p, ". BB_POSTS_TEXT ." pt, ". BB_USERS ." u + WHERE p.topic_id = ". (int) $topic_id ." + AND u.user_id = p.poster_id + AND pt.post_id = p.post_id + AND p.post_time > $topic_last_read + ORDER BY p.post_time + LIMIT ". $bb_cfg['posts_per_page']; + + if ($rowset = DB()->fetch_rowset($sql)) + { + $topic_has_new_posts = true; + + foreach ($rowset as $i => $row) + { + if ($row['poster_id'] == ANONYMOUS) + { + $new_post_username = (!$row['post_username']) ? $lang['GUEST'] : $row['post_username']; + } + else + { + $new_post_username = $row['username']; + } + + $template->assign_block_vars('new_posts', array( + 'ROW_CLASS' => !($i % 2) ? 'row1' : 'row2', + 'POSTER_NAME' => $new_post_username, + 'POSTER_NAME_JS' => addslashes($new_post_username), + 'POST_DATE' => bb_date($row['post_time'], $bb_cfg['post_date_format']), + 'MESSAGE' => get_parsed_post($row), + )); + } + $template->assign_vars(array( + 'TPL_SHOW_NEW_POSTS' => true, + )); + + set_tracks(COOKIE_TOPIC, $tracking_topics, $topic_id); + unset($rowset); + } + } +} + +// -------------------- +// What shall we do? +// +if ( ( $delete || $poll_delete || $mode == 'delete' ) && !$confirm ) +{ + if (isset($_POST['cancel'])) + { + redirect(POST_URL . "$post_id#$post_id"); + } + // + // Confirm deletion + // + $hidden_fields = array( + 'p' => $post_id, + 'mode' => ($delete || $mode == "delete") ? 'delete' : 'poll_delete', + ); + + print_confirmation(array( + 'QUESTION' => ($delete || $mode == 'delete') ? $lang['CONFIRM_DELETE'] : $lang['CONFIRM_DELETE_POLL'], + 'FORM_ACTION' => "posting.php", + 'HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + )); +} +else if ( $mode == 'vote' ) +{ + // + // Vote in a poll + // + if ( !empty($_POST['vote_id']) ) + { + $vote_option_id = intval($_POST['vote_id']); + + $sql = "SELECT vd.vote_id + FROM " . BB_VOTE_DESC . " vd, " . BB_VOTE_RESULTS . " vr + WHERE vd.topic_id = $topic_id + AND vr.vote_id = vd.vote_id + AND vr.vote_option_id = $vote_option_id + GROUP BY vd.vote_id"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain vote data for this topic', '', __LINE__, __FILE__, $sql); + } + + if ( $vote_info = DB()->sql_fetchrow($result) ) + { + $vote_id = $vote_info['vote_id']; + + $sql = "SELECT * + FROM " . BB_VOTE_USERS . " + WHERE vote_id = $vote_id + AND vote_user_id = " . $userdata['user_id']; + if ( !($result2 = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain user vote data for this topic', '', __LINE__, __FILE__, $sql); + } + + if ( !($row = DB()->sql_fetchrow($result2)) ) + { + $sql = "UPDATE " . BB_VOTE_RESULTS . " + SET vote_result = vote_result + 1 + WHERE vote_id = $vote_id + AND vote_option_id = $vote_option_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update poll result', '', __LINE__, __FILE__, $sql); + } + + $sql = "INSERT INTO " . BB_VOTE_USERS . " (vote_id, vote_user_id, vote_user_ip) + VALUES ($vote_id, " . $userdata['user_id'] . ", '". USER_IP ."')"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not insert user_id for poll", "", __LINE__, __FILE__, $sql); + } + + $message = $lang['VOTE_CAST']; + } + else + { + $message = $lang['ALREADY_VOTED']; + } + DB()->sql_freeresult($result2); + } + else + { + $message = $lang['NO_VOTE_OPTION']; + } + DB()->sql_freeresult($result); + + meta_refresh(append_sid("viewtopic.php?" . POST_TOPIC_URL . "=$topic_id")); + $message .= '

    ' . sprintf($lang['CLICK_RETURN_TOPIC'], '', ''); + message_die(GENERAL_MESSAGE, $message); + } + else + { + redirect(append_sid("viewtopic.php?" . POST_TOPIC_URL . "=$topic_id", true)); + } +} +//snp +// else if ( $submit || $confirm ) +else if ( ($submit || $confirm) && !$topic_has_new_posts ) +//snp end +{ + // + // Submit post/vote (newtopic, edit, reply, etc.) + // + $return_message = ''; + $return_meta = ''; + + switch ( $mode ) + { + case 'editpost': + case 'newtopic': + case 'reply': + $username = ( !empty($_POST['username']) ) ? $_POST['username'] : ''; + $subject = ( !empty($_POST['subject']) ) ? trim($_POST['subject']) : ''; + $message = ( !empty($_POST['message']) ) ? $_POST['message'] : ''; + $poll_title = ( isset($_POST['poll_title']) && $is_auth['auth_pollcreate'] ) ? $_POST['poll_title'] : ''; + $poll_options = ( isset($_POST['poll_option_text']) && $is_auth['auth_pollcreate'] ) ? $_POST['poll_option_text'] : ''; + $poll_length = ( isset($_POST['poll_length']) && $is_auth['auth_pollcreate'] ) ? $_POST['poll_length'] : ''; + $bbcode_uid = ''; + + prepare_post($mode, $post_data, $bbcode_on, $smilies_on, $error_msg, $username, $bbcode_uid, $subject, $message, $poll_title, $poll_options, $poll_length); + + if (!$error_msg) + { + $topic_type = ( isset($post_data['topic_type']) && $topic_type != $post_data['topic_type'] && !$is_auth['auth_sticky'] && !$is_auth['auth_announce'] ) ? $post_data['topic_type'] : $topic_type; + + submit_post($mode, $post_data, $return_message, $return_meta, $forum_id, $topic_id, $post_id, $poll_id, $topic_type, $bbcode_on, $smilies_on, $attach_sig, $bbcode_uid, str_replace("\'", "''", $username), str_replace("\'", "''", $subject), str_replace("\'", "''", $message), str_replace("\'", "''", $poll_title), $poll_options, $poll_length, $update_post_time); + } + break; + + case 'delete': + case 'poll_delete': + require_once(INC_DIR .'functions_admin.php'); + delete_post($mode, $post_data, $return_message, $return_meta, $forum_id, $topic_id, $post_id, $poll_id); + break; + } + + if (!$error_msg) + { + if (!in_array($mode, array('editpost', 'delete', 'poll_delete'))) + { + $user_id = ( $mode == 'reply' || $mode == 'newtopic' ) ? $userdata['user_id'] : $post_data['poster_id']; + update_post_stats($mode, $post_data, $forum_id, $topic_id, $post_id, $user_id); + } + $attachment_mod['posting']->insert_attachment($post_id); + + if (!$error_msg && $mode != 'poll_delete') + { + user_notification($mode, $post_data, $post_info['topic_title'], $forum_id, $topic_id, $post_id, $notify_user); + } + + if ($mode == 'newtopic' || $mode == 'reply') + { + set_tracks(COOKIE_TOPIC, $tracking_topics, $topic_id); + } + + $torrent_ext = (@$attachment_mod['posting']->extension === TORRENT_EXT || @$attachment_mod['posting']->attachment_extension_list[0] === TORRENT_EXT); + $torrent_attach = ($torrent_ext && defined('TORRENT_ATTACH_ID') && 1 == count($attachment_mod['posting']->attachment_list)); + + if ($torrent_attach && $bb_cfg['bt_newtopic_auto_reg'] && $mode == 'newtopic' && !$error_msg) + { + include(INC_DIR .'functions_torrent.php'); + tracker_register(TORRENT_ATTACH_ID, 'newtopic'); + } + + if ($mode == 'reply' && $post_info['topic_status'] == TOPIC_LOCKED) + { + $locked_warn = ' +
    + '. $lang['LOCKED_WARN'] .' +
    +


    + '; + $return_message = $locked_warn . $return_message; + } + + message_die(GENERAL_MESSAGE, $return_message); + } +} + +//snp +//if( $refresh || isset($_POST['del_poll_option']) || $error_msg != '' ) +if( $refresh || isset($_POST['del_poll_option']) || $error_msg || ($submit && $topic_has_new_posts) ) +//snp end +{ + $username = ( !empty($_POST['username']) ) ? htmlspecialchars(trim(stripslashes($_POST['username']))) : ''; + $subject = ( !empty($_POST['subject']) ) ? htmlspecialchars(trim(stripslashes($_POST['subject']))) : ''; + $message = ( !empty($_POST['message']) ) ? htmlspecialchars(trim(stripslashes($_POST['message']))) : ''; + + $poll_title = ( !empty($_POST['poll_title']) ) ? htmlspecialchars(trim(stripslashes($_POST['poll_title']))) : ''; + $poll_length = ( isset($_POST['poll_length']) ) ? max(0, intval($_POST['poll_length'])) : 0; + + $poll_options = array(); + if ( !empty($_POST['poll_option_text']) ) + { +# while( list($option_id, $option_text) = @each($_POST['poll_option_text']) ) + foreach ($_POST['poll_option_text'] as $option_id => $option_text) + { + if( isset($_POST['del_poll_option'][$option_id]) ) + { + unset($poll_options[$option_id]); + } + else if ( !empty($option_text) ) + { + $poll_options[$option_id] = htmlspecialchars(trim(stripslashes($option_text))); + } + } + } + + if ( $poll_add && !empty($_POST['add_poll_option_text']) ) + { + $poll_options[] = htmlspecialchars(trim(stripslashes($_POST['add_poll_option_text']))); + } + + if ($preview) + { + $preview_message = $msg_html = $msg_html_tidy = ''; + + $text = $message; + $text = htmlCHR($text, false, ENT_NOQUOTES); + $preview_message = bbcode2html($text); // создает объект $bbcode + + // ### DBG ### + if (0 && $user->id == 10838) + { + $text = $_POST['message']; + $text = htmlCHR($text, false, ENT_NOQUOTES); + $msg_html_tidy = $bbcode->bbcode2html($text, true); + + if (1 && !empty($_COOKIE['explain'])) + { + $msg_html = $bbcode->bbcode2html($text, false); + + $msg_html = html_compact($msg_html, true); + $msg_html_tidy = html_compact($msg_html_tidy, true); + $preview_message = html_compact($preview_message, true); + + file_write($msg_html, LOG_DIR.'before_tidy', false, true, true); + file_write($msg_html_tidy, LOG_DIR.'after_tidy', false, true, true); + } + $template->assign_vars(array( + 'MSG_HTML_TIDY' => $msg_html_tidy, + )); + } + if (IS_AM) + { + $template->assign_vars(array( + 'SPAM_WORD' => ($bbcode->found_spam) ? '
    '. htmlCHR(join("\n", $bbcode->found_spam)) .'
    ' : '', + )); + } + if (0 && $user->id == 10838) + { + $template->assign_vars(array( + 'PREVIEW_INPUT_SRC' => get_html_src($_POST['message']), + 'PREVIEW_HTML_SRC' => get_html_src($preview_message), + )); + } + // ### DBG ### + + $template->assign_vars(array( + 'TPL_PREVIEW_POST' => true, + 'PREVIEW_MSG' => $preview_message, + )); + + } +} +else +{ + // User default entry point + if ( $mode == 'newtopic' ) + { + $username = ($userdata['session_logged_in']) ? $userdata['username'] : ''; + $poll_title = ''; + $poll_length = ''; + $subject = ''; + $message = ''; + } + else if ( $mode == 'reply' ) + { + $username = ( $userdata['session_logged_in'] ) ? $userdata['username'] : ''; + $subject = ''; + $message = ''; + } + else if ( $mode == 'quote' || $mode == 'editpost' ) + { + $subject = ( $post_data['first_post'] ) ? $post_info['topic_title'] : $post_info['post_subject']; + $message = $post_info['post_text']; + + if ( $mode == 'editpost' ) + { + $attach_sig = $post_info['enable_sig']; + $bbcode_on = $post_info['enable_bbcode']; + $smilies_on = $post_info['enable_smilies']; + } + else + { + $attach_sig = bf($userdata['user_opt'], 'user_opt', 'attachsig'); + } + + if ( $post_info['bbcode_uid'] != '' ) + { + $message = preg_replace('/\:(([a-z0-9]:)?)' . $post_info['bbcode_uid'] . '/s', '', $message); + } + + $message = str_replace('<', '<', $message); + $message = str_replace('>', '>', $message); + $message = str_replace('
    ', "\n", $message); + + if ( $mode == 'quote' ) + { + if (!defined('WORD_LIST_OBTAINED')) + { + $orig_word = array(); + $replace_word = array(); + obtain_word_list($orig_word, $replace_word); + define('WORD_LIST_OBTAINED', TRUE); + } + + $msg_date = bb_date($postrow['post_time']); + + // Use trim to get rid of spaces placed there by MS-SQL 2000 + $quote_username = ( trim($post_info['post_username']) != '' ) ? $post_info['post_username'] : $post_info['username']; + $message = '[quote="' . $quote_username . '"]' . $message . '[/quote]'; + // hide user passkey + $message = preg_replace('#(?<=\?uk=)[a-zA-Z0-9]{10}(?=&)#', 'passkey', $message); + // hide sid + $message = preg_replace('#(?<=[\?&;]sid=)[a-zA-Z0-9]{12}#', 'sid', $message); + + if ( !empty($orig_word) ) + { + $subject = ( !empty($subject) ) ? preg_replace($orig_word, $replace_word, $subject) : ''; + $message = ( !empty($message) ) ? preg_replace($orig_word, $replace_word, $message) : ''; + } + + if ( !preg_match('/^Re:/', $subject) && strlen($subject) > 0 ) + { + $subject = 'Re: ' . $subject; + } + + $mode = 'reply'; + } + else + { + $username = ( $post_info['user_id'] == ANONYMOUS && !empty($post_info['post_username']) ) ? $post_info['post_username'] : ''; + } + } +} + +if ($error_msg) +{ + $template->assign_vars(array( + 'ERROR_MESSAGE' => $error_msg, + )); +} + +if (IS_GUEST || ($mode == 'editpost' && $post_info['poster_id'] == ANONYMOUS)) +{ + $template->assign_var('POSTING_USERNAME'); +} + +// +// Notify checkbox +// +if (!IS_GUEST) +{ + if ($mode != 'editpost' || ($mode == 'editpost' && $post_info['poster_id'] != ANONYMOUS)) + { + $template->assign_var('SHOW_NOTIFY_CHECKBOX'); + } +} + +// +// Topic type selection +// +$topic_type_toggle = ''; +if ( $mode == 'newtopic' || ( $mode == 'editpost' && $post_data['first_post'] ) ) +{ + $template->assign_block_vars('switch_type_toggle', array()); + + if( $is_auth['auth_sticky'] ) + { + $topic_type_toggle .= ' ' . $lang['POST_NORMAL'] . '  ' . $topic_type_toggle; + } +} +//bt +$topic_dl_type = (isset($post_info['topic_dl_type'])) ? $post_info['topic_dl_type'] : 0; + +if ($topic_dl_type || $post_info['allow_dl_topic'] || $is_auth['auth_mod']) +{ + if (!$topic_type_toggle) + { + $topic_type_toggle = $lang['POST_TOPIC_AS'] . ': '; + } + + $dl_ds = $dl_ch = $dl_hid = ''; + $dl_type_name = 'topic_dl_type'; + $dl_type_val = ($topic_dl_type) ? 1 : 0; + + if (!$post_info['allow_dl_topic'] && !$is_auth['auth_mod']) + { + $dl_ds = ' disabled="disabled" '; + $dl_hid = ''; + $dl_type_name = ''; + } + + $dl_ch = ($mode == 'editpost' && $post_data['first_post'] && $topic_dl_type) ? ' checked="checked" ' : ''; + + $topic_type_toggle .= ''; + $topic_type_toggle .= $dl_hid; +} +//bt end + +$hidden_form_fields = ''; + +switch( $mode ) +{ + case 'newtopic': + $page_title = $lang['POST_A_NEW_TOPIC']; + $hidden_form_fields .= ''; + break; + + case 'reply': + $page_title = $lang['POST_A_REPLY']; + $hidden_form_fields .= ''; + break; + + case 'editpost': + $page_title = $lang['EDIT_POST']; + $hidden_form_fields .= ''; + break; +} + +// Generate smilies listing for page output +generate_smilies('inline'); + +$template->set_filenames(array( + 'body' => 'posting.tpl', +)); + +$template->assign_vars(array( + 'FORUM_NAME' => htmlCHR($forum_name), + 'PAGE_TITLE' => $page_title, + 'POSTING_TYPE_TITLE' => $page_title, + 'POSTING_TOPIC_ID' => ($mode != 'newtopic') ? $topic_id : '', + 'POSTING_TOPIC_TITLE' => ($mode != 'newtopic') ? wbr($post_info['topic_title']) : '', + + 'SHOW_VIRTUAL_KEYBOARD' => $bb_cfg['show_virtual_keyboard'], + + 'U_VIEW_FORUM' => append_sid("viewforum.php?" . POST_FORUM_URL . "=$forum_id")) +); + +if ($mode == 'newtopic' || $post_data['first_post']) +{ + $template->assign_var('POSTING_SUBJECT'); +} + +// Update post time +if ($mode == 'editpost' && $post_data['last_post'] && !$post_data['first_post']) +{ + $template->assign_vars(array( + 'SHOW_UPDATE_POST_TIME' => ($is_auth['auth_mod'] || ($post_data['poster_post'] && $post_info['post_time'] + 3600*3 > TIMENOW)), + 'UPDATE_POST_TIME_CHECKED' => ($post_data['poster_post'] && ($post_info['post_time'] + 3600*2 > TIMENOW)), + )); +} + +// +// Output the data to the template +// +$bbcode_status = ($bb_cfg['allow_bbcode']) ? $lang['BBCODE_IS_ON'] : $lang['BBCODE_IS_OFF']; + +$template->assign_vars(array( + 'USERNAME' => @$username, + 'CAPTCHA_HTML' => (IS_GUEST) ? CAPTCHA()->get_html() : '', + 'SUBJECT' => $subject, + 'MESSAGE' => $message, + 'BBCODE_STATUS' => sprintf($bbcode_status, '', ''), + 'SMILIES_STATUS' => ($bb_cfg['allow_smilies']) ? $lang['SMILIES_ARE_ON'] : $lang['SMILIES_ARE_OFF'], + + 'L_SUBJECT' => $lang['SUBJECT'], + 'L_MESSAGE_BODY' => $lang['MESSAGE_BODY'], + 'L_CONFIRM_DELETE' => $lang['CONFIRM_DELETE'], + 'L_DISABLE_BBCODE' => $lang['DISABLE_BBCODE_POST'], + 'L_DISABLE_SMILIES' => $lang['DISABLE_SMILIES_POST'], + 'L_NOTIFY_ON_REPLY' => $lang['NOTIFY'], + 'L_DELETE_POST' => $lang['DELETE_POST'], + 'L_UPDATE_POST_TIME' => $lang['UPDATE_POST_TIME'], + + '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_STYLES_TIP' => $lang['STYLES_TIP'], + + 'U_VIEWTOPIC' => ( $mode == 'reply' ) ? append_sid("viewtopic.php?" . POST_TOPIC_URL . "=$topic_id&postorder=desc") : '', + + 'S_BBCODE_CHECKED' => ( !$bbcode_on ) ? 'checked="checked"' : '', + 'S_SMILIES_CHECKED' => ( !$smilies_on ) ? 'checked="checked"' : '', + 'S_SIGNATURE_CHECKED' => ( $attach_sig ) ? 'checked="checked"' : '', + 'S_NOTIFY_CHECKED' => ( $notify_user ) ? 'checked="checked"' : '', + 'S_TYPE_TOGGLE' => $topic_type_toggle, + 'S_TOPIC_ID' => $topic_id, + 'S_POST_ACTION' => append_sid("posting.php"), + 'S_HIDDEN_FORM_FIELDS' => $hidden_form_fields) +); + +// Output the data to the template (for MAIL.RU Keyboard) +$template->assign_vars(array( + 'L_KB_TITLE' => $lang['KB_TITLE'], + 'L_LAYOUT' => $lang['KB_RUS_KEYLAYOUT'], + 'L_NONE' => $lang['KB_NONE'], + 'L_TRANSLIT' => $lang['KB_TRANSLIT'], + 'L_TRADITIONAL' => $lang['KB_TRADITIONAL'], + 'L_RULES' => $lang['KB_RULES'], + 'L_SHOW' => $lang['KB_SHOW'], + 'L_CLOSE' => $lang['KB_CLOSE'], + 'L_TRANSLIT_OPERA7' => $lang['KB_TRANSLIT_OPERA7'], + 'L_TRANSLIT_MOZILLA' => $lang['KB_TRANSLIT_MOZILLA'], + 'S_VISIBILITY_RULES' => 'position:absolute;visibility:hidden;', + 'S_VISIBILITY_KEYB' => 'position:absolute;visibility:hidden;', + 'S_VISIBILITY_OFF' => '') +); +// +// Poll entry switch/output +// +if( ( $mode == 'newtopic' || ( $mode == 'editpost' && $post_data['edit_poll']) ) && $is_auth['auth_pollcreate'] ) +{ + $template->assign_vars(array( + 'L_ADD_A_POLL' => $lang['ADD_POLL'], + 'L_ADD_POLL_EXPLAIN' => $lang['ADD_POLL_EXPLAIN'], + 'L_POLL_QUESTION' => $lang['POLL_QUESTION'], + 'L_POLL_OPTION' => $lang['POLL_OPTION'], + 'L_ADD_OPTION' => $lang['ADD_OPTION'], + 'L_POLL_LENGTH' => $lang['POLL_FOR'], + 'L_DAYS' => $lang['DAYS'], + 'L_POLL_LENGTH_EXPLAIN' => $lang['POLL_FOR_EXPLAIN'], + 'L_POLL_DELETE' => $lang['DELETE_POLL'], + + 'POLL_TITLE' => @$poll_title, + 'POLL_LENGTH' => @$poll_length) + ); + + if( $mode == 'editpost' && $post_data['edit_poll'] && $post_data['has_poll']) + { + $template->assign_block_vars('switch_poll_delete_toggle', array()); + } + + if( !empty($poll_options) ) + { + while( list($option_id, $option_text) = each($poll_options) ) + { + $template->assign_block_vars('poll_option_rows', array( + 'POLL_OPTION' => str_replace('"', '"', $option_text), + + 'S_POLL_OPTION_NUM' => $option_id) + ); + } + } + + $template->assign_var('POLLBOX'); +} + +// +// Topic review +// +if( $mode == 'reply' && $is_auth['auth_read'] ) +{ + topic_review($topic_id); +} + +require(PAGE_HEADER); + +$template->pparse('body'); + +require(PAGE_FOOTER); \ No newline at end of file diff --git a/upload/privmsg.php b/upload/privmsg.php new file mode 100644 index 000000000..ab40d8e18 --- /dev/null +++ b/upload/privmsg.php @@ -0,0 +1,1901 @@ +#', '#"#'); +$html_entities_replace = array('&', '<', '>', '"'); + +// +// Parameters +// +//$submit = ( isset($_POST['post']) ) ? TRUE : 0; +$submit = (bool) request_var('post', false); //test it! +$submit_search = ( isset($_POST['usersubmit']) ) ? TRUE : 0; +$submit_msgdays = ( isset($_POST['submit_msgdays']) ) ? TRUE : 0; +$cancel = ( isset($_POST['cancel']) ) ? TRUE : 0; +$preview = ( isset($_POST['preview']) ) ? TRUE : 0; +$confirmed = ( isset($_POST['confirm']) ) ? TRUE : 0; +$delete = ( isset($_POST['delete']) ) ? TRUE : 0; +$delete_all = ( isset($_POST['deleteall']) ) ? TRUE : 0; +$save = ( isset($_POST['save']) ) ? TRUE : 0; +$mode = isset($_REQUEST['mode']) ? (string) $_REQUEST['mode'] : ''; + +$refresh = $preview || $submit_search; + +$mark_list = ( !empty($_POST['mark']) ) ? $_POST['mark'] : 0; + +if ($folder =& $_REQUEST['folder']) +{ + if ($folder != 'inbox' && $folder != 'outbox' && $folder != 'sentbox' && $folder != 'savebox') + { + $folder = 'inbox'; + } +} +else +{ + $folder = 'inbox'; +} + +// Start session management +$user->session_start(array('req_login' => true)); + +if (IS_ADMIN || IS_MOD) +{ + $bb_cfg['max_inbox_privmsgs'] += 1000; + $bb_cfg['max_sentbox_privmsgs'] += 1000; + $bb_cfg['max_savebox_privmsgs'] += 1000; +} +else if (IS_GROUP_MEMBER) +{ + $bb_cfg['max_inbox_privmsgs'] += 200; + $bb_cfg['max_sentbox_privmsgs'] += 200; + $bb_cfg['max_savebox_privmsgs'] += 200; +} + +$template->assign_vars(array( + 'IN_PM' => true, + 'L_FONT_COLOR_SEL' => $lang['QR_COLOR_SEL'], + 'L_FONT_SEL' => $lang['QR_FONT_SEL'], + 'L_FONT_SIZE_SEL' => $lang['QR_SIZE_SEL'], + 'L_STEEL_BLUE' => $lang['COLOR_STEEL_BLUE'], + 'QUICK_REPLY' => ($bb_cfg['show_quick_reply'] && $folder == 'inbox' && $mode == 'read'), +)); + +// +// Cancel +// +if ( $cancel ) +{ + redirect(append_sid("privmsg.php?folder=$folder", true)); +} + +// +// Var definitions +// +$start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; + +if ( isset($_POST[POST_POST_URL]) || isset($_GET[POST_POST_URL]) ) +{ + $privmsg_id = ( isset($_POST[POST_POST_URL]) ) ? intval($_POST[POST_POST_URL]) : intval($_GET[POST_POST_URL]); +} +else +{ + $privmsg_id = ''; +} + +$error = FALSE; + +// +// Define the box image links +// +$inbox_url = ( $folder != 'inbox' || $mode != '' ) ? ''. $lang['INBOX'] .'' : $lang['INBOX']; + +$outbox_url = ( $folder != 'outbox' || $mode != '' ) ? ''. $lang['OUTBOX'] .'' : $lang['OUTBOX']; + +$sentbox_url = ( $folder != 'sentbox' || $mode != '' ) ? ''. $lang['SENTBOX'] .'' : $lang['SENTBOX']; + +$savebox_url = ( $folder != 'savebox' || $mode != '' ) ? ''. $lang['SAVEBOX'] .'' : $lang['SAVEBOX']; + +// ---------- +// Start main +// + +$template->assign_var('POSTING_SUBJECT'); + +if ( $mode == 'read' ) +{ + if ( !empty($_GET[POST_POST_URL]) ) + { + $privmsgs_id = intval($_GET[POST_POST_URL]); + } + else + { + message_die(GENERAL_ERROR, $lang['NO_POST_ID']); + } + + // + // SQL to pull appropriate message, prevents nosey people + // reading other peoples messages ... hopefully! + // + switch( $folder ) + { + case 'inbox': + $l_box_name = $lang['INBOX']; + $pm_sql_user = "AND pm.privmsgs_to_userid = " . $userdata['user_id'] . " + AND ( pm.privmsgs_type = " . PRIVMSGS_READ_MAIL . " + OR pm.privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR pm.privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + case 'outbox': + $l_box_name = $lang['OUTBOX']; + $pm_sql_user = "AND pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND ( pm.privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR pm.privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " ) "; + break; + case 'sentbox': + $l_box_name = $lang['SENTBOX']; + $pm_sql_user = "AND pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND pm.privmsgs_type = " . PRIVMSGS_SENT_MAIL; + break; + case 'savebox': + $l_box_name = $lang['SAVEBOX']; + $pm_sql_user = "AND ( ( pm.privmsgs_to_userid = " . $userdata['user_id'] . " + AND pm.privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) + OR ( pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND pm.privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . " ) + )"; + break; + default: + message_die(GENERAL_ERROR, $lang['NO_SUCH_FOLDER']); + break; + } + + // + // Major query obtains the message ... + // + $sql = "SELECT u.username AS username_1, u.user_id AS user_id_1, u2.username AS username_2, u2.user_id AS user_id_2, u.user_posts, u.user_from, u.user_email, u.user_regdate, u.user_rank, u.user_avatar, pm.*, pmt.privmsgs_bbcode_uid, pmt.privmsgs_text + FROM " . BB_PRIVMSGS . " pm, " . BB_PRIVMSGS_TEXT . " pmt, " . BB_USERS . " u, " . BB_USERS . " u2 + WHERE pm.privmsgs_id = $privmsgs_id + AND pmt.privmsgs_text_id = pm.privmsgs_id + $pm_sql_user + AND u.user_id = pm.privmsgs_from_userid + AND u2.user_id = pm.privmsgs_to_userid"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query private message post information', '', __LINE__, __FILE__, $sql); + } + + // + // Did the query return any data? + // + if ( !($privmsg = DB()->sql_fetchrow($result)) ) + { + redirect(append_sid("privmsg.php?folder=$folder", true)); + } + + $privmsg_id = $privmsg['privmsgs_id']; + + // + // Is this a new message in the inbox? If it is then save + // a copy in the posters sent box + // + if (($privmsg['privmsgs_type'] == PRIVMSGS_NEW_MAIL || $privmsg['privmsgs_type'] == PRIVMSGS_UNREAD_MAIL) && $folder == 'inbox') + { + // Update appropriate counter + switch ($privmsg['privmsgs_type']) + { + case PRIVMSGS_NEW_MAIL: + $sql = "user_new_privmsg = IF(user_new_privmsg, user_new_privmsg - 1, 0)"; + break; + case PRIVMSGS_UNREAD_MAIL: + $sql = "user_unread_privmsg = IF(user_unread_privmsg, user_unread_privmsg - 1, 0)"; + break; + } + + $sql = "UPDATE " . BB_USERS . " + SET $sql + WHERE user_id = " . $userdata['user_id']; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update private message read status for user', '', __LINE__, __FILE__, $sql); + } + if (DB()->affected_rows()) + { + cache_rm_userdata($userdata); + } + + $sql = "UPDATE " . BB_PRIVMSGS . " + SET privmsgs_type = " . PRIVMSGS_READ_MAIL . " + WHERE privmsgs_id = " . $privmsg['privmsgs_id']; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update private message read status', '', __LINE__, __FILE__, $sql); + } + + // Check to see if the poster has a 'full' sent box + $sql = "SELECT COUNT(privmsgs_id) AS sent_items, MIN(privmsgs_date) AS oldest_post_time + FROM " . BB_PRIVMSGS . " + WHERE privmsgs_type = " . PRIVMSGS_SENT_MAIL . " + AND privmsgs_from_userid = " . $privmsg['privmsgs_from_userid']; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain sent message info for sendee', '', __LINE__, __FILE__, $sql); + } + + if ( $sent_info = DB()->sql_fetchrow($result) ) + { + if ($bb_cfg['max_sentbox_privmsgs'] && $sent_info['sent_items'] >= $bb_cfg['max_sentbox_privmsgs']) + { + $sql = "SELECT privmsgs_id FROM " . BB_PRIVMSGS . " + WHERE privmsgs_type = " . PRIVMSGS_SENT_MAIL . " + AND privmsgs_date = " . $sent_info['oldest_post_time'] . " + AND privmsgs_from_userid = " . $privmsg['privmsgs_from_userid']; + if ( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not find oldest privmsgs', '', __LINE__, __FILE__, $sql); + } + $old_privmsgs_id = DB()->sql_fetchrow($result); + $old_privmsgs_id = (int) $old_privmsgs_id['privmsgs_id']; + + $sql = "DELETE FROM " . BB_PRIVMSGS . " + WHERE privmsgs_id = $old_privmsgs_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete oldest privmsgs (sent)', '', __LINE__, __FILE__, $sql); + } + + $sql = "DELETE FROM " . BB_PRIVMSGS_TEXT . " + WHERE privmsgs_text_id = $old_privmsgs_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete oldest privmsgs text (sent)', '', __LINE__, __FILE__, $sql); + } + } + } + + // + // This makes a copy of the post and stores it as a SENT message from the sendee. Perhaps + // not the most DB friendly way but a lot easier to manage, besides the admin will be able to + // set limits on numbers of storable posts for users ... hopefully! + // + $sql = "INSERT INTO " . BB_PRIVMSGS . " (privmsgs_type, privmsgs_subject, privmsgs_from_userid, privmsgs_to_userid, privmsgs_date, privmsgs_ip, privmsgs_enable_bbcode, privmsgs_enable_smilies) + VALUES (" . PRIVMSGS_SENT_MAIL . ", '" . str_replace("\'", "''", addslashes($privmsg['privmsgs_subject'])) . "', " . $privmsg['privmsgs_from_userid'] . ", " . $privmsg['privmsgs_to_userid'] . ", " . $privmsg['privmsgs_date'] . ", '" . $privmsg['privmsgs_ip'] . "', " . $privmsg['privmsgs_enable_bbcode'] . ", " . $privmsg['privmsgs_enable_smilies'] . ")"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not insert private message sent info', '', __LINE__, __FILE__, $sql); + } + + $privmsg_sent_id = DB()->sql_nextid(); + + $sql = "INSERT INTO " . BB_PRIVMSGS_TEXT . " (privmsgs_text_id, privmsgs_bbcode_uid, privmsgs_text) + VALUES ($privmsg_sent_id, '" . $privmsg['privmsgs_bbcode_uid'] . "', '" . str_replace("\'", "''", addslashes($privmsg['privmsgs_text'])) . "')"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not insert private message sent text', '', __LINE__, __FILE__, $sql); + } + } + + // + // Pick a folder, any folder, so long as it's one below ... + // + $post_urls = array( + 'post' => append_sid("privmsg.php?mode=post"), + 'reply' => append_sid("privmsg.php?mode=reply&" . POST_POST_URL . "=$privmsg_id"), + 'quote' => append_sid("privmsg.php?mode=quote&" . POST_POST_URL . "=$privmsg_id"), + 'edit' => append_sid("privmsg.php?mode=edit&" . POST_POST_URL . "=$privmsg_id") + ); + $post_icons = array( + 'post_img' => '' . $lang['POST_NEW_PM'] . '', + 'post' => '' . $lang['POST_NEW_PM'] . '', + 'reply_img' => '' . $lang['POST_REPLY_PM'] . '', + 'reply' => '' . $lang['POST_REPLY_PM'] . '', + 'quote_img' => '' . $lang['POST_QUOTE_PM'] . '', + 'quote' => '' . $lang['POST_QUOTE_PM'] . '', + 'edit_img' => '' . $lang['EDIT_PM'] . '', + 'edit' => '' . $lang['EDIT_PM'] . '' + ); + + if ( $folder == 'inbox' ) + { + $post_img = $post_icons['post_img']; + $reply_img = $post_icons['reply_img']; + $quote_img = $post_icons['quote_img']; + $edit_img = ''; + $post = $post_icons['post']; + $reply = $post_icons['reply']; + $quote = $post_icons['quote']; + $edit = ''; + $l_box_name = $lang['INBOX']; + } + else if ( $folder == 'outbox' ) + { + $post_img = $post_icons['post_img']; + $reply_img = ''; + $quote_img = ''; + $edit_img = $post_icons['edit_img']; + $post = $post_icons['post']; + $reply = ''; + $quote = ''; + $edit = $post_icons['edit']; + $l_box_name = $lang['OUTBOX']; + } + else if ( $folder == 'savebox' ) + { + if ( $privmsg['privmsgs_type'] == PRIVMSGS_SAVED_IN_MAIL ) + { + $post_img = $post_icons['post_img']; + $reply_img = $post_icons['reply_img']; + $quote_img = $post_icons['quote_img']; + $edit_img = ''; + $post = $post_icons['post']; + $reply = $post_icons['reply']; + $quote = $post_icons['quote']; + $edit = ''; + } + else + { + $post_img = $post_icons['post_img']; + $reply_img = ''; + $quote_img = ''; + $edit_img = ''; + $post = $post_icons['post']; + $reply = ''; + $quote = ''; + $edit = ''; + } + $l_box_name = $lang['SAVED']; + } + else if ( $folder == 'sentbox' ) + { + $post_img = $post_icons['post_img']; + $reply_img = ''; + $quote_img = ''; + $edit_img = ''; + $post = $post_icons['post']; + $reply = ''; + $quote = ''; + $edit = ''; + $l_box_name = $lang['SENT']; + } + + // Report + // + // Get report privmsg module and create report links + // + if ($folder == 'inbox') + { + include(INC_DIR ."functions_report.php"); + $report_privmsg = report_modules('name', 'report_privmsg'); + + if ($report_privmsg && $report_privmsg->auth_check('auth_write')) + { + if ($privmsg['privmsgs_reported']) + { + $report_img = '' . $report_privmsg->lang['DUPLICATE_REPORT'] . ''; + $report = $report_privmsg->lang['DUPLICATE_REPORT']; + } + else + { + $temp_url = append_sid("report.php?mode=" . $report_privmsg->mode . "&id=$privmsg_id"); + $report_img = '' . $report_privmsg->lang['WRITE_REPORT'] . ''; + $report = '' . $report_privmsg->lang['WRITE_REPORT'] . ''; + } + + $template->assign_vars(array( + 'REPORT_PM_IMG' => $report_img, + 'REPORT_PM' => $report) + ); + } + } + // Report [END] + + $s_hidden_fields = ''; + + $page_title = $lang['READ_PM']; + + // + // Load templates + // + $template->set_filenames(array( + 'body' => 'privmsgs_read.tpl') + ); + + $template->assign_vars(array( + 'INBOX' => $inbox_url, + + 'POST_PM_IMG' => $post_img, + 'REPLY_PM_IMG' => $reply_img, + 'EDIT_PM_IMG' => $edit_img, + 'QUOTE_PM_IMG' => $quote_img, + 'POST_PM' => $post, + 'REPLY_PM' => $reply, + 'EDIT_PM' => $edit, + 'QUOTE_PM' => $quote, + + 'SENTBOX' => $sentbox_url, + 'OUTBOX' => $outbox_url, + 'SAVEBOX' => $savebox_url, + + 'BOX_NAME' => $l_box_name, + + 'L_SENTBOX' => $lang['SENT'], + 'L_SAVEBOX' => $lang['SAVED'], + 'L_SAVE_MSG' => $lang['SAVE_MESSAGE'], + 'L_DELETE_MSG' => $lang['DELETE_MESSAGE'], + + 'S_PRIVMSGS_ACTION' => append_sid("privmsg.php?folder=$folder"), + 'S_HIDDEN_FIELDS' => $s_hidden_fields) + ); + + $username_from = $privmsg['username_1']; + $user_id_from = $privmsg['user_id_1']; + $username_to = $privmsg['username_2']; + $user_id_to = $privmsg['user_id_2']; + + $post_date = bb_date($privmsg['privmsgs_date']); + + $temp_url = append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $user_id_from); + $profile_img = '' . $lang['READ_PROFILE'] . ''; + $profile = '' . $lang['READ_PROFILE'] . ''; + + $temp_url = append_sid("privmsg.php?mode=post&" . POST_USERS_URL . "=$user_id_from"); + $pm_img = '' . $lang['SEND_PRIVATE_MESSAGE'] . ''; + $pm = '' . $lang['SEND_PRIVATE_MESSAGE'] . ''; + + $temp_url = append_sid("search.php?search_author=1&uid=$user_id_from"); + $search_img = '' . sprintf($lang['SEARCH_USER_POSTS'], $username_from) . ''; + $search = '' . sprintf($lang['SEARCH_USER_POSTS'], $username_from) . ''; + + // + // Processing of post + // + $post_subject = htmlCHR($privmsg['privmsgs_subject']); + + $private_message = $privmsg['privmsgs_text']; + $bbcode_uid = $privmsg['privmsgs_bbcode_uid']; + + if ( $bbcode_uid != '' ) + { + $private_message = ( $bb_cfg['allow_bbcode'] ) ? bbencode_second_pass($private_message, $bbcode_uid) : preg_replace('/\:[0-9a-z\:]+\]/si', ']', $private_message); + } + + $orig_word = array(); + $replacement_word = array(); + obtain_word_list($orig_word, $replacement_word); + + if ( count($orig_word) ) + { + $post_subject = preg_replace($orig_word, $replacement_word, $post_subject); + $private_message = preg_replace($orig_word, $replacement_word, $private_message); + } + + $private_message = str_replace("\n", '
    ', $private_message); + + // + // Dump it to the templating engine + // + $template->assign_vars(array( + 'TO_USER_ID' => $user_id_to, + 'TO_USER_NAME' => $username_to, + 'FROM_USER_ID' => $user_id_from, + 'FROM_USER_NAME' => $username_from, + + 'QR_SUBJECT' => ((!preg_match('/^Re:/', $post_subject)) ? 'Re: ' : '') . $post_subject, + 'MESSAGE_TO' => $username_to, + 'MESSAGE_FROM' => $username_from, + 'RANK_IMAGE' => (@$rank_image) ? $rank_image : '', + 'POSTER_JOINED' => (@$poster_joined) ? $poster_joined : '', + 'POSTER_POSTS' => (@$poster_posts) ? $poster_posts : '', + 'POSTER_FROM' => (@$poster_from) ? $poster_from : '', + 'POSTER_AVATAR' => (@$poster_avatar) ? $poster_avatar : '', + 'POST_SUBJECT' => $post_subject, + 'POST_DATE' => $post_date, + 'PM_MESSAGE' => $private_message, + + 'PROFILE_IMG' => $profile_img, + 'PROFILE' => $profile, + 'SEARCH_IMG' => $search_img, + 'SEARCH' => $search, + )); +} +else if ( ( $delete && $mark_list ) || $delete_all ) +{ + if ( isset($mark_list) && !is_array($mark_list) ) + { + // Set to empty array instead of '0' if nothing is selected. + $mark_list = array(); + } + + if (!$confirmed) + { + $delete = isset($_POST['delete']) ? 'delete' : 'deleteall'; + + $hidden_fields = array( + 'mode' => $mode, + $delete => 1, + ); + foreach ($mark_list as $pm_id) + { + $hidden_fields['mark'][] = (int) $pm_id; + } + + print_confirmation(array( + 'QUESTION' => (count($mark_list) == 1) ? $lang['CONFIRM_DELETE_PM'] : $lang['CONFIRM_DELETE_PMS'], + 'FORM_ACTION' => "privmsg.php?folder=$folder", + 'HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + )); + } + else if ( $confirmed ) + { + $delete_sql_id = ''; + + if (!$delete_all) + { + for ($i = 0; $i < count($mark_list); $i++) + { + $delete_sql_id .= (($delete_sql_id != '') ? ', ' : '') . intval($mark_list[$i]); + } + $delete_sql_id = "AND privmsgs_id IN ($delete_sql_id)"; + } + + switch($folder) + { + case 'inbox': + $delete_type = "privmsgs_to_userid = " . $userdata['user_id'] . " AND ( + privmsgs_type = " . PRIVMSGS_READ_MAIL . " OR privmsgs_type = " . PRIVMSGS_NEW_MAIL . " OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + + case 'outbox': + $delete_type = "privmsgs_from_userid = " . $userdata['user_id'] . " AND ( privmsgs_type = " . PRIVMSGS_NEW_MAIL . " OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + + case 'sentbox': + $delete_type = "privmsgs_from_userid = " . $userdata['user_id'] . " AND privmsgs_type = " . PRIVMSGS_SENT_MAIL; + break; + + case 'savebox': + $delete_type = "( ( privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . " ) + OR ( privmsgs_to_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) )"; + break; + } + + $sql = "SELECT privmsgs_id + FROM " . BB_PRIVMSGS . " + WHERE $delete_type $delete_sql_id"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain id list to delete messages', '', __LINE__, __FILE__, $sql); + } + + $mark_list = array(); + while ( $row = DB()->sql_fetchrow($result) ) + { + $mark_list[] = $row['privmsgs_id']; + } + + unset($delete_type); + + if ( count($mark_list) ) + { + $delete_sql_id = ''; + for ($i = 0; $i < sizeof($mark_list); $i++) + { + $delete_sql_id .= (($delete_sql_id != '') ? ', ' : '') . intval($mark_list[$i]); + } + + if ($folder == 'inbox' || $folder == 'outbox') + { + switch ($folder) + { + case 'inbox': + $sql = "privmsgs_to_userid = " . $userdata['user_id']; + break; + case 'outbox': + $sql = "privmsgs_from_userid = " . $userdata['user_id']; + break; + } + + // Get information relevant to new or unread mail + // so we can adjust users counters appropriately + $sql = "SELECT privmsgs_to_userid, privmsgs_type + FROM " . BB_PRIVMSGS . " + WHERE privmsgs_id IN ($delete_sql_id) + AND $sql + AND privmsgs_type IN (" . PRIVMSGS_NEW_MAIL . ", " . PRIVMSGS_UNREAD_MAIL . ")"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain user id list for outbox messages', '', __LINE__, __FILE__, $sql); + } + + if ( $row = DB()->sql_fetchrow($result)) + { + $update_users = $update_list = array(); + + do + { + switch ($row['privmsgs_type']) + { + case PRIVMSGS_NEW_MAIL: + @$update_users['new'][$row['privmsgs_to_userid']]++; + break; + + case PRIVMSGS_UNREAD_MAIL: + @$update_users['unread'][$row['privmsgs_to_userid']]++; + break; + } + } + while ($row = DB()->sql_fetchrow($result)); + + if (sizeof($update_users)) + { + while (list($type, $users) = each($update_users)) + { + while (list($user_id, $dec) = each($users)) + { + $update_list[$type][$dec][] = $user_id; + } + } + unset($update_users); + + while (list($type, $dec_ary) = each($update_list)) + { + switch ($type) + { + case 'new': + $type = "user_new_privmsg"; + break; + + case 'unread': + $type = "user_unread_privmsg"; + break; + } + + while (list($dec, $user_ary) = each($dec_ary)) + { + $user_ids = join(', ', $user_ary); + + $sql = "UPDATE " . BB_USERS . " + SET $type = $type - $dec + WHERE user_id IN ($user_ids)"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update user pm counters', '', __LINE__, __FILE__, $sql); + } + } + } + unset($update_list); + } + } + DB()->sql_freeresult($result); + } + + // Delete the messages + $delete_text_sql = "DELETE FROM " . BB_PRIVMSGS_TEXT . " + WHERE privmsgs_text_id IN ($delete_sql_id)"; + $delete_sql = "DELETE FROM " . BB_PRIVMSGS . " + WHERE privmsgs_id IN ($delete_sql_id) + AND "; + + switch( $folder ) + { + case 'inbox': + $delete_sql .= "privmsgs_to_userid = " . $userdata['user_id'] . " AND ( + privmsgs_type = " . PRIVMSGS_READ_MAIL . " OR privmsgs_type = " . PRIVMSGS_NEW_MAIL . " OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + + case 'outbox': + $delete_sql .= "privmsgs_from_userid = " . $userdata['user_id'] . " AND ( + privmsgs_type = " . PRIVMSGS_NEW_MAIL . " OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + + case 'sentbox': + $delete_sql .= "privmsgs_from_userid = " . $userdata['user_id'] . " AND privmsgs_type = " . PRIVMSGS_SENT_MAIL; + break; + + case 'savebox': + $delete_sql .= "( ( privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . " ) + OR ( privmsgs_to_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) )"; + break; + } + + if ( !DB()->sql_query($delete_sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete private message info', '', __LINE__, __FILE__, $delete_sql); + } + + if ( !DB()->sql_query($delete_text_sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete private message text', '', __LINE__, __FILE__, $delete_text_sql); + } + + pm_message_die($lang['DELETE_POSTS_SUCCESFULLY']); + } + else + { + pm_message_die($lang['NONE_SELECTED']); + } + } +} +else if ( $save && $mark_list && $folder != 'savebox' && $folder != 'outbox' ) +{ + if (sizeof($mark_list)) + { + // See if recipient is at their savebox limit + $sql = "SELECT COUNT(privmsgs_id) AS savebox_items, MIN(privmsgs_date) AS oldest_post_time + FROM " . BB_PRIVMSGS . " + WHERE ( ( privmsgs_to_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) + OR ( privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . ") )"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain sent message info for sendee', '', __LINE__, __FILE__, $sql); + } + + if ( $saved_info = DB()->sql_fetchrow($result) ) + { + if ($bb_cfg['max_savebox_privmsgs'] && $saved_info['savebox_items'] >= $bb_cfg['max_savebox_privmsgs'] ) + { + $sql = "SELECT privmsgs_id FROM " . BB_PRIVMSGS . " + WHERE ( ( privmsgs_to_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) + OR ( privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . ") ) + AND privmsgs_date = " . $saved_info['oldest_post_time']; + if ( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not find oldest privmsgs (save)', '', __LINE__, __FILE__, $sql); + } + $old_privmsgs_id = DB()->sql_fetchrow($result); + $old_privmsgs_id = (int) $old_privmsgs_id['privmsgs_id']; + + $sql = "DELETE FROM " . BB_PRIVMSGS . " + WHERE privmsgs_id = $old_privmsgs_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete oldest privmsgs (save)', '', __LINE__, __FILE__, $sql); + } + + $sql = "DELETE FROM " . BB_PRIVMSGS_TEXT . " + WHERE privmsgs_text_id = $old_privmsgs_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete oldest privmsgs text (save)', '', __LINE__, __FILE__, $sql); + } + } + } + + $saved_sql_id = ''; + for ($i = 0; $i < sizeof($mark_list); $i++) + { + $saved_sql_id .= (($saved_sql_id != '') ? ', ' : '') . intval($mark_list[$i]); + } + + // Process request + $saved_sql = "UPDATE " . BB_PRIVMSGS; + + // Decrement read/new counters if appropriate + if ($folder == 'inbox' || $folder == 'outbox') + { + switch ($folder) + { + case 'inbox': + $sql = "privmsgs_to_userid = " . $userdata['user_id']; + break; + case 'outbox': + $sql = "privmsgs_from_userid = " . $userdata['user_id']; + break; + } + + // Get information relevant to new or unread mail + // so we can adjust users counters appropriately + $sql = "SELECT privmsgs_to_userid, privmsgs_type + FROM " . BB_PRIVMSGS . " + WHERE privmsgs_id IN ($saved_sql_id) + AND $sql + AND privmsgs_type IN (" . PRIVMSGS_NEW_MAIL . ", " . PRIVMSGS_UNREAD_MAIL . ")"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain user id list for outbox messages', '', __LINE__, __FILE__, $sql); + } + + if ( $row = DB()->sql_fetchrow($result)) + { + $update_users = $update_list = array(); + + do + { + switch ($row['privmsgs_type']) + { + case PRIVMSGS_NEW_MAIL: + @$update_users['new'][$row['privmsgs_to_userid']]++; + break; + + case PRIVMSGS_UNREAD_MAIL: + @$update_users['unread'][$row['privmsgs_to_userid']]++; + break; + } + } + while ($row = DB()->sql_fetchrow($result)); + + if (sizeof($update_users)) + { + while (list($type, $users) = each($update_users)) + { + while (list($user_id, $dec) = each($users)) + { + $update_list[$type][$dec][] = $user_id; + } + } + unset($update_users); + + while (list($type, $dec_ary) = each($update_list)) + { + switch ($type) + { + case 'new': + $type = "user_new_privmsg"; + break; + + case 'unread': + $type = "user_unread_privmsg"; + break; + } + + while (list($dec, $user_ary) = each($dec_ary)) + { + $user_ids = join(', ', $user_ary); + + $sql = "UPDATE " . BB_USERS . " + SET $type = $type - $dec + WHERE user_id IN ($user_ids)"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update user pm counters', '', __LINE__, __FILE__, $sql); + } + } + } + unset($update_list); + } + } + DB()->sql_freeresult($result); + } + + switch ($folder) + { + case 'inbox': + $saved_sql .= " SET privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " + WHERE privmsgs_to_userid = " . $userdata['user_id'] . " + AND ( privmsgs_type = " . PRIVMSGS_READ_MAIL . " + OR privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . ")"; + break; + + case 'outbox': + $saved_sql .= " SET privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . " + WHERE privmsgs_from_userid = " . $userdata['user_id'] . " + AND ( privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " ) "; + break; + + case 'sentbox': + $saved_sql .= " SET privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . " + WHERE privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SENT_MAIL; + break; + } + + $saved_sql .= " AND privmsgs_id IN ($saved_sql_id)"; + + if ( !DB()->sql_query($saved_sql) ) + { + message_die(GENERAL_ERROR, 'Could not save private messages', '', __LINE__, __FILE__, $saved_sql); + } + + redirect(append_sid("privmsg.php?folder=savebox", true)); + } +} +else if ( $submit || $refresh || $mode != '' ) +{ + // + // Toggles + // + if ( !$bb_cfg['allow_bbcode'] ) + { + $bbcode_on = 0; + } + else + { + $bbcode_on = ($submit || $refresh) ? (int) empty($_POST['disable_bbcode']) : $bb_cfg['allow_bbcode']; + } + + if ( !$bb_cfg['allow_smilies'] ) + { + $smilies_on = 0; + } + else + { + $smilies_on = ($submit || $refresh) ? (int) empty($_POST['disable_smilies']) : $bb_cfg['allow_smilies']; + } + + if (IS_USER && $submit && $mode != 'edit') + { + // + // Flood control + // + $sql = "SELECT MAX(privmsgs_date) AS last_post_time + FROM " . BB_PRIVMSGS . " + WHERE privmsgs_from_userid = " . $userdata['user_id']; + if ( $result = DB()->sql_query($sql) ) + { + $db_row = DB()->sql_fetchrow($result); + + $last_post_time = $db_row['last_post_time']; + $current_time = time(); + + if ( ( $current_time - $last_post_time ) < $bb_cfg['flood_interval']) + { + message_die(GENERAL_MESSAGE, $lang['FLOOD_ERROR']); + } + } + // + // End Flood control + // + } + + if ($submit && $mode == 'edit') + { + $sql = 'SELECT privmsgs_from_userid + FROM ' . BB_PRIVMSGS . ' + WHERE privmsgs_id = ' . (int) $privmsg_id . ' + AND privmsgs_from_userid = ' . $userdata['user_id']; + + if (!($result = DB()->sql_query($sql))) + { + message_die(GENERAL_ERROR, "Could not obtain message details", "", __LINE__, __FILE__, $sql); + } + + if (!($row = DB()->sql_fetchrow($result))) + { + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_POST']); + } + DB()->sql_freeresult($result); + + unset($row); + } + + if ( $submit ) + { + if ( !empty($_POST['username']) ) + { + $to_username = clean_username($_POST['username']); + // DelUsrKeepPM + $to_username_sql = str_replace("\'", "''", $to_username); + + $sql = "SELECT user_id, user_notify_pm, user_email, user_lang, user_active + FROM " . BB_USERS . " + WHERE username = '$to_username_sql'"; + + $to_userdata = DB()->sql_fetchrow(DB()->sql_query($sql)); + + if (!$to_userdata || $to_userdata['user_id'] == ANONYMOUS) + { + $error = TRUE; + $error_msg = $lang['NO_SUCH_USER']; + } + // DelUsrKeepPM end + } + else + { + $error = TRUE; + $error_msg .= ( ( !empty($error_msg) ) ? '
    ' : '' ) . $lang['NO_TO_USER']; + } + + $privmsg_subject = trim(strip_tags($_POST['subject'])); + if ( empty($privmsg_subject) ) + { + $error = TRUE; + $error_msg .= ( ( !empty($error_msg) ) ? '
    ' : '' ) . $lang['EMPTY_SUBJECT']; + } + + if ( !empty($_POST['message']) ) + { + if ( !$error ) + { + $privmsg_message = bbcode2html($_POST['message']); + } + } + else + { + $error = TRUE; + $error_msg .= ( ( !empty($error_msg) ) ? '
    ' : '' ) . $lang['EMPTY_MESSAGE']; + } + } + + if ( $submit && !$error ) + { + // + // Has admin prevented user from sending PM's? + // + if ( !$userdata['user_allow_pm'] ) + { + $message = $lang['CANNOT_SEND_PRIVMSG']; + message_die(GENERAL_MESSAGE, $message); + } + + $msg_time = time(); + + if ( $mode != 'edit' ) + { + // + // See if recipient is at their inbox limit + // + $sql = "SELECT COUNT(privmsgs_id) AS inbox_items, MIN(privmsgs_date) AS oldest_post_time + FROM " . BB_PRIVMSGS . " + WHERE ( privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_READ_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " ) + AND privmsgs_to_userid = " . $to_userdata['user_id']; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_USER']); + } + + if ( $inbox_info = DB()->sql_fetchrow($result) ) + { + if ($bb_cfg['max_inbox_privmsgs'] && $inbox_info['inbox_items'] >= $bb_cfg['max_inbox_privmsgs']) + { + $sql = "SELECT privmsgs_id FROM " . BB_PRIVMSGS . " + WHERE ( privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_READ_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " ) + AND privmsgs_date = " . $inbox_info['oldest_post_time'] . " + AND privmsgs_to_userid = " . $to_userdata['user_id']; + if ( !$result = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not find oldest privmsgs (inbox)', '', __LINE__, __FILE__, $sql); + } + $old_privmsgs_id = DB()->sql_fetchrow($result); + $old_privmsgs_id = (int) $old_privmsgs_id['privmsgs_id']; + + $sql = "DELETE FROM " . BB_PRIVMSGS . " + WHERE privmsgs_id = $old_privmsgs_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete oldest privmsgs (inbox)'.$sql, '', __LINE__, __FILE__, $sql); + } + + $sql = "DELETE FROM " . BB_PRIVMSGS_TEXT . " + WHERE privmsgs_text_id = $old_privmsgs_id"; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not delete oldest privmsgs text (inbox)', '', __LINE__, __FILE__, $sql); + } + } + } + + $sql_info = "INSERT INTO " . BB_PRIVMSGS . " (privmsgs_type, privmsgs_subject, privmsgs_from_userid, privmsgs_to_userid, privmsgs_date, privmsgs_ip, privmsgs_enable_bbcode, privmsgs_enable_smilies) + VALUES (" . PRIVMSGS_NEW_MAIL . ", '" . str_replace("\'", "''", $privmsg_subject) . "', " . $userdata['user_id'] . ", " . $to_userdata['user_id'] . ", $msg_time, '". USER_IP ."', $bbcode_on, $smilies_on)"; + } + else + { + $sql_info = "UPDATE " . BB_PRIVMSGS . " + SET privmsgs_type = " . PRIVMSGS_NEW_MAIL . ", privmsgs_subject = '" . str_replace("\'", "''", $privmsg_subject) . "', privmsgs_from_userid = " . $userdata['user_id'] . ", privmsgs_to_userid = " . $to_userdata['user_id'] . ", privmsgs_date = $msg_time, privmsgs_ip = '". USER_IP ."', privmsgs_enable_bbcode = $bbcode_on, privmsgs_enable_smilies = $smilies_on + WHERE privmsgs_id = $privmsg_id"; + } + + if ( !($result = DB()->sql_query($sql_info)) ) + { + message_die(GENERAL_ERROR, "Could not insert/update private message sent info.", "", __LINE__, __FILE__, $sql_info); + } + + if ( $mode != 'edit' ) + { + $privmsg_sent_id = DB()->sql_nextid(); + + $sql = "INSERT INTO " . BB_PRIVMSGS_TEXT . " (privmsgs_text_id, privmsgs_bbcode_uid, privmsgs_text) + VALUES ($privmsg_sent_id, '" . @$bbcode_uid . "', '" . str_replace("\'", "''", $privmsg_message) . "')"; + } + else + { + $sql = "UPDATE " . BB_PRIVMSGS_TEXT . " + SET privmsgs_text = '" . str_replace("\'", "''", $privmsg_message) . "', privmsgs_bbcode_uid = '$bbcode_uid' + WHERE privmsgs_text_id = $privmsg_id"; + } + + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, "Could not insert/update private message sent text.", "", __LINE__, __FILE__, $sql_info); + } + + if ( $mode != 'edit' ) + { + $timenow = TIMENOW; + // + // Add to the users new pm counter + // + $sql = "UPDATE ". BB_USERS ." SET + user_new_privmsg = user_new_privmsg + 1, + user_last_privmsg = $timenow, + user_newest_pm_id = $privmsg_sent_id + WHERE user_id = {$to_userdata['user_id']} + LIMIT 1"; + + if ( !$status = DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update private message new/read status for user', '', __LINE__, __FILE__, $sql); + } + + if ( $to_userdata['user_notify_pm'] && !empty($to_userdata['user_email']) && $to_userdata['user_active'] && $bb_cfg['pm_notify_enabled'] ) + { + $script_name = preg_replace('/^\/?(.*?)\/?$/', "\\1", trim($bb_cfg['script_path'])); + $script_name = ( $script_name != '' ) ? $script_name . '/privmsg.php' : 'privmsg.php'; + $server_name = trim($bb_cfg['server_name']); + $server_protocol = ( $bb_cfg['cookie_secure'] ) ? 'https://' : 'http://'; + $server_port = ( $bb_cfg['server_port'] <> 80 ) ? ':' . trim($bb_cfg['server_port']) . '/' : '/'; + + include(INC_DIR .'emailer.class.php'); + $emailer = new emailer($bb_cfg['smtp_delivery']); + + $emailer->from($bb_cfg['board_email']); + $emailer->replyto($bb_cfg['board_email']); + + $emailer->use_template('privmsg_notify', $to_userdata['user_lang']); + $emailer->email_address($to_userdata['user_email']); + $emailer->set_subject($lang['NOTIFICATION_SUBJECT']); + + $emailer->assign_vars(array( + 'USERNAME' => stripslashes($to_username), + 'NAME_FROM' => $userdata['username'], + 'MSG_SUBJECT' => stripslashes($privmsg_subject), + 'SITENAME' => $bb_cfg['sitename'], + 'EMAIL_SIG' => (!empty($bb_cfg['board_email_sig'])) ? str_replace('
    ', "\n", "-- \n" . $bb_cfg['board_email_sig']) : '', + + 'U_INBOX' => $server_protocol . $server_name . $server_port . $script_name . '?folder=inbox&mode=read&p=' . $privmsg_sent_id) + ); + + $emailer->send(); + $emailer->reset(); + } + } + + pm_message_die($lang['MESSAGE_SENT']); + } + else if ( $preview || $refresh || $error ) + { + + // + // If we're previewing or refreshing then obtain the data + // passed to the script, process it a little, do some checks + // where neccessary, etc. + // + $to_username = (isset($_POST['username']) ) ? trim(htmlspecialchars(stripslashes($_POST['username']))) : ''; + + $privmsg_subject = ( isset($_POST['subject']) ) ? trim(strip_tags(stripslashes($_POST['subject']))) : ''; + $privmsg_message = ( isset($_POST['message']) ) ? trim($_POST['message']) : ''; + if ( !$preview ) + { + $privmsg_message = stripslashes($privmsg_message); + } + + // + // Do mode specific things + // + if ( $mode == 'post' ) + { + $page_title = $lang['POST_NEW_PM']; + } + else if ( $mode == 'reply' ) + { + $page_title = $lang['POST_REPLY_PM']; + } + else if ( $mode == 'edit' ) + { + $page_title = $lang['EDIT_PM']; + + $sql = "SELECT u.user_id + FROM " . BB_PRIVMSGS . " pm, " . BB_USERS . " u + WHERE pm.privmsgs_id = $privmsg_id + AND u.user_id = pm.privmsgs_from_userid"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Could not obtain post and post text", "", __LINE__, __FILE__, $sql); + } + + if ( $postrow = DB()->sql_fetchrow($result) ) + { + if ( $userdata['user_id'] != $postrow['user_id'] ) + { + message_die(GENERAL_MESSAGE, $lang['EDIT_OWN_POSTS']); + } + } + } + } + else + { + if ( !$privmsg_id && ( $mode == 'reply' || $mode == 'edit' || $mode == 'quote' ) ) + { + message_die(GENERAL_ERROR, $lang['NO_POST_ID']); + } + + if ( !empty($_GET[POST_USERS_URL]) ) + { + $user_id = intval($_GET[POST_USERS_URL]); + + $sql = "SELECT username + FROM " . BB_USERS . " + WHERE user_id = $user_id + AND user_id <> " . ANONYMOUS; + if ( !($result = DB()->sql_query($sql)) ) + { + $error = TRUE; + $error_msg = $lang['NO_SUCH_USER']; + } + + if ( $row = DB()->sql_fetchrow($result) ) + { + $to_username = $row['username']; + } + } + + else if ( $mode == 'edit' ) + { + $sql = "SELECT pm.*, pmt.privmsgs_bbcode_uid, pmt.privmsgs_text, u.username, u.user_id + FROM " . BB_PRIVMSGS . " pm, " . BB_PRIVMSGS_TEXT . " pmt, " . BB_USERS . " u + WHERE pm.privmsgs_id = $privmsg_id + AND pmt.privmsgs_text_id = pm.privmsgs_id + AND pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND ( pm.privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR pm.privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " ) + AND u.user_id = pm.privmsgs_to_userid"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain private message for editing', '', __LINE__, __FILE__, $sql); + } + + if ( !($privmsg = DB()->sql_fetchrow($result)) ) + { + redirect(append_sid("privmsg.php?folder=$folder", true)); + } + + $privmsg_subject = $privmsg['privmsgs_subject']; + $privmsg_message = $privmsg['privmsgs_text']; + $privmsg_bbcode_uid = $privmsg['privmsgs_bbcode_uid']; + $privmsg_bbcode_enabled = ($privmsg['privmsgs_enable_bbcode'] == 1); + + if ( $privmsg_bbcode_enabled ) + { + $privmsg_message = preg_replace("/\:(([a-z0-9]:)?)$privmsg_bbcode_uid/si", '', $privmsg_message); + } + + $privmsg_message = str_replace('
    ', "\n", $privmsg_message); + + $to_username = $privmsg['username']; + $to_userid = $privmsg['user_id']; + + } + else if ( $mode == 'reply' || $mode == 'quote' ) + { + + $sql = "SELECT pm.privmsgs_subject, pm.privmsgs_date, pmt.privmsgs_bbcode_uid, pmt.privmsgs_text, u.username, u.user_id + FROM " . BB_PRIVMSGS . " pm, " . BB_PRIVMSGS_TEXT . " pmt, " . BB_USERS . " u + WHERE pm.privmsgs_id = $privmsg_id + AND pmt.privmsgs_text_id = pm.privmsgs_id + AND pm.privmsgs_to_userid = " . $userdata['user_id'] . " + AND u.user_id = pm.privmsgs_from_userid"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not obtain private message for editing', '', __LINE__, __FILE__, $sql); + } + + if ( !($privmsg = DB()->sql_fetchrow($result)) ) + { + redirect(append_sid("privmsg.php?folder=$folder", true)); + } + + $privmsg_subject = ( ( !preg_match('/^Re:/', $privmsg['privmsgs_subject']) ) ? 'Re: ' : '' ) . $privmsg['privmsgs_subject']; + + $to_username = $privmsg['username']; + $to_userid = $privmsg['user_id']; + + if ( $mode == 'quote' ) + { + $privmsg_message = $privmsg['privmsgs_text']; + $privmsg_bbcode_uid = $privmsg['privmsgs_bbcode_uid']; + + $privmsg_message = preg_replace("/\:(([a-z0-9]:)?)$privmsg_bbcode_uid/si", '', $privmsg_message); + $privmsg_message = str_replace('
    ', "\n", $privmsg_message); + + $msg_date = bb_date($privmsg['privmsgs_date']); + + $privmsg_message = '[quote="' . $to_username . '"]' . $privmsg_message . '[/quote]'; + + $mode = 'reply'; + } + } + else + { + $privmsg_subject = $privmsg_message = $to_username = ''; + } + } + + // + // Has admin prevented user from sending PM's? + // + if ( !$userdata['user_allow_pm'] && $mode != 'edit' ) + { + $message = $lang['CANNOT_SEND_PRIVMSG']; + message_die(GENERAL_MESSAGE, $message); + } + + // + // Start output, first preview, then errors then post form + // + $page_title = $lang['SEND_PRIVATE_MESSAGE']; + + if ( $preview && !$error ) + { + $orig_word = array(); + $replacement_word = array(); + obtain_word_list($orig_word, $replacement_word); + + $preview_message = stripslashes(bbcode2html($privmsg_message)); + $privmsg_message = stripslashes(preg_replace($html_entities_match, $html_entities_replace, $privmsg_message)); + + + if ( count($orig_word) ) + { + $preview_subject = preg_replace($orig_word, $replacement_word, $privmsg_subject); + $preview_message = preg_replace($orig_word, $replacement_word, $preview_message); + } + else + { + $preview_subject = $privmsg_subject; + } + + $preview_message = str_replace("\n", '
    ', $preview_message); + + $s_hidden_fields = ''; + $s_hidden_fields .= ''; + + if ( isset($privmsg_id) ) + { + $s_hidden_fields .= ''; + } + + $template->assign_vars(array( + 'TPL_PREVIEW_POST' => true, + 'TOPIC_TITLE' => wbr($preview_subject), + 'POST_SUBJECT' => $preview_subject, + 'MESSAGE_TO' => $to_username, + 'MESSAGE_FROM' => $userdata['username'], + 'POST_DATE' => bb_date(TIMENOW), + 'PREVIEW_MSG' => $preview_message, + + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + )); + } + + // + // Start error handling + // + if ($error) + { + $template->assign_vars(array('ERROR_MESSAGE' => $error_msg)); + } + + // + // Load templates + // + $template->set_filenames(array( + 'body' => 'posting.tpl') + ); + + // + // Enable extensions in posting_body + // + $template->assign_block_vars('switch_privmsg', array()); + $template->assign_var('POSTING_USERNAME'); + + // + // BBCode toggle selection + // + if ( $bb_cfg['allow_bbcode'] ) + { + $bbcode_status = $lang['BBCODE_IS_ON']; + $template->assign_block_vars('switch_bbcode_checkbox', array()); + } + else + { + $bbcode_status = $lang['BBCODE_IS_OFF']; + } + + // + // Smilies toggle selection + // + if ( $bb_cfg['allow_smilies'] ) + { + $smilies_status = $lang['SMILIES_ARE_ON']; + $template->assign_block_vars('switch_smilies_checkbox', array()); + } + else + { + $smilies_status = $lang['SMILIES_ARE_OFF']; + } + + $post_a = ' '; + if ( $mode == 'post' ) + { + $post_a = $lang['SEND_A_NEW_MESSAGE']; + } + else if ( $mode == 'reply' ) + { + $post_a = $lang['SEND_A_REPLY']; + $mode = 'post'; + } + else if ( $mode == 'edit' ) + { + $post_a = $lang['EDIT_MESSAGE']; + } + + $s_hidden_fields = ''; + $s_hidden_fields .= ''; + if ( $mode == 'edit' ) + { + $s_hidden_fields .= ''; + } + + // + // Send smilies to template + // + generate_smilies('inline'); + + $privmsg_subject = preg_replace($html_entities_match, $html_entities_replace, $privmsg_subject); + $privmsg_subject = str_replace('"', '"', $privmsg_subject); + + $template->assign_vars(array( + 'SUBJECT' => htmlCHR($privmsg_subject), + 'USERNAME' => $to_username, + 'MESSAGE' => $privmsg_message, + 'SMILIES_STATUS' => $smilies_status, + 'BBCODE_STATUS' => sprintf($bbcode_status, '', ''), + 'FORUM_NAME' => $lang['PRIVATE_MESSAGE'], + + 'BOX_NAME' => $l_box_name, + 'INBOX' => $inbox_url, + 'SENTBOX' => $sentbox_url, + 'OUTBOX' => $outbox_url, + 'SAVEBOX' => $savebox_url, + + 'POSTING_TYPE_TITLE' => $post_a, + 'L_DISABLE_BBCODE' => $lang['DISABLE_BBCODE_PM'], + 'L_DISABLE_SMILIES' => $lang['DISABLE_SMILIES_PM'], + + 'S_BBCODE_CHECKED' => ( !$bbcode_on ) ? ' checked="checked"' : '', + 'S_SMILIES_CHECKED' => ( !$smilies_on ) ? ' checked="checked"' : '', + 'S_HIDDEN_FORM_FIELDS' => $s_hidden_fields, + 'S_POST_ACTION' => append_sid("privmsg.php"), + + 'U_SEARCH_USER' => append_sid("search.php?mode=searchuser"), + 'U_VIEW_FORUM' => append_sid("privmsg.php")) + ); + + // Output the data to the template (for MAIL.RU Keyboard) + $template->assign_vars(array( + 'SHOW_VIRTUAL_KEYBOARD' => $bb_cfg['show_virtual_keyboard'], + 'L_LAYOUT' => $lang['KB_RUS_KEYLAYOUT'], + 'L_NONE' => $lang['KB_NONE'], + 'L_TRANSLIT' => $lang['KB_TRANSLIT'], + 'L_TRADITIONAL' => $lang['KB_TRADITIONAL'], + 'L_RULES' => $lang['KB_RULES'], + 'L_SHOW' => $lang['KB_SHOW'], + 'L_CLOSE' => $lang['KB_CLOSE'], + 'L_TRANSLIT_OPERA7' => $lang['KB_TRANSLIT_OPERA7'], + 'L_TRANSLIT_MOZILLA' => $lang['KB_TRANSLIT_MOZILLA'], + 'S_VISIBILITY_RULES' => 'position:absolute;visibility:hidden;', + 'S_VISIBILITY_KEYB' => 'position:absolute;visibility:hidden;', + 'S_VISIBILITY_OFF' => '') + ); +} +else +{ + // + // Default page + // + + // + // Reset PM counters + // + $userdata['user_new_privmsg'] = 0; + $userdata['user_unread_privmsg'] = $userdata['user_new_privmsg'] + $userdata['user_unread_privmsg']; + $userdata['user_last_privmsg'] = $userdata['session_start']; + + // + // Update unread status + // + db_update_userdata($userdata, array( + 'user_unread_privmsg' => 'user_unread_privmsg + user_new_privmsg', + 'user_new_privmsg' => 0, + 'user_last_privmsg' => $userdata['session_start'], + )); + + $sql = "UPDATE " . BB_PRIVMSGS . " + SET privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " + WHERE privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + AND privmsgs_to_userid = " . $userdata['user_id']; + if ( !DB()->sql_query($sql) ) + { + message_die(GENERAL_ERROR, 'Could not update private message new/read status (2) for user', '', __LINE__, __FILE__, $sql); + } + + // + // Generate page + // + $page_title = $lang['PRIVATE_MESSAGING']; + + // + // Load templates + // + $template->set_filenames(array( + 'body' => 'privmsgs.tpl') + ); + + $orig_word = array(); + $replacement_word = array(); + obtain_word_list($orig_word, $replacement_word); + + // + // New message + // + $post_new_mesg_url = '' . $lang['SEND_A_NEW_MESSAGE'] . ''; + + // + // General SQL to obtain messages + // + $sql_tot = "SELECT COUNT(privmsgs_id) AS total + FROM " . BB_PRIVMSGS . " "; + $sql = "SELECT pm.privmsgs_type, pm.privmsgs_id, pm.privmsgs_date, pm.privmsgs_subject, u.user_id, u.username + FROM " . BB_PRIVMSGS . " pm, " . BB_USERS . " u "; + switch( $folder ) + { + case 'inbox': + $sql_tot .= "WHERE privmsgs_to_userid = " . $userdata['user_id'] . " + AND ( privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_READ_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + + $sql .= "WHERE pm.privmsgs_to_userid = " . $userdata['user_id'] . " + AND u.user_id = pm.privmsgs_from_userid + AND ( pm.privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR pm.privmsgs_type = " . PRIVMSGS_READ_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + + case 'outbox': + $sql_tot .= "WHERE privmsgs_from_userid = " . $userdata['user_id'] . " + AND ( privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + + $sql .= "WHERE pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND u.user_id = pm.privmsgs_to_userid + AND ( pm.privmsgs_type = " . PRIVMSGS_NEW_MAIL . " + OR privmsgs_type = " . PRIVMSGS_UNREAD_MAIL . " )"; + break; + + case 'sentbox': + $sql_tot .= "WHERE privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SENT_MAIL; + + $sql .= "WHERE pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND u.user_id = pm.privmsgs_to_userid + AND pm.privmsgs_type = " . PRIVMSGS_SENT_MAIL; + break; + + case 'savebox': + $sql_tot .= "WHERE ( ( privmsgs_to_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) + OR ( privmsgs_from_userid = " . $userdata['user_id'] . " + AND privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . ") )"; + + $sql .= "WHERE u.user_id = pm.privmsgs_from_userid + AND ( ( pm.privmsgs_to_userid = " . $userdata['user_id'] . " + AND pm.privmsgs_type = " . PRIVMSGS_SAVED_IN_MAIL . " ) + OR ( pm.privmsgs_from_userid = " . $userdata['user_id'] . " + AND pm.privmsgs_type = " . PRIVMSGS_SAVED_OUT_MAIL . " ) )"; + break; + + default: + message_die(GENERAL_MESSAGE, $lang['NO_SUCH_FOLDER']); + break; + } + + // + // Show messages over previous x days/months + // + if ( $submit_msgdays && ( !empty($_POST['msgdays']) || !empty($_GET['msgdays']) ) ) + { + $msg_days = ( !empty($_POST['msgdays']) ) ? intval($_POST['msgdays']) : intval($_GET['msgdays']); + $min_msg_time = time() - ($msg_days * 86400); + + $limit_msg_time_total = " AND privmsgs_date > $min_msg_time"; + $limit_msg_time = " AND pm.privmsgs_date > $min_msg_time "; + + if ( !empty($_POST['msgdays']) ) + { + $start = 0; + } + } + else + { + $limit_msg_time = $limit_msg_time_total = ''; + $msg_days = 0; + } + + $sql .= $limit_msg_time . " ORDER BY pm.privmsgs_date DESC LIMIT $start, " . $bb_cfg['topics_per_page']; + $sql_all_tot = $sql_tot; + $sql_tot .= $limit_msg_time_total; + + // + // Get messages + // + if ( !($result = DB()->sql_query($sql_tot)) ) + { + message_die(GENERAL_ERROR, 'Could not query private message information', '', __LINE__, __FILE__, $sql_tot); + } + + $pm_total = ( $row = DB()->sql_fetchrow($result) ) ? $row['total'] : 0; + + if ( !($result = DB()->sql_query($sql_all_tot)) ) + { + message_die(GENERAL_ERROR, 'Could not query private message information', '', __LINE__, __FILE__, $sql_tot); + } + + $pm_all_total = ( $row = DB()->sql_fetchrow($result) ) ? $row['total'] : 0; + + // + // Build select box + // + $previous_days = array(0, 1, 7, 14, 30, 90, 180, 364); + $previous_days_text = array($lang['ALL_POSTS'], $lang['1_DAY'], $lang['7_DAYS'], $lang['2_WEEKS'], $lang['1_MONTH'], $lang['3_MONTHS'], $lang['6_MONTHS'], $lang['1_YEAR']); + + $select_msg_days = ''; + for($i = 0; $i < count($previous_days); $i++) + { + $selected = ( $msg_days == $previous_days[$i] ) ? ' selected="selected"' : ''; + $select_msg_days .= ''; + } + + // + // Define correct icons + // + switch ( $folder ) + { + case 'inbox': + $l_box_name = $lang['INBOX']; + break; + case 'outbox': + $l_box_name = $lang['OUTBOX']; + break; + case 'savebox': + $l_box_name = $lang['SAVEBOX']; + break; + case 'sentbox': + $l_box_name = $lang['SENTBOX']; + break; + } + $post_pm = append_sid("privmsg.php?mode=post"); + $post_pm_img = '' . $lang['POST_NEW_PM'] . ''; + $post_pm = '' . $lang['POST_NEW_PM'] . ''; + + // + // Output data for inbox status + // + $box_limit_img_length = $box_limit_percent = $l_box_size_status = ''; + $max_pm = ($folder != 'outbox') ? $bb_cfg["max_{$folder}_privmsgs"] : null; + + if ($max_pm) + { + $box_limit_percent = min(round(($pm_all_total / $max_pm) * 100), 100); + $box_limit_img_length = min(round(($pm_all_total / $max_pm) * $bb_cfg['privmsg_graphic_length']), $bb_cfg['privmsg_graphic_length']); + $box_limit_remain = max(($max_pm - $pm_all_total), 0); + + $template->assign_var('PM_BOX_SIZE_INFO'); + + switch( $folder ) + { + case 'inbox': + $l_box_size_status = sprintf($lang['INBOX_SIZE'], $box_limit_percent); + break; + case 'sentbox': + $l_box_size_status = sprintf($lang['SENTBOX_SIZE'], $box_limit_percent); + break; + case 'savebox': + $l_box_size_status = sprintf($lang['SAVEBOX_SIZE'], $box_limit_percent); + break; + default: + $l_box_size_status = ''; + break; + } + } + + // + // Dump vars to template + // + $template->assign_vars(array( + 'BOX_NAME' => $l_box_name, + 'BOX_EXPL' => ($folder == 'outbox') ? $lang['OUTBOX_EXPL'] : '', + 'INBOX' => $inbox_url, + 'SENTBOX' => $sentbox_url, + 'OUTBOX' => $outbox_url, + 'SAVEBOX' => $savebox_url, + + 'POST_PM_IMG' => $post_pm_img, + 'POST_PM' => $post_pm, + + 'INBOX_LIMIT_IMG_WIDTH' => max(4, $box_limit_img_length), + 'INBOX_LIMIT_PERCENT' => $box_limit_percent, + + 'BOX_SIZE_STATUS' => ($l_box_size_status) ? $l_box_size_status : '', + + 'L_SENTBOX' => $lang['SENT'], + 'L_SAVEBOX' => $lang['SAVED'], + 'L_FROM_OR_TO' => ( $folder == 'inbox' || $folder == 'savebox' ) ? $lang['FROM'] : $lang['TO'], + + 'S_PRIVMSGS_ACTION' => append_sid("privmsg.php?folder=$folder"), + 'S_HIDDEN_FIELDS' => '', + 'S_POST_NEW_MSG' => $post_new_mesg_url, + 'S_SELECT_MSG_DAYS' => $select_msg_days, + + 'U_POST_NEW_TOPIC' => append_sid("privmsg.php?mode=post")) + ); + + // + // Okay, let's build the correct folder + // + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, 'Could not query private messages', '', __LINE__, __FILE__, $sql); + } + + if ( $row = DB()->sql_fetchrow($result) ) + { + $i = 0; + do + { + $privmsg_id = $row['privmsgs_id']; + + $flag = $row['privmsgs_type']; + + $icon_flag = ( $flag == PRIVMSGS_NEW_MAIL || $flag == PRIVMSGS_UNREAD_MAIL ) ? $images['pm_unreadmsg'] : $images['pm_readmsg']; + $icon_flag_alt = ( $flag == PRIVMSGS_NEW_MAIL || $flag == PRIVMSGS_UNREAD_MAIL ) ? $lang['UNREAD_MESSAGE'] : $lang['READ_MESSAGE']; + + $msg_userid = $row['user_id']; + $msg_username = $row['username']; + + $u_from_user_profile = append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . "=$msg_userid"); + + $msg_subject = $row['privmsgs_subject']; + + if ( count($orig_word) ) + { + $msg_subject = preg_replace($orig_word, $replacement_word, $msg_subject); + } + + $u_subject = append_sid("privmsg.php?folder=$folder&mode=read&" . POST_POST_URL . "=$privmsg_id"); + + $msg_date = bb_date($row['privmsgs_date']); + + if ( $flag == PRIVMSGS_NEW_MAIL && $folder == 'inbox' ) + { + $msg_subject = '' . $msg_subject . ''; + $msg_date = '' . $msg_date . ''; + $msg_username = '' . $msg_username . ''; + } + + $row_class = !($i & 1) ? 'prow1' : 'prow2'; + $i++; + + $template->assign_block_vars('listrow', array( + 'ROW_CLASS' => $row_class, + 'FROM' => $msg_username, + 'SUBJECT' => htmlCHR($msg_subject), + 'DATE' => $msg_date, + + 'PRIVMSG_FOLDER_IMG' => $icon_flag, + + 'L_PRIVMSG_FOLDER_ALT' => $icon_flag_alt, + + 'S_MARK_ID' => $privmsg_id, + + 'U_READ' => $u_subject, + 'U_FROM_USER_PROFILE' => $u_from_user_profile) + ); + } + while( $row = DB()->sql_fetchrow($result) ); + + $template->assign_vars(array( + 'PAGINATION' => generate_pagination("privmsg.php?folder=$folder", $pm_total, $bb_cfg['topics_per_page'], $start), + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], ( floor( $start / $bb_cfg['topics_per_page'] ) + 1 ), ceil( $pm_total / $bb_cfg['topics_per_page'] )), + )); + + } + else + { + $template->assign_vars(array( + 'L_NO_MESSAGES' => $lang['NO_MESSAGES_FOLDER']) + ); + + $template->assign_block_vars("switch_no_messages", array() ); + } +} + +$template->assign_vars(array('PAGE_TITLE' => @$page_title)); + +require(PAGE_HEADER); + +$template->pparse('body'); + +require(PAGE_FOOTER); + +// +// Functions +// +function pm_message_die ($msg) +{ + global $lang; + + $msg .= '

    '; + $msg .= sprintf($lang['CLICK_RETURN_INBOX'], '', ' '); + $msg .= sprintf($lang['CLICK_RETURN_SENTBOX'], '', ' '); + $msg .= sprintf($lang['CLICK_RETURN_OUTBOX'], '', ' '); + $msg .= sprintf($lang['CLICK_RETURN_SAVEBOX'], '', ' '); + $msg .= '

    '; + $msg .= sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + + message_die(GENERAL_MESSAGE, $msg); +} diff --git a/upload/profile.php b/upload/profile.php new file mode 100644 index 000000000..682039247 --- /dev/null +++ b/upload/profile.php @@ -0,0 +1,51 @@ +session_start(); + +// session id check +$sid = request_var('sid', ''); +$mode = request_var('mode', ''); +$mode = htmlspecialchars($mode); + +switch ($mode) +{ + case 'viewprofile': + require(INC_DIR . 'ucp/usercp_viewprofile.php'); + break; + + case 'register': + case 'editprofile': + if ( !$userdata['session_logged_in'] && $mode == 'editprofile' ) + { + login_redirect(); + } + + require(INC_DIR . 'ucp/usercp_register.php'); + break; + + case 'sendpassword': + require(INC_DIR .'ucp/usercp_sendpasswd.php'); + break; + + case 'activate': + require(INC_DIR .'ucp/usercp_activate.php'); + break; + + case 'email': + require(INC_DIR .'ucp/usercp_email.php'); + break; + + case 'attachcp': + require(INC_DIR .'ucp/usercp_attachcp.php'); + break; + + default: + bb_die('Invalid mode'); +} diff --git a/upload/report.php b/upload/report.php new file mode 100644 index 000000000..1252d5963 --- /dev/null +++ b/upload/report.php @@ -0,0 +1,819 @@ +session_start(); + +if (!$userdata['session_logged_in']) +{ + redirect(append_sid("index.php", true)); +} + +$return_links = array( + 'index' => '

    ' . sprintf($lang['CLICK_RETURN_INDEX'], '', ''), + 'list' => '

    ' . sprintf($lang['CLICK_RETURN_REPORT_LIST'], '', '') +); + +if (isset($_POST['mode']) || isset($_GET['mode'])) +{ + $mode = (isset($_POST['mode'])) ? $_POST['mode'] : $_GET['mode']; +} +else +{ + $mode = ''; +} + +$report_modules = report_modules(); + +// +// Check for matching report module +// +if (!empty($mode)) +{ + foreach (array_keys($report_modules) as $report_module_id) + { + $report_module =& $report_modules[$report_module_id]; + + if (!empty($report_module->mode) && $mode == $report_module->mode) + { + break; + } + + unset($report_module); + } +} + +// +// Report module matched, show report form +// +if (isset($report_module)) +{ + $errors = array(); + + if (isset($_POST['id']) || isset($_GET['id'])) + { + $report_subject_id = (isset($_POST['id'])) ? (int) $_POST['id'] : (int) $_GET['id']; + } + else + { + $report_subject_id = 0; + } + + // + // Check authorisation, check for duplicate reports + // + if (!$report_module->auth_check('auth_write')) + { + message_die(GENERAL_MESSAGE, $report_module->lang['AUTH_WRITE_ERROR'] . $report_module->return_link($report_subject_id) . $return_links['index']); + } + else if (!$report_module->duplicates && report_duplicate_check($report_module->id, $report_subject_id)) + { + message_die(GENERAL_MESSAGE, $report_module->lang['DUPLICATE_ERROR'] . $report_module->return_link($report_subject_id) . $return_links['index']); + } + + if (isset($_POST['submit'])) + { + $report_reason = (isset($_POST['reason'])) ? (int) $_POST['reason'] : 0; + $report_desc = (isset($_POST['message'])) ? htmlspecialchars($_POST['message']) : ''; + + // + // Obtain report title if necessary + // + if (method_exists($report_module, 'subject_obtain')) + { + $report_title = addslashes($report_module->subject_obtain($report_subject_id)); + } + else + { + $report_title = (isset($_POST['title'])) ? htmlspecialchars($_POST['title']) : ''; + $report_subject_id = 0; + } + + // + // Validate values + // + if (empty($report_title)) + { + $errors[] = $lang['REPORT_TITLE_EMPTY']; + } + + if (empty($report_desc)) + { + $errors[] = $lang['REPORT_DESC_EMPTY']; + } + + // + // Insert report + // + if (empty($errors)) + { + $report_desc = str_replace("\'", "'", $report_desc); + $report_title = str_replace("\'", "'", $report_title); + + report_insert($report_module->id, $report_subject_id, $report_reason, $report_title, $report_desc, false); + + message_die(GENERAL_MESSAGE, $lang['REPORT_INSERTED'] . $report_module->return_link($report_subject_id) . $return_links['index']); + } + } + else if (isset($_POST['cancel'])) + { + $redirect_url = (method_exists($report_module, 'subject_url')) ? $report_module->subject_url($report_subject_id, true) : append_sid("index.php", true); + redirect($redirect_url); + } + + $page_title = $report_module->lang['WRITE_REPORT']; + include(PAGE_HEADER); + $template->set_filenames(array( + 'body' => 'report_form_body.tpl') + ); + + // + // Show validation errors + // + if (!empty($errors)) + { + $template->assign_block_vars('switch_report_errors', array()); + foreach ($errors as $error) + { + $template->assign_block_vars('switch_report_errors.report_errors', array( + 'MESSAGE' => $error) + ); + } + } + + // + // Generate report reasons select + // + if ($report_reasons = $report_module->reasons_obtain()) + { + $template->assign_block_vars('switch_report_reasons', array()); + + foreach ($report_reasons as $reason_id => $reason_desc) + { + $template->assign_block_vars('switch_report_reasons.report_reasons', array( + 'ID' => $reason_id, + 'DESC' => $reason_desc, + 'CHECKED' => (isset($report_reason) && $report_reason == $reason_id) ? ' selected="selected"' : '') + ); + } + } + + // + // Show report subject, check for correct subject + // + if (method_exists($report_module, 'subject_obtain')) + { + if ($report_subject = $report_module->subject_obtain($report_subject_id)) + { + $template->assign_block_vars('switch_report_subject', array()); + $template->assign_var('REPORT_SUBJECT', $report_subject); + + if (method_exists($report_module, 'subject_url')) + { + $template->assign_block_vars('switch_report_subject.switch_url', array()); + $template->assign_var('U_REPORT_SUBJECT', $report_module->subject_url($report_subject_id)); + } + } + else + { + message_die(GENERAL_MESSAGE, $report_module->lang['WRITE_REPORT_ERROR'] . $return_links['index']); + } + } + // + // Show report title input + // + else + { + $template->assign_block_vars('switch_report_title', array()); + } + + $hidden_fields = ''; + + $template->assign_vars(array( + 'S_REPORT_ACTION' => append_sid("report.php"), + 'S_HIDDEN_FIELDS' => $hidden_fields, + + 'L_WRITE_REPORT' => $report_module->lang['WRITE_REPORT'], + 'L_WRITE_REPORT_EXPLAIN' => $report_module->lang['WRITE_REPORT_EXPLAIN'], + 'REPORT_TITLE' => (!method_exists($report_module, 'subject_obtain') && isset($report_title)) ? stripslashes($report_title) : '', + 'REPORT_DESC' => (isset($report_desc)) ? stripslashes($report_desc) : '', + + 'L_TITLE' => $lang['POST_SUBJECT'], + 'L_SUBJECT' => $lang['REPORT_SUBJECT']) + ); + + $template->pparse('body'); + include(PAGE_FOOTER); +} +else +{ + if ($userdata['user_level'] != ADMIN && ($bb_cfg['report_list_admin'] || $userdata['user_level'] != MOD)) + { + redirect(append_sid("index.php", true)); + } + + $params = array('open', 'process', 'clear', 'delete'); + foreach ($params as $param) + { + if (isset($_POST[$param])) + { + $mode = $param; + } + } + + // Report status css classes + $report_status_classes = array( + REPORT_NEW => 'report_new', + REPORT_OPEN => 'report_open', + REPORT_IN_PROCESS => 'report_process', + REPORT_CLEARED => 'report_cleared', + REPORT_DELETE => 'report_delete' + ); + + switch ($mode) + { + case 'open': + case 'process': + case 'clear': + case 'delete': + // + // Validate report ids + // + if (isset($_POST[POST_REPORT_URL]) || isset($_GET[POST_REPORT_URL])) + { + $report_id = (isset($_POST[POST_REPORT_URL])) ? $_POST[POST_REPORT_URL] : $_GET[POST_REPORT_URL]; + $reports = array((int) $report_id); + + $single_report = true; + } + else if (isset($_POST['reports'])) + { + $reports = array(); + foreach ($_POST['reports'] as $report_id) + { + $reports[] = (int) $report_id; + } + + $single_report = false; + } + + if (empty($reports)) + { + $template->assign_var('META', ''); + + message_die(GENERAL_MESSAGE, $lang['NO_REPORTS_SELECTED'] . $return_links['list'] . $return_links['index']); + } + + // + // Cancel action + // + if (isset($_POST['cancel'])) + { + $redirect_url = ($single_report) ? "report.php?" . POST_REPORT_URL . '=' . $reports[0] : "report.php"; + redirect(append_sid($redirect_url, true)); + } + + // + // Hidden fields + // + $hidden_fields = ''; + if ($single_report) + { + $hidden_fields .= ''; + } + else + { + foreach ($reports as $report_id) + { + $hidden_fields .= ''; + } + } + + $template->assign_vars(array( + 'S_CONFIRM_ACTION' => append_sid("report.php"), + 'S_HIDDEN_FIELDS' => $hidden_fields) + ); + + // + // Change reports status + // + if ($mode != 'delete') + { + if (isset($_POST['confirm'])) + { + $comment = (isset($_POST['comment'])) ? htmlspecialchars(str_replace("\'", "'", $_POST['comment'])) : ''; + + switch ($mode) + { + case 'open': + $status = REPORT_OPEN; + break; + + case 'process': + $status = REPORT_IN_PROCESS; + break; + + case 'clear': + $status = REPORT_CLEARED; + break; + } + + reports_update_status($reports, $status, $comment); + + $meta_url = ($single_report) ? "report.php?" . POST_REPORT_URL . '=' . $reports[0] : "report.php"; + $template->assign_var('META', ''); + + $return_link = ($single_report) ? '

    ' . sprintf($lang['CLICK_RETURN_REPORT'], '', '') : ''; + $message = ($single_report) ? 'REPORT_CHANGED' : 'REPORTS_CHANGED'; + message_die(GENERAL_MESSAGE, $lang[$message] . $return_link . $return_links['list'] . $return_links['index']); + } + + $page_title = ($single_report) ? $lang['CHANGE_REPORT'] : $lang['CHANGE_REPORTS']; + + include(PAGE_HEADER); + $template->set_filenames(array( + 'body' => 'report_change_body.tpl') + ); + + $template->assign_vars(array( + 'MESSAGE_TITLE' => $page_title, + 'MESSAGE_TEXT' => ($single_report) ? $lang['CHANGE_REPORT_EXPLAIN'] : $lang['CHANGE_REPORTS_EXPLAIN']) + ); + + $template->pparse('body'); + include(PAGE_FOOTER); + } + // + // Delete reports + // + else + { + if (isset($_POST['confirm'])) + { + reports_delete($reports); + + $template->assign_var('META', ''); + + $message = ($single_report) ? 'REPORT_DELETED' : 'REPORTS_DELETED'; + message_die(GENERAL_MESSAGE, $lang[$message] . $return_links['list'] . $return_links['index']); + } + + $page_title = ($single_report) ? $lang['DELETE_REPORT'] : $lang['DELETE_REPORTS']; + + include(PAGE_HEADER); + $template->set_filenames(array( + 'confirm' => 'confirm_body.tpl') + ); + + $template->assign_vars(array( + 'MESSAGE_TITLE' => $page_title, + 'MESSAGE_TEXT' => ($single_report) ? $lang['DELETE_REPORT_EXPLAIN'] : $lang['DELETE_REPORTS_EXPLAIN']) + ); + + $template->pparse('confirm'); + include(PAGE_FOOTER); + } + break; + + case 'reported': + $cat = (isset($_GET[POST_CAT_URL])) ? (int) $_GET[POST_CAT_URL] : 0; + $report_subject_id = (isset($_GET['id'])) ? (int) $_GET['id'] : 0; + + if (empty($cat) || empty($report_subject_id) || !isset($report_modules[$cat])) + { + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['index']); + } + + $report_module =& $report_modules[$cat]; + $reports = reports_open_obtain($cat, $report_subject_id); + + // + // No open reports for the subject, sync report module + // + if (empty($reports)) + { + if (method_exists($report_module, 'sync')) + { + $report_module->sync(); + } + + message_die(GENERAL_MESSAGE, $lang['NO_REPORTS_FOUND'] . $report_module->return_link($report_subject_id) . $return_links['index']); + } + // + // Redirect to the open report + // + else if (count($reports) == 1) + { + $redirect_url = append_sid("report.php?" . POST_REPORT_URL . '=' . $reports[0]['report_id'], true); + redirect($redirect_url); + } + + $page_title = $lang['OPEN_REPORTS']; + include(PAGE_HEADER); + $template->set_filenames(array( + 'body' => 'report_open_body.tpl') + ); + + $template->assign_vars(array( + 'S_REPORT_ACTION', append_sid("report.php"), + + 'L_BY' => $lang['REPORT_BY'], + 'L_MARK' => $lang['REPORT_MARK'], + 'L_STATUS_CLEARED' => $lang['REPORT_STATUS'][REPORT_CLEARED], + 'L_STATUS_IN_PROCESS' => $lang['REPORT_STATUS'][REPORT_IN_PROCESS], + 'L_STATUS_OPEN' => $lang['REPORT_STATUS'][REPORT_OPEN], + 'L_SELECT_ALL' => $lang['MARK_ALL']) + ); + + // + // Show list with open reports + // + foreach ($reports as $report) + { + $template->assign_block_vars('open_reports', array( + 'U_SHOW' => append_sid("report.php?" . POST_REPORT_URL . '=' . $report['report_id']), + 'U_AUTHOR' => append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $report['user_id']), + + 'ID' => $report['report_id'], + 'TITLE' => $report['report_title'], + 'AUTHOR' => $report['username'], + 'TIME' => bb_date($report['report_time'])) + ); + } + + $template->pparse('body'); + include(PAGE_FOOTER); + break; + + case '': + $page_title = $lang['REPORTS']; + include(PAGE_HEADER); + $template->set_filenames(array( + 'body' => 'report_list_body.tpl') + ); + + $template->assign_vars(array( + 'S_REPORT_ACTION' => append_sid("report.php"), + + 'U_REPORT_INDEX' => append_sid("report.php"), + + 'L_BY' => $lang['REPORT_BY'], + 'L_MARK' => $lang['REPORT_MARK'], + 'L_STATUS_CLEARED' => $lang['REPORT_STATUS'][REPORT_CLEARED], + 'L_STATUS_IN_PROCESS' => $lang['REPORT_STATUS'][REPORT_IN_PROCESS], + 'L_STATUS_OPEN' => $lang['REPORT_STATUS'][REPORT_OPEN], + 'L_SELECT_ALL' => $lang['MARK_ALL']) + ); + + $cat = (isset($_GET[POST_CAT_URL])) ? (int) $_GET[POST_CAT_URL] : null; + $cat_url = (!empty($cat)) ? '&' . POST_CAT_URL . "=$cat" : ''; + + $show_delete_option = false; + + // + // Show report list + // + $reports = reports_obtain($cat); + foreach (array_keys($report_modules) as $report_module_id) + { + $report_module =& $report_modules[$report_module_id]; + + // + // Check module authorisation + // + if (!$report_module->auth_check('auth_view')) + { + continue; + } + + $template->assign_block_vars('report_modules', array( + 'U_SHOW' => append_sid("report.php?" . POST_CAT_URL . '=' . $report_module->id), + + 'TITLE' => $report_module->lang['REPORT_LIST_TITLE']) + ); + + // + // No reports in this category, display no reports message + // + if (!isset($reports[$report_module->id])) + { + if (empty($cat) || $cat == $report_module->id) + { + $template->assign_block_vars('report_modules.no_reports', array()); + } + + continue; + } + + // + // Check if deletions are allowed + // + if ($report_module->auth_check('auth_delete_view')) + { + $show_delete_option = true; + } + + // + // Show reports + // + foreach ($reports[$report_module->id] as $report) + { + $template->assign_block_vars('report_modules.reports', array( + 'U_SHOW' => append_sid("report.php?" . POST_REPORT_URL . '=' . $report['report_id'] . $cat_url), + 'U_AUTHOR' => append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $report['user_id']), + + 'ROW_CLASS' => $report_status_classes[$report['report_status']], + 'ID' => $report['report_id'], + 'TITLE' => (strlen($report['report_title'] > 53)) ? substr($report['report_title'], 0, 50) . '...' : $report['report_title'], + 'AUTHOR' => $report['username'], + 'TIME' => bb_date($report['report_time']), + 'STATUS' => $lang['REPORT_STATUS'][$report['report_status']]) + ); + + if (isset($_GET[POST_REPORT_URL]) && $_GET[POST_REPORT_URL] == $report['report_id']) + { + $template->assign_block_vars('report_modules.reports.switch_current', array()); + } + } + } + + if ($show_delete_option) + { + $template->assign_block_vars('switch_global_delete_option', array()); + } + + // + // Show information for one report + // + if (isset($_GET[POST_REPORT_URL])) + { + $template->set_filenames(array( + 'report_view' => 'report_view_body.tpl') + ); + + if (!$report = report_obtain((int) $_GET[POST_REPORT_URL])) + { + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_EXISTS'] . $return_links['list'] . $return_links['index']); + } + + if ($report['report_status'] == REPORT_NEW) + { + reports_update_status($report['report_id'], REPORT_OPEN, '', false, true, false); + $report['report_status'] = REPORT_OPEN; + } + + // + // Show report subject (with or without details, depending on the report module) + // + $report_module =& $report_modules[$report['report_module_id']]; + if (method_exists($report_module, 'subject_details_obtain')) + { + if ($report_subject = $report_module->subject_details_obtain($report['report_subject'])) + { + if (isset($report_subject['subject']) || isset($report_subject['details'])) + { + $template->assign_block_vars('report_subject', array()); + } + + // + // Assign report subject + // + if (isset($report_subject['subject'])) + { + $template->assign_block_vars('report_subject.switch_subject', array()); + $template->assign_var('REPORT_SUBJECT', $report_subject['subject']); + + if (method_exists($report_module, 'subject_url')) + { + $template->assign_block_vars('report_subject.switch_subject.switch_url', array()); + $template->assign_vars(array( + 'S_REPORT_SUBJECT_TARGET' => ($bb_cfg['report_new_window']) ? ' target="_blank"' : '', + 'U_REPORT_SUBJECT' => $report_module->subject_url($report['report_subject'])) + ); + } + } + + // + // Assign report subject details + // + if (isset($report_subject['details'])) + { + foreach ($report_subject['details'] as $detail_title => $detail_value) + { + $template->assign_block_vars('report_subject.details', array( + 'TITLE' => $report_module->lang[$detail_title], + 'VALUE' => $detail_value) + ); + } + } + } + else + { + $template->assign_block_vars('switch_report_subject_deleted', array()); + $template->assign_var('L_REPORT_SUBJECT_DELETED', $report_module->lang['DELETED_ERROR']); + } + } + else if (method_exists($report_module, 'subject_obtain')) + { + if ($report_subject = $report_module->subject_obtain($report['report_subject'])) + { + // + // Assign report subject + // + $template->assign_block_vars('report_subject', array()); + $template->assign_block_vars('report_subject.switch_subject', array()); + $template->assign_var('REPORT_SUBJECT', $report_subject); + + if (method_exists($report_module, 'subject_url')) + { + $template->assign_block_vars('report_subject.switch_subject.switch_url', array()); + $template->assign_vars(array( + 'S_REPORT_SUBJECT_TARGET' => ($bb_cfg['report_new_window']) ? ' target="_blank"' : '', + 'U_REPORT_SUBJECT' => $report_module->subject_url($report['report_subject'])) + ); + } + } + else + { + $template->assign_block_vars('switch_report_subject_deleted', array()); + $template->assign_var('L_REPORT_SUBJECT_DELETED', $report_module->lang['DELETED_ERROR']); + } + } + + // + // Assign report reason + // + if (!empty($report['report_reason_desc'])) + { + $template->assign_block_vars('switch_report_reason', array()); + + $template->assign_var('REPORT_REASON', $report['report_reason_desc']); + } + + // + // Show report changes + // + if ($report_changes = report_changes_obtain($report['report_id'])) + { + $template->assign_block_vars('switch_report_changes', array()); + + foreach ($report_changes as $report_change) + { + $u_report_change_user = append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $report_change['user_id']); + $report_change_user = '' . $report_change['username'] . ''; + + $report_change_status = $lang['REPORT_STATUS'][$report_change['report_status']]; + $report_change_time = bb_date($report_change['report_change_time']); + + // + // Text that contains all information + // + if ($report_change['report_status'] == REPORT_DELETE) + { + $report_change_text = sprintf($lang['REPORT_CHANGE_DELETE_TEXT'], $report_change_user, $report_change_time); + } + else if ($report_change['report_change_comment'] != '') + { + $report_change_text = sprintf($lang['REPORT_CHANGE_TEXT_COMMENT'], $report_change_status, $report_change_user, $report_change_time, $report_change['report_change_comment']); + } + else + { + $report_change_text = sprintf($lang['REPORT_CHANGE_TEXT'], $report_change_status, $report_change_user, $report_change_time); + } + + $template->assign_block_vars('switch_report_changes.report_changes', array( + 'U_USER' => $u_report_change_user, + + 'ROW_CLASS' => $report_status_classes[$report_change['report_status']], + 'STATUS' => $report_change_status, + 'USER' => $report_change['username'], + 'TIME' => $report_change_time, + + 'TEXT' => $report_change_text) + ); + } + + // + // Assign last change information + // + $template->assign_vars(array( + 'U_REPORT_LAST_CHANGE_USER' => $u_report_change_user, + + 'REPORT_LAST_CHANGE_TIME' => $report_change_time, + 'REPORT_LAST_CHANGE_USER' => $report_change['username']) + ); + } + + // + // Check if deletions are allowed + // + if ($report_module->auth_check('auth_delete_view')) + { + $template->assign_block_vars('switch_delete_option', array()); + } + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => '', + + 'U_REPORT_AUTHOR' => append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $report['user_id']), + 'U_REPORT_AUTHOR_PRIVMSG' => append_sid("privmsg.php?mode=post&" . POST_USERS_URL . '=' . $report['user_id']), + + 'REPORT_TYPE' => $report_module->lang['REPORT_TYPE'], + 'REPORT_TITLE' => $report['report_title'], + 'REPORT_AUTHOR' => $report['username'], + 'REPORT_TIME' => bb_date($report['report_time']), + 'REPORT_DESC' => str_replace("\n", '
    ', $report['report_desc']), + 'REPORT_STATUS' => $lang['REPORT_STATUS'][$report['report_status']], + 'REPORT_STATUS_CLASS' => $report_status_classes[$report['report_status']], + + 'L_SUBJECT' => $lang['REPORT_SUBJECT'], + 'L_SEND_PRIVMSG' => $lang['SEND_PRIVATE_MESSAGE']) + ); + } + // + // Show report index page + // + else + { + $template->set_filenames(array( + 'report_view' => 'report_index_body.tpl') + ); + + $statistics = array( + 'Report_count' => 'report_count', + 'Report_modules_count' => 'modules_count', + 'Report_hack_count' => 'report_hack_count'); + foreach ($statistics as $stat_lang => $stat_mode) + { + $template->assign_block_vars('report_statistics', array( + 'STATISTIC' => $lang[strtoupper($stat_lang)], + 'VALUE' => report_statistics($stat_mode)) + ); + } + + /* + if ($userdata['user_level'] == ADMIN) + { + */ + $deleted_reports = reports_deleted_obtain(); + if (!empty($deleted_reports)) + { + $template->assign_block_vars('switch_deleted_reports', array()); + foreach ($deleted_reports as $report) + { + $report_module =& $report_modules[$report['report_module_id']]; + + $template->assign_block_vars('switch_deleted_reports.deleted_reports', array( + 'U_SHOW' => append_sid("report.php?" . POST_REPORT_URL . '=' . $report['report_id'] . $cat_url), + 'U_AUTHOR' => append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $report['user_id']), + + 'ID' => $report['report_id'], + 'TITLE' => $report['report_title'], + 'TYPE' => $report_module->lang['REPORT_TYPE'], + 'AUTHOR' => $report['username'], + 'TIME' => bb_date($report['report_time']), + 'STATUS' => $lang['REPORT_STATUS'][REPORT_DELETE]) + ); + } + } + /* + } + */ + } + + $template->assign_var_from_handle('REPORT_VIEW', 'report_view'); + + $template->pparse('body'); + include(PAGE_FOOTER); + break; + + default: + message_die(GENERAL_MESSAGE, $lang['REPORT_NOT_SUPPORTED'] . $return_links['index']); + break; + } +} \ No newline at end of file diff --git a/upload/search.php b/upload/search.php new file mode 100644 index 000000000..abe4b4f20 --- /dev/null +++ b/upload/search.php @@ -0,0 +1,919 @@ +session_start(array('req_login' => $bb_cfg['disable_search_for_guest'])); + +$tracking_topics = get_tracks('topic'); +$tracking_forums = get_tracks('forum'); + +if ($mode =& $_REQUEST['mode']) +{ + // This handles the simple windowed user search functions called from various other scripts + if ($mode == 'searchuser') + { + $username = isset($_POST['search_username']) ? $_POST['search_username'] : ''; + username_search($username); + exit; + } +} + +$excluded_forums_csv = $user->get_excluded_forums(AUTH_READ); + +$search_limit = 500; +$forum_select_size = 16; // forum select box max rows +$max_forum_name_len = 60; // inside forum select box +$text_match_max_len = 60; +$poster_name_max_len = 25; + +$start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; +$url = basename(__FILE__); + +$anon_id = ANONYMOUS; +$user_id = $userdata['user_id']; +$lastvisit = (IS_GUEST) ? TIMENOW : $userdata['user_lastvisit']; +$search_id = (isset($_GET['id']) && verify_id($_GET['id'], SEARCH_ID_LENGTH)) ? $_GET['id'] : ''; +$session_id = $userdata['session_id']; + +$items_found = $items_display = $previous_settings = null; +$text_match_sql = ''; + +$cat_tbl = BB_CATEGORIES .' c'; +$dl_stat_tbl = BB_BT_DLSTATUS .' dl'; +$forums_tbl = BB_FORUMS .' f'; +$posts_tbl = BB_POSTS .' p'; +$posts_text_tbl = BB_POSTS_TEXT .' pt'; +$posts_html_tbl = BB_POSTS_HTML .' h'; +$search_tbl = BB_POSTS_SEARCH .' ps'; +$tr_snap_tbl = BB_BT_TRACKER_SNAP .' sn'; +$topics_tbl = BB_TOPICS .' t'; +$torrents_tbl = BB_BT_TORRENTS .' tor'; +$tracker_tbl = BB_BT_TRACKER .' tr'; +$users_tbl = BB_USERS .' u'; + +// Cat/forum data +if (!$forums = $datastore->get('cat_forums')) +{ + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); +} +$forum_name_html = $forums['forum_name_html']; + +// +// Search options +// +// Key values +$search_all = 0; + +$sort_asc = 1; +$sort_desc = 0; + +$as_topics = 0; +$as_posts = 1; + +$show_all = 0; +$show_briefly = 1; + +$ord_posted = 1; +$ord_name = 2; +$ord_repl = 3; +$ord_views = 4; +$ord_last_p = 5; +$ord_created = 6; + +// Order options +$order_opt = array( + $ord_posted => array( + 'lang' => $lang['SORT_TIME'], + 'sql' => 'item_id', + ), + $ord_last_p => array( + 'lang' => $lang['BT_LAST_POST'], + 'sql' => 't.topic_last_post_id', + ), + $ord_created => array( + 'lang' => $lang['BT_CREATED'], + 'sql' => 't.topic_time', + ), + $ord_name => array( + 'lang' => $lang['SORT_TOPIC_TITLE'], + 'sql' => 't.topic_title', + ), + $ord_repl => array( + 'lang' => $lang['REPLIES'], + 'sql' => 't.topic_replies', + ), +); +$order_select = array(); +foreach ($order_opt as $val => $opt) +{ + $order_select[$opt['lang']] = $val; +} + +// Sort direction +$sort_opt = array( + $sort_asc => array( + 'lang' => $lang['ASC'], + 'sql' => ' ASC ', + ), + $sort_desc => array( + 'lang' => $lang['DESC'], + 'sql' => ' DESC ', + ), +); +$sort_select = array(); +foreach ($sort_opt as $val => $opt) +{ + $sort_select[$opt['lang']] = $val; +} + +// Previous days +$time_opt = array( + $search_all => array( + 'lang' => $lang['BT_ALL_DAYS_FOR'], + 'sql' => 0, + ), + 1 => array( + 'lang' => $lang['BT_1_DAY_FOR'], + 'sql' => TIMENOW - 86400, + ), + 3 => array( + 'lang' => $lang['BT_3_DAY_FOR'], + 'sql' => TIMENOW - 86400*3, + ), + 7 => array( + 'lang' => $lang['BT_7_DAYS_FOR'], + 'sql' => TIMENOW - 86400*7, + ), + 14 => array( + 'lang' => $lang['BT_2_WEEKS_FOR'], + 'sql' => TIMENOW - 86400*14, + ), + 30 => array( + 'lang' => $lang['BT_1_MONTH_FOR'], + 'sql' => TIMENOW - 86400*30, + ), +); +$time_select = array(); +foreach ($time_opt as $val => $opt) +{ + $time_select[$opt['lang']] = $val; +} + +// Display as +$display_as_opt = array( + $as_topics => array( + 'lang' => $lang['TOPICS'], + ), + $as_posts => array( + 'lang' => $lang['MESSAGE'], + ), +); +$display_as_select = array(); +foreach ($display_as_opt as $val => $opt) +{ + $display_as_select[$opt['lang']] = $val; +} + +// Chars +$chars_opt = array( + $show_all => array( + 'lang' => $lang['ALL_AVAILABLE'], + ), + $show_briefly => array( + 'lang' => $lang['BRIEFLY'], + ), +); +$chars_select = array(); +foreach ($chars_opt as $val => $opt) +{ + $chars_select[$opt['lang']] = $val; +} + +$GPC = array( +# var_name key_name def_value GPC type + 'all_words' => array('allw', 1, CHBOX), + 'cat' => array('c', null, REQUEST), + 'chars' => array('ch', $show_all, SELECT), + 'display_as' => array('dm', $as_topics, SELECT), + 'dl_cancel' => array('dla', 0, CHBOX), + 'dl_compl' => array('dlc', 0, CHBOX), + 'dl_down' => array('dld', 0, CHBOX), + 'dl_user_id' => array('dlu', $user_id, CHBOX), + 'dl_will' => array('dlw', 0, CHBOX), + 'forum' => array('f', $search_all, REQUEST), + 'my_topics' => array('myt', 0, CHBOX), + 'new' => array('new', 0, CHBOX), + 'new_topics' => array('nt', 0, CHBOX), + 'order' => array('o', $ord_posted, SELECT), + 'poster_id' => array('uid', null, REQUEST), + 'poster_name' => array('pn', null, REQUEST), + 'sort' => array('s', $sort_desc, SELECT), + 'text_match' => array('nm', null, REQUEST), + 'time' => array('tm', $search_all, SELECT), + 'title_only' => array('to', 0, CHBOX), + 'topic' => array('t', null, REQUEST), +); + +// Define all GPC vars with default values +foreach ($GPC as $var_name => $var_options) +{ + $GLOBALS["{$var_name}_key"] = $var_options[KEY_NAME]; + $GLOBALS["{$var_name}_val"] = $var_options[DEF_VAL]; +} + +// Output basic page +if (empty($_GET) && empty($_POST)) +{ + // Make forum select box + $forum_select_mode = explode(',', $excluded_forums_csv); + $forum_select = get_forum_select($forum_select_mode, "{$forum_key}[]", $search_all, $max_forum_name_len, $forum_select_size, 'style="width: 95%;"', $search_all); + + $template->assign_vars(array( + 'TPL_SEARCH_MAIN' => true, + 'PAGE_TITLE' => $lang['SEARCH'], + + 'POSTER_ID_KEY' => $poster_id_key, + 'TEXT_MATCH_KEY' => $text_match_key, + 'POSTER_NAME_KEY' => $poster_name_key, + + 'THIS_USER_ID' => $userdata['user_id'], + 'THIS_USER_NAME' => addslashes($userdata['username']), + 'SEARCH_ACTION' => "search.php", + 'U_SEARCH_USER' => "search.php?mode=searchuser&input_name=$poster_name_key", + 'ONLOAD_FOCUS_ID' => 'text_match_input', + + 'MY_TOPICS_ID' => 'my_topics', + 'MY_TOPICS_CHBOX' => build_checkbox ($my_topics_key, $lang['SEARCH_MY_TOPICS'], $my_topics_val, true, null, 'my_topics'), + 'TITLE_ONLY_CHBOX' => build_checkbox ($title_only_key, $lang['SEARCH_TITLES_ONLY'], true, $bb_cfg['disable_ft_search_in_posts']), + 'ALL_WORDS_CHBOX' => build_checkbox ($all_words_key, $lang['SEARCH_ALL_WORDS'], true), + 'DL_CANCEL_CHBOX' => build_checkbox ($dl_cancel_key, $lang['SEARCH_DL_CANCEL'], $dl_cancel_val, IS_GUEST, 'dlCancel'), + 'DL_COMPL_CHBOX' => build_checkbox ($dl_compl_key, $lang['SEARCH_DL_COMPLETE'], $dl_compl_val, IS_GUEST, 'dlComplete'), + 'DL_DOWN_CHBOX' => build_checkbox ($dl_down_key, $lang['SEARCH_DL_DOWN'], $dl_down_val, IS_GUEST, 'dlDown'), + 'DL_WILL_CHBOX' => build_checkbox ($dl_will_key, $lang['SEARCH_DL_WILL'], $dl_will_val, IS_GUEST, 'dlWill'), + 'ONLY_NEW_CHBOX' => build_checkbox ($new_key, $lang['BT_ONLY_NEW'], $new_val, IS_GUEST), + 'NEW_TOPICS_CHBOX' => build_checkbox ($new_topics_key, $lang['NEW_TOPICS'], $new_topics_val, IS_GUEST), + + 'FORUM_SELECT' => $forum_select, + 'TIME_SELECT' => build_select ($time_key, $time_select, $time_val), + 'ORDER_SELECT' => build_select ($order_key, $order_select, $order_val), + 'SORT_SELECT' => build_select ($sort_key, $sort_select, $sort_val), + 'CHARS_SELECT' => '', # build_select ($chars_key, $chars_select, $chars_val), + 'DISPLAY_AS_SELECT' => build_select ($display_as_key, $display_as_select, $display_as_val), + )); + + print_page('search.tpl'); +} + +unset($forums); +$datastore->rm('cat_forums'); + +// Restore previously found items list and search settings if we have valid $search_id +if ($search_id) +{ + $row = DB()->fetch_row(" + SELECT search_array, search_settings + FROM ". BB_SEARCH ." + WHERE session_id = '$session_id' + AND search_type = ". SEARCH_TYPE_POST ." + AND search_id = '$search_id' + LIMIT 1 + "); + + if (empty($row['search_settings'])) + { + bb_die($lang['SESSION_EXPIRED']); + } + + $previous_settings = unserialize($row['search_settings']); + $items_found = explode(',', $row['search_array']); +} + +// Get simple "CHBOX" and "SELECT" type vars +foreach ($GPC as $name => $params) +{ + if ($params[GPC_TYPE] == CHBOX) + { + checkbox_get_val($params[KEY_NAME], ${"{$name}_val"}, $params[DEF_VAL]); + } + else if ($params[GPC_TYPE] == SELECT) + { + select_get_val($params[KEY_NAME], ${"{$name}_val"}, ${"{$name}_opt"}, $params[DEF_VAL]); + } +} + +// Get other "REQUEST" vars +$egosearch = false; + +if (!$items_found) +{ + // For compatibility with old-style params + if (isset($_REQUEST['search_id'])) + { + switch ($_REQUEST['search_id']) + { + case 'egosearch': + $egosearch = true; + $display_as_val = $as_topics; + if (empty($_REQUEST[$poster_id_key])) + { + $_REQUEST[$poster_id_key] = $user_id; + } + break; + case 'newposts': + $new_val = true; + break; + } + } + + // Forum + if ($var =& $_REQUEST[$forum_key]) + { + $forum_selected = get_id_ary($var); + + if (!in_array($search_all, $forum_selected)) + { + $forum_val = join(',', $forum_selected); + } + } + + // Topic + if ($var =& $_REQUEST[$topic_key]) + { + $topic_val = join(',', get_id_ary($var)); + } + + // Poster id (from requested name or id) + if ($var = request_var($poster_id_key, 0)) + { + $poster_id_val = (int) $var; + + if ($poster_id_val != $user_id && !get_username($poster_id_val)) + { + bb_die($lang['USER_NOT_EXIST']); + } + } + else if ($var =& $_POST[$poster_name_key]) + { + $poster_name_sql = str_replace("\\'", "''", clean_username($var)); + + if (!$poster_id_val = get_user_id($poster_name_sql)) + { + bb_die($lang['USER_NOT_EXIST']); + } + } + + // Search words + if ($var =& $_REQUEST[$text_match_key]) + { + if ($tmp = substr(trim($var), 0, $text_match_max_len)) + { + $text_match_sql = clean_text_match($tmp, $all_words_val, false, true); + } + } +} + +$dl_status = array(); +if ($dl_cancel_val) $dl_status[] = DL_STATUS_CANCEL; +if ($dl_compl_val) $dl_status[] = DL_STATUS_COMPLETE; +if ($dl_down_val) $dl_status[] = DL_STATUS_DOWN; +if ($dl_will_val) $dl_status[] = DL_STATUS_WILL; +$dl_status_csv = join(',', $dl_status); + +// Switches +$dl_search = ($dl_status && !IS_GUEST); +$new_posts = ($new_val && !IS_GUEST); +$prev_days = ($time_val != $search_all); +$new_topics = (!IS_GUEST && ($new_topics_val || isset($_GET['newposts']))); +$my_topics = ($poster_id_val && $my_topics_val); +$my_posts = ($poster_id_val && !$my_topics_val); +$title_match = ($text_match_sql && ($title_only_val || $bb_cfg['disable_ft_search_in_posts'])); + +// "Display as" mode (posts or topics) +$post_mode = (!$dl_search && ($display_as_val == $as_posts || isset($_GET['search_author']))); + +// Start building SQL +$SQL = DB()->get_empty_sql_array(); + +// Displaying "as posts" mode +if ($post_mode) +{ + $order = $order_opt[$order_val]['sql']; + $sort = $sort_opt[$sort_val]['sql']; + $per_page = $bb_cfg['posts_per_page']; + $display_as_val = $as_posts; + + // Run initial search for post_ids + if (!$items_found) + { + $join_t = ($title_match || $my_topics || $new_topics || in_array($order_val, array($ord_last_p, $ord_created, $ord_name, $ord_repl))); + $join_s = ($text_match_sql && !$title_match); + $join_p = ($my_posts || $join_s); + + $tbl = ($join_t && !$join_p) ? 't' : 'p'; + $time_field = ($join_t && !$join_p) ? 'topic_last_post_time' : 'post_time'; + + // SELECT + $SQL['SELECT'][] = ($join_t && !$join_p) ? 't.topic_first_post_id AS item_id' : 'p.post_id AS item_id'; + + // FROM + if ($join_t) $SQL['FROM'][] = $topics_tbl; + if ($join_p) $SQL['FROM'][] = $posts_tbl; + if ($join_s) $SQL['FROM'][] = $search_tbl; + + if (!$SQL['FROM']) + { + $join_p = true; + $SQL['FROM'][] = $posts_tbl; + } + + // WHERE + if ($join_p && $join_t) $SQL['WHERE'][] = "t.topic_id = p.topic_id"; + if ($join_s) $SQL['WHERE'][] = "ps.post_id = p.post_id"; + + if ($excluded_forums_csv) $SQL['WHERE'][] = "$tbl.forum_id NOT IN($excluded_forums_csv)"; + + if ($forum_val) $SQL['WHERE'][] = "$tbl.forum_id IN($forum_val)"; + if ($topic_val) $SQL['WHERE'][] = "$tbl.topic_id IN($topic_val)"; + if ($new_posts) $SQL['WHERE'][] = "$tbl.$time_field > $lastvisit"; + if ($new_topics) $SQL['WHERE'][] = "t.topic_time > $lastvisit"; + if ($prev_days) $SQL['WHERE'][] = "$tbl.$time_field > ". $time_opt[$time_val]['sql']; + if ($my_posts) $SQL['WHERE'][] = "p.poster_id = $poster_id_val"; + if ($my_topics) $SQL['WHERE'][] = "t.topic_poster = $poster_id_val"; + + if ($text_match_sql) + { + $field_match = ($title_match) ? "t.topic_title" : "ps.search_words" ; + $tmp_text_match_sql = $text_match_sql; + if (mb_substr($tmp_text_match_sql, 0, 1) == '+') $tmp_text_match_sql = mb_substr($tmp_text_match_sql, 1); + $tmp_text_match_sql = str_replace(' +', ' ', $tmp_text_match_sql); + $tmp_text_match_sql = extract_search_words($tmp_text_match_sql, true); + $tmp_text_match_sql = str_replace(' ', '%', $tmp_text_match_sql); + $tmp_text_match_sql = str_replace('%%%', '%', $tmp_text_match_sql); + $tmp_text_match_sql = str_replace('%%', '%', $tmp_text_match_sql); + if ($tmp_text_match_sql == '' || $tmp_text_match_sql == '%') bb_die($lang['NO_SEARCH_MATCH']); + $SQL['WHERE'][] = "$field_match LIKE '%$tmp_text_match_sql%'"; + prevent_huge_searches($SQL); + } + + if (!$SQL['WHERE']) redirect(basename(__FILE__)); + + $SQL['GROUP BY'][] = "item_id"; + $SQL['ORDER BY'][] = ($new_posts && $join_p) ? "p.topic_id ASC, p.post_time ASC" : "$order $sort"; + $SQL['LIMIT'][] = "$search_limit"; + + $items_display = fetch_search_ids($SQL); + } + else if (!$items_display = array_slice($items_found, $start, $per_page)) + { + bb_die($lang['NO_SEARCH_MATCH']); + } + + // Build SQL for displaying posts + $excluded_forums_sql = ($excluded_forums_csv) ? " AND t.forum_id NOT IN($excluded_forums_csv) " : ''; + + $sql = " + SELECT + p.post_id AS item_id, + t.*, + p.*, + h.post_html, IF(h.post_html IS NULL, pt.post_text, NULL) AS post_text, + pt.post_subject, pt.bbcode_uid, + IF(p.poster_id = $anon_id, p.post_username, u.username) AS username, u.user_id + FROM $posts_tbl + INNER JOIN $topics_tbl ON(t.topic_id = p.topic_id) + INNER JOIN $posts_text_tbl ON(pt.post_id = p.post_id) + LEFT JOIN $posts_html_tbl ON(h.post_id = pt.post_id) + INNER JOIN $users_tbl ON(u.user_id = p.poster_id) + WHERE + p.post_id IN(". join(',', $items_display) .") + $excluded_forums_sql + LIMIT $per_page + "; + + // Fetch posts data + if (!$unsorted_rows = DB()->fetch_rowset($sql)) + { + bb_die($lang['NO_SEARCH_MATCH']); + } + $tmp = $sorted_rows = array(); + + foreach ($unsorted_rows as $row) + { + $tmp[$row['post_id']] = $row; + } + foreach ($items_display as $post_id) + { + if (empty($tmp[$post_id])) + { + continue; // if post was deleted but still remain in search results + } + $topic_id = $tmp[$post_id]['topic_id']; + $sorted_rows[$topic_id][] = $tmp[$post_id]; + } + + // Output page + $new_tracks = array(); + + foreach ($sorted_rows as $topic_id => $topic_posts) + { + // Topic title block + $first_post = $topic_posts[0]; + $topic_id = (int) $topic_id; + $forum_id = (int) $first_post['forum_id']; + $is_unread_t = is_unread($first_post['topic_last_post_time'], $topic_id, $forum_id); + + $template->assign_block_vars('t', array( + 'FORUM_ID' => $forum_id, + 'FORUM_NAME' => $forum_name_html[$forum_id], + 'TOPIC_ID' => $topic_id, + 'TOPIC_TITLE' => $first_post['topic_title'], + 'TOPIC_ICON' => get_topic_icon($first_post, $is_unread_t), + )); + + $quote_btn = true; + $edit_btn = $delpost_btn = $ip_btn = (IS_MOD || IS_ADMIN); + + // Topic posts block + foreach ($topic_posts as $row_num => $post) + { + $template->assign_block_vars('t.p', array( + 'ROW_NUM' => $row_num, + 'POSTER_ID' => $post['poster_id'], + 'POSTER_NAME' => ($post['username']) ? wbr($post['username']) : $lang['GUEST'], + 'POST_ID' => $post['post_id'], + 'POST_DATE' => bb_date($post['post_time'], $bb_cfg['post_date_format']), + 'IS_UNREAD' => is_unread($post['post_time'], $topic_id, $forum_id), + 'MESSAGE' => ($chars_val == $show_all) ? get_parsed_post($post, 'full') : get_parsed_post($post, 'briefly'), + 'AVATAR' => '', + 'POSTED_AFTER' => '', + 'QUOTE' => $quote_btn, + 'EDIT' => $edit_btn, + 'DELETE' => $delpost_btn, + 'IP' => $ip_btn, + )); + + $curr_new_track_val = !empty($new_tracks[$topic_id]) ? $new_tracks[$topic_id] : 0; + $new_tracks[$topic_id] = max($curr_new_track_val, $post['post_time']); + } + } + set_tracks(COOKIE_TOPIC, $tracking_topics, $new_tracks); +} +// Displaying "as topics" mode +else +{ + $order = $order_opt[$order_val]['sql']; + $sort = $sort_opt[$sort_val]['sql']; + $per_page = $bb_cfg['topics_per_page']; + $display_as_val = $as_topics; + + // Run initial search for topic_ids + if (!$items_found) + { + $join_t = ($title_match || $my_topics || $new_topics || $dl_search || $new_posts || in_array($order_val, array($ord_last_p, $ord_created, $ord_name, $ord_repl))); + $join_s = ($text_match_sql && !$title_match); + $join_p = ($my_posts || $join_s); + $join_dl = ($dl_search); + + $tbl = ($join_p && !$join_t) ? 'p' : 't'; + $time_field = ($join_p && !$join_t) ? 'post_time' : 'topic_last_post_time'; + + // SELECT + if ($egosearch) + { + $SQL['SELECT'][] = 'p.topic_id AS item_id, MAX(p.post_time) AS max_post_time'; + } + else + { + $SQL['SELECT'][] = ($join_p && !$join_t) ? 'p.topic_id AS item_id' : 't.topic_id AS item_id'; + } + + // FROM + if ($join_t) $SQL['FROM'][] = $topics_tbl; + if ($join_s) $SQL['FROM'][] = $search_tbl; + if ($join_p) $SQL['FROM'][] = $posts_tbl; + + if (!$SQL['FROM']) + { + $join_t = true; + $SQL['FROM'][] = $topics_tbl; + } + + // WHERE + if ($join_p && $join_t) $SQL['WHERE'][] = "t.topic_id = p.topic_id"; + if ($join_s) $SQL['WHERE'][] = "ps.post_id = p.post_id"; + + if ($excluded_forums_csv) $SQL['WHERE'][] = "$tbl.forum_id NOT IN($excluded_forums_csv)"; + + if ($join_t) $SQL['WHERE'][] = "t.topic_status != ". TOPIC_MOVED; + if ($forum_val) $SQL['WHERE'][] = "$tbl.forum_id IN($forum_val)"; + if ($topic_val) $SQL['WHERE'][] = "$tbl.topic_id IN($topic_val)"; + if ($new_posts) $SQL['WHERE'][] = "$tbl.$time_field > $lastvisit"; + if ($new_topics) $SQL['WHERE'][] = "t.topic_time > $lastvisit"; + if ($prev_days) $SQL['WHERE'][] = "$tbl.$time_field > ". $time_opt[$time_val]['sql']; + if ($my_posts) $SQL['WHERE'][] = "p.poster_id = $poster_id_val"; + if ($my_topics) $SQL['WHERE'][] = "t.topic_poster = $poster_id_val"; + + if ($text_match_sql) + { + $field_match = ($title_match) ? "t.topic_title" : "ps.search_words" ; + $tmp_text_match_sql = $text_match_sql; + if (mb_substr($tmp_text_match_sql, 0, 1) == '+') $tmp_text_match_sql = mb_substr($tmp_text_match_sql, 1); + $tmp_text_match_sql = str_replace(' +', ' ', $tmp_text_match_sql); + $tmp_text_match_sql = extract_search_words($tmp_text_match_sql, true); + $tmp_text_match_sql = str_replace(' ', '%', $tmp_text_match_sql); + $tmp_text_match_sql = str_replace('%%%', '%', $tmp_text_match_sql); + $tmp_text_match_sql = str_replace('%%', '%', $tmp_text_match_sql); + if ($tmp_text_match_sql == '' || $tmp_text_match_sql == '%') bb_die($lang['NO_SEARCH_MATCH']); + $SQL['WHERE'][] = "$field_match LIKE '%$tmp_text_match_sql%'"; + prevent_huge_searches($SQL); + } + + if ($join_dl) $SQL['FROM'][] = $dl_stat_tbl; + if ($join_dl) $SQL['WHERE'][] = "dl.topic_id = t.topic_id AND dl.user_id = $dl_user_id_val AND dl.user_status IN($dl_status_csv)"; + + if (!$SQL['WHERE']) redirect(basename(__FILE__)); + + $SQL['GROUP BY'][] = "item_id"; + $SQL['LIMIT'][] = "$search_limit"; + + if ($egosearch) + { + $SQL['ORDER BY'][] = 'max_post_time DESC'; + } + else + { + $SQL['ORDER BY'][] = ($order_val == $ord_posted) ? "$tbl.$time_field $sort" : "$order $sort"; + } + + $items_display = fetch_search_ids($SQL); + } + else if (!$items_display = array_slice($items_found, $start, $per_page)) + { + bb_die($lang['NO_SEARCH_MATCH']); + } + + // Build SQL for displaying topics + $SQL = DB()->get_empty_sql_array(); + $join_dl = ($bb_cfg['show_dl_status_in_search'] && !IS_GUEST); + + $SQL['SELECT'][] = " + t.*, t.topic_poster AS first_user_id, + IF(t.topic_poster = $anon_id, p1.post_username, u1.username) AS first_username, + p2.poster_id AS last_user_id, + IF(p2.poster_id = $anon_id, p2.post_username, u2.username) AS last_username + "; + if ($join_dl) $SQL['SELECT'][] = "dl.user_status AS dl_status"; + + $SQL['FROM'][] = BB_TOPICS ." t"; + $SQL['LEFT JOIN'][] = BB_POSTS ." p1 ON(t.topic_first_post_id = p1.post_id)"; + $SQL['LEFT JOIN'][] = BB_USERS ." u1 ON(t.topic_poster = u1.user_id)"; + $SQL['LEFT JOIN'][] = BB_POSTS ." p2 ON(t.topic_last_post_id = p2.post_id)"; + $SQL['LEFT JOIN'][] = BB_USERS ." u2 ON(p2.poster_id = u2.user_id)"; + if ($join_dl) + { + $SQL['LEFT JOIN'][] = BB_BT_DLSTATUS ." dl ON(dl.user_id = $user_id AND dl.topic_id = t.topic_id)"; + } + + $SQL['WHERE'][] = "t.topic_id IN(". join(',', $items_display) .")"; + if ($excluded_forums_csv) + { + $SQL['WHERE'][] = "t.forum_id NOT IN($excluded_forums_csv)"; + } + + $SQL['LIMIT'][] = "$per_page"; + + // Fetch topics data + $topic_rows = array(); + foreach (DB()->fetch_rowset($SQL) as $row) + { + $topic_rows[$row['topic_id']] = $row; + } + if (!$topic_rows) + { + bb_die($lang['NO_SEARCH_MATCH']); + } + + // Output page + foreach ($items_display as $row_num => $item_id) + { + if (empty($topic_rows[$item_id])) + { + continue; // if topic was deleted but still remain in search results + } + $topic = $topic_rows[$item_id]; + $topic_id = $topic['topic_id']; + $forum_id = $topic['forum_id']; + $is_unread = is_unread($topic['topic_last_post_time'], $topic_id, $forum_id); + $moved = ($topic['topic_status'] == TOPIC_MOVED); + + $template->assign_block_vars('t', array( + 'ROW_NUM' => $row_num, + 'FORUM_ID' => $forum_id, + 'FORUM_NAME' => $forum_name_html[$forum_id], + 'TOPIC_ID' => $topic_id, + 'HREF_TOPIC_ID' => ($moved) ? $topic['topic_moved_id'] : $topic['topic_id'], + 'TOPIC_TITLE' => wbr($topic['topic_title']), + 'IS_UNREAD' => $is_unread, + 'TOPIC_ICON' => get_topic_icon($topic, $is_unread), + 'PAGINATION' => ($moved) ? '' : build_topic_pagination(TOPIC_URL . $topic_id, $topic['topic_replies'], $bb_cfg['posts_per_page']), + 'REPLIES' => $topic['topic_replies'], + 'ATTACH' => $topic['topic_attachment'], + 'STATUS' => $topic['topic_status'], + 'TYPE' => $topic['topic_type'], + 'DL' => ($topic['topic_dl_type'] == TOPIC_DL_TYPE_DL), + 'POLL' => $topic['topic_vote'], + 'DL_CLASS' => isset($topic['dl_status']) ? $dl_link_css[$topic['dl_status']] : '', + + 'TOPIC_AUTHOR_HREF' => ($topic['first_user_id'] != ANONYMOUS) ? $topic['first_user_id'] : '', + 'TOPIC_AUTHOR_NAME' => ($topic['first_username']) ? wbr($topic['first_username']) : $lang['GUEST'], + 'LAST_POSTER_HREF' => ($topic['last_user_id'] != ANONYMOUS) ? $topic['last_user_id'] : '', + 'LAST_POSTER_NAME' => ($topic['last_username']) ? str_short($topic['last_username'], 15) : $lang['GUEST'], + 'LAST_POST_TIME' => bb_date($topic['topic_last_post_time']), + 'LAST_POST_ID' => $topic['topic_last_post_id'], + )); + } +} + +if ($items_display) +{ + $items_count = count($items_found); + $pages = (!$items_count) ? 1 : ceil($items_count / $per_page); + $url = ($search_id) ? url_arg($url, 'id', $search_id) : $url; + + $template->assign_vars(array( + 'PAGE_TITLE' => $lang['SEARCH'], + 'PAGINATION' => generate_pagination($url, $items_count, $per_page, $start), + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], floor($start / $per_page) + 1, $pages), + + 'SEARCH_MATCHES' => ($items_count) ? sprintf($lang['FOUND_SEARCH_MATCHES'], $items_count) : '', + 'DISPLAY_AS_POSTS' => $post_mode, + + 'DL_CONTROLS' => ($dl_search && $dl_user_id_val == $user_id), + 'DL_ACTION' => "dl_list.php", + )); + + print_page('search_results.tpl'); +} + +redirect(basename(__FILE__)); + +// ----------------------------------------------------------- // +// Functions +// +function fetch_search_ids ($sql, $search_type = SEARCH_TYPE_POST, $redirect_to_result = UA_IE) +{ + global $lang, $search_id, $session_id; + global $items_found, $per_page; + + $items_found = array(); + foreach (DB()->fetch_rowset($sql) as $row) + { + $items_found[] = $row['item_id']; + } + if (!$items_count = count($items_found)) + { + bb_die($lang['NO_SEARCH_MATCH']); + } + + // Save results in DB + $search_id = make_rand_str(SEARCH_ID_LENGTH); + $redirect = ($redirect_to_result && isset($_POST['submit'])); + + if ($items_count > $per_page || $redirect) + { + $search_array = join(',', $items_found); + + $save_in_db = array( + 'order', + 'sort', + 'display_as', + 'chars', + ); + if ($GLOBALS['dl_cancel_val']) $save_in_db[] = 'dl_cancel'; + if ($GLOBALS['dl_compl_val']) $save_in_db[] = 'dl_compl'; + if ($GLOBALS['dl_down_val']) $save_in_db[] = 'dl_down'; + if ($GLOBALS['dl_will_val']) $save_in_db[] = 'dl_will'; + + $curr_set = array(); + foreach ($save_in_db as $name) + { + $curr_set[$GLOBALS["{$name}_key"]] = $GLOBALS["{$name}_val"]; + } + $search_settings = DB()->escape(serialize($curr_set)); + + $columns = 'session_id, search_type, search_id, search_time, search_settings, search_array'; + $values = "'$session_id', $search_type, '$search_id', ". TIMENOW .", '$search_settings', '$search_array'"; + + DB()->query("REPLACE INTO ". BB_SEARCH ." ($columns) VALUES ($values)"); + } + + if ($redirect) + { + redirect("search.php?id=$search_id"); + } + + return array_slice($items_found, 0, $per_page); +} + +function prevent_huge_searches ($SQL) +{ + global $bb_cfg; + + if ($bb_cfg['limit_max_search_results']) + { + $SQL['select_options'][] = 'SQL_CALC_FOUND_ROWS'; + $SQL['ORDER BY'] = array(); + $SQL['LIMIT'] = array('0'); + + if (DB()->query($SQL) AND $row = DB()->fetch_row("SELECT FOUND_ROWS() AS rows_count")) + { + if ($row['rows_count'] > $bb_cfg['limit_max_search_results']) + { +# bb_log(str_compact(DB()->build_sql($SQL)) ." [{$row['rows_count']} rows]". LOG_LF, 'sql_huge_search'); + bb_die('Too_many_search_results'); + } + } +### TEMP ### +# preg_match("#MATCH \((\w).*?\) AGAINST \('(.*?)' IN BOOLEAN MODE\)#", stripslashes($SQL['WHERE'][count($SQL['WHERE'])-1]), $m); +# $msg = date('m-d | H:i:s | ') . sprintf('%-18s', $GLOBALS['userdata']['username']) .' | '. sprintf('%04d', $row['rows_count']) .' | '. $m[1] .' | '. sprintf('%-40s', $m[2]) .' | '; +# bb_log($msg . str_compact(DB()->build_sql($SQL)) . LOG_LF, 'sql_text_search'); +### / TEMP ### + } +} + +function username_search ($search_match) +{ + global $template, $lang; + global $gen_simple_header; + + $username_list = ''; + + if (!empty($search_match)) + { + $username_search = preg_replace('/\*/', '%', clean_username($search_match)); + + $sql = " + SELECT username + FROM ". BB_USERS ." + WHERE username LIKE '". str_replace("\'", "''", $username_search) . "' + AND user_id <> ". ANONYMOUS ." + ORDER BY username + LIMIT 200 + "; + + foreach (DB()->fetch_rowset($sql) as $row) + { + $username = htmlCHR(stripslashes(html_entity_decode($row['username']))); + $username_list .= ''; + } + if (!$username_list) + { + $username_list = ''; + } + } + + $input_name = isset($_REQUEST['input_name']) ? htmlCHR($_REQUEST['input_name']) : 'username'; + + $template->assign_vars(array( + 'TPL_SEARCH_USERNAME' => true, + + 'PAGE_TITLE' => $lang['SEARCH'], + 'USERNAME' => !empty($search_match) ? htmlCHR(stripslashes(html_entity_decode($search_match))) : '', + 'INPUT_NAME' => $input_name, + 'USERNAME_OPTIONS' => $username_list, + 'SEARCH_ACTION' => "search.php?mode=searchuser&input_name=$input_name", + )); + + print_page('search.tpl', 'simple'); +} diff --git a/upload/stats/tr_stats.php b/upload/stats/tr_stats.php new file mode 100644 index 000000000..b817b43c3 --- /dev/null +++ b/upload/stats/tr_stats.php @@ -0,0 +1,35 @@ +session_start(); + +if (!IS_ADMIN) die('Unauthorized'); + +$titles[] = 'неактивные пользователи в течение 30 дней'; +$titles[] = 'неактивные пользователи в течение 90 дней'; +$titles[] = 'средний размер раздачи на трекере (сколько мегабайт)'; +$titles[] = 'сколько у нас всего раздач на трекере'; +$titles[] = 'сколько живых раздач (есть хотя бы 1 сид)'; +$titles[] = 'сколько раздач где которые сидируются больше 5 сидами'; +$titles[] = 'сколько у нас аплоадеров (те, кто залили хотя бы 1 раздачу)'; +$titles[] = 'сколько аплоадеров за последние 30 дней'; + +$sql[] = 'SELECT count(*) FROM `'.BB_USERS.'` WHERE `user_lastvisit` < UNIX_TIMESTAMP()-2592000'; +$sql[] = 'SELECT count(*) FROM `'.BB_USERS.'` WHERE `user_lastvisit` < UNIX_TIMESTAMP()-7776000'; +$sql[] = 'SELECT round(avg(size)/1048576) FROM `'.BB_BT_TORRENTS.'`'; +$sql[] = 'SELECT count(*) FROM `'.BB_BT_TORRENTS.'`'; +$sql[] = 'SELECT count(distinct(topic_id)) FROM `'.BB_BT_TRACKER_SNAP.'` WHERE seeders > 0'; +$sql[] = 'SELECT count(distinct(topic_id)) FROM `'.BB_BT_TRACKER_SNAP.'` WHERE seeders > 5'; +$sql[] = 'SELECT count(distinct(poster_id)) FROM `'.BB_BT_TORRENTS.'`'; +$sql[] = 'SELECT count(distinct(poster_id)) FROM `'.BB_BT_TORRENTS.'` WHERE reg_time >= UNIX_TIMESTAMP()-2592000'; + +foreach($sql as $i => $query) { + $res = DB()->query($query) or die('Oh shit!'); + $row = mysql_fetch_row($res); + echo "
  • {$titles[$i]} - {$row[0]}"; +} + +?> \ No newline at end of file diff --git a/upload/stats/tracker.php b/upload/stats/tracker.php new file mode 100644 index 000000000..8e557b979 --- /dev/null +++ b/upload/stats/tracker.php @@ -0,0 +1,141 @@ +query(" + CREATE TEMPORARY TABLE ". TMP_TRACKER_TABLE ." ( + `topic_id` mediumint(8) unsigned NOT NULL default '0', + `user_id` mediumint(9) NOT NULL default '0', + `ip` char(8) binary NOT NULL default '0', + `seeder` tinyint(1) NOT NULL default '0', + `speed_up` mediumint(8) unsigned NOT NULL default '0', + `speed_down` mediumint(8) unsigned NOT NULL default '0', + `update_time` int(11) NOT NULL default '0' + ) + SELECT + topic_id, user_id, ip, seeder, speed_up, speed_down, update_time + FROM ". BB_BT_TRACKER ." +"); + +// Peers within announce interval +$stat += DB()->fetch_row("SELECT COUNT(*) AS p_within_ann FROM ". TMP_TRACKER_TABLE ." WHERE update_time >= ". (TIMENOW - $announce_interval)); +// All peers, "max_peer_time" +$stat += DB()->fetch_row("SELECT COUNT(*) AS p_all, SUM(speed_up) as speed_up, SUM(speed_down) as speed_down, UNIX_TIMESTAMP() - MIN(update_time) AS max_peer_time, UNIX_TIMESTAMP() - MAX(update_time) AS last_peer_time FROM ". TMP_TRACKER_TABLE); + + +// Active users +$stat += DB()->fetch_row("SELECT COUNT(DISTINCT user_id) AS u_bt_active FROM ". TMP_TRACKER_TABLE); +// All bt-users +$stat += DB()->fetch_row("SELECT COUNT(*) AS u_bt_all FROM ". BB_BT_USERS); +// All bb-users +$stat += DB()->fetch_row("SELECT COUNT(*) AS u_bb_all FROM ". BB_USERS); + + +// Active torrents +$stat += DB()->fetch_row("SELECT COUNT(DISTINCT topic_id) AS tor_active FROM ". TMP_TRACKER_TABLE); +// With seeder +$stat += DB()->fetch_row("SELECT COUNT(DISTINCT topic_id) AS tor_with_seeder FROM ". TMP_TRACKER_TABLE ." WHERE seeder = 1"); +// All torrents +$stat += DB()->fetch_row("SELECT COUNT(*) AS tor_all, SUM(size) AS torrents_size FROM ". BB_BT_TORRENTS); + + +// Last xx minutes +$peers_in_last_min = array(); +foreach ($peers_in_last_minutes as $t) +{ + $row = DB()->fetch_row(" + SELECT COUNT(*) AS peers FROM ". TMP_TRACKER_TABLE ." WHERE update_time >= ". (TIMENOW - 60*$t) ." + "); + $peers_in_last_min[$t] = (int) $row['peers']; +} +// Last xx seconds +$peers_in_last_sec = array(); +$rowset = DB()->fetch_rowset("SELECT COUNT(*) AS peers FROM ". TMP_TRACKER_TABLE ." GROUP BY update_time DESC LIMIT $peers_in_last_sec_limit"); +foreach ($rowset as $cnt => $row) +{ + $peers_in_last_sec[] = sprintf('%3s', $row['peers']) . (($cnt && !(++$cnt%15)) ? " \n" : ''); +} + + + +function commify_callback ($matches) +{ + return commify($matches[0]); +} +function commify_ob ($contents) +{ + return preg_replace_callback("#\b\d+\b#", 'commify_callback', $contents); +} +ob_start('commify_ob'); + + +echo ''; +echo ' +


    + +++'; + +echo "\n\n"; + +echo "\n + + +\n"; + +echo "\n + + +\n"; + +echo "\n\n"; +echo "\n\n"; + +echo "\n\n"; +echo '\n"; + +echo '
    users: bb-all / bt-all / bt-active $stat[u_bb_all] / $stat[u_bt_all] / $stat[u_bt_active]
    torrents: all / active / with seeder + $stat[tor_all] / $stat[tor_active] / $stat[tor_with_seeder] +   + [ ". humn_size($stat['torrents_size']) ." ] +
    peers: all ($stat[max_peer_time] s) / in ann interval ($announce_interval s) + $stat[p_all] / $stat[p_within_ann] +   + [ up: ". humn_size($stat['speed_up']) ."/s, + down: ". humn_size($stat['speed_down']) ."/s ] +
    peers: in last ". join(' / ', $peers_in_last_minutes) ." min". join(' / ', $peers_in_last_min) ."
    peers in last $peers_in_last_sec_limit sec
    [ per second, DESC order --> ]
    last peer: $stat[last_peer_time] seconds ago
    ". date("j M H:i:s [T O]") ."
     '. join(' ', $peers_in_last_sec) ."
    '; + +echo '
    ';
    +
    +if ($loadavg = get_loadavg())
    +{
    +	echo "\n\nloadavg: $loadavg\n\n";
    +}
    +
    +echo 'gen time: '. sprintf('%.3f', (array_sum(explode(' ', microtime())) - TIMESTART)) ." sec\n";
    +
    +echo '
    '; +echo ''; + +DB()->query("DROP TEMPORARY TABLE ". TMP_TRACKER_TABLE); + +bb_exit(); + diff --git a/upload/templates/admin/admin_attach_cp.tpl b/upload/templates/admin/admin_attach_cp.tpl new file mode 100644 index 000000000..5240433ba --- /dev/null +++ b/upload/templates/admin/admin_attach_cp.tpl @@ -0,0 +1,254 @@ + +

    {L_CONTROL_PANEL_TITLE}

    + +

    {L_CONTROL_PANEL_EXPLAIN}

    +
    + + + + +
    + + + + +
    {L_VIEW}: {S_VIEW_SELECT}   + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_STATISTIC}{L_VALUE}
    {L_NUMBER_OF_ATTACHMENTS}:{NUMBER_OF_ATTACHMENTS}
    {L_TOTAL_FILESIZE}:{TOTAL_FILESIZE}
    {L_ATTACH_QUOTA}:{ATTACH_QUOTA}
    {L_NUMBER_POSTS_ATTACH}:{NUMBER_OF_POSTS}
    {L_NUMBER_PMS_ATTACH}:{NUMBER_OF_PMS}
    {L_NUMBER_TOPICS_ATTACH}:{NUMBER_OF_TOPICS}
    {L_NUMBER_USERS_ATTACH}:{NUMBER_OF_USERS}
    +
    + + + + + + + +
    + + + + +
    {L_VIEW}: {S_VIEW_SELECT}   + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_ATTACH_SEARCH_QUERY}
    {L_FILE_NAME}:
    {L_SEARCH_WILDCARD_EXPLAIN}
    {L_FILE_COMMENT}:
    {L_SEARCH_WILDCARD_EXPLAIN}
    {L_SEARCH_AUTHOR}:
    {L_SEARCH_WILDCARD_EXPLAIN}
    {L_SIZE_SMALLER_THAN}:
    {L_SIZE_GREATER_THAN}:
    {L_COUNT_SMALLER_THAN}:
    {L_COUNT_GREATER_THAN}:
    {L_MORE_DAYS_OLD}:
    {L_SEARCH_OPTIONS}
    {L_FORUM}:
    {L_SORT_BY}: {S_SORT_OPTIONS}
    {L_SORT}: {S_SORT_ORDER}
    {S_HIDDEN_FIELDS}
    + +
    + + + + + + + +
    + + + + +
    {L_VIEW}: {S_VIEW_SELECT}  {L_SORT_BY}: {S_MODE_SELECT}  {L_ORDER} {S_ORDER_SELECT}   + +
    + + + + + + + + + + + + + + + +
    #{L_USERNAME}{L_ATTACHMENTS}{L_SIZE_IN_KB}
     {memberrow.ROW_NUMBER} {memberrow.USERNAME} {memberrow.TOTAL_ATTACHMENTS}  {memberrow.TOTAL_SIZE} 
    + + + + + + +
    {PAGE_NUMBER}{PAGINATION} 
    +
    + + + + + + + + +{L_STATISTICS_FOR_USER} + + + + +
    + + + + +
    {L_VIEW}: {S_VIEW_SELECT}  {L_SORT_BY}: {S_MODE_SELECT}  {L_ORDER} {S_ORDER_SELECT}   + + +
    + + + + + + + + + + + + + + + + + + + + + + + + {attachrow.S_HIDDEN} + + + + + +
    #{L_FILE_NAME}{L_FILE_COMMENT_CP}{L_EXTENSION}{L_SIZE_IN_KB}{L_DOWNLOADS}{L_POST_TIME}{L_POSTED_IN_TOPIC}{L_DELETE}
     {attachrow.ROW_NUMBER} {attachrow.FILENAME}{attachrow.EXTENSION}{attachrow.SIZE}{attachrow.POST_TIME}{attachrow.POST_TITLE}{attachrow.S_DELETE_BOX}
    + +   + +
    + + + {S_USER_HIDDEN} + + + + + + +
    {L_MARK_ALL} :: {L_UNMARK_ALL}
    + + + + + + +
    {PAGE_NUMBER}{PAGINATION} 
    +
    + + + + +
    diff --git a/upload/templates/admin/admin_attachments.tpl b/upload/templates/admin/admin_attachments.tpl new file mode 100644 index 000000000..5d40bc57f --- /dev/null +++ b/upload/templates/admin/admin_attachments.tpl @@ -0,0 +1,345 @@ + + + + +

    {L_MANAGE_CAT_TITLE}

    + +

    {L_MANAGE_CAT_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_SETTINGS_CAT_IMAGES}
    {L_ASSIGNED_GROUP}: {S_ASSIGNED_GROUP_IMAGES}
    {L_DISPLAY_INLINED}
    {L_DISPLAY_INLINED_EXPLAIN}
    {L_YES}   {L_NO}
    {L_CREATE_THUMBNAIL}
    {L_CREATE_THUMBNAIL_EXPLAIN}
    {L_YES}   {L_NO}
    {L_MIN_THUMB_FILESIZE}
    {L_MIN_THUMB_FILESIZE_EXPLAIN}
    {L_BYTES}
    {L_USE_GD2}
    {L_USE_GD2_EXPLAIN}
    {L_YES}   {L_NO}
    {L_IMAGICK_PATH}
    {L_IMAGICK_PATH_EXPLAIN}
    {L_MAX_IMAGE_SIZE}
    {L_MAX_IMAGE_SIZE_EXPLAIN}
    x
    {L_IMAGE_LINK_SIZE}
    {L_IMAGE_LINK_SIZE_EXPLAIN}
    x
    {S_HIDDEN_FIELDS}      
    +
    + + + + + + + +

    {L_MANAGE_TITLE}

    + +

    {L_MANAGE_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_ATTACHMENT_SETTINGS}
    {L_UPLOAD_DIR}
    {L_UPLOAD_DIR_EXPLAIN}
    {L_ATTACHMENT_IMG_PATH}
    {L_IMG_PATH_EXPLAIN}
    {L_ATTACHMENT_TOPIC_ICON}
    {L_TOPIC_ICON_EXPLAIN}
    {L_DISPLAY_ORDER}
    {L_DISPLAY_ORDER_EXPLAIN}
    + + + + + + + +
    {L_DESC}
    {L_ASC}
    {L_ATTACHMENT_FILESIZE_SETTINGS}
    {L_MAX_FILESIZE}
    {L_MAX_FILESIZE_EXPLAIN}
    {S_FILESIZE}
    {L_ATTACH_QUOTA}
    {L_ATTACH_QUOTA_EXPLAIN}
    {S_FILESIZE_QUOTA}
    {L_MAX_FILESIZE_PM}
    {L_MAX_FILESIZE_PM_EXPLAIN}
    {S_FILESIZE_PM}
    {L_DEFAULT_QUOTA_LIMIT}
    {L_DEFAULT_QUOTA_LIMIT_EXPLAIN}
    + + + + + + + + + +
    {S_DEFAULT_UPLOAD_LIMIT} {L_UPLOAD_QUOTA} 
    {S_DEFAULT_PM_LIMIT} {L_PM_QUOTA} 
    +
    {L_ATTACHMENT_NUMBER_SETTINGS}
    {L_MAX_ATTACHMENTS}
    {L_MAX_ATTACHMENTS_EXPLAIN}
    {L_MAX_ATTACHMENTS_PM}
    {L_MAX_ATTACHMENTS_PM_EXPLAIN}
    {L_ATTACHMENT_OPTIONS_SETTINGS}
    {L_DISABLE_MOD}
    {L_DISABLE_MOD_EXPLAIN}
    {L_YES}   {L_NO}
    {L_PM_ATTACH}
    {L_PM_ATTACH_EXPLAIN}
    {L_YES}   {L_NO}
    {L_FTP_UPLOAD}
    {L_FTP_UPLOAD_EXPLAIN}
    {L_YES}   {L_NO}
    {L_ATTACHMENT_FTP_SETTINGS}
    {L_ATTACHMENT_FTP_SERVER}
    {L_ATTACHMENT_FTP_SERVER_EXPLAIN}
    {L_ATTACHMENT_FTP_PATH}
    {L_ATTACHMENT_FTP_PATH_EXPLAIN}
    {L_DOWNLOAD_PATH}
    {L_DOWNLOAD_PATH_EXPLAIN}
    {L_FTP_PASSIVE_MODE}
    {L_FTP_PASSIVE_MODE_EXPLAIN}
    {L_YES}   {L_NO}
    {L_ATTACHMENT_FTP_USER}
    {L_ATTACHMENT_FTP_PASS}
    {L_ATTACHMENT_FTP_SETTINGS}
    {L_NO_FTP_EXTENSIONS}
    {S_HIDDEN_FIELDS}    
    +
    + + + + + + + +

    {L_MANAGE_QUOTAS_TITLE}

    + +

    {L_MANAGE_QUOTAS_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_MANAGE_QUOTAS_TITLE} +
    {L_DESCRIPTION}{L_SIZE}{L_ADD_NEW}
    {S_FILESIZE}
    {S_HIDDEN_FIELDS}
    {L_DESCRIPTION}{L_SIZE}{L_DELETE}
    + + + + + + +
    {L_VIEW}
    +
    {limit_row.S_FILESIZE}
    +
    + + + + +

    {L_QUOTA_LIMIT_DESC}

    + + + + + + + + + + + + + + +
    + + + + + + + +
    {L_ASSIGNED_USERS} - {L_UPLOAD_QUOTA}
    + +
    +
    +     + + + + + + + + +
    {L_ASSIGNED_GROUPS} - {L_UPLOAD_QUOTA}
    + +
    +
    +     +
    + + + + + + + +
    {L_ASSIGNED_USERS} - {L_PM_QUOTA}
    + +
    +
    +     + + + + + + + + +
    {L_ASSIGNED_GROUPS} - {L_PM_QUOTA}
    + +
    +
    + + + + + +
    \ No newline at end of file diff --git a/upload/templates/admin/admin_board.tpl b/upload/templates/admin/admin_board.tpl new file mode 100644 index 000000000..0ba61941a --- /dev/null +++ b/upload/templates/admin/admin_board.tpl @@ -0,0 +1,211 @@ + +

    {L_GENERAL_CONFIG}

    + +

    {L_CONFIG_EXPLAIN}

    +
    + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_GENERAL_SETTINGS}

    {L_SITE_NAME}

    {L_SITE_DESC}

    {L_BOARD_DISABLE}

    {L_BOARD_DISABLE_EXPLAIN}
    {L_YES}   {L_NO}

    {L_ACCT_ACTIVATION}

    +
    {L_ACC_NONE}
    +
    {L_ACC_USER}
    +
    {L_ACC_ADMIN}
    +

    {L_VISUAL_CONFIRM}

    {L_VISUAL_CONFIRM_EXPLAIN}
    {L_YES}   {L_NO}

    {L_ALLOW_AUTOLOGIN}

    {L_ALLOW_AUTOLOGIN_EXPLAIN}
    {L_YES}   {L_NO}

    {L_AUTOLOGIN_TIME}

    {L_AUTOLOGIN_TIME_EXPLAIN}
    days

    {L_BOARD_EMAIL_FORM}

    {L_BOARD_EMAIL_FORM_EXPLAIN}
    {L_ENABLED}   {L_DISABLED}

    {L_FLOOD_INTERVAL}

    {L_FLOOD_INTERVAL_EXPLAIN}
    sec

    {L_TOPICS_PER_PAGE}

    {L_POSTS_PER_PAGE}

    {L_HOT_THRESHOLD}

    {L_DEFAULT_LANGUAGE}

    {LANG_SELECT}

    {L_DATE_FORMAT}

    {L_DATE_FORMAT_EXPLAIN}

    {L_SYSTEM_TIMEZONE}

    {TIMEZONE_SELECT}

    {L_ENABLE_PRUNE}

    {L_YES}   {L_NO}
    {L_PRIVATE_MESSAGING}

    {L_DISABLE_PRIVMSG}

    {L_ENABLED}   {L_DISABLED}

    {L_INBOX_LIMITS}

    {L_SENTBOX_LIMITS}

    {L_SAVEBOX_LIMITS}

    {L_ABILITIES_SETTINGS}

    {L_MAX_POLL_OPTIONS}

    {L_ALLOW_BBCODE}

    {L_YES}   {L_NO}

    {L_ALLOW_SMILIES}

    {L_YES}   {L_NO}

    {L_SMILIES_PATH}

    {L_SMILIES_PATH_EXPLAIN}

    {L_ALLOW_SIG}

    {L_YES}   {L_NO}

    {L_MAX_SIG_LENGTH}

    {L_MAX_SIG_LENGTH_EXPLAIN}

    {L_ALLOW_NAME_CHANGE}

    {L_YES}   {L_NO}
    {L_AVATAR_SETTINGS}

    {L_ALLOW_LOCAL}

    {L_YES}   {L_NO}

    {L_ALLOW_REMOTE}

    {L_ALLOW_REMOTE_EXPLAIN}
    {L_YES}   {L_NO}

    {L_ALLOW_UPLOAD}

    {L_YES}   {L_NO}

    {L_MAX_FILESIZE}

    {L_MAX_FILESIZE_EXPLAIN}
    Bytes

    {L_MAX_AVATAR_SIZE}

    {L_MAX_AVATAR_SIZE_EXPLAIN}
    x

    {L_AVATAR_STORAGE_PATH}

    {L_AVATAR_STORAGE_PATH_EXPLAIN}

    {L_AVATAR_GALLERY_PATH}

    {L_AVATAR_GALLERY_PATH_EXPLAIN}
    {L_EMAIL_SETTINGS}

    {L_ADMIN_EMAIL}

    {L_EMAIL_SIG}

    {L_EMAIL_SIG_EXPLAIN}

    {L_USE_SMTP}

    {L_USE_SMTP_EXPLAIN}
    {L_YES}   {L_NO}

    {L_SMTP_SERVER}

    {L_SMTP_USERNAME}

    {L_SMTP_USERNAME_EXPLAIN}

    {L_SMTP_PASSWORD}

    {L_SMTP_PASSWORD_EXPLAIN}
    +    +
    + +
    + +
    \ No newline at end of file diff --git a/upload/templates/admin/admin_bt_forum_cfg.tpl b/upload/templates/admin/admin_bt_forum_cfg.tpl new file mode 100644 index 000000000..ae7105a88 --- /dev/null +++ b/upload/templates/admin/admin_bt_forum_cfg.tpl @@ -0,0 +1,190 @@ +

    {L_FORUM_CFG_TITLE}

    + +
    +{S_HIDDEN_FIELDS} + + ++++ + + + + + + + + + + + + + + + +
    {L_BT_SELECT_FORUMS}
    {L_ALLOW_REG_TRACKER}{L_SELF_MODERATED}{L_ALLOW_DL_TOPIC}
    {S_ALLOW_REG_TRACKER}{S_SELF_MODERATED}{S_ALLOW_DL_TOPIC}
    {L_BT_SELECT_FORUMS_EXPL}
    + +
    + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_BT_ANNOUNCE_URL_HEAD}

    {L_BT_ANNOUNCE_URL}

    {L_BT_ANNOUNCE_URL_EXPL}

    {L_BT_DISABLE_DHT}

    {L_BT_DISABLE_DHT_EXPL}

    {L_BT_CHECK_ANNOUNCE_URL}

    {L_BT_CHECK_ANNOUNCE_URL_EXPL}

    {L_BT_REPLACE_ANN_URL}

    {L_BT_REPLACE_ANN_URL_EXPL}

    {L_BT_DEL_ADDIT_ANN_URLS}

    {L_BT_DEL_ADDIT_ANN_URLS_EXPL}

    {L_BT_ADD_COMMENT}

    {L_BT_ADD_COMMENT_EXPL}

    {L_BT_ADD_PUBLISHER}

    {L_BT_ADD_PUBLISHER_EXPL}
    {L_BT_SHOW_PEERS_HEAD}

    {L_BT_SHOW_PEERS}

    {L_BT_SHOW_PEERS_EXPL}

    {L_BT_SHOW_PEERS_MODE}

    +
    +
    +
    +

    {L_BT_ALLOW_SPMODE_CHANGE}

    {L_BT_ALLOW_SPMODE_CHANGE_EXPL}

    {L_BT_SHOW_IP_ONLY_MODER}

    {L_BT_SHOW_PORT_ONLY_MODER}

    {L_BT_SHOW_DL_LIST_HEAD}

    {L_BT_SHOW_DL_LIST}

    {L_BT_DL_LIST_ONLY_1ST_PAGE}

    {L_BT_DL_LIST_ONLY_COUNT}

    +

    {L_BT_SHOW_DL_LIST_BUTTONS}

    + + + + + + + + + + + + + + + + + + + +
    {L_BT_SHOW_DL_BUT_WILL}
    {L_BT_SHOW_DL_BUT_DOWN}
    {L_BT_SHOW_DL_BUT_COMPL}
    {L_BT_SHOW_DL_BUT_CANCEL}
    +

    {L_BT_SET_DLTYPE_ON_TOR_REG}

    {L_BT_SET_DLTYPE_ON_TOR_REG_EXPL}

    {L_BT_UNSET_DLTYPE_ON_TOR_UNREG}

    {L_BT_ADD_AUTH_KEY_HEAD}

    {L_BT_ADD_AUTH_KEY}

    {L_BT_GEN_PASSKEY_ON_REG}

    {L_BT_GEN_PASSKEY_ON_REG_EXPL}
    {L_BT_TOR_BROWSE_ONLY_REG_HEAD}

    {L_BT_TOR_BROWSE_ONLY_REG}

    {L_BT_SEARCH_BOOL_MODE}

    {L_BT_SEARCH_BOOL_MODE_EXPL}
    {L_BT_SHOW_DL_STAT_ON_INDEX_HEAD}

    {L_BT_SHOW_DL_STAT_ON_INDEX}

    {L_BT_NEWTOPIC_AUTO_REG}

    +    +    + +
    + +
    + +
    + diff --git a/upload/templates/admin/admin_bt_tracker_cfg.tpl b/upload/templates/admin/admin_bt_tracker_cfg.tpl new file mode 100644 index 000000000..073bc6dda --- /dev/null +++ b/upload/templates/admin/admin_bt_tracker_cfg.tpl @@ -0,0 +1,125 @@ +

    {L_CONFIGURATION_TITLE}

    + +
    + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_TRACKER_SETTINGS}
    +

    Changes disabled (see $tr_cfg in config.php)

    +

    {L_OFF}

    {L_OFF_REASON}

    {L_OFF_REASON_EXPL}
     

    {L_AUTOCLEAN}

    Used in cron Tracker cleanup and dlstat
    {L_AUTOCLEAN_EXPL}

    {L_COMPACT_MODE}

    {L_COMPACT_MODE_EXPL}

    {L_BROWSER_REDIRECT_URL}

    {L_BROWSER_REDIRECT_URL_EXPL}
       
    {L_USE_AUTH_KEY_HEAD}

    {L_USE_AUTH_KEY}

    {L_USE_AUTH_KEY_EXPL}
      {L_YES}

    {L_AUTH_KEY_NAME}

    $bb_cfg['passkey_key']
    {L_AUTH_KEY_NAME_EXPL}
      {PASSKEY_KEY}

    {L_ALLOW_GUEST_DL}

    {L_ALLOW_GUEST_DL_EXPL}
      {L_NO}
    {L_LIMIT_ACTIVE_TOR_HEAD}

    {L_NUMWANT}

    {L_NUMWANT_EXPL}
     

    {L_LIMIT_ACTIVE_TOR}

    {L_LIMIT_SEED_COUNT}

    {L_LIMIT_SEED_COUNT_EXPL}
      torrents

    {L_LIMIT_LEECH_COUNT}

    {L_LIMIT_LEECH_COUNT_EXPL}
      torrents

    {L_LEECH_EXPIRE_FACTOR}

    {L_LEECH_EXPIRE_FACTOR_EXPL}
      minutes

    {L_LIMIT_CONCURRENT_IPS}

    {L_LIMIT_CONCURRENT_IPS_EXPL}

    {L_LIMIT_SEED_IPS}

    {L_LIMIT_SEED_IPS_EXPL}
      IP's

    {L_LIMIT_LEECH_IPS}

    {L_LIMIT_LEECH_IPS_EXPL}
      IP's
    {L_ANNOUNCE_INTERVAL_HEAD}

    {L_ANNOUNCE_INTERVAL}

    $bb_cfg['announce_interval']
    {L_ANNOUNCE_INTERVAL_EXPL}
      {ANNOUNCE_INTERVAL} seconds

    {L_EXPIRE_FACTOR}

    {L_EXPIRE_FACTOR_EXPL}
     

    {L_UPDATE_DLSTAT}

    Used in cron Tracker cleanup and dlstat

    {L_IGNORE_GIVEN_IP}

    $bb_cfg['ignore_reported_ip']
    {L_IGNOR_GIVEN_IP_EXPL}
      {L_YES}{L_NO}
    + + {S_HIDDEN_FIELDS} +   +   +   + + +
    +
    + +
    + diff --git a/upload/templates/admin/admin_cron.tpl b/upload/templates/admin/admin_cron.tpl new file mode 100644 index 000000000..08cb6197e --- /dev/null +++ b/upload/templates/admin/admin_cron.tpl @@ -0,0 +1,241 @@ + + + +
    + + + + + + + + + + + + + + + + + + + +{LIST} + +
    + {L_CRON_LIST} +
    + + + + {L_CRON_ID} + + + + {L_CRON_ACTIVE} + + + + {L_CRON_TITLE} + + + + {L_CRON_SCRIPT} + + + + {L_CRON_SCHEDULE} + + + + {L_CRON_LAST_RUN} + + + + {L_CRON_NEXT_RUN} + + + + {L_CRON_RUN_COUNT} + + + + {L_CRON_MANAGE} + +
    + + + + + + + + + + + + + + + +
    + {L_CRON_OPTIONS} +
    {L_CRON_ENABLED}
    {L_CRON_CHECK_INTERVAL}
    + {L_WITH_SELECTED} + + +    +
    +
    +
    +
    +{L_RUN_MAIN_CRON}
    +{L_ADD_JOB} +
    +{CRON_ACTION} + +
    {L_CRON_WORKS} +{L_REPAIR_CRON}
    + + + + + + +

    {L_CRON_EDIT_HEAD}

    +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_CRON_EDIT_HEAD}

    {L_CRON_ID}

    {CRON_ID}

    {L_CRON_ACTIVE}

    {L_CRON_ACTIVE_EXPL}

    {L_CRON_TITLE}

    {L_CRON_SCRIPT}

    {L_CRON_SCRIPT_EXPL}

    {L_SCHEDULE}

    {SCHEDULE}

    {L_RUN_DAY}

    {L_RUN_DAY_EXPL}
    {RUN_DAY}

    {L_RUN_TIME}

    {L_RUN_TIME_EXPL}

    {L_RUN_ORDER}

    {L_LAST_RUN}

    {L_NEXT_RUN}

    {L_RUN_INTERVAL}

    {L_RUN_INTERVAL_EXPL}

    {L_LOG_ENABLED}

    {L_LOG_FILE}

    {L_LOG_FILE_EXPL}

    {L_LOG_SQL_QUERIES}

    {L_DISABLE_BOARD}

    {L_DISABLE_BOARD_EXPL}

    {L_RUN_COUNTER}

    +    +    + +
    + +
    + \ No newline at end of file diff --git a/upload/templates/admin/admin_disallow.tpl b/upload/templates/admin/admin_disallow.tpl new file mode 100644 index 000000000..0622d6419 --- /dev/null +++ b/upload/templates/admin/admin_disallow.tpl @@ -0,0 +1,31 @@ + +

    {L_DISALLOW_TITLE}

    + +

    {L_DISALLOW_EXPLAIN}

    +
    + +
    + + +++ + + + + + + + + + + + + + + + + +
    {L_ADD_DISALLOW}

    {L_USERNAME}

    {L_ADD_EXPLAIN}
     
    {L_DELETE_DISALLOW}

    {L_USERNAME}

    {L_DELETE_EXPLAIN}
    {S_DISALLOW_SELECT} 
     
    + +
    diff --git a/upload/templates/admin/admin_extensions.tpl b/upload/templates/admin/admin_extensions.tpl new file mode 100644 index 000000000..7f5a20023 --- /dev/null +++ b/upload/templates/admin/admin_extensions.tpl @@ -0,0 +1,220 @@ + + + + +

    {L_EXTENSIONS_TITLE}

    + +

    {L_EXTENSIONS_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_EXTENSIONS_TITLE} +
     {L_EXPLANATION}  {L_EXTENSION}  {L_EXTENSION_GROUP}  {L_ADD_NEW} 
    {S_ADD_GROUP_SELECT}
    {S_HIDDEN_FIELDS}
     {L_EXPLANATION}  {L_EXTENSION}  {L_EXTENSION_GROUP}  {L_DELETE} 
    {extension_row.EXTENSION}{extension_row.S_GROUP_SELECT}
    + +
    + +
    + + + + + + + +{GROUP_PERMISSIONS_BOX} + +

    {L_EXTENSION_GROUPS_TITLE}

    + +

    {L_EXTENSION_GROUPS_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_EXTENSION_GROUPS_TITLE} +
     {L_EXTENSION_GROUP}  {L_SPECIAL_CATEGORY}  {L_ALLOWED}  {L_DOWNLOAD_MODE}  {L_UPLOAD_ICON}  {L_MAX_FILESIZE}  {L_ALLOWED_FORUMS}  {L_ADD_NEW} 
    + + + + + +
     
    +
    {S_SELECT_CAT}{S_ADD_DOWNLOAD_MODE} {S_FILESIZE} 
     {L_EXTENSION_GROUP}  {L_SPECIAL_CATEGORY}  {L_ALLOWED}  {L_DOWNLOAD_MODE}  {L_UPLOAD_ICON}  {L_MAX_FILESIZE}  {L_ALLOWED_FORUMS}  {L_DELETE} 
    + + + + + +
    {grouprow.CAT_BOX}
    +
    {grouprow.S_SELECT_CAT}{grouprow.S_DOWNLOAD_MODE} {grouprow.S_FILESIZE}{L_FORUM_PERMISSIONS}
    {grouprow.extensionrow.EXTENSION}{grouprow.extensionrow.EXPLANATION}      
    + +
    + +
    + + + + + + + +

    {L_GROUP_PERMISSIONS_TITLE}

    + +

    {L_GROUP_PERMISSIONS_EXPLAIN}

    +
    + + + + + + + +
    +
    + + + + + + + + + + +
    {L_ALLOWED_FORUMS}
    + +
     
    +
    +
    +
    + + + + + + + + + + +
    {L_ADD_FORUMS}
    + +
       
    +
    +
    + + + + +
    + diff --git a/upload/templates/admin/admin_forum_prune.tpl b/upload/templates/admin/admin_forum_prune.tpl new file mode 100644 index 000000000..f00b4e64c --- /dev/null +++ b/upload/templates/admin/admin_forum_prune.tpl @@ -0,0 +1,51 @@ + +

    {L_FORUM_PRUNE}

    + + +

    {L_PRUNE_EXPLAIN}

    + + + +

    {L_FORUM}: {FORUM_NAME}

    + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_FORUM}{L_TOPICS_PRUNED}
    {pruned.FORUM_NAME}{pruned.PRUNED_TOPICS}
    {L_PRUNE_RESULT}
    {L_FORUM_PRUNE}
    {SEL_FORUM}
    +

    {L_PRUNE_TOPICS} {L_DAYS}

    +

    +
    + +
    + +
    \ No newline at end of file diff --git a/upload/templates/admin/admin_forumauth.tpl b/upload/templates/admin/admin_forumauth.tpl new file mode 100644 index 000000000..3ba6e9117 --- /dev/null +++ b/upload/templates/admin/admin_forumauth.tpl @@ -0,0 +1,68 @@ +

    {L_AUTH_TITLE}

    + +

    {L_AUTH_EXPLAIN}

    +
    + + + + +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + +
    {L_AUTH_SELECT}
    +

    {S_AUTH_SELECT}

    +

    +

    + +
    + +



    + + + + + + +

    {L_FORUM}: {FORUM_NAME}

    + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + +
    {L_AUTH_TITLE}
    {forum_auth.CELL_TITLE}{forum_auth.S_AUTH_LEVELS_SELECT}
    {U_SWITCH_MODE}
    +    + +
    + +
    + + + + + diff --git a/upload/templates/admin/admin_forumauth_list.tpl b/upload/templates/admin/admin_forumauth_list.tpl new file mode 100644 index 000000000..55404bd40 --- /dev/null +++ b/upload/templates/admin/admin_forumauth_list.tpl @@ -0,0 +1,94 @@ + + + + +

    {L_AUTH_TITLE}

    + +

    {L_AUTH_EXPLAIN}

    +
    + + + + + + + + + + + + + + + + + + + + + +
    {L_FORUM_NAME}{forum_auth_titles.CELL_TITLE}
    {cat_row.CAT_NAME}
    {cat_row.forum_row.FORUM_NAME}{cat_row.forum_row.forum_auth_data.CELL_VALUE}
    +
    + + + + + + + +

    {L_AUTH_TITLE}

    + +

    {L_AUTH_EXPLAIN}

    + +

    {L_CATEGORY} : {CAT_NAME}

    + + + + + + + + + + + + + + + + + + + + + +
    {L_FORUM_NAME}{forum_auth_titles.CELL_TITLE}
    {cat_row.CAT_NAME}
    {cat_row.forum_row.FORUM_NAME}{cat_row.forum_row.forum_auth_data.CELL_VALUE}
    +
    + +
    + + + + + + + + + + + + + + + + +
     {forum_auth_titles.CELL_TITLE}
    {CAT_NAME}{forum_auth_data.S_AUTH_LEVELS_SELECT}
    {S_HIDDEN_FIELDS} + +    + +
    +
    + + + + diff --git a/upload/templates/admin/admin_forums.tpl b/upload/templates/admin/admin_forums.tpl new file mode 100644 index 000000000..a5b1a898c --- /dev/null +++ b/upload/templates/admin/admin_forums.tpl @@ -0,0 +1,234 @@ + + + + + + +

    {L_FORUM_TITLE}

    + +

    {L_FORUM_EXPLAIN}

    +
    + +
    +{S_HIDDEN_FIELDS} +{SID_HIDDEN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_FORUM_SETTINGS}
    {L_FORUM_NAME}
    {L_FORUM_DESCRIPTION}
    {L_PARENT_FORUM}
    {L_CATEGORY}
    {L_SHOW_ON_INDEX}
    {L_FORUM_STATUS}
    {L_AUTO_PRUNE} + + + + + + + + + +
    {L_ENABLED}
    {L_PRUNE_DAYS}  {L_DAYS}
    {L_SORT_BY} +   +   +
    +
    + + + + + + + +

    {L_EDIT_CAT}

    + +

    {L_EDIT_CAT_EXPL}

    +
    + +
    +{S_HIDDEN_FIELDS} +{SID_HIDDEN} + + ++ + + + + + +
    {L_EDIT_CAT}
    + {L_CATEGORY}: +   + +
    + +
    + + + + + + + +

    {DELETE_TITLE}

    + +

    {L_DELETE_EXPL}

    +
    + +
    +{S_HIDDEN_FIELDS} +{SID_HIDDEN} + + +++ + + + + + + + + + + + + + + + +
    {DELETE_TITLE}
    {CAT_FORUM_NAME}{WHAT_TO_DELETE}
    {L_MOVE_CONTENTS} + + {NOWHERE_TO_MOVE} + + + +
    + +
    + +
    + + + + + + + + + + + +

    {L_FORUM_TITLE}

    + +

    {L_FORUM_EXPLAIN}

    +
    + +
    +{SID_HIDDEN} + + + + + + + + + + + + + + + + + + + +
     ↑  ↓  + + {catrow.CAT_DESC} + + + {L_CREATE_FORUM} + | + {L_EDIT} + | + {L_DELETE} + + {L_PRUNE}
     ↑  ↓ {catrow.forumrow.FORUM_NAME} {L_EDIT}  +sub  {L_RESYNC}  {L_REMOVE} {catrow.forumrow.PRUNE_DAYS}
    + + + + + + +
    + +
    + +
    +

    {L_SHOW_ALL_FORUMS_ON_ONE_PAGE}

    +
    + + + + + + diff --git a/upload/templates/admin/admin_groups.tpl b/upload/templates/admin/admin_groups.tpl new file mode 100644 index 000000000..4473c7fac --- /dev/null +++ b/upload/templates/admin/admin_groups.tpl @@ -0,0 +1,103 @@ + + + + +

    {L_GROUP_ADMINISTRATION}

    + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {T_GROUP_EDIT_DELETE}
    {L_GROUP_NAME}:
    {L_GROUP_DESCRIPTION}:
    {L_GROUP_MODERATOR}:  
    {L_GROUP_STATUS}: +
    {L_GROUP_OPEN}
    +
    {L_GROUP_CLOSED}
    +
    {L_GROUP_HIDDEN}
    +
    {L_DELETE_OLD_GROUP_MOD} + {L_YES} +
    {L_DELETE_OLD_GROUP_MOD_EXPL}
    +
    {L_GROUP_DELETE}: {L_GROUP_DELETE_CHECK}
    {L_UPLOAD_QUOTA}{S_SELECT_UPLOAD_QUOTA}
    {L_PM_QUOTA}{S_SELECT_PM_QUOTA}
    +    + +
    + +
    + + + + + + + +

    {L_GROUP_ADMINISTRATION}

    + +

    {L_GROUP_ADMIN_EXPLAIN}

    + +

    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + +
    {L_SELECT_GROUP}
    + {S_GROUP_SELECT}   +
    +
    + +



    + + + + diff --git a/upload/templates/admin/admin_log.tpl b/upload/templates/admin/admin_log.tpl new file mode 100644 index 000000000..b64f8feaa --- /dev/null +++ b/upload/templates/admin/admin_log.tpl @@ -0,0 +1,216 @@ + + + +
    + +
    + + + + + + + + + + + + + + + +
    Log actions: search options
    + + + + + + +
    +
    + Forum +
    +

    {SEL_FORUM}

    +
    +
    +
    +
    + Action +
    +

    {SEL_LOG_TYPE}

    +
    +
    +
    +
    + User +
    +

    {SEL_USERS}

    +
    +
    +
    +
    + + + + + + +
    +
    + Logs from (first: {FIRST_LOG_TIME}) +
    +

    + + & + + days back +

    +
    +
    +
    +
    + Topic title match +
    +

    +
    +
    +
    +
    + Sort by +
    +

    + + + +

    +
    +
    +
    +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    ActionUsernameTimeInfo
    {log.ACTION_DESC} + +
    {log.USER_IP}
    +
    +
    {log.TIME}
    + +
    + +
    {log.MSG}
    + + +
    + {log.TOPIC_TITLE} + + + + + » + {log.TOPIC_TITLE_NEW} + + +
    + + + + +
    {L_NO_MATCH}
    + + + +
    + + +
    + + + +
    + +
    +Filter + + + + + + + + + + + + + + +
    +

    Forums:

    +
    + +

    {forums.FORUM_NAME}

    + +
    +
    +

    Topics:

    +
    + +

    {topics.TOPIC_TITLE}

    + +
    +
    +

    Users:

    +
    + +

    {users.USERNAME}

    + +
    +
    +
    + + diff --git a/upload/templates/admin/admin_mass_email.tpl b/upload/templates/admin/admin_mass_email.tpl new file mode 100644 index 000000000..a7d9f0154 --- /dev/null +++ b/upload/templates/admin/admin_mass_email.tpl @@ -0,0 +1,30 @@ + +

    {L_EMAIL}

    + +

    {L_EMAIL_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + +
    {L_COMPOSE}
    {L_RECIPIENTS}{S_GROUP_SELECT}
    {L_EMAIL_SUBJECT}
    {L_MESSAGE} + +
    + +
    \ No newline at end of file diff --git a/upload/templates/admin/admin_ranks.tpl b/upload/templates/admin/admin_ranks.tpl new file mode 100644 index 000000000..5179eea84 --- /dev/null +++ b/upload/templates/admin/admin_ranks.tpl @@ -0,0 +1,83 @@ + + + + +

    {L_RANKS_TITLE}

    + +

    {L_RANKS_TEXT}

    +
    + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + +
    {L_RANKS_TITLE}

    {L_RANK_TITLE}

    + +

    {L_RANK_IMAGE}:

    + +

    + {IMAGE_DISPLAY} +

    +
    {L_RANK_IMAGE_EXPLAIN}
    +
    +     + +
    + +
    + + + + + + + +

    {L_RANKS_TITLE}

    + +

    {L_RANKS_TEXT}

    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    {L_RANK}Image{L_EDIT}{L_DELETE}
    {ranks.RANK}{ranks.IMAGE_DISPLAY}{L_EDIT}{L_DELETE}
    + +
    + +
    + + + diff --git a/upload/templates/admin/admin_rebuild_search.tpl b/upload/templates/admin/admin_rebuild_search.tpl new file mode 100644 index 000000000..2768fd3ca --- /dev/null +++ b/upload/templates/admin/admin_rebuild_search.tpl @@ -0,0 +1,259 @@ + + + + + + +

    {L_REBUILD_SEARCH}

    + +

    {L_REBUILD_SEARCH_DESC}

    + +
    + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_REBUILD_SEARCH}

    {L_STARTING_POST_ID}

    {L_STARTING_POST_ID_EXPLAIN}
    + + + + + + + +

    {L_CLEAR_SEARCH_TABLES}

    {L_CLEAR_SEARCH_TABLES_EXPLAIN}
    + {L_CLEAR_SEARCH_NO}  + {L_CLEAR_SEARCH_DELETE}  + {L_CLEAR_SEARCH_TRUNCATE}  +

    {L_NUM_OF_POSTS}

    {L_NUM_OF_POSTS_EXPLAIN}

    {L_POSTS_PER_CYCLE}

    {L_POSTS_PER_CYCLE_EXPLAIN}

    {L_TIME_LIMIT}

    {L_TIME_LIMIT_EXPLAIN}

    {L_REFRESH_RATE}

    {L_REFRESH_RATE_EXPLAIN}
    {LAST_SAVED_PROCESSING}
    + + +
    + +
    + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + +
    {L_REBUILD_SEARCH_PROGRESS}
    +
    {PROCESSING_POSTS}
    +
    {PROCESSING_MESSAGES}
    +
    +
    + + + + + + + + + + + + + + +
    {L_PROCESSING_POST_DETAILS}
    {L_CURRENT_SESSION} {SESSION_DETAILS} +

    {SESSION_PERCENT}

    + +
    +
    +
    + +
    {L_TOTAL} {TOTAL_DETAILS} +

    {TOTAL_PERCENT}

    + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_PROCESSING_TIME_DETAILS}
    {L_TIME_LAST_POSTS_ADMIN} {LAST_CYCLE_TIME}{L_TIME_BEGINNING} {SESSION_TIME}
    {L_TIME_AVERAGE} {SESSION_AVERAGE_CYCLE_TIME}{L_TIME_ESTIMATED} {SESSION_ESTIMATED_TIME}
    {L_SIZE_SEARCH_TABLES} {SEARCH_TABLES_SIZE}Data size {SEARCH_DATA_SIZE}
    {L_SIZE_ESTIMATED} {FINAL_SEARCH_TABLES_SIZE}Index size {SEARCH_INDEX_SIZE}
    + {L_STARTING_POST_ID}: {START_POST}, + {L_POSTS_LAST_CYCLE}: {POST_LIMIT}, + {L_TIME_LIMIT}: {TIME_LIMIT} +
    + +
    {L_ESTIMATED_VALUES}
    +   + +     + + + +
    + +
    + + + + diff --git a/upload/templates/admin/admin_smilies.tpl b/upload/templates/admin/admin_smilies.tpl new file mode 100644 index 000000000..c169cc996 --- /dev/null +++ b/upload/templates/admin/admin_smilies.tpl @@ -0,0 +1,118 @@ + + + + +

    {L_SMILEY_TITLE}

    + +

    {L_SMILEY_TEXT}

    +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + + + + + + +
    {L_CODE}{L_SMILE}{L_EMOT}{L_ACTION}
    {smiles.CODE}{smiles.CODE}{smiles.EMOT}{L_EDIT}{L_DELETE}
        
    + +
    + + + + + + + +

    {L_SMILEY_TITLE}

    + +

    {L_SMILEY_EXPLAIN}

    +
    + + + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + + + + + + +
    {L_SMILEY_CONFIG}
    {L_SMILEY_CODE}
    {L_SMILEY_URL}    
    {L_SMILEY_EMOTION}
    + +
    + + + + + + + +

    {L_SMILEY_TITLE}

    + +

    {L_SMILEY_EXPLAIN}

    +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + + + + + +
    {L_SMILEY_IMPORT}
    {L_SELECT_LBL}{S_SMILE_SELECT}
    {L_DEL_EXISTING}
    {L_CONFLICTS}
    {L_REPLACE_EXISTING}   {L_KEEP_EXISTING}
    + +
    + + + + diff --git a/upload/templates/admin/admin_topic_templates.tpl b/upload/templates/admin/admin_topic_templates.tpl new file mode 100644 index 000000000..1c968a9cf --- /dev/null +++ b/upload/templates/admin/admin_topic_templates.tpl @@ -0,0 +1,28 @@ +

    {L_ADMIN_TITLE}

    + +

    {L_ADMIN_TEXT}

    +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + +
    {L_FORUM}{L_TEMPLATE}
    {forum.FORUM_NAME}{forum.TPL_SELECT}
    +    + +
    + +
    diff --git a/upload/templates/admin/admin_ug_auth.tpl b/upload/templates/admin/admin_ug_auth.tpl new file mode 100644 index 000000000..1d0ce49dc --- /dev/null +++ b/upload/templates/admin/admin_ug_auth.tpl @@ -0,0 +1,332 @@ + + + + + + +
    +{S_HIDDEN_FIELDS} + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_FORUM}{L_MODERATOR_STATUS}{acltype.ACL_TYPE_NAME}
    + +
      {c.CAT_TITLE}
    {c.f.SF_SPACER}{c.f.FORUM_NAME}
    {c.f.SF_SPACER}{c.f.FORUM_NAME}
    + onclick="flip_mod('{c.f.FORUM_ID}', '{AUTH_MOD_BF}');" + + onmouseover="hl('{c.f.FORUM_ID}', '{AUTH_MOD_BF}', 1);" + onmouseout="hl('{c.f.FORUM_ID}', '{AUTH_MOD_BF}', 0);" + class="{c.f.MOD_CLASS}">{c.f.MOD_STATUS} + onclick="flip_perm('{c.f.acl.FORUM_ID}', '{c.f.acl.ACL_TYPE_BF}');" + + onmouseover="hl('{c.f.acl.FORUM_ID}', '{c.f.acl.ACL_TYPE_BF}', 1);" + onmouseout="hl('{c.f.acl.FORUM_ID}', '{c.f.acl.ACL_TYPE_BF}', 0);" + class="{c.f.acl.ACL_CLASS}Disabled">{c.f.acl.PERM_SIGN}
    + +
    + +
    +

    {L_SHOW_ALL_FORUMS_ON_ONE_PAGE}

    +
    + + + +disabled="disabled" /> + +disabled="disabled" /> + + + + + +
    + +
    +{S_HIDDEN_FIELDS} + +

    {L_PERMISSIONS} ({T_AUTH_TITLE})

    +

    {T_USER_OR_GROUPNAME}: {USER_OR_GROUPNAME}

    +{USER_LEVEL}   +

    {T_AUTH_EXPLAIN}

    + +
    + + + + + + + + + +

    {L_USER_ADMIN}

    + +

    {L_USER_AUTH_EXPLAIN}

    +

    + +
    + +{S_HIDDEN_FIELDS} + + + + + + + + +
    {L_USER_SELECT}
    +

    + + +

    +

    + +

    +
    + +
    + +



    + + + + + + + +

    {L_GROUP_ADMINISTRATION}

    + +

    {L_GROUP_AUTH_EXPLAIN}

    +

    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + +
    {L_GROUP_SELECT}
    +  {S_GROUP_SELECT}  +   +
    + +
    + +



    + + + + diff --git a/upload/templates/admin/admin_user_ban.tpl b/upload/templates/admin/admin_user_ban.tpl new file mode 100644 index 000000000..db5c28b38 --- /dev/null +++ b/upload/templates/admin/admin_user_ban.tpl @@ -0,0 +1,59 @@ + +

    {L_BAN_TITLE}

    + +

    {L_BAN_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_BAN_USER}
    {L_USERNAME}: {S_HIDDEN_FIELDS}
    {L_UNBAN_USER}
    {L_USERNAME}:
    {L_UNBAN_USER_EXPLAIN}
    {S_UNBAN_USERLIST_SELECT}
    {L_BAN_IP}
    {L_IP_OR_HOSTNAME}:
    {L_BAN_IP_EXPLAIN}
    {L_UNBAN_IP}
    {L_IP_OR_HOSTNAME}:
    {L_UNBAN_IP_EXPLAIN}
    {S_UNBAN_IPLIST_SELECT}
    {L_BAN_EMAIL}
    {L_EMAIL_ADDRESS}:
    {L_BAN_EMAIL_EXPLAIN}
    {L_UNBAN_EMAIL}
    {L_EMAIL_ADDRESS}:
    {L_UNBAN_EMAIL_EXPLAIN}
    {S_UNBAN_EMAILLIST_SELECT}
      
    + +
    + +

    {L_BAN_EXPLAIN_WARN}

    \ No newline at end of file diff --git a/upload/templates/admin/admin_user_search.tpl b/upload/templates/admin/admin_user_search.tpl new file mode 100644 index 000000000..a33fba53b --- /dev/null +++ b/upload/templates/admin/admin_user_search.tpl @@ -0,0 +1,204 @@ + + + + +

    {L_USER_SEARCH}

    + +

    {L_SEARCH_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    {L_USERNAME}:   {L_REGEX}
    {L_USERNAME_EXPLAIN}
    .
    {L_EMAIL}:   {L_REGEX}
    {L_EMAIL_EXPLAIN}
    .
    {L_IP}:  
    {L_IP_EXPLAIN}
    .
    {L_USERS_JOINED}  // 
    {L_JOIN_DATE_EXPLAIN}
    .
    {L_GROUP_MEMBERS}:  
    {L_SEARCH_USERS_GROUPS_EXPLAIN}
    .
    {L_POSTER_RANK}:  
    {L_SEARCH_USERS_RANKS_EXPLAIN}
    .
    {L_POSTCOUNT}   
    {L_POSTCOUNT_EXPLAIN}
    .
    {L_USERFIELD}:    {L_REGEX}
    {L_USERFIELD_EXPLAIN}
    .
    {L_LASTVISITED}   
    {L_LASTVISITED_EXPLAIN}
    .
    {L_LANGUAGE}: {LANGUAGE_LIST} 
    {L_LANGUAGE_EXPLAIN}
    .
    {L_TIMEZONE}: {TIMEZONE_LIST} 
    {L_TIMEZONE_EXPLAIN}
    .
    {L_MODERATORS_OF}:  
    {L_MODERATORS_OF_EXPLAIN}
    .
     
    {L_MISC_EXPLAIN}
    .
    +
    + + + + + + + +

    {L_USER_SEARCH}

    + +

    {NEW_SEARCH}

    +
    + +
    + + + + +
    +

     

    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_USERNAME}{L_EMAIL}{L_JOINDATE}{L_POSTS}{L_LASTVISIT}   {L_ACCOUNT_STATUS}
     {userrow.USERNAME}  {userrow.EMAIL}  {userrow.JOINDATE}  {userrow.POSTS}  {userrow.LASTVISIT}  {L_MANAGE}  {L_PERMISSIONS}  {userrow.BAN}  {userrow.ABLED} 
    .
    + + + + +
    +
    + + + + diff --git a/upload/templates/admin/admin_users.tpl b/upload/templates/admin/admin_users.tpl new file mode 100644 index 000000000..47fad995d --- /dev/null +++ b/upload/templates/admin/admin_users.tpl @@ -0,0 +1,369 @@ + + + + +

    {L_USER_ADMIN}

    + +

    {L_USER_EXPLAIN}

    +

    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + +
    {L_USER_SELECT}
    +

    + + +

    +

    + +

    +
    + +
    + +



    + + + + + + + +

    {L_USER_ADMIN}

    + +

    {L_USER_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_REGISTRATION_INFO}
    {L_ITEMS_REQUIRED}
    {L_USERNAME}: * + +
    {L_EMAIL_ADDRESS}: * + +
    {L_NEW_PASSWORD}: *
    + {L_PASSWORD_IF_CHANGED}
    + +
    {L_CONFIRM_PASSWORD}: *
    + {L_PASSWORD_CONFIRM_IF_CHANGED}
    + +
     
    {L_PROFILE_INFO}
    {L_PROFILE_INFO_NOTICE}
    {L_ICQ} + +
    {L_WEBSITE} + +
    {L_LOCATION} + +
    {L_FLAG}: + + + + +
    {FLAG_SELECT}    
    +
    {L_OCCUPATION} + +
    {L_INTERESTS} + +
    {L_SIGNATURE}
    + {L_SIGNATURE_EXP}
    +
    + {BBCODE_STATUS}
    + {SMILIES_STATUS}
    + +
     
    {L_PREFERENCES}
    {L_PUBLIC_VIEW_EMAIL} + + {L_YES}   + + {L_NO}
    {L_HIDE_USER} + + {L_YES}   + + {L_NO}
    {L_NOTIFY_ON_REPLY} + + {L_YES}   + + {L_NO}
    {L_NOTIFY_ON_PRIVMSG} + + {L_YES}   + + {L_NO}
    {L_ALWAYS_ADD_SIGNATURE} + + {L_YES}   + + {L_NO}
    {L_BOARD_LANGUAGE}{LANGUAGE_SELECT}
    {L_TIMEZONE}{TIMEZONE_SELECT}
    {L_DATE_FORMAT}
    + {L_DATE_FORMAT_EXPLAIN}
    + +
     
    {L_AVATAR_PANEL}
    + + + + + +
    {L_AVATAR_EXP}{L_CURRENT_IMAGE}
    + {ADMIN_AVATAR}
    + +  {L_DELETE_AVATAR}
    +
    {L_UPLOAD_AVATAR_FILE} + + +
    {L_UPLOAD_AVATAR_URL} + +
    {L_LINK_REMOTE_AVATAR} + +
    {L_AVATAR_GALLERY} + +
     
    {L_SPECIAL}
    {L_SPECIAL_EXPLAIN}
    {L_UPLOAD_QUOTA}{S_SELECT_UPLOAD_QUOTA}
    {L_PM_QUOTA}{S_SELECT_PM_QUOTA}
    {L_USER_ACTIVE} + + {L_YES}   + + {L_NO}
    {L_ALLOW_PM} + + {L_YES}   + + {L_NO}
    {L_ALLOW_AVATAR} + + {L_YES}   + + {L_NO}
    {L_SELECT_RANK}
    {L_DELETE_USER}? +
    + + {L_DELETE_USER_EXPLAIN} +
    +
    + + {L_DELETE_USER_POSTS} +
    +
    {S_HIDDEN_FIELDS} + +    + +
    + + + + + + + +

    {L_USER_ADMIN}

    + +

    {L_USER_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_AVATAR_GALLERY}
    {L_SELECT_CATEGORY}:  
    {S_HIDDEN_FIELDS} + +    + +
    +
    + + + + diff --git a/upload/templates/admin/admin_words.tpl b/upload/templates/admin/admin_words.tpl new file mode 100644 index 000000000..5857731da --- /dev/null +++ b/upload/templates/admin/admin_words.tpl @@ -0,0 +1,63 @@ + + + + +

    {L_WORDS_TITLE}

    + +

    {L_WORDS_TEXT}

    +
    + +
    + + + + + + + + + + + + + + + + + + +
    {L_WORD}{L_REPLACEMENT}{L_ACTION}
    {words.WORD}{words.REPLACEMENT}{L_EDIT}{L_DELETE}
    {S_HIDDEN_FIELDS}
    + + + + + + + +

    {L_WORDS_TITLE}

    + +

    {L_WORDS_TEXT}

    +
    + +
    + + + + + + + + + + + + + + + + +
    {L_WORD_CENSOR}
    {L_WORD}
    {L_REPLACEMENT}
    {S_HIDDEN_FIELDS}
    + + + + diff --git a/upload/templates/admin/index.tpl b/upload/templates/admin/index.tpl new file mode 100644 index 000000000..52e27afc3 --- /dev/null +++ b/upload/templates/admin/index.tpl @@ -0,0 +1,178 @@ + + + + + + + + + Administration + + + + + + + + + <body bgcolor="#FFFFFF" text="#000000"> + <p>Sorry, your browser doesn't seem to support frames</p> + </body> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_ADMIN}
    {L_ADMIN_INDEX}
    {L_MAIN_INDEX}
    {catrow.ADMIN_CATEGORY}
    {catrow.modulerow.ADMIN_MODULE}
    + + + + + + + +
    + + + + + + + + + + + + + +
    {L_CLEAR_CACHE}: + {L_DATASTORE},  + {L_TEMPLATES}  +
    {L_UPDATE}: + {L_USER_LEVELS}  +
    {L_SYNCHRONIZE}: + {L_TOPICS},  + {L_USER_POSTS_COUNT}  +
    +
    + + + + + + + + + + + + + +
    {L_VERSION_INFORMATION}
    {L_TP_VERSION}:{$bb_cfg['tp_version']} ({$bb_cfg['tp_release_state']})
    {L_TP_RELEASE_DATE}:{$bb_cfg['tp_release_date']}
    +

    {L_FORUM_STATS}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_STATISTIC}{L_VALUE}{L_STATISTIC}{L_VALUE}
    {L_NUMBER_POSTS}:{NUMBER_OF_POSTS}{L_POSTS_PER_DAY}:{POSTS_PER_DAY}
    {L_NUMBER_TOPICS}:{NUMBER_OF_TOPICS}{L_TOPICS_PER_DAY}:{TOPICS_PER_DAY}
    {L_NUMBER_USERS}:{NUMBER_OF_USERS}{L_USERS_PER_DAY}:{USERS_PER_DAY}
    {L_BOARD_STARTED}:{START_DATE}{L_AVATAR_DIR_SIZE}:{AVATAR_DIR_SIZE}
    {L_DB_SIZE}:{DB_SIZE}{L_GZIP_COMPRESSION}:{GZIP_COMPRESSION}
    + + +

    {L_WHOSONLINE}

    + + + + + + + + + + + + + + + + + + + + + + + + + +
     {L_USERNAME}  {L_LOGIN}
    {L_LAST_UPDATE} 
     {L_IP_ADDRESS} 
     {reg_user_row.USERNAME}  {reg_user_row.STARTED}-{reg_user_row.LASTUPDATE}  {reg_user_row.IP_ADDRESS} 
    .
     {guest_user_row.USERNAME}  {guest_user_row.STARTED}-{guest_user_row.LASTUPDATE}  {guest_user_row.IP_ADDRESS} 
    + +{L_WHOSONLINE} + + + + + diff --git a/upload/templates/board_disabled_exit.php b/upload/templates/board_disabled_exit.php new file mode 100644 index 000000000..7c93d5468 --- /dev/null +++ b/upload/templates/board_disabled_exit.php @@ -0,0 +1,49 @@ + + + + + + <?php echo $bb_cfg['sitename']?> + + + + +
    + +
    +
    +

    + + +
    +
    +

    ваше сообщение не было отправлено:

    + + + +
    + + + + + \ No newline at end of file diff --git a/upload/templates/default/agreement.tpl b/upload/templates/default/agreement.tpl new file mode 100644 index 000000000..4a6083ee3 --- /dev/null +++ b/upload/templates/default/agreement.tpl @@ -0,0 +1,27 @@ + +

    Регистрация

    + + + + + + + + +
    {$bb_cfg['sitename']} - Условия регистрации
    + +
    + + diff --git a/upload/templates/default/attach_rules.tpl b/upload/templates/default/attach_rules.tpl new file mode 100644 index 000000000..d9c0ca1f7 --- /dev/null +++ b/upload/templates/default/attach_rules.tpl @@ -0,0 +1,24 @@ +
    + + + + + + + + + + + + + + + +
    {L_RULES_TITLE}
    {L_EMPTY_GROUP_PERMS}
    +

    {group_row.GROUP_RULE_HEADER}

    +

    + + {group_row.extension_row.EXTENSION}  + +

    +
    \ No newline at end of file diff --git a/upload/templates/default/bbcode.tpl b/upload/templates/default/bbcode.tpl new file mode 100644 index 000000000..7a5960c69 --- /dev/null +++ b/upload/templates/default/bbcode.tpl @@ -0,0 +1,87 @@ +
      +
    + +
      +
    + +
  • + + +
    +

    {USERNAME} {L_WROTE}:

    +
    + + + +
    +

    {L_QUOTE}:

    +
    + + + +
    +
    +
    + + + +
    +
    +

    {L_CODE}:

    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +{DESCRIPTION} + +{EMAIL} \ No newline at end of file diff --git a/upload/templates/default/common.tpl b/upload/templates/default/common.tpl new file mode 100644 index 000000000..a3462dbf8 --- /dev/null +++ b/upload/templates/default/common.tpl @@ -0,0 +1,50 @@ + + + +

    + + + + +
    {MESSAGE_TITLE}
    {MESSAGE_TEXT}
    + +

    + + + + + + + +
    + {HIDDEN_FIELDS} + +
    + + + + + + + + +
    {CONFIRM_TITLE}
    +

    {QUESTION}

    + + + +
    +
    • {ITEMS_LIST}
    +
    + +
    +   + +
    +
    + +
    +
    + + + \ No newline at end of file diff --git a/upload/templates/default/confirm_body.tpl b/upload/templates/default/confirm_body.tpl new file mode 100644 index 000000000..285022b40 --- /dev/null +++ b/upload/templates/default/confirm_body.tpl @@ -0,0 +1,10 @@ + + + + + + + +
    {MESSAGE_TITLE}

    {MESSAGE_TEXT}

    {S_HIDDEN_FIELDS}  
    + +
    \ No newline at end of file diff --git a/upload/templates/default/css/admin.css b/upload/templates/default/css/admin.css new file mode 100644 index 000000000..03bb98b79 --- /dev/null +++ b/upload/templates/default/css/admin.css @@ -0,0 +1,8 @@ + +body { background: #E5E5E5; min-width: 10px; } +#body_container { background: #E5E5E5; padding: 0 6px 4px; } +h1, h2, h3 { margin: 0.8em 0; font-size: 16px; } +h4 { margin: 0.1em 0.2em; color: #273F61; font-size: 11px; font-weight: bold; } +h5 { margin: 0.1em 0.6em; color: #333399; font-family: "Courier New"; } +h6 { margin: 0.3em 0.6em; color: #444444; line-height: 100%; } +* html table.forumline { width: 97%; } diff --git a/upload/templates/default/css/backup/admin.css b/upload/templates/default/css/backup/admin.css new file mode 100644 index 000000000..03bb98b79 --- /dev/null +++ b/upload/templates/default/css/backup/admin.css @@ -0,0 +1,8 @@ + +body { background: #E5E5E5; min-width: 10px; } +#body_container { background: #E5E5E5; padding: 0 6px 4px; } +h1, h2, h3 { margin: 0.8em 0; font-size: 16px; } +h4 { margin: 0.1em 0.2em; color: #273F61; font-size: 11px; font-weight: bold; } +h5 { margin: 0.1em 0.6em; color: #333399; font-family: "Courier New"; } +h6 { margin: 0.3em 0.6em; color: #444444; line-height: 100%; } +* html table.forumline { width: 97%; } diff --git a/upload/templates/default/css/backup/dbg.css b/upload/templates/default/css/backup/dbg.css new file mode 100644 index 000000000..89ef3ce24 --- /dev/null +++ b/upload/templates/default/css/backup/dbg.css @@ -0,0 +1,31 @@ +/* dbg */ +.b1 { border: 1px solid #000 !important; } +.b2 { border: 1px solid #f00 !important; } +.b3 { border: 1px solid #00f !important; } + +.bg1 { background: #FAEBD7 !important; } +.bg2 { background: #A52A2A !important; } +.bg3 { background: #E9967A !important; } + +/* ------------------------------------------------------------------- +ERROR CHECKING +This is to determine if deprecated elements are used. If so, they should be replaced: +1a. and +1b. ...: Shouldn't be used. CSS should dictate font attributes. +2.
    : Shouldn't be used. CSS should dictate horizontal alignment. +3a.
    ...
    +3b.

    ...

    +3c. ...
    : +Shouldn't be used. CSS should dictate horizontal alignment. + +font, center, div[align], p[align], table[align], font[color] +{ + color : #cd0000; + font-weight : bold; + background : #eecc11 url(images/warning.gif) repeat 0 0; + margin : 10px; + padding : 10px; + border : 2px dashed #cd0000; + font-size : 2em; +} +------------------------------------------------------------------- */ \ No newline at end of file diff --git a/upload/templates/default/css/backup/index.html b/upload/templates/default/css/backup/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/upload/templates/default/css/backup/main.css b/upload/templates/default/css/backup/main.css new file mode 100644 index 000000000..1ed55c7cc --- /dev/null +++ b/upload/templates/default/css/backup/main.css @@ -0,0 +1,875 @@ +/* + * Initial neutralization + * Top Level + * Globals + + * Links + * Backgrounds + * Headers + * General text + + * Code blocks + * Quote blocks + * Spoiler + + ? Infoboxes + * Inputs, buttons, forms + * Text replacement for buttons + * Basic tables + + * Page header + - TopMenu + - Logo + - Main navigation + - Quick Login, PM Info, Loguot.. + ? Breadcrumb + ? Important info + + * Latest News + * Sidebar 1 + + * Forums on home page + * Forums on viewforum page + + * Topics on viewtopic page + * Attachments + * Search Results page + * Tracker + + * Images + * Page footer + * Menus + * Misc + * Shortcuts +*/ + +/* ================================================================ * + Initial neutralization + * ================================================================ */ + +/* Clean out MARGIN and PADDING */ +html, body, form, fieldset, h3, h4, h5, h6, p, pre, blockquote, +ul, ol, dl, li, dd { + margin: 0; padding: 0; +} +/* Add LEFT MARGIN */ +blockquote, ul, ol, li, dd { margin-left: 1em; } + +/* ================================================================ * + Top Level + * ================================================================ */ +html { + min-height: 100.1%; /* always show vertical scrollbar in Mozilla */ +} +body { + min-width: 760px; color: #000000; background: #E3E3E3; +} +body, th, td, font { + font: 12px Verdana,Arial,sans-serif; +} + +#body_container { background: #E3E3E3; padding: 0 2px 4px; } + #page_container { + margin: 0 auto; + background: #FFFFFF; border: 1px solid #D1D7DC; + } + #page_header { + position: relative; width: 100%; + } + #page_content { + padding: 12px 4px 0; margin: 0 auto; + clear: both; position: relative; + } + #sidebar1 { + padding: 0 6px 0 3px; vertical-align: top; + width: 210px; + } + #sidebar2 { + padding: 0 3px 0 6px; vertical-align: top; + width: 240px; + } + #sidebar1-wrap {} + #sidebar2-wrap {} + #main_content { + vertical-align: top; + } + #main_content_wrap {} + #page_footer { + clear: both; + margin: 12px 0 3px; + } + +/* ================================================================ * + Globals + * ================================================================ */ +hr { height: 0px; border: 0px solid #B7C0C5; border-top-width: 1px; } +.hr1 { border-top: 1px #B7C0C5 solid; } + +form { display: inline; } +label { cursor: pointer; white-space: nowrap; } +img { border: 0px; } + +.highlight { color: #FF0000; background: #FFFFE0; } +/* ---------------------------------- * + Links + * ---------------------------------- */ +:link:focus, :visited:focus { color: #DD6900; } +:link { color: #006699; } +:visited { color: #006699; } +:link:hover, :visited:hover { color: #DD6900; text-decoration: underline !important; } +:link:active, :visited:active { color: #DD6900; text-decoration: underline !important; } + +.colorAdmin, a.colorAdmin, a.colorAdmin:visited { color: #FF8C24; } +.colorMod, a.colorMod, a.colorMod:visited { color: #008000; } +.colorGroup, a.colorGroup, a.colorGroup:visited { color: #476996; } + +.dlWill { color: #0066CC; } +.dlDown, .leech, .leechmed, .leechsmall { color: #800000; } +.dlComplete, .seed, .seedmed, .seedsmall { color: #006600; } +.dlCancel { color: #666666; } + +a.dlWill, a.dlWill:visited { color: #0066CC; text-decoration: none; } +a.dlDown, a.dlDown:visited { color: #800000; text-decoration: none; } +a.dlComplete, a.dlComplete:visited { color: #006600; text-decoration: none; } +a.dlCancel, a.dlCancel:visited { color: #666666; text-decoration: none; } + +a.leech, a.leechmed, a.leechsmall, +a.leech:visited, a.leechmed:visited, a.leechsmall:visited +{ + color: #800000; text-decoration: none; +} +a.seed, a.seedmed, a.seedsmall, +a.seed:visited, a.seedmed:visited, a.seedsmall:visited +{ + color: #006600; text-decoration: none; +} +/* Poster name in viewtopic */ +.nick, .nick a { + color: #005A88 !important; font-size: 13px; font-weight: bold; text-decoration: none; +} +/* Nav links */ +.nav { margin: 0.3em 0; font-size: 11px; font-weight: bold; } +.nav a { text-decoration: none; } +.nav em { color: #660000; font-style: normal; } +/* Topic titles */ +.topictitle, a.topictitle { + font-size: 11px; text-decoration: none; font-weight: bold; +} +.torTopic, a.torTopic { + font-size: 11px; text-decoration: none; +} +a.topictitle:visited { color: #5493B4; } +a.torTopic:visited { color: #5493B4; } +/* ---------------------------------- * + Backgrounds + * ---------------------------------- */ +.row1, .row1 td { background: #EFEFEF; } +.row2, .row2 td { background: #DEE3E7; } +.row3, .row3 td { background: #D1D7DC; } +.row4, .row4 td { background: #ECECEC; } +.row5, .row5 td { background: #E7E7E7; } +.row6, .row6 td { background: #E9E9E6; } + +.prow1 { background: #ECECEC; } +.prow2 { background: #E7E7E7; } +.prow3 { background: #DEE3E7; } +/* ---------------------------------- * + Headers + * ---------------------------------- */ +h1 { font-size: 18px; font-weight: bold; margin: 0.2em 0 0.5em; } +h2 { font-size: 16px; font-weight: bold; margin: 0.2em 0 0.5em; } +h3 { font-size: 13px; font-weight: bold; letter-spacing: 1px; } +h4 { font-size: 12px; font-weight: bold; } +h5 { font-size: 12px; font-weight: normal; } +h6 { font-size: 11px; font-weight: normal; } +/* Page title and toptic title */ +.maintitle, .pagetitle { + font-family: "Trebuchet MS",Verdana,sans-serif; color: #3C3C3C; + padding: 0 4px; margin: 0.2em 0 0.5em; +} +.maintitle a, .pagetitle a { text-decoration: none; } +.maintitle { font-size: 22px; } +/* ---------------------------------- * + General text + * ---------------------------------- */ +.gen, .seed, .leech, +.gen td { font-size: 12px; } +.med, .genmed, .seedmed, .leechmed, +.med td { font-size: 11px; } +.small, .gensmall, .seedsmall, .leechsmall, +.small td { font-size: 10px; } +.tiny, .tiny td { font-size: 10px; letter-spacing: -1px; } + +td.gen { font-size: 12px !important; } +td.med { font-size: 11px !important; } +td.small { font-size: 10px !important; } + +.gen, .med, .genmed, +.small, .gensmall { color: #000000; } +a.gen, a.med, a.genmed, +a.small, a.gensmall { color: #006699; text-decoration: none; } +/* ---------------------------------- * + Code blocks + * ---------------------------------- */ +.code_wrap { width: 95%; margin: 0 auto; clear: both; } +.code_head p { font-size: 11px; padding: 2px 0 1px; } +.code { + font-size: 13px; font-family: "Courier New",Courier,monospace; + padding: 1px 6px 2px; border: 1px solid #C3CBD1; clear: both; + color: #006600; background: #FAFAFA; +} +/* ---------------------------------- * + Quote blocks + * ---------------------------------- */ +.q_wrap { width: 95%; margin: 0 auto 6px; clear: both; } +.q_wrap .q_wrap { width: 95%; } + +.q_head { font-size: 11px; padding: 2px 0 1px; color: #444444; } +.q { padding: 1px 6px 2px; color: #444444; border: solid #C3CBD1; border-width: 1px 1px 1px 2px; } + +.q { background: #FAFAFA; } +.q .q { background: #F5F5F5; } +.q .q .q { background: #FAFAFA; } +.q .q .q .q { background: #F5F5F5; } +.q .q .q .q .q { background: #FAFAFA; } +.q .q .q .q .q .q { background: #F5F5F5; } +.q .q .q .q .q .q .q { background: #FAFAFA; } +/* ---------------------------------- * + Spoiler + * ---------------------------------- */ +.spoiler-wrap { + width: 95%; margin: 6px auto; clear: both; background: #E9E9E6; + border: solid #C3CBD1; border-width: 1px 1px 1px 2px; +} +.spoiler-head { + font-size: 11px; padding: 1px 14px 3px; margin-left: 6px; line-height: 15px; +} +.spoiler-body { + padding: 1px 6px 2px; display: none; + border-top: 1px solid #C3CBD1; background: #F5F5F5; +} +/* ---------------------------------- * + Infoboxes + * ---------------------------------- */ +.infobox { + border: 1px #B7C0C5 solid; background: #EFEFEF; padding: 1px; + } + .infobox h1 { + background: #D1D7DC; font-size: 1.2em; padding: 0px 0.6em 2px; + } +/* ---------------------------------- * + Inputs, buttons, forms + * ---------------------------------- */ +input, textarea, select { + font-family: Verdana,sans-serif; +} +input.post, textarea.post { } + +select, input { font-size: 11px; } +textarea { font-size: 12px; } + +input.mainoption, input.main, +input.liteoption, input.lite { + font-size: 11px; border: 1px solid; background: #FAFAFA; + padding-left: 10px; padding-right: 10px; +} +input.mainoption, input.main { + font-weight: bold; /* main submit button */ +} + +/* The buttons used for bbCode styling in message post */ +input.button, .buttons input { border: 1px solid; background: #F5F5F5; } +input.long { padding-left: 20px; padding-right: 20px; } + +input.button, .buttons input, +input.mainoption, input.main, input.liteoption, input.lite { + border-color: #B4B4B4 #000000 #000000 #B4B4B4; +} + +input[type="checkbox"] { margin-bottom: 1px; } +input[type="radio"] { margin-bottom: -2px; } + +input[disabled="disabled"] { color: #808080; } +input.hint { color: #999999; font-style: italic; text-indent: 0.3em; } +input.error { color: #FF0000; font-weight: bold; } +input.found { font-weight: bold; } +.cat input[type="text"] { background: #FCFCFC; } + +optgroup, option, fieldset, legend { + font-family: Verdana,sans-serif; +} +optgroup { + font-size: 11px; letter-spacing: 0px; font-weight: bold; font-style: italic; + color: #005A88; background: #DEE3E7; border-top: 1px solid #A5AFB4; +} +optgroup option { color: #000000; background: #FFFFFF; } +option { font-size: 11px; } +legend { padding: 0 2px 2px; font-size: 11px; color: #000066; } +legend a { text-decoration: none; } +fieldset > legend { margin-left: 6px; } +.root_forum {} +.has_sf { color: #333333; background: #F5F5F5; font-weight: bold; } + +input.pOrdSel { + border: 0px solid #EFEFEF; width: 18px; overflow: hidden; + color: #333333; background: transparent; + font-size: 12px; font-family: Arial,sans-serif; + cursor: pointer; +} + +textarea.editor { display: block; width: 98%; } + +.fieldsets td { vertical-align: top; white-space: nowrap; } +.fieldsets fieldset { margin: 4px 4px; } +.fieldsets fieldset div { padding: 3px 6px 4px; } +.fieldsets div p { margin-bottom: 1px; } +.fieldsets div > p { margin-bottom: 2px; } +.fieldsets .select { margin-bottom: 3px; } +.fieldsets .radio {} +.fieldsets .chbox {} +.fieldsets .input {} +table.my_downloads { margin-bottom: 2px; } + .my_downloads td { padding: 1px 8px 2px 0 !important; } + +select.text_color option { background: #ECECEC; } +select.text_size option.em { font-weight: bold; background: #ECECEC; } + +.fldSet1 { margin: 2px 4px 1px 4px; padding: 0px; } +.fldSetCont1 { margin: 0px; padding: 3px 8px 4px 8px; } +.fldSetCont2 { margin: 0px; padding: 2px 8px 4px 8px; } +.fldSetCont3 { margin: 0px; padding: 6px 8px 8px 8px; } + +.hl_only_new { color: #993300; } +.select-action { background: #F5F5F5; } +/* ---------------------------------- * + Text replacement for buttons + * ---------------------------------- */ +.txtb, .txtb:link, .txtb:visited, .txtb:hover { + color: #003366; font-size: 11px; text-decoration: none; +} +.txtb:hover { text-decoration: underline; } +/* ---------------------------------- * + Basic tables + * ---------------------------------- */ +.bodyline { + background: #FFFFFF; border: 1px solid #A5AFB4; +} +.bodyline th { + background: #71869F; color: #F0F8FF; font-weight: bold; +} + +table.forumline { + width: 100%; background: #B7C0C5; border-collapse: collapse; + margin-left: auto; margin-right: auto; + border-top: 1px solid #B7C0C5; +} +.forumline th { + border: 1px solid #B7C0C5; border-width: 1px; border-top-color: #92A3A4; +} +.forumline td { + border: 1px solid #B7C0C5; border-width: 0 1px 1px; +} +.forumline th, .thHead { + padding: 6px 8px 7px; text-align: center; + color: #D5E4EC; font-size: 11px; font-weight: bold; + background: #006699 url(../images/cellpic3.gif) repeat-x; +} +* > .forumline th { height: 28px; padding: 2px 4px; } +.forumline th:first-child { border-left-color: #92A3A4; } +.forumline th:last-child { border-right-color: #92A3A4; } +.forumline td { + padding: 2px 4px 3px; +} + +table.borderless th, table.borderless td { border: 0px none; } + +table.bordered { border-collapse: collapse; border: 1px solid #B7C0C5; } + .bordered th, .bordered td { border-style: solid; border-width: 1px; border-color: #B7C0C5; } + +table.message { margin: 0 auto; width: 100%; } +table.message td { + padding: 16px; text-align: center; background: #EFEFEF; +} + +.cat, td.cat, td.catTitle, td.catHead, td.catBottom { + padding: 5px 4px 6px; + background: #E0E5E9 url(../images/cellpic1.gif) repeat-x; +} +.catTitle { + font-weight: bold; letter-spacing: 1px; + color: #006699; text-align: center; +} +.catTitle a { text-decoration: none; } +.catBottom { text-align: center; } +#acp_main_nav .catTitle { + padding: 2px 6px 3px; text-align: left; font-size: 11px; letter-spacing: 0px; +} + +.info_msg_wrap { margin: 12px 0; } +table.info_msg { width: 100%; border: 1px solid #B7C0C5; background: #DEE3E7; margin: 0 auto; } +table.info_msg .msg { + border: 1px solid #B7C0C5; background: #EFEFEF; + padding: 20px; text-align: center; +} +table.error { width: 100%; border: 2px solid #993300; background: #FFD4CC; margin: 0 auto; } +table.error .msg { + border: 1px solid #993300; background: #FAEBD7; + padding: 20px; color: #A52A2A; text-align: center; +} + +table.search_username { margin: 12px; width: 370px; } + +table.pm_box_size { width: 175px; margin: 8px 2px; } + .pm_box_size .progress { background: #008000; } + .pm_box_size b { font-size: 10px; } + .pm_nav td { padding: 4px; font-size: 14px; font-weight: bold; } + +table.translit_expl th { + width: 30px; padding-right: 8px; font-weight: bold; text-align: right; +} +table.translit_expl td { width: 14px; } + +table.user_contacts th { text-align: right; width: 100%; } + .user_contacts td { padding: 2px 6px; } + +table.user_details th { padding: 2px 6px; text-align: right; vertical-align: top; } + .user_details td { width: 70%; } + +table.ratio_details th { padding: 2px 6px; text-align: right; } + .ratio_details td { white-space: nowrap; } + +table.usercp_register h6 { + margin: 0.3em 0.4em; color: #444444; line-height: 100%; +} + +table.smilies td { padding: 3px; text-align: center; } + +/* ================================================================ * + Page header + * ================================================================ */ +/* ---------------------------------- * + Breadcrumb [ home >> forum1 >> etc. ] + * ---------------------------------- */ +#breadcrumb {} +/* ---------------------------------- * + Important info + * ---------------------------------- */ +#important_info {} +/* ================================================================ * + Page content + * ================================================================ */ +#user_ratio { + padding: 6px 6px 4px 12px; font-size: 11px; +} +/* ================================================================ * + Main content + * ================================================================ */ +/* ---------------------------------- * + Forums on home page + * ---------------------------------- */ +#forums_list_wrap { margin-top: 4px; padding-right: 2px; } +#forums_top_links { clear: both; } +#forums_wrap { clear: both; padding-top: 1px; } +.cat_title { /* Category header */ + padding: 3px 8px 5px; letter-spacing: 1px; text-indent: 0.6em; + background: #DEE3E7 url(../images/cellpic1.gif) repeat-x; + } + .cat_title a { text-decoration: none; color: #333333 !important; } +table.forums { width: 100%; } + .forums th { + padding: 0 !important; font-size: 10px; font-weight: normal; color: #3C3C3C; + } + .forums td { + padding: 3px 4px; font-size: 11px; + } +.forums em { /* titles like: "Subforums:", "Moderators:" */ + color: #5E5E5E; font-style: italic; +} +.forumlink { /* forum links */ + font-size: 13px; font-weight: bold; + } + .forumlink a { text-decoration: none; } +.forums .forumlink { /* forum title */ + margin-top: 1px; +} +.forum_desc { /* forum description */ + margin-top: 2px; color: #333333; font-size: 11px; line-height: 110%; +} +.subforums { /* subforums */ + margin-top: 2px; + } + .subforums + .moderators { margin-top: 0; } + .sf_title { white-space: nowrap; } + .sf_icon { margin-right: 1px; } + .sf_separator {} + .sf_title a { text-decoration: none; } +.moderators { /* moderators */ + margin-top: 2px; font-size: 11px; line-height: 110%; + } + .moderators a, .moderators a:visited { + color: #333333; font-size: 10px; text-decoration: none; + } +.f_last_post { /* last topic/post */ + text-align: center; + } + .last_topic { margin-top: 1px; white-space: nowrap; } + .last_topic a { text-decoration: none; } + .last_post_time { margin-top: 2px; font-size: 10px; white-space: nowrap; } + .last_time {} + .last_author { padding-left: 3px; } + .f_stat_inline { /* Posts: xx Topics: xx */ + margin-top: 1px; white-space: nowrap; } + .f_stat_topics {} + .f_stat_posts { padding-left: 3px; } + +.forums thead { /* Forum TH-Headers */ +} +.f_icon { /* Forum Icon cell */ + width: 46px; + padding: 4px 0 !important; +} +.f_titles { /* Forum Title cell */ + width: auto; +} +.f_topics { /* Topics Count cell */ + width: 40px; text-align: center; +} +.f_posts { /* Posts Count cell */ + width: 50px; text-align: center; +} +.f_last_post { /* Forum Last Topic/Post cell */ + width: 230px; +} +.f_stat_inline { /* Inline Topic/Post count */ + display: none; +} + +table.forums { border-collapse: collapse; } +.cat_title { border: 1px solid #B7C0C5; border-bottom-color: #C3CBD1 !important; } +.f_tbl_wrap, #board_stats_wrap { + border: solid #B7C0C5; border-width: 0 1px; } +table.forums th { border-bottom: 1px solid #C3CBD1; } +.forums td.row1 { border: solid #C3CBD1; border-width: 0 1px 1px 0; } +.forums td.row2 { border: solid #C3CBD1; border-width: 0 1px 1px 0; } +td.f_titles { border-right-color: #C3CBD1 !important; } +td.last_td { border-right-width: 0 !important; } + +.cat_footer { + height: 0px; margin-top: -1px; border-top: 1px solid #B7C0C5; + font-size: 0px; line-height: 0px; +} +.cat_separator { height: 10px; font-size: 0px; line-height: 0px; } +#mark_all_forums_read { margin: -10px 0 3px 0; } + +#online_time { float: left; font-style: italic; color: #444444; } +#online_explain { float: right; } +#online_userlist a { white-space: nowrap; } + +/* ---------------------------------- * + Forums on viewforum page + * ---------------------------------- */ +table.forum th { white-space: nowrap; } +td.topic_id { padding: 4px 6px; } + +.spaceRow { + padding: 0 !important; background: #D1D7DC; +} +td.topicSep { /* Topic type groups separator */ + padding: 2px 12px 3px; font-weight: bold; letter-spacing: 1px; color: #333333 +} +.topicMoved { /* Topic Moved prefix */ + font-weight: normal; font-style: italic; +} +.topicAnnounce { /* Topic Announce prefix */ + color: #DD6900; +} +.topicPoll { /* Topic Poll prefix */ + font-weight: normal; color: #006699; +} +.topicPG { /* Topic pagination links */ + font-weight: normal; white-space: nowrap; font-size: 10px; +} +.iconDL { /* DL Icon */ + border: 1px outset; background: #EFEFEF; + padding: 0px 3px 0px 2px; margin: 2px 1px 2px 0px; +} +.topicAuthor, a.topicAuthor, a.topicAuthor:visited { + font-size: 11px; color: #333333; text-decoration: none; +} +.torSize { + font-size: 11px; color: #333333; text-decoration: none; +} +.hl-selected-topic { background-color: #FAF0E6 !important; } +/* ---------------------------------- * + Topics on viewtopic page + * ---------------------------------- */ +table.topic { width: 100%; } + + .post_head { padding: 0 6px; font-size: 10px; } + .post_wrap { padding: 5px 5px 8px; } + .post_body { line-height: 18px; } /* The content of the posts */ + a.postLink { text-decoration: none; } + a.postLink:visited { text-decoration: none; color: #5493B4; } + .posted_since { color: #666666; padding-left: 4px; } + .signature { clear: both; } + .signature, .signature * { + font-size: 10px !important; color: #5E5E5E !important; + text-decoration: none !important; background: transparent !important; + border: 0 none !important; padding: 0 !important; margin: 1px 0 !important; + } + .signature .code_head, .signature .q_head { display: none !important; } + .signature .code_wrap, .signature .code, + .signature .q_wrap, .signature .q { display: inline !important; } + .signature a { text-decoration: underline !important; } + .last_edited { font-size: 10px; color: #5E5E5E; } + + .poster_info p { margin: 2px 0; color: #444444; } + .poster_info .nick { margin: 0 0 4px; color: #333333; line-height: 110%; } + .poster_info .avatar { margin: 5px 0 4px; max-width: 100px; max-height: 100px; overflow: hidden; } + .avatar img { display: block; } + .poster_info .flag { margin: 4px 0; } + .poster_info em { font-style: normal; color: #000000; } + + table.topic, .topic .td1, .topic .td2, .topic .td3, .post_head, .post_btn_2 { + border-style: solid; border-color: #C3CBD1; } + .topic .td1 { border-width: 1px 1px 0px 0px; border-right-color: #B7C0C5; } + .topic .td2 { border-width: 1px 0px 0px 0px; width: 100%; } + .topic .td3 { border-width: 0px 1px 0px 0px; border-right-color: #B7C0C5; height: 100%; } + .post_head { border-width: 0px 0px 1px 0px; } + .post_btn_2 { border-width: 1px 0px 0px 0px; } + table.topic { border-width: 0px 1px 1px 1px; border-color: #B7C0C5; } + + .poster_info { padding: 4px; vertical-align: top; font-size: 10px; line-height: 100%; } + .poster_btn { padding: 0; vertical-align: bottom; text-align: center; white-space: nowrap; } + .message { padding: 0; vertical-align: top; width: 100%; } + + input.select_post { margin-top: 0px; float: right; } + input[type="checkbox"].select_post { margin-top: 4px; } + + table.peers { border-collapse: collapse; } + table.peers th { border: 1px #A5AFB4 solid; padding: 1px; height: auto; background: #D1D7DC; color: #333333; } + table.peers td { border: 1px #A5AFB4 solid; padding: 4px; } + #last_seed_info { border: 1px #A5AFB4 solid; } + + .dl_list {} + .dl_list td { text-align: center; } + .dl_list img { display: block; } + #dl_counts td { font-size: 12px; } + + #poll { border: solid #B7C0C5; border-width: 1px; margin-bottom: -1px; } + + .quick_reply_box { width: 640px; } + .hl-selected-post { background-color: #FFEFD5 !important; } + +/* ---------------------------------- * + Attachments + * ---------------------------------- */ +table.attach { width: 93%; margin: 0 auto; clear: both; border-color: #A5AFB4; } + .attach th, .attach td { border-color: #A5AFB4; } + .attach th { padding: 3px; text-align: center; font-weight: bold; background: #D1D7DC; } + .attach td { padding: 2px 4px; } + +fieldset.attach { width: 93%; margin: 0 auto; padding: 2px; clear: both; } + .attach_link { margin: 2px 12px 6px; } + .attach_stats { padding-left: 3px; } + .attach_comment { + margin: 6px 12px; padding: 1px 8px; line-height: 110%; + color: #444444; border-left: 2px solid #CC9933; + } + .attach .denied { color: #800000; } + +#tor_blocked { width: 93%; } + #tor_blocked td { background: #FAEBD7; padding: 8px 12px; color: #6E380F; } +/* ---------------------------------- * + Search Results page + * ---------------------------------- */ +.opened { /* Clicked link color */ + color: #71869F; +} +/* ---------------------------------- * + Tracker + * ---------------------------------- */ +.dlSp { font-size: 6px; } + +/* ================================================================ * + Images + * ================================================================ */ +img.forum_icon { width: 46px; height: 25px; } +img.topic_icon { width: 19px; height: 18px; } +img.pm_box_icon { width: 28px; height: 25px; } +img.icon1 { width: 12px; height: 9px; } +img.icon2 { width: 18px; height: 9px; } +img.spacer { display: block; height: 1px; } +/* ================================================================ * + Page footer + * ================================================================ */ +.bottom_info { font-size: 11px; } +.copyright { font-size: 10px; color: #444444; letter-spacing: -1px; } + .copyright a { text-decoration: none; } + +#timezone { + float: right; text-align: right; white-space: nowrap; + font-size: 10px; line-height: 110%; color: #333333; +} +.tz_time { font-family: "Courier New",Courier,monospace; font-size: 11px; } + +#f_icons_legend { margin: 4px auto; } +/* ================================================================ * + Menus + * ================================================================ */ +.menu-root { padding-right: 13px; white-space: nowrap; + background: transparent url(../images/menu_open.gif) no-repeat right; } +.menu-alt1 { padding-right: 0; background: transparent; } +img.menu-alt1 { width: 9px; height: 9px; } +a.menu-root, a.menu-root:visited, a.menu-root:hover { + text-decoration: none !important; } +.menu-sub { position: absolute; display: none; z-index: 1000; } + .menu-sub table { background: #FFFFFF; border: 1px solid #92A3A4; } + .menu-sub table th { background: #71869F; color: #F0F8FF; font-weight: bold; font-size: 11px; } + .menu-sub table td { background: #E7E7E7; font-size: 11px; } + .menu-sub table td.cat { background: #B5BEC3; } + .menu-sub legend { font-weight: bold; } + .menu-sub label { display: block; padding-right: 2px; margin-right: 1px; } + .menu-sub label:hover { background: #D1D7DC; color: #993300; } + .menu-sub iframe.ie-fix-select-overlap { + display: none; + display/**/: block; + position: absolute; z-index: -1; filter: mask(); } +/* ================================================================ * + Ajax + * ================================================================ */ +var.ajax-params { display: none; } +#ajax-loading, #ajax-error { + position: absolute; z-index: 2000; padding: 4px; font-size: 11px; + max-width: 400px; max-height: 200px; white-space: nowrap; display: none; +} +#ajax-loading { min-width: 100px; background: #2E8B57; color: #FFF5EE; } +#ajax-error { min-width: 200px; background: #8B0000; color: #F5F5F5; overflow: auto; } +.editable-container { cursor: pointer; } +.editable-container:hover { background: #E8E9F8; } +/* ================================================================ * + Misc + * ================================================================ */ +.sf { padding-left: 20px !important; } +.jumpbox { margin: 6px 0; text-align: right; white-space: nowrap; } + +.attachrow { font-size: 11px; border: 1px #A5AFB4 solid; } +.attachheader { font-size: 11px; border: 1px #A5AFB4 solid; background: #D1D7DC; } +.attachtable { font-size: 12px; border: 1px #A5AFB4 solid; border-collapse: collapse; } + +pre, .pre { + font-family: Courier,monospace; font-size: 12px; + border: 1px solid #B7C0C5; background: #F5F5F5; + padding: 4px; margin: 10px; +} +.pre { width:100%; overflow: auto; white-space: nowrap; } + +.wrap { + /* Browser specific (not valid) styles to make preformatted text wrap */ + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ +} + +.ann { font-size: 13px; text-align: center; color: #993300; font-weight: bold; } + +.clickable { cursor: pointer; } +.folded, .folded2 { display: block; + background: transparent url(../images/icon_plus_1.gif) no-repeat left center; padding-left: 14px; } +.unfolded, .unfolded2 { display: block; + background: transparent url(../images/icon_minus_1.gif) no-repeat left center; padding-left: 14px; } +.folded2 { background-image: url(../images/icon_plus_2.gif); } +.unfolded2 { background-image: url(../images/icon_minus_2.gif); } + +.warnColor1 { color: #993300; } +.warnColor2 { color: #FF0000; } +.warnBorder1 { border: 1px solid #A52A2A; } +.warningBox1 { border: 1px solid #A52A2A; color: #993300; padding: 12px; } +.warningBox2 { background:#FFD9B2 none repeat scroll 0%; border:2px solid #CC6600; color:#993300 !important; padding:8px; } + +/* ================================================================ * + Shortcuts + * ================================================================ */ +.spacer_0, .spacer_2, .spacer_4, .spacer_6, .spacer_8, .spacer_10, .spacer_12 { + font-size: 0px; line-height: 0px; } +.spacer_0 { height: 0px; } +.spacer_2 { height: 2px; } +.spacer_4 { height: 4px; } +.spacer_6 { height: 6px; } +.spacer_8 { height: 8px; } +.spacer_10 { height: 10px; } +.spacer_12 { height: 12px; } + +.pad_0, .pad_0 td, td.pad_0 { padding: 0; } +.pad_2, .pad_2 td, td.pad_2 { padding: 2px; } +.pad_4, .pad_4 td, td.pad_4 { padding: 4px; } +.pad_6, .pad_6 td, td.pad_6 { padding: 6px; } +.pad_8, .pad_8 td, td.pad_8 { padding: 8px; } +.pad_10, .pad_10 td, td.pad_10 { padding: 10px; } +.pad_12, .pad_12 td, td.pad_12 { padding: 12px; } +.pad_14, .pad_14 td, td.pad_14 { padding: 14px; } +.pad_16, .pad_16 td, td.pad_16 { padding: 16px; } + +.mrg_0 { margin: 0 !important; } +.mrg_2 { margin: 2px !important; } +.mrg_4 { margin: 4px !important; } +.mrg_6 { margin: 6px !important; } +.mrg_8 { margin: 8px !important; } +.mrg_10 { margin: 10px !important; } +.mrg_12 { margin: 12px !important; } +.mrg_14 { margin: 14px !important; } +.mrg_16 { margin: 16px !important; } + +.lh_100 { line-height: 100%; } +.lh_110 { line-height: 110%; } +.lh_120 { line-height: 120%; } +.lh_150 { line-height: 150%; } + +.wAuto { width: auto !important; } /* widthAuto */ +.w50 { width: 50% !important; } +.w60 { width: 60% !important; } +.w70 { width: 70% !important; } +.w80 { width: 80% !important; } +.w85 { width: 85% !important; } +.w90 { width: 90% !important; } +.w95 { width: 95% !important; } +.w100 { width: 100% !important; } + +.border { border-style: solid; border-color: #B7C0C5; } +.bw_T { border-width: 1px 0px 0px 0px !important; } +.bw_TR { border-width: 1px 1px 0px 0px !important; } +.bw_TRB { border-width: 1px 1px 1px 0px !important; } +.bw_TRBL { border-width: 1px 1px 1px 1px !important; } +.bw_TB { border-width: 1px 0px 1px 0px !important; } +.bw_TBL { border-width: 1px 0px 1px 1px !important; } +.bw_TL { border-width: 1px 0px 0px 1px !important; } +.bw_TRL { border-width: 1px 1px 0px 1px !important; } +.bw_R { border-width: 0px 1px 0px 0px !important; } +.bw_RB { border-width: 0px 1px 1px 0px !important; } +.bw_RBL { border-width: 0px 1px 1px 1px !important; } +.bw_RL { border-width: 0px 1px 0px 1px !important; } +.bw_B { border-width: 0px 0px 1px 0px !important; } +.bw_BL { border-width: 0px 0px 1px 1px !important; } +.bw_L { border-width: 0px 0px 0px 1px !important; } + +.clear { clear: both; height: 0; font-size: 0px; line-height: 0px; overflow: hidden; } +.clearB { clear: both; } +.hidden { display: none; } +.inline { display: inline; } +.block { display: block; } +.bold { font-weight: bold; } +.normal { font-weight: normal; } +.bCenter { margin-left: auto !important; margin-right: auto !important; } /* blockCenter */ +.bLeft { margin-right: auto !important; } +.bRight { margin-left: auto !important; } +.tCenter { text-align: center !important; } /* textCenter */ +.tLeft { text-align: left !important; } +.tRight { text-align: right !important; } +.vTop { vertical-align: top !important; } +.vBottom { vertical-align: bottom !important; } +.floatL { float: left; } +.floatR { float: right; } +.wrap { white-space: normal !important; } +.nowrap { white-space: nowrap !important; } diff --git a/upload/templates/default/css/backup/theme_default.css b/upload/templates/default/css/backup/theme_default.css new file mode 100644 index 000000000..ac3de1964 --- /dev/null +++ b/upload/templates/default/css/backup/theme_default.css @@ -0,0 +1,130 @@ +/* ================================================================ * + Page header + * ================================================================ */ +/* ---------------------------------- * + TopMenu, Quick Login, PM Info, Loguot.. + * ---------------------------------- */ +.topmenu { + background: #EFEFEF; border: solid #CFD4D8; border-width: 1px 0px; + margin: 3px 4px 0; padding: 0 8px; +} +.topmenu a:link, .topmenu a:visited { text-decoration: none; } +.topmenu td { padding: 4px; font-size: 11px; white-space: nowrap; } +.new-pm { background: #FFD9B2; border-color: #CC6600; } +.new-pm-link { color: #993300 !important; font-weight: bold; } +/* ---------------------------------- * + Logo + * ---------------------------------- */ +#logo { padding-left: 14px; min-height: 75px; } + #logo h1 { + margin: 0 300px 0 0; padding-top: 6px; + font-size: 42px; font-variant: small-caps; + } + #logo h6 { + margin: 0 300px 0 0; padding-top: 1px; padding-bottom: 3px; + font-size: 14px; font-variant: small-caps; + } +/* ---------------------------------- * + Main navigation + * ---------------------------------- */ +#main_nav { + padding: 2px 10px; margin: 0 4px; + border: solid #CFD4D8; border-width: 1px 0; background: #CFD4D8; + } + #main_nav b { padding: 0 4px 0 1px; } + #main_nav a { color: #535F62; text-decoration: none; } + #main_nav a:hover, #main_nav a:active { + text-decoration: none !important; color: #000000; + } +/* ---------------------------------- * + Quick Login, PM Info, Loguot.. + * ---------------------------------- */ +#logon { + position: absolute; top: 6px; right: 20px; + font-size: 11px; line-height: 160%; + border: 1px solid #B4B4B4; background: #EFEFEF; + } + #logon a:link, #logon a:visited { text-decoration: none; } + #logon span { + display: block; padding: 0 1px; + } + #name_pwd { /* Username/Password group */ + float: left; text-align: right; margin: 5px 0 5px 6px; + } + #login_button { /* Submit button and Autologin checkbox group */ + float: left; margin: 4px 6px 0 0; + } + #hello_username { font-size: 12px; line-height: 160%; margin: 4px; } + #name_pwd input { font-size: 11px; width: 80px; } + #login_button input { font-size: 12px; margin-top: 1px; } + #logged_in_links, #logged_out_links { + clear: both; text-align: center; + margin: 0 6px 2px; padding-top: 1px !important; + border-top: 1px solid #B4B4B4; + } + #register_link { font-weight: bold; } + .new_pm { + top: 5px !important; + background-color: #FFD9B2 !important; + border: 3px double #CC6600 !important; + } + .new_pm #pm_info a:link, + .new_pm #pm_info a:visited { + font-size: 11px; font-weight: bold; color: #993300; + } + .unread_pm a:link, + .unread_pm a:visited { + font-size: 11px; font-weight: bold; color: #993300; + } + .new_pm big, + .unread_pm big { font-size: 14px; } +/* ---------------------------------- * +Latest News +* ---------------------------------- */ +#latest_news { margin-bottom: 8px; } +#latest_news table { +border-collapse: collapse; +} +#latest_news h3 { padding: 0 0 3px 0; color: #333333; } +#latest_news td { vertical-align: top; } +.news_date { +float: right; padding: 1px 8px 1px; +white-space: nowrap; font-family: "Courier New",Courier,monospace; +color: #333333; background: #F2F2F2; border: 1px solid #B4B4B4; +} +.news_title { +padding: 3px 8px 2px; margin-bottom: 2px; +background: transparent url(../images/hr400_ltr_gradient.jpg) no-repeat left top; +} +#latest_news a { text-decoration: none; } +#latest_news .new a { color: #A52A2A; font-weight: bold; } +/* ================================================================ * +Page content +* ================================================================ */ +/* ---------------------------------- * +Sidebar 1 +* ---------------------------------- */ +#sidebar1 { +margin-top: -8px; +} +#sidebar1 h3 { +padding: 0 0 4px 0; margin: 8px 0 2px 0; +color: #333333; text-indent: 0.5em; +background: transparent url(../images/hr200_ltr_gradient.jpg) no-repeat left bottom; +} +#sidebar1 h3 a { color: #333333; } +#sidebar1 h5 { padding: 2px 4px 5px; } +#sidebar1 ul { margin: 6px 0 0 10px; } +#sidebar1 li { margin-bottom: 2px; margin-left: 14px; } +#sidebar1 a { text-decoration: none; color: #005A88; } +#user_ratio { padding: 0;} /* User ratio */ +#user_ratio td { +padding: 1px 6px 1px 8px ; font-size: 11px; +} +#tr_main_cats {} /* Main tracker categories list */ +#tr_main_cats ul { } +#tr_main_cats li { +margin-bottom: 3px; margin-left: 11px; font-size: 11px; font-weight: bold; line-height: 110%; +} +/* ================================================================ */ + diff --git a/upload/templates/default/css/dbg.css b/upload/templates/default/css/dbg.css new file mode 100644 index 000000000..89ef3ce24 --- /dev/null +++ b/upload/templates/default/css/dbg.css @@ -0,0 +1,31 @@ +/* dbg */ +.b1 { border: 1px solid #000 !important; } +.b2 { border: 1px solid #f00 !important; } +.b3 { border: 1px solid #00f !important; } + +.bg1 { background: #FAEBD7 !important; } +.bg2 { background: #A52A2A !important; } +.bg3 { background: #E9967A !important; } + +/* ------------------------------------------------------------------- +ERROR CHECKING +This is to determine if deprecated elements are used. If so, they should be replaced: +1a. and +1b. ...: Shouldn't be used. CSS should dictate font attributes. +2.
    : Shouldn't be used. CSS should dictate horizontal alignment. +3a.
    ...
    +3b.

    ...

    +3c. ...
    : +Shouldn't be used. CSS should dictate horizontal alignment. + +font, center, div[align], p[align], table[align], font[color] +{ + color : #cd0000; + font-weight : bold; + background : #eecc11 url(images/warning.gif) repeat 0 0; + margin : 10px; + padding : 10px; + border : 2px dashed #cd0000; + font-size : 2em; +} +------------------------------------------------------------------- */ \ No newline at end of file diff --git a/upload/templates/default/css/main.css b/upload/templates/default/css/main.css new file mode 100644 index 000000000..7ab0998ac --- /dev/null +++ b/upload/templates/default/css/main.css @@ -0,0 +1,1159 @@ +/* + * Initial neutralization + * Top Level + * Globals + + * Links + * Backgrounds + * Headers + * General text + + * Code blocks + * Quote blocks + * Spoiler + + ? Infoboxes + * Inputs, buttons, forms + * Text replacement for buttons + * Basic tables + + * Page header + - TopMenu, Quick Login, PM Info, Loguot.. + - Logo + - Main navigation + - Latest News + ? Breadcrumb + ? Important info + + * Page content + * Sidebar 1 + * Latest News + + * Forums on home page + * Forums on viewforum page + + * Topics on viewtopic page + * Torrent status + * Attachments + * Search Results page + * Tracker + + * Images + * Page footer + * Menus + * Misc + * Reports + * Shortcuts +*/ + +/* ================================================================ * + Initial neutralization + * ================================================================ */ + +/* Clean out MARGIN and PADDING */ +html, body, form, fieldset, h3, h4, h5, h6, p, pre, blockquote, +ul, ol, dl, li, dd { + margin: 0; padding: 0; +} +/* Add LEFT MARGIN */ +blockquote, ul, ol, li, dd { margin-left: 1em; } + +/* ================================================================ * + Top Level + * ================================================================ */ +html { + min-height: 100.1%; /* always show vertical scrollbar in Mozilla */ +} +body { + min-width: 760px; color: #000000; background: #E3E3E3; +} +body, th, td, font { + font: 12px Verdana,Arial,sans-serif; +} + +#body_container { background: #E3E3E3; padding: 0 2px 4px; } + #page_container { + margin: 0 auto; + background: #FFFFFF; border: 1px solid #D1D7DC; + } + #page_header { + position: relative; width: 100%; + } + #page_content { + padding: 12px 4px 0; margin: 0 auto; + clear: both; position: relative; + } + #sidebar1 {} + #sidebar2 { + padding: 0 3px 0 6px; vertical-align: top; + width: 240px; + } + #sidebar1-wrap { margin-top: -8px; width: 210px; } + #sidebar2-wrap {} + #main_content { + vertical-align: top; + } + #main_content_wrap {} + #page_footer { + clear: both; + margin: 12px 0 3px; + } + +/* ================================================================ * + Globals + * ================================================================ */ +hr { height: 0px; border: 0px solid #B7C0C5; border-top-width: 1px; } +.hr1 { border-top: 1px #B7C0C5 solid; } + +form { display: inline; } +label { cursor: pointer; white-space: nowrap; } +img { border: 0px; } + +.highlight { color: #FF0000; background: #FFFFE0; } +/* ---------------------------------- * + Links + * ---------------------------------- */ +:link:focus, :visited:focus { color: #DD6900; } +:link { color: #006699; } +:visited { color: #006699; } +:link:hover, :visited:hover { color: #DD6900; text-decoration: underline !important; } +:link:active, :visited:active { color: #DD6900; text-decoration: underline !important; } + +.colorAdmin, a.colorAdmin, a.colorAdmin:visited { color: #FF8C24 !important; } +.colorSuperMod, a.colorSuperMod, a.colorSuperMod:visited { color: #000000;!important; } +.colorMod, a.colorMod, a.colorMod:visited { color: #008000 !important; } +.colorGroup, a.colorGroup, a.colorGroup:visited { color: #476996 !important; } +.colorCPH, a.colorCPH, a.colorCPH:visited { color: #0080FF !important; } + +.adm, a.adm, a.adm:visited { color: #800000; text-decoration: none; font-size: 11px; } + +.dlWill { color: #0066CC; } +.dlDown, .leech, .leechmed, .leechsmall { color: #800000; } +.dlComplete, .seed, .seedmed, .seedsmall { color: #006600; } +.dlCancel { color: #666666; } + +a.dlWill, a.dlWill:visited { color: #0066CC; text-decoration: none; } +a.dlDown, a.dlDown:visited { color: #800000; text-decoration: none; } +a.dlComplete, a.dlComplete:visited { color: #006600; text-decoration: none; } +a.dlCancel, a.dlCancel:visited { color: #666666; text-decoration: none; } + +a.leech, a.leechmed, a.leechsmall, +a.leech:visited, a.leechmed:visited, a.leechsmall:visited +{ + color: #800000; text-decoration: none; +} +a.seed, a.seedmed, a.seedsmall, +a.seed:visited, a.seedmed:visited, a.seedsmall:visited +{ + color: #006600; text-decoration: none; +} +/* Poster name in viewtopic */ +.nick, .nick a { + color: #005A88 !important; font-size: 13px; font-weight: bold; text-decoration: none; +} +/* Nav links */ +.nav { margin: 0.3em 0; font-size: 11px; font-weight: bold; } +.nav a { text-decoration: none; } +.nav em { color: #660000; font-style: normal; } +/* Topic titles */ +.topictitle, a.topictitle { + font-size: 11px; text-decoration: none; font-weight: bold; +} +.torTopic, a.torTopic { + font-size: 11px; text-decoration: none; +} +a.topictitle:visited, a.torTopic:visited, a.tLink:visited { + color: #5493B4; +} +/* ---------------------------------- * + Backgrounds + * ---------------------------------- */ +.row1, .row1 td { background: #EFEFEF; } +.row2, .row2 td { background: #DEE3E7; } +.row3, .row3 td { background: #D1D7DC; } +.row4, .row4 td { background: #ECECEC; } +.row5, .row5 td { background: #E7E7E7; } +.row6, .row6 td { background: #E9E9E6; } + +.prow1 { background: #ECECEC; } +.prow2 { background: #E7E7E7; } +.prow3 { background: #DEE3E7; } + +.p-body tr { background: #ECECEC; } +.p-body tr:hover { background: #DEE3E7; } + +/* ---------------------------------- * + Headers + * ---------------------------------- */ +h1 { font-size: 18px; font-weight: bold; margin: 0.2em 0 0.5em; } +h2 { font-size: 16px; font-weight: bold; margin: 0.2em 0 0.5em; } +h3 { font-size: 13px; font-weight: bold; letter-spacing: 1px; } +h4 { font-size: 12px; font-weight: bold; } +h5 { font-size: 12px; font-weight: normal; } +h6 { font-size: 11px; font-weight: normal; } +/* Page title and toptic title */ +.maintitle, .pagetitle { + font-family: "Trebuchet MS",Verdana,sans-serif; color: #3C3C3C; + padding: 0 4px; margin: 0.2em 0 0.5em; +} +.maintitle a, .pagetitle a { text-decoration: none; } +.maintitle { font-size: 22px; } +/* ---------------------------------- * + General text + * ---------------------------------- */ +.gen, .seed, .leech, +.gen td { font-size: 12px; } +.med, .genmed, .seedmed, .leechmed, +.med td { font-size: 11px; } +.small, .gensmall, .seedsmall, .leechsmall, +.small td { font-size: 10px; } +.tiny, .tiny td { font-size: 10px; letter-spacing: -1px; } + +td.gen { font-size: 12px !important; } +td.med { font-size: 11px !important; } +td.small { font-size: 10px !important; } + +.gen, .med, .genmed, +.small, .gensmall { color: #000000; } +a.gen, a.med, a.genmed, +a.small, a.gensmall { color: #006699; text-decoration: none; } +/* ---------------------------------- * + Post elements + * ---------------------------------- */ +.post-align, .post-br, .post-hr, .postImgAligned { + display: block; +} +.sp-wrap, .post-hr { margin: 8px auto; } +.c-wrap, .q-wrap { margin: 8px auto; } +.c-wrap, .q-wrap, .sp-wrap { width: 98%; clear: both; } +.q-wrap .q-wrap, .sp-wrap .sp-wrap { margin: 2px auto 4px; } +.c-head, .q-head { padding: 0 1px; font-size: 11px; color: #444444; } +.c-body, .q, .sp-wrap, .sp-head, .sp-body { + border: solid #C3CBD1; border-width: 1px 1px 1px 2px; clear: both; +} +.c-body, .q, .sp-body { padding: 2px 6px; } +.c-head, .q-head, .sp-head { text-align: left !important; } + +.post-align { margin: 8px auto; } +.post-br { line-height: 12px; } +.post-b { font-weight: bold; } +.post-u { text-decoration: underline; } +.post-i { font-style: italic; } +.post-s { text-decoration: line-through; } +/* ---------------------------------- * + Code blocks + * ---------------------------------- */ +.c-body { font-size: 13px; font-family: "Courier New",Courier,monospace; color: #006600; background: #FAFAFA; } +/* ---------------------------------- * + Quote blocks + * ---------------------------------- */ +.q { background: #FAFAFA; color: #2E2E2E; max-height: 350px; overflow: auto; } +.q .q { background: #F5F5F5; max-height: 100%; overflow: visible; } +.q .q .q { background: #FAFAFA; } +.q .q .q .q { background: #F5F5F5; } +.q .q .q .q .q { background: #FAFAFA; } +.q .q .q .q .q .q { background: #F5F5F5; } +/* ---------------------------------- * + Spoiler + * ---------------------------------- */ +.sp-wrap { padding: 0; background: #E9E9E6; } +.sp-head { border-width: 0; font-size: 11px; padding: 1px 14px 3px; margin-left: 6px; line-height: 15px; font-weight: bold; color: #2A2A2A; cursor: pointer; } +.sp-body { border-width: 1px 0 0 0; display: none; font-weight: normal; background: #F5F5F5; border-bottom: 1px solid #C3CBD1;} +.sp-fold { width: 98%; margin: 0 auto; text-align: right; font-size: 10px; color: #444444; } +/* ---------------------------------- * + List + * ---------------------------------- */ +.post_body ul, .post_body ol { + margin: 8px auto 8px 8px; +} +.post_body li { margin: 0px 4px 1px 24px; } +/* ---------------------------------- * + Post images + * ---------------------------------- */ +img.smile, img.postImg { vertical-align: text-bottom; } +img.postImg { margin: 2px 2px 0 0; } +img.postImgAligned { margin: 4px 4px 2px; } +var.img-left { float: left; clear: left; } +var.img-right { float: right; clear: right; } +/* ---------------------------------- * + Other BBCode related + * ---------------------------------- */ +.post_body pre { + border: none; background: transparent; + padding: 0; margin: 0; +} +.post-pre { white-space: pre; font-family: monospace; } +a.postLink-name, a.postLink-name:visited { text-decoration: none; } +/* ---------------------------------- * + Infoboxes + * ---------------------------------- */ +.infobox { + border: 1px #B7C0C5 solid; background: #EFEFEF; padding: 1px; + } + .infobox h1 { + background: #D1D7DC; font-size: 1.2em; padding: 0px 0.6em 2px; + } +/* ---------------------------------- * + Inputs, buttons, forms + * ---------------------------------- */ +input, textarea, select { + font-family: Verdana,sans-serif; +} +input.post, textarea.post { } + +select, input { font-size: 11px; } +textarea { font-size: 12px; } + +input.mainoption, input.main, +input.liteoption, input.lite { + font-size: 11px; border: 1px solid; background: #FAFAFA; + padding-left: 10px; padding-right: 10px; +} +input.mainoption, input.main { + font-weight: bold; /* main submit button */ +} + +/* The buttons used for bbCode styling in message post */ +input.button, .buttons input { border: 1px solid; background: #F5F5F5; } +input.long { padding-left: 20px; padding-right: 20px; } + +input.button, .buttons input, +input.mainoption, input.main, input.liteoption, input.lite { + color: #000000; border-color: #B4B4B4 #000000 #000000 #B4B4B4; +} + +/* "gte IE 7" in page_header.tpl */ +input[type="checkbox"] { margin-bottom: 0px; } +input[type="radio"] { margin-bottom: -2px; } + +input[disabled="disabled"] { color: #808080; } +input.hint { color: #999999; font-style: italic; text-indent: 0.3em; } +input.error { color: #FF0000; font-weight: bold; } +input.found { font-weight: bold; } +.cat input[type="text"] { background: #FCFCFC; } + +optgroup, option, fieldset, legend { + font-family: Verdana,sans-serif; +} +optgroup { + font-size: 11px; letter-spacing: 0px; font-weight: bold; font-style: italic; + color: #005A88; background: #DEE3E7; +} +optgroup option { color: #000000; background: #FFFFFF; } +option { font-size: 11px; } +legend { padding: 0 2px 2px; font-size: 11px; color: #000066; } +legend a { text-decoration: none; } +fieldset > legend { margin-left: 6px; } +.root_forum {} +.has_sf { color: #333333; background: #F5F5F5; font-weight: bold; } + +input.pOrdSel { + border: 0px solid #EFEFEF; width: 18px; overflow: hidden; + color: #333333; background: transparent; + font-size: 12px; font-family: Arial,sans-serif; + cursor: pointer; +} + +textarea.editor { display: block; width: 98%; } + +.fieldsets td { vertical-align: top; white-space: nowrap; } +.fieldsets fieldset { margin: 4px 4px; } +.fieldsets fieldset div { padding: 3px 6px 4px; } +.fieldsets div p { margin-bottom: 1px; } +.fieldsets div > p { margin-bottom: 2px; } +.fieldsets .select { margin-bottom: 3px; } +.fieldsets .radio {} +.fieldsets .chbox {} +.fieldsets .input {} +table.my_downloads { margin-bottom: 2px; } + .my_downloads td { padding: 1px 8px 2px 0 !important; } + +select.text_color option { background: #ECECEC; } +select.text_size option.em { font-weight: bold; background: #ECECEC; } + +.fldSet1 { margin: 2px 4px 1px 4px; padding: 0px; } +.fldSetCont1 { margin: 0px; padding: 3px 8px 4px 8px; } +.fldSetCont2 { margin: 0px; padding: 2px 8px 4px 8px; } +.fldSetCont3 { margin: 0px; padding: 6px 8px 8px 8px; } + +.hl_only_new { color: #993300; } +.select-action { background: #F5F5F5; } +/* ---------------------------------- * + Text replacement for buttons + * ---------------------------------- */ +.txtb, .txtb:link, .txtb:visited, .txtb:hover { + color: #003366; font-size: 11px; text-decoration: none; +} +.txtb:hover { text-decoration: underline; } +/* ---------------------------------- * + Basic tables + * ---------------------------------- */ +.bodyline { + background: #FFFFFF; border: 1px solid #A5AFB4; +} +.bodyline th { + background: #71869F; color: #F0F8FF; font-weight: bold; +} + +table.forumline { + width: 100%; background: #B7C0C5; border-collapse: collapse; + margin-left: auto; margin-right: auto; + border-top: 1px solid #B7C0C5; +} +.forumline th { + border: 1px solid #B7C0C5; border-width: 1px; border-top-color: #92A3A4; +} +.forumline td { + border: 1px solid #B7C0C5; border-width: 0 1px 1px; +} +.forumline th, .thHead { + padding: 6px 8px 7px; text-align: center; + color: #D5E4EC; font-size: 11px; font-weight: bold; + background: #006699 url(../images/cellpic3.gif) repeat-x; +} +/* "lte IE 6" in page_header.tpl */ +.forumline th:first-child { border-left-color: #92A3A4; } +.forumline th:last-child { border-right-color: #92A3A4; } +.forumline td { + padding: 2px 4px 3px; +} + +table.borderless th, table.borderless td { border: 0px none; } + +table.bordered { border-collapse: collapse; border: 1px solid #B7C0C5; } + .bordered th, .bordered td { border-style: solid; border-width: 1px; border-color: #B7C0C5; } + +table.message { margin: 0 auto; width: 100%; } +table.message td { + padding: 16px; text-align: center; background: #EFEFEF; +} + +.cat, td.cat, td.catTitle, td.catHead, td.catBottom { + padding: 5px 4px 6px; + background: #E0E5E9 url(../images/cellpic1.gif) repeat-x; +} +.catTitle { + font-weight: bold; letter-spacing: 1px; + color: #333333; text-align: center; +} +.catTitle a { text-decoration: none; } +.catBottom { text-align: center; } +#acp_main_nav .catTitle { + padding: 2px 6px 3px; text-align: left; font-size: 11px; letter-spacing: 0px; +} + +.info_msg_wrap { margin: 12px 0; } +table.info_msg { width: 100%; border: 1px solid #B7C0C5; background: #DEE3E7; margin: 0 auto; } +table.info_msg .msg { + border: 1px solid #B7C0C5; background: #EFEFEF; + padding: 20px; text-align: center; +} +table.error { width: 100%; border: 2px solid #993300; background: #FFD4CC; margin: 0 auto; } +table.error .msg { + border: 1px solid #993300; background: #FAEBD7; + padding: 20px; color: #A52A2A; text-align: center; +} + +table.search_username { margin: 12px; width: 370px; } + +table.pm_box_size { width: 175px; margin: 8px 2px; } + .pm_box_size .progress { background: #008000; } + .pm_box_size b { font-size: 10px; } + .pm_nav td { padding: 4px; font-size: 14px; font-weight: bold; } + +table.translit_expl th { + width: 30px; padding-right: 8px; font-weight: bold; text-align: right; +} +table.translit_expl td { width: 14px; } + +table.user_contacts th { text-align: right; width: 100%; } + .user_contacts td { padding: 2px 6px; } + +table.user_details th { padding: 2px 6px; text-align: right; vertical-align: top; } + .user_details td { width: 70%; } + +table.usercp_register h6 { + margin: 0.3em 0.4em; color: #444444; line-height: 100%; +} + +table.smilies td { padding: 3px; text-align: center; } + +/* ================================================================ * + Page header + * ================================================================ */ +/* ---------------------------------- * + TopMenu, Quick Login, PM Info, Loguot.. + * ---------------------------------- */ +.topmenu { + background: #EFEFEF; border: solid #CFD4D8; border-width: 1px 0px; + margin: 3px 4px 0; padding: 0 8px; +} +.topmenu a:link, .topmenu a:visited { text-decoration: none; } +.topmenu td { padding: 4px; font-size: 11px; white-space: nowrap; } +.new-pm { background: #FFD9B2 !important; border-top-color: #FFD9B2 !important; border-bottom-color: #FFAA51 !important; } +.new-pm-link { color: #993300 !important; font-weight: bold; } +.new-pm-link:hover { color: #591D00 !important; } +/* ---------------------------------- * + Logo + * ---------------------------------- */ +#logo { padding: 2px 4px; min-height: 75px; } + #logo h1 { + margin: 0 300px 0 0; padding-top: 6px; + font-size: 42px; font-variant: small-caps; + } + #logo h6 { + margin: 0 300px 0 0; padding-top: 1px; padding-bottom: 3px; + font-size: 14px; font-variant: small-caps; + } + #logo img { + padding: 7px 7px 6px 5px; + } +/* ---------------------------------- * + Main navigation + * ---------------------------------- */ +#main-nav { + padding: 2px 10px; margin: 0 4px; + border: solid #CFD4D8; border-width: 1px 0; background: #CFD4D8; + } + #main-nav b { padding: 0 4px 0 1px; } + #main-nav a { color: #535F62; text-decoration: none; } + #main-nav a:hover, #main-nav a:active { + text-decoration: none !important; color: #000000; + } +/* ---------------------------------- * + Latest News + * ---------------------------------- */ +#latest_news { margin-bottom: 8px; } + #latest_news table { + border-collapse: collapse; + } + #latest_news h3 { padding: 0 0 3px 0; color: #333333; } + #latest_news td { vertical-align: top; } + .news_date { + float: right; padding: 1px 8px 1px; + white-space: nowrap; font-family: "Courier New",Courier,monospace; + color: #333333; background: #F2F2F2; border: 1px solid #B4B4B4; + } + .news_title { + padding: 3px 8px 2px; margin-bottom: 2px; + background: transparent url(../images/hr400_ltr_gradient.jpg) no-repeat left top; + } + #latest_news a { text-decoration: none; color: #000000; } + #latest_news .new a { color: #A52A2A; font-weight: bold; } +/* ---------------------------------- * + Breadcrumb [ home >> forum1 >> etc. ] + * ---------------------------------- */ +#breadcrumb {} +/* ---------------------------------- * + Important info + * ---------------------------------- */ +#important_info {} +/* ================================================================ * + Page content + * ================================================================ */ +/* ---------------------------------- * + Sidebar 1 + * ---------------------------------- */ +#sidebar1 { + margin-top: -8px; width: 210px; padding: 0 6px 0 3px; vertical-align: top; + } + #sidebar1 h3 { + padding: 0 0 4px 0; margin: 8px 0 2px 0; + color: #333333; text-indent: 0.5em; + background: transparent url(../images/hr200_ltr_gradient.jpg) no-repeat left bottom; + } + #sidebar1 h3 a { color: #333333; } + #sidebar1 h5 { padding: 2px 4px 5px; } + #sidebar1 ul { margin: 6px 0 0 10px; } + #sidebar1 li { margin-bottom: 2px; margin-left: 14px; } + #sidebar1 a { text-decoration: none; color: #005A88; } + + #user_ratio { padding: 0;} /* User ratio */ + #user_ratio td { + padding: 1px 6px 1px 6px ; font-size: 11px; + } + #tr_main_cats {} /* Main tracker categories list */ + #tr_main_cats ul { + list-style-image: url(../images/arrow1.gif); + } + #tr_main_cats li { + margin-bottom: 3px; margin-left: 11px; font-size: 11px; font-weight: bold; line-height: 110%; + } +#user_ratio { + padding: 1px 6px 0px 0px; font-size: 11px; +} +#author-rel a { color: #800000; } +/* ================================================================ * + Main content + * ================================================================ */ +/* ---------------------------------- * + Forums on home page + * ---------------------------------- */ +#forums_list_wrap { margin-top: 4px; padding-right: 2px; } +#forums_top_links { clear: both; } +#forums_wrap { clear: both; padding-top: 1px; } +.cat_title { /* Category header */ + padding: 3px 8px 5px; letter-spacing: 1px; text-indent: 0.6em; + background: #DEE3E7 url(../images/cellpic1.gif) repeat-x; + } + .cat_title a { text-decoration: none; color: #333333 !important; } +table.forums { width: 100%; } + .forums th { + padding: 0 !important; font-size: 10px; font-weight: normal; color: #3C3C3C; + } + .forums td { + padding: 3px 4px; font-size: 11px; + } +.forums em { /* titles like: "Subforums:", "Moderators:" */ + color: #5E5E5E; font-style: italic; +} +.forumlink { /* forum links */ + font-size: 13px; font-weight: bold; + } + .forumlink a { text-decoration: none; } +.forums .forumlink { /* forum title */ + margin-top: 1px; +} +.forum_desc { /* forum description */ + margin-top: 2px; color: #333333; font-size: 11px; line-height: 110%; +} +.subforums { /* subforums */ + margin-top: 2px; padding-left: 0.5em; + } + .subforums em { display: none; } + .subforums + .moderators { margin-top: 0; } + .dot-sf { color: #417998 !important; font-size: 11px; margin-right: 4px; } + .new .dot-sf { color: #CA4200 !important; } + .sf_title { white-space: normal; } + .sf_icon { margin-right: 1px; } + .sf_separator {} + .sf_title a { text-decoration: none; } +.moderators { /* moderators */ + margin-top: 2px; font-size: 11px; line-height: 110%; + } + .moderators a, .moderators a:visited { + color: #333333; font-size: 10px; text-decoration: none; + } +.f_last_post { /* last topic/post */ + text-align: center; + } + .last_topic { margin-top: 1px; white-space: nowrap; } + .last_topic a { text-decoration: none; } + .last_post_time { margin-top: 2px; font-size: 10px; white-space: nowrap; } + .last_time {} + .last_author { padding-left: 3px; } + .f_stat_inline { /* Posts: xx Topics: xx */ + margin-top: 1px; white-space: nowrap; } + .f_stat_topics {} + .f_stat_posts { padding-left: 3px; } + +.forums thead { /* Forum TH-Headers */ + display: none; +} +.f_icon { /* Forum Icon cell */ + width: 46px; + padding: 6px 0 !important; +} +.f_titles { /* Forum Title cell */ + width: auto; +} +.f_topics { /* Topics Count cell */ + width: 40px; text-align: center; +} +.f_posts { /* Posts Count cell */ + width: 50px; text-align: center; +} +.f_last_post { /* Forum Last Topic/Post cell */ + width: 230px; +} +.f_stat_inline { /* Inline Topic/Post count */ + display: block; +} + +table.forums { border-collapse: collapse; } +.cat_title { border: 0 none; + border-top: 1px solid #B7C0C5; + border-bottom: 1px solid #C3CBD1; } +.f_tbl_wrap, #board_stats_wrap { + border: 0 none; } +.forums td.row1 { border: solid #FDFDFD; border-width: 0 1px 1px 0; } +.forums td.row2 { border: solid #F5F5F5; border-width: 0 1px 1px 0; } +td.f_titles { border-right-color: #FAFCFD !important; } +td.last_td { border-right-width: 0 !important; } + +.cat_footer { + height: 0px; margin-top: -1px; border-top: 1px solid #C3CBD1; + font-size: 0px; line-height: 0px; +} +.cat_separator { height: 10px; font-size: 0px; line-height: 0px; } +#mark_all_forums_read { margin: -10px 0 3px 0; } + +#online_time { float: left; font-style: italic; color: #444444; } +#online_explain { float: right; } +#online_userlist a { white-space: nowrap; } +#forums_top_nav { display: none; } +/* ---------------------------------- * + Forums on viewforum page + * ---------------------------------- */ +table.forum th { white-space: nowrap; } +td.topic_id { padding: 4px 6px; } + +.spaceRow { + padding: 0 !important; background: #D1D7DC; +} +td.topicSep { /* Topic type groups separator */ + padding: 2px 12px 3px; font-weight: bold; letter-spacing: 1px; color: #333333; +} +.topicMoved { /* Topic Moved prefix */ + font-weight: normal; font-style: italic; +} +.topicAnnounce { /* Topic Announce prefix */ + color: #DD6900; +} +.topicSticky { /* Topic Sticky prefix */ + color: #009900; +} +.topicPoll { /* Topic Poll prefix */ + font-weight: normal; color: #006699; +} +.topicPG { /* Topic pagination links */ + font-weight: normal; white-space: nowrap; font-size: 10px; +} +.iconDL { /* DL Icon */ + border: 1px outset; background: #EFEFEF; + padding: 0px 3px 0px 2px; margin: 2px 1px 2px 0px; +} +.topicAuthor, a.topicAuthor, a.topicAuthor:visited { + font-size: 11px; color: #333333; text-decoration: none; +} +.torSize { + font-size: 11px; color: #333333; text-decoration: none; +} +.hl-selected-topic { background-color: #FAF0E6 !important; } +.hl-selected-row, .hl-selected-row td { background-color: #FAF0E6 !important; } +/* ---------------------------------- * + Topics on viewtopic page + * ---------------------------------- */ +table.topic { width: 100%; } + + .post_head { padding: 0 6px; font-size: 10px; } + .post_wrap { margin: 5px 5px 8px; } + .post_body { line-height: 18px; } /* The content of the posts */ + a.postLink { text-decoration: none; } + a.postLink:visited { text-decoration: none; color: #5493B4; } + .posted_since { color: #666666; padding-left: 4px; } + .signature { clear: both; } + .signature { max-height: 100px; overflow: hidden; } + .signature, .signature * { + font-size: 10px !important; color: #5E5E5E !important; + text-decoration: none !important; background: transparent !important; + border: 0 none !important; padding: 0 !important; margin: 1px 0 !important; + } + .signature .c-head, .signature .q-head { display: none !important; } + .signature .c-wrap, .signature .c-body, + .signature .q-wrap, .signature .q { display: inline !important; } + .signature a { text-decoration: underline !important; } + .signature img { max-width: 600px; } + .last_edited { font-size: 10px; color: #5E5E5E; } + .poster_info p { margin: 2px 0; color: #444444; } + .poster_info .nick { margin: 0 0 4px; color: #333333; line-height: 110%; } + .poster_info .avatar { margin: 5px 0 4px; max-width: 100px; max-height: 100px; overflow: hidden; } + .avatar imgreflect { display: block; } + .poster_info .flag { margin: 4px 0; } + .poster_info em { font-style: normal; color: #000000; } + + table.topic, .topic .td1, .topic .td2, .topic .td3, .post_head, .post_btn_2 { + border-style: solid; border-color: #C3CBD1; } + .topic .td1 { border-width: 1px 1px 0px 0px; border-right-color: #B7C0C5; } + .topic .td2 { border-width: 1px 0px 0px 0px; width: 100%; } + .topic .td3 { border-width: 0px 1px 0px 0px; border-right-color: #B7C0C5; height: 100%; } + .post_head { border-width: 0px 0px 1px 0px; } + .post_btn_2 { border-width: 1px 0px 0px 0px; } + table.topic { border-width: 0px 1px 1px 1px; border-color: #B7C0C5; } + + .poster_info { padding: 4px; vertical-align: top; font-size: 10px; line-height: 100%; } + .poster_btn { padding: 0; vertical-align: bottom; text-align: center; white-space: nowrap; } + .message { padding: 0; vertical-align: top; width: 100%; } + + input.select_post { margin-top: 0px; float: right; } + input[type="checkbox"].select_post { margin-top: 4px; } + + table.peers { border-collapse: collapse; } + table.peers th { border: 1px #A5AFB4 solid; background: #D1D7DC; color: #333333; } + table.peers td { border: 1px #A5AFB4 solid; padding: 4px; } + #last_seed_info { border: 1px #A5AFB4 solid; } + + .dl_list {} + .dl_list td { text-align: center; } + .dl_list img { display: block; } + #dl_counts td { font-size: 12px; } + + #poll { border: solid #B7C0C5; border-width: 1px; margin-bottom: -1px; } + + .quick_reply_box { width: 640px; } + .hl-selected-post { background-color: #FFEFD5 !important; } +/* ---------------------------------- * + Torrent status + * ---------------------------------- */ +.tor-status-td:hover { background: #F8F8FF; } +.tor-icon { margin: 0 3px; } +.tor-approved { margin-left: 1px; color: #008000; font-weight: bold; } +.tor-closed { padding-left: 1px; color: #FF4500; font-weight: bold; } +.tor-closed-cp { color: #CE3800; font-weight: bold; } +.tor-consumed { color: #D26900; font-weight: bold; } +.tor-dup { padding-left: 1px; color: #0000FF; font-weight: bold; } +.tor-need-edit { color: #FF0000; font-weight: bold; } +.tor-no-desc { padding-left: 1px; color: #FF4500; font-weight: bold; } +.tor-not-approved { color: #C71585; } +.tor-checking { color: #2424FF; } + +/* ---------------------------------- * + Attachments + * ---------------------------------- */ +table.attach { width: 95%; margin: 0 auto; clear: both; border-color: #A5AFB4; } + .attach th, .attach td { border-color: #A5AFB4; } + .attach th { padding: 3px; text-align: center; font-weight: bold; background: #D1D7DC; } + .attach td { padding: 2px 4px; } + .dl-link { font-size: 13px; } + +fieldset.attach { width: 95%; margin: 14px auto; padding: 2px; clear: both; } + .attach_link { margin: 2px 12px 6px; } + .attach_stats { padding-left: 3px; } + .attach_comment { + margin: 6px 12px; padding: 1px 8px; line-height: 110%; + color: #444444; border-left: 2px solid #CC9933; + } + .attach .denied { color: #800000; } + +#tor_blocked { width: 95%; } + #tor_blocked td { background: #FAEBD7; padding: 8px 12px; color: #6E380F; } +/* ---------------------------------- * + Search Results page + * ---------------------------------- */ +.opened { /* Clicked link color */ + color: #71869F; +} +/* ---------------------------------- * + Tracker + * ---------------------------------- */ +a.tr-dl { font-weight: bold; } +a.tr-dl:visited { color: #5493B4; font-weight: normal; } + +/* ================================================================ * + Images + * ================================================================ */ +img.forum_icon { width: 46px; height: 25px; } +img.topic_icon { width: 19px; height: 18px; } +img.pm_box_icon { width: 28px; height: 25px; } +img.icon1 { width: 12px; height: 9px; } +img.icon2 { width: 18px; height: 9px; } +img.spacer { display: block; height: 1px; } +/* ================================================================ * + Page footer + * ================================================================ */ +.bottom_info { font-size: 11px; } +.copyright { font-size: 10px; color: #444444; letter-spacing: -1px; } + .copyright a { text-decoration: none; } + +#timezone { + float: right; text-align: right; white-space: nowrap; + font-size: 10px; line-height: 110%; color: #333333; +} +.tz_time { font-family: "Courier New",Courier,monospace; font-size: 11px; } + +#f_icons_legend { margin: 4px auto; } +/* ================================================================ * + Menus + * ================================================================ */ +.menu-root { padding-right: 13px; white-space: nowrap; + background: transparent url(../images/menu_open.gif) no-repeat right; } +.menu-alt1 { padding-right: 0; background: transparent; } +img.menu-alt1 { width: 9px; height: 9px; } +a.menu-root, a.menu-root:visited, a.menu-root:hover { + text-decoration: none !important; } +.menu-sub { position: absolute; display: none; z-index: 1000; } + .menu-sub table { background: #FFFFFF; border: 1px solid #92A3A4; } + .menu-sub table th { background: #71869F; color: #F0F8FF; font-weight: bold; font-size: 11px; } + .menu-sub table td { background: #E7E7E7; font-size: 11px; } + .menu-sub table td.cat { background: #B5BEC3; } + .menu-sub legend { font-weight: bold; } + .menu-sub label { display: block; padding-right: 2px; margin-right: 1px; } + .menu-sub label:hover { background: #D1D7DC; color: #993300; } + .menu-sub iframe.ie-fix-select-overlap { + display: none; + display/**/: block; + position: absolute; z-index: -1; filter: mask(); } +/* ================================================================ * + Ajax + * ================================================================ */ +var.ajax-params { display: none; } +#ajax-loading, #ajax-error { + position: fixed; right: 3px; top: 0px; + z-index: 5000; + display: none; +} +#ajax-loading td, #ajax-error td { + font-size: 11px; + font-weight: bold; + white-space: nowrap; + padding: 3px 4px 4px 4px; + border: 1px solid #2E8B57; + color: #FFF5EE; background: #2E8B57; +} +#ajax-loading td.icon { + width: 12px; height: 12px; + background: #EFEFEF url(../images/loading.gif) no-repeat center center; +} +#ajax-error { + background: #8B0000; color: #F5F5F5; + border: 0px; padding: 4px; + white-space: nowrap; overflow: auto; +} +.editable-container { cursor: pointer; } +.editable-container:hover { background: #E8E9F8; } +.loading-1 { background: transparent url(../images/loading_1.gif) no-repeat left center; padding-left: 22px; } +/* ================================================================ * + Treeview, TableSorter + * ================================================================ */ +.treeview, .treeview ul { + padding: 0; margin: 0; list-style: none; font-size: 11px; line-height: 14px; +} +.treeview ul { + margin-top: 4px; +} +.treeview .hitarea { + background: url(../images/treeview/treeview-default.gif) -64px -25px no-repeat; + width: 16px; height: 16px; margin-left: -16px; float: left; cursor: pointer; +} +/* fix for IE6 */ +* html .hitarea { + display: inline; float: none; +} +.treeview li { + margin: 0; padding: 1px 0 1px 16px; +} +.treeview span { + padding-left: 3px; display: block; +} +.treeview a.selected { + background-color: #eee; +} +#treecontrol { margin: 1em 0; display: none; } +.treeview .hover { color: red; cursor: pointer; } + +.treeview li { background: url(../images/treeview/treeview-default-line.gif) 0 0 no-repeat; } +.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; } + +.treeview .expandable-hitarea { background-position: -80px -3px; } + +.treeview li.last { background-position: 0 -1766px } +.treeview li.lastCollapsable, .treeview li.lastExpandable { + background-image: url(../images/treeview/treeview-default.gif); +} +.treeview li.lastCollapsable { background-position: 0 -111px } +.treeview li.lastExpandable { background-position: -32px -67px } + +.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; } + +/* Tablesorter */ +.tablesorter u { display: none; } +.tablesorter .header { + cursor: pointer; white-space: nowrap; +} +.tablesorter .tbs-text { + padding-bottom: 1px; +} +.headerSortUp .tbs-text, .headerSortDown .tbs-text { + border-bottom-width: 2px; border-bottom-style: solid; +} +.tbs-icon { + padding-left: 8px; + background-image: url(../images/tbl_sort_bg.gif); background-repeat: no-repeat; background-position: 0 50%; +} +.headerSortUp .tbs-icon { + background-image: url(../images/tbl_sort_asc.gif); +} +.headerSortDown .tbs-icon { + background-image: url(../images/tbl_sort_desc.gif); +} +/* ================================================================ * + Misc + * ================================================================ */ +.sf { padding-left: 20px !important; } +.jumpbox { margin: 6px 0; text-align: right; white-space: nowrap; } + +.attachrow { font-size: 11px; border: 1px #A5AFB4 solid; } +.attachheader { font-size: 11px; border: 1px #A5AFB4 solid; background: #D1D7DC; } +.attachtable { font-size: 12px; border: 1px #A5AFB4 solid; border-collapse: collapse; } + +pre, .pre { + font-family: Courier,monospace; font-size: 12px; + border: 1px solid #B7C0C5; background: #F5F5F5; + padding: 4px; margin: 10px; text-align: left; +} +.pre { width:100%; overflow: auto; white-space: nowrap; } + +.ann { font-size: 13px; text-align: center; color: #993300; font-weight: bold; } + +.clickable { cursor: pointer; } +.folded, .folded2 { display: block; + background: transparent url(../images/icon_plus_1.gif) no-repeat left center; padding-left: 14px; } +.unfolded, .unfolded2 { display: block; + background: transparent url(../images/icon_minus_1.gif) no-repeat left center; padding-left: 14px; } +.folded2 { background-image: url(../images/icon_plus_2.gif); } +.unfolded2 { background-image: url(../images/icon_minus_2.gif); } + +.warnColor1 { color: #993300; } +.warnColor2 { color: #FF0000; } +.warnBorder1 { border: 1px solid #A52A2A; } +.warningBox1 { border: 1px solid #A52A2A; color: #993300; padding: 12px; } +.warningBox2 { color: #993300 !important; background: #FFD9B2; border: 2px solid #CC6600; padding: 8px; } + +/* ================================================================ * + Reports + * ================================================================ */ +/* Color pixel */ +div.report_pixel { + height: 1em; + width: 1em; + float: left; + margin-right: 3px +} + +/* Report list colors */ +td.report_cleared, div.report_cleared { + background-color: #7ce380; +} + +td.report_process, div.report_process { + background-color: #ffc267; +} + +td.report_open, div.report_open { + background-color: #f2a0a7; +} + +td.report_new, div.report_new { + background-color: #f88085; +} + +td.report_delete, div.report_delete { + background-color: #9eabb2; +} + +/* Report mode select */ +select.report_mode option { + margin: 1px 0 +} + +select.report_mode optgroup { + background-color: #FFF; + color: #000; + font-style: normal; + font-weight: bold; + margin-left: 3px +} + +select.report_mode optgroup option { + border-left: 1.3em solid; + padding-left: 2px; + margin-left: 1px; +} + +select.report_mode option.report_cleared { + border-color: #1e6731 +} + +select.report_mode option.report_process { + border-color: #e6721b +} + +select.report_mode option.report_open { + border-color: #8b201d +} + +/* ================================================================ * + Shortcuts + * ================================================================ */ +.spacer_0, .spacer_2, .spacer_4, .spacer_6, .spacer_8, .spacer_10, .spacer_12 { + font-size: 0px; line-height: 0px; } +.spacer_0 { height: 0px; } +.spacer_2 { height: 2px; } +.spacer_4 { height: 4px; } +.spacer_6 { height: 6px; } +.spacer_8 { height: 8px; } +.spacer_10 { height: 10px; } +.spacer_12 { height: 12px; } + +.pad_0, .pad_0 td, td.pad_0 { padding: 0; } +.pad_2, .pad_2 td, td.pad_2 { padding: 2px; } +.pad_4, .pad_4 td, td.pad_4 { padding: 4px; } +.pad_6, .pad_6 td, td.pad_6 { padding: 6px; } +.pad_8, .pad_8 td, td.pad_8 { padding: 8px; } +.pad_10, .pad_10 td, td.pad_10 { padding: 10px; } +.pad_12, .pad_12 td, td.pad_12 { padding: 12px; } +.pad_14, .pad_14 td, td.pad_14 { padding: 14px; } +.pad_16, .pad_16 td, td.pad_16 { padding: 16px; } + +.mrg_0 { margin: 0 !important; } +.mrg_2 { margin: 2px !important; } +.mrg_4 { margin: 4px !important; } +.mrg_6 { margin: 6px !important; } +.mrg_8 { margin: 8px !important; } +.mrg_10 { margin: 10px !important; } +.mrg_12 { margin: 12px !important; } +.mrg_14 { margin: 14px !important; } +.mrg_16 { margin: 16px !important; } + +.lh_100 { line-height: 100%; } +.lh_110 { line-height: 110%; } +.lh_120 { line-height: 120%; } +.lh_150 { line-height: 150%; } + +.wAuto { width: auto !important; } /* widthAuto */ +.w50 { width: 50% !important; } +.w60 { width: 60% !important; } +.w70 { width: 70% !important; } +.w80 { width: 80% !important; } +.w85 { width: 85% !important; } +.w90 { width: 90% !important; } +.w95 { width: 95% !important; } +.w100 { width: 100% !important; } + +.border { border-style: solid; border-color: #B7C0C5; } +.bw_T { border-width: 1px 0px 0px 0px !important; } +.bw_TR { border-width: 1px 1px 0px 0px !important; } +.bw_TRB { border-width: 1px 1px 1px 0px !important; } +.bw_TRBL { border-width: 1px 1px 1px 1px !important; } +.bw_TB { border-width: 1px 0px 1px 0px !important; } +.bw_TBL { border-width: 1px 0px 1px 1px !important; } +.bw_TL { border-width: 1px 0px 0px 1px !important; } +.bw_TRL { border-width: 1px 1px 0px 1px !important; } +.bw_R { border-width: 0px 1px 0px 0px !important; } +.bw_RB { border-width: 0px 1px 1px 0px !important; } +.bw_RBL { border-width: 0px 1px 1px 1px !important; } +.bw_RL { border-width: 0px 1px 0px 1px !important; } +.bw_B { border-width: 0px 0px 1px 0px !important; } +.bw_BL { border-width: 0px 0px 1px 1px !important; } +.bw_L { border-width: 0px 0px 0px 1px !important; } + +.bCenter { margin-left: auto !important; margin-right: auto !important; } /* blockCenter */ +.bLeft { margin-right: auto !important; } +.block { display: block; } +.bold { font-weight: bold; } +.bRight { margin-left: auto !important; } +.clear { clear: both; height: 0; font-size: 0px; line-height: 0px; overflow: hidden; } +.clearB { clear: both; } +.floatL { float: left; } +.floatR { float: right; } +.hidden { display: none; } +.inline { display: inline; } +.normal { font-weight: normal; } +.nowrap { white-space: nowrap !important; } +.wrap { white-space: normal !important; } +.strike { text-decoration: line-through; } +.tCenter { text-align: center !important; } /* textCenter */ +.tLeft { text-align: left !important; } +.tRight { text-align: right !important; } +.vBottom { vertical-align: bottom !important; } +.vTop { vertical-align: top !important; } diff --git a/upload/templates/default/donate.tpl b/upload/templates/default/donate.tpl new file mode 100644 index 000000000..072b7a3a7 --- /dev/null +++ b/upload/templates/default/donate.tpl @@ -0,0 +1,54 @@ +

    {PAGE_TITLE}

    + + + + + + + + + + + + + +
    {L_DONATE_TITLE}
    +

    Финансовая помощь

    + Вся денежная помощь идет на обновление нашего сервера и оборудования, поэтому мы рады любым вашим пожертвованиям... +
    + Если Вы желаете материально помочь в развитии проекту - ниже указаны возможные способы перевода денежных средств. +

    + +
    + WMID: ************* +

    + + + + + + + + + + + + + + + + + + + + + + + +
    ВалютаКошелёк
    Евро E*************
    Доллар Z*************
    Гривны U*************
    Рубли R*************
    +
    + Как перевести WebMoney деньги можно посмотреть здесь +
    +
     
    + +
    \ No newline at end of file diff --git a/upload/templates/default/faq.tpl b/upload/templates/default/faq.tpl new file mode 100644 index 000000000..0785b2176 --- /dev/null +++ b/upload/templates/default/faq.tpl @@ -0,0 +1,43 @@ +

    {PAGE_TITLE}

    + + + + + + + + + + + + + +
    {L_FAQ_TITLE}
    +
    + +

    {faq_block_link.BLOCK_TITLE}

    + +

    {faq_block_link.faq_row_link.FAQ_LINK}

    + +
    + +
     
    + +
    + + + + + + + + + + + + +
    {faq_block.BLOCK_TITLE}
    + +

    {faq_block.faq_row.FAQ_QUESTION}

    +

    {faq_block.faq_row.FAQ_ANSWER}

    +

    {L_BACK_TO_TOP}

    \ No newline at end of file diff --git a/upload/templates/default/gallery.tpl b/upload/templates/default/gallery.tpl new file mode 100644 index 000000000..c58da0fda --- /dev/null +++ b/upload/templates/default/gallery.tpl @@ -0,0 +1,112 @@ + + + + + + + + + +
    {L_GALLERY}
    + +

    {MAX_SIZE_HINT} {MAX_SIZE}

    + {MSG} +
    +
    +
    +
    {MORE}
    +
    + +
    + +
    +
    +
    +
    \ No newline at end of file diff --git a/upload/templates/default/groupcp.tpl b/upload/templates/default/groupcp.tpl new file mode 100644 index 000000000..1bba40ea0 --- /dev/null +++ b/upload/templates/default/groupcp.tpl @@ -0,0 +1,229 @@ +

    {PAGE_TITLE} :: {GROUP_NAME}

    + + + + + + + +++ + + + + + + + + +
    {L_MEMBERSHIP_DETAILS}
    {groups.MEMBERSHIP} +
    + {S_HIDDEN_FIELDS} +
    + {groups.GROUP_SELECT} +
    +
    + +
    +
    +
    + + + + + + + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + + + + + +
    {L_GROUP_INFORMATION}
    {L_GROUP_NAME}:{GROUP_NAME}
    {L_GROUP_DESCRIPTION}:{GROUP_DESCRIPTION}
    {L_GROUP_MEMBERSHIP}:

    {GROUP_DETAILS}

    + +

    +    +

    + + +

    +    +

    + +
    {L_GROUP_TYPE}: +

    +    +    + +

    +

    + +

    +
    + +
    + +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_PRIVATE_MESSAGE}{L_USERNAME}{L_POSTS_SHORT}{L_LOCATION}{L_EMAIL}{L_WEBSITE}{L_SELECT}
    {L_GROUP_MODERATOR}
    {MOD_PM_IMG}{MOD_USERNAME}{MOD_POSTS}{MOD_FROM}{MOD_EMAIL_IMG}{MOD_WWW_IMG} 
    {L_GROUP_MEMBERS}
    {member.PM_IMG}{member.USERNAME}{member.POSTS}{member.FROM}{member.EMAIL_IMG}{member.WWW_IMG} + + + +
    {L_NO_GROUP_MEMBERS}
    {L_HIDDEN_GROUP_MEMBERS}
    +

    + + + +

    +

    + +

    +
    + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_SELECT}{L_USERNAME}{L_POSTS_SHORT}{L_LOCATION}{L_EMAIL}{L_WEBSITE}{L_PRIVATE_MESSAGE}
    {L_PENDING_MEMBERS}
    {pending.USERNAME}{pending.POSTS}{pending.FROM}{pending.EMAIL_IMG}{pending.WWW_IMG}{pending.PM_IMG}
    + +   + +
    + + + +
    + + + + + +
    + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/images/arrow1.gif b/upload/templates/default/images/arrow1.gif new file mode 100644 index 000000000..5350962c7 Binary files /dev/null and b/upload/templates/default/images/arrow1.gif differ diff --git a/upload/templates/default/images/button.gif b/upload/templates/default/images/button.gif new file mode 100644 index 000000000..17660cd2b Binary files /dev/null and b/upload/templates/default/images/button.gif differ diff --git a/upload/templates/default/images/cellpic.gif b/upload/templates/default/images/cellpic.gif new file mode 100644 index 000000000..47457ef5f Binary files /dev/null and b/upload/templates/default/images/cellpic.gif differ diff --git a/upload/templates/default/images/cellpic1.gif b/upload/templates/default/images/cellpic1.gif new file mode 100644 index 000000000..715b8d4aa Binary files /dev/null and b/upload/templates/default/images/cellpic1.gif differ diff --git a/upload/templates/default/images/cellpic2.jpg b/upload/templates/default/images/cellpic2.jpg new file mode 100644 index 000000000..a0ca7e89d Binary files /dev/null and b/upload/templates/default/images/cellpic2.jpg differ diff --git a/upload/templates/default/images/cellpic3.gif b/upload/templates/default/images/cellpic3.gif new file mode 100644 index 000000000..37414bf19 Binary files /dev/null and b/upload/templates/default/images/cellpic3.gif differ diff --git a/upload/templates/default/images/folder.gif b/upload/templates/default/images/folder.gif new file mode 100644 index 000000000..c16bfa75d Binary files /dev/null and b/upload/templates/default/images/folder.gif differ diff --git a/upload/templates/default/images/folder_announce.gif b/upload/templates/default/images/folder_announce.gif new file mode 100644 index 000000000..0589feb14 Binary files /dev/null and b/upload/templates/default/images/folder_announce.gif differ diff --git a/upload/templates/default/images/folder_announce_new.gif b/upload/templates/default/images/folder_announce_new.gif new file mode 100644 index 000000000..56b2702b1 Binary files /dev/null and b/upload/templates/default/images/folder_announce_new.gif differ diff --git a/upload/templates/default/images/folder_big.gif b/upload/templates/default/images/folder_big.gif new file mode 100644 index 000000000..9b2bc47c6 Binary files /dev/null and b/upload/templates/default/images/folder_big.gif differ diff --git a/upload/templates/default/images/folder_dl.gif b/upload/templates/default/images/folder_dl.gif new file mode 100644 index 000000000..e40cbe08b Binary files /dev/null and b/upload/templates/default/images/folder_dl.gif differ diff --git a/upload/templates/default/images/folder_dl_hot.gif b/upload/templates/default/images/folder_dl_hot.gif new file mode 100644 index 000000000..7762869f8 Binary files /dev/null and b/upload/templates/default/images/folder_dl_hot.gif differ diff --git a/upload/templates/default/images/folder_dl_hot_new.gif b/upload/templates/default/images/folder_dl_hot_new.gif new file mode 100644 index 000000000..2fa1b91ec Binary files /dev/null and b/upload/templates/default/images/folder_dl_hot_new.gif differ diff --git a/upload/templates/default/images/folder_dl_new.gif b/upload/templates/default/images/folder_dl_new.gif new file mode 100644 index 000000000..da61bd782 Binary files /dev/null and b/upload/templates/default/images/folder_dl_new.gif differ diff --git a/upload/templates/default/images/folder_hot.gif b/upload/templates/default/images/folder_hot.gif new file mode 100644 index 000000000..a7e8831e2 Binary files /dev/null and b/upload/templates/default/images/folder_hot.gif differ diff --git a/upload/templates/default/images/folder_lock.gif b/upload/templates/default/images/folder_lock.gif new file mode 100644 index 000000000..10eb77697 Binary files /dev/null and b/upload/templates/default/images/folder_lock.gif differ diff --git a/upload/templates/default/images/folder_lock_new.gif b/upload/templates/default/images/folder_lock_new.gif new file mode 100644 index 000000000..720e21028 Binary files /dev/null and b/upload/templates/default/images/folder_lock_new.gif differ diff --git a/upload/templates/default/images/folder_locked_big.gif b/upload/templates/default/images/folder_locked_big.gif new file mode 100644 index 000000000..436f3d21c Binary files /dev/null and b/upload/templates/default/images/folder_locked_big.gif differ diff --git a/upload/templates/default/images/folder_new.gif b/upload/templates/default/images/folder_new.gif new file mode 100644 index 000000000..4e56157dc Binary files /dev/null and b/upload/templates/default/images/folder_new.gif differ diff --git a/upload/templates/default/images/folder_new_big.gif b/upload/templates/default/images/folder_new_big.gif new file mode 100644 index 000000000..5eec565b3 Binary files /dev/null and b/upload/templates/default/images/folder_new_big.gif differ diff --git a/upload/templates/default/images/folder_new_hot.gif b/upload/templates/default/images/folder_new_hot.gif new file mode 100644 index 000000000..25ced64b8 Binary files /dev/null and b/upload/templates/default/images/folder_new_hot.gif differ diff --git a/upload/templates/default/images/folder_sticky.gif b/upload/templates/default/images/folder_sticky.gif new file mode 100644 index 000000000..09861a996 Binary files /dev/null and b/upload/templates/default/images/folder_sticky.gif differ diff --git a/upload/templates/default/images/folder_sticky_new.gif b/upload/templates/default/images/folder_sticky_new.gif new file mode 100644 index 000000000..dd2e36654 Binary files /dev/null and b/upload/templates/default/images/folder_sticky_new.gif differ diff --git a/upload/templates/default/images/hr200_ltr_gradient.jpg b/upload/templates/default/images/hr200_ltr_gradient.jpg new file mode 100644 index 000000000..0cc7e7a4c Binary files /dev/null and b/upload/templates/default/images/hr200_ltr_gradient.jpg differ diff --git a/upload/templates/default/images/hr400_ltr_gradient.jpg b/upload/templates/default/images/hr400_ltr_gradient.jpg new file mode 100644 index 000000000..0e1908abc Binary files /dev/null and b/upload/templates/default/images/hr400_ltr_gradient.jpg differ diff --git a/upload/templates/default/images/icon_delete.gif b/upload/templates/default/images/icon_delete.gif new file mode 100644 index 000000000..1153ba5b2 Binary files /dev/null and b/upload/templates/default/images/icon_delete.gif differ diff --git a/upload/templates/default/images/icon_latest_reply.gif b/upload/templates/default/images/icon_latest_reply.gif new file mode 100644 index 000000000..b45e57aed Binary files /dev/null and b/upload/templates/default/images/icon_latest_reply.gif differ diff --git a/upload/templates/default/images/icon_mini_faq.gif b/upload/templates/default/images/icon_mini_faq.gif new file mode 100644 index 000000000..b8b873d15 Binary files /dev/null and b/upload/templates/default/images/icon_mini_faq.gif differ diff --git a/upload/templates/default/images/icon_mini_groups.gif b/upload/templates/default/images/icon_mini_groups.gif new file mode 100644 index 000000000..be5c2018c Binary files /dev/null and b/upload/templates/default/images/icon_mini_groups.gif differ diff --git a/upload/templates/default/images/icon_mini_login.gif b/upload/templates/default/images/icon_mini_login.gif new file mode 100644 index 000000000..30b309b26 Binary files /dev/null and b/upload/templates/default/images/icon_mini_login.gif differ diff --git a/upload/templates/default/images/icon_mini_members.gif b/upload/templates/default/images/icon_mini_members.gif new file mode 100644 index 000000000..a79a5a74b Binary files /dev/null and b/upload/templates/default/images/icon_mini_members.gif differ diff --git a/upload/templates/default/images/icon_mini_message.gif b/upload/templates/default/images/icon_mini_message.gif new file mode 100644 index 000000000..57071d6e8 Binary files /dev/null and b/upload/templates/default/images/icon_mini_message.gif differ diff --git a/upload/templates/default/images/icon_mini_profile.gif b/upload/templates/default/images/icon_mini_profile.gif new file mode 100644 index 000000000..3dc087189 Binary files /dev/null and b/upload/templates/default/images/icon_mini_profile.gif differ diff --git a/upload/templates/default/images/icon_mini_register.gif b/upload/templates/default/images/icon_mini_register.gif new file mode 100644 index 000000000..11b8f3171 Binary files /dev/null and b/upload/templates/default/images/icon_mini_register.gif differ diff --git a/upload/templates/default/images/icon_mini_search.gif b/upload/templates/default/images/icon_mini_search.gif new file mode 100644 index 000000000..1295e9f1d Binary files /dev/null and b/upload/templates/default/images/icon_mini_search.gif differ diff --git a/upload/templates/default/images/icon_mini_tracker.gif b/upload/templates/default/images/icon_mini_tracker.gif new file mode 100644 index 000000000..4e6607f52 Binary files /dev/null and b/upload/templates/default/images/icon_mini_tracker.gif differ diff --git a/upload/templates/default/images/icon_minipost.gif b/upload/templates/default/images/icon_minipost.gif new file mode 100644 index 000000000..d172abb06 Binary files /dev/null and b/upload/templates/default/images/icon_minipost.gif differ diff --git a/upload/templates/default/images/icon_minipost_new.gif b/upload/templates/default/images/icon_minipost_new.gif new file mode 100644 index 000000000..8ec44a178 Binary files /dev/null and b/upload/templates/default/images/icon_minipost_new.gif differ diff --git a/upload/templates/default/images/icon_minus_1.gif b/upload/templates/default/images/icon_minus_1.gif new file mode 100644 index 000000000..d9fcfcf54 Binary files /dev/null and b/upload/templates/default/images/icon_minus_1.gif differ diff --git a/upload/templates/default/images/icon_minus_2.gif b/upload/templates/default/images/icon_minus_2.gif new file mode 100644 index 000000000..7a1b4f67e Binary files /dev/null and b/upload/templates/default/images/icon_minus_2.gif differ diff --git a/upload/templates/default/images/icon_mod.gif b/upload/templates/default/images/icon_mod.gif new file mode 100644 index 000000000..12084ccd1 Binary files /dev/null and b/upload/templates/default/images/icon_mod.gif differ diff --git a/upload/templates/default/images/icon_newest_reply.gif b/upload/templates/default/images/icon_newest_reply.gif new file mode 100644 index 000000000..eca286183 Binary files /dev/null and b/upload/templates/default/images/icon_newest_reply.gif differ diff --git a/upload/templates/default/images/icon_plus_1.gif b/upload/templates/default/images/icon_plus_1.gif new file mode 100644 index 000000000..6f7abae62 Binary files /dev/null and b/upload/templates/default/images/icon_plus_1.gif differ diff --git a/upload/templates/default/images/icon_plus_2.gif b/upload/templates/default/images/icon_plus_2.gif new file mode 100644 index 000000000..a3d6bda02 Binary files /dev/null and b/upload/templates/default/images/icon_plus_2.gif differ diff --git a/upload/templates/default/images/icon_report.gif b/upload/templates/default/images/icon_report.gif new file mode 100644 index 000000000..19c7c3838 Binary files /dev/null and b/upload/templates/default/images/icon_report.gif differ diff --git a/upload/templates/default/images/icon_reported.gif b/upload/templates/default/images/icon_reported.gif new file mode 100644 index 000000000..d32e26b3b Binary files /dev/null and b/upload/templates/default/images/icon_reported.gif differ diff --git a/upload/templates/default/images/index.html b/upload/templates/default/images/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/upload/templates/default/images/lang_english/icon_edit.gif b/upload/templates/default/images/lang_english/icon_edit.gif new file mode 100644 index 000000000..bb70004b9 Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_edit.gif differ diff --git a/upload/templates/default/images/lang_english/icon_email.gif b/upload/templates/default/images/lang_english/icon_email.gif new file mode 100644 index 000000000..3d359c2a2 Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_email.gif differ diff --git a/upload/templates/default/images/lang_english/icon_icq_add.gif b/upload/templates/default/images/lang_english/icon_icq_add.gif new file mode 100644 index 000000000..4bf276df5 Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_icq_add.gif differ diff --git a/upload/templates/default/images/lang_english/icon_ip.gif b/upload/templates/default/images/lang_english/icon_ip.gif new file mode 100644 index 000000000..bf17a5141 Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_ip.gif differ diff --git a/upload/templates/default/images/lang_english/icon_pm.gif b/upload/templates/default/images/lang_english/icon_pm.gif new file mode 100644 index 000000000..f87b4f57f Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_pm.gif differ diff --git a/upload/templates/default/images/lang_english/icon_profile.gif b/upload/templates/default/images/lang_english/icon_profile.gif new file mode 100644 index 000000000..2bd32d2d7 Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_profile.gif differ diff --git a/upload/templates/default/images/lang_english/icon_quote.gif b/upload/templates/default/images/lang_english/icon_quote.gif new file mode 100644 index 000000000..3dec6756b Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_quote.gif differ diff --git a/upload/templates/default/images/lang_english/icon_search.gif b/upload/templates/default/images/lang_english/icon_search.gif new file mode 100644 index 000000000..8dd38a366 Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_search.gif differ diff --git a/upload/templates/default/images/lang_english/icon_www.gif b/upload/templates/default/images/lang_english/icon_www.gif new file mode 100644 index 000000000..8c1731f3a Binary files /dev/null and b/upload/templates/default/images/lang_english/icon_www.gif differ diff --git a/upload/templates/default/images/lang_english/index.html b/upload/templates/default/images/lang_english/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/upload/templates/default/images/lang_english/msg_newpost.gif b/upload/templates/default/images/lang_english/msg_newpost.gif new file mode 100644 index 000000000..ce2c1a87f Binary files /dev/null and b/upload/templates/default/images/lang_english/msg_newpost.gif differ diff --git a/upload/templates/default/images/lang_english/post.gif b/upload/templates/default/images/lang_english/post.gif new file mode 100644 index 000000000..4b7cb2064 Binary files /dev/null and b/upload/templates/default/images/lang_english/post.gif differ diff --git a/upload/templates/default/images/lang_english/reply-locked.gif b/upload/templates/default/images/lang_english/reply-locked.gif new file mode 100644 index 000000000..5ab1d7a1b Binary files /dev/null and b/upload/templates/default/images/lang_english/reply-locked.gif differ diff --git a/upload/templates/default/images/lang_english/reply.gif b/upload/templates/default/images/lang_english/reply.gif new file mode 100644 index 000000000..cb385af62 Binary files /dev/null and b/upload/templates/default/images/lang_english/reply.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_edit.gif b/upload/templates/default/images/lang_russian/icon_edit.gif new file mode 100644 index 000000000..4471849ad Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_edit.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_email.gif b/upload/templates/default/images/lang_russian/icon_email.gif new file mode 100644 index 000000000..3be32c8c7 Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_email.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_icq_add.gif b/upload/templates/default/images/lang_russian/icon_icq_add.gif new file mode 100644 index 000000000..4d1efe71f Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_icq_add.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_ip.gif b/upload/templates/default/images/lang_russian/icon_ip.gif new file mode 100644 index 000000000..3865d855d Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_ip.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_pm.gif b/upload/templates/default/images/lang_russian/icon_pm.gif new file mode 100644 index 000000000..ec1b8f0a2 Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_pm.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_profile.gif b/upload/templates/default/images/lang_russian/icon_profile.gif new file mode 100644 index 000000000..385c35e21 Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_profile.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_quote.gif b/upload/templates/default/images/lang_russian/icon_quote.gif new file mode 100644 index 000000000..633010d93 Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_quote.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_search.gif b/upload/templates/default/images/lang_russian/icon_search.gif new file mode 100644 index 000000000..4542d84ce Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_search.gif differ diff --git a/upload/templates/default/images/lang_russian/icon_www.gif b/upload/templates/default/images/lang_russian/icon_www.gif new file mode 100644 index 000000000..a684496c5 Binary files /dev/null and b/upload/templates/default/images/lang_russian/icon_www.gif differ diff --git a/upload/templates/default/images/lang_russian/index.html b/upload/templates/default/images/lang_russian/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/upload/templates/default/images/lang_russian/msg_newpost.gif b/upload/templates/default/images/lang_russian/msg_newpost.gif new file mode 100644 index 000000000..92007e6ca Binary files /dev/null and b/upload/templates/default/images/lang_russian/msg_newpost.gif differ diff --git a/upload/templates/default/images/lang_russian/post.gif b/upload/templates/default/images/lang_russian/post.gif new file mode 100644 index 000000000..d9c981214 Binary files /dev/null and b/upload/templates/default/images/lang_russian/post.gif differ diff --git a/upload/templates/default/images/lang_russian/reply-locked.gif b/upload/templates/default/images/lang_russian/reply-locked.gif new file mode 100644 index 000000000..ddbf6d0d0 Binary files /dev/null and b/upload/templates/default/images/lang_russian/reply-locked.gif differ diff --git a/upload/templates/default/images/lang_russian/reply.gif b/upload/templates/default/images/lang_russian/reply.gif new file mode 100644 index 000000000..bbc94626d Binary files /dev/null and b/upload/templates/default/images/lang_russian/reply.gif differ diff --git a/upload/templates/default/images/loading.gif b/upload/templates/default/images/loading.gif new file mode 100644 index 000000000..e846e1d6c Binary files /dev/null and b/upload/templates/default/images/loading.gif differ diff --git a/upload/templates/default/images/loading_1.gif b/upload/templates/default/images/loading_1.gif new file mode 100644 index 000000000..5e62d01af Binary files /dev/null and b/upload/templates/default/images/loading_1.gif differ diff --git a/upload/templates/default/images/menu_open.gif b/upload/templates/default/images/menu_open.gif new file mode 100644 index 000000000..f20639b9b Binary files /dev/null and b/upload/templates/default/images/menu_open.gif differ diff --git a/upload/templates/default/images/menu_open_1.gif b/upload/templates/default/images/menu_open_1.gif new file mode 100644 index 000000000..839d8ac9a Binary files /dev/null and b/upload/templates/default/images/menu_open_1.gif differ diff --git a/upload/templates/default/images/msg_inbox.gif b/upload/templates/default/images/msg_inbox.gif new file mode 100644 index 000000000..011d0bd36 Binary files /dev/null and b/upload/templates/default/images/msg_inbox.gif differ diff --git a/upload/templates/default/images/msg_outbox.gif b/upload/templates/default/images/msg_outbox.gif new file mode 100644 index 000000000..84fdce33e Binary files /dev/null and b/upload/templates/default/images/msg_outbox.gif differ diff --git a/upload/templates/default/images/msg_savebox.gif b/upload/templates/default/images/msg_savebox.gif new file mode 100644 index 000000000..86d1f2cb8 Binary files /dev/null and b/upload/templates/default/images/msg_savebox.gif differ diff --git a/upload/templates/default/images/msg_sentbox.gif b/upload/templates/default/images/msg_sentbox.gif new file mode 100644 index 000000000..b95db7540 Binary files /dev/null and b/upload/templates/default/images/msg_sentbox.gif differ diff --git a/upload/templates/default/images/progress_bar.gif b/upload/templates/default/images/progress_bar.gif new file mode 100644 index 000000000..75cf61c59 Binary files /dev/null and b/upload/templates/default/images/progress_bar.gif differ diff --git a/upload/templates/default/images/progress_bar_full.gif b/upload/templates/default/images/progress_bar_full.gif new file mode 100644 index 000000000..624b0d1f0 Binary files /dev/null and b/upload/templates/default/images/progress_bar_full.gif differ diff --git a/upload/templates/default/images/spacer.gif b/upload/templates/default/images/spacer.gif new file mode 100644 index 000000000..5bfd67a2d Binary files /dev/null and b/upload/templates/default/images/spacer.gif differ diff --git a/upload/templates/default/images/tbl_sort_asc.gif b/upload/templates/default/images/tbl_sort_asc.gif new file mode 100644 index 000000000..74157867f Binary files /dev/null and b/upload/templates/default/images/tbl_sort_asc.gif differ diff --git a/upload/templates/default/images/tbl_sort_bg.gif b/upload/templates/default/images/tbl_sort_bg.gif new file mode 100644 index 000000000..fac668fcf Binary files /dev/null and b/upload/templates/default/images/tbl_sort_bg.gif differ diff --git a/upload/templates/default/images/tbl_sort_desc.gif b/upload/templates/default/images/tbl_sort_desc.gif new file mode 100644 index 000000000..3b30b3c58 Binary files /dev/null and b/upload/templates/default/images/tbl_sort_desc.gif differ diff --git a/upload/templates/default/images/topic_delete.gif b/upload/templates/default/images/topic_delete.gif new file mode 100644 index 000000000..3b21b1108 Binary files /dev/null and b/upload/templates/default/images/topic_delete.gif differ diff --git a/upload/templates/default/images/topic_dl.gif b/upload/templates/default/images/topic_dl.gif new file mode 100644 index 000000000..e40cbe08b Binary files /dev/null and b/upload/templates/default/images/topic_dl.gif differ diff --git a/upload/templates/default/images/topic_lock.gif b/upload/templates/default/images/topic_lock.gif new file mode 100644 index 000000000..fe32fea5e Binary files /dev/null and b/upload/templates/default/images/topic_lock.gif differ diff --git a/upload/templates/default/images/topic_move.gif b/upload/templates/default/images/topic_move.gif new file mode 100644 index 000000000..ab2fd2353 Binary files /dev/null and b/upload/templates/default/images/topic_move.gif differ diff --git a/upload/templates/default/images/topic_normal.gif b/upload/templates/default/images/topic_normal.gif new file mode 100644 index 000000000..c16bfa75d Binary files /dev/null and b/upload/templates/default/images/topic_normal.gif differ diff --git a/upload/templates/default/images/topic_report.gif b/upload/templates/default/images/topic_report.gif new file mode 100644 index 000000000..7ac86b520 Binary files /dev/null and b/upload/templates/default/images/topic_report.gif differ diff --git a/upload/templates/default/images/topic_reported.gif b/upload/templates/default/images/topic_reported.gif new file mode 100644 index 000000000..a7d2bfcf1 Binary files /dev/null and b/upload/templates/default/images/topic_reported.gif differ diff --git a/upload/templates/default/images/topic_split.gif b/upload/templates/default/images/topic_split.gif new file mode 100644 index 000000000..bdbc88428 Binary files /dev/null and b/upload/templates/default/images/topic_split.gif differ diff --git a/upload/templates/default/images/topic_unlock.gif b/upload/templates/default/images/topic_unlock.gif new file mode 100644 index 000000000..dae3e4de6 Binary files /dev/null and b/upload/templates/default/images/topic_unlock.gif differ diff --git a/upload/templates/default/images/treeview/treeview-default-line.gif b/upload/templates/default/images/treeview/treeview-default-line.gif new file mode 100644 index 000000000..37114d306 Binary files /dev/null and b/upload/templates/default/images/treeview/treeview-default-line.gif differ diff --git a/upload/templates/default/images/treeview/treeview-default.gif b/upload/templates/default/images/treeview/treeview-default.gif new file mode 100644 index 000000000..a12ac52ff Binary files /dev/null and b/upload/templates/default/images/treeview/treeview-default.gif differ diff --git a/upload/templates/default/images/vote_lcap.gif b/upload/templates/default/images/vote_lcap.gif new file mode 100644 index 000000000..269088b81 Binary files /dev/null and b/upload/templates/default/images/vote_lcap.gif differ diff --git a/upload/templates/default/images/vote_rcap.gif b/upload/templates/default/images/vote_rcap.gif new file mode 100644 index 000000000..f9584e23a Binary files /dev/null and b/upload/templates/default/images/vote_rcap.gif differ diff --git a/upload/templates/default/images/voting_bar.gif b/upload/templates/default/images/voting_bar.gif new file mode 100644 index 000000000..99473151e Binary files /dev/null and b/upload/templates/default/images/voting_bar.gif differ diff --git a/upload/templates/default/images/whosonline.gif b/upload/templates/default/images/whosonline.gif new file mode 100644 index 000000000..b45092743 Binary files /dev/null and b/upload/templates/default/images/whosonline.gif differ diff --git a/upload/templates/default/index.tpl b/upload/templates/default/index.tpl new file mode 100644 index 000000000..1aab43f07 --- /dev/null +++ b/upload/templates/default/index.tpl @@ -0,0 +1,230 @@ + + +
    + + +
    + + + + + + + + + + + +
    + + + + +
    +

    {c.CAT_TITLE}

    +
    + + + + + + + + + + + + + + + + + + + + + + + +
     {L_FORUM}{L_TOPICS_SHORT}{L_POSTS_SHORT}{L_LASTPOST}
    + {c.f.FORUM_FOLDER_ALT} + + + + + +

    {c.f.FORUM_DESC}

    + + + +

    + {L_SUBFORUMS}: + + {c.f.sf.SF_NAME} + +

    + + + +

    {L_MODERATORS}: {c.f.MODERATORS}

    + + +
    {c.f.TOPICS}{c.f.POSTS} + + + + +
    + {c.f.last.LAST_TOPIC_TITLE} +
    + + +

    + {c.f.last.LAST_POST_TIME} + by + + {c.f.last.LAST_POST_USER_NAME} + + {c.f.last.LAST_POST_USER_NAME} + + +

    + + +

    + {L_TOPICS_SHORT}: {c.f.TOPICS} + {L_POSTS_SHORT}: {c.f.POSTS} +

    + + + {L_NO_POSTS} + + +
    +
    +
    + +
    + + + + + + +
    {NO_FORUMS_MSG}
    +
    + + + +
    + + + + + + + +
    +

    {L_WHOSONLINE}

    +
    + + + + + + +
    +
    +

    {TOTAL_TOPICS}

    +

    {TOTAL_POSTS}

    +

    {TOTAL_USERS}

    +

    {NEWEST_USER}

    + +
    + +

    {TORRENTS_STAT}

    +

    {PEERS_STAT}

    +

    {SPEED_STAT}

    + +
    + +

    {TOTAL_USERS_ONLINE}  {USERS_ONLINE_COUNTS}

    +

    {RECORD_USERS}

    + + + + +
    {LOGGED_IN_USER_LIST}
    + +
    + +

    {L_ONLINE_EXPLAIN}

    +

    + [ {L_ONLINE_ADMIN} ] + [ {L_ONLINE_MOD} ] + [ {L_ONLINE_GROUP_MEMBER} ] +

    + +
    +
    +
    +
    + + +
    + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + + + + + + + + + + +
    new{L_NEW_POSTS}old{L_NO_NEW_POSTS}locked{L_FORUM_LOCKED_MAIN}
    + +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/kb.tpl b/upload/templates/default/kb.tpl new file mode 100644 index 000000000..be9ac5a2d --- /dev/null +++ b/upload/templates/default/kb.tpl @@ -0,0 +1,136 @@ + + + + + + + + + + {L_KB_TITLE} +
    + + {L_TRANSLIT}
    + {L_RULES}
    + {L_HIDE} +
    + + + +
    {L_SHOW}
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RULES}{L_CLOSE}
    а
    б
    в
    г
    д
    е
    - a
    - b
    - v
    - g
    - d
    - e
    ë
    ж
    з
    и
    й
    к
    - 'o
    - 'z ('g)
    - z
    - i
    - j
    - k
    л
    м
    н
    о
    п
    р
    - l
    - m
    - n
    - o
    - p
    - r
    с
    т
    у
    ф
    х
    ц
    - s
    - t
    - u
    - f
    - h
    - c
    ч
    ш
    щ
    ъ
    ы
    ь
    - 'c
    - 's
    - w ('h)
    - ]
    - y
    - [
    э
    ю
    я
    '
    - 'e
    - q ('u)
    - 'a
    - ''
    +
    + +
    + + + + +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + +
    + + + + + + + + + + + + + +
    + + +
    + +
    +
    + + + + + \ No newline at end of file diff --git a/upload/templates/default/login.tpl b/upload/templates/default/login.tpl new file mode 100644 index 000000000..3638e6766 --- /dev/null +++ b/upload/templates/default/login.tpl @@ -0,0 +1,61 @@ + +

    Вход

    + +
    + + + + + + + + + + + + + +
    Вход
    + + +

    {LOGIN_ERR_MSG}

    + +

    Для получения доступа к мод/админ опциям необходимо еще раз ввести пароль

    + +

    Введите ваше имя и пароль

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Имя:readonly="readonly" style="color: gray" />
    Пароль:
    Код:{CAPTCHA_HTML}
    В вашем браузере должны быть включены куки и JavaScript!
    Забыли пароль?
    +
    + +
    + +
    diff --git a/upload/templates/default/memberlist.tpl b/upload/templates/default/memberlist.tpl new file mode 100644 index 000000000..6cdb9f472 --- /dev/null +++ b/upload/templates/default/memberlist.tpl @@ -0,0 +1,83 @@ +

    {PAGE_TITLE}

    + +
    + + + + + + + + + + + +
    {L_SORT_BY}: {S_MODE_SELECT}  {L_ORDER} {S_ORDER_SELECT}  
    +   +
    {L_SORT_PER_LETTER}: {S_LETTER_SELECT}{S_LETTER_HIDDEN}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #{L_USERNAME}PM{L_EMAIL}{L_LOCATION}{L_JOINED}{L_POSTS_SHORT}{L_WEBSITE}
     {no_username.NO_USER_ID_SPECIFIED} 
    {memberrow.ROW_NUMBER}{memberrow.USERNAME}{memberrow.PM}{memberrow.EMAIL} + + + + + +
    {memberrow.FROM}{memberrow.FLAG}
    +
    + {memberrow.JOINED_RAW} + {memberrow.JOINED} + {memberrow.POSTS}{memberrow.WWW}
     
    + +
    + + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/modcp.tpl b/upload/templates/default/modcp.tpl new file mode 100644 index 000000000..750023a09 --- /dev/null +++ b/upload/templates/default/modcp.tpl @@ -0,0 +1,133 @@ +

    {PAGE_TITLE}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_IP_INFO}
    {L_THIS_POST_IP}
    +

    {IP}

    +

    [ {L_LOOKUP_IP}

    +
    {L_OTHER_USERS}
    +

    {userrow.USERNAME}

    +

    [ {L_POSTS}: {userrow.POSTS} ]

    +

    [ {userrow.L_SEARCH_POSTS}

    +
    {L_OTHER_IPS}
    +

    {iprow.IP}

    +

    [ {L_POSTS}: {iprow.POSTS} ]

    +

    [ {L_LOOKUP_IP}

    +
    + + + + + + + + + +{S_HIDDEN_FIELDS} + + + + + + + + +
    {MESSAGE_TITLE}
    + +
    + + + + + +
    {L_MOVE_TO_FORUM} +

    {S_FORUM_SELECT}

    + + + +
    +
    + + +
    + + + + +
    + +

    + + +

    + +
    +
    + + +

    {MESSAGE_TEXT}

    + + + + + + +
    +
    • {TOPIC_TITLES}
    +
    + + +
    +   + +
    + +
    + +
    + + + + + +
    + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/modcp_split.tpl b/upload/templates/default/modcp_split.tpl new file mode 100644 index 000000000..c5f28da35 --- /dev/null +++ b/upload/templates/default/modcp_split.tpl @@ -0,0 +1,95 @@ + + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_SPLIT_TOPIC}
    {L_SPLIT_TOPIC_EXPLAIN}
    {L_NEW_TOPIC_TITLE}
    {L_FORUM_FOR_NEW_TOPIC}{S_FORUM_SELECT}
    + + + + + + +
     
    +
    + + + +
    +
    + + + + + + + + + id="{postrow.ROW_ID}" onclick="toggle_cbox('{postrow.CB_ID}', '{postrow.ROW_ID}');" class="{postrow.ROW_CLASS}"> + + + + + + + + +
    #{L_AUTHOR}{L_MESSAGE}
    +

    {postrow.POSTER_NAME}

    +

    {postrow.POST_DATE}

    +
    +
    +
    {postrow.MESSAGE}
    +
    +
    + + + + + {S_HIDDEN_FIELDS} +
    +
    \ No newline at end of file diff --git a/upload/templates/default/page_footer.tpl b/upload/templates/default/page_footer.tpl new file mode 100644 index 000000000..30f99c8d2 --- /dev/null +++ b/upload/templates/default/page_footer.tpl @@ -0,0 +1,74 @@ + + +
    + + + + + +
    + + +
    + + + + +
    + + + + + + + + + +
    + + + + + + + + + \ No newline at end of file diff --git a/upload/templates/default/page_header.tpl b/upload/templates/default/page_header.tpl new file mode 100644 index 000000000..7e930df7a --- /dev/null +++ b/upload/templates/default/page_header.tpl @@ -0,0 +1,540 @@ + + + + +<!-- IF PAGE_TITLE -->{PAGE_TITLE} :: {SITENAME}<!-- ELSE -->{SITENAME}<!-- ENDIF --> + + +{META} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Loading...
    +
    Error
    + +
    + +
    + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/upload/templates/default/posting_editor.tpl b/upload/templates/default/posting_editor.tpl new file mode 100644 index 000000000..4b169f0b6 --- /dev/null +++ b/upload/templates/default/posting_editor.tpl @@ -0,0 +1,215 @@ + + +
    + +  + +  + +  + +  + + +   + + +  +
    + + +
    + + + +    + + +   + + +   +   + ? +
    + + + +
    +
    + +
    +

    {L_BT_RATIO}

    + +
    {AVATAR}
    + + + + + +
    {L_YOUR_RATIO}{USER_RATIO}{L_NONE} (DL < {MIN_DL_FOR_RATIO})
    {L_DOWNLOADED}{DOWN_TOTAL}
    {L_UPLOADED}{UP_TOTAL}
    {L_RELEASED}{RELEASED}
    {L_BT_BONUS_UP}{UP_BONUS}
    +
    + + + + +
    +
    +
    + + +
    + + +
    +

    {L_LATEST_NEWS}

    + + + + + + + +
    {news.NEWS_TIME}
    +
    +
    + + + +
    {AD_BLOCK_200}
    {AD_BLOCK_100}
    + + + + + + +
    + + +
    {ERROR_MESSAGE}
    +
    + + + +
    + + +
    {INFO_MESSAGE}
    +
    + + + + \ No newline at end of file diff --git a/upload/templates/default/posting.tpl b/upload/templates/default/posting.tpl new file mode 100644 index 000000000..487bfae93 --- /dev/null +++ b/upload/templates/default/posting.tpl @@ -0,0 +1,218 @@ +
    + + + + + + + + + + + + + + + + + + + +
    {L_NEW_POSTS_PREVIEW}
    {L_AUTHOR}{L_MESSAGE}
    +

    + {new_posts.POSTER_NAME} +

    +

    +
    +
    {MINIPOST_IMG_NEW} {new_posts.POST_DATE}
    +
    {new_posts.MESSAGE}
    +
    + +
    + + + + + + + + + + + + + + +
    {L_PREVIEW}
    {PREVIEW_MSG}
    + +
    + + + + + + +
    +{S_HIDDEN_FORM_FIELDS} +{ADD_ATTACH_HIDDEN_FIELDS} +{POSTED_ATTACHMENTS_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {POSTING_TYPE_TITLE}
    {L_USERNAME} +   + +
    {L_SUBJECT}
    +

    {L_MESSAGE_BODY}

    + + + + + + + + + + + + + + +
    {L_MORE_SMILIES}
    + +
    +

    {L_OPTIONS}

    +

    + {BBCODE_STATUS}
    + {SMILIES_STATUS}
    +

    +
    + +
    + + + + + + + + + +
    disabled="disabled" />
    checked="checked" disabled="disabled" />
    +
    + + + +
      
    + +
    + + + + + + + + + + + + + + + + + +
    checked="checked" />
    +
    + + +
    {S_TYPE_TOGGLE}
    + +
    + + + + +
    + + + + + + + + + + + + + + + + +
    {L_TOPIC_REVIEW}
    {L_AUTHOR}{L_MESSAGE}
    +

    + {review.POSTER_NAME} +

    +

    +
    +
    {MINIPOST_IMG} {review.POST_DATE}
    +
    {review.MESSAGE}
    +
    + +
    + + + \ No newline at end of file diff --git a/upload/templates/default/posting_attach.tpl b/upload/templates/default/posting_attach.tpl new file mode 100644 index 000000000..554c43df2 --- /dev/null +++ b/upload/templates/default/posting_attach.tpl @@ -0,0 +1,71 @@ + + + +
    {L_ADD_ATTACH_TITLE}
    {L_FILE_NAME} + + + + + +
    + +

    {L_ADD_ATTACH_EXPLAIN}

    +
    {RULES}
    +
    {L_FILE_COMMENT} + + +
    {L_POSTED_ATTACHMENTS}
    {L_FILE_NAME}{attach_row.FILE_NAME}
    {L_FILE_COMMENT} +   + +
    {L_OPTIONS} + +   + +   + +   + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    А-aД-dИ-iМ-mР-rФ-fШ-shЫ-y
    Б-bЕ-eЙ-jН-nС-sХ-h,xЩ-sz,wЭ-eh
    В-vЖ-zhК-kО-oТ-tЦ-cЬ-'Ю-ju
    Г-gЗ-zЛ-lП-pУ-uЧ-chЪ-#Я-ja
    +
    + + +
    Для отправки сообщений необходимo включить JavaScript
    + + + + + + + + + + + + \ No newline at end of file diff --git a/upload/templates/default/posting_poll.tpl b/upload/templates/default/posting_poll.tpl new file mode 100644 index 000000000..6031308ba --- /dev/null +++ b/upload/templates/default/posting_poll.tpl @@ -0,0 +1,40 @@ + + + {L_ADD_A_POLL} + + + {L_POLL_QUESTION} + + + + + {L_POLL_OPTION} + +   +   + + + + + + {L_POLL_OPTION} + +   + + + + + {L_POLL_LENGTH} + +   + {L_DAYS}   + {L_POLL_LENGTH_EXPLAIN} + + + + + {L_POLL_DELETE} + + + + \ No newline at end of file diff --git a/upload/templates/default/posting_smilies.tpl b/upload/templates/default/posting_smilies.tpl new file mode 100644 index 000000000..d9be37baf --- /dev/null +++ b/upload/templates/default/posting_smilies.tpl @@ -0,0 +1,44 @@ + + + + + + +
    + + + + + + + + + + +
    {L_EMOTICONS}
    + + + + + + + + + + + + + +
    {smilies_row.smilies_col.SMILEY_DESC}
    {L_MORE_SMILIES}

    {L_CLOSE_WINDOW}
    \ No newline at end of file diff --git a/upload/templates/default/privmsgs.tpl b/upload/templates/default/privmsgs.tpl new file mode 100644 index 000000000..433ec13e0 --- /dev/null +++ b/upload/templates/default/privmsgs.tpl @@ -0,0 +1,150 @@ +
    + +
    + + + + + + + + + + + + + +
    {BOX_SIZE_STATUS}
    +
    +
    0%50%100%
    + + + + + + + + + + + + + +
    {BOX_SIZE_STATUS}
    +
    +
    0%50%100%
    + + + + + + + + + + + +
    {INBOX_IMG}{INBOX}{SENTBOX_IMG}{SENTBOX}
    {OUTBOX_IMG}{OUTBOX}{SAVEBOX_IMG}{SAVEBOX}
    + +
    +
    + + +

    {BOX_EXPL}

    + + +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + +
    {POST_PM_IMG} + {L_DISPLAY_MESSAGES}: + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     {L_SUBJECT}{L_FROM_OR_TO}{L_DATE} 
    {listrow.L_PRIVMSG_FOLDER_ALT}{listrow.SUBJECT}{listrow.FROM}{listrow.DATE}
    {L_NO_MESSAGES}
    +
    + +
    +
    +    +   +
    +
    + +
    + +

    + {L_MARK_ALL} + :: + {L_UNMARK_ALL} +

    + + +
    + +
    + + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    + + \ No newline at end of file diff --git a/upload/templates/default/privmsgs_read.tpl b/upload/templates/default/privmsgs_read.tpl new file mode 100644 index 000000000..c567a3540 --- /dev/null +++ b/upload/templates/default/privmsgs_read.tpl @@ -0,0 +1,94 @@ +
    + + + + + + + + + + +
    {INBOX_IMG}{INBOX}{SENTBOX_IMG}{SENTBOX}
    {OUTBOX_IMG}{OUTBOX}{SAVEBOX_IMG}{SAVEBOX}
    + +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + +
    {REPLY_PM_IMG} 
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {BOX_NAME} :: {L_MESSAGE}
    {L_FROM}: {FROM_USER_NAME}
    {L_TO}: {TO_USER_NAME}
    {L_POSTED}: {POST_DATE}
    {L_SUBJECT}: {POST_SUBJECT}
    +
    {PM_MESSAGE}
    +
    {QUOTE_PM_IMG} {EDIT_PM_IMG} {REPORT_PM_IMG}
    +
    +   +   +
    + +
    + + +
    + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + +
    {L_QUICK_REPLY}
    + {L_TO}: +   + {L_SUBJECT}: + +
    +
    + +
    +
    + +
    + \ No newline at end of file diff --git a/upload/templates/default/report_change_body.tpl b/upload/templates/default/report_change_body.tpl new file mode 100644 index 000000000..e7c049dfb --- /dev/null +++ b/upload/templates/default/report_change_body.tpl @@ -0,0 +1,29 @@ + + + + +
    + +
    + + + + + + + + + + + + + + +
    {MESSAGE_TITLE}
    {MESSAGE_TEXT}
    {L_COMMENT}: + +
    + {S_HIDDEN_FIELDS} + + +
    +
    \ No newline at end of file diff --git a/upload/templates/default/report_config_body.tpl b/upload/templates/default/report_config_body.tpl new file mode 100644 index 000000000..cf4823e55 --- /dev/null +++ b/upload/templates/default/report_config_body.tpl @@ -0,0 +1,92 @@ +

    {L_CONFIGURATION_TITLE}

    + +

    {L_CONFIGURATION_EXPLAIN}

    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    + {L_REPORT_SUBJECT_AUTH}:
    + {L_REPORT_SUBJECT_AUTH_EXPLAIN} +
    + +   + +
    + {L_REPORT_MODULES_CACHE}:
    + {L_REPORT_MODULES_CACHE_EXPLAIN} +
    + +   + +
    {L_REPORT_NOTIFY}: + +
    + +
    + +
    {L_REPORT_LIST_ADMIN}: + +   + +
    + {L_REPORT_NEW_WINDOW}:
    + {L_REPORT_NEW_WINDOW_EXPLAIN} +
    + +   + +
    + {S_HIDDEN_FIELDS} + + +
    +
    \ No newline at end of file diff --git a/upload/templates/default/report_form_body.tpl b/upload/templates/default/report_form_body.tpl new file mode 100644 index 000000000..51f5e91ea --- /dev/null +++ b/upload/templates/default/report_form_body.tpl @@ -0,0 +1,72 @@ +
    + + + + +
    + + + + + + +
    + + {switch_report_errors.report_errors.MESSAGE}
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_WRITE_REPORT}
    {L_WRITE_REPORT_EXPLAIN}
    {L_SUBJECT}: + + + + {REPORT_SUBJECT} + + + +
    + +
    + + +
    + {S_HIDDEN_FIELDS} +
    \ No newline at end of file diff --git a/upload/templates/default/report_index_body.tpl b/upload/templates/default/report_index_body.tpl new file mode 100644 index 000000000..70811834c --- /dev/null +++ b/upload/templates/default/report_index_body.tpl @@ -0,0 +1,81 @@ + + + + + + + + + + +
    {L_REPORT_INDEX}
    + {L_STATISTICS}:

    + + + + + + + + + + + +
    {L_STATISTIC}{L_VALUE}
    {report_statistics.STATISTIC}:{report_statistics.VALUE}
    + +
    + + + {L_DELETED_REPORTS}:

    + +
    + + + + + + + + + + + + + + + +
    {L_REPORTS}{L_REPORT_TYPE}
    + {switch_deleted_reports.deleted_reports.TITLE}
    + + {L_BY} {switch_deleted_reports.deleted_reports.AUTHOR} + +
    {switch_deleted_reports.deleted_reports.TYPE}
    + + +
    +
    + + + + + +
    + {L_SELECT_ALL} :: + {L_INVERT_SELECT} +
    + +
    + +
    +
    \ No newline at end of file diff --git a/upload/templates/default/report_list_body.tpl b/upload/templates/default/report_list_body.tpl new file mode 100644 index 000000000..7c87c913b --- /dev/null +++ b/upload/templates/default/report_list_body.tpl @@ -0,0 +1,115 @@ + + + + + + +
    + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_REPORTS}
    {L_REPORT_INDEX}
    {report_modules.TITLE}
    + + + + {report_modules.reports.TITLE}
    + +
    + + + {L_BY} {report_modules.reports.AUTHOR} + +
    {L_NO_REPORTS}
    + + +
    +
    + + {L_SELECT_ALL} :: + {L_INVERT_SELECT} + +
    + {REPORT_VIEW} +
    \ No newline at end of file diff --git a/upload/templates/default/report_module_edit_body.tpl b/upload/templates/default/report_module_edit_body.tpl new file mode 100644 index 000000000..07b0a194b --- /dev/null +++ b/upload/templates/default/report_module_edit_body.tpl @@ -0,0 +1,96 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_EDIT_MODULE}
    {L_REPORT_MODULE}: + {MODULE_TITLE}
    + {MODULE_EXPLAIN} +
    {L_REPORT_NOTIFY}: + +   + +
    + :
    + {L_REPORT_PRUNE_EXPLAIN} +
    + + {L_DAYS} +
    {L_REPORT_PERMISSIONS}
    + : + + +
    + : + + +
    + :
    + {L_AUTH_NOTIFY_EXPLAIN} +
    + +
    + :
    + {L_AUTH_DELETE_EXPLAIN} +
    + +
    + {S_HIDDEN_FIELDS} + + +
    +
    \ No newline at end of file diff --git a/upload/templates/default/report_module_reasons_body.tpl b/upload/templates/default/report_module_reasons_body.tpl new file mode 100644 index 000000000..5874fdf87 --- /dev/null +++ b/upload/templates/default/report_module_reasons_body.tpl @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + +
    {L_REPORT_REASON}{L_ACTION}
    {report_reasons.DESC} + {L_EDIT} | + {L_MOVE_UP} | + {L_MOVE_DOWN} | + {L_DELETE} +
    {L_NO_REASONS}
    + {L_ADD_REASON} | + {L_BACK_MODULES} +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/report_modules_body.tpl b/upload/templates/default/report_modules_body.tpl new file mode 100644 index 000000000..b2f186b81 --- /dev/null +++ b/upload/templates/default/report_modules_body.tpl @@ -0,0 +1,65 @@ +

    {L_REPORTS_TITLE}

    + +

    {L_REPORTS_EXPLAIN}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_REPORT_MODULE}{L_REPORT_COUNT}{L_ACTION}
    {L_INSTALLED_MODULES}
    + {installed_modules.modules.MODULE_TITLE}
    + {installed_modules.modules.MODULE_EXPLAIN} +
    {installed_modules.modules.REPORT_COUNT} + {L_EDIT} | + {installed_modules.modules.L_REASONS} | + + {L_SYNC} | + + {L_MOVE_UP} | + {L_MOVE_DOWN} | + {L_UNINSTALL} +
    {L_NO_MODULES_INSTALLED}
    {L_INACTIVE_MODULES}
    + {inactive_modules.modules.MODULE_TITLE}
    + {inactive_modules.modules.MODULE_EXPLAIN} +
    {inactive_modules.modules.REPORT_COUNT} + {L_INSTALL} +
    {L_NO_MODULES_INACTIVE}
    + +
    \ No newline at end of file diff --git a/upload/templates/default/report_open_body.tpl b/upload/templates/default/report_open_body.tpl new file mode 100644 index 000000000..84a41262b --- /dev/null +++ b/upload/templates/default/report_open_body.tpl @@ -0,0 +1,90 @@ + + + + + + +
    + +
    + + + + + + + + + + + + + +
    {L_OPEN_REPORTS}
    + {open_reports.TITLE}
    + + {L_BY} {open_reports.AUTHOR} + +
    + + +
    +
    + + + + + +
    + {L_SELECT_ALL} :: + {L_INVERT_SELECT} +
    \ No newline at end of file diff --git a/upload/templates/default/report_reason_edit_body.tpl b/upload/templates/default/report_reason_edit_body.tpl new file mode 100644 index 000000000..dfa938f68 --- /dev/null +++ b/upload/templates/default/report_reason_edit_body.tpl @@ -0,0 +1,36 @@ +
    + + + + + +
    + + {switch_report_errors.report_errors.MESSAGE}
    + +
    +
    + + + + + + + + + + + + + +
    {L_EDIT_REASON}
    + :
    + {L_REASON_DESC_EXPLAIN} +
    + +
    + {S_HIDDEN_FIELDS} + + +
    +
    \ No newline at end of file diff --git a/upload/templates/default/report_view_body.tpl b/upload/templates/default/report_view_body.tpl new file mode 100644 index 000000000..732514af3 --- /dev/null +++ b/upload/templates/default/report_view_body.tpl @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + +
    {REPORT_TYPE}
    + {REPORT_TITLE}

    + + + + + + +
    {L_REPORT_SUBJECT_DELETED}
    +
    + + + + + + + + + + + + + + + + +
    {L_SUBJECT}: + + + + {REPORT_SUBJECT} + + + +
    {report_subject.details.TITLE}:{report_subject.details.VALUE}
    +
    + + + + + + + + + + + + + + + + + + + + + +
    {L_REPORTED_BY}: + {REPORT_AUTHOR}  + [ {L_SEND_PRIVMSG} ] +
    {L_REPORTED_TIME}:{REPORT_TIME}
    {L_REASON}:{REPORT_REASON}
    {L_MESSAGE}:{REPORT_DESC}
    + +
    + + + + + + + + + + + + +
    {L_STATUS}: +
    + {REPORT_STATUS} +
    {L_LAST_CHANGED_BY}: + {REPORT_LAST_CHANGE_USER} ({REPORT_LAST_CHANGE_TIME}) +
    + +
    +
    {L_CHANGES}
    {switch_report_changes.report_changes.TEXT}
    +
    + + + + + + + {S_HIDDEN_FIELDS} +
    +
    \ No newline at end of file diff --git a/upload/templates/default/rss_body.tpl b/upload/templates/default/rss_body.tpl new file mode 100644 index 000000000..c0b0521cd --- /dev/null +++ b/upload/templates/default/rss_body.tpl @@ -0,0 +1,41 @@ + + + + + + +{BOARD_TITLE} +{BOARD_URL} +{BOARD_DESCRIPTION} +{BOARD_MANAGING_EDITOR} +http://blogs.law.harvard.edu/tech/rss +{PROGRAM}{LANGUAGE} +{BUILD_DATE} + + {BOARD_URL}images/logo/logo.gif + {BOARD_TITLE} + {BOARD_URL} + 122 + 56 + + + +{post_item.FORUM_NAME} :: {post_item.TOPIC_TITLE} +{post_item.POST_URL} +{post_item.UTF_TIME} +{post_item.POST_URL} +{L_AUTHOR}: {post_item.AUTHOR}<br /> +{post_item.POST_SUBJECT} +{L_POSTED}: {post_item.POST_TIME}<br /> +<br /><span class="postbody"> +{post_item.POST_TEXT}{post_item.USER_SIG}</span><br /> + +{post_item.AUTHOR0} +{post_item.FORUM_NAME} + +{post_item.REPLY_URL} + + + + \ No newline at end of file diff --git a/upload/templates/default/search.tpl b/upload/templates/default/search.tpl new file mode 100644 index 000000000..8b2fca8ff --- /dev/null +++ b/upload/templates/default/search.tpl @@ -0,0 +1,171 @@ + + + + +

    {PAGE_TITLE}

    + + + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + + + + + +
    {L_SEARCH_OPTIONS}
    +
    + {L_SEARCH_WORDS} [?] +
    +

    +

    {TITLE_ONLY_CHBOX}  {ALL_WORDS_CHBOX}

    +
    +
    +
    +
    + {L_SEARCH_AUTHOR} +
    +

    +   + +

    +

    + + {MY_TOPICS_CHBOX} +

    +
    +
    +
    +

    {$bb_cfg['search_help_url']}

    +

    {L_SEARCH_WORDS_EXPL}

    +
    +
    + {L_FORUM}: +
    +

    {FORUM_SELECT}

    +
    +
    +
    +
    + {L_MY_DOWNLOADS} +
    + + + + + + + + + +
    {DL_COMPL_CHBOX}{DL_WILL_CHBOX}
    {DL_DOWN_CHBOX}{DL_CANCEL_CHBOX}
    +
    +
    +
    + {L_SEARCH_PREVIOUS}: +
    +

    {TIME_SELECT}

    +

    {ONLY_NEW_CHBOX}  {NEW_TOPICS_CHBOX}

    +
    +
    +
    + {L_DISPLAY_RESULTS_AS}: +
    +

    {DISPLAY_AS_SELECT} {CHARS_SELECT}

    +
    +
    +
    + {L_SORT_BY}: +
    +

    {ORDER_SELECT} {SORT_SELECT}

    +
    +
    +
    + +
    + +
    + + +
    + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    + + + + + + + + + +
    + + + + + + + + +
    {L_FIND_USERNAME}
    +

    +   + +

    +

    {L_SEARCH_AUTHOR_EXPL}

    + +
    {L_SELECT_USERNAME}
    +

    +   + +

    + +
    + {L_CLOSE_WINDOW} +
    + +
    + + + \ No newline at end of file diff --git a/upload/templates/default/search_results.tpl b/upload/templates/default/search_results.tpl new file mode 100644 index 000000000..52c6e96b1 --- /dev/null +++ b/upload/templates/default/search_results.tpl @@ -0,0 +1,162 @@ + +

    {SEARCH_MATCHES}

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_AUTHOR}{L_MESSAGE}
    + +

    {t.p.POSTER_NAME}

    +

    + +
    + +
    +

    + {MINIPOST_IMG_NEW}{MINIPOST_IMG} + {t.p.POST_DATE} + + ({L_POSTED_AFTER} {t.p.POSTED_AFTER}) + +

    + +

    + {QUOTE_IMG}{POST_BTN_SPACER} + {EDIT_POST_IMG}{POST_BTN_SPACER} + {DELETE_POST_IMG}{POST_BTN_SPACER} + {IP_POST_IMG}{POST_BTN_SPACER} +

    +
    +
    + +
    +
    {t.p.MESSAGE}
    +
    + +
     
    + + + + +
    + + + +++++++ + + + + + + + + + + + + + + + + + + + + +
     {L_FORUM}{L_TOPICS}{L_AUTHOR}{L_REPLIES_SHORT}{L_LASTPOST}
    + + + + + + {t.FORUM_NAME} +
    + {ICON_NEWEST_REPLY} + {L_MOVED} + {L_ANNOUNCE} + {L_DL_TOPIC} + {TOPIC_ATTACH_ICON} + + {L_POLL} + {t.TOPIC_TITLE} + [{ICON_GOTOPOST}{L_GOTO_SHORT} {t.PAGINATION} ] +
    +
    {t.TOPIC_AUTHOR_NAME}{t.TOPIC_AUTHOR_NAME}{t.REPLIES} +

    {t.LAST_POST_TIME}

    +

    + {t.LAST_POSTER_NAME}{t.LAST_POSTER_NAME} + {ICON_LATEST_REPLY} +

    +
    + + + + + + + + +   + +
    + + +
    + + + + +
    + + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/topic_templates/audiobooks.tpl b/upload/templates/default/topic_templates/audiobooks.tpl new file mode 100644 index 000000000..f1fd39881 --- /dev/null +++ b/upload/templates/default/topic_templates/audiobooks.tpl @@ -0,0 +1,160 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_AUTHOR}:
    {L_PERFORMER}:
    {L_GENRE}:
    {L_PUBLISHER}:
    {L_FORMAT}: +   +   + {L_AUDIO_BITRATE}: +
    {L_DESCRIPTION}:
    {L_MOREINFO}:
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/books.tpl b/upload/templates/default/topic_templates/books.tpl new file mode 100644 index 000000000..c9c9e6f53 --- /dev/null +++ b/upload/templates/default/topic_templates/books.tpl @@ -0,0 +1,148 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_AUTHOR}:
    {L_GENRE}:
    {L_PUBLISHER}:
    {L_ISBN}: +    + {L_EDITION}: +
    {L_FORMAT}: +   + {L_PAGES_COUNT}: +
    {L_QUALITY}:
    {L_DESCRIPTION}:
    {L_MOREINFO}:
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/games.tpl b/upload/templates/default/topic_templates/games.tpl new file mode 100644 index 000000000..e2d7a9e37 --- /dev/null +++ b/upload/templates/default/topic_templates/games.tpl @@ -0,0 +1,151 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_GENRE}:
    {L_DEVELOPER}:
    {L_PUBLISHER}:
    {L_SOURCE_TYPE}: +   + {L_LOCALIZATION}:   + {L_MEDICINE}: +
    {L_PLATFORM}:
    {L_SYSREQ}:
    {L_DESCRIPTION}:
    {L_MOREINFO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/games_ps.tpl b/upload/templates/default/topic_templates/games_ps.tpl new file mode 100644 index 000000000..2f2452012 --- /dev/null +++ b/upload/templates/default/topic_templates/games_ps.tpl @@ -0,0 +1,157 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_GENRE}:
    {L_DEVELOPER}:
    {L_PUBLISHER}:
    {L_SOURCE_TYPE}: + {L_PLATFORM}:   + {L_REGION}:   + {L_MULTIPLAYER}:   +
    {L_TRANSLATION}: + {L_LOCALIZATION}:   + {L_TRANSLATION_TYPE}:   +
    {L_MEDIUM}: +   + {L_AGE}: +
    {L_DESCRIPTION}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/games_psp.tpl b/upload/templates/default/topic_templates/games_psp.tpl new file mode 100644 index 000000000..b1c82b6c6 --- /dev/null +++ b/upload/templates/default/topic_templates/games_psp.tpl @@ -0,0 +1,146 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_GENRE}:
    {L_DEVELOPER}:
    {L_PUBLISHER}:
    {L_SOURCE_TYPE}: + {L_VERSION}:   + {L_CD_IMAGE_TYPE}:   + {L_FIRMWARE}:   +
    {L_TRANSLATION}: + {L_LOCALIZATION}:   + {L_TRANSLATION_TYPE}:   +
    {L_DESCRIPTION}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/games_xbox.tpl b/upload/templates/default/topic_templates/games_xbox.tpl new file mode 100644 index 000000000..88548f060 --- /dev/null +++ b/upload/templates/default/topic_templates/games_xbox.tpl @@ -0,0 +1,153 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_GENRE}:
    {L_DEVELOPER}:
    {L_PUBLISHER}:
    {L_FIRMWARE}: +   +
    {L_SOURCE_TYPE}: +   + {L_REGION}:   + {L_CAN_PLAY_XBOX360}:   +
    {L_TRANSLATION}: + {L_LOCALIZATION}:   + {L_TRANSLATION_TYPE}:   +
    {L_DESCRIPTION}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/music.tpl b/upload/templates/default/topic_templates/music.tpl new file mode 100644 index 000000000..d5bc1a0a3 --- /dev/null +++ b/upload/templates/default/topic_templates/music.tpl @@ -0,0 +1,154 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_COVER}: URL
    {L_YEAR}:
    {L_COUNTRY}:
    {L_GENRE}:
    {L_PLAYTIME}:
    {L_FORMAT}: +   + {L_AUDIO_BITRATE}:   +
    {L_TRACKLIST}:
    {L_MOREINFO}:
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/progs.tpl b/upload/templates/default/topic_templates/progs.tpl new file mode 100644 index 000000000..60b6c262f --- /dev/null +++ b/upload/templates/default/topic_templates/progs.tpl @@ -0,0 +1,150 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_VERSION}: +   +   +
    {L_DEVELOPER}:
    {L_DEVELOPER_URL}: URL
    {L_PLATFORM}: + +   +   +
    {L_SYS_REQUIREMENTS}:
    {L_DESCRIPTION}:
    {L_MOREINFO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/progs_mac.tpl b/upload/templates/default/topic_templates/progs_mac.tpl new file mode 100644 index 000000000..91a752620 --- /dev/null +++ b/upload/templates/default/topic_templates/progs_mac.tpl @@ -0,0 +1,151 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}:
    {L_PICTURE}: URL
    {L_YEAR}:
    {L_VERSION}:
    {L_DEVELOPER}:
    {L_DEVELOPER_URL}: URL
    {L_PLATFORM}: +   +   +   +
    {L_SYS_REQUIREMENTS}:
    {L_DESCRIPTION}:
    {L_MOREINFO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/sport.tpl b/upload/templates/default/topic_templates/sport.tpl new file mode 100644 index 000000000..d928152e8 --- /dev/null +++ b/upload/templates/default/topic_templates/sport.tpl @@ -0,0 +1,154 @@ + + +

    {FORUM_NAME}

    + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}{L_TITLE}:
    {L_PICTURE}{L_PICTURE}: URL
    {L_SPORT_TYPE}{L_SPORT_TYPE}:
    {L_PARTICIPANTS}{L_PARTICIPANTS}:
    {L_PLAYTIME}{L_PLAYTIME}:
    {L_YEAR}{L_YEAR}:
    {L_COMMENTS}{L_COMMENTS}:
    {L_DESCRIPTION}{L_DESCRIPTION}:
    {L_MOREINFO}{L_MOREINFO}:
    {L_FORMAT}{L_FORMAT}: +   +   +   +   +
    {L_VIDEO}{L_VIDEO}:
    {L_AUDIO}{L_AUDIO}:
    {L_TORRENT}{L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/video.tpl b/upload/templates/default/topic_templates/video.tpl new file mode 100644 index 000000000..311eede5f --- /dev/null +++ b/upload/templates/default/topic_templates/video.tpl @@ -0,0 +1,171 @@ + + +

    {FORUM_NAME}

    + + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}{L_TITLE}: {L_TITLE_DESC}
    {L_ORIGINAL_TITLE}{L_ORIGINAL_TITLE}: {L_ORIGINAL_TITLE_DESC}
    {L_PICTURE}{L_PICTURE}: URL
    {L_COUNTRY}{L_COUNTRY}:
    {L_DIRECTOR}{L_DIRECTOR}:
    {L_GENRE}{L_GENRE}:
    {L_PLAYTIME}{L_PLAYTIME}:
    {L_YEAR}{L_YEAR}:
    {L_TRANSLATION}{L_TRANSLATION}:
    {L_CASTING}{L_CASTING}:
    {L_DESCRIPTION}{L_DESCRIPTION}:
    {L_MOREINFO}{L_MOREINFO}:
    {L_FORMAT}{L_FORMAT}: +   +   +   +   +
    {L_VIDEO}{L_VIDEO}:
    {L_AUDIO}{L_AUDIO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}{L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/video_home.tpl b/upload/templates/default/topic_templates/video_home.tpl new file mode 100644 index 000000000..36691588d --- /dev/null +++ b/upload/templates/default/topic_templates/video_home.tpl @@ -0,0 +1,159 @@ + + +

    {FORUM_NAME}

    + + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}{L_TITLE}:
    {L_PICTURE}{L_PICTURE}: URL
    {L_DIRECTOR}{L_DIRECTOR}:
    {L_GENRE}{L_GENRE}:
    {L_PLAYTIME}{L_PLAYTIME}:
    {L_YEAR}{L_YEAR}:
    {L_CASTING}{L_CASTING}:
    {L_DESCRIPTION}{L_DESCRIPTION}:
    {L_MOREINFO}{L_MOREINFO}:
    {L_FORMAT}{L_FORMAT}: +   +   +   +   +
    {L_VIDEO}{L_VIDEO}:
    {L_AUDIO}{L_AUDIO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}{L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/video_lesson.tpl b/upload/templates/default/topic_templates/video_lesson.tpl new file mode 100644 index 000000000..3f32160e7 --- /dev/null +++ b/upload/templates/default/topic_templates/video_lesson.tpl @@ -0,0 +1,136 @@ + + +

    {FORUM_NAME}

    + + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}{L_TITLE}:
    {L_YEAR}{L_YEAR}:
    {L_MANUFACTURER}:
    {L_MANUFACTURER_URL}: URL
    {L_DESCRIPTION}{L_DESCRIPTION}:
    {L_FORMAT}{L_FORMAT}: +   + +
    {L_VIDEO}{L_VIDEO}:
    {L_AUDIO}{L_AUDIO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}{L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/topic_templates/video_simple.tpl b/upload/templates/default/topic_templates/video_simple.tpl new file mode 100644 index 000000000..786ca599b --- /dev/null +++ b/upload/templates/default/topic_templates/video_simple.tpl @@ -0,0 +1,151 @@ + + +

    {FORUM_NAME}

    + + + + + + +
    + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_RELEASE_WELCOME}
    {L_TITLE}{L_TITLE}:
    {L_PICTURE}{L_PICTURE}: URL
    {L_COUNTRY}:
    {L_GENRE}{L_GENRE}:
    {L_PLAYTIME}{L_PLAYTIME}:
    {L_YEAR}{L_YEAR}:
    {L_DESCRIPTION}{L_DESCRIPTION}:
    {L_FORMAT}{L_FORMAT}: +   +   +   +   +
    {L_VIDEO}{L_VIDEO}:
    {L_AUDIO}{L_AUDIO}:
    {L_SCREEN_SHOTS}: URLs
    {L_TORRENT}{L_TORRENT}: +

    +

    {L_TORRENT_EXP}

    +
    + +
    + +
    diff --git a/upload/templates/default/torhelp.tpl b/upload/templates/default/torhelp.tpl new file mode 100644 index 000000000..e8f8592de --- /dev/null +++ b/upload/templates/default/torhelp.tpl @@ -0,0 +1,28 @@ + + +
    + + + + + + +
    {L_TORHELP_TITLE}
    +

    [ + {L_HIDE} + ]

    +
    • {TORHELP_TOPICS}
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/tpl_config.php b/upload/templates/default/tpl_config.php new file mode 100644 index 000000000..0560ad68d --- /dev/null +++ b/upload/templates/default/tpl_config.php @@ -0,0 +1,191 @@ +assign_vars(array( + 'IMG' => $_main, + + 'TEXT_BUTTONS' => $bb_cfg['text_buttons'], + 'POST_BTN_SPACER' => ($bb_cfg['text_buttons']) ? ' ' : '', + 'TOPIC_ATTACH_ICON' => '', + 'ATTACHMENT_ICON' => '', + 'OPEN_MENU_IMG_ALT1' => '', + + 'TOPIC_LEFT_COL_SPACER_WITDH' => $bb_cfg['topic_left_column_witdh'] - 8, // 8px padding +// Images auto-resize + 'POST_IMG_WIDTH_DECR_JS' => $bb_cfg['topic_left_column_witdh'] + $bb_cfg['post_img_width_decr'], + 'ATTACH_IMG_WIDTH_DECR_JS' => $bb_cfg['topic_left_column_witdh'] + $bb_cfg['attach_img_width_decr'], + + 'MAGNET_LINKS' => $bb_cfg['magnet_links_enabled'], +)); + +// post_buttons +if (!empty($page_cfg['load_tpl_vars']) AND $vars = array_flip($page_cfg['load_tpl_vars'])) +{ + if (isset($vars['post_buttons'])) + { + $template->assign_vars(array( + 'QUOTE_IMG' => ($bb_cfg['text_buttons']) ? $lang['REPLY_WITH_QUOTE_TXTB'] : 'Quote', + 'EDIT_POST_IMG' => ($bb_cfg['text_buttons']) ? $lang['EDIT_DELETE_POST_TXTB'] : 'Edit', + 'DELETE_POST_IMG' => ($bb_cfg['text_buttons']) ? $lang['DELETE_POST_TXTB'] : 'Delete', + 'IP_POST_IMG' => ($bb_cfg['text_buttons']) ? $lang['VIEW_IP_TXTB'] : 'IP', + 'MOD_POST_IMG' => ($bb_cfg['text_buttons']) ? $lang['MODERATE_POST_TXTB'] : 'Moderate', + + 'QUOTE_URL' => BB_ROOT ."posting.php?mode=quote&p=", + 'EDIT_POST_URL' => BB_ROOT ."posting.php?mode=editpost&p=", + 'DELETE_POST_URL' => BB_ROOT ."posting.php?mode=delete&p=", + 'IP_POST_URL' => BB_ROOT ."modcp.php?mode=ip&p=", + + 'PROFILE_IMG' => ($bb_cfg['text_buttons']) ? $lang['READ_PROFILE_TXTB'] : 'Profile', + 'PM_IMG' => ($bb_cfg['text_buttons']) ? $lang['SEND_PM_TXTB'] : 'PM', + 'EMAIL_IMG' => ($bb_cfg['text_buttons']) ? $lang['SEND_EMAIL_TXTB'] : 'email', + 'WWW_IMG' => ($bb_cfg['text_buttons']) ? $lang['VISIT_WEBSITE_TXTB'] : 'www', + 'ICQ_IMG' => ($bb_cfg['text_buttons']) ? $lang['ICQ_TXTB'] : 'ICQ', + + 'EMAIL_URL' => BB_ROOT ."profile.php?mode=email&u=", + 'FORUM_URL' => BB_ROOT . FORUM_URL, + 'ICQ_URL' => 'http://wwp.icq.com/scripts/search.dll?to=', + 'PM_URL' => BB_ROOT . PM_URL, + 'PROFILE_URL' => BB_ROOT . PROFILE_URL, + )); + } + if (isset($vars['post_icons'])) + { + $template->assign_vars(array( + 'MINIPOST_IMG' => 'post', + 'ICON_GOTOPOST' => 'goto', + 'MINIPOST_IMG_NEW' => 'new', + 'ICON_LATEST_REPLY' => 'latest', + 'ICON_NEWEST_REPLY' => 'newest', + )); + } + if (isset($vars['topic_icons'])) + { + $template->assign_vars(array( + 'MOVED' => TOPIC_MOVED, + 'ANNOUNCE' => POST_ANNOUNCE, + 'STICKY' => POST_STICKY, + 'LOCKED' => TOPIC_LOCKED, + 'L_MOVED' => $lang['TOPIC_MOVED'], + 'L_ANNOUNCE' => $lang['TOPIC_ANNOUNCEMENT'], + 'L_DL_TOPIC' => $lang['TOPIC_DL'], + 'L_POLL' => $lang['TOPIC_POLL'], + )); + } + if (isset($vars['pm_icons'])) + { + $template->assign_vars(array( + 'INBOX_IMG' => '', + 'OUTBOX_IMG' => '', + 'SENTBOX_IMG' => '', + 'SAVEBOX_IMG' => '', + )); + } +} \ No newline at end of file diff --git a/upload/templates/default/tracker.tpl b/upload/templates/default/tracker.tpl new file mode 100644 index 000000000..40339f8b9 --- /dev/null +++ b/upload/templates/default/tracker.tpl @@ -0,0 +1,439 @@ + + + + + + + + + + + + + +

    {PAGE_TITLE}

    + + + + + +
    + + + + + + + +
    +{S_HIDDEN_FIELDS} + + ++ + + + + + + + + +
    {L_TOR_SEARCH_TITLE}
    + + + + + + + + + + +
    +
    + + + + +
    +

    {CAT_FORUM_SELECT}

    +

    +
    +
    +
    +
    + {L_SORT_BY} +
    +

    {ORDER_SELECT}

    +

    +

    +
    +
    +
    + {L_TORRENTS_FROM} +
    +

    {TIME_SELECT}

    +
    +
    +
    + {L_SEED_NOT_SEEN} +
    +

    {S_NOT_SEEN_SELECT}

    +
    +
    +
    +
    + {L_SHOW_ONLY} +
    +

    {ONLY_MY_CHBOX}[®]

    +

    {ONLY_ACTIVE_CHBOX}

    +

    {SEED_EXIST_CHBOX}

    +

    {ONLY_NEW_CHBOX}[{MINIPOST_IMG_NEW}] 

    +
    +
    +
    + {L_MY_DOWNLOADS} +
    + + + + + + + + + +
    {DL_COMPL_CHBOX}{DL_WILL_CHBOX}
    {DL_DOWN_CHBOX}{DL_CANCEL_CHBOX}
    +
    +
    +
    +
    + {L_SHOW_COLUMN} +
    +

    {SHOW_CAT_CHBOX}  {SHOW_FORUM_CHBOX}  {SHOW_AUTHOR_CHBOX}  {SHOW_SPEED_CHBOX} 

    +
    +
    +
    + {L_AUTHOR} +
    +

    style="color: red" class="post" type="text" size="16" maxlength="{POSTER_NAME_MAX}" name="{POSTER_NAME_NAME}" value="{POSTER_NAME_VAL}" />

    +
    +
    +
    + {L_TITLE_MATCH} +
    +

    + +

    +

    + {ALL_WORDS_CHBOX} ·  + Помощь по поиску +

    +
    +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    + + + + + + + +
    +   + + {L_DISPLAYING_OPTIONS} + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {L_CATEGORY}{L_FORUM}{L_TOPIC}{L_AUTHOR}{L_SIZE}SLCSP{L_ADDED}

     ® 

    {MINIPOST_IMG_NEW}{MINIPOST_IMG}
    {tor.TOR_STATUS_ICON}{tor.CAT_TITLE}{tor.FORUM_NAME} + onclick="ajax.view_post({tor.POST_ID}, this); return false;" href="{TOPIC_URL}{tor.TOPIC_ID}">{tor.TOPIC_TITLE}{tor.TOR_TYPE}{tor.TOPIC_TITLE} + {tor.USERNAME} + {tor.TOR_SIZE_RAW} + {tor.TOR_SIZE} {tor.MAGNET} + {tor.TOR_SIZE} + {tor.SEEDS}{tor.LEECHS}{tor.COMPLETED} +

    {tor.UL_SPEED}

    +

    {tor.DL_SPEED}

    +
    + {tor.ADDED_RAW} +

    {tor.ADDED_TIME}

    +

    {tor.ADDED_DATE}

    +
    {NO_MATCH_MSG}
     
    + +
    + + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    + + \ No newline at end of file diff --git a/upload/templates/default/usercp_attachcp.tpl b/upload/templates/default/usercp_attachcp.tpl new file mode 100644 index 000000000..87f8bb50e --- /dev/null +++ b/upload/templates/default/usercp_attachcp.tpl @@ -0,0 +1,113 @@ +

    {L_UACP} :: {USERNAME}

    + +
    +{S_USER_HIDDEN} + + + + + + +
    + {L_SORT_BY}: {S_MODE_SELECT} + {L_ORDER} {S_ORDER_SELECT} + +
    + + + + ++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #{L_POSTED_IN_TOPIC}{L_FILENAME}{L_FILECOMMENT}{L_EXTENSION}{L_SIZE}{L_DOWNLOADS}{L_POST_TIME}{L_DELETE}
    {attachrow.ROW_NUMBER}{attachrow.POST_TITLE}{attachrow.FILENAME}{attachrow.COMMENT}{attachrow.EXTENSION} + {attachrow.SIZE_RAW} +

    {attachrow.SIZE}

    +
    {attachrow.DOWNLOAD_COUNT} + {attachrow.POST_TIME_RAW} + {attachrow.POST_TIME} + {attachrow.S_DELETE_BOX}{attachrow.S_HIDDEN}
    + +
    + +
    + +

    + {L_MARK_ALL} + :: + {L_UNMARK_ALL} +

    + + +
    + +
    + + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    + + \ No newline at end of file diff --git a/upload/templates/default/usercp_avatar_gallery.tpl b/upload/templates/default/usercp_avatar_gallery.tpl new file mode 100644 index 000000000..b679896ad --- /dev/null +++ b/upload/templates/default/usercp_avatar_gallery.tpl @@ -0,0 +1,35 @@ + + +
    +{S_HIDDEN_FIELDS} + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_AVATAR_GALLERY}
    {L_SELECT_CATEGORY}: {S_CATEGORY_SELECT}
    +    + +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/usercp_email.tpl b/upload/templates/default/usercp_email.tpl new file mode 100644 index 000000000..8bc717d18 --- /dev/null +++ b/upload/templates/default/usercp_email.tpl @@ -0,0 +1,73 @@ +
    + + + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + + + + + + +
    {L_SEND_EMAIL_MSG}
    {L_RECIPIENT}{USERNAME}
    {L_SUBJECT}
    {L_MESSAGE_BODY}

    {L_MESSAGE_BODY_DESC}

    {L_OPTIONS}
    + +
    + +
    + + +
    + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    + + \ No newline at end of file diff --git a/upload/templates/default/usercp_register.tpl b/upload/templates/default/usercp_register.tpl new file mode 100644 index 000000000..9aa6a37bd --- /dev/null +++ b/upload/templates/default/usercp_register.tpl @@ -0,0 +1,200 @@ + + + +

    {PAGE_TITLE}

    + + + +
    + + + + + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Регистрационная информация
    Поля отмеченные * обязательны к заполнению
    Имя: *{USERNAME} +  
    Адрес email: *
    На этот адрес вам будет отправлено письмо для завершения регистрации
    readonly="readonly" style="color: gray;" /> +
    Текущий пароль: *
    Вы должны указать ваш текущий пароль, если хотите изменить его или поменять свой e-mail
    Новый пароль: *
    Указывайте пароль только если вы хотите его поменять
    Пароль: *
     максимум 20 символов
    Подтвердите пароль: *
    Подтверждать пароль нужно в том случае, если вы изменили его выше
    +
    Код подтверждения:{CAPTCHA_HTML}
    {L_AUTOLOGIN}:{L_RESET_AUTOLOGIN}
    {L_RESET_AUTOLOGIN_EXPL}
    TorrentPier
    {L_GEN_PASSKEY}
    {L_GEN_PASSKEY_EXPLAIN}
    {L_GEN_PASSKEY_EXPLAIN_2}
    {S_GEN_PASSKEY}
    {L_CURR_PASSKEY}{CURR_PASSKEY}
    Профиль
    Пол: + +
    ICQ:
    CommFort:
    Skype:
    Сайт:
    Род занятий:
    Интересы:
    Откуда: +
    +
    Часовой пояс:{TIMEZONE_SELECT}
    Личные настройки
    Опция управления подписью отключена за нарушение правил форума
    Подпись:
    максимум {$bb_cfg['max_sig_chars']} символов
    Уведомлять о новых личных сообщениях: +    + +
    {$bb_cfg['lang_hide_porno_forums']}: +    + +
    + +
    +
    + Для продолжения регистрации Вы должны принять наше ПОЛЬЗОВАТЕЛЬСКОЕ СОГЛАШЕНИЕ +
    + +
    +

    +
    +
    +
    +
    +   + +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/usercp_sendpasswd.tpl b/upload/templates/default/usercp_sendpasswd.tpl new file mode 100644 index 000000000..234624973 --- /dev/null +++ b/upload/templates/default/usercp_sendpasswd.tpl @@ -0,0 +1,33 @@ + + +
    +{S_HIDDEN_FIELDS} + + +++ + + + + + + + + + + + + + + + + + + +
    {L_FORGOTTEN_PASSWORD}
    {L_ITEMS_REQUIRED}
    {L_USERNAME}: *
    {L_EMAIL_ADDRESS}: *
    +   + +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/usercp_viewprofile.tpl b/upload/templates/default/usercp_viewprofile.tpl new file mode 100644 index 000000000..a2d1a76b0 --- /dev/null +++ b/upload/templates/default/usercp_viewprofile.tpl @@ -0,0 +1,371 @@ + + + +{action: "edit_user_profile", id: "user_regdate"} +{action: "edit_user_profile", id: "user_lastvisit"} + +{action: "edit_user_profile", id: "ignore_srv_load", editableType: "yesno-radio"} + + +{action: "edit_user_profile", id: "u_up_total"} +{action: "edit_user_profile", id: "u_down_total"} +{action: "edit_user_profile", id: "u_up_release"} +{action: "edit_user_profile", id: "u_up_bonus"} + + + + + + +

    {L_VIEWING_PROFILE}

    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_VIEW_TOR_PROF}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_DOWN_TOTAL}: + {DOWN_TOTAL} +
    {L_UP_TOTAL}: + {UP_TOTAL} +
    {L_TOTAL_RELEASED}: + {RELEASED} +  [ {L_SEARCH_RELEASES} ] +
    {L_BONUS}: + {UP_BONUS} +
    {L_MAX_SPEED}: + {SPEED_UP} / {SPEED_DOWN} +
    {L_USER_RATIO}: + + {USER_RATIO}  + [?] + + {L_IT_WILL_BE_DOWN} {MIN_DL_FOR_RATIO} + +
    Passkey:{AUTH_KEY}
    + +
    {L_CUR_ACTIVE_DLS}
    {L_RELEASINGS}{L_NONE}
    {L_FORUM}{L_TOPICS}
    {seed.releasedrow.FORUM_NAME}{seed.releasedrow.TOPIC_TITLE}
    {L_SEEDINGS}{L_NONE}
    {L_FORUM}{L_TOPICS}
    {seed.seedrow.FORUM_NAME}{seed.seedrow.TOPIC_TITLE}
    {L_LEECHINGS}{L_NONE}
    {L_FORUM}{L_TOPICS}%
    {leech.leechrow.FORUM_NAME}{leech.leechrow.TOPIC_TITLE}{leech.leechrow.COMPL_PERC}
    + + {L_SEARCH_DL_WILL_DOWNLOADS} + :: + {L_SEARCH_DL_DOWN} + :: + {L_SEARCH_DL_COMPLETE} + :: + {L_SEARCH_DL_CANCEL} + +
    + + +
    + + +
    +

    + +

    +
    + +
    + + + +
    + {L_MANAGE_USER}:  + {L_MANAGE}  + {L_PERMISSIONS} +
    + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/viewforum.tpl b/upload/templates/default/viewforum.tpl new file mode 100644 index 000000000..d1abf2275 --- /dev/null +++ b/upload/templates/default/viewforum.tpl @@ -0,0 +1,650 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    {FORUM_NAME}

    + +

    {L_MODERATORS}: {MODERATORS}

    + + +

    {LOGGED_IN_USER_LIST}

    + +
    {PAGINATION}
    + + + + + + +
    {T_POST_NEW_TOPIC}
    + + + + ++++++ + + + + + + + + + + + + + + + + + +
    {L_FORUM}{L_TOPICS}{L_POSTS_SHORT}{L_LASTPOST}
    {f.TOPIC_TYPE} + +

    {f.FORUM_DESC}

    +

    {L_MODERATORS}: {f.MODERATORS}

    +
    {f.TOPICS}{f.POSTS} + + + + + +
    + {f.last.LAST_TOPIC_TITLE} + {ICON_LATEST_REPLY} +
    +

    + {f.last.LAST_POST_TIME} + by + + {f.last.LAST_POST_USER_NAME} + + {f.last.LAST_POST_USER_NAME} + +

    + + + +

    {f.last.LAST_POST_TIME}

    +

    + + {f.last.LAST_POST_USER_NAME} + + {f.last.LAST_POST_USER_NAME} + + {ICON_LATEST_REPLY} +

    + + + + {L_NO_POSTS} + + +
    +
    + + + + + + + +
    + + + + + + + + + + + + + + +
    + {L_MODERATE_FORUM} + |{L_TOPICS_PER_PAGE}: +
    {SELECT_TPP}
    +
    +   + + {L_SEARCH_SELF}  |  + {L_DISPLAYING_OPTIONS} + + +
    + + value="{TITLE_MATCH}" class="found"class="error" + + value="{L_TITLE_SEARCH_HINT}" class="hint" + + style="width: 150px;" /> + +
    +
    + +
    + + + + +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_TOPICS}{L_TORRENT}{L_REPLIES_SHORT}{L_LASTPOST}
    {t.TOPICS_SEPARATOR}
    +
    + {t.TOR_STATUS_ICON}· + {ICON_NEWEST_REPLY} + {L_MOVED} + {L_DL_TOPIC} + + {L_POLL} + + {TOPIC_ATTACH_ICON} + {t.TOPIC_TITLE} + + {t.TOR_TYPE}{t.TOPIC_TITLE} + +
    +
    + {t.TOPIC_AUTHOR_NAME} + {t.TOPIC_AUTHOR_NAME} +  [{ICON_GOTOPOST}{L_GOTO_SHORT} {t.PAGINATION} ] +
    +
    + +
    +
    {t.tor.SEEDERS} | {t.tor.LEECHERS}
    +
    {t.tor.TOR_SIZE}{t.tor.TOR_SIZE} {t.tor.MAGNET}
    +
    + +
    +

    + {t.REPLIES} + | + {t.VIEWS} +

    + +

    + {t.tor.COMPL_CNT} +

    + +
    +

    {t.LAST_POST_TIME}

    +

    + {t.LAST_POSTER_NAME}{t.LAST_POSTER_NAME} + {ICON_LATEST_REPLY} +

    +
    {NO_TOPICS}
    + +
    + {L_DISPLAY_TOPICS}: {S_SELECT_TOPIC_DAYS} {S_DISPLAY_ORDER} + +
    + +   + +
    + + + + ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_TOPICS}{L_REPLIES}{L_AUTHOR}{L_VIEWS}{L_LASTPOST}
    {t.TOPICS_SEPARATOR}
    + + {ICON_NEWEST_REPLY} + {L_MOVED} + {L_DL_TOPIC} + {TOPIC_ATTACH_ICON} + + {L_POLL} + {t.TOPIC_TITLE} + + [{ICON_GOTOPOST}{L_GOTO_SHORT} {t.PAGINATION} ] + {t.REPLIES}{t.TOPIC_AUTHOR_NAME}{t.TOPIC_AUTHOR_NAME}{t.VIEWS} +

    {t.LAST_POST_TIME}

    +

    + {t.LAST_POSTER_NAME}{t.LAST_POSTER_NAME} + {ICON_LATEST_REPLY} +

    +
    {NO_TOPICS}
    + +
    + {L_DISPLAY_TOPICS}: {S_SELECT_TOPIC_DAYS} {S_DISPLAY_ORDER} + +
    + +   + +
    + + + + + + + + +
    {T_POST_NEW_TOPIC}
    + + +
    + + + + + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + + +

    {L_MARK_TOPICS_READ}

    + + + + + + + +
    {S_AUTH_LIST} + + + + + + + + + + + + + + + + + + + +
    {L_NEW_POSTS}{L_POST_ANNOUNCEMENT}
    {L_NO_NEW_POSTS}{L_POST_STICKY}
    {L_NO_NEW_POSTS_LOCKED}{L_POST_DOWNLOAD}
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/viewonline.tpl b/upload/templates/default/viewonline.tpl new file mode 100644 index 000000000..2a1a09ad7 --- /dev/null +++ b/upload/templates/default/viewonline.tpl @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_USERNAME}{L_LAST_UPDATE}
    {TOTAL_REGISTERED_USERS_ONLINE}
    {reg_user_row.USERNAME}{reg_user_row.LASTUPDATE}
    {TOTAL_GUEST_USERS_ONLINE}
    {guest_user_row.USERNAME}{guest_user_row.LASTUPDATE}
    + +
    + +
    + +

    {L_ONLINE_EXPLAIN}

    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    \ No newline at end of file diff --git a/upload/templates/default/viewtopic.tpl b/upload/templates/default/viewtopic.tpl new file mode 100644 index 000000000..97e595d9c --- /dev/null +++ b/upload/templates/default/viewtopic.tpl @@ -0,0 +1,448 @@ + + + + + + + + + + + +
    + +

    {TOPIC_TITLE}

    + +

    {PAGINATION}

    + + + + + + + +
    + {T_POST_REPLY} +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + {L_MODERATE_TOPIC}{L_MODERATE_TOPIC} + |{L_SELECT_PPP} +
    {SELECT_PPP}
    +
    +   + + {L_SEARCH_SELF}  |  + {L_DISPLAYING_OPTIONS} + + +
    + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_AUTHOR}{L_MESSAGE}
    + + +

    {postrow.POSTER_NAME}

    +

    {postrow.POSTER_AVATAR}

    + + +

    + {postrow.POSTER_NAME} +

    + +

    {postrow.POSTER_NAME}

    + + +

    {postrow.POSTER_RANK}

    +

    {postrow.RANK_IMAGE}

    +

    {postrow.POSTER_AVATAR}

    +

    {L_LONGEVITY}: {postrow.POSTER_JOINED}

    +

    {L_POSTS}: {postrow.POSTER_POSTS}

    +

    {L_LOCATION}: {postrow.POSTER_FROM}

    +

    {postrow.POSTER_FROM_FLAG}

    + + +

    + +
    + +
    +

    + {MINIPOST_IMG_NEW}{MINIPOST_IMG} + {postrow.POST_DATE} + + ({L_POSTED_AFTER} {postrow.POSTED_AFTER}) + +

    + + + +

    + {QUOTE_IMG}{POST_BTN_SPACER} + {EDIT_POST_IMG}{POST_BTN_SPACER} + {DELETE_POST_IMG}{POST_BTN_SPACER} + {IP_POST_IMG}{POST_BTN_SPACER} + {postrow.REPORT}{POST_BTN_SPACER} + + {MOD_POST_IMG}{POST_BTN_SPACER} + +

    +
    +
    + +
    +
    {postrow.MESSAGE}{postrow.ATTACHMENTS}
    + {postrow.SIGNATURE} +
    {postrow.EDITED_MESSAGE}
    +
    + +
    + + +   + +
    + {PROFILE_IMG}{POST_BTN_SPACER} + {PM_IMG}{POST_BTN_SPACER} +
    + + +
    + + + + + + + + +
    + + +
    + + + + + + + + + + + + + +
    {L_QUICK_REPLY}
    + +
    + +

    {L_QR_USERNAME}:

    + +
    + +
    +
    + +
    + + {L_QR_DISABLE}:  + + + + + +   + + + +   + + + +
    + +
    + + + + + + +
    +
    + {L_DISPLAY_POSTS}: {S_SELECT_POST_DAYS}  + {S_SELECT_POST_ORDER}  + +
    +
    + + + + + + + + + + +
    + {T_POST_REPLY} +
    + + +
    + +
    + +
    +

    {LAST_VISIT_DATE}

    +

    {CURRENT_TIME}

    +

    {S_TIMEZONE}

    +
    +
    + +
    + + + + + +
    {S_WATCH_TOPIC}
    +
    + +
    +
    {S_TOPIC_ADMIN}
    + + +
    + Admin:  + {L_LOGS}  +
    + + +
    +
    {S_DL_DELETE}
    + +
    +
    {S_AUTH_LIST}
    +
    +
    \ No newline at end of file diff --git a/upload/templates/default/viewtopic_attach.tpl b/upload/templates/default/viewtopic_attach.tpl new file mode 100644 index 000000000..4b8d715c3 --- /dev/null +++ b/upload/templates/default/viewtopic_attach.tpl @@ -0,0 +1,443 @@ + +
    +
    + + +
    +{ATTACHMENT_ICON} Attachment + +
    + +
    + + + +
    + + + + + + + + + + + + + + + + + + + +
    {postrow.attach.cat_stream.DOWNLOAD_NAME}
     {L_DESCRIPTION}: + + + + +
    {postrow.attach.cat_stream.COMMENT}
    +
     {L_FILESIZE}: {postrow.attach.cat_stream.FILESIZE} {postrow.attach.cat_stream.SIZE_VAR}
     {L_VIEWED}: {postrow.attach.cat_stream.DOWNLOAD_COUNT}

    + + + + + + + + + + + +

    +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + +
    {postrow.attach.cat_swf.DOWNLOAD_NAME}
     {L_DESCRIPTION}: + + + + +
    {postrow.attach.cat_swf.COMMENT}
    +
     {L_FILESIZE}: {postrow.attach.cat_swf.FILESIZE} {postrow.attach.cat_swf.SIZE_VAR}
     {L_VIEWED}: {postrow.attach.cat_swf.DOWNLOAD_COUNT}

    + + + + + + + + +

    +
    +
    + + + +
    +{ATTACHMENT_ICON} Attachment ({postrow.attach.cat_images.FILESIZE} {postrow.attach.cat_images.SIZE_VAR}) +

    + img +

    + +

    + {postrow.attach.cat_images.COMMENT} +

    + +
    + +
    + + + +
    +{ATTACHMENT_ICON} Attachment Thumbnail + + + +

    + {postrow.attach.cat_thumb_images.COMMENT} +

    + +
    + +
    + + + +
    +{postrow.attach.attachrow.S_UPLOAD_IMAGE} Attachment + + +

    + {postrow.attach.attachrow.COMMENT} +

    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {postrow.attach.tor_not_reged.DOWNLOAD_NAME}
    {L_TRACKER}:{postrow.attach.tor_not_reged.TRACKER_LINK} +

    {postrow.attach.tor_not_reged.S_UPLOAD_IMAGE}

    +

    {L_DOWNLOAD}

    +

    {postrow.attach.tor_not_reged.FILESIZE}

    +
    {L_ADDED}:{postrow.attach.tor_not_reged.POSTED_TIME}
    {L_DOWNLOADED}:{postrow.attach.tor_not_reged.DOWNLOAD_COUNT}  [ {L_SHOW_DL_LIST} ]
    {postrow.attach.tor_not_reged.comment.COMMENT}
      + + + + + +   + +  
    + +
    + + + + + + + + +

    {TOR_BLOCKED_MSG}

    + +
    + + + + +

    {RATIO_WARN_MSG}

    + +
    + + + + + + + + + + + + + + + + + + + + + + + style="padding: 6px 4px;"> + {postrow.attach.tor_reged.TOR_STATUS_ICON} {postrow.attach.tor_reged.TOR_STATUS_TEXT} + {postrow.attach.tor_reged.TOR_STATUS_BY} + + +
    + + + {postrow.attach.tor_reged.TOR_STATUS_SELECT} + + [ Изменить ] + + + +
    + + + + + + + + + + + + + + + + +
    {postrow.attach.tor_reged.DOWNLOAD_NAME} {postrow.attach.tor_reged.MAGNET}
     {L_SILVER_STATUS} 
     {L_GOLD_STATUS} 
    {L_TRACKER}: + {postrow.attach.tor_reged.TRACKER_LINK}   + [ {postrow.attach.tor_reged.REGED_TIME} ] + + +

    {postrow.attach.tor_reged.S_UPLOAD_IMAGE}

    {L_DOWNLOAD}

    + + +

    {postrow.attach.tor_reged.S_UPLOAD_IMAGE}

    {L_DOWNLOAD}

    + +

    {postrow.attach.tor_reged.FILESIZE}

    +

    +
    {L_TOR_STATUS}:
    {L_COMPLETED}:{postrow.attach.tor_reged.COMPLETED}
    {L_SIZE}:{postrow.attach.tor_reged.TORRENT_SIZE}
    {postrow.attach.tor_reged.comment.COMMENT}
    + + + + + +   + + + {TOR_HELP_LINKS} + +   + +
    + + + + + + + +
    + + + + \ No newline at end of file diff --git a/upload/templates/default/viewtopic_attach_guest.tpl b/upload/templates/default/viewtopic_attach_guest.tpl new file mode 100644 index 000000000..663fe14ce --- /dev/null +++ b/upload/templates/default/viewtopic_attach_guest.tpl @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/upload/templates/default/viewtopic_poll.tpl b/upload/templates/default/viewtopic_poll.tpl new file mode 100644 index 000000000..966cf9cd1 --- /dev/null +++ b/upload/templates/default/viewtopic_poll.tpl @@ -0,0 +1,51 @@ +
    + + + + +
    + {S_HIDDEN_FIELDS} + +

    {POLL_QUESTION}

    + + + + + + + + +
    + +

    + +

    {L_VIEW_RESULTS}

    + +
    + + + + + + + +

    {POLL_QUESTION}

    + + + + + + + + + + + +
    {poll_option.POLL_OPTION_CAPTION} {poll_option.POLL_OPTION_PERCENT} {poll_option.POLL_OPTION_PERCENT} [ {poll_option.POLL_OPTION_RESULT} ]
    + +

    {L_TOTAL_VOTES} : {TOTAL_VOTES}

    + + + + +
    \ No newline at end of file diff --git a/upload/templates/default/viewtopic_torrent.tpl b/upload/templates/default/viewtopic_torrent.tpl new file mode 100644 index 000000000..ddeff4395 --- /dev/null +++ b/upload/templates/default/viewtopic_torrent.tpl @@ -0,0 +1,266 @@ + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + {L_DL_LIST_AND_TORRENT_ACTIVITY} +
    {dl_users.users_row.DL_OPTION_NAME}
    {dl_users.users_row.DL_OPTION_USERS}
    + + + + + + + +
    {dl_counts.count_row.DL_OPTION_NAME}:[ {dl_counts.count_row.DL_OPTION_USERS} ]
    +
    + {L_SIZE}:  {TOR_SIZE}   |    + {L_IS_REGISTERED}:  {TOR_LONGEVITY}   |    + {L_COMPLETED}:  {TOR_COMPLETED} +
    DL-List: {L_NONE}
    + +

    {SEEDER_LAST_SEEN}

    + + + +
    + + + {L_SEEDERS}:  {SEED_COUNT}  [  {TOR_SPEED_UP}  ]   + + + {L_LEECHERS}:  {LEECH_COUNT}  [  {TOR_SPEED_DOWN}  ]   + + + + + {L_SPMODE_FULL} + +
    + +
    {L_SEEDERS}{SEED_LIST}
    +

    {SEEDER_LAST_SEEN}

    +
    {L_LEECHERS}{LEECH_LIST}
    + + +
    +

    {SEEDER_LAST_SEEN}

    +
    + + + +
    + + + + + + + + + + +
    +
    + +

    {L_SEEDERS}:

    + +

    + {L_SORT_BY}: {sfull.sorder.SEED_ORDER_SELECT} + +

    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    Username + UL
    Ratio +
    Transfers + Speed + + IP + + + Port + +
    up + down + up + down +
    {sfull.srow.NAME}{sfull.srow.COMPL_PRC}{sfull.srow.UP_TOTAL}{sfull.srow.DOWN_TOTAL}{sfull.srow.SPEED_UP}{sfull.srow.SPEED_DOWN}{sfull.srow.ip.IP}{sfull.srow.port.PORT}
    + +
    + + + + + + + + + + + +
    +
    + +

    {L_LEECHERS}:

    + +

    + {L_SORT_BY}: {lfull.lorder.LEECH_ORDER_SELECT} + +

    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    Username + % + Transfers + Speed + + IP + + + Port + +
    up + down + up + down +
    {lfull.lrow.NAME}{lfull.lrow.COMPL_PRC}{lfull.lrow.UP_TOTAL}{lfull.lrow.DOWN_TOTAL}{lfull.lrow.SPEED_UP}{lfull.lrow.SPEED_DOWN}{lfull.lrow.ip.IP}{lfull.lrow.port.PORT}
    + +
    + + +
    показаны данные только за текущую сессию
    + +
    + + +
    +   + +
    {DL_HIDDEN_FIELDS} +   +   +   + +
    + +   +
    +
    \ No newline at end of file diff --git a/upload/templates/limit_load_exit.php b/upload/templates/limit_load_exit.php new file mode 100644 index 000000000..a47a52e37 --- /dev/null +++ b/upload/templates/limit_load_exit.php @@ -0,0 +1,70 @@ +close(); +} +send_no_cache_headers(); + +$redirect_url = !empty($_POST['redirect']) ? $_POST['redirect'] : $_SERVER['REQUEST_URI']; + + + // LOG + global $userdata; + + if ($userdata['username']) + { + $name = html_entity_decode($userdata['username']); + } + else if (!empty($_POST['login_username'])) + { + $name = $_POST['login_username']; + } + else + { + $name = ''; + } + + $file = 'load/load-'. date('m-d'); + $str = array(); + $str[] = date('H:i:s'); + $str[] = sprintf('%-5s', floatval(LOADAVG)); + $str[] = sprintf('%-15s', $_SERVER['REMOTE_ADDR']); + $str[] = sprintf('%-20s', $name); + $str[] = $redirect_url; + $str = join(LOG_SEPR, $str) . LOG_LF; + bb_log($str, $file); + + +?> + + + + + <?php echo $bb_cfg['sitename']?> + + + + +
    + + +
    +

    Извините, в данный момент сервер перегружен.

    +

    Попробуйте зайти через несколько минут.

    +

    +
    + +
    + + + + + \ No newline at end of file diff --git a/upload/templates/topic_tpl_overall_header.html b/upload/templates/topic_tpl_overall_header.html new file mode 100644 index 000000000..699e02c49 --- /dev/null +++ b/upload/templates/topic_tpl_overall_header.html @@ -0,0 +1,51 @@ + + + + + + + + +
    Общие правила и положения
    + +
    + +

    Правила оформления раздач на трекере

    + +
    +
      +
    • + Все создающие раздачу (выкладывающие файл для общедоступного скачивания) обязаны контролировать содержимое этой раздачи по качеству (к примеру, отсутствие звука в фильмах, неснятая защита в программах, неработоспособность программы и т.п.). +
    • +
    • + Данная конференция ведется на русском языке. Для не имеющих возможности писать кириллицей в форум встроена виртуальная русская клавиатура и транслит, кроме того в интернете существует целый ряд подобных сервисов. Модераторы и администрация оставляют за собой право редактировать или удалять сообщения, написанные латиницей, без предупреждения. +
    • +
    • + Перед тем, как создавать раздачу, воспользуйтесь поиском - возможно такая раздача уже существует. +
    • +
    +
    + +

    Всем участникам раздач на данном трекере запрещается:

    + +
    +
      +
    • Создавать раздачу, дублирующую то, что уже существует на трекере. Дублирующей считается не отличающаяся ни по содержанию, ни по качеству информация.
    • +
    • Создавать раздачу, содержание которой нарушает общественные нормы морали, различные Базы Данных, отсутствующие в свободном законном доступе и т.п.
    • +
    • Выкладывать для общедоступного скачивания более двадцати раздач одновременно или по совокупности (исключение делается для пользователей с очень широким каналом, по личному разрешению Администрации). Пользователи, раздающие больше 20 раздач, будут предупреждаться. Если предупреждения не приведут к должному результату, то часть Ваших раздач будет приостановлена (а возможно, и удалена).
    • +
    +
    + +
    Решение по соответствию раздачи данным требованиям принимает Модератор или Администратор. В их полномочиях редактировать, перемещать, закрывать или удалять раздачу.
    + +
    + +
    + +
    \ No newline at end of file diff --git a/upload/templates/topic_tpl_rules_video.html b/upload/templates/topic_tpl_rules_video.html new file mode 100644 index 000000000..df0348915 --- /dev/null +++ b/upload/templates/topic_tpl_rules_video.html @@ -0,0 +1,99 @@ + + + + + + + +
    Правила оформления
    + +
    + +

    Перед тем, как начинать оформление раздачи, вы должны обязательно ознакомиться со следующими темами:

    + + +
    + + Является ли ваш релиз повтором + +
    + + Как получить информацию по видео файлу + +
    + + Как сделать скриншот с фильма + +
    + + Как залить скриншот на бесплатный хост + +
    + + Обозначение качества видео + +
    + + Как подписывать торрент файлы + +
    + + Как правильно писать на форуме + +
    + +

    Правила оформления раздач в этом разделе:

    + +
      + +
    • +Если при оформлении раздачи фильма вы указываете русское название, оно должно соответствовать названию под которым фильм выходил на территории Российской Федерации. Буквальный перевод оригинального названия не приветствуется. В названии темы должно быть название фильма на русском языке / на английском или на языке оригинала. +
    • +
    • +В раздаче должен обязательно присутствовать постер. +
    • +
    • +Также вы должны заполнить все графы в бланке по оформлению раздачи - продолжительность, перевод, страна, год создания фильма, режиссёр, актёры (в ролях), для чего вы можете воспользоваться авторитетными сайтами о кинематографии, такими как - IMdB либо VideoGuide. +
    • +
    • +Обязательно должно присутствовать хотя бы краткое описание сюжета фильма. +
    • +
    • +В описании обязательно должно присутствовать обозначение качества раздающегося материала, формат, а также параметры аудио и видео потоков. +
    • +
    • +При сознательном введении в заблуждение пользователей форума относительно качества раздаваемого материала, раздающему будет сделано предупреждение с запретом на дальнейшее оформление раздач. +
    • +
    • +Сриншоты при качестве фильма ниже DVDRip выкладывать обязательно. На качество DVDRip раздающий обязан выложить скриншоты по первому требованию пользователей ресурса. Скриншот должен быть сделан непосредственно с того видео файла, который раздаётся! +
    • +
    • +В имени торрент-файла должно присутствовать русское название фильма, написанное на латинице. Далее, в скобках, должно быть указано имя трекера. Например: Imja_Faila_[].torrent (если оригинальное название торрент-файла было Имя Файла.torrent). В названии торрент-файла и его содержимого, не должно присутствовать ссылок на другие ресурсы. +
    • +
    • +Если вы имеете принадлежность к одной из релиз-групп, то разрешается указывать в теме название вашей релиз-группы, но только в виде текста либо графического файла, не содержащих прямых ссылок на другой ресурс, иначе это будет расцениваться как реклама и данная ссылка будет удалена. При желании вы можете указать название релиз-группы раздаваемого фильма, не принадлежа к ней, но также без ссылок на другой ресурс. +
    • +
    • +Если по различного рода объективным причинам, в какое-то время суток вы будете отсутствовать на раздаче длительное время, являясь единственным сидом на ней, вы должны указать это. +
    • +
    • +При несоблюдении вышеперечисленных правил, либо в случае отсутствия сида на раздаче по истечении 2 часов после оформления, раздача будет перенесена в Тестовый форум, а раздающему будет сделано предупреждение. При наличии трёх предупреждений, аккаунт пользователя будет удалён без объяснения причины. Для проб используйте Тестовый форум. +
    • +
    • +При скорости отдачи (Upload) менее 12 кб/с не разрешается сидировать более 1-ого файла одновременно (другие раздачи и закачки на этот момент должны быть завершены). При нарушении данного условия все ваши последующие одновременные раздачи будут закрываться. Начав раздачу, вы должны довести её до конца, пока не появится минимум 3-5 скачавших. +
    • +
    • +Если вы по каким-либо причинам не смогли сделать что-либо из вышеперечисленного - оформлять раздачу напрямую в данном разделе запрещено, для этого существует Тестовый форум. +
    • + +
    + +
    + +
    + +
    + +
    diff --git a/upload/templates/xs_mod/tpl/cache.tpl b/upload/templates/xs_mod/tpl/cache.tpl new file mode 100644 index 000000000..0d679fd8d --- /dev/null +++ b/upload/templates/xs_mod/tpl/cache.tpl @@ -0,0 +1,43 @@ + +/*************************************************************************** + * cache.tpl + * --------- + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 55 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:55 + * + ***************************************************************************/ + + +

    {L_XS_MANAGE_CACHE}

    + +

    +{L_XS_MANAGE_CACHE_EXPLAIN2} +{RESULT} +

    + + + + + + + + + + + + + + + + + + + +
    {L_XS_MANAGE_CACHE}
    {L_XS_TEMPLATE}{L_XS_STYLES}{L_XS_CLEAR_ALL_LC}{L_XS_COMPILE_ALL_LC}
    {styles.TPL}{styles.STYLES}{L_XS_CLEAR_CACHE_LC}{L_XS_COMPILE_CACHE_LC}
    +
    \ No newline at end of file diff --git a/upload/templates/xs_mod/tpl/config.tpl b/upload/templates/xs_mod/tpl/config.tpl new file mode 100644 index 000000000..74ea40b78 --- /dev/null +++ b/upload/templates/xs_mod/tpl/config.tpl @@ -0,0 +1,171 @@ + +/*************************************************************************** + * confir.tpl + * ---------- + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 55 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:55 + * + ***************************************************************************/ + + +

    {L_XS_CONFIG_MAINTITLE}

    + +

    {L_XS_CONFIG_SUBTITLE}

    + + + + + + + + + + + + +
    {L_XS_CONFIG_UPDATED}
    + + + + + + + + + +
     
    {L_XS_CONFIG_UPDATED_EXPLAIN}
     
    +
    + + + + + + + + + + +
    {L_XS_CONFIG_WARNING}
    + + + + + + + + + +
     
    {L_XS_CONFIG_WARNING_EXPLAIN}
     
    +
    + + + + + + + + + + +
    {L_Error}
    + + + + + + + + + +
     
    {L_XS_FTP_COMMENT3}
     
    +
    + + + + + + + + + + +
    {L_Error}
    + + + + + + + + + +
     
    {ftperror.ERROR}
     
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_XS_CONFIG_TITLE}
    {L_XS_CONFIG_TPL_COMMENTS}
    {L_XS_CONFIG_TPL_COMMENTS_EXPLAIN}
      
    {L_XS_CONFIG_CACHE}
    {L_XS_CONFIG_USE_CACHE}
    {L_XS_CONFIG_USE_CACHE_EXPLAIN}
      
    {L_XS_CONFIG_AUTO_COMPILE}
    {L_XS_CONFIG_AUTO_COMPILE_EXPLAIN}
      
    {L_XS_CONFIG_AUTO_RECOMPILE}
    {L_XS_CONFIG_AUTO_RECOMPILE_EXPLAIN}
      
    {L_XS_CONFIG_PHP}
    {L_XS_CONFIG_PHP_EXPLAIN}
    {S_HIDDEN_FIELDS}
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_XS_DEBUG_HEADER}
    {L_XS_DEBUG_EXPLAIN}
    {XS_DEBUG_HDR1}
    {L_XS_DEBUG_TPL_NAME}{XS_DEBUG_FILENAME1}
    {L_XS_DEBUG_CACHE_FILENAME}{XS_DEBUG_FILENAME2}
    {L_XS_DEBUG_DATA}{XS_DEBUG_DATA}
    diff --git a/upload/templates/xs_mod/tpl/frameset.tpl b/upload/templates/xs_mod/tpl/frameset.tpl new file mode 100644 index 000000000..f95487b4c --- /dev/null +++ b/upload/templates/xs_mod/tpl/frameset.tpl @@ -0,0 +1,22 @@ + +/*************************************************************************** + * frameset.tpl + * ------------ + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 57 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:55 + * + ***************************************************************************/ + + + + + + +{L_XS_CLICK_HERE_LC} + \ No newline at end of file diff --git a/upload/templates/xs_mod/tpl/index.tpl b/upload/templates/xs_mod/tpl/index.tpl new file mode 100644 index 000000000..a8ce8bb8e --- /dev/null +++ b/upload/templates/xs_mod/tpl/index.tpl @@ -0,0 +1,34 @@ + +/*************************************************************************** + * index.tpl + * --------- + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 72 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:55 + * + ***************************************************************************/ + + +

    {L_XS_TITLE}

    + + + + + + + + + + + + + +
    {L_XS_MAIN_TITLE}
    {L_XS_CONFIGURATION}:
    {L_XS_CONFIGURATION_EXPLAIN}
    [{L_XS_SET_CONFIGURATION_LC}]
    {L_XS_MANAGE_CACHE}:
    {L_XS_MANAGE_CACHE_EXPLAIN}
    [{L_XS_MANAGE_CACHE_LC}]
    + +
    + diff --git a/upload/templates/xs_mod/tpl/message.tpl b/upload/templates/xs_mod/tpl/message.tpl new file mode 100644 index 000000000..481827aaa --- /dev/null +++ b/upload/templates/xs_mod/tpl/message.tpl @@ -0,0 +1,41 @@ + +/*************************************************************************** + * message.tpl + * ----------- + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 72 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:54 + * + ***************************************************************************/ + + + + + + + + + + + + + +
    {MESSAGE_TITLE}
    + + + + + + + + + +
     
    {MESSAGE_TEXT}
     
    + diff --git a/upload/templates/xs_mod/tpl/xs_footer.tpl b/upload/templates/xs_mod/tpl/xs_footer.tpl new file mode 100644 index 000000000..6c8cc65bb --- /dev/null +++ b/upload/templates/xs_mod/tpl/xs_footer.tpl @@ -0,0 +1,36 @@ + +/*************************************************************************** + * xs_footer.tpl + * ------------- + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 72 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:55 + * + ***************************************************************************/ + + + + + + +
    Powered by phpBB © phpBB Group and by eXtreme Styles mod © Vjacheslav Trushkin.
    + + + \ No newline at end of file diff --git a/upload/templates/xs_mod/tpl/xs_header.tpl b/upload/templates/xs_mod/tpl/xs_header.tpl new file mode 100644 index 000000000..969db4ba1 --- /dev/null +++ b/upload/templates/xs_mod/tpl/xs_header.tpl @@ -0,0 +1,40 @@ + +/*************************************************************************** + * xs_header.tpl + * ------------- + * copyright : (C) 2003 - 2005 CyberAlien + * support : http://www.phpbbstyles.com + * + * version : 2.3.1 + * + * file revision : 72 + * project revision : 78 + * last modified : 05 Dec 2005 13:54:54 + * + ***************************************************************************/ + + + + + + + + + + +
    + + + + + + +
    diff --git a/upload/tracker.php b/upload/tracker.php new file mode 100644 index 000000000..37ba89757 --- /dev/null +++ b/upload/tracker.php @@ -0,0 +1,914 @@ +session_start(array('req_login' => $bb_cfg['bt_tor_browse_only_reg'])); + +$tor_search_limit = (IS_AM) ? 2000 : 500; +$title_match_limit = 700; // больше $tor_search_limit т.к. ищет по всем темам, а не только по раздачам +$forum_select_size = (UA_OPERA) ? 21 : 24; // forum select box max rows +$max_forum_name_len = 60; // inside forum select box +$title_match_max_len = 60; +$poster_name_max_len = 25; +$tor_colspan = 13; // torrents table colspan with all columns +$per_page = $bb_cfg['topics_per_page']; +$tracker_url = basename(__FILE__); + +$time_format = 'H:i'; +$date_format = 'j-M-y'; +$row_class_1 = 'prow1'; +$row_class_2 = 'prow2'; + +$start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0; + +$set_default = isset($_GET['def']); +$user_id = $userdata['user_id']; +$lastvisit = (!IS_GUEST) ? $userdata['user_lastvisit'] : ''; +$search_id = (isset($_GET['search_id']) && verify_id($_GET['search_id'], SEARCH_ID_LENGTH)) ? $_GET['search_id'] : ''; +$session_id = $userdata['session_id']; + +$cat_forum = $tor_to_show = $search_in_forums_ary = array(); +$title_match_sql = $title_match_q = $search_in_forums_csv = ''; +$tr_error = $poster_error = false; +$row_num = $tor_count = 0; + +$torrents_tbl = BB_BT_TORRENTS .' tor'; +$cat_tbl = BB_CATEGORIES .' c'; +$forums_tbl = BB_FORUMS .' f'; +$topics_tbl = BB_TOPICS .' t'; +$users_tbl = BB_USERS .' u'; +$tracker_tbl = BB_BT_TRACKER .' tr'; +$tr_snap_tbl = BB_BT_TRACKER_SNAP .' sn'; +$dl_stat_tbl = BB_BT_DLSTATUS .' dl'; + +// +// Search options +// +// Key values +$search_all = -1; +$never = -2; + +$sort_asc = 1; +$sort_desc = 2; + +$ord_posted = 1; +$ord_name = 2; +$ord_compl = 4; +$ord_repl = 5; +$ord_views = 6; +$ord_size = 7; +$ord_last_p = 8; +$ord_last_s = 9; +$ord_seeders = 10; +$ord_leechers = 11; +$ord_sp_up = 12; +$ord_sp_down = 13; + +// Order options +$order_opt = array( + $ord_posted => array( + 'lang' => $lang['IS_REGISTERED'], + 'sql' => 'tor.reg_time', + ), + $ord_name => array( + 'lang' => $lang['BT_TOPIC_TITLE'], + 'sql' => 't.topic_title', + ), + $ord_compl => array( + 'lang' => $lang['COMPLETED'], + 'sql' => 'tor.complete_count', + ), + $ord_seeders => array( + 'lang' => 'Seeders', + 'sql' => 'sn.seeders', + ), + $ord_leechers => array( + 'lang' => 'Leechers', + 'sql' => 'sn.leechers', + ), + $ord_sp_up => array( + 'lang' => 'Speed UP', + 'sql' => 'sn.speed_up', + ), + $ord_sp_down => array( + 'lang' => 'Speed DOWN', + 'sql' => 'sn.speed_down', + ), + $ord_repl => array( + 'lang' => $lang['BT_REPLIES'], + 'sql' => 't.topic_replies', + ), + $ord_views => array( + 'lang' => $lang['BT_VIEWS'], + 'sql' => 't.topic_views', + ), + $ord_size => array( + 'lang' => $lang['SIZE'], + 'sql' => 'tor.size', + ), + $ord_last_p => array( + 'lang' => $lang['BT_LAST_POST'], + 'sql' => 't.topic_last_post_id', + ), + $ord_last_s => array( + 'lang' => $lang['BT_SEEDER_LAST_SEEN'], + 'sql' => 'tor.seeder_last_seen', + ), +); +$order_select = array(); +foreach ($order_opt as $val => $opt) +{ + $order_select[$opt['lang']] = $val; +} + +// Sort direction +$sort_opt = array( + $sort_asc => array( + 'lang' => $lang['ASC'], + 'sql' => 'ASC', + ), + $sort_desc => array( + 'lang' => $lang['DESC'], + 'sql' => 'DESC', + ), +); + +// Previous days +$time_opt = array( + $search_all => array( + 'lang' => $lang['BT_ALL_DAYS_FOR'], + 'sql' => 0, + ), + 1 => array( + 'lang' => $lang['BT_1_DAY_FOR'], + 'sql' => TIMENOW - 86400, + ), + 3 => array( + 'lang' => $lang['BT_3_DAY_FOR'], + 'sql' => TIMENOW - 86400*3, + ), + 7 => array( + 'lang' => $lang['BT_7_DAYS_FOR'], + 'sql' => TIMENOW - 86400*7, + ), + 14 => array( + 'lang' => $lang['BT_2_WEEKS_FOR'], + 'sql' => TIMENOW - 86400*14, + ), + 30 => array( + 'lang' => $lang['BT_1_MONTH_FOR'], + 'sql' => TIMENOW - 86400*30, + ), +); +$time_select = array(); +foreach ($time_opt as $val => $opt) +{ + $time_select[$opt['lang']] = $val; +} + +// Seeder not seen +$s_not_seen_opt = array( + $search_all => array( + 'lang' => $lang['BT_DISREGARD'], + 'sql' => 0, + ), + 1 => array( + 'lang' => $lang['BT_1_DAY'], + 'sql' => TIMENOW - 86400, + ), + 3 => array( + 'lang' => $lang['BT_3_DAYS'], + 'sql' => TIMENOW - 86400*3, + ), + 7 => array( + 'lang' => $lang['BT_7_DAYS'], + 'sql' => TIMENOW - 86400*7, + ), + 14 => array( + 'lang' => $lang['BT_2_WEEKS'], + 'sql' => TIMENOW - 86400*14, + ), + 30 => array( + 'lang' => $lang['BT_1_MONTH'], + 'sql' => TIMENOW - 86400*30, + ), + $never => array( + 'lang' => $lang['BT_NEVER'], + 'sql' => 0, + ), +); +$s_not_seen_select = array(); +foreach ($s_not_seen_opt as $val => $opt) +{ + $s_not_seen_select[$opt['lang']] = $val; +} + +$GPC = array( +# var_name key_name def_value GPC type + 'all_words' => array('allw', 1, CHBOX), + 'active' => array('a', 0, CHBOX), + 'cat' => array('c', null, REQUEST), + 'dl_cancel' => array('dla', 0, CHBOX), + 'dl_compl' => array('dlc', 0, CHBOX), + 'dl_down' => array('dld', 0, CHBOX), + 'dl_will' => array('dlw', 0, CHBOX), + 'forum' => array('f', $search_all, REQUEST), + 'my' => array('my', 0, CHBOX), + 'new' => array('new', 0, CHBOX), + 'title_match' => array('nm', null, REQUEST), + 'order' => array('o', $ord_posted, SELECT), + 'poster_id' => array('pid', null, GET), + 'poster_name' => array('pn', null, REQUEST), + 'user_releases' => array('rid', null, GET), + 'sort' => array('s', $sort_desc, SELECT), + 'seed_exist' => array('sd', 0, CHBOX), + 'show_author' => array('da', 1, CHBOX), + 'show_cat' => array('dc', 0, CHBOX), + 'show_forum' => array('df', 1, CHBOX), + 'show_speed' => array('ds', 0, CHBOX), + 's_not_seen' => array('sns', $search_all, SELECT), + 'time' => array('tm', $search_all, SELECT), +); + +// Define all GPC vars with default values +foreach ($GPC as $name => $params) +{ + ${"{$name}_key"} = $params[KEY_NAME]; + ${"{$name}_val"} = $params[DEF_VAL]; +} + +if (isset($_GET[$user_releases_key])) +{ + // Search releases by user + $_GET[$poster_id_key] = (int) $_GET[$user_releases_key]; + $_REQUEST[$forum_key] = $search_all; +} +else if (!empty($_REQUEST['max'])) +{ + $_REQUEST[$forum_key] = $search_all; +} +else +{ + // Get "checkbox" and "select" vars + foreach ($GPC as $name => $params) + { + if ($params[GPC_TYPE] == CHBOX) + { + checkbox_get_val($params[KEY_NAME], ${"{$name}_val"}, $params[DEF_VAL]); + } + else if ($params[GPC_TYPE] == SELECT) + { + select_get_val($params[KEY_NAME], ${"{$name}_val"}, ${"{$name}_opt"}, $params[DEF_VAL]); + } + } +} + +// Restore torrents list and search settings if we have valid $search_id +$tor_list_ary = array(); +$tor_list_sql = ''; + +if ($search_id) +{ + $row = DB()->fetch_row(" + SELECT search_array, search_settings + FROM ". BB_SEARCH ." + WHERE session_id = '$session_id' + AND search_type = ". SEARCH_TYPE_TRACKER ." + AND search_id = '$search_id' + LIMIT 1 + "); + + if (empty($row['search_settings'])) + { + bb_die($lang['SESSION_EXPIRED']); + } + + $previous_settings = unserialize($row['search_settings']); + $tor_list_sql = $row['search_array']; + $tor_list_ary = explode(',', $tor_list_sql); + $tor_count = count($tor_list_ary); + unset($row); +} + +// Get allowed for searching forums list +if (!$forums = $datastore->get('cat_forums')) +{ + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); +} +$cat_title_html = $forums['cat_title_html']; +$forum_name_html = $forums['forum_name_html']; + +$excluded_forums_csv = $user->get_excluded_forums(AUTH_READ); +$allowed_forums = array_diff(explode(',', $forums['tracker_forums']), explode(',', $excluded_forums_csv)); + +foreach ($allowed_forums as $forum_id) +{ + $f = $forums['f'][$forum_id]; + $cat_forum['c'][$f['cat_id']][] = $forum_id; + + if ($f['forum_parent']) + { + $cat_forum['subforums'][$forum_id] = true; + $cat_forum['forums_with_sf'][$f['forum_parent']] = true; + } +} +unset($forums); +$datastore->rm('cat_forums'); + +// Get current search settings +if (!$set_default) +{ + // Search in forum or category + // Get requested cat_id + $search_in_forums_fary = array(); + + if ($req_cat_id =& $_REQUEST[$cat_key]) + { + if (isset($cat_forum['c'][$req_cat_id])) + { + $valid_forums = $cat_forum['c'][$req_cat_id]; + $forum_val = join(',', $valid_forums); + } + } + // Get requested forum_id(s) + else if ($req_forums =& $_REQUEST[$forum_key]) + { + if ($req_forums != $search_all) + { + $req_forums = (array) $req_forums; + array_deep($req_forums, 'intval'); + $valid_forums = array_intersect($req_forums, $allowed_forums); + $forum_val = join(',', $valid_forums); + } + } + else if (isset($previous_settings[$forum_key])) + { + $valid_forums = array_intersect(explode(',', $previous_settings[$forum_key]), $allowed_forums); + $forum_val = join(',', $valid_forums); + } + + if ($forum_val && $forum_val != $search_all) + { + $search_in_forums_ary = array_slice(explode(',', $forum_val), 0, $max_forums_selected); + $search_in_forums_fary = array_flip($search_in_forums_ary); + $search_in_forums_csv = join(',', $search_in_forums_ary); + $forum_val = $search_in_forums_csv; + } + else + { + $forum_val = $search_all; + } + + // Get poster_id + if (!$my_val) + { + $req_poster_id = ''; + + if (isset($_GET[$poster_id_key]) && !$search_id) + { + $req_poster_id = intval($_GET[$poster_id_key]); + } + else if (isset($_POST[$poster_name_key]) && !$search_id) + { + if ($req_poster_name = clean_username($_POST[$poster_name_key])) + { + $poster_name_sql = str_replace("\\'", "''", $req_poster_name); + + if ($poster_id = get_user_id($poster_name_sql)) + { + $poster_id_val = $poster_id; + $poster_name_val = stripslashes(html_entity_decode($req_poster_name)); + } + else + { + $poster_name_val = $lang['BT_USER_NOT_FOUND']; + $tr_error = $poster_error = true; + } + } + } + else if ($search_id && $previous_settings[$poster_id_key]) + { + $poster_id_val = intval($previous_settings[$poster_id_key]); + $poster_name_val = ($previous_settings[$poster_name_key]) ? $previous_settings[$poster_name_key] : ''; + } + + if ($req_poster_id) + { + if ($req_poster_id == ANONYMOUS) + { + $poster_id_val = ANONYMOUS; + $poster_name_val = $lang['GUEST']; + } + else if ($poster_name_val = get_username($req_poster_id)) + { + $poster_name_val = stripslashes(html_entity_decode($poster_name_val)); + $poster_id_val = $req_poster_id; + } + } + } + + if ($tm =& $_REQUEST[$title_match_key] AND is_string($tm)) + { + if ($tmp = mb_substr(trim($tm), 0, $title_match_max_len)) + { + $title_match_val = $tmp; + $title_match_sql = clean_text_match($title_match_val, true, false, false); + } + } +} + +$dl_status = array(); +if ($dl_cancel_val) $dl_status[] = DL_STATUS_CANCEL; +if ($dl_compl_val) $dl_status[] = DL_STATUS_COMPLETE; +if ($dl_down_val) $dl_status[] = DL_STATUS_DOWN; +if ($dl_will_val) $dl_status[] = DL_STATUS_WILL; +$dl_status_csv = join(',', $dl_status); + +// Switches +$only_new = ($new_val && !IS_GUEST); +$seed_exist = (bool) $seed_exist_val; +$only_active = ($active_val || $seed_exist); +$dl_search = ($dl_status && !IS_GUEST); +$only_my = ($my_val && !IS_GUEST && !$dl_search); +$prev_days = ($time_val != $search_all); +$poster_id = (bool) $poster_id_val; +$title_match = (bool) $title_match_sql; +$s_not_seen = ($s_not_seen_val != $search_all); + +$hide_cat = intval(!$show_cat_val); +$hide_forum = intval(!$show_forum_val); +$hide_author = intval(!$show_author_val); +$hide_speed = intval(!$show_speed_val); + +if ($s_not_seen_val != $search_all) +{ + $seed_exist_val = 0; +} +if ($seed_exist_val) +{ + $active_val = 1; +} +if ($dl_search) +{ + $my_val = 0; +} + +if ($allowed_forums) +{ + // Text search + $search_match_topics_csv = ''; + + if ($title_match) + { + $title_match_topics = get_title_match_topics($title_match_sql, $title_match_limit, $search_in_forums_ary); + + if (!$search_match_topics_csv = join(',', $title_match_topics)) + { + $tr_error = true; + } + } + else + { + $title_match_val = ''; + } + + // Get torrents list + if (!$tr_error && !$tor_list_sql) + { + $reg_time = $time_opt[$time_val]['sql']; + $poster_id_sql = (int) $poster_id_val; + $s_seen_time = $s_not_seen_opt[$s_not_seen_val]['sql']; + $s_seen_sign = ($s_not_seen_val == $never) ? '=' : '<'; + $s_seen_exclude = ($s_not_seen_val == $never) ? '' : "AND tor.seeder_last_seen != 0"; + $order_by_peers = ($order_val == $ord_seeders || $order_val == $ord_leechers); + $order_by_speed = ($order_val == $ord_sp_up || $order_val == $ord_sp_down); + + $join_t = in_array($order_val, array($ord_name, $ord_repl, $ord_views, $ord_last_p, $title_match)); + $join_sn = ($only_active || $order_by_peers || $order_by_speed); + $join_dl = $dl_search; + + // Start building SQL + $SQL = DB()->get_empty_sql_array(); + + // SELECT + $SQL['SELECT'][] = "tor.topic_id"; + + // FROM + $SQL['FROM'][] = $torrents_tbl; + + if ($join_t) + { + $SQL['INNER JOIN'][] = "$topics_tbl ON(t.topic_id = tor.topic_id)"; + } + if ($join_sn) + { + $SQL['LEFT JOIN'][] = "$tr_snap_tbl ON(sn.topic_id = tor.topic_id)"; + } + if ($join_dl) + { + $SQL['INNER JOIN'][] = "$dl_stat_tbl ON( + dl.topic_id = tor.topic_id + AND dl.user_id = $user_id + AND dl.user_status IN($dl_status_csv) + )"; + } + + // WHERE + $title_match_notfound_flag = false; + if ($search_match_topics_csv) + { + $SQL['WHERE'][] = "tor.topic_id IN($search_match_topics_csv)"; + } + if ($search_in_forums_csv) + { + $SQL['WHERE'][] = "tor.forum_id IN($search_in_forums_csv)"; + } + if ($excluded_forums_csv) + { + $SQL['WHERE'][] = "tor.forum_id NOT IN($excluded_forums_csv)"; + } + if ($poster_id) + { + $SQL['WHERE'][] = "tor.poster_id = $poster_id_sql"; + } + if ($only_new) + { + $SQL['WHERE'][] = "tor.reg_time > $lastvisit"; + } + if ($prev_days) + { + $SQL['WHERE'][] = "tor.reg_time > $reg_time"; + } + if ($s_not_seen) + { + $SQL['WHERE'][] = "tor.seeder_last_seen $s_seen_sign $s_seen_time $s_seen_exclude"; + } + if ($only_my) + { + $SQL['WHERE'][] = "tor.poster_id = $user_id"; + } + if ($only_active) + { + $SQL['WHERE'][] = "sn.topic_id IS NOT NULL"; + } + if ($seed_exist) + { + $SQL['WHERE'][] = "sn.seeders >= 1"; + } + + // ORDER + $SQL['ORDER BY'][] = "{$order_opt[$order_val]['sql']} {$sort_opt[$sort_val]['sql']}"; + + // LIMIT + $SQL['LIMIT'][] = $tor_search_limit; + + if ($title_match && $title_match_notfound_flag) + { + $tor_list_sql = ''; + $tor_count = 0; + } + else + { + foreach (DB()->fetch_rowset($SQL) as $row) + { + $tor_list_ary[] = $row['topic_id']; + } + $tor_list_sql = join(',', $tor_list_ary); + $tor_count = count($tor_list_ary); + } + } + + if (!$tor_list_sql || $start > $tor_count) + { + $template->assign_vars(array( + 'TOR_NOT_FOUND' => true, + 'NO_MATCH_MSG' => $lang['NO_MATCH'], + )); + } + else + { + // Save result in DB + if ($tor_count > $per_page && !$search_id) + { + $search_id = make_rand_str(SEARCH_ID_LENGTH); + $search_type = SEARCH_TYPE_TRACKER; + + $columns = 'session_id, search_type, search_id, search_time, search_settings, search_array'; + $values = "'$session_id', $search_type, '$search_id', ". TIMENOW .", '$curr_set_sql', '$tor_list_sql'"; + + DB()->query("REPLACE INTO ". BB_SEARCH ." ($columns) VALUES ($values)"); + } + unset($columns, $values, $curr_set_sql, $tor_list_sql); + + $tor_to_show = ($tor_count > $per_page) ? array_slice($tor_list_ary, $start, $per_page) : $tor_list_ary; + + if (!$tor_to_show = join(',', $tor_to_show)) + { + bb_die($lang['NO_SEARCH_MATCH']); + } + + // SELECT + $select = " + SELECT + tor.topic_id, tor.post_id, tor.attach_id, tor.size, tor.reg_time, tor.complete_count, tor.seeder_last_seen, tor.tor_status, tor.tor_type, + t.topic_title, t.topic_replies, t.topic_views, sn.seeders, sn.leechers, tor.info_hash + "; + $select .= (!$hide_speed) ? ", sn.speed_up, sn.speed_down" : ''; + $select .= (!$hide_forum) ? ", tor.forum_id" : ''; + $select .= (!$hide_cat) ? ", f.cat_id" : ''; + $select .= (!$hide_author) ? ", tor.poster_id, u.username" : ''; + $select .= (!IS_GUEST) ? ", dl.user_status AS dl_status" : ''; + + // FROM + $from = " + FROM $torrents_tbl + LEFT JOIN $topics_tbl ON(t.topic_id = tor.topic_id) + "; + $from .= (!$hide_cat) ? " + LEFT JOIN $forums_tbl ON(f.forum_id = t.forum_id) + " : ''; + $from .= (!$hide_author) ? " + LEFT JOIN $users_tbl ON(u.user_id = tor.poster_id) + " : ''; + $from .= (!IS_GUEST) ? " + LEFT JOIN $dl_stat_tbl ON(dl.topic_id = tor.topic_id AND dl.user_id = $user_id) + " : ''; + $from .= "LEFT JOIN $tr_snap_tbl ON(sn.topic_id = tor.topic_id)"; + + // WHERE + $where = " + WHERE tor.topic_id IN($tor_to_show) + "; + + // ORDER + $order = "ORDER BY ". $order_opt[$order_val]['sql']; + + // SORT + $sort = $sort_opt[$sort_val]['sql']; + + // LIMIT + $limit = "LIMIT $per_page"; + + $sql = " + $select + $from + $where + $order + $sort + $limit + "; + + $passkey = DB()->fetch_row("SELECT auth_key FROM ". BB_BT_USERS ." WHERE user_id = ". (int) $user_id ." LIMIT 1"); + // Build torrents table + foreach (DB()->fetch_rowset($sql) as $tor) + { + $dl = isset($tor['speed_down']) ? $tor['speed_down'] : 0; + $ul = isset($tor['speed_up']) ? $tor['speed_up'] : 0; + + $seeds = $tor['seeders']; + $leechs = $tor['leechers']; + $s_last = $tor['seeder_last_seen']; + $att_id = $tor['attach_id']; + $size = $tor['size']; + $tor_magnet = create_magnet($tor['info_hash'], $passkey['auth_key'], $userdata['session_logged_in']); + $compl = $tor['complete_count']; + $dl_sp = ($dl) ? humn_size($dl, 0, 'KB') .'/s' : '0 KB/s'; + $ul_sp = ($ul) ? humn_size($ul, 0, 'KB') .'/s' : '0 KB/s'; + + $dl_class = isset($tor['dl_status']) ? $dl_link_css[$tor['dl_status']] : 'genmed'; + $row_class = !($row_num & 1) ? $row_class_1 : $row_class_2; + $row_num++; + + $cat_id = (!$hide_cat && isset($tor['cat_id'])) ? $tor['cat_id'] : ''; + $forum_id = (!$hide_forum && isset($tor['forum_id'])) ? $tor['forum_id'] : ''; + $poster_id = (!$hide_author && isset($tor['poster_id'])) ? $tor['poster_id'] : ''; + + // Gold/Silver releases mod + $is_gold = ''; + if ($bb_cfg['gold_silver_enabled']) + { + if ($tor['tor_type'] == TOR_TYPE_GOLD) + { + $is_gold = ' '; + } + elseif ($tor['tor_type'] == TOR_TYPE_SILVER) + { + $is_gold = ' '; + } + } + // END Gold/Silver releases mod + + $template->assign_block_vars('tor', array( + 'CAT_ID' => $cat_id, + 'CAT_TITLE' => ($cat_id) ? $cat_title_html[$cat_id] : '', + 'FORUM_ID' => $forum_id, + 'FORUM_NAME' => ($forum_id) ? $forum_name_html[$forum_id] : '', + 'TOPIC_ID' => $tor['topic_id'], + 'TOPIC_TITLE' => wbr($tor['topic_title']), + 'POST_ID' => $tor['post_id'], + 'POSTER_ID' => $poster_id, + 'USERNAME' => isset($tor['username']) ? wbr($tor['username']) : '', + + 'ROW_CLASS' => $row_class, + 'ROW_NUM' => $row_num, + 'DL_CLASS' => $dl_class, + 'IS_NEW' => (!IS_GUEST && $tor['reg_time'] > $lastvisit), + 'USER_AUTHOR' => (!IS_GUEST && $poster_id == $user_id), + + 'ATTACH_ID' => $att_id, + 'MAGNET' => $tor_magnet, + 'TOR_TYPE' => $is_gold, + + 'TOR_FROZEN' => isset($bb_cfg['tor_frozen'][$tor['tor_status']]), + 'TOR_STATUS_ICON' => $bb_cfg['tor_icons'][$tor['tor_status']], + 'TOR_STATUS_TEXT' => $lang['tor_status'][$tor['tor_status']], + + 'TOR_SIZE_RAW' => $size, + 'TOR_SIZE' => humn_size($size), + 'UL_SPEED' => $ul_sp, + 'DL_SPEED' => $dl_sp, + 'SEEDS' => ($seeds) ? $seeds : 0, + 'SEEDS_TITLE' => ($seeds) ? 'Seeders' : (" Last seen: \n ". (($s_last) ? bb_date($s_last, $date_format) : 'Never')), + 'LEECHS' => ($leechs) ? $leechs : 0, + 'COMPLETED' => ($compl) ? $compl : 0, + 'REPLIES' => $tor['topic_replies'], + 'VIEWS' => $tor['topic_views'], + 'ADDED_RAW' => $tor['reg_time'], + 'ADDED_TIME' => bb_date($tor['reg_time'], $time_format), + 'ADDED_DATE' => bb_date($tor['reg_time'], $date_format), + )); + } + } +} +else +{ + $template->assign_vars(array( + 'TOR_NOT_FOUND' => true, + 'NO_MATCH_MSG' => $lang['BT_NO_SEARCHABLE_FORUMS'], + )); +} + +// Pagination +if ($tor_count) +{ + $base_url = "$tracker_url?search_id=$search_id"; + $search_matches = ($tor_count == 1) ? sprintf($lang['FOUND_SEARCH_MATCH'], $tor_count) : sprintf($lang['FOUND_SEARCH_MATCHES'], $tor_count); + $search_max = "(max: $tor_search_limit)"; + + $template->assign_vars(array( + 'MATCHES' => $search_matches, + 'SERACH_MAX' => $search_max, + 'PAGINATION' => generate_pagination($base_url, $tor_count, $per_page, $start), + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], (floor($start / $per_page) + 1), ceil($tor_count / $per_page)), + )); +} + +if(empty($cat_forum)) +{ + message_die(GENERAL_MESSAGE, $lang['BT_NO_SEARCHABLE_FORUMS']); +} + +// Forum select +$opt = ''; +foreach ($cat_forum['c'] as $cat_id => $forums_ary) +{ + $opt .= '\n"; + + foreach ($forums_ary as $forum_id) + { + $forum_name = $forum_name_html[$forum_id]; + $forum_name = str_short($forum_name, $max_forum_name_len-2); + $style = ''; + if (!isset($cat_forum['subforums'][$forum_id])) + { + $class = 'root_forum'; + $class .= isset($cat_forum['forums_with_sf'][$forum_id]) ? ' has_sf' : ''; + $style = " class=\"$class\""; + } + $selected = (isset($search_in_forums_fary[$forum_id])) ? HTML_SELECTED : ''; + $opt .= '\n"; + } + + $opt .= "\n"; +} +$search_all_opt = '\n"; +$cat_forum_select = "\n".'\n"; + +// Sort dir +$template->assign_vars(array( + 'SORT_NAME' => $sort_key, + 'SORT_ASC' => $sort_asc, + 'SORT_DESC' => $sort_desc, + 'SORT_ASC_CHECKED' => ($sort_val == $sort_asc) ? HTML_CHECKED : '', + 'SORT_DESC_CHECKED' => ($sort_val == $sort_desc) ? HTML_CHECKED : '', +)); + +// Displaying options +$template->assign_vars(array( + 'SHOW_CAT_CHBOX' => build_checkbox ($show_cat_key, $lang['BT_SHOW_CAT'], $show_cat_val), + 'SHOW_FORUM_CHBOX' => build_checkbox ($show_forum_key, $lang['BT_SHOW_FORUM'], $show_forum_val), + 'SHOW_AUTHOR_CHBOX' => build_checkbox ($show_author_key, $lang['BT_SHOW_AUTHOR'], $show_author_val), + 'SHOW_SPEED_CHBOX' => build_checkbox ($show_speed_key, $lang['BT_SHOW_SPEED'], $show_speed_val), + 'ALL_WORDS_CHBOX' => build_checkbox ($all_words_key, $lang['SEARCH_ALL_WORDS'], $all_words_val), + + 'ONLY_MY_CHBOX' => build_checkbox ($my_key, $lang['BT_ONLY_MY'], $only_my, IS_GUEST), + 'ONLY_ACTIVE_CHBOX' => build_checkbox ($active_key, $lang['BT_ONLY_ACTIVE'], $active_val), + 'SEED_EXIST_CHBOX' => build_checkbox ($seed_exist_key, $lang['BT_SEED_EXIST'], $seed_exist), + 'ONLY_NEW_CHBOX' => build_checkbox ($new_key, $lang['BT_ONLY_NEW'], $only_new, IS_GUEST), + + 'DL_CANCEL_CHBOX' => build_checkbox ($dl_cancel_key, $lang['SEARCH_DL_CANCEL'], $dl_cancel_val, IS_GUEST, 'dlCancel'), + 'DL_COMPL_CHBOX' => build_checkbox ($dl_compl_key, $lang['SEARCH_DL_COMPLETE'], $dl_compl_val, IS_GUEST, 'dlComplete'), + 'DL_DOWN_CHBOX' => build_checkbox ($dl_down_key, $lang['SEARCH_DL_DOWN'], $dl_down_val, IS_GUEST, 'dlDown'), + 'DL_WILL_CHBOX' => build_checkbox ($dl_will_key, $lang['SEARCH_DL_WILL'], $dl_will_val, IS_GUEST, 'dlWill'), + + 'POSTER_NAME_NAME' => $poster_name_key, + 'POSTER_NAME_VAL' => htmlCHR($poster_name_val), + 'TITLE_MATCH_NAME' => $title_match_key, + 'TITLE_MATCH_VAL' => $title_match_val, + + 'AJAX_TOPICS' => $user->opt_js['tr_t_ax'], + 'U_SEARCH_USER' => "search.php?mode=searchuser&input_name=$poster_name_key", +)); + +// Hidden fields +$save_through_pages = array( + 'all_words', + 'active', + 'dl_cancel', + 'dl_compl', + 'dl_down', + 'dl_will', + 'my', + 'new', + 'seed_exist', + 'show_author', + 'show_cat', + 'show_forum', + 'show_speed', +); +$hidden_fields = array(); +foreach ($save_through_pages as $name) +{ + $hidden_fields['prev_'. ${"{$name}_key"}] = ${"{$name}_val"}; +} + +// Set colspan +$tor_colspan = $tor_colspan - $hide_cat - $hide_forum - $hide_author - $hide_speed; + +$template->assign_vars(array( + 'PAGE_TITLE' => $lang['TRACKER'], + 'S_HIDDEN_FIELDS' => build_hidden_fields($hidden_fields), + 'CAT_FORUM_SELECT' => $cat_forum_select, + 'ORDER_SELECT' => build_select($order_key, $order_select, $order_val), + 'TIME_SELECT' => build_select($time_key, $time_select, $time_val), + 'S_NOT_SEEN_SELECT' => build_select($s_not_seen_key, $s_not_seen_select, $s_not_seen_val), + 'TOR_SEARCH_ACTION' => $tracker_url, + 'TOR_COLSPAN' => $tor_colspan, + 'TITLE_MATCH_MAX' => $title_match_max_len, + 'POSTER_NAME_MAX' => $poster_name_max_len, + 'POSTER_ERROR' => $poster_error, + 'SHOW_SEARCH_OPT' => (bool) $allowed_forums, + 'SHOW_CAT' => $show_cat_val, + 'SHOW_FORUM' => $show_forum_val, + 'SHOW_AUTHOR' => $show_author_val, + 'SHOW_SPEED' => $show_speed_val, + + 'TR_CAT_URL' => "$tracker_url?$cat_key=", + 'TR_FORUM_URL' => "$tracker_url?$forum_key=", + 'TR_POSTER_URL' => "$tracker_url?$poster_id_key=", +)); + +print_page('tracker.tpl'); \ No newline at end of file diff --git a/upload/triggers/$on b/upload/triggers/$on new file mode 100644 index 000000000..e69de29bb diff --git a/upload/triggers/.htaccess b/upload/triggers/.htaccess new file mode 100644 index 000000000..baa56e5a3 --- /dev/null +++ b/upload/triggers/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/upload/triggers/cron_allowed b/upload/triggers/cron_allowed new file mode 100644 index 000000000..e69de29bb diff --git a/upload/viewforum.php b/upload/viewforum.php new file mode 100644 index 000000000..33f4f1a66 --- /dev/null +++ b/upload/viewforum.php @@ -0,0 +1,618 @@ +enqueue(array( + 'moderators', +)); + +$page_cfg['load_tpl_vars'] = array( + 'post_icons', + 'topic_icons', +); + +// Init request vars +$forum_id = (int) request_var('f', ''); +$start = abs(intval(request_var('start', ''))); +$mark_read = (request_var('mark', '') === 'topics'); + +$anon = ANONYMOUS; + +// Start session +$user->session_start(); + +$lastvisit = (IS_GUEST) ? TIMENOW : $userdata['user_lastvisit']; + +// Caching output +$req_page = "forum_f{$forum_id}"; +$req_page .= ($start) ? "_start{$start}" : ''; + +define('REQUESTED_PAGE', $req_page); +caching_output(IS_GUEST, 'send', REQUESTED_PAGE .'_guest'); + +// Check if the user has actually sent a forum ID +$sql = "SELECT * FROM ". BB_FORUMS ." WHERE forum_id = $forum_id LIMIT 1"; + +if (!$forum_id OR !$forum_data = DB()->fetch_row($sql)) +{ + bb_die($lang['FORUM_NOT_EXIST']); +} + +// Only new +$only_new = $user->opt_js['only_new']; +$only_new_sql = ''; +if ($only_new == ONLY_NEW_POSTS) +{ + $only_new_sql = "AND t.topic_last_post_time > $lastvisit"; +} +else if ($only_new == ONLY_NEW_TOPICS) +{ + $only_new_sql = "AND t.topic_time > $lastvisit"; +} + +// Auth +$is_auth = auth(AUTH_ALL, $forum_id, $userdata, $forum_data); + +$moderation = (!empty($_REQUEST['mod']) && $is_auth['auth_mod']); + +if (!$is_auth['auth_view']) +{ + if (IS_GUEST) + { + $redirect = "f=$forum_id"; + $redirect .= ($start) ? "&start=$start" : ''; + redirect("login.php?redirect=viewforum.php&$redirect"); + } + // The user is not authed to read this forum ... + $message = sprintf($lang['SORRY_AUTH_VIEW'], $is_auth['auth_view_type']); + bb_die($message); +} + +// Redirect to login page if not admin session +$mod_redirect_url = ''; + +if ($is_auth['auth_mod']) +{ + $redirect = isset($_POST['redirect']) ? $_POST['redirect'] : $_SERVER['REQUEST_URI']; + $redirect = url_arg($redirect, 'mod', 1, '&'); + $mod_redirect_url = "login.php?redirect=$redirect&admin=1"; + + if ($moderation && !$userdata['session_admin']) + { + redirect($mod_redirect_url); + } + + $select_st = array_merge(array('Выберите статус' => -1), array_flip($lang['tor_status'])); + $template->assign_vars(array( + 'SELECT_ST' => build_select('st', $select_st, -1), + )); +} + +// Topics read tracks +$tracking_topics = get_tracks('topic'); +$tracking_forums = get_tracks('forum'); + +if ($mark_read && !IS_GUEST) +{ + set_tracks(COOKIE_FORUM, $tracking_forums, $forum_id); + + $message = $lang['TOPICS_MARKED_READ'] .'

    '; + $message .= sprintf($lang['CLICK_RETURN_FORUM'], '', ''); + $message .= '

    '; + $message .= sprintf($lang['CLICK_RETURN_INDEX'], '', ''); + bb_die($message); +} + +// Subforums +$show_subforums = ($bb_cfg['sf_on_first_page_only']) ? !$start : true; + +if (!$forums = $datastore->get('cat_forums')) +{ + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); +} + +if (!$forum_data['forum_parent'] && isset($forums['f'][$forum_id]['subforums']) && $show_subforums) +{ + $not_auth_forums = ($bb_cfg['sf_check_view_permissions']) ? $user->get_not_auth_forums(AUTH_VIEW) : ''; + $ignore_forum_sql = ($not_auth_forums) ? "AND f.forum_id NOT IN($not_auth_forums)" : ''; + + $sql = " + SELECT + f.forum_id, f.forum_status, f.forum_last_post_id, f.forum_posts, f.forum_topics, + t.topic_last_post_time, t.topic_id AS last_topic_id, t.topic_title AS last_topic_title, + p.poster_id AS sf_last_user_id, IF(p.poster_id = $anon, p.post_username, u.username) AS sf_last_username + FROM ". BB_FORUMS ." f + LEFT JOIN ". BB_TOPICS ." t ON(f.forum_last_post_id = t.topic_last_post_id) + LEFT JOIN ". BB_POSTS ." p ON(f.forum_last_post_id = p.post_id) + LEFT JOIN ". BB_USERS ." u ON(p.poster_id = u.user_id) + WHERE f.forum_parent = $forum_id + $only_new_sql + $ignore_forum_sql + GROUP BY f.forum_id + ORDER BY f.forum_order + "; + + if ($rowset = DB()->fetch_rowset($sql)) + { + $template->assign_vars(array( + 'SHOW_SUBFORUMS' => true, + 'FORUM_IMG' => $images['forum'], + 'FORUM_NEW_IMG' => $images['forum_new'], + 'FORUM_LOCKED_IMG' => $images['forum_locked'], + )); + } + foreach ($rowset as $sf_data) + { + $sf_forum_id = $sf_data['forum_id']; + $sf_last_tid = $sf_data['last_topic_id']; + $folder_image = $images['forum']; + $last_post = $lang['NO_POSTS']; + + if (!$fname_html =& $forums['forum_name_html'][$sf_forum_id]) + { + continue; + } + + if ($sf_data['forum_status'] == FORUM_LOCKED) + { + $folder_image = $images['forum_locked']; + } + else if (is_unread($sf_data['topic_last_post_time'], $sf_last_tid, $sf_forum_id)) + { + $folder_image = $images['forum_new']; + } + + $last_post_username = ($sf_data['sf_last_username']) ? $sf_data['sf_last_username'] : $lang['GUEST']; + + if ($sf_data['forum_last_post_id']) + { + $last_post = bb_date($sf_data['topic_last_post_time'], $bb_cfg['last_post_date_format']); + $last_post .= '
    '; + $last_post .= ($sf_data['sf_last_user_id'] != ANONYMOUS) ? ''. $last_post_username .'' : $last_post_username; + $last_post .= 'latest'; + } + + $template->assign_block_vars('f', array( + 'FORUM_FOLDER_IMG' => $folder_image, + + 'FORUM_NAME' => $fname_html, + 'FORUM_DESC' => $forums['f'][$sf_forum_id]['forum_desc'], + 'U_VIEWFORUM' => FORUM_URL . $sf_forum_id, + 'TOPICS' => commify($sf_data['forum_topics']), + 'POSTS' => commify($sf_data['forum_posts']), + 'LAST_POST' => $last_post, + 'MODERATORS' => '', + )); + + if ($sf_data['forum_last_post_id']) + { + $template->assign_block_vars('f.last', array( + 'FORUM_LAST_POST' => true, + 'SHOW_LAST_TOPIC' => $show_last_topic, + 'LAST_TOPIC_ID' => $sf_data['last_topic_id'], + 'LAST_TOPIC_TIP' => $sf_data['last_topic_title'], + 'LAST_TOPIC_TITLE' => str_short($sf_data['last_topic_title'], $last_topic_max_len), + 'LAST_POST_TIME' => bb_date($sf_data['topic_last_post_time'], $bb_cfg['last_post_date_format']), + 'LAST_POST_ID' => $sf_data['forum_last_post_id'], + 'LAST_POST_USER_NAME' => $last_post_username, + 'LAST_POST_USER_ID' => ($sf_data['sf_last_user_id'] != ANONYMOUS) ? $sf_data['sf_last_user_id'] : '', + 'ICON_LATEST_REPLY' => $images['icon_latest_reply'], + )); + } + else + { + $template->assign_block_vars('f.last', array('FORUM_LAST_POST' => false)); + } + } +} +else if ($parent_id = $forum_data['forum_parent']) +{ + $template->assign_vars(array( + 'HAS_PARENT_FORUM' => true, + 'PARENT_FORUM_HREF' => FORUM_URL . $forum_data['forum_parent'], + 'PARENT_FORUM_NAME' => $forums['forum_name_html'][$parent_id], + )); +} +unset($forums, $rowset); +$datastore->rm('cat_forums'); + +// Topics per page +$topics_per_page = $bb_cfg['topics_per_page']; +$select_tpp = ''; + +if ($is_auth['auth_mod']) +{ + if ($req_tpp = abs(intval(@$_REQUEST['tpp'])) AND in_array($req_tpp, $bb_cfg['allowed_topics_per_page'])) + { + $topics_per_page = $req_tpp; + } + + $select_tpp = array(); + foreach ($bb_cfg['allowed_topics_per_page'] as $tpp) + { + $select_tpp[$tpp] = $tpp; + } +} + +// Obtain list of moderators +$moderators = array(); +if (!$mod = $datastore->get('moderators')) +{ + $datastore->update('moderators'); + $mod = $datastore->get('moderators'); +} + +if (isset($mod['mod_users'][$forum_id])) +{ + foreach ($mod['mod_users'][$forum_id] as $user_id) + { + $moderators[] = ''. $mod['name_users'][$user_id] .''; + } +} +if (isset($mod['mod_groups'][$forum_id])) +{ + foreach ($mod['mod_groups'][$forum_id] as $group_id) + { + $moderators[] = ''. $mod['name_groups'][$group_id] .''; + } +} + +$template->assign_vars(array( + 'MODERATORS' => ($moderators) ? join(', ', $moderators) : $lang['NONE'], +)); + +unset($moderators, $mod); +$datastore->rm('moderators'); + +// Generate a 'Show topics in previous x days' select box. +$topic_days = 0; // all the time +$forum_topics = $forum_data['forum_topics']; + +$sel_previous_days = array( + 0 => $lang['ALL_POSTS'], + 1 => $lang['1_DAY'], + 7 => $lang['7_DAYS'], + 14 => $lang['2_WEEKS'], + 30 => $lang['1_MONTH'], + 90 => $lang['3_MONTHS'], + 180 => $lang['6_MONTHS'], + 364 => $lang['1_YEAR'], +); + +if (!empty($_REQUEST['topicdays'])) +{ + if ($req_topic_days = abs(intval($_REQUEST['topicdays'])) AND isset($sel_previous_days[$req_topic_days])) + { + $sql = " + SELECT COUNT(*) AS forum_topics + FROM ". BB_TOPICS ." + WHERE forum_id = $forum_id + AND topic_last_post_time > ". (TIMENOW - 86400*$req_topic_days) ." + "; + + if ($row = DB()->fetch_row($sql)) + { + $topic_days = $req_topic_days; + $forum_topics = $row['forum_topics']; + } + } +} +// Correct $start value +if ($start > $forum_topics) +{ + redirect("viewforum.php?f=$forum_id"); +} + +// Generate SORT and ORDER selects +$sort_value = isset($_REQUEST['sort']) ? (int) $_REQUEST['sort'] : $forum_data['forum_display_sort']; +$order_value = isset($_REQUEST['order']) ? (int) $_REQUEST['order'] : $forum_data['forum_display_order']; +$sort_list = ''; +$order_list = ''; +$s_display_order = ' '. $lang['SORT_BY'] .': '. $sort_list . $order_list .' '; + +// Selected SORT and ORDER methods +$sort_method = get_forum_display_sort_option($sort_value, 'field', 'sort'); +$order_method = get_forum_display_sort_option($order_value, 'field', 'order'); + +$order_sql = "ORDER BY t.topic_type DESC, $sort_method $order_method"; + +$limit_topics_time_sql = ($topic_days) ? "AND t.topic_last_post_time > ". (TIMENOW - 86400*$topic_days) : ''; + +$select_tor_sql = $join_tor_sql = ''; +$join_dl = ($bb_cfg['show_dl_status_in_forum'] && !IS_GUEST); + +if ($forum_data['allow_reg_tracker']) +{ + $select_tor_sql = ', + bt.auth_key, tor.info_hash, tor.size AS tor_size, tor.reg_time, tor.complete_count, tor.seeder_last_seen, tor.attach_id, tor.tor_status, tor.tor_type, + sn.seeders, sn.leechers + '; + $select_tor_sql .= ($join_dl) ? ', dl.user_status AS dl_status' : ''; + + $join_tor_sql = " + LEFT JOIN ". BB_BT_TORRENTS ." tor ON(t.topic_id = tor.topic_id) + LEFT JOIN ". BB_BT_USERS ." bt ON(bt.user_id = {$userdata['user_id']}) + LEFT JOIN ". BB_BT_TRACKER_SNAP ." sn ON(tor.topic_id = sn.topic_id) + "; + $join_tor_sql .= ($join_dl) ? " LEFT JOIN ". BB_BT_DLSTATUS ." dl ON(dl.user_id = {$userdata['user_id']} AND dl.topic_id = t.topic_id)" : ''; +} + +// Title match +$title_match_sql = ''; + +if ($title_match =& $_REQUEST[$title_match_key]) +{ + if ($title_match = substr(trim($title_match), 0, $title_match_max_len)) + { + $search_bool_mode = ($bb_cfg['allow_search_in_bool_mode']) ? " IN BOOLEAN MODE" : ''; + $search_text_sql = DB()->escape($title_match); + $title_match_sql = " + AND MATCH (t.topic_title) AGAINST ('$search_text_sql'". $search_bool_mode .") + "; + $start = 0; + $forum_topics = $topics_per_page; + } +} + +// Get topics +$topic_ids = $topic_rowset = array(); + +// IDs +$sql = " + SELECT t.topic_id + FROM ". BB_TOPICS ." t + WHERE t.forum_id = $forum_id + $only_new_sql + $title_match_sql + $limit_topics_time_sql + $order_sql + LIMIT $start, $topics_per_page +"; +foreach (DB()->fetch_rowset($sql) as $row) +{ + $topic_ids[] = $row['topic_id']; +} + +// Titles, posters etc. +if ($topics_csv = join(',', $topic_ids)) +{ + $topic_rowset = DB()->fetch_rowset(" + SELECT + t.*, t.topic_poster AS first_user_id, + IF(t.topic_poster = $anon, p1.post_username, u1.username) AS first_username, + p2.poster_id AS last_user_id, + IF(p2.poster_id = $anon, p2.post_username, u2.username) AS last_username + $select_tor_sql + FROM ". BB_TOPICS ." t + LEFT JOIN ". BB_POSTS ." p1 ON(t.topic_first_post_id = p1.post_id) + LEFT JOIN ". BB_USERS ." u1 ON(t.topic_poster = u1.user_id) + LEFT JOIN ". BB_POSTS ." p2 ON(t.topic_last_post_id = p2.post_id) + LEFT JOIN ". BB_USERS ." u2 ON(p2.poster_id = u2.user_id) + $join_tor_sql + WHERE t.topic_id IN($topics_csv) + GROUP BY t.topic_id + $order_sql + "); +} + +$found_topics = count($topic_rowset); + +// Define censored word matches +$orig_word = $replacement_word = array(); +obtain_word_list($orig_word, $replacement_word); + +$post_new_topic_url = "posting.php?mode=newtopic&f=$forum_id"; +$post_new_topic_url .= ($forum_data['topic_tpl_id']) ? '&tpl=1' : ''; + +// Post URL generation for templating vars +$template->assign_vars(array( + 'U_POST_NEW_TOPIC' => $post_new_topic_url, + 'S_SELECT_TOPIC_DAYS' => build_select('topicdays', array_flip($sel_previous_days), $topic_days), + 'S_POST_DAYS_ACTION' => "viewforum.php?f=$forum_id&start=$start", + 'S_DISPLAY_ORDER' => $s_display_order, +)); + +// User authorisation levels output +$u_auth = array(); +$u_auth[] = ($is_auth['auth_post']) ? $lang['RULES_POST_CAN'] : $lang['RULES_POST_CANNOT']; +$u_auth[] = ($is_auth['auth_reply']) ? $lang['RULES_REPLY_CAN'] : $lang['RULES_REPLY_CANNOT']; +$u_auth[] = ($is_auth['auth_edit']) ? $lang['RULES_EDIT_CAN'] : $lang['RULES_EDIT_CANNOT']; +$u_auth[] = ($is_auth['auth_delete']) ? $lang['RULES_DELETE_CAN'] : $lang['RULES_DELETE_CANNOT']; +$u_auth[] = ($is_auth['auth_vote']) ? $lang['RULES_VOTE_CAN'] : $lang['RULES_VOTE_CANNOT']; +$u_auth[] = ($is_auth['auth_attachments']) ? $lang['RULES_ATTACH_CAN'] : $lang['RULES_ATTACH_CANNOT']; +$u_auth[] = ($is_auth['auth_download']) ? $lang['RULES_DOWNLOAD_CAN'] : $lang['RULES_DOWNLOAD_CANNOT']; +$u_auth[] = ($is_auth['auth_mod']) ? $lang['RULES_MODERATE'] : ''; +$u_auth = join("
    \n", $u_auth); + +$template->assign_vars(array( + 'SHOW_JUMPBOX' => true, + 'PAGE_TITLE' => htmlCHR($forum_data['forum_name']), + 'FORUM_ID' => $forum_id, + 'FORUM_NAME' => htmlCHR($forum_data['forum_name']), + 'TORRENTS' => $forum_data['allow_reg_tracker'], + 'POST_IMG' => ($forum_data['forum_status'] == FORUM_LOCKED) ? $images['post_locked'] : $images['post_new'], + + 'FOLDER_IMG' => $images['folder'], + 'FOLDER_NEW_IMG' => $images['folder_new'], + 'FOLDER_LOCKED_IMG' => $images['folder_locked'], + 'FOLDER_STICKY_IMG' => $images['folder_sticky'], + 'FOLDER_ANNOUNCE_IMG' => $images['folder_announce'], + 'FOLDER_DOWNLOAD_IMG' => $images['folder_dl'], + + 'SHOW_ONLY_NEW_MENU' => true, + 'ONLY_NEW_POSTS_ON' => ($only_new == ONLY_NEW_POSTS), + 'ONLY_NEW_TOPICS_ON' => ($only_new == ONLY_NEW_TOPICS), + + 'TITLE_MATCH' => htmlCHR($title_match), + 'SELECT_TPP' => ($select_tpp) ? build_select('tpp', $select_tpp, $topics_per_page, null, null, 'onchange="$(\'#tpp\').submit();"') : '', + 'T_POST_NEW_TOPIC' => ($forum_data['forum_status'] == FORUM_LOCKED) ? $lang['FORUM_LOCKED'] : $lang['POST_NEW_TOPIC'], + 'S_AUTH_LIST' => $u_auth, + 'U_VIEW_FORUM' => FORUM_URL . $forum_id, + 'U_MARK_READ' => FORUM_URL . $forum_id ."&mark=topics", + 'U_SEARCH_SELF' => "search.php?uid={$userdata['user_id']}&f=$forum_id", +)); + +// Okay, lets dump out the page ... +foreach ($topic_rowset as $topic) +{ + $topic_id = $topic['topic_id']; + $moved = ($topic['topic_status'] == TOPIC_MOVED); + $replies = $topic['topic_replies']; + $t_hot = ($replies >= $bb_cfg['hot_threshold']); + $t_type = $topic['topic_type']; + $separator = ''; + $is_unread = is_unread($topic['topic_last_post_time'], $topic_id, $forum_id); + + if ($t_type == POST_ANNOUNCE && !defined('ANNOUNCE_SEP')) + { + define('ANNOUNCE_SEP', true); + $separator = $lang['TOPICS_ANNOUNCEMENT']; + } + else if ($t_type == POST_STICKY && !defined('STICKY_SEP')) + { + define('STICKY_SEP', true); + $separator = $lang['TOPICS_STICKY']; + } + else if ($t_type == POST_NORMAL && !defined('NORMAL_SEP')) + { + if (defined('ANNOUNCE_SEP') || defined('STICKY_SEP')) + { + define('NORMAL_SEP', true); + $separator = $lang['TOPICS_NORMAL']; + } + } + + // Gold/Silver releases mod + $is_gold = ''; + if ($bb_cfg['gold_silver_enabled'] && isset($topic['tor_type'])) + { + if ($topic['tor_type'] == TOR_TYPE_GOLD) + { + $is_gold = ' '; + } + elseif ($topic['tor_type'] == TOR_TYPE_SILVER) + { + $is_gold = ' '; + } + } + // END Gold/Silver releases mod + + $template->assign_block_vars('t', array( + 'FORUM_ID' => $forum_id, + 'TOPIC_ID' => $topic_id, + 'HREF_TOPIC_ID' => ($moved) ? $topic['topic_moved_id'] : $topic['topic_id'], + 'TOPIC_TITLE' => wbr($topic['topic_title']), + 'TOPICS_SEPARATOR' => $separator, + 'IS_UNREAD' => $is_unread, + 'TOPIC_ICON' => get_topic_icon($topic, $is_unread), + 'PAGINATION' => ($moved) ? '' : build_topic_pagination(TOPIC_URL . $topic_id, $replies, $bb_cfg['posts_per_page']), + 'REPLIES' => $replies, + 'VIEWS' => $topic['topic_views'], + 'TOR_STALED' => ($forum_data['allow_reg_tracker'] && !($t_type == POST_ANNOUNCE || $t_type == POST_STICKY || $topic['tor_size'])), + 'TOR_FROZEN' => isset($topic['tor_status']) ? isset($bb_cfg['tor_frozen'][$topic['tor_status']]) : '', + 'TOR_TYPE' => $is_gold, + + 'TOR_STATUS_ICON' => isset($topic['tor_status']) ? $bb_cfg['tor_icons'][$topic['tor_status']] : '', + + 'ATTACH' => $topic['topic_attachment'], + 'STATUS' => $topic['topic_status'], + 'TYPE' => $topic['topic_type'], + 'DL' => ($topic['topic_dl_type'] == TOPIC_DL_TYPE_DL && !$forum_data['allow_reg_tracker']), + 'POLL' => $topic['topic_vote'], + 'DL_CLASS' => isset($topic['dl_status']) ? $dl_link_css[$topic['dl_status']] : '', + + 'TOPIC_AUTHOR_ID' => ($topic['first_user_id'] != ANONYMOUS) ? $topic['first_user_id'] : '', + 'TOPIC_AUTHOR_NAME' => ($topic['first_username']) ? wbr($topic['first_username']) : $lang['GUEST'], + 'LAST_POSTER_HREF' => ($topic['last_user_id'] != ANONYMOUS) ? $topic['last_user_id'] : '', + 'LAST_POSTER_NAME' => ($topic['last_username']) ? str_short($topic['last_username'], 15) : $lang['GUEST'], + 'LAST_POST_TIME' => bb_date($topic['topic_last_post_time']), + 'LAST_POST_ID' => $topic['topic_last_post_id'], + )); + + if (isset($topic['tor_size'])) + { + $tor_magnet = create_magnet($topic['info_hash'], $topic['auth_key'], $userdata['session_logged_in']); + + $template->assign_block_vars('t.tor', array( + 'SEEDERS' => (int) $topic['seeders'], + 'LEECHERS' => (int) $topic['leechers'], + 'TOR_SIZE' => humn_size($topic['tor_size']), + 'COMPL_CNT' => (int) $topic['complete_count'], + 'ATTACH_ID' => $topic['attach_id'], + 'MAGNET' => $tor_magnet, + )); + } +} +unset($topic_rowset); + +$pg_url = FORUM_URL . $forum_id; +$pg_url .= ($topic_days) ? "&topicdays=$topic_days" : ''; +$pg_url .= ($sort_value) ? "&sort=$sort_value" : ''; +$pg_url .= ($order_value) ? "&order=$order_value" : ''; +$pg_url .= ($moderation) ? "&mod=1" : ''; +$pg_url .= ($topics_per_page != $bb_cfg['topics_per_page']) ? "&tpp=$topics_per_page" : ''; + +if ($found_topics) +{ + $template->assign_vars(array( + 'PAGINATION' => generate_pagination($pg_url, $forum_topics, $topics_per_page, $start), + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], (floor($start / $topics_per_page) + 1), ceil($forum_topics / $topics_per_page)), + )); +} +else +{ + if ($only_new) + { + $no_topics_msg = $lang['NO_NEW_POSTS']; + } + else + { + $no_topics_msg = ($topic_days || $title_match) ? $lang['NO_SEARCH_MATCH'] : $lang['NO_TOPICS_POST_ONE']; + } + $template->assign_vars(array( + 'NO_TOPICS' => $no_topics_msg, + )); +} + +$template->assign_vars(array( + 'PAGE_URL' => $pg_url, + 'PAGE_URL_TPP' => url_arg($pg_url, 'tpp', null), + 'FOUND_TOPICS' => $found_topics, + + 'AUTH_MOD' => $is_auth['auth_mod'], + 'SESSION_ADMIN' => $userdata['session_admin'], + 'MOD_REDIRECT_URL' => $mod_redirect_url, + 'MODERATION_ON' => $moderation, +)); + +print_page('viewforum.tpl'); diff --git a/upload/viewonline.php b/upload/viewonline.php new file mode 100644 index 000000000..25e2b3348 --- /dev/null +++ b/upload/viewonline.php @@ -0,0 +1,201 @@ +session_start(array('req_login' => true)); + +// +// Output page header and load viewonline template +// +$template->assign_vars(array( + 'PAGE_TITLE' => $lang['WHOSONLINE'], + 'L_LAST_UPDATE' => $lang['LAST_UPDATED'], +)); + +// +// Get auth data +// +$is_auth_ary = array(); +$is_auth_ary = auth(AUTH_VIEW, AUTH_LIST_ALL, $userdata); + +// +// Get user list +// +$sql = "SELECT u.user_id, u.username, u.user_allow_viewonline, u.user_level, s.session_logged_in, s.session_time, s.session_ip + FROM ".BB_USERS." u, ".BB_SESSIONS." s + WHERE u.user_id = s.session_user_id + AND s.session_time >= ".( time() - 300 ) . " + ORDER BY u.username ASC, s.session_ip ASC"; +if ( !($result = DB()->sql_query($sql)) ) +{ + message_die(GENERAL_ERROR, 'Could not obtain regd user/online information', '', __LINE__, __FILE__, $sql); +} + +$guest_users = 0; +$registered_users = 0; +$hidden_users = 0; + +$reg_counter = 0; +$guest_counter = 0; +$prev_user = 0; +$prev_ip = ''; + +$user_id = 0; + +while ( $row = DB()->sql_fetchrow($result) ) +{ + $view_online = false; + + if ( $row['session_logged_in'] ) + { + $user_id = $row['user_id']; + + if ( $user_id != $prev_user ) + { + $username = $row['username']; + + $style_color = ''; + if ( $row['user_level'] == ADMIN ) + { + $username = '' . $username . ''; + } + else if ( $row['user_level'] == MOD ) + { + $username = '' . $username . ''; + } + else if ( $row['user_level'] == GROUP_MEMBER ) + { + $username = '' . $username . ''; + } + + if ( !$row['user_allow_viewonline'] ) + { + $view_online = IS_AM; + $hidden_users++; + + $username = '' . $username . ''; + } + else + { + $view_online = true; + $registered_users++; + } + + $which_counter = 'reg_counter'; + $which_row = 'reg_user_row'; + $prev_user = $user_id; + } + } + else + { + if ( $row['session_ip'] != $prev_ip ) + { + $username = $lang['GUEST']; + $view_online = true; + $guest_users++; + + $which_counter = 'guest_counter'; + $which_row = 'guest_user_row'; + } + } + + $prev_ip = $row['session_ip']; + + if ( $view_online ) + { + $row_class = !($$which_counter % 2) ? 'row1' : 'row2'; + + $template->assign_block_vars("$which_row", array( + 'ROW_CLASS' => $row_class, + 'USERNAME' => $username, + 'LASTUPDATE' => bb_date($row['session_time']), + + 'U_USER_PROFILE' => ((isset($user_id)) ? append_sid("profile.php?mode=viewprofile&" . POST_USERS_URL . '=' . $user_id) : ''), + )); + + $$which_counter++; + } +} + +if( $registered_users == 0 ) +{ + $l_r_user_s = $lang['REG_USERS_ZERO_ONLINE']; +} +else if( $registered_users == 1 ) +{ + $l_r_user_s = $lang['REG_USER_ONLINE']; +} +else +{ + $l_r_user_s = $lang['REG_USERS_ONLINE']; +} + +if( $hidden_users == 0 ) +{ + $l_h_user_s = $lang['HIDDEN_USERS_ZERO_ONLINE']; +} +else if( $hidden_users == 1 ) +{ + $l_h_user_s = $lang['HIDDEN_USER_ONLINE']; +} +else +{ + $l_h_user_s = $lang['HIDDEN_USERS_ONLINE']; +} + +if( $guest_users == 0 ) +{ + $l_g_user_s = $lang['GUEST_USERS_ZERO_ONLINE']; +} +else if( $guest_users == 1 ) +{ + $l_g_user_s = $lang['GUEST_USER_ONLINE']; +} +else +{ + $l_g_user_s = $lang['GUEST_USERS_ONLINE']; +} + +$template->assign_vars(array( + 'TOTAL_REGISTERED_USERS_ONLINE' => sprintf($l_r_user_s, $registered_users) . sprintf($l_h_user_s, $hidden_users), + 'TOTAL_GUEST_USERS_ONLINE' => sprintf($l_g_user_s, $guest_users)) +); + +if ( $registered_users + $hidden_users == 0 ) +{ + $template->assign_vars(array( + 'L_NO_REGISTERED_USERS_BROWSING' => $lang['NO_USERS_BROWSING']) + ); +} + +if ( $guest_users == 0 ) +{ + $template->assign_vars(array( + 'L_NO_GUESTS_BROWSING' => $lang['NO_USERS_BROWSING']) + ); +} + +print_page('viewonline.tpl'); diff --git a/upload/viewtopic.php b/upload/viewtopic.php new file mode 100644 index 000000000..dabf4745b --- /dev/null +++ b/upload/viewtopic.php @@ -0,0 +1,1085 @@ +enqueue(array( + 'ranks', +)); + +$page_cfg['load_tpl_vars'] = array( + 'post_buttons', + 'post_icons', + 'topic_icons', +); + +$newest = $next_topic_id = 0; +$start = isset($_GET['start']) ? abs(intval($_GET['start'])) : 0; +$topic_id = isset($_GET[POST_TOPIC_URL]) ? (int) $_GET[POST_TOPIC_URL] : 0; +$post_id = (!$topic_id && isset($_GET[POST_POST_URL])) ? (int) $_GET[POST_POST_URL] : 0; +$porno_forums = array_flip(explode(',', $bb_cfg['porno_forums'])); + +// Start session +$user->session_start(); + +// Posts per page +$posts_per_page = $bb_cfg['posts_per_page']; +$select_ppp = ''; + +if ($userdata['session_admin']) +{ + if ($req_ppp = abs(intval(@$_REQUEST['ppp'])) AND in_array($req_ppp, $bb_cfg['allowed_posts_per_page'])) + { + $posts_per_page = $req_ppp; + } + + $select_ppp = array(); + foreach ($bb_cfg['allowed_posts_per_page'] as $ppp) + { + $select_ppp[$ppp] = $ppp; + } +} + +if (isset($_REQUEST['single'])) +{ + $posts_per_page = 1; +} +else +{ + $start = floor($start/$posts_per_page) * $posts_per_page; +} + +if (!$topic_id && !$post_id) +{ + bb_die($lang['TOPIC_POST_NOT_EXIST']); +} + +$tracking_topics = get_tracks('topic'); +$tracking_forums = get_tracks('forum'); + +// Find topic id if user requested a newer or older topic +if ($topic_id && isset($_GET['view']) && ($_GET['view'] == 'next' || $_GET['view'] == 'previous')) +{ + $sql_condition = ($_GET['view'] == 'next') ? '>' : '<'; + $sql_ordering = ($_GET['view'] == 'next') ? 'ASC' : 'DESC'; + + $sql = "SELECT t.topic_id + FROM ". BB_TOPICS ." t, ". BB_TOPICS ." t2 + WHERE t2.topic_id = $topic_id + AND t.forum_id = t2.forum_id + AND t.topic_moved_id = 0 + AND t.topic_last_post_id $sql_condition t2.topic_last_post_id + ORDER BY t.topic_last_post_id $sql_ordering + LIMIT 1"; + + if ($row = DB()->fetch_row($sql)) + { + $next_topic_id = $topic_id = $row['topic_id']; + } + else + { + $message = ($_GET['view'] == 'next') ? $lang['NO_NEWER_TOPICS'] : $lang['NO_OLDER_TOPICS']; + bb_die($message); + } +} + +// Get forum/topic data +if ($topic_id) +{ + $sql = "SELECT t.*, f.* + FROM ". BB_TOPICS ." t, ". BB_FORUMS ." f + WHERE t.topic_id = $topic_id + AND f.forum_id = t.forum_id + LIMIT 1"; +} +else if ($post_id) +{ + $sql = "SELECT t.*, f.*, p.post_time + FROM ". BB_TOPICS ." t, ". BB_FORUMS ." f, ". BB_POSTS ." p + WHERE p.post_id = $post_id + AND t.topic_id = p.topic_id + AND f.forum_id = t.forum_id + LIMIT 1"; +} +else +{ + bb_die($lang['TOPIC_POST_NOT_EXIST']); +} + +if (!$t_data = DB()->fetch_row($sql)) +{ + bb_die($lang['TOPIC_POST_NOT_EXIST']); +} + +$forum_topic_data =& $t_data; +$topic_id = $t_data['topic_id']; +$forum_id = $t_data['forum_id']; + +if ($userdata['session_admin'] && !empty($_REQUEST['mod'])) +{ + if (IS_ADMIN) + { + $datastore->enqueue(array('viewtopic_forum_select')); + } +} +if ($t_data['topic_attachment']) +{ + $datastore->enqueue(array( + 'attach_extensions', + )); +} + +// Find newest post +if (($next_topic_id || @$_GET['view'] === 'newest') && !IS_GUEST && $topic_id) +{ + $post_time = 'post_time >= '. get_last_read($topic_id, $forum_id); + $post_id_altern = ($next_topic_id) ? '' : ' OR post_id = '. $t_data['topic_last_post_id']; + + $sql = "SELECT post_id, post_time + FROM ". BB_POSTS ." + WHERE topic_id = $topic_id + AND ($post_time $post_id_altern) + ORDER BY post_time ASC + LIMIT 1"; + + if ($row = DB()->fetch_row($sql)) + { + $post_id = $newest = $row['post_id']; + $t_data['post_time'] = $row['post_time']; + } +} + +if ($post_id && !empty($t_data['post_time']) && ($t_data['topic_replies'] + 1) > $posts_per_page) +{ + $sql = "SELECT COUNT(post_id) AS prev_posts + FROM ". BB_POSTS ." + WHERE topic_id = $topic_id + AND post_time <= {$t_data['post_time']}"; + + if ($row = DB()->fetch_row($sql)) + { + $t_data['prev_posts'] = $row['prev_posts']; + } +} + +// Auth check +$is_auth = auth(AUTH_ALL, $forum_id, $userdata, $t_data); + +if (!$is_auth['auth_read']) +{ + if (IS_GUEST) + { + $redirect = ($post_id) ? POST_POST_URL . "=$post_id" : POST_TOPIC_URL . "=$topic_id"; + $redirect .= ($start) ? "&start=$start" : ''; + redirect("login.php?redirect=viewtopic.php&$redirect"); + } + bb_die($lang['TOPIC_POST_NOT_EXIST']); +} + +$forum_name = $t_data['forum_name']; +$topic_title = $t_data['topic_title']; +$topic_id = $t_data['topic_id']; +$topic_time = $t_data['topic_time']; + +$moderation = (!empty($_REQUEST['mod']) && $is_auth['auth_mod']); + +// Redirect to login page if not admin session +$mod_redirect_url = ''; + +if ($is_auth['auth_mod']) +{ + $redirect = isset($_POST['redirect']) ? $_POST['redirect'] : $_SERVER['REQUEST_URI']; + $redirect = url_arg($redirect, 'mod', 1, '&'); + $mod_redirect_url = "login.php?redirect=$redirect&admin=1"; + + if ($moderation && !$userdata['session_admin']) + { + redirect($mod_redirect_url); + } +} + +if ($moderation) +{ + if (IS_ADMIN) + { + if (!$forum_select = $datastore->get('viewtopic_forum_select')) + { + $datastore->update('viewtopic_forum_select'); + $forum_select = $datastore->get('viewtopic_forum_select'); + } + $forum_select_html = $forum_select['viewtopic_forum_select']; + } + else + { + $not_auth_forums_csv = $user->get_not_auth_forums(AUTH_VIEW); + $forum_select_html = get_forum_select(explode(',', $not_auth_forums_csv), 'new_forum_id'); + } + $template->assign_vars(array( + 'S_FORUM_SELECT' => $forum_select_html, + )); +} + +if ($parent_id = $t_data['forum_parent']) +{ + if (!$forums = $datastore->get('cat_forums')) + { + $datastore->update('cat_forums'); + $forums = $datastore->get('cat_forums'); + } + + $template->assign_vars(array( + 'HAS_PARENT_FORUM' => true, + 'PARENT_FORUM_HREF' => FORUM_URL . $parent_id, + 'PARENT_FORUM_NAME' => htmlCHR($forums['f'][$parent_id]['forum_name']), + )); + unset($forums); +} +$datastore->rm('cat_forums'); + +if ($post_id && !empty($t_data['prev_posts'])) +{ + $start = floor(($t_data['prev_posts'] - 1) / $posts_per_page) * $posts_per_page; +} + +// +// Is user watching this thread? +// +$can_watch_topic = $is_watching_topic = false; + +if ($bb_cfg['topic_notify_enabled']) +{ + if( $userdata['session_logged_in'] ) + { + $can_watch_topic = TRUE; + + $sql = "SELECT notify_status + FROM " . BB_TOPICS_WATCH . " + WHERE topic_id = $topic_id + AND user_id = " . $userdata['user_id']; + + if ($row = DB()->fetch_row($sql)) + { + if ( isset($_GET['unwatch']) ) + { + if ( $_GET['unwatch'] == 'topic' ) + { + $is_watching_topic = 0; + + $sql = "DELETE FROM " . BB_TOPICS_WATCH . " + WHERE topic_id = $topic_id + AND user_id = " . $userdata['user_id']; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Could not delete topic watch information", '', __LINE__, __FILE__, $sql); + } + } + + $message = $lang['NO_LONGER_WATCHING'] . '

    ' . sprintf($lang['CLICK_RETURN_TOPIC'], '', ''); + bb_die($message); + } + else + { + $is_watching_topic = TRUE; + + if ( $row['notify_status'] ) + { + $sql = "UPDATE " . BB_TOPICS_WATCH . " + SET notify_status = 0 + WHERE topic_id = $topic_id + AND user_id = " . $userdata['user_id']; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Could not update topic watch information", '', __LINE__, __FILE__, $sql); + } + } + } + } + else + { + if ( isset($_GET['watch']) ) + { + if ( $_GET['watch'] == 'topic' ) + { + $is_watching_topic = TRUE; + + $sql = "INSERT INTO " . BB_TOPICS_WATCH . " (user_id, topic_id, notify_status) + VALUES (" . $userdata['user_id'] . ", $topic_id, 0)"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Could not insert topic watch information", '', __LINE__, __FILE__, $sql); + } + } + + $message = $lang['YOU_ARE_WATCHING'] . '

    ' . sprintf($lang['CLICK_RETURN_TOPIC'], '', ''); + bb_die($message); + } + else + { + $is_watching_topic = 0; + } + } + } + else + { + if ( isset($_GET['unwatch']) ) + { + if ( $_GET['unwatch'] == 'topic' ) + { + redirect("login.php?redirect=viewtopic.php&t=$topic_id&unwatch=topic"); + } + } + } +} + +// Generate a 'Show posts in previous x days' select box. If the postdays var is POSTed +// then get it's value, find the number of topics with dates newer than it (to properly +// handle pagination) and alter the main query +$post_days = 0; +$limit_posts_time = ''; +$total_replies = $t_data['topic_replies'] + 1; + +if (!empty($_REQUEST['postdays'])) +{ + if ($post_days = abs(intval($_REQUEST['postdays']))) + { + if (!empty($_POST['postdays'])) + { + $start = 0; + } + $min_post_time = TIMENOW - ($post_days*86400); + + $sql = "SELECT COUNT(p.post_id) AS num_posts + FROM " . BB_TOPICS . " t, " . BB_POSTS . " p + WHERE t.topic_id = $topic_id + AND p.topic_id = t.topic_id + AND p.post_time > $min_post_time"; + + $total_replies = ($row = DB()->fetch_row($sql)) ? $row['num_posts'] : 0; + $limit_posts_time = "AND p.post_time >= $min_post_time "; + } +} + +// Decide how to order the post display +$post_order = (isset($_POST['postorder']) && $_POST['postorder'] !== 'asc') ? 'desc' : 'asc'; + +// +// Go ahead and pull all data for this topic +// +$sql = " + SELECT + u.username, u.user_id, u.user_posts, u.user_from, u.user_from_flag, + u.user_regdate, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, + u.user_avatar, u.user_avatar_type, u.user_allowavatar, + p.*, + h.post_html, IF(h.post_html IS NULL, pt.post_text, NULL) AS post_text, + pt.post_subject, pt.bbcode_uid + FROM ". BB_POSTS ." p + LEFT JOIN ". BB_USERS ." u ON(u.user_id = p.poster_id) + LEFT JOIN ". BB_POSTS_TEXT ." pt ON(pt.post_id = p.post_id) + LEFT JOIN ". BB_POSTS_HTML ." h ON(h.post_id = p.post_id) + WHERE + p.topic_id = $topic_id + $limit_posts_time + GROUP BY + p.post_id + ORDER BY + p.post_time + $post_order + LIMIT + $start, $posts_per_page +"; + +if ($postrow = DB()->fetch_rowset($sql)) +{ + $total_posts = count($postrow); +} +else +{ + bb_die($lang['NO_POSTS_TOPIC']); +} + +if (!$ranks = $datastore->get('ranks')) +{ + $datastore->update('ranks'); + $ranks = $datastore->get('ranks'); +} + +// +// Define censored word matches +// +$orig_word = array(); +$replacement_word = array(); +obtain_word_list($orig_word, $replacement_word); + +// +// Censor topic title +// +if ( count($orig_word) ) +{ + $topic_title = preg_replace($orig_word, $replacement_word, $topic_title); +} + +// +// Post, reply and other URL generation for +// templating vars +// +$new_topic_url = "posting.php?mode=newtopic&f=$forum_id"; +$new_topic_url .= ($t_data['topic_tpl_id']) ? '&tpl=1' : ''; +$reply_topic_url = "posting.php?mode=reply&t=$topic_id"; +$view_forum_url = "viewforum.php?f=$forum_id"; +$view_prev_topic_url = "viewtopic.php?t=$topic_id&view=previous#newest"; +$view_next_topic_url = "viewtopic.php?t=$topic_id&view=next#newest"; + +$reply_img = ( $t_data['forum_status'] == FORUM_LOCKED || $t_data['topic_status'] == TOPIC_LOCKED ) ? $images['reply_locked'] : $images['reply_new']; +$reply_alt = ( $t_data['forum_status'] == FORUM_LOCKED || $t_data['topic_status'] == TOPIC_LOCKED ) ? $lang['TOPIC_LOCKED_SHORT'] : $lang['REPLY_TO_TOPIC']; + +// Set 'body' template for attach_mod +$template->set_filenames(array('body' => 'viewtopic.tpl')); + +// +// User authorisation levels output +// +$s_auth_can = ( ( $is_auth['auth_post'] ) ? $lang['RULES_POST_CAN'] : $lang['RULES_POST_CANNOT'] ) . '
    '; +$s_auth_can .= ( ( $is_auth['auth_reply'] ) ? $lang['RULES_REPLY_CAN'] : $lang['RULES_REPLY_CANNOT'] ) . '
    '; +$s_auth_can .= ( ( $is_auth['auth_edit'] ) ? $lang['RULES_EDIT_CAN'] : $lang['RULES_EDIT_CANNOT'] ) . '
    '; +$s_auth_can .= ( ( $is_auth['auth_delete'] ) ? $lang['RULES_DELETE_CAN'] : $lang['RULES_DELETE_CANNOT'] ) . '
    '; +$s_auth_can .= ( ( $is_auth['auth_vote'] ) ? $lang['RULES_VOTE_CAN'] : $lang['RULES_VOTE_CANNOT'] ) . '
    '; +$s_auth_can .= ( ($is_auth['auth_attachments'] ) ? $lang['RULES_ATTACH_CAN'] : $lang['RULES_ATTACH_CANNOT'] ) . '
    '; +$s_auth_can .= ( ($is_auth['auth_download'] ) ? $lang['RULES_DOWNLOAD_CAN'] : $lang['RULES_DOWNLOAD_CANNOT'] ) . '
    '; + +$topic_mod = ''; + +if ( $is_auth['auth_mod'] ) +{ + $s_auth_can .= $lang['RULES_MODERATE']; + + $topic_mod .= "' . $lang['DELETE_TOPIC'] . ' '; + + $topic_mod .= "' . $lang['MOVE_TOPIC'] . ' '; + + $topic_mod .= ( $t_data['topic_status'] == TOPIC_UNLOCKED ) ? "' . $lang['LOCK_TOPIC'] . ' ' : "' . $lang['UNLOCK_TOPIC'] . ' '; + + $topic_mod .= "' . $lang['SPLIT_TOPIC'] . ' '; + //bt + if ($t_data['allow_dl_topic'] || $t_data['topic_dl_type'] == TOPIC_DL_TYPE_DL || IS_ADMIN) + { + if ($t_data['topic_dl_type'] == TOPIC_DL_TYPE_DL) + { + $topic_mod .= "' . $lang['UNSET_DL_STATUS'] . ''; + } + else + { + $topic_mod .= "' . $lang['SET_DL_STATUS'] . ''; + } + } + //bt end +} +//bt +else if (($t_data['topic_poster'] == $userdata['user_id']) && $userdata['session_logged_in'] && $t_data['self_moderated']) +{ + $topic_mod .= "' . $lang['MOVE_TOPIC'] . ' '; +} +//bt end + +// Report +// +// Get report topic module and create report link +// +require_once(INC_DIR ."functions_report.php"); +$report_topic = report_modules('name', 'report_topic'); + +if ($report_topic && $report_topic->auth_check('auth_write')) +{ + if ($forum_topic_data['topic_reported']) + { + $report_auth = ($userdata['user_level'] == ADMIN || (!$bb_cfg['report_list_admin'] && (!$bb_cfg['report_subject_auth'] || $is_auth['auth_mod']))); + if ($report_topic->auth_check('auth_view') && $is_auth) + { + $target = ($bb_cfg['report_new_window']) ? ' target="_blank"' : ''; + $s_report_topic =' ' . $report_topic->lang['DUPLICATE_REPORT'] . ' '; + } + else + { + $s_report_topic = ' ' . $report_topic->lang['DUPLICATE_REPORT'] . ' '; + } + } + else + { + $s_report_topic = ' ' . $report_topic->lang['WRITE_REPORT'] . ' '; + } + + $topic_mod .= $s_report_topic; + $template->assign_var('S_REPORT_TOPIC', $s_report_topic); +} +// Report [END] + +// +// Topic watch information +// +$s_watching_topic = $s_watching_topic_img = ''; +if ( $can_watch_topic ) +{ + if ( $is_watching_topic ) + { + $s_watching_topic = "' . $lang['STOP_WATCHING_TOPIC'] . ''; + $s_watching_topic_img = ( isset($images['topic_un_watch']) ) ? "' . $lang['STOP_WATCHING_TOPIC'] . '' : ''; + } + else + { + $s_watching_topic = "' . $lang['START_WATCHING_TOPIC'] . ''; + $s_watching_topic_img = ( isset($images['Topic_watch']) ) ? "' . $lang['START_WATCHING_TOPIC'] . '' : ''; + } +} + +// If we've got a hightlight set pass it on to pagination, +$pg_url = TOPIC_URL . $topic_id; +$pg_url .= ($post_days) ? "&postdays=$post_days" : ''; +$pg_url .= ($post_order != 'asc') ? "&postorder=$post_order" : ''; +$pg_url .= isset($_REQUEST['single']) ? "&single=1" : ''; +$pg_url .= ($moderation) ? "&mod=1" : ''; +$pg_url .= ($posts_per_page != $bb_cfg['posts_per_page']) ? "&ppp=$posts_per_page" : ''; + +$pagination = generate_pagination($pg_url, $total_replies, $posts_per_page, $start); + +// +// Selects +// +$sel_previous_days = array( + 0 => $lang['ALL_POSTS'], + 1 => $lang['1_DAY'], + 7 => $lang['7_DAYS'], + 14 => $lang['2_WEEKS'], + 30 => $lang['1_MONTH'], + 90 => $lang['3_MONTHS'], + 180 => $lang['6_MONTHS'], + 364 => $lang['1_YEAR'], +); + +$sel_post_order_ary = array( + $lang['OLDEST_FIRST'] => 'asc', + $lang['NEWEST_FIRST'] => 'desc', +); + +// +// Send vars to template +// +$template->assign_vars(array( + 'PAGE_URL' => $pg_url, + 'PAGE_URL_PPP' => url_arg($pg_url, 'ppp', null), + 'PAGE_START' => $start, + 'SHOW_JUMPBOX' => true, + + 'FORUM_ID' => $forum_id, + 'FORUM_NAME' => htmlCHR($forum_name), + 'TOPIC_ID' => $topic_id, + 'PAGE_TITLE' => $topic_title, + 'TOPIC_TITLE' => wbr($topic_title), + 'PAGINATION' => $pagination, + 'PAGE_NUMBER' => sprintf($lang['PAGE_OF'], ( floor($start/$posts_per_page) + 1 ), ceil( $total_replies / $posts_per_page )), + 'PORNO_FORUM' => isset($porno_forums[$forum_id]), + 'REPLY_IMG' => $reply_img, + 'SHOW_BOT_NICK' => $bb_cfg['show_bot_nick'], + 'T_POST_REPLY' => $reply_alt, + + 'HIDE_FLAGS' => ($user->opt_js['h_flag'] && $bb_cfg['show_poster_flag']), + 'HIDE_AVATAR' => $user->opt_js['h_av'], + 'HIDE_RANK_IMG' => ($user->opt_js['h_rnk_i'] && $bb_cfg['show_rank_image']), + 'HIDE_POST_IMG' => $user->opt_js['h_post_i'], + 'HIDE_SMILE' => $user->opt_js['h_smile'], + 'HIDE_SIGNATURE' => $user->opt_js['h_sig'], + 'SPOILER_OPENED' => $user->opt_js['sp_op'], + + 'HIDE_FLAGS_DIS' => !$bb_cfg['show_poster_flag'], + 'HIDE_RANK_IMG_DIS' => !$bb_cfg['show_rank_image'], + + 'AUTH_MOD' => $is_auth['auth_mod'], + 'IN_MODERATION' => $moderation, + 'L_SELECT_PPP' => $lang['SELECT_POSTS_PER_PAGE'], + 'SELECT_PPP' => ($moderation && $select_ppp && $total_replies > $posts_per_page) ? build_select('ppp', $select_ppp, $posts_per_page, null, null, 'onchange="$(\'#ppp\').submit();"') : '', + + 'S_SELECT_POST_DAYS' => build_select('postdays', array_flip($sel_previous_days), $post_days), + 'S_SELECT_POST_ORDER' => build_select('postorder', $sel_post_order_ary, $post_order), + 'S_POST_DAYS_ACTION' => "viewtopic.php?t=$topic_id&start=$start", + 'S_AUTH_LIST' => $s_auth_can, + 'S_TOPIC_ADMIN' => $topic_mod, + 'S_WATCH_TOPIC' => $s_watching_topic, + 'S_WATCH_TOPIC_IMG' => $s_watching_topic_img, + 'U_VIEW_TOPIC' => TOPIC_URL . $topic_id, + 'U_VIEW_FORUM' => $view_forum_url, + 'U_VIEW_OLDER_TOPIC' => $view_prev_topic_url, + 'U_VIEW_NEWER_TOPIC' => $view_next_topic_url, + 'U_POST_NEW_TOPIC' => $new_topic_url, + 'U_POST_REPLY_TOPIC' => $reply_topic_url, + 'U_SEARCH_SELF' => "search.php?uid={$userdata['user_id']}&t=$topic_id&dm=1", + +)); + +// Does this topic contain DL-List? +$template->assign_vars(array( + 'SHOW_TOR_ACT' => false, + 'PEERS_FULL_LINK' => false, + 'DL_LIST_HREF' => TOPIC_URL ."$topic_id&dl=names&spmode=full", +)); +require(INC_DIR .'torrent_show_dl_list.php'); + +// +// Does this topic contain a poll? +// +if ( !empty($t_data['topic_vote']) ) +{ + $s_hidden_fields = ''; + + $sql = "SELECT vd.vote_id, vd.vote_text, vd.vote_start, vd.vote_length, vr.vote_option_id, vr.vote_option_text, vr.vote_result + FROM " . BB_VOTE_DESC . " vd, " . BB_VOTE_RESULTS . " vr + WHERE vd.topic_id = $topic_id + AND vr.vote_id = vd.vote_id + ORDER BY vr.vote_option_id ASC"; + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Could not obtain vote data for this topic", '', __LINE__, __FILE__, $sql); + } + + if ( $vote_info = DB()->sql_fetchrowset($result) ) + { + DB()->sql_freeresult($result); + $vote_options = count($vote_info); + + $vote_id = $vote_info[0]['vote_id']; + $vote_title = $vote_info[0]['vote_text']; + + $sql = "SELECT vote_id + FROM " . BB_VOTE_USERS . " + WHERE vote_id = $vote_id + AND vote_user_id = " . intval($userdata['user_id']); + if ( !($result = DB()->sql_query($sql)) ) + { + message_die(GENERAL_ERROR, "Could not obtain user vote data for this topic", '', __LINE__, __FILE__, $sql); + } + + $user_voted = ( $row = DB()->sql_fetchrow($result) ) ? TRUE : 0; + DB()->sql_freeresult($result); + + if ( isset($_GET['vote']) || isset($_POST['vote']) ) + { + $view_result = ( ( ( isset($_GET['vote']) ) ? $_GET['vote'] : $_POST['vote'] ) == 'viewresult' ) ? TRUE : 0; + } + else + { + $view_result = 0; + } + + $poll_expired = ( $vote_info[0]['vote_length'] ) ? ( ( $vote_info[0]['vote_start'] + $vote_info[0]['vote_length'] < time() ) ? TRUE : 0 ) : 0; + + if ( $user_voted || $view_result || $poll_expired || !$is_auth['auth_vote'] || $t_data['topic_status'] == TOPIC_LOCKED ) + { + $vote_results_sum = 0; + + for($i = 0; $i < $vote_options; $i++) + { + $vote_results_sum += $vote_info[$i]['vote_result']; + } + + $vote_graphic = 0; + $vote_graphic_max = count($images['voting_graphic']); + + for($i = 0; $i < $vote_options; $i++) + { + $vote_percent = ( $vote_results_sum > 0 ) ? $vote_info[$i]['vote_result'] / $vote_results_sum : 0; + $vote_graphic_length = round($vote_percent * $bb_cfg['vote_graphic_length']); + + $vote_graphic_img = $images['voting_graphic'][$vote_graphic]; + $vote_graphic = ($vote_graphic < $vote_graphic_max - 1) ? $vote_graphic + 1 : 0; + + if ( count($orig_word) ) + { + $vote_info[$i]['vote_option_text'] = preg_replace($orig_word, $replacement_word, $vote_info[$i]['vote_option_text']); + } + + $template->assign_block_vars("poll_option", array( + 'POLL_OPTION_CAPTION' => $vote_info[$i]['vote_option_text'], + 'POLL_OPTION_RESULT' => $vote_info[$i]['vote_result'], + 'POLL_OPTION_PERCENT' => sprintf("%.1d%%", ($vote_percent * 100)), + + 'POLL_OPTION_IMG' => $vote_graphic_img, + 'POLL_OPTION_IMG_WIDTH' => $vote_graphic_length) + ); + } + + $template->assign_vars(array( + 'TPL_POLL_RESULT' => true, + 'TOTAL_VOTES' => $vote_results_sum, + )); + } + else + { + for($i = 0; $i < $vote_options; $i++) + { + if ( count($orig_word) ) + { + $vote_info[$i]['vote_option_text'] = preg_replace($orig_word, $replacement_word, $vote_info[$i]['vote_option_text']); + } + + $template->assign_block_vars("poll_option", array( + 'POLL_OPTION_ID' => $vote_info[$i]['vote_option_id'], + 'POLL_OPTION_CAPTION' => $vote_info[$i]['vote_option_text']) + ); + } + + $template->assign_vars(array( + 'TPL_POLL_BALLOT' => true, + 'U_VIEW_RESULTS' => TOPIC_URL ."$topic_id&vote=viewresult", + )); + + $s_hidden_fields = ''; + } + + if ( count($orig_word) ) + { + $vote_title = preg_replace($orig_word, $replacement_word, $vote_title); + } + + $s_hidden_fields .= ''; + + $template->assign_vars(array( + 'TOPIC_HAS_POLL' => true, + 'POLL_QUESTION' => $vote_title, + + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_POLL_ACTION' => "posting.php?mode=vote&t=$topic_id", + )); + } +} + +if ($t_data['topic_attachment']) +{ + require(BB_ROOT .'attach_mod/attachment_mod.php'); + init_display_post_attachments($t_data['topic_attachment']); +} + +// +// Update the topic view counter +// +$sql = "INSERT INTO ". BUF_TOPIC_VIEW ." + (topic_id, topic_views) VALUES + ($topic_id, 1) + ON DUPLICATE KEY UPDATE + topic_views = topic_views + 1"; + +if ( !DB()->sql_query($sql) ) +{ + message_die(GENERAL_ERROR, "Could not update topic views.", '', __LINE__, __FILE__, $sql); +} + +$prev_post_time = $max_post_time = 0; + +// Report +// +// Get report post module +// +require_once(INC_DIR ."functions_report.php"); +$report_post = report_modules('name', 'report_post'); +// Report [END] + +// +// Okay, let's do the loop, yeah come on baby let's do the loop +// and it goes like this ... +// +for($i = 0; $i < $total_posts; $i++) +{ + $poster_id = $postrow[$i]['user_id']; + $poster = ( $poster_id == ANONYMOUS ) ? $lang['GUEST'] : $postrow[$i]['username']; + + $post_date = bb_date($postrow[$i]['post_time'], $bb_cfg['post_date_format']); + $max_post_time = max($max_post_time, $postrow[$i]['post_time']); + + $poster_posts = ( $postrow[$i]['user_id'] != ANONYMOUS ) ? $postrow[$i]['user_posts'] : ''; + + $poster_from = ( $postrow[$i]['user_from'] && $postrow[$i]['user_id'] != ANONYMOUS ) ? $postrow[$i]['user_from'] : ''; + +// FLAGHACK-start + $poster_from_flag = ( !$user->opt_js['h_flag'] && $postrow[$i]['user_from_flag'] && $postrow[$i]['user_id'] != ANONYMOUS ) ? make_user_flag($postrow[$i]['user_from_flag']) : ""; +// FLAGHACK-end + + $poster_joined = ( $postrow[$i]['user_id'] != ANONYMOUS ) ? $lang['JOINED'] . ': ' . bb_date($postrow[$i]['user_regdate'], $lang['DATE_FORMAT']) : ''; + + + + $poster_longevity = ( $postrow[$i]['user_id'] != ANONYMOUS ) ? delta_time($postrow[$i]['user_regdate']) : ''; + + $poster_avatar = ''; + if ( !$user->opt_js['h_av'] && $poster_id != ANONYMOUS ) + { + $poster_avatar = get_avatar($postrow[$i]['user_avatar'], $postrow[$i]['user_avatar_type'], $postrow[$i]['user_allowavatar']); + } + + // + // Generate ranks, set them to empty string initially. + // + $poster_rank = $rank_image = ''; + + if (!$user->opt_js['h_rnk_i'] AND $user_rank = $postrow[$i]['user_rank'] AND isset($ranks[$user_rank])) + { + $rank_image = ($bb_cfg['show_rank_image'] && $ranks[$user_rank]['rank_image']) ? '' : ''; + $poster_rank = ($bb_cfg['show_rank_text']) ? $ranks[$user_rank]['rank_title'] : ''; + } + + // + // Handle anon users posting with usernames + // + if ( $poster_id == ANONYMOUS && $postrow[$i]['post_username'] != '' ) + { + $poster = $postrow[$i]['post_username']; + } + + // Buttons + $pm_btn = ''; + $profile_btn = ''; + + $delpost_btn = ''; + $edit_btn = ''; + $ip_btn = ''; + $quote_btn = ''; + + if ($poster_id != ANONYMOUS) + { + // profile + $profile_btn = true; + // pm + $pm_btn = true; + } + + if ($poster_id != BOT_UID) + { + // Quote + $quote_btn = true; + // Edit + $edit_btn = (($userdata['user_id'] == $poster_id && $is_auth['auth_edit']) || $is_auth['auth_mod']); + // IP + $ip_btn = ($is_auth['auth_mod'] || IS_MOD); + } + // Delete + $delpost_btn = ($postrow[$i]['post_id'] != $t_data['topic_first_post_id'] && ($is_auth['auth_mod'] || ($userdata['user_id'] == $poster_id && $is_auth['auth_delete'] && $t_data['topic_last_post_id'] == $postrow[$i]['post_id'] && $postrow[$i]['post_time'] + 3600*3 > TIMENOW))); + + // + // Parse message and sig + // + $post_subject = ( $postrow[$i]['post_subject'] != '' ) ? $postrow[$i]['post_subject'] : ''; + + $message = get_parsed_post($postrow[$i]); + + $bbcode_uid = $postrow[$i]['bbcode_uid']; + + $user_sig = ($bb_cfg['allow_sig'] && !$user->opt_js['h_sig'] && $postrow[$i]['enable_sig'] && $postrow[$i]['user_sig']) ? $postrow[$i]['user_sig'] : ''; + + if ($user_sig) + { + $user_sig = bbcode2html($user_sig); + } + + // + // Replace naughty words + // + if (count($orig_word)) + { + $post_subject = preg_replace($orig_word, $replacement_word, $post_subject); + + if ($user_sig) + { + $user_sig = str_replace('\"', '"', substr(@preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "@preg_replace(\$orig_word, \$replacement_word, '\\0')", '>' . $user_sig . '<'), 1, -1)); + } + + $message = str_replace('\"', '"', substr(@preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "@preg_replace(\$orig_word, \$replacement_word, '\\0')", '>' . $message . '<'), 1, -1)); + } + + // + // Replace newlines (we use this rather than nl2br because + // till recently it wasn't XHTML compliant) + // + if ($user_sig) + { + $user_sig = '
    _________________
    ' . str_replace("\n", "\n
    \n", $user_sig); + } + + // + // Editing information + // + if ( $postrow[$i]['post_edit_count'] ) + { + $l_edit_time_total = ( $postrow[$i]['post_edit_count'] == 1 ) ? $lang['EDITED_TIME_TOTAL'] : $lang['EDITED_TIMES_TOTAL']; + + $l_edited_by = '

    ' . sprintf($l_edit_time_total, $poster, bb_date($postrow[$i]['post_edit_time']), $postrow[$i]['post_edit_count']); + } + else + { + $l_edited_by = ''; + } + + // + // Again this will be handled by the templating + // code at some point + // + $pg_row_class = !($i % 2) ? 'row2' : 'row1'; + + // Report + // + // Create report links + // + if ($report_post && $report_post->auth_check('auth_write')) + { + if ($postrow[$i]['post_reported']) + { + $report_auth = ($userdata['user_level'] == ADMIN || (!$bb_cfg['report_list_admin'] && (!$bb_cfg['report_subject_auth'] || $is_auth['auth_mod']))); + if ($report_post->auth_check('auth_view') && $report_auth) + { + $temp_url = append_sid("report.php?mode=reported&" . POST_CAT_URL . '=' . $report_post->id . '&id=' . $postrow[$i]['post_id']); + $target = ($bb_cfg['report_new_window']) ? ' target="_blank"' : ''; + $report_img = '' . $report_post->lang['DUPLICATE_REPORT'] . ''; + $report = '[' . $report_post->lang['DUPLICATE_REPORT'] . ']'; + } + else + { + $report_img = '' . $report_post->lang['DUPLICATE_REPORT'] . ''; + $report = '['. $report_post->lang['DUPLICATE_REPORT'] .']'; + } + } + else + { + $temp_url = append_sid("report.php?mode=" . $report_post->mode . '&id=' . $postrow[$i]['post_id']); + $report_img = '' . $report_post->lang['WRITE_REPORT'] . ''; + $report = '[' . $report_post->lang['WRITE_REPORT'] . ']'; + } + } + else + { + $report_img = $report = ''; + } + // Report [END] + + $template->assign_block_vars('postrow', array( + 'ROW_CLASS' => !($i % 2) ? 'row1' : 'row2', + 'POST_ID' => $postrow[$i]['post_id'], + 'IS_NEWEST' => ($postrow[$i]['post_id'] == $newest), + 'POSTER_NAME' => wbr($poster), + 'POSTER_NAME_JS' => addslashes($poster), + 'POSTER_RANK' => $poster_rank, + 'RANK_IMAGE' => $rank_image, + 'POSTER_JOINED' => ($bb_cfg['show_poster_joined']) ? $poster_longevity : '', + + 'POSTER_JOINED_DATE' => $poster_joined, + 'POSTER_POSTS' => ($bb_cfg['show_poster_posts']) ? $poster_posts : '', + 'POSTER_FROM' => ($bb_cfg['show_poster_from']) ? wbr($poster_from) : '', + 'POSTER_BOT' => ($poster_id == BOT_UID), + 'POSTER_ID' => $poster_id, + 'POSTED_AFTER' => ($prev_post_time) ? delta_time($postrow[$i]['post_time'], $prev_post_time) : '', + 'POSTER_FROM_FLAG' => ($bb_cfg['show_poster_flag']) ? $poster_from_flag : '', + 'IS_UNREAD' => is_unread($postrow[$i]['post_time'], $topic_id, $forum_id), + 'IS_FIRST_POST' => (!$start && ($postrow[$i]['post_id'] == $t_data['topic_first_post_id'])), + 'MOD_CHECKBOX' => ($moderation && ($start || defined('SPLIT_FORM_START'))), + 'POSTER_AVATAR' => $poster_avatar, + 'POST_NUMBER' => ($i + $start + 1), + 'POST_DATE' => $post_date, + 'POST_SUBJECT' => $post_subject, + 'MESSAGE' => $message, + 'SIGNATURE' => $user_sig, + 'EDITED_MESSAGE' => $l_edited_by, + + 'PM' => $pm_btn, + 'PROFILE' => $profile_btn, + + 'QUOTE' => $quote_btn, + 'EDIT' => $edit_btn, + 'DELETE' => $delpost_btn, + 'IP' => $ip_btn, + + // Report + 'REPORT' => ($bb_cfg['text_buttons']) ? $report : $report_img, + // Report [END] + )); + + if ($postrow[$i]['post_attachment'] && $is_auth['auth_download'] && function_exists('display_post_attachments')) + { + display_post_attachments($postrow[$i]['post_id'], $postrow[$i]['post_attachment']); + } + + if ($moderation && !defined('SPLIT_FORM_START') && ($start || $postrow[$i]['post_id'] == $t_data['topic_first_post_id'])) + { + define('SPLIT_FORM_START', TRUE); + } + + if ($poster_id != BOT_UID) + { + $prev_post_time = $postrow[$i]['post_time']; + } +} + +set_tracks(COOKIE_TOPIC, $tracking_topics, $topic_id, $max_post_time); + +if (defined('SPLIT_FORM_START')) +{ + $template->assign_vars(array( + 'SPLIT_FORM' => true, + 'START' => $start, + 'S_SPLIT_ACTION' => "modcp.php", + 'POST_FORUM_URL' => POST_FORUM_URL, + 'POST_TOPIC_URL' => POST_TOPIC_URL, + )); +} + +// +// Quick Reply +// +if ($bb_cfg['show_quick_reply']) +{ + if ($is_auth['auth_reply'] && !($t_data['forum_status'] == FORUM_LOCKED || $t_data['topic_status'] == TOPIC_LOCKED)) + { + $template->assign_vars(array( + 'QUICK_REPLY' => true, + 'QR_POST_ACTION' => "posting.php", + 'QR_TOPIC_ID' => $topic_id, + 'CAPTCHA_HTML' => (IS_GUEST) ? CAPTCHA()->get_html() : '', + )); + if (!IS_GUEST) + { + $template->assign_vars(array( + 'QR_ATTACHSIG_CHECKED' => bf($userdata['user_opt'], 'user_opt', 'attachsig'), + 'QR_NOTIFY_CHECKED' => ($userdata['user_notify'] || $is_watching_topic), + )); + } + } +} + +$template->assign_vars(array( + 'PG_ROW_CLASS' => isset($pg_row_class) ? $pg_row_class : 'row1', +)); + +if (IS_ADMIN) +{ + $template->assign_vars(array( + 'U_LOGS' => "admin/admin_log.php?sid={$userdata['session_id']}&t=$topic_id&db=900", + )); +} + +print_page('viewtopic.tpl');